diff options
| author | Isaac Andrade <andradei@proton.me> | 2024-08-27 18:51:58 -0600 |
|---|---|---|
| committer | Isaac Andrade <andradei@proton.me> | 2024-08-27 18:51:58 -0600 |
| commit | 45322023e30a372e4a22fe51a2841b07d68ebfc6 (patch) | |
| tree | 1de0b1961a147430541d3a7c408e0055d1f61b99 /src | |
| parent | 7d94810d016dc12327cd390aeb618a7753418295 (diff) | |
| parent | 9684ade23e80540da9a44ee33e7a3b4c14f85ea0 (diff) | |
Merge branch 'master' of github.com:odin-lang/Odin into posix-linux
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_builtin.cpp | 61 | ||||
| -rw-r--r-- | src/check_expr.cpp | 41 | ||||
| -rw-r--r-- | src/check_stmt.cpp | 11 | ||||
| -rw-r--r-- | src/checker.cpp | 38 | ||||
| -rw-r--r-- | src/checker_builtin_procs.hpp | 7 | ||||
| -rw-r--r-- | src/llvm_backend_debug.cpp | 16 | ||||
| -rw-r--r-- | src/llvm_backend_utility.cpp | 2 | ||||
| -rw-r--r-- | src/parser.cpp | 48 | ||||
| -rw-r--r-- | src/parser.hpp | 6 |
9 files changed, 197 insertions, 33 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1c4b88101..3742caeda 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2048,6 +2048,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return ok; } + if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) { + if (build_context.metrics.arch == TargetArch_riscv64) { + if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) { + error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features"); + } + } + } + switch (id) { default: GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); @@ -5665,6 +5673,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } break; + + case BuiltinProc_type_has_shared_fields: + { + Type *u = check_type(c, ce->args[0]); + Type *ut = base_type(u); + if (ut == nullptr || ut == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(ut); + error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + Type *v = check_type(c, ce->args[1]); + Type *vt = base_type(v); + if (vt == nullptr || vt == t_invalid) { + error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(vt); + error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + bool is_shared = true; + + for (Entity *v_field : vt->Struct.fields) { + bool found = false; + for (Entity *u_field : ut->Struct.fields) { + if (v_field->token.string == u_field->token.string && + are_types_identical(v_field->type, u_field->type)) { + found = true; + break; + } + } + + if (!found) { + is_shared = false; + break; + } + } + + operand->mode = Addressing_Constant; + operand->value = exact_value_bool(is_shared); + operand->type = t_untyped_bool; + break; + } + case BuiltinProc_type_field_type: { Operand op = {}; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9cdba2710..7ac09ac56 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1180,11 +1180,15 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ LIT(article), LIT(context_name)); } else { + ERROR_BLOCK(); error(operand->expr, "Cannot assign '%s', a type, to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); + if (type && are_types_identical(type, t_any)) { + error_line("\tSuggestion: 'typeid_of(%s)'", expr_str); + } } break; default: @@ -3782,10 +3786,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ // NOTE(bill): Allow comparisons between types if (is_ise_expr(be->left)) { // Evalute the right before the left for an '.X' expression - check_expr_or_type(c, y, be->right, type_hint); + check_expr_or_type(c, y, be->right, nullptr /* ignore type hint */); check_expr_or_type(c, x, be->left, y->type); } else { - check_expr_or_type(c, x, be->left, type_hint); + check_expr_or_type(c, x, be->left, nullptr /* ignore type hint */); check_expr_or_type(c, y, be->right, x->type); } bool xt = x->mode == Addressing_Type; @@ -4658,7 +4662,8 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { if (value) *value = 0; - return false; + // NOTE(bill): return true here to propagate the errors better + return true; } Type *index_type = t_int; @@ -4879,7 +4884,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; - return tav.value;; + return tav.value; } } @@ -4954,7 +4959,6 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper return value; } } - if (success_) *success_ = true; return value; } else if (value.kind == ExactValue_Quaternion) { @@ -7625,7 +7629,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3); s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string)); - TypeTuple *tuple = get_record_polymorphic_params(e->type); + TypeTuple *tuple = get_record_polymorphic_params(bt); if (tuple != nullptr) for_array(i, tuple->variables) { Entity *v = tuple->variables[i]; String name = v->token.string; @@ -7640,8 +7644,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = write_type_to_string(s, v->type, false); } } else if (v->kind == Entity_Constant) { - s = gb_string_append_fmt(s, "="); - s = write_exact_value_to_string(s, v->Constant.value); + if (v->Constant.value.kind != ExactValue_Invalid) { + s = gb_string_append_fmt(s, "="); + s = write_exact_value_to_string(s, v->Constant.value); + } } } s = gb_string_append_fmt(s, ")"); @@ -10055,6 +10061,22 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * is_constant = o->mode == Addressing_Constant; } + if (elem->kind == Ast_BinaryExpr) { + switch (elem->BinaryExpr.op.kind) { + case Token_Or: + { + gbString x = expr_to_string(elem->BinaryExpr.left); + gbString y = expr_to_string(elem->BinaryExpr.right); + gbString e = expr_to_string(elem); + error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e); + gb_string_free(e); + gb_string_free(y); + gb_string_free(x); + } + break; + } + } + check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); if (o->mode == Addressing_Constant) { i64 lower = t->BitSet.lower; @@ -10544,7 +10566,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, o->expr = node; return kind; } else if (ok && !is_type_matrix(t)) { - ExactValue value = type_and_value_of_expr(ie->expr).value; + TypeAndValue tav = type_and_value_of_expr(ie->expr); + ExactValue value = tav.value; o->mode = Addressing_Constant; bool success = false; bool finish = false; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 12156df01..c8717ba98 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -199,6 +199,9 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit) } break; + case Ast_DeferStmt: + return check_has_break(stmt->DeferStmt.stmt, label, implicit); + case Ast_BlockStmt: return check_has_break_list(stmt->BlockStmt.stmts, label, implicit); @@ -1695,7 +1698,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } } } - bool is_ptr = type_deref(operand.type); + bool is_ptr = is_type_pointer(type_deref(operand.type)); Type *t = base_type(type_deref(operand.type)); switch (t->kind) { @@ -1735,6 +1738,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; case Type_EnumeratedArray: + is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr; array_add(&vals, t->EnumeratedArray.elem); array_add(&vals, t->EnumeratedArray.index); break; @@ -2706,6 +2710,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(bs->label, "A branch statement's label name must be an identifier"); return; } + Ast *ident = bs->label; String name = ident->Ident.token.string; Operand o = {}; @@ -2737,6 +2742,10 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) break; } + + if (ctx->in_defer) { + error(bs->label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(token.string)); + } } case_end; diff --git a/src/checker.cpp b/src/checker.cpp index b24a7afdb..fdc1ce840 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3174,8 +3174,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_prefix") { if (ev.kind == ExactValue_String) { - String link_prefix = ev.value_string; - if (!is_foreign_name_valid(link_prefix)) { + String link_prefix = string_trim_whitespace(ev.value_string); + if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) { error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); } else { c->foreign_context.link_prefix = link_prefix; @@ -3186,8 +3186,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_suffix") { if (ev.kind == ExactValue_String) { - String link_suffix = ev.value_string; - if (!is_foreign_name_valid(link_suffix)) { + String link_suffix = string_trim_whitespace(ev.value_string); + if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) { error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); } else { c->foreign_context.link_suffix = link_suffix; @@ -3489,7 +3489,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3501,7 +3501,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { @@ -3774,7 +3774,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3785,7 +3785,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { @@ -4532,7 +4532,9 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n case_end; case_ast_node(fb, ForeignBlockDecl, decl); - check_add_foreign_block_decl(c, decl); + if (curr_file != nullptr) { + array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl); + } case_end; default: @@ -4548,6 +4550,14 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source if (curr_file == nullptr) { + // For 'foreign' block statements that are not in file scope. + for_array(decl_index, nodes) { + Ast *decl = nodes[decl_index]; + if (decl->kind == Ast_ForeignBlockDecl) { + check_add_foreign_block_decl(c, decl); + } + } + for_array(decl_index, nodes) { Ast *decl = nodes[decl_index]; if (decl->kind == Ast_WhenStmt) { @@ -5512,6 +5522,16 @@ gb_internal void check_import_entities(Checker *c) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); + for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) { + check_add_foreign_block_decl(&ctx, decl); + } + array_clear(&f->delayed_decls_queues[AstDelayQueue_ForeignBlock]); + } + + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + reset_checker_context(&ctx, f, &untyped); + for (Ast *expr : f->delayed_decls_queues[AstDelayQueue_Expr]) { Operand o = {}; check_expr(&ctx, &o, expr); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index ef07938c7..2dfd570e4 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -99,6 +99,7 @@ enum BuiltinProcId { BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_data, +BuiltinProc__atomic_begin, BuiltinProc_atomic_type_is_lock_free, BuiltinProc_atomic_thread_fence, BuiltinProc_atomic_signal_fence, @@ -124,6 +125,7 @@ enum BuiltinProcId { BuiltinProc_atomic_compare_exchange_strong_explicit, BuiltinProc_atomic_compare_exchange_weak, BuiltinProc_atomic_compare_exchange_weak_explicit, +BuiltinProc__atomic_end, BuiltinProc_fixed_point_mul, BuiltinProc_fixed_point_div, @@ -313,6 +315,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_map_info, BuiltinProc_type_map_cell_info, + BuiltinProc_type_has_shared_fields, + BuiltinProc__type_end, BuiltinProc_procedure_of, @@ -436,6 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -461,6 +466,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -647,6 +653,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index c896f889d..5d90dccea 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -55,6 +55,16 @@ gb_internal void lb_debug_file_line(lbModule *m, Ast *node, LLVMMetadataRef *fil } } +gb_internal LLVMMetadataRef lb_debug_procedure_parameters(lbModule *m, Type *type) { + if (is_type_proc(type)) { + return lb_debug_type(m, t_rawptr); + } + if (type->kind == Type_Tuple && type->Tuple.variables.count == 1) { + return lb_debug_procedure_parameters(m, type->Tuple.variables[0]->type); + } + return lb_debug_type(m, type); +} + gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) { i64 size = type_size_of(type); // Check size gb_unused(size); @@ -78,7 +88,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (type->Proc.result_count == 0) { parameters[param_index++] = nullptr; } else { - parameters[param_index++] = lb_debug_type(m, type->Proc.results); + parameters[param_index++] = lb_debug_procedure_parameters(m, type->Proc.results); } LLVMMetadataRef file = nullptr; @@ -88,7 +98,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (e->kind != Entity_Variable) { continue; } - parameters[param_index] = lb_debug_type(m, e->type); + parameters[param_index] = lb_debug_procedure_parameters(m, e->type); param_index += 1; } @@ -969,7 +979,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { return lb_debug_struct(m, type, bt, name, scope, file, line); } - case Type_Struct: return lb_debug_struct(m, type, base_type(type), name, scope, file, line); + case Type_Struct: return lb_debug_struct(m, type, bt, name, scope, file, line); case Type_Slice: return lb_debug_slice(m, type, name, scope, file, line); case Type_DynamicArray: return lb_debug_dynamic_array(m, type, name, scope, file, line); case Type_Union: return lb_debug_union(m, type, name, scope, file, line); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 68c1e9d1e..f63c42ab9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -263,7 +263,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); return res; - } else if (is_type_array_like(src) && is_type_simd_vector(dst)) { + } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) { unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst)); lbValue ptr = lb_address_from_load_or_generate_local(p, value); if (lb_try_update_alignment(ptr, align)) { diff --git a/src/parser.cpp b/src/parser.cpp index 5796012d9..e3143dd33 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1921,6 +1921,9 @@ gb_internal Array<Ast *> parse_enum_field_list(AstFile *f) { f->curr_token.kind != Token_EOF) { CommentGroup *docs = f->lead_comment; CommentGroup *comment = nullptr; + + parse_enforce_tabs(f); + Ast *name = parse_value(f); Ast *value = nullptr; if (f->curr_token.kind == Token_Eq) { @@ -2259,6 +2262,7 @@ gb_internal Array<Ast *> parse_union_variant_list(AstFile *f) { auto variants = array_make<Ast *>(ast_allocator(f)); while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { + parse_enforce_tabs(f); Ast *type = parse_type(f); if (type->kind != Ast_BadExpr) { array_add(&variants, type); @@ -4274,6 +4278,7 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { + if (!is_signature) parse_enforce_tabs(f); u32 flags = parse_field_prefixes(f); Ast *param = parse_var_type(f, allow_ellipsis, allow_typeid_token); if (param->kind == Ast_Ellipsis) { @@ -4363,6 +4368,8 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl f->curr_token.kind != Token_EOF && f->curr_token.kind != Token_Semicolon) { CommentGroup *docs = f->lead_comment; + + if (!is_signature) parse_enforce_tabs(f); u32 set_flags = parse_field_prefixes(f); Token tag = {}; Array<Ast *> names = parse_ident_list(f, allow_poly_names); @@ -4532,6 +4539,10 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { return ast_bad_stmt(f, f->curr_token, f->curr_token); } + Ast *top_if_stmt = nullptr; + + Ast *prev_if_stmt = nullptr; +if_else_chain:; Token token = expect_token(f, Token_if); Ast *init = nullptr; Ast *cond = nullptr; @@ -4573,12 +4584,24 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { ignore_strict_style = true; } skip_possible_newline_for_literal(f, ignore_strict_style); + + Ast *curr_if_stmt = ast_if_stmt(f, token, init, cond, body, nullptr); + if (top_if_stmt == nullptr) { + top_if_stmt = curr_if_stmt; + } + if (prev_if_stmt != nullptr) { + prev_if_stmt->IfStmt.else_stmt = curr_if_stmt; + } + if (f->curr_token.kind == Token_else) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { case Token_if: - else_stmt = parse_if_stmt(f); - break; + // NOTE(bill): Instead of relying on recursive descent for an if-else chain + // we can just inline the tail-recursion manually with a simple loop like + // construct using a `goto` + prev_if_stmt = curr_if_stmt; + goto if_else_chain; case Token_OpenBrace: else_stmt = parse_block_stmt(f, false); break; @@ -4593,7 +4616,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { } } - return ast_if_stmt(f, token, init, cond, body, else_stmt); + curr_if_stmt->IfStmt.else_stmt = else_stmt; + + return top_if_stmt; } gb_internal Ast *parse_when_stmt(AstFile *f) { @@ -5357,6 +5382,11 @@ gb_internal u64 check_vet_flags(AstFile *file) { gb_internal void parse_enforce_tabs(AstFile *f) { + // Checks to see if tabs have been used for indentation + if ((check_vet_flags(f) & VetFlag_Tabs) == 0) { + return; + } + Token prev = f->prev_token; Token curr = f->curr_token; if (prev.pos.line < curr.pos.line) { @@ -5373,6 +5403,10 @@ gb_internal void parse_enforce_tabs(AstFile *f) { isize len = end-it; for (isize i = 0; i < len; i++) { + if (it[i] == '/') { + // ignore comments + break; + } if (it[i] == ' ') { syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation"); break; @@ -5387,11 +5421,7 @@ gb_internal Array<Ast *> parse_stmt_list(AstFile *f) { while (f->curr_token.kind != Token_case && f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { - - // Checks to see if tabs have been used for indentation - if (check_vet_flags(f) & VetFlag_Tabs) { - parse_enforce_tabs(f); - } + parse_enforce_tabs(f); Ast *stmt = parse_stmt(f); if (stmt && stmt->kind != Ast_EmptyStmt) { @@ -6416,7 +6446,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->total_file_decl_count += calc_decl_count(stmt); - if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl) { + if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl || stmt->kind == Ast_ForeignBlockDecl) { f->delayed_decl_count += 1; } } diff --git a/src/parser.hpp b/src/parser.hpp index 565a8e621..d5117a31e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -82,6 +82,7 @@ enum AstFileFlag : u32 { enum AstDelayQueueKind { AstDelayQueue_Import, AstDelayQueue_Expr, + AstDelayQueue_ForeignBlock, AstDelayQueue_COUNT, }; @@ -885,4 +886,7 @@ gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) { gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind); gb_internal gbString expr_to_string(Ast *expression); -gb_internal bool allow_field_separator(AstFile *f);
\ No newline at end of file +gb_internal bool allow_field_separator(AstFile *f); + + +gb_internal void parse_enforce_tabs(AstFile *f);
\ No newline at end of file |