From 24f2d97c0ee48eead850c6a9365748d8ba5c172e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 27 Apr 2021 16:55:39 +0100 Subject: Make atomic compare related intrinsics optional ok --- src/check_builtin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 00963487f..898239234 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2017,8 +2017,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } - operand->mode = Addressing_Value; - operand->type = make_optional_ok_type(default_type(x.type), false); // Just reusing this procedure, it's not optional + operand->mode = Addressing_OptionalOk; + operand->type = default_type(x.type); } break; @@ -2149,8 +2149,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 check_assignment(c, &x, elem, builtin_name); check_assignment(c, &y, elem, builtin_name); - operand->mode = Addressing_Value; - operand->type = make_optional_ok_type(elem, /*typed*/false); + operand->mode = Addressing_OptionalOk; + operand->type = elem; break; } break; -- cgit v1.2.3 From d027a5f1a470233a0307bcf3c7c4fe0b6494cd87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 May 2021 18:48:48 +0100 Subject: Add min_f16 and max_f16 dependencies --- src/check_builtin.cpp | 4 ++++ src/llvm_backend.cpp | 2 ++ 2 files changed, 6 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 898239234..6b299a68a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1509,6 +1509,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 { Type *bt = base_type(x.type); + if (are_types_identical(bt, t_f16)) { + add_package_dependency(c, "runtime", "min_f16"); + add_package_dependency(c, "runtime", "max_f16"); + } if (are_types_identical(bt, t_f32)) { add_package_dependency(c, "runtime", "min_f32"); add_package_dependency(c, "runtime", "max_f32"); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a7c149f06..9649af6c9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5458,6 +5458,7 @@ lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) { args[0] = x; args[1] = y; switch (sz) { + case 16: return lb_emit_runtime_call(p, "min_f16", args); case 32: return lb_emit_runtime_call(p, "min_f32", args); case 64: return lb_emit_runtime_call(p, "min_f64", args); } @@ -5475,6 +5476,7 @@ lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) { args[0] = x; args[1] = y; switch (sz) { + case 16: return lb_emit_runtime_call(p, "max_f16", args); case 32: return lb_emit_runtime_call(p, "max_f32", args); case 64: return lb_emit_runtime_call(p, "max_f64", args); } -- cgit v1.2.3 From b37d344eb214336036c597250206f36043c75975 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 May 2021 12:04:51 +0100 Subject: Add intrinsics.type_is_variant_of --- core/intrinsics/intrinsics.odin | 1 + src/check_builtin.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 ++++ 3 files changed, 45 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index d767f5e47..60b595aab 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -159,6 +159,7 @@ type_is_simd_vector :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- +type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 6b299a68a..8932ac914 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2429,6 +2429,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } break; + case BuiltinProc_type_is_variant_of: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *v = check_type(c, ce->args[1]); + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + bool is_variant = false; + + for_array(i, u->Union.variants) { + Type *vt = u->Union.variants[i]; + if (are_types_identical(v, vt)) { + is_variant = true; + break; + } + } + + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + operand->value = exact_value_bool(is_variant); + } + break; + case BuiltinProc_type_struct_field_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 98ef5180b..5b1aecd68 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -197,6 +197,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, + BuiltinProc_type_is_variant_of, + BuiltinProc_type_struct_field_count, BuiltinProc_type_proc_parameter_count, @@ -415,6 +417,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From e0225c3579147557ad4fe2241d8fbe61851a6389 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 May 2021 10:32:41 +0100 Subject: Add `intrinsics.sqrt` for floating-point values --- core/runtime/internal.odin | 17 ++++++----------- src/check_builtin.cpp | 28 ++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend.cpp | 22 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 11 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 0e128567a..b95f3e64d 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -409,11 +409,6 @@ string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4; } -@(default_calling_convention = "none") -foreign { - @(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 --- - @(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 --- -} abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 { return -x if x < 0 else x; } @@ -445,27 +440,27 @@ max_f64 :: proc(a, b: f64) -> f64 { abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 { r, i := real(x), imag(x); - return f16(_sqrt_f32(f32(r*r + i*i))); + return f16(intrinsics.sqrt(f32(r*r + i*i))); } abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 { r, i := real(x), imag(x); - return _sqrt_f32(r*r + i*i); + return intrinsics.sqrt(r*r + i*i); } abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 { r, i := real(x), imag(x); - return _sqrt_f64(r*r + i*i); + return intrinsics.sqrt(r*r + i*i); } abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 { r, i, j, k := real(x), imag(x), jmag(x), kmag(x); - return f16(_sqrt_f32(f32(r*r + i*i + j*j + k*k))); + return f16(intrinsics.sqrt(f32(r*r + i*i + j*j + k*k))); } abs_quaternion128 :: #force_inline proc "contextless" (x: quaternion128) -> f32 { r, i, j, k := real(x), imag(x), jmag(x), kmag(x); - return _sqrt_f32(r*r + i*i + j*j + k*k); + return intrinsics.sqrt(r*r + i*i + j*j + k*k); } abs_quaternion256 :: #force_inline proc "contextless" (x: quaternion256) -> f64 { r, i, j, k := real(x), imag(x), jmag(x), kmag(x); - return _sqrt_f64(r*r + i*i + j*j + k*k); + return intrinsics.sqrt(r*r + i*i + j*j + k*k); } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8932ac914..54cd21582 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2026,6 +2026,34 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } break; + case BuiltinProc_sqrt: + { + Operand x = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!is_type_float(x.type)) { + gbString xts = type_to_string(x.type); + error(x.expr, "Expected a floating point value for '%.*s', got %s", LIT(builtin_procs[id].name), xts); + gb_string_free(xts); + return false; + } + + if (x.mode == Addressing_Constant) { + f64 v = exact_value_to_f64(x.value); + + operand->mode = Addressing_Constant; + operand->type = x.type; + operand->value = exact_value_float(gb_sqrt(v)); + break; + } + operand->mode = Addressing_Value; + operand->type = default_type(x.type); + } + break; + + case BuiltinProc_atomic_fence: case BuiltinProc_atomic_fence_acq: case BuiltinProc_atomic_fence_rel: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 5b1aecd68..cb864f37d 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -56,6 +56,8 @@ enum BuiltinProcId { BuiltinProc_overflow_sub, BuiltinProc_overflow_mul, + BuiltinProc_sqrt, + BuiltinProc_volatile_store, BuiltinProc_volatile_load, @@ -278,6 +280,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("overflow_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("overflow_mul"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("volatile_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("volatile_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a15b6a172..9dfa123a2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9429,6 +9429,28 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } + case BuiltinProc_sqrt: + { + Type *type = tv.type; + + lbValue x = lb_build_expr(p, ce->args[0]); + x = lb_emit_conv(p, x, type); + + char const *name = "llvm.sqrt"; + LLVMTypeRef types[1] = {lb_type(p->module, type)}; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[1] = {}; + args[0] = x.value; + + lbValue res = {}; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.type = type; + return res; + } + case BuiltinProc_atomic_fence: LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, ""); -- cgit v1.2.3 From e82e4398b65de36bf68e9f61d634165642b03af1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 May 2021 10:50:02 +0100 Subject: Add `intrinsics.mem_copy` and `intrinsics.mem_copy_non_overlapping` --- core/runtime/internal.odin | 24 ++++---------------- src/check_builtin.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 +++++ src/llvm_backend.cpp | 38 +++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 20 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index b95f3e64d..8a7b22ca4 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -105,17 +105,9 @@ mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { if src == nil { return dst; } + // NOTE(bill): This _must_ be implemented like C's memmove - foreign _ { - when size_of(rawptr) == 8 { - @(link_name="llvm.memmove.p0i8.p0i8.i64") - llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---; - } else { - @(link_name="llvm.memmove.p0i8.p0i8.i32") - llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---; - } - } - llvm_memmove(dst, src, len); + intrinsics.mem_copy(dst, src, len); return dst; } @@ -123,17 +115,9 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r if src == nil { return dst; } + // NOTE(bill): This _must_ be implemented like C's memcpy - foreign _ { - when size_of(rawptr) == 8 { - @(link_name="llvm.memcpy.p0i8.p0i8.i64") - llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---; - } else { - @(link_name="llvm.memcpy.p0i8.p0i8.i32") - llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---; - } - } - llvm_memcpy(dst, src, len); + intrinsics.mem_copy_non_overlapping(dst, src, len); return dst; } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 54cd21582..c9b911f92 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2053,6 +2053,59 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } break; + case BuiltinProc_mem_copy: + case BuiltinProc_mem_copy_non_overlapping: + { + operand->mode = Addressing_NoValue; + operand->type = t_invalid; + + Operand dst = {}; + Operand src = {}; + Operand len = {}; + check_expr(c, &dst, ce->args[0]); + check_expr(c, &src, ce->args[1]); + check_expr(c, &len, ce->args[2]); + if (dst.mode == Addressing_Invalid) { + return false; + } + if (src.mode == Addressing_Invalid) { + return false; + } + if (len.mode == Addressing_Invalid) { + return false; + } + + + if (!is_type_pointer(dst.type)) { + gbString str = type_to_string(dst.type); + error(dst.expr, "Expected a pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str); + gb_string_free(str); + return false; + } + if (!is_type_pointer(src.type)) { + gbString str = type_to_string(src.type); + error(src.expr, "Expected a pointer value for '%.*s', got %s", LIT(builtin_procs[id].name), str); + gb_string_free(str); + return false; + } + if (!is_type_integer(len.type)) { + gbString str = type_to_string(len.type); + error(len.expr, "Expected an integer value for the number of bytes for '%.*s', got %s", LIT(builtin_procs[id].name), str); + gb_string_free(str); + return false; + } + + if (len.mode == Addressing_Constant) { + i64 n = exact_value_to_i64(len.value); + if (n < 0) { + gbString str = expr_to_string(len.expr); + error(len.expr, "Expected a non-negative integer value for the number of bytes for '%.*s', got %s", LIT(builtin_procs[id].name), str); + gb_string_free(str); + } + } + } + break; + case BuiltinProc_atomic_fence: case BuiltinProc_atomic_fence_acq: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index cb864f37d..b69bacd30 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -58,6 +58,9 @@ enum BuiltinProcId { BuiltinProc_sqrt, + BuiltinProc_mem_copy, + BuiltinProc_mem_copy_non_overlapping, + BuiltinProc_volatile_store, BuiltinProc_volatile_load, @@ -282,6 +285,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("mem_copy"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("mem_copy_non_overlapping"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("volatile_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("volatile_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 9dfa123a2..b6d1990c3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9451,6 +9451,44 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } + case BuiltinProc_mem_copy: + case BuiltinProc_mem_copy_non_overlapping: + { + + + lbValue dst = lb_build_expr(p, ce->args[0]); + lbValue src = lb_build_expr(p, ce->args[1]); + lbValue len = lb_build_expr(p, ce->args[2]); + dst = lb_emit_conv(p, dst, t_rawptr); + src = lb_emit_conv(p, src, t_rawptr); + len = lb_emit_conv(p, len, t_int); + + char const *name = nullptr; + switch (id) { + case BuiltinProc_mem_copy: name = "llvm.memmove"; break; + case BuiltinProc_mem_copy_non_overlapping: name = "llvm.memcpy"; break; + } + + LLVMTypeRef types[3] = { + lb_type(p->module, t_rawptr), + lb_type(p->module, t_rawptr), + lb_type(p->module, t_int) + }; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[4] = {}; + args[0] = dst.value; + args[1] = src.value; + args[2] = len.value; + args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, false); // is_volatile parameter + + LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + + return {}; + } + case BuiltinProc_atomic_fence: LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, ""); -- cgit v1.2.3 From 9c54ed57924bf8ff241b0bffebaeabfa541db24c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 May 2021 14:15:57 +0100 Subject: Add range-based error messages to `-verbose-errors` Example: Cannot convert '(1 + 2)' to 'untyped bool' from 'untyped integer' x := (1 + 2) * true; ^~~~~~^ --- src/check_builtin.cpp | 4 +- src/check_expr.cpp | 17 +-- src/check_stmt.cpp | 2 +- src/check_type.cpp | 10 +- src/llvm_backend.cpp | 4 +- src/parser.cpp | 158 ++++++------------------ src/parser.hpp | 6 +- src/parser_pos.cpp | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tokenizer.cpp | 64 ++++++---- 9 files changed, 429 insertions(+), 167 deletions(-) create mode 100644 src/parser_pos.cpp (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c9b911f92..1acb9732f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -87,7 +87,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); - String name = bd->name; + String name = bd->name.string; if (name == "defined") { break; } @@ -124,7 +124,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); - String name = bd->name; + String name = bd->name.string; if (name == "location") { if (ce->args.count > 1) { error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 68f05084e..81fe3baa9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5516,7 +5516,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr if (proc != nullptr && proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, proc); - String name = bd->name; + String name = bd->name.string; if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "config" || name == "load") { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; @@ -6191,13 +6191,14 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(bd, BasicDirective, node); o->mode = Addressing_Constant; - if (bd->name == "file") { + String name = bd->name.string; + if (name == "file") { o->type = t_untyped_string; o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id)); - } else if (bd->name == "line") { + } else if (name == "line") { o->type = t_untyped_integer; o->value = exact_value_i64(bd->token.pos.line); - } else if (bd->name == "procedure") { + } else if (name == "procedure") { if (c->curr_proc_decl == nullptr) { error(node, "#procedure may only be used within procedures"); o->type = t_untyped_string; @@ -6206,7 +6207,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->type = t_untyped_string; o->value = exact_value_string(c->proc_name); } - } else if (bd->name == "caller_location") { + } else if (name == "caller_location") { init_core_source_code_location(c->checker); error(node, "#caller_location may only be used as a default argument parameter"); o->type = t_source_code_location; @@ -6373,7 +6374,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (cl->type->ArrayType.tag != nullptr) { Ast *tag = cl->type->ArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); - String name = tag->BasicDirective.name; + String name = tag->BasicDirective.name.string; if (name == "soa") { error(node, "#soa arrays are not supported for compound literals"); return kind; @@ -6385,7 +6386,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (cl->elems.count > 0) { Ast *tag = cl->type->DynamicArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); - String name = tag->BasicDirective.name; + String name = tag->BasicDirective.name.string; if (name == "soa") { error(node, "#soa arrays are not supported for compound literals"); return kind; @@ -8151,7 +8152,7 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { case_ast_node(bd, BasicDirective, node); str = gb_string_append_rune(str, '#'); - str = string_append_string(str, bd->name); + str = string_append_string(str, bd->name.string); case_end; case_ast_node(ud, Undef, node); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a62b55ab2..64d17a8c8 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -7,7 +7,7 @@ bool is_diverging_stmt(Ast *stmt) { return false; } if (expr->CallExpr.proc->kind == Ast_BasicDirective) { - String name = expr->CallExpr.proc->BasicDirective.name; + String name = expr->CallExpr.proc->BasicDirective.name.string; return name == "panic"; } Ast *proc = unparen_expr(expr->CallExpr.proc); diff --git a/src/check_type.cpp b/src/check_type.cpp index 24a3e0a59..419904876 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1191,7 +1191,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type * if (allow_caller_location && expr->kind == Ast_BasicDirective && - expr->BasicDirective.name == "caller_location") { + expr->BasicDirective.name.string == "caller_location") { init_core_source_code_location(ctx->checker); param_value.kind = ParameterValue_Location; o.type = t_source_code_location; @@ -2711,7 +2711,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t bool is_partial = false; if (at->tag != nullptr) { GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name; + String name = at->tag->BasicDirective.name.string; if (name == "partial") { is_partial = true; } else { @@ -2745,7 +2745,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t if (at->tag != nullptr) { GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name; + String name = at->tag->BasicDirective.name.string; if (name == "soa") { *type = make_soa_struct_fixed(ctx, e, at->elem, elem, count, generic_type); } else if (name == "simd") { @@ -2770,7 +2770,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t if (at->tag != nullptr) { GB_ASSERT(at->tag->kind == Ast_BasicDirective); - String name = at->tag->BasicDirective.name; + String name = at->tag->BasicDirective.name.string; if (name == "soa") { *type = make_soa_struct_slice(ctx, e, at->elem, elem); } else { @@ -2790,7 +2790,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t Type *elem = check_type(ctx, dat->elem); if (dat->tag != nullptr) { GB_ASSERT(dat->tag->kind == Ast_BasicDirective); - String name = dat->tag->BasicDirective.name; + String name = dat->tag->BasicDirective.name.string; if (name == "soa") { *type = make_soa_struct_dynamic_array(ctx, e, dat->elem, elem); } else { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8bd5aaa37..08c9445bd 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8887,7 +8887,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, switch (id) { case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); - String name = bd->name; + String name = bd->name.string; GB_ASSERT(name == "location"); String procedure = p->entity->token.string; TokenPos pos = ast_token(ce->proc).pos; @@ -11515,7 +11515,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { case_ast_node(bd, BasicDirective, expr); TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name)); + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); case_end; case_ast_node(i, Implicit, expr); diff --git a/src/parser.cpp b/src/parser.cpp index b8d53e724..a5180b4dd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,109 +1,4 @@ -Token ast_token(Ast *node) { - switch (node->kind) { - case Ast_Ident: return node->Ident.token; - case Ast_Implicit: return node->Implicit; - case Ast_Undef: return node->Undef; - case Ast_BasicLit: return node->BasicLit.token; - case Ast_BasicDirective: return node->BasicDirective.token; - case Ast_ProcGroup: return node->ProcGroup.token; - case Ast_ProcLit: return ast_token(node->ProcLit.type); - case Ast_CompoundLit: - if (node->CompoundLit.type != nullptr) { - return ast_token(node->CompoundLit.type); - } - return node->CompoundLit.open; - - case Ast_TagExpr: return node->TagExpr.token; - case Ast_BadExpr: return node->BadExpr.begin; - case Ast_UnaryExpr: return node->UnaryExpr.op; - case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left); - case Ast_ParenExpr: return node->ParenExpr.open; - case Ast_CallExpr: return ast_token(node->CallExpr.proc); - case Ast_SelectorExpr: - if (node->SelectorExpr.selector != nullptr) { - return ast_token(node->SelectorExpr.selector); - } - return node->SelectorExpr.token; - case Ast_SelectorCallExpr: - if (node->SelectorCallExpr.expr != nullptr) { - return ast_token(node->SelectorCallExpr.expr); - } - return node->SelectorCallExpr.token; - case Ast_ImplicitSelectorExpr: - if (node->ImplicitSelectorExpr.selector != nullptr) { - return ast_token(node->ImplicitSelectorExpr.selector); - } - return node->ImplicitSelectorExpr.token; - case Ast_IndexExpr: return node->IndexExpr.open; - case Ast_SliceExpr: return node->SliceExpr.open; - case Ast_Ellipsis: return node->Ellipsis.token; - case Ast_FieldValue: return node->FieldValue.eq; - case Ast_DerefExpr: return node->DerefExpr.op; - case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); - case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x); - case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr); - case Ast_TypeCast: return node->TypeCast.token; - case Ast_AutoCast: return node->AutoCast.token; - case Ast_InlineAsmExpr: return node->InlineAsmExpr.token; - - case Ast_BadStmt: return node->BadStmt.begin; - case Ast_EmptyStmt: return node->EmptyStmt.token; - case Ast_ExprStmt: return ast_token(node->ExprStmt.expr); - case Ast_TagStmt: return node->TagStmt.token; - case Ast_AssignStmt: return node->AssignStmt.op; - case Ast_BlockStmt: return node->BlockStmt.open; - case Ast_IfStmt: return node->IfStmt.token; - case Ast_WhenStmt: return node->WhenStmt.token; - case Ast_ReturnStmt: return node->ReturnStmt.token; - case Ast_ForStmt: return node->ForStmt.token; - case Ast_RangeStmt: return node->RangeStmt.token; - case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token; - case Ast_CaseClause: return node->CaseClause.token; - case Ast_SwitchStmt: return node->SwitchStmt.token; - case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; - case Ast_DeferStmt: return node->DeferStmt.token; - case Ast_BranchStmt: return node->BranchStmt.token; - case Ast_UsingStmt: return node->UsingStmt.token; - - case Ast_BadDecl: return node->BadDecl.begin; - case Ast_Label: return node->Label.token; - - case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]); - case Ast_PackageDecl: return node->PackageDecl.token; - case Ast_ImportDecl: return node->ImportDecl.token; - case Ast_ForeignImportDecl: return node->ForeignImportDecl.token; - - case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token; - - case Ast_Attribute: - return node->Attribute.token; - - case Ast_Field: - if (node->Field.names.count > 0) { - return ast_token(node->Field.names[0]); - } - return ast_token(node->Field.type); - case Ast_FieldList: - return node->FieldList.token; - - case Ast_TypeidType: return node->TypeidType.token; - case Ast_HelperType: return node->HelperType.token; - case Ast_DistinctType: return node->DistinctType.token; - case Ast_PolyType: return node->PolyType.token; - case Ast_ProcType: return node->ProcType.token; - case Ast_RelativeType: return ast_token(node->RelativeType.tag); - case Ast_PointerType: return node->PointerType.token; - case Ast_ArrayType: return node->ArrayType.token; - case Ast_DynamicArrayType: return node->DynamicArrayType.token; - case Ast_StructType: return node->StructType.token; - case Ast_UnionType: return node->UnionType.token; - case Ast_EnumType: return node->EnumType.token; - case Ast_BitSetType: return node->BitSetType.token; - case Ast_MapType: return node->MapType.token; - } - - return empty_token; -} +#include "parser_pos.cpp" Token token_end_of_line(AstFile *f, Token tok) { u8 const *start = f->tokenizer.start + tok.pos.offset; @@ -474,12 +369,15 @@ Ast *clone_ast(Ast *node) { void error(Ast *node, char const *fmt, ...) { Token token = {}; + TokenPos end_pos = {}; if (node != nullptr) { token = ast_token(node); + end_pos = ast_end_pos(node); } + va_list va; va_start(va, fmt); - error_va(token.pos, fmt, va); + error_va(token.pos, end_pos, fmt, va); va_end(va); if (node != nullptr && node->file != nullptr) { node->file->error_count += 1; @@ -501,16 +399,28 @@ void error_no_newline(Ast *node, char const *fmt, ...) { } void warning(Ast *node, char const *fmt, ...) { + Token token = {}; + TokenPos end_pos = {}; + if (node != nullptr) { + token = ast_token(node); + end_pos = ast_end_pos(node); + } va_list va; va_start(va, fmt); - warning_va(ast_token(node).pos, fmt, va); + warning_va(token.pos, end_pos, fmt, va); va_end(va); } void syntax_error(Ast *node, char const *fmt, ...) { + Token token = {}; + TokenPos end_pos = {}; + if (node != nullptr) { + token = ast_token(node); + end_pos = ast_end_pos(node); + } va_list va; va_start(va, fmt); - syntax_error_va(ast_token(node).pos, fmt, va); + syntax_error_va(token.pos, end_pos, fmt, va); va_end(va); if (node != nullptr && node->file != nullptr) { node->file->error_count += 1; @@ -682,7 +592,7 @@ Ast *ast_basic_lit(AstFile *f, Token basic_lit) { return result; } -Ast *ast_basic_directive(AstFile *f, Token token, String name) { +Ast *ast_basic_directive(AstFile *f, Token token, Token name) { Ast *result = alloc_ast_node(f, Ast_BasicDirective); result->BasicDirective.token = token; result->BasicDirective.name = name; @@ -2042,27 +1952,27 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (name.string == "type") { return ast_helper_type(f, token, parse_type(f)); } else if (name.string == "file") { - return ast_basic_directive(f, token, name.string); - } else if (name.string == "line") { return ast_basic_directive(f, token, name.string); - } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string); - } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string); + return ast_basic_directive(f, token, name); + } else if (name.string == "line") { return ast_basic_directive(f, token, name); + } else if (name.string == "procedure") { return ast_basic_directive(f, token, name); + } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name); } else if (name.string == "location") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); return parse_call_expr(f, tag); } else if (name.string == "load") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); return parse_call_expr(f, tag); } else if (name.string == "assert") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); return parse_call_expr(f, tag); } else if (name.string == "defined") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); return parse_call_expr(f, tag); } else if (name.string == "config") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); return parse_call_expr(f, tag); } else if (name.string == "soa" || name.string == "simd") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); switch (type->kind) { @@ -2074,7 +1984,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { } return original_type; } else if (name.string == "partial") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); switch (type->kind) { @@ -2107,7 +2017,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { } return operand; } else if (name.string == "relative") { - Ast *tag = ast_basic_directive(f, token, name.string); + Ast *tag = ast_basic_directive(f, token, name); tag = parse_call_expr(f, tag); Ast *type = parse_type(f); return ast_relative_type(f, tag, type); @@ -4554,10 +4464,10 @@ Ast *parse_stmt(AstFile *f) { } return s; } else if (tag == "assert") { - Ast *t = ast_basic_directive(f, hash_token, tag); + Ast *t = ast_basic_directive(f, hash_token, name); return ast_expr_stmt(f, parse_call_expr(f, t)); } else if (tag == "panic") { - Ast *t = ast_basic_directive(f, hash_token, tag); + Ast *t = ast_basic_directive(f, hash_token, name); return ast_expr_stmt(f, parse_call_expr(f, t)); } else if (name.string == "force_inline" || name.string == "force_no_inline") { diff --git a/src/parser.hpp b/src/parser.hpp index 77d5f1b02..89f714aaa 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -286,8 +286,8 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { Token token; \ }) \ AST_KIND(BasicDirective, "basic directive", struct { \ - Token token; \ - String name; \ + Token token; \ + Token name; \ }) \ AST_KIND(Ellipsis, "ellipsis", struct { \ Token token; \ @@ -324,7 +324,7 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(SelectorCallExpr, "selector call expression", struct { Token token; Ast *expr, *call; bool modified_call; }) \ AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \ - AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \ + AST_KIND(DerefExpr, "dereference expression", struct { Ast *expr; Token op; }) \ AST_KIND(SliceExpr, "slice expression", struct { \ Ast *expr; \ Token open, close; \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp new file mode 100644 index 000000000..c5ad89604 --- /dev/null +++ b/src/parser_pos.cpp @@ -0,0 +1,331 @@ +Token ast_token(Ast *node) { + switch (node->kind) { + case Ast_Ident: return node->Ident.token; + case Ast_Implicit: return node->Implicit; + case Ast_Undef: return node->Undef; + case Ast_BasicLit: return node->BasicLit.token; + case Ast_BasicDirective: return node->BasicDirective.token; + case Ast_ProcGroup: return node->ProcGroup.token; + case Ast_ProcLit: return ast_token(node->ProcLit.type); + case Ast_CompoundLit: + if (node->CompoundLit.type != nullptr) { + return ast_token(node->CompoundLit.type); + } + return node->CompoundLit.open; + + case Ast_TagExpr: return node->TagExpr.token; + case Ast_BadExpr: return node->BadExpr.begin; + case Ast_UnaryExpr: return node->UnaryExpr.op; + case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left); + case Ast_ParenExpr: return node->ParenExpr.open; + case Ast_CallExpr: return ast_token(node->CallExpr.proc); + case Ast_SelectorExpr: + if (node->SelectorExpr.selector != nullptr) { + return ast_token(node->SelectorExpr.selector); + } + return node->SelectorExpr.token; + case Ast_SelectorCallExpr: + if (node->SelectorCallExpr.expr != nullptr) { + return ast_token(node->SelectorCallExpr.expr); + } + return node->SelectorCallExpr.token; + case Ast_ImplicitSelectorExpr: + if (node->ImplicitSelectorExpr.selector != nullptr) { + return ast_token(node->ImplicitSelectorExpr.selector); + } + return node->ImplicitSelectorExpr.token; + case Ast_IndexExpr: return node->IndexExpr.open; + case Ast_SliceExpr: return node->SliceExpr.open; + case Ast_Ellipsis: return node->Ellipsis.token; + case Ast_FieldValue: return node->FieldValue.eq; + case Ast_DerefExpr: return node->DerefExpr.op; + case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); + case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x); + case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr); + case Ast_TypeCast: return node->TypeCast.token; + case Ast_AutoCast: return node->AutoCast.token; + case Ast_InlineAsmExpr: return node->InlineAsmExpr.token; + + case Ast_BadStmt: return node->BadStmt.begin; + case Ast_EmptyStmt: return node->EmptyStmt.token; + case Ast_ExprStmt: return ast_token(node->ExprStmt.expr); + case Ast_TagStmt: return node->TagStmt.token; + case Ast_AssignStmt: return node->AssignStmt.op; + case Ast_BlockStmt: return node->BlockStmt.open; + case Ast_IfStmt: return node->IfStmt.token; + case Ast_WhenStmt: return node->WhenStmt.token; + case Ast_ReturnStmt: return node->ReturnStmt.token; + case Ast_ForStmt: return node->ForStmt.token; + case Ast_RangeStmt: return node->RangeStmt.token; + case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token; + case Ast_CaseClause: return node->CaseClause.token; + case Ast_SwitchStmt: return node->SwitchStmt.token; + case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; + case Ast_DeferStmt: return node->DeferStmt.token; + case Ast_BranchStmt: return node->BranchStmt.token; + case Ast_UsingStmt: return node->UsingStmt.token; + + case Ast_BadDecl: return node->BadDecl.begin; + case Ast_Label: return node->Label.token; + + case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]); + case Ast_PackageDecl: return node->PackageDecl.token; + case Ast_ImportDecl: return node->ImportDecl.token; + case Ast_ForeignImportDecl: return node->ForeignImportDecl.token; + + case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token; + + case Ast_Attribute: + return node->Attribute.token; + + case Ast_Field: + if (node->Field.names.count > 0) { + return ast_token(node->Field.names[0]); + } + return ast_token(node->Field.type); + case Ast_FieldList: + return node->FieldList.token; + + case Ast_TypeidType: return node->TypeidType.token; + case Ast_HelperType: return node->HelperType.token; + case Ast_DistinctType: return node->DistinctType.token; + case Ast_PolyType: return node->PolyType.token; + case Ast_ProcType: return node->ProcType.token; + case Ast_RelativeType: return ast_token(node->RelativeType.tag); + case Ast_PointerType: return node->PointerType.token; + case Ast_ArrayType: return node->ArrayType.token; + case Ast_DynamicArrayType: return node->DynamicArrayType.token; + case Ast_StructType: return node->StructType.token; + case Ast_UnionType: return node->UnionType.token; + case Ast_EnumType: return node->EnumType.token; + case Ast_BitSetType: return node->BitSetType.token; + case Ast_MapType: return node->MapType.token; + } + + return empty_token; +} + +TokenPos token_pos_end(Token const &token) { + TokenPos pos = token.pos; + pos.offset += cast(i32)token.string.len; + for (isize i = 0; i < token.string.len; i++) { + // TODO(bill): This assumes ASCII + char c = token.string[i]; + if (c == '\n') { + pos.line += 1; + pos.column = 1; + } else { + pos.column += 1; + } + } + return pos; +} + +Token ast_end_token(Ast *node) { + GB_ASSERT(node != nullptr); + + switch (node->kind) { + case Ast_Ident: return node->Ident.token; + case Ast_Implicit: return node->Implicit; + case Ast_Undef: return node->Undef; + case Ast_BasicLit: return node->BasicLit.token; + case Ast_BasicDirective: return node->BasicDirective.token; + case Ast_ProcGroup: return node->ProcGroup.close; + case Ast_ProcLit: + if (node->ProcLit.body) { + return ast_end_token(node->ProcLit.body); + } + return ast_end_token(node->ProcLit.type); + case Ast_CompoundLit: + return node->CompoundLit.close; + + case Ast_BadExpr: return node->BadExpr.end; + case Ast_TagExpr: return ast_end_token(node->TagExpr.expr); + case Ast_UnaryExpr: return ast_end_token(node->UnaryExpr.expr); + case Ast_BinaryExpr: return ast_end_token(node->BinaryExpr.right); + case Ast_ParenExpr: return node->ParenExpr.close; + case Ast_CallExpr: return node->CallExpr.close; + case Ast_SelectorExpr: + return ast_end_token(node->SelectorExpr.selector); + case Ast_SelectorCallExpr: + return ast_end_token(node->SelectorCallExpr.call); + case Ast_ImplicitSelectorExpr: + return ast_end_token(node->SelectorExpr.selector); + case Ast_IndexExpr: return node->IndexExpr.close; + case Ast_SliceExpr: return node->SliceExpr.close; + case Ast_Ellipsis: + if (node->Ellipsis.expr) { + return ast_end_token(node->Ellipsis.expr); + } + return node->Ellipsis.token; + case Ast_FieldValue: return ast_end_token(node->FieldValue.value); + case Ast_DerefExpr: return node->DerefExpr.op; + case Ast_TernaryIfExpr: return ast_end_token(node->TernaryIfExpr.y); + case Ast_TernaryWhenExpr: return ast_end_token(node->TernaryWhenExpr.y); + case Ast_TypeAssertion: return ast_end_token(node->TypeAssertion.type); + case Ast_TypeCast: return ast_end_token(node->TypeCast.expr); + case Ast_AutoCast: return ast_end_token(node->AutoCast.expr); + case Ast_InlineAsmExpr: return node->InlineAsmExpr.close; + + case Ast_BadStmt: return node->BadStmt.end; + case Ast_EmptyStmt: return node->EmptyStmt.token; + case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr); + case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt); + case Ast_AssignStmt: + if (node->AssignStmt.rhs.count > 0) { + return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]); + } + return node->AssignStmt.op; + case Ast_BlockStmt: return node->BlockStmt.close; + case Ast_IfStmt: + if (node->IfStmt.else_stmt) { + return ast_end_token(node->IfStmt.else_stmt); + } + return ast_end_token(node->IfStmt.body); + case Ast_WhenStmt: + if (node->WhenStmt.else_stmt) { + return ast_end_token(node->WhenStmt.else_stmt); + } + return ast_end_token(node->WhenStmt.body); + case Ast_ReturnStmt: + if (node->ReturnStmt.results.count > 0) { + return ast_end_token(node->ReturnStmt.results[node->ReturnStmt.results.count-1]); + } + return node->ReturnStmt.token; + case Ast_ForStmt: return ast_end_token(node->ForStmt.body); + case Ast_RangeStmt: return ast_end_token(node->RangeStmt.body); + case Ast_UnrollRangeStmt: return ast_end_token(node->UnrollRangeStmt.body); + case Ast_CaseClause: + if (node->CaseClause.stmts.count) { + return ast_end_token(node->CaseClause.stmts[node->CaseClause.stmts.count-1]); + } else if (node->CaseClause.list.count) { + return ast_end_token(node->CaseClause.list[node->CaseClause.list.count-1]); + } + return node->CaseClause.token; + case Ast_SwitchStmt: return ast_end_token(node->SwitchStmt.body); + case Ast_TypeSwitchStmt: return ast_end_token(node->TypeSwitchStmt.body); + case Ast_DeferStmt: return ast_end_token(node->DeferStmt.stmt); + case Ast_BranchStmt: + if (node->BranchStmt.label) { + return ast_end_token(node->BranchStmt.label); + } + return node->BranchStmt.token; + case Ast_UsingStmt: + if (node->UsingStmt.list.count > 0) { + return ast_end_token(node->UsingStmt.list[node->UsingStmt.list.count-1]); + } + return node->UsingStmt.token; + + case Ast_BadDecl: return node->BadDecl.end; + case Ast_Label: + if (node->Label.name) { + return ast_end_token(node->Label.name); + } + return node->Label.token; + + case Ast_ValueDecl: + if (node->ValueDecl.values.count > 0) { + return ast_end_token(node->ValueDecl.values[node->ValueDecl.values.count-1]); + } + if (node->ValueDecl.type) { + return ast_end_token(node->ValueDecl.type); + } + if (node->ValueDecl.names.count > 0) { + return ast_end_token(node->ValueDecl.names[node->ValueDecl.names.count-1]); + } + return {}; + + case Ast_PackageDecl: return node->PackageDecl.name; + case Ast_ImportDecl: return node->ImportDecl.relpath; + case Ast_ForeignImportDecl: + if (node->ForeignImportDecl.filepaths.count > 0) { + return node->ForeignImportDecl.filepaths[node->ForeignImportDecl.filepaths.count-1]; + } + if (node->ForeignImportDecl.library_name.kind != Token_Invalid) { + return node->ForeignImportDecl.library_name; + } + return node->ForeignImportDecl.token; + + case Ast_ForeignBlockDecl: + return ast_end_token(node->ForeignBlockDecl.body); + + case Ast_Attribute: + if (node->Attribute.close.kind != Token_Invalid) { + return node->Attribute.close; + } + return ast_end_token(node->Attribute.elems[node->Attribute.elems.count-1]); + + case Ast_Field: + if (node->Field.tag.kind != Token_Invalid) { + return node->Field.tag; + } + if (node->Field.default_value) { + return ast_end_token(node->Field.default_value); + } + if (node->Field.type) { + return ast_end_token(node->Field.type); + } + return ast_end_token(node->Field.names[node->Field.names.count-1]); + case Ast_FieldList: + if (node->FieldList.list.count > 0) { + return ast_end_token(node->FieldList.list[node->FieldList.list.count-1]); + } + return node->FieldList.token; + + case Ast_TypeidType: + if (node->TypeidType.specialization) { + return ast_end_token(node->TypeidType.specialization); + } + return node->TypeidType.token; + case Ast_HelperType: return ast_end_token(node->HelperType.type); + case Ast_DistinctType: return ast_end_token(node->DistinctType.type); + case Ast_PolyType: + if (node->PolyType.specialization) { + return ast_end_token(node->PolyType.specialization); + } + return ast_end_token(node->PolyType.type); + case Ast_ProcType: + if (node->ProcType.results) { + return ast_end_token(node->ProcType.results); + } + if (node->ProcType.params) { + return ast_end_token(node->ProcType.params); + } + return node->ProcType.token; + case Ast_RelativeType: + return ast_end_token(node->RelativeType.type); + case Ast_PointerType: return ast_end_token(node->PointerType.type); + case Ast_ArrayType: return ast_end_token(node->ArrayType.elem); + case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem); + case Ast_StructType: + if (node->StructType.fields.count > 0) { + return ast_end_token(node->StructType.fields[node->StructType.fields.count-1]); + } + return node->StructType.token; + case Ast_UnionType: + if (node->UnionType.variants.count > 0) { + return ast_end_token(node->UnionType.variants[node->UnionType.variants.count-1]); + } + return node->UnionType.token; + case Ast_EnumType: + if (node->EnumType.fields.count > 0) { + return ast_end_token(node->EnumType.fields[node->EnumType.fields.count-1]); + } + if (node->EnumType.base_type) { + return ast_end_token(node->EnumType.base_type); + } + return node->EnumType.token; + case Ast_BitSetType: + if (node->BitSetType.underlying) { + return ast_end_token(node->BitSetType.underlying); + } + return ast_end_token(node->BitSetType.elem); + case Ast_MapType: return ast_end_token(node->MapType.value); + } + + return empty_token; +} + +TokenPos ast_end_pos(Ast *node) { + return token_pos_end(ast_end_token(node)); +} diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 3c44aaad4..826fccc04 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -423,7 +423,7 @@ void error_out(char const *fmt, ...) { } -bool show_error_on_line(TokenPos const &pos) { +bool show_error_on_line(TokenPos const &pos, TokenPos end) { if (!show_error_line()) { return false; } @@ -435,6 +435,8 @@ bool show_error_on_line(TokenPos const &pos) { if (the_line != nullptr) { String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); + // TODO(bill): This assumes ASCII + enum { MAX_LINE_LENGTH = 76, MAX_TAB_WIDTH = 8, @@ -462,15 +464,33 @@ bool show_error_on_line(TokenPos const &pos) { } error_out("\n\t"); - for (i32 i = 0; i < offset; i++) error_out(" "); - error_out("^\n"); - error_out("\n"); + for (i32 i = 0; i < offset; i++) { + error_out(" "); + } + error_out("^"); + if (end.file_id == pos.file_id) { + if (end.line > pos.line) { + for (i32 i = offset; i < line.len; i++) { + error_out("~"); + } + } else if (end.line == pos.line && end.column > pos.column) { + i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset)); + for (i32 i = 1; i < length-1; i++) { + error_out("~"); + } + if (length > 1) { + error_out("^"); + } + } + } + + error_out("\n\n"); return true; } return false; } -void error_va(TokenPos pos, char const *fmt, va_list va) { +void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); global_error_collector.count++; // NOTE(bill): Duplicate error, skip it @@ -481,7 +501,7 @@ void error_va(TokenPos pos, char const *fmt, va_list va) { error_out("%s %s\n", token_pos_to_string(pos), gb_bprintf_va(fmt, va)); - show_error_on_line(pos); + show_error_on_line(pos, end); } gb_mutex_unlock(&global_error_collector.mutex); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { @@ -489,9 +509,9 @@ void error_va(TokenPos pos, char const *fmt, va_list va) { } } -void warning_va(TokenPos const &pos, char const *fmt, va_list va) { +void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { if (global_warnings_as_errors()) { - error_va(pos, fmt, va); + error_va(pos, end, fmt, va); return; } gb_mutex_lock(&global_error_collector.mutex); @@ -505,7 +525,7 @@ void warning_va(TokenPos const &pos, char const *fmt, va_list va) { error_out("%s Warning: %s\n", token_pos_to_string(pos), gb_bprintf_va(fmt, va)); - show_error_on_line(pos); + show_error_on_line(pos, end); } } gb_mutex_unlock(&global_error_collector.mutex); @@ -537,7 +557,7 @@ void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { } -void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) { +void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); global_error_collector.count++; // NOTE(bill): Duplicate error, skip it @@ -546,7 +566,7 @@ void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) { error_out("%s Syntax Error: %s\n", token_pos_to_string(pos), gb_bprintf_va(fmt, va)); - show_error_on_line(pos); + show_error_on_line(pos, end); } else if (pos.line == 0) { error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); } @@ -557,9 +577,9 @@ void syntax_error_va(TokenPos const &pos, char const *fmt, va_list va) { } } -void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) { +void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { if (global_warnings_as_errors()) { - syntax_error_va(pos, fmt, va); + syntax_error_va(pos, end, fmt, va); return; } gb_mutex_lock(&global_error_collector.mutex); @@ -571,7 +591,7 @@ void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) { error_out("%s Syntax Warning: %s\n", token_pos_to_string(pos), gb_bprintf_va(fmt, va)); - show_error_on_line(pos); + show_error_on_line(pos, end); } else if (pos.line == 0) { error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); } @@ -584,14 +604,14 @@ void syntax_warning_va(TokenPos const &pos, char const *fmt, va_list va) { void warning(Token const &token, char const *fmt, ...) { va_list va; va_start(va, fmt); - warning_va(token.pos, fmt, va); + warning_va(token.pos, {}, fmt, va); va_end(va); } void error(Token const &token, char const *fmt, ...) { va_list va; va_start(va, fmt); - error_va(token.pos, fmt, va); + error_va(token.pos, {}, fmt, va); va_end(va); } @@ -600,7 +620,7 @@ void error(TokenPos pos, char const *fmt, ...) { va_start(va, fmt); Token token = {}; token.pos = pos; - error_va(pos, fmt, va); + error_va(pos, {}, fmt, va); va_end(va); } @@ -615,21 +635,21 @@ void error_line(char const *fmt, ...) { void syntax_error(Token const &token, char const *fmt, ...) { va_list va; va_start(va, fmt); - syntax_error_va(token.pos, fmt, va); + syntax_error_va(token.pos, {}, fmt, va); va_end(va); } void syntax_error(TokenPos pos, char const *fmt, ...) { va_list va; va_start(va, fmt); - syntax_error_va(pos, fmt, va); + syntax_error_va(pos, {}, fmt, va); va_end(va); } void syntax_warning(Token const &token, char const *fmt, ...) { va_list va; va_start(va, fmt); - syntax_warning_va(token.pos, fmt, va); + syntax_warning_va(token.pos, {}, fmt, va); va_end(va); } @@ -748,7 +768,7 @@ void tokenizer_err(Tokenizer *t, char const *msg, ...) { pos.offset = cast(i32)(t->read_curr - t->start); va_start(va, msg); - syntax_error_va(pos, msg, va); + syntax_error_va(pos, {}, msg, va); va_end(va); t->error_count++; @@ -762,7 +782,7 @@ void tokenizer_err(Tokenizer *t, TokenPos const &pos, char const *msg, ...) { } va_start(va, msg); - syntax_error_va(pos, msg, va); + syntax_error_va(pos, {}, msg, va); va_end(va); t->error_count++; -- cgit v1.2.3