diff --git a/build.bat b/build.bat index 23bf7a358..f6653e051 100644 --- a/build.bat +++ b/build.bat @@ -30,10 +30,8 @@ set linker_flags= -incremental:no -opt:ref -subsystem:console if %release_mode% EQU 0 ( rem Debug set linker_flags=%linker_flags% -debug - set libs=%libs% src\utf8proc\utf8proc_debug.lib ) else ( rem Release - set linker_flags=%linker_flags% -debug - set libs=%libs% src\utf8proc\utf8proc.lib + set linker_flags=%linker_flags% ) set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings% @@ -48,7 +46,13 @@ rem pushd %build_dir% cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin run code/wills_game/willsgame.odin + && odin run code/demo.odin + rem clang++ src\main.cpp -o %exe_name% ^ + rem -Wno-deprecated-declarations ^ + rem -Wno-unused-value ^ + rem -Wno-switch ^ + rem -Wno-writable-strings + rem && odin run code/demo.odin rem odin run code/demo.odin diff --git a/code/demo.odin b/code/demo.odin index 282adcb67..be7426d9f 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,3 +1,5 @@ -main :: proc() { +#import "fmt.odin" +main :: proc() { + fmt.println("Hello") } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 9f669e7c1..73f50c17f 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -104,6 +104,7 @@ struct ProcedureInfo { DeclInfo *decl; Type * type; // Type_Procedure AstNode * body; // AstNode_BlockStatement + u32 tags; }; struct Scope { @@ -213,6 +214,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { struct CheckerContext { Scope *scope; DeclInfo *decl; + u32 stmt_state_flags; }; // NOTE(bill): Symbol tables @@ -321,6 +323,7 @@ void check_open_scope(Checker *c, AstNode *node) { scope->is_proc = true; } c->context.scope = scope; + c->context.stmt_state_flags |= StmtStateFlag_bounds_check; } void check_close_scope(Checker *c) { @@ -528,7 +531,6 @@ void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->foreign_procs); map_destroy(&i->type_info_map); map_destroy(&i->files); - } @@ -574,14 +576,16 @@ TypeAndValue *type_and_value_of_expression(CheckerInfo *i, AstNode *expression) Entity *entity_of_ident(CheckerInfo *i, AstNode *identifier) { - GB_ASSERT(identifier->kind == AstNode_Ident); - Entity **found = map_get(&i->definitions, hash_pointer(identifier)); - if (found) - return *found; - - found = map_get(&i->uses, hash_pointer(identifier)); - if (found) - return *found; + if (identifier->kind == AstNode_Ident) { + Entity **found = map_get(&i->definitions, hash_pointer(identifier)); + if (found) { + return *found; + } + found = map_get(&i->uses, hash_pointer(identifier)); + if (found) { + return *found; + } + } return NULL; } @@ -611,8 +615,9 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode if (mode == Addressing_Constant) { GB_ASSERT(value.kind != ExactValue_Invalid); - GB_ASSERT_MSG(type != t_invalid || is_type_constant_type(type), - "type: %s", type_to_string(type)); + if (!(type != t_invalid || is_type_constant_type(type))) { + compiler_error("add_type_and_value - invalid type: %s", type_to_string(type)); + } } TypeAndValue tv = {}; @@ -666,21 +671,19 @@ b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { return true; } -void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) { +void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) { GB_ASSERT(identifier != NULL); - GB_ASSERT(identifier->kind == AstNode_Ident); - HashKey key = hash_pointer(identifier); - map_set(&i->uses, key, entity); - - if (entity != NULL && entity->kind == Entity_ImportName) { - entity->ImportName.used = true; + if (identifier->kind != AstNode_Ident) { + return; } + map_set(&c->info.uses, hash_pointer(identifier), entity); + add_declaration_dependency(c, entity); // TODO(bill): Should this be here? } -void add_file_entity(Checker *c, Scope *file_scope, AstNode *identifier, Entity *e, DeclInfo *d) { +void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) { GB_ASSERT(identifier->Ident.string == e->token.string); - add_entity(c, file_scope, identifier, e); + add_entity(c, e->scope, identifier, e); map_set(&c->info.entities, hash_pointer(e), d); } @@ -721,7 +724,7 @@ void add_type_info_type(Checker *c, Type *t) { return; } - Type *bt = get_base_type(t); + Type *bt = base_type(t); switch (bt->kind) { case Type_Basic: { if (bt->Basic.kind == Basic_string) { @@ -778,13 +781,14 @@ void add_type_info_type(Checker *c, Type *t) { } -void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body) { +void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u32 tags) { ProcedureInfo info = {}; info.file = file; info.token = token; info.decl = decl; info.type = type; info.body = body; + info.tags = tags; gb_array_append(c->procs, info); } @@ -808,6 +812,50 @@ void add_curr_ast_file(Checker *c, AstFile *file) { TokenPos zero_pos = {}; global_error_collector.prev = zero_pos; c->curr_ast_file = file; + c->context.decl = file->decl_info; +} + + + + +void add_dependency_to_map(Map *map, CheckerInfo *info, Entity *node) { + if (node == NULL) { + return; + } + if (map_get(map, hash_pointer(node)) != NULL) { + return; + } + map_set(map, hash_pointer(node), node); + + + DeclInfo **found = map_get(&info->entities, hash_pointer(node)); + if (found == NULL) { + return; + } + + DeclInfo *decl = *found; + gb_for_array(i, decl->deps.entries) { + Entity *e = cast(Entity *)cast(uintptr)decl->deps.entries[i].key.key; + add_dependency_to_map(map, info, e); + } +} + +Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { + Map map = {}; // Key: Entity * + map_init(&map, gb_heap_allocator()); + + add_dependency_to_map(&map, info, start); + + gb_for_array(i, info->entities.entries) { + auto *entry = &info->entities.entries[i]; + Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + if (e->scope->is_global) { + // NOTE(bill): Require runtime stuff + add_dependency_to_map(&map, info, e); + } + } + + return map; } @@ -853,7 +901,7 @@ void init_runtime_types(Checker *c) { t_type_info = e->type; t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); - auto *record = &get_base_type(e->type)->Record; + auto *record = &base_type(e->type)->Record; t_type_info_member = record->other_fields[0]->type; t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member); @@ -899,7 +947,6 @@ void init_runtime_types(Checker *c) { } } - void check_parsed_files(Checker *c) { gbArray(AstNode *) import_decls; @@ -929,6 +976,7 @@ void check_parsed_files(Checker *c) { } f->scope = scope; + f->decl_info = make_declaration_info(c->allocator, f->scope); HashKey key = hash_string(f->tokenizer.fullpath); map_set(&file_scopes, key, scope); map_set(&c->info.files, key, f); @@ -963,10 +1011,11 @@ void check_parsed_files(Checker *c) { AstNode *value = cd->values[i]; ExactValue v = {ExactValue_Invalid}; Entity *e = make_entity_constant(c->allocator, file_scope, name->Ident, NULL, v); + e->identifier = name; DeclInfo *di = make_declaration_info(c->allocator, file_scope); di->type_expr = cd->type; di->init_expr = value; - add_file_entity(c, file_scope, name, e, di); + add_entity_and_decl_info(c, name, e, di); } isize lhs_count = gb_array_count(cd->names); @@ -999,6 +1048,7 @@ void check_parsed_files(Checker *c) { value = vd->values[i]; } Entity *e = make_entity_variable(c->allocator, file_scope, name->Ident, NULL); + e->identifier = name; entities[entity_index++] = e; DeclInfo *d = di; @@ -1010,25 +1060,27 @@ void check_parsed_files(Checker *c) { d->var_decl_tags = vd->tags; } - add_file_entity(c, file_scope, name, e, d); + add_entity_and_decl_info(c, name, e, d); } case_end; case_ast_node(td, TypeDecl, decl); ast_node(n, Ident, td->name); Entity *e = make_entity_type_name(c->allocator, file_scope, *n, NULL); + e->identifier = td->name; DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->type_expr = td->type; - add_file_entity(c, file_scope, td->name, e, d); + add_entity_and_decl_info(c, td->name, e, d); case_end; case_ast_node(pd, ProcDecl, decl); ast_node(n, Ident, pd->name); Token token = *n; Entity *e = make_entity_procedure(c->allocator, file_scope, token, NULL); + e->identifier = pd->name; DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->proc_decl = decl; - add_file_entity(c, file_scope, pd->name, e, d); + add_entity_and_decl_info(c, pd->name, e, d); case_end; default: @@ -1069,7 +1121,7 @@ void check_parsed_files(Checker *c) { warning(id->token, "Multiple #import of the same file within this scope"); } - if (id->import_name.string == make_string(".")) { + if (id->import_name.string == ".") { // NOTE(bill): Add imported entities to this file's scope gb_for_array(elem_index, scope->elements.entries) { Entity *e = scope->elements.entries[elem_index].value; @@ -1155,7 +1207,7 @@ void check_parsed_files(Checker *c) { check_global_entity(c, Entity_TypeName); init_runtime_types(c); -#if 1 + check_global_entity(c, Entity_Constant); check_global_entity(c, Entity_Procedure); check_global_entity(c, Entity_Variable); @@ -1164,13 +1216,42 @@ void check_parsed_files(Checker *c) { gb_for_array(i, c->procs) { ProcedureInfo *pi = &c->procs[i]; add_curr_ast_file(c, pi->file); + + b32 bounds_check = (pi->tags & ProcTag_bounds_check) != 0; + b32 no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; + + auto prev_context = c->context; + defer (c->context = prev_context); + if (bounds_check) { + c->context.stmt_state_flags |= StmtStateFlag_bounds_check; + c->context.stmt_state_flags &= ~StmtStateFlag_no_bounds_check; + } else if (no_bounds_check) { + c->context.stmt_state_flags |= StmtStateFlag_no_bounds_check; + c->context.stmt_state_flags &= ~StmtStateFlag_bounds_check; + } + check_proc_body(c, pi->token, pi->decl, pi->type, pi->body); } + if (false) { + gb_printf("Dependency graph:\n"); + gb_for_array(i, c->info.entities.entries) { + auto *entry = &c->info.entities.entries[i]; + Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + DeclInfo *d = entry->value; + if (gb_array_count(d->deps.entries) > 0) { + gb_printf("\t%.*s depends on\n", LIT(e->token.string)); + gb_for_array(j, d->deps.entries) { + Entity *e = cast(Entity *)cast(uintptr)d->deps.entries[j].key.key; + gb_printf("\t\t%.*s\n", LIT(e->token.string)); + } + } + } + } // Add untyped expression values gb_for_array(i, c->info.untyped.entries) { - auto *entry = c->info.untyped.entries + i; + auto *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; AstNode *expr = cast(AstNode *)cast(uintptr)key.key; ExpressionInfo *info = &entry->value; @@ -1181,24 +1262,6 @@ void check_parsed_files(Checker *c) { add_type_and_value(&c->info, expr, info->mode, info->type, info->value); } } -#endif - -#if 0 - gb_for_array(i, c->parser->files) { - AstFile *f = &c->parser->files[i]; - Scope *scope = f->scope; - gb_for_array(j, scope->elements.entries) { - Entity *e = scope->elements.entries[j].value; - switch (e->kind) { - case Entity_ImportName: { - if (!e->ImportName.used) { - warning(e->token, "Unused import name: %.*s", LIT(e->ImportName.name)); - } - } break; - } - } - } -#endif } diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 1ff39b7e1..b5f73c187 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -34,6 +34,8 @@ struct Entity { Scope * scope; Token token; Type * type; + AstNode * identifier; // Can be NULL + Entity * using_parent; AstNode * using_expr; @@ -51,6 +53,7 @@ struct Entity { b8 is_field; // Is struct field } Variable; struct { + b32 used; } TypeName; struct { b32 used; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 0d1306408..cd46d3fbc 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -18,8 +18,8 @@ void update_expr_type (Checker *c, AstNode *e, Type *type, b32 fina b32 check_is_assignable_to_using_subtype(Type *dst, Type *src) { Type *prev_src = src; // Type *prev_dst = dst; - src = get_base_type(type_deref(src)); - // dst = get_base_type(type_deref(dst)); + src = base_type(type_deref(src)); + // dst = base_type(type_deref(dst)); b32 src_is_ptr = src != prev_src; // b32 dst_is_ptr = dst != prev_dst; @@ -62,8 +62,8 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu return true; } - Type *src = get_base_type(s); - Type *dst = get_base_type(type); + Type *src = base_type(s); + Type *dst = base_type(type); if (is_type_untyped(src)) { @@ -184,7 +184,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map *entity_map) { - t = get_base_type(type_deref(t)); + t = base_type(type_deref(t)); gbString str = expr_to_string(node); defer (gb_string_free(str)); @@ -266,7 +266,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, AstNode *name = cd->names[i]; Entity *e = entities[i]; Token name_token = name->Ident; - if (name_token.string == make_string("_")) { + if (name_token.string == "_") { other_fields[other_field_index++] = e; } else { HashKey key = hash_string(name_token.string); @@ -288,7 +288,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, add_entity(c, c->context.scope, td->name, e); check_type_decl(c, e, td->type, NULL, NULL); - if (name_token.string == make_string("_")) { + if (name_token.string == "_") { other_fields[other_field_index++] = e; } else { HashKey key = hash_string(name_token.string); @@ -299,7 +299,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, map_set(&entity_map, key, e); other_fields[other_field_index++] = e; } - add_entity_use(&c->info, td->name, e); + add_entity_use(c, td->name, e); } } @@ -326,7 +326,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, type->Named.type_name = e; add_entity(c, c->context.scope, name, e); - if (name_token.string == make_string("_")) { + if (name_token.string == "_") { error(name_token, "`_` cannot be used a union subtype"); continue; } @@ -339,7 +339,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, map_set(&entity_map, key, e); fields[field_index++] = e; } - add_entity_use(&c->info, name, e); + add_entity_use(c, name, e); } } } else { @@ -365,7 +365,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using, cast(i32)field_index); - if (name_token.string == make_string("_")) { + if (name_token.string == "_") { fields[field_index++] = e; } else { HashKey key = hash_string(name_token.string); @@ -377,13 +377,13 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, fields[field_index++] = e; add_entity(c, c->context.scope, name, e); } - add_entity_use(&c->info, name, e); + add_entity_use(c, name, e); } } if (vd->is_using) { - Type *t = get_base_type(type_deref(type)); + Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t)) { Token name_token = vd->names[0]->Ident; error(name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string)); @@ -619,15 +619,15 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod ast_node(f, FieldValue, field); Token name_token = f->field->Ident; - if (name_token.string == make_string("count")) { + if (name_token.string == "count") { error(name_token, "`count` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; - } else if (name_token.string == make_string("min_value")) { + } else if (name_token.string == "min_value") { error(name_token, "`min_value` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; - } else if (name_token.string == make_string("max_value")) { + } else if (name_token.string == "max_value") { error(name_token, "`max_value` is a reserved identifier for enumerations"); fields[field_index++] = blank_entity; continue; @@ -672,7 +672,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod add_entity(c, c->context.scope, NULL, e); fields[field_index++] = e; } - add_entity_use(&c->info, f->field, e); + add_entity_use(c, f->field, e); } gb_sort_array(fields, gb_array_count(et->fields), cmp_enum_order); @@ -802,7 +802,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->expr = n; Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string); if (e == NULL) { - if (n->Ident.string == make_string("_")) { + if (n->Ident.string == "_") { error(n->Ident, "`_` cannot be used as a value type"); } else { error(n->Ident, "Undeclared name: %.*s", LIT(n->Ident.string)); @@ -814,7 +814,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl } return; } - add_entity_use(&c->info, n, e); + add_entity_use(c, n, e); CycleChecker local_cycle_checker = {}; if (cycle_checker == NULL) { @@ -835,19 +835,21 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl switch (e->kind) { case Entity_Constant: - add_declaration_dependency(c, e); - if (type == t_invalid) + if (type == t_invalid) { + o->type = t_invalid; return; + } o->value = e->Constant.value; GB_ASSERT(o->value.kind != ExactValue_Invalid); o->mode = Addressing_Constant; break; case Entity_Variable: - add_declaration_dependency(c, e); e->Variable.used = true; - if (type == t_invalid) + if (type == t_invalid) { + o->type = t_invalid; return; + } o->mode = Addressing_Variable; break; @@ -872,7 +874,6 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl } break; case Entity_Procedure: - add_declaration_dependency(c, e); o->mode = Addressing_Value; break; @@ -996,7 +997,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c case_ast_node(vt, VectorType, e); Type *elem = check_type(c, vt->elem); - Type *be = get_base_type(elem); + Type *be = base_type(elem); i64 count = check_array_count(c, vt->count); if (!is_type_boolean(be) && !is_type_numeric(be)) { err_str = type_to_string(elem); @@ -1097,7 +1098,7 @@ end: b32 check_unary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly - Type *type = get_base_type(base_vector_type(get_base_type(o->type))); + Type *type = base_type(base_vector_type(o->type)); gbString str = NULL; defer (gb_string_free(str)); switch (op.kind) { @@ -1132,7 +1133,7 @@ b32 check_unary_op(Checker *c, Operand *o, Token op) { b32 check_binary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly - Type *type = get_base_type(base_vector_type(o->type)); + Type *type = base_type(base_vector_type(o->type)); switch (op.kind) { case Token_Add: case Token_Sub: @@ -1285,7 +1286,7 @@ b32 check_is_expr_vector_index(Checker *c, AstNode *expr) { ast_node(ie, IndexExpr, expr); Type *t = type_of_expr(&c->info, ie->expr); if (t != NULL) { - return is_type_vector(get_base_type(t)); + return is_type_vector(base_type(t)); } } return false; @@ -1313,7 +1314,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { } if (o->mode == Addressing_Constant) { - Type *type = get_base_type(o->type); + Type *type = base_type(o->type); GB_ASSERT(type->kind == Type_Basic); i32 precision = 0; if (is_type_unsigned(type)) @@ -1344,13 +1345,13 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { switch (op.kind) { case Token_CmpEq: case Token_NotEq: - defined = is_type_comparable(get_base_type(x->type)); + defined = is_type_comparable(base_type(x->type)); break; case Token_Lt: case Token_Gt: case Token_LtEq: case Token_GtEq: { - defined = is_type_ordered(get_base_type(x->type)); + defined = is_type_ordered(base_type(x->type)); } break; } @@ -1385,8 +1386,8 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { update_expr_type(c, y->expr, default_type(y->type), true); } - if (is_type_vector(get_base_type(y->type))) { - x->type = make_type_vector(c->allocator, t_bool, get_base_type(y->type)->Vector.count); + if (is_type_vector(base_type(y->type))) { + x->type = make_type_vector(c->allocator, t_bool, base_type(y->type)->Vector.count); } else { x->type = t_untyped_bool; } @@ -1461,7 +1462,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->value = exact_value_shift(be->op, x_val, make_exact_value_integer(amount)); if (is_type_typed(x->type)) { - check_is_expressible(c, x, get_base_type(x->type)); + check_is_expressible(c, x, base_type(x->type)); } return; } @@ -1491,8 +1492,8 @@ b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) { return true; Type *x = operand->type; - Type *xb = get_base_type(x); - Type *yb = get_base_type(y); + Type *xb = base_type(x); + Type *yb = base_type(y); if (are_types_identical(xb, yb)) { return true; } @@ -1561,7 +1562,7 @@ String check_down_cast_name(Type *dst_, Type *src_) { String result = {}; Type *dst = type_deref(dst_); Type *src = type_deref(src_); - Type *dst_s = get_base_type(dst); + Type *dst_s = base_type(dst); GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s)); for (isize i = 0; i < dst_s->Record.field_count; i++) { Entity *f = dst_s->Record.fields[i]; @@ -1603,10 +1604,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { b32 is_const_expr = x->mode == Addressing_Constant; b32 can_convert = false; - Type *base_type = get_base_type(type); - if (is_const_expr && is_type_constant_type(base_type)) { - if (base_type->kind == Type_Basic) { - if (check_value_is_expressible(c, x->value, base_type, &x->value)) { + Type *bt = base_type(type); + if (is_const_expr && is_type_constant_type(bt)) { + if (bt->kind == Type_Basic) { + if (check_value_is_expressible(c, x->value, bt, &x->value)) { can_convert = true; } } @@ -1707,8 +1708,8 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { Type *src = type_deref(x->type); Type *dst = type_deref(type); - Type *bsrc = get_base_type(src); - Type *bdst = get_base_type(dst); + Type *bsrc = base_type(src); + Type *bdst = base_type(dst); if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) { gbString expr_str = expr_to_string(node); @@ -1823,7 +1824,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { ExactValue a = x->value; ExactValue b = y->value; - Type *type = get_base_type(x->type); + Type *type = base_type(x->type); GB_ASSERT(type->kind == Type_Basic); if (op.kind == Token_Quo && is_type_integer(type)) { op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers @@ -1869,7 +1870,7 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) { } if (!final && is_type_untyped(type)) { - found->type = get_base_type(type); + found->type = base_type(type); map_set(&c->info.untyped, key, *found); } else { ExpressionInfo old = *found; @@ -1934,7 +1935,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { return; } - Type *t = get_enum_base_type(get_base_type(target_type)); + Type *t = get_enum_base_type(base_type(target_type)); switch (t->kind) { case Type_Basic: if (operand->mode == Addressing_Constant) { @@ -2015,7 +2016,8 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu return false; } - if (operand.mode == Addressing_Constant) { + if (operand.mode == Addressing_Constant && + (c->context.stmt_state_flags & StmtStateFlag_bounds_check) != 0) { i64 i = exact_value_to_integer(operand.value).value_integer; if (i < 0) { gbString expr_str = expr_to_string(operand.expr); @@ -2031,7 +2033,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (i >= max_count) { gbString expr_str = expr_to_string(operand.expr); error(ast_node_token(operand.expr), - "Index `%s` is out of bounds range [0, %lld)", expr_str, max_count); + "Index `%s` is out of bounds range 0..<%lld", expr_str, max_count); gb_string_free(expr_str); return false; } @@ -2062,7 +2064,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { if (op_expr->kind == AstNode_Ident) { String name = op_expr->Ident.string; Entity *e = scope_lookup_entity(c->context.scope, name); - add_entity_use(&c->info, op_expr, e); + add_entity_use(c, op_expr, e); if (e != NULL && e->kind == Entity_ImportName) { String sel_name = selector->Ident.string; check_op_expr = false; @@ -2091,7 +2093,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { // NOTE(bill): Not really an error so don't goto error } - add_entity_use(&c->info, selector, entity); + add_entity_use(c, selector, entity); } } if (check_op_expr) { @@ -2116,7 +2118,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { } - add_entity_use(&c->info, selector, entity); + add_entity_use(c, selector, entity); operand->type = entity->type; operand->expr = node; @@ -2186,7 +2188,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Operand op = {}; check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; - if (op.mode != Addressing_Type && type == NULL || type == t_invalid) { + if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `new`"); return false; } @@ -2198,7 +2200,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Operand op = {}; check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; - if (op.mode != Addressing_Type && type == NULL || type == t_invalid) { + if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `new_slice`"); return false; } @@ -2297,7 +2299,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_offset_of: { // offset_val :: proc(Type, field) -> int Operand op = {}; - Type *type = get_base_type(check_type(c, ce->args[0])); + Type *type = base_type(check_type(c, ce->args[0])); if (type != NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); return false; @@ -2345,8 +2347,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; Type *type = operand->type; - if (get_base_type(type)->kind == Type_Pointer) { - Type *p = get_base_type(type); + if (base_type(type)->kind == Type_Pointer) { + Type *p = base_type(type); if (is_type_struct(p)) { type = p->Pointer.elem; } @@ -2456,7 +2458,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) // copy :: proc(x, y: []Type) -> int Type *dest_type = NULL, *src_type = NULL; - Type *d = get_base_type(operand->type); + Type *d = base_type(operand->type); if (d->kind == Type_Slice) dest_type = d->Slice.elem; @@ -2464,7 +2466,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr(c, &op, ce->args[1]); if (op.mode == Addressing_Invalid) return false; - Type *s = get_base_type(op.type); + Type *s = base_type(op.type); if (s->kind == Type_Slice) src_type = s->Slice.elem; @@ -2495,13 +2497,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_append: { // append :: proc(x : ^[]Type, y : Type) -> bool Type *x_type = NULL, *y_type = NULL; - x_type = get_base_type(operand->type); + x_type = base_type(operand->type); Operand op = {}; check_expr(c, &op, ce->args[1]); if (op.mode == Addressing_Invalid) return false; - y_type = get_base_type(op.type); + y_type = base_type(op.type); if (!(is_type_pointer(x_type) && is_type_slice(x_type->Pointer.elem))) { error(ast_node_token(call), "First argument to `append` must be a pointer to a slice"); @@ -2530,7 +2532,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_swizzle: { // swizzle :: proc(v: {N}T, T...) -> {M}T - Type *vector_type = get_base_type(operand->type); + Type *vector_type = base_type(operand->type); if (!is_type_vector(vector_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2549,7 +2551,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr(c, &op, arg); if (op.mode == Addressing_Invalid) return false; - Type *arg_type = get_base_type(op.type); + Type *arg_type = base_type(op.type); if (!is_type_integer(arg_type) || op.mode != Addressing_Constant) { error(ast_node_token(op.expr), "Indices to `swizzle` must be constant integers"); return false; @@ -2581,7 +2583,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_ptr_offset: { // ptr_offset :: proc(ptr: ^T, offset: int) -> ^T // ^T cannot be rawptr - Type *ptr_type = get_base_type(operand->type); + Type *ptr_type = base_type(operand->type); if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2602,7 +2604,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr(c, &op, offset); if (op.mode == Addressing_Invalid) return false; - Type *offset_type = get_base_type(op.type); + Type *offset_type = base_type(op.type); if (!is_type_integer(offset_type)) { error(ast_node_token(op.expr), "Pointer offsets for `ptr_offset` must be an integer"); return false; @@ -2623,7 +2625,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_ptr_sub: { // ptr_sub :: proc(a, b: ^T) -> int // ^T cannot be rawptr - Type *ptr_type = get_base_type(operand->type); + Type *ptr_type = base_type(operand->type); if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2652,7 +2654,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; } - if (get_base_type(op.type) == t_rawptr) { + if (base_type(op.type) == t_rawptr) { error(ast_node_token(call), "`rawptr` cannot have pointer arithmetic"); return false; @@ -2684,7 +2686,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_slice_ptr: { // slice_ptr :: proc(a: ^T, len: int[, cap: int]) -> []T // ^T cannot be rawptr - Type *ptr_type = get_base_type(operand->type); + Type *ptr_type = base_type(operand->type); if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2744,7 +2746,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_min: { // min :: proc(a, b: comparable) -> comparable - Type *type = get_base_type(operand->type); + Type *type = base_type(operand->type); if (!is_type_comparable(type) || !is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2804,7 +2806,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_max: { // min :: proc(a, b: comparable) -> comparable - Type *type = get_base_type(operand->type); + Type *type = base_type(operand->type); if (!is_type_comparable(type) || !is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2864,7 +2866,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_abs: { // abs :: proc(n: numeric) -> numeric - Type *type = get_base_type(operand->type); + Type *type = base_type(operand->type); if (!is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -2894,7 +2896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_enum_to_string: { - Type *type = get_base_type(operand->type); + Type *type = base_type(operand->type); if (!is_type_enum(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); @@ -3003,7 +3005,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode if (variadic_expand) { check_assignment(c, operand, arg_type, make_string("argument"), true); } else { - arg_type = get_base_type(arg_type)->Slice.elem; + arg_type = base_type(arg_type)->Slice.elem; check_assignment(c, operand, arg_type, make_string("argument"), true); } } else { @@ -3033,7 +3035,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } Type *arg_type = sig_params[index]->type; if (end_variadic && is_type_slice(arg_type)) { - arg_type = get_base_type(arg_type)->Slice.elem; + arg_type = base_type(arg_type)->Slice.elem; } check_assignment(c, operand, arg_type, make_string("argument"), true); param_index++; @@ -3099,7 +3101,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { return builtin_procs[id].kind; } - Type *proc_type = get_base_type(operand->type); + Type *proc_type = base_type(operand->type); if (proc_type == NULL || proc_type->kind != Type_Proc) { AstNode *e = operand->expr; gbString str = expr_to_string(e); @@ -3225,7 +3227,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - Type *t = get_base_type(type); + Type *t = base_type(type); switch (t->kind) { case Type_Record: { if (!is_type_struct(t)) @@ -3269,7 +3271,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } Entity *field = t->Record.fields[sel.index[0]]; - add_entity_use(&c->info, kv->field, field); + add_entity_use(c, kv->field, field); if (fields_visited[sel.index[0]]) { error(ast_node_token(elem), @@ -3425,7 +3427,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint b32 valid = false; i64 max_count = -1; - Type *t = get_base_type(o->type); + Type *t = base_type(o->type); switch (t->kind) { case Type_Basic: if (is_type_string(t)) { @@ -3463,7 +3465,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint break; case Type_Pointer: { - Type *bt = get_base_type(t->Pointer.elem); + Type *bt = base_type(t->Pointer.elem); if (bt->kind == Type_Array) { valid = true; max_count = bt->Array.count; @@ -3501,7 +3503,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint b32 valid = false; i64 max_count = -1; - Type *t = get_base_type(o->type); + Type *t = base_type(o->type); switch (t->kind) { case Type_Basic: if (is_type_string(t)) { @@ -3533,7 +3535,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint break; case Type_Pointer: { - Type *bt = get_base_type(t->Pointer.elem); + Type *bt = base_type(t->Pointer.elem); if (bt->kind == Type_Array) { valid = true; max_count = bt->Array.count; @@ -3591,7 +3593,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (o->mode == Addressing_Invalid) { goto error; } else { - Type *t = get_base_type(o->type); + Type *t = base_type(o->type); if (t->kind == Type_Pointer) { o->mode = Addressing_Variable; o->type = t->Pointer.elem; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 03bf85656..da3910f77 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -17,7 +17,10 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { Entity *e; DeclInfo *d; }; - gbArray(Delay) delayed; gb_array_init(delayed, gb_heap_allocator()); + gbArray(Delay) delayed_const; gb_array_init(delayed_const, gb_heap_allocator()); + gbArray(Delay) delayed_type; gb_array_init(delayed_type, gb_heap_allocator()); + defer (gb_array_free(delayed_const)); + defer (gb_array_free(delayed_type)); gb_for_array(i, stmts) { AstNode *node = stmts[i]; @@ -29,6 +32,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { ExactValue v = {ExactValue_Invalid}; Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); + e->identifier = name; add_entity(c, e->scope, name, e); DeclInfo *di = make_declaration_info(c->allocator, e->scope); @@ -36,7 +40,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { di->init_expr = value; Delay delay = {e, di}; - gb_array_append(delayed, delay); + gb_array_append(delayed_const, delay); } isize lhs_count = gb_array_count(cd->names); @@ -51,27 +55,24 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { case_ast_node(td, TypeDecl, node); Entity *e = make_entity_type_name(c->allocator, c->context.scope, td->name->Ident, NULL); + e->identifier = td->name; add_entity(c, c->context.scope, td->name, e); DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->type_expr = td->type; Delay delay = {e, d}; - gb_array_append(delayed, delay); + gb_array_append(delayed_type, delay); case_end; } } - auto check_scope_entity = [](Checker *c, gbArray(Delay) delayed, EntityKind kind) { - gb_for_array(i, delayed) { - auto delay = delayed[i]; - if (delay.e->kind == kind) { - check_entity_decl(c, delay.e, delay.d, NULL); - } - } - }; - check_scope_entity(c, delayed, Entity_TypeName); - check_scope_entity(c, delayed, Entity_Constant); + gb_for_array(i, delayed_type) { + check_entity_decl(c, delayed_type[i].e, delayed_type[i].d, NULL); + } + gb_for_array(i, delayed_const) { + check_entity_decl(c, delayed_const[i].e, delayed_const[i].d, NULL); + } b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0; u32 f = flags & (~Stmt_FallthroughAllowed); @@ -227,7 +228,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { // NOTE(bill): Ignore assignments to `_` if (node->kind == AstNode_Ident && - node->Ident.string == make_string("_")) { + node->Ident.string == "_") { add_entity_definition(&c->info, node, NULL); check_assignment(c, op_a, NULL, make_string("assignment to `_` identifier")); if (op_a->mode == Addressing_Invalid) @@ -301,8 +302,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex } - if (e->type == NULL) + if (e->type == NULL) { e->type = t_invalid; + } return NULL; } @@ -321,8 +323,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex } check_assignment(c, operand, e->type, context_name); - if (operand->mode == Addressing_Invalid) + if (operand->mode == Addressing_Invalid) { return NULL; + } return e->type; } @@ -448,9 +451,9 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle gb_array_free(local_cycle_checker.path); }); - Type *base_type = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e)); - named->Named.base = base_type; - named->Named.base = get_base_type(named->Named.base); + Type *bt = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e)); + named->Named.base = bt; + named->Named.base = base_type(named->Named.base); if (named->Named.base == t_invalid) { gb_printf("check_type_decl: %s\n", type_to_string(named)); } @@ -474,7 +477,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod if (!e->Variable.anonymous) continue; String name = e->token.string; - Type *t = get_base_type(type_deref(e->type)); + Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); @@ -524,8 +527,8 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) { return false; } for (isize i = 0; i < a->param_count; i++) { - Type *x = get_base_type(a->params->Tuple.variables[i]->type); - Type *y = get_base_type(b->params->Tuple.variables[i]->type); + Type *x = base_type(a->params->Tuple.variables[i]->type); + Type *y = base_type(b->params->Tuple.variables[i]->type); if (is_type_pointer(x) && is_type_pointer(y)) { continue; } @@ -535,8 +538,8 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) { } } for (isize i = 0; i < a->result_count; i++) { - Type *x = get_base_type(a->results->Tuple.variables[i]->type); - Type *y = get_base_type(b->results->Tuple.variables[i]->type); + Type *x = base_type(a->results->Tuple.variables[i]->type); + Type *y = base_type(b->results->Tuple.variables[i]->type); if (is_type_pointer(x) && is_type_pointer(y)) { continue; } @@ -559,15 +562,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { defer (check_close_scope(c)); check_procedure_type(c, proc_type, pd->type); - - b32 is_foreign = (pd->tags & ProcTag_foreign) != 0; - b32 is_link_name = (pd->tags & ProcTag_link_name) != 0; - b32 is_inline = (pd->tags & ProcTag_inline) != 0; - b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0; - + b32 is_foreign = (pd->tags & ProcTag_foreign) != 0; + b32 is_link_name = (pd->tags & ProcTag_link_name) != 0; + b32 is_inline = (pd->tags & ProcTag_inline) != 0; + b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0; if ((d->scope->is_file || d->scope->is_global) && - e->token.string == make_string("main")) { + e->token.string == "main") { if (proc_type != NULL) { auto *pt = &proc_type->Proc; if (pt->param_count != 0 || @@ -595,7 +596,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { d->scope = c->context.scope; GB_ASSERT(pd->body->kind == AstNode_BlockStmt); - check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body); + check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags); } if (is_foreign) { @@ -610,8 +611,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { if (found) { Entity *f = *found; TokenPos pos = f->token.pos; - Type *this_type = get_base_type(e->type); - Type *other_type = get_base_type(f->type); + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); if (!are_signatures_similar_enough(this_type, other_type)) { error(ast_node_token(d->proc_decl), "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" @@ -639,7 +640,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { map_set(fp, key, e); } } - } void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) { @@ -674,7 +674,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } AstNodeArray inits; - gb_array_init(inits, c->allocator); + gb_array_init_reserve(inits, c->allocator, 1); gb_array_append(inits, init_expr); check_init_variables(c, entities, entity_count, inits, make_string("variable declaration")); } @@ -701,9 +701,10 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc check_proc_decl(c, e, d); return; } - Scope *prev = c->context.scope; + auto prev = c->context; c->context.scope = d->scope; - defer (c->context.scope = prev); + c->context.decl = d; + defer (c->context = prev); switch (e->kind) { case Entity_Constant: @@ -790,6 +791,24 @@ void check_var_decl_node(Checker *c, AstNode *node) { void check_stmt(Checker *c, AstNode *node, u32 flags) { + u32 prev_stmt_state_flags = c->context.stmt_state_flags; + defer (c->context.stmt_state_flags = prev_stmt_state_flags); + + if (node->stmt_state_flags != 0) { + u32 in = node->stmt_state_flags; + u32 out = c->context.stmt_state_flags; + defer (c->context.stmt_state_flags = out); + + if (in & StmtStateFlag_bounds_check) { + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; + } else if (in & StmtStateFlag_no_bounds_check) { + out |= StmtStateFlag_no_bounds_check; + out &= ~StmtStateFlag_bounds_check; + } + } + + u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { case_ast_node(_, EmptyStmt, node); case_end; @@ -1180,7 +1199,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { "Expected a pointer to a union for this type match expression, got `%s`", str); break; } - Type *base_union = get_base_type(type_deref(x.type)); + Type *base_union = base_type(type_deref(x.type)); // NOTE(bill): Check for multiple defaults @@ -1274,7 +1293,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tag_ptr_type); tag_var->Variable.used = true; add_entity(c, c->context.scope, ms->var, tag_var); - add_entity_use(&c->info, ms->var, tag_var); + add_entity_use(c, ms->var, tag_var); } check_stmt_list(c, cc->stmts, mod_flags); check_close_scope(c); @@ -1342,7 +1361,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { switch (e->kind) { case Entity_TypeName: { - Type *t = get_base_type(e->type); + Type *t = base_type(e->type); if (is_type_struct(t) || is_type_enum(t)) { for (isize i = 0; i < t->Record.other_field_count; i++) { Entity *f = t->Record.other_fields[i]; @@ -1404,7 +1423,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { break; case Entity_Variable: { - Type *t = get_base_type(type_deref(e->type)); + Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); @@ -1444,7 +1463,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { ast_node(i, Ident, item); String name = i->string; Entity *e = scope_lookup_entity(c->context.scope, name); - Type *t = get_base_type(type_deref(e->type)); + Type *t = base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); GB_ASSERT(found != NULL); @@ -1511,6 +1530,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { // NOTE(bill): This must be handled here so it has access to the parent scope stuff // e.g. using Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL); + e->identifier = pd->name; add_entity(c, c->context.scope, pd->name, e); DeclInfo *d = make_declaration_info(c->allocator, e->scope); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 24bab46ad..a814db218 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -92,8 +92,8 @@ enum TypeRecordKind { }; struct Type { - u32 flags; // See parser.cpp `enum TypeFlag` TypeKind kind; + u32 flags; // See parser.cpp `enum TypeFlag` union { BasicType Basic; struct { @@ -157,7 +157,7 @@ struct Type { gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator()); -Type *get_base_type(Type *t) { +Type *base_type(Type *t) { for (;;) { if (t == NULL || t->kind != Type_Named) { break; @@ -259,7 +259,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun } GB_ASSERT(params != NULL && params->kind == Type_Tuple); Entity *e = params->Tuple.variables[param_count-1]; - if (get_base_type(e->type)->kind != Type_Slice) { + if (base_type(e->type)->kind != Type_Slice) { // NOTE(bill): For custom calling convention GB_PANIC("variadic parameter must be of type slice"); } @@ -277,7 +277,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun Type *type_deref(Type *t) { if (t != NULL) { - Type *bt = get_base_type(t); + Type *bt = base_type(t); if (bt == NULL) return NULL; if (bt != NULL && bt->kind == Type_Pointer) @@ -289,34 +289,34 @@ Type *type_deref(Type *t) { #define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1} gb_global Type basic_types[] = { - {0, Type_Basic, {Basic_Invalid, 0, STR_LIT("invalid type")}}, - {0, Type_Basic, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}}, - {0, Type_Basic, {Basic_i8, BasicFlag_Integer, STR_LIT("i8")}}, - {0, Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}}, - {0, Type_Basic, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}}, - {0, Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}}, - {0, Type_Basic, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}}, - {0, Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}}, - {0, Type_Basic, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}}, - {0, Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}}, - {0, Type_Basic, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}}, - {0, Type_Basic, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}}, - {0, Type_Basic, {Basic_int, BasicFlag_Integer, STR_LIT("int")}}, - {0, Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}}, - {0, Type_Basic, {Basic_rawptr, BasicFlag_Pointer, STR_LIT("rawptr")}}, - {0, Type_Basic, {Basic_string, BasicFlag_String, STR_LIT("string")}}, - {0, Type_Basic, {Basic_any, 0, STR_LIT("any")}}, - {0, Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}}, - {0, Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}}, - {0, Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}}, - {0, Type_Basic, {Basic_UntypedPointer, BasicFlag_Pointer | BasicFlag_Untyped, STR_LIT("untyped pointer")}}, - {0, Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}}, - {0, Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}}, + {Type_Basic, 0, {Basic_Invalid, 0, STR_LIT("invalid type")}}, + {Type_Basic, 0, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}}, + {Type_Basic, 0, {Basic_i8, BasicFlag_Integer, STR_LIT("i8")}}, + {Type_Basic, 0, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}}, + {Type_Basic, 0, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}}, + {Type_Basic, 0, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}}, + {Type_Basic, 0, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}}, + {Type_Basic, 0, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}}, + {Type_Basic, 0, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}}, + {Type_Basic, 0, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}}, + {Type_Basic, 0, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}}, + {Type_Basic, 0, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}}, + {Type_Basic, 0, {Basic_int, BasicFlag_Integer, STR_LIT("int")}}, + {Type_Basic, 0, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}}, + {Type_Basic, 0, {Basic_rawptr, BasicFlag_Pointer, STR_LIT("rawptr")}}, + {Type_Basic, 0, {Basic_string, BasicFlag_String, STR_LIT("string")}}, + {Type_Basic, 0, {Basic_any, 0, STR_LIT("any")}}, + {Type_Basic, 0, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}}, + {Type_Basic, 0, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}}, + {Type_Basic, 0, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}}, + {Type_Basic, 0, {Basic_UntypedPointer, BasicFlag_Pointer | BasicFlag_Untyped, STR_LIT("untyped pointer")}}, + {Type_Basic, 0, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}}, + {Type_Basic, 0, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}}, }; gb_global Type basic_type_aliases[] = { - {0, Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}}, - {0, Type_Basic, {Basic_rune, BasicFlag_Integer, STR_LIT("rune")}}, + {Type_Basic, 0, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}}, + {Type_Basic, 0, {Basic_rune, BasicFlag_Integer, STR_LIT("rune")}}, }; gb_global Type *t_invalid = &basic_types[Basic_Invalid]; @@ -342,8 +342,8 @@ gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_pointer = &basic_types[Basic_UntypedPointer]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; -gb_global Type *t_byte = &basic_type_aliases[Basic_byte]; -gb_global Type *t_rune = &basic_type_aliases[Basic_rune]; +gb_global Type *t_byte = &basic_type_aliases[0]; +gb_global Type *t_rune = &basic_type_aliases[1]; gb_global Type *t_type_info = NULL; @@ -377,140 +377,161 @@ gb_global Type *t_context_ptr = NULL; b32 is_type_named(Type *t) { - if (t->kind == Type_Basic) + if (t->kind == Type_Basic) { return true; + } return t->kind == Type_Named; } b32 is_type_boolean(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Boolean) != 0; + } return false; } b32 is_type_integer(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Integer) != 0; + } return false; } b32 is_type_unsigned(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Unsigned) != 0; + } return false; } b32 is_type_numeric(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Numeric) != 0; - if (t->kind == Type_Vector) + } + if (t->kind == Type_Vector) { return is_type_numeric(t->Vector.elem); + } return false; } b32 is_type_string(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_String) != 0; + } return false; } b32 is_type_typed(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) == 0; + } return true; } b32 is_type_untyped(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) != 0; + } return false; } b32 is_type_ordered(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Ordered) != 0; - if (t->kind == Type_Pointer) + } + if (t->kind == Type_Pointer) { return true; + } return false; } b32 is_type_constant_type(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_ConstantType) != 0; + } + if (t->kind == Type_Record) { + return t->Record.kind == TypeRecord_Enum; + } return false; } b32 is_type_float(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Float) != 0; + } return false; } b32 is_type_pointer(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Basic) + t = base_type(t); + if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Pointer) != 0; + } return t->kind == Type_Pointer; } b32 is_type_int_or_uint(Type *t) { - if (t->kind == Type_Basic) + if (t->kind == Type_Basic) { return (t->Basic.kind == Basic_int) || (t->Basic.kind == Basic_uint); + } return false; } b32 is_type_rawptr(Type *t) { - if (t->kind == Type_Basic) + if (t->kind == Type_Basic) { return t->Basic.kind == Basic_rawptr; + } return false; } b32 is_type_u8(Type *t) { - if (t->kind == Type_Basic) + if (t->kind == Type_Basic) { return t->Basic.kind == Basic_u8; + } return false; } b32 is_type_slice(Type *t) { - t = get_base_type(t); + t = base_type(t); return t->kind == Type_Slice; } b32 is_type_u8_slice(Type *t) { - t = get_base_type(t); - if (t->kind == Type_Slice) + t = base_type(t); + if (t->kind == Type_Slice) { return is_type_u8(t->Slice.elem); + } return false; } b32 is_type_vector(Type *t) { return t->kind == Type_Vector; } b32 is_type_proc(Type *t) { - t = get_base_type(t); + t = base_type(t); return t->kind == Type_Proc; } Type *base_vector_type(Type *t) { if (is_type_vector(t)) { - return t->Vector.elem; + return base_type(t)->Vector.elem; } return t; } b32 is_type_enum(Type *t) { - t = get_base_type(t); + t = base_type(t); return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum); } b32 is_type_struct(Type *t) { - t = get_base_type(t); + t = base_type(t); return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct); } b32 is_type_union(Type *t) { - t = get_base_type(t); + t = base_type(t); return (t->kind == Type_Record && t->Record.kind == TypeRecord_Union); } b32 is_type_raw_union(Type *t) { - t = get_base_type(t); + t = base_type(t); return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion); } Type *get_enum_base_type(Type *t) { - Type *bt = get_base_type(t); + Type *bt = base_type(t); if (is_type_enum(bt)) { return bt->Record.enum_base; } @@ -518,14 +539,14 @@ Type *get_enum_base_type(Type *t) { } b32 is_type_any(Type *t) { - t = get_base_type(t); + t = base_type(t); return (t->kind == Type_Basic && t->Basic.kind == Basic_any); } b32 is_type_comparable(Type *t) { - t = get_base_type(t); + t = base_type(t); switch (t->kind) { case Type_Basic: return true; @@ -722,13 +743,13 @@ gb_global Entity *entity__slice_capacity = NULL; Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) { GB_ASSERT(type_ != NULL); - if (field_name == make_string("_")) { + if (field_name == "_") { return empty_selection; } Type *type = type_deref(type_); b32 is_ptr = type != type_; - type = get_base_type(type); + type = base_type(type); if (type->kind == Type_Basic) { switch (type->Basic.kind) { @@ -850,13 +871,13 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ } if (is_type_enum(type)) { - if (field_name == make_string("count")) { + if (field_name == "count") { sel.entity = type->Record.enum_count; return sel; - } else if (field_name == make_string("min_value")) { + } else if (field_name == "min_value") { sel.entity = type->Record.min_value; return sel; - } else if (field_name == make_string("max_value")) { + } else if (field_name == "max_value") { sel.entity = type->Record.max_value; return sel; } @@ -907,7 +928,7 @@ i64 align_formula(i64 size, i64 align) { } i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { - t = get_base_type(t); + t = base_type(t); switch (t->kind) { case Type_Array: @@ -996,7 +1017,7 @@ b32 type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) { } i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { - t = get_base_type(t); + t = base_type(t); switch (t->kind) { case Type_Basic: { @@ -1107,7 +1128,7 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type * i64 offset = 0; for (isize i = 0; i < gb_array_count(sel.index); i++) { isize index = sel.index[i]; - t = get_base_type(t); + t = base_type(t); if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) { type_set_offsets(s, allocator, t); GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index c8a272202..c2aa43d3c 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -19,7 +19,7 @@ b32 ssa_gen_init(ssaGen *s, Checker *c) { s->module.generate_debug_info = false; // TODO(bill): generate appropriate output name - isize pos = string_extension_position(c->parser->init_fullpath); + int pos = cast(int)string_extension_position(c->parser->init_fullpath); gbFileError err = gb_file_create(&s->output_file, gb_bprintf("%.*s.ll", pos, c->parser->init_fullpath.text)); if (err != gbFileError_None) return false; @@ -59,18 +59,15 @@ String ssa_mangle_name(ssaGen *s, String path, String name) { isize new_name_len = gb_snprintf( cast(char *)new_name, max_len, "%.*s-%u.%.*s", - base_len, base, + cast(int)base_len, base, file->id, LIT(name)); return make_string(new_name, new_name_len-1); } + void ssa_gen_tree(ssaGen *s) { - struct ssaGlobalVariable { - ssaValue *var, *init; - DeclInfo *decl; - }; ssaModule *m = &s->module; CheckerInfo *info = m->info; @@ -87,31 +84,46 @@ void ssa_gen_tree(ssaGen *s) { } isize global_variable_max_count = 0; - - gb_for_array(i, info->entities.entries) { - auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; - if (e->kind == Entity_Variable) { - global_variable_max_count++; - } - } - - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - gbArray(ssaGlobalVariable) global_variables; - gb_array_init_reserve(global_variables, m->tmp_allocator, global_variable_max_count); - - + Entity *entry_point = NULL; gb_for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; String name = e->token.string; + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } else if (e->kind == Entity_Procedure) { + if (e->scope->is_init && name == "main") { + entry_point = e; + } + } + } + struct ssaGlobalVariable { + ssaValue *var, *init; + DeclInfo *decl; + }; + gbArray(ssaGlobalVariable) global_variables; + gb_array_init_reserve(global_variables, m->tmp_allocator, global_variable_max_count); + + auto min_dep_map = generate_minimum_dependency_map(info, entry_point); + defer (map_destroy(&min_dep_map)); + + gb_for_array(i, info->entities.entries) { + auto *entry = &info->entities.entries[i]; + Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + String name = e->token.string; DeclInfo *decl = entry->value; Scope *scope = e->scope; + + if (entry_point != NULL) { + auto found = map_get(&min_dep_map, hash_pointer(e)); + if (found == NULL) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } + } + if (!scope->is_global && !scope->is_init) { name = ssa_mangle_name(s, e->token.pos.file, name); } diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 9b90106df..420bb112f 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -194,7 +194,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { ssa_fprintf(f, ", "); } Type *ft = t->Record.fields[i]->type; - Type *bft = get_base_type(ft); + Type *bft = base_type(ft); if (!is_type_struct(bft)) { ft = bft; } @@ -229,7 +229,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { ssa_print_encoded_local(f, *name); // ssa_print_encoded_local(f, t->Named.name); } else { - ssa_print_type(f, m, get_base_type(t)); + ssa_print_type(f, m, base_type(t)); } break; case Type_Tuple: @@ -264,7 +264,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { } void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type) { - type = get_base_type(type); + type = base_type(type); if (is_type_float(type)) { value = exact_value_to_float(value); } else if (is_type_integer(type)) { @@ -275,7 +275,7 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ switch (value.kind) { case ExactValue_Bool: - ssa_fprintf(f, (value.value_bool ? "true" : "false")); + ssa_fprintf(f, "%s", (value.value_bool ? "true" : "false")); break; case ExactValue_String: { ssa_fprintf(f, "c\""); @@ -528,10 +528,10 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { case ssaInstr_BinaryOp: { auto *bo = &value->Instr.BinaryOp; - Type *type = get_base_type(ssa_type(bo->left)); + Type *type = base_type(ssa_type(bo->left)); Type *elem_type = type; while (elem_type->kind == Type_Vector) { - elem_type = get_base_type(elem_type->Vector.elem); + elem_type = base_type(elem_type->Vector.elem); } ssa_fprintf(f, "%%%d = ", value->id); @@ -651,7 +651,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, "("); if (call->arg_count > 0) { - Type *proc_type = get_base_type(ssa_type(call->value)); + Type *proc_type = base_type(ssa_type(call->value)); GB_ASSERT(proc_type->kind == Type_Proc); auto *params = &proc_type->Proc.params->Tuple; for (isize i = 0; i < call->arg_count; i++) { @@ -848,13 +848,13 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { void ssa_print_type_name(ssaFileBuffer *f, ssaModule *m, ssaValue *v) { GB_ASSERT(v->kind == ssaValue_TypeName); - Type *base_type = get_base_type(ssa_type(v)); - if (!is_type_struct(base_type) && !is_type_union(base_type)) { + Type *bt = base_type(ssa_type(v)); + if (!is_type_struct(bt) && !is_type_union(bt)) { return; } ssa_print_encoded_local(f, v->TypeName.name); ssa_fprintf(f, " = type "); - ssa_print_type(f, m, get_base_type(v->TypeName.type)); + ssa_print_type(f, m, base_type(v->TypeName.type)); ssa_fprintf(f, "\n"); } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index c9d8b6129..f95473fd8 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -497,7 +497,7 @@ Type *ssa_type(ssaInstr *instr) { case ssaInstr_Select: return ssa_type(instr->Select.true_value); case ssaInstr_Call: { - Type *pt = get_base_type(instr->Call.type); + Type *pt = base_type(instr->Call.type); if (pt != NULL) { if (pt->kind == Type_Tuple && pt->Tuple.variable_count == 1) return pt->Tuple.variables[0]->type; @@ -507,7 +507,7 @@ Type *ssa_type(ssaInstr *instr) { } break; case ssaInstr_ExtractElement: { Type *vt = ssa_type(instr->ExtractElement.vector); - Type *bt = base_vector_type(get_base_type(vt)); + Type *bt = base_vector_type(vt); GB_ASSERT(!is_type_vector(bt)); return bt; } break; @@ -768,7 +768,7 @@ ssaValue *ssa_make_instr_shuffle_vector(ssaProcedure *p, ssaValue *vector, i32 * v->Instr.ShuffleVector.indices = indices; v->Instr.ShuffleVector.index_count = index_count; - Type *vt = get_base_type(ssa_type(vector)); + Type *vt = base_type(ssa_type(vector)); v->Instr.ShuffleVector.type = make_type_vector(p->module->allocator, vt->Vector.elem, index_count); return v; @@ -950,7 +950,7 @@ ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { ssaValue *ssa_emit_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count) { - Type *pt = get_base_type(ssa_type(value)); + Type *pt = base_type(ssa_type(value)); GB_ASSERT(pt->kind == Type_Proc); Type *results = pt->Proc.results; return ssa_emit(p, ssa_make_instr_call(p, value, args, arg_count, results)); @@ -1077,7 +1077,7 @@ ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaAddr lval, ssaValue *value) { if (lval.addr != NULL) { if (lval.is_vector) { ssaValue *v = ssa_emit_load(proc, lval.addr); - Type *elem_type = get_base_type(ssa_type(v))->Vector.elem; + Type *elem_type = base_type(ssa_type(v))->Vector.elem; ssaValue *elem = ssa_emit_conv(proc, value, elem_type); ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, elem, lval.index)); return ssa_emit_store(proc, lval.addr, out); @@ -1095,7 +1095,7 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) { return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index)); } // NOTE(bill): Imported procedures don't require a load as they are pointers - Type *t = get_base_type(ssa_type(lval.addr)); + Type *t = base_type(ssa_type(lval.addr)); if (t->kind == Type_Proc) { return lval.addr; } @@ -1214,8 +1214,8 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue } ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) { - Type *a = get_base_type(ssa_type(left)); - Type *b = get_base_type(ssa_type(right)); + Type *a = base_type(ssa_type(left)); + Type *b = base_type(ssa_type(right)); if (are_types_identical(a, b)) { // NOTE(bill): No need for a conversion @@ -1280,7 +1280,7 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S e = ssa_emit_load(proc, e); e = ssa_emit_ptr_offset(proc, e, v_zero); } - type = get_base_type(type); + type = base_type(type); if (is_type_raw_union(type)) { @@ -1329,7 +1329,7 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se e = ssa_emit_load(proc, e); e = ssa_emit_ptr_offset(proc, e, v_zero); } - type = get_base_type(type); + type = base_type(type); if (is_type_raw_union(type)) { @@ -1465,20 +1465,20 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba // TODO(bill): array bounds checking for slice creation // TODO(bill): check that low < high <= max gbAllocator a = proc->module->allocator; - Type *base_type = get_base_type(ssa_type(base)); + Type *bt = base_type(ssa_type(base)); if (low == NULL) { low = v_zero; } if (high == NULL) { - switch (base_type->kind) { + switch (bt->kind) { case Type_Array: high = ssa_array_len(proc, base); break; case Type_Slice: high = ssa_slice_len(proc, base); break; case Type_Pointer: high = v_one; break; } } if (max == NULL) { - switch (base_type->kind) { + switch (bt->kind) { case Type_Array: max = ssa_array_cap(proc, base); break; case Type_Slice: max = ssa_slice_cap(proc, base); break; case Type_Pointer: max = high; break; @@ -1491,7 +1491,7 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int); ssaValue *elem = NULL; - switch (base_type->kind) { + switch (bt->kind) { case Type_Array: elem = ssa_array_elem(proc, base); break; case Type_Slice: elem = ssa_slice_elem(proc, base); break; case Type_Pointer: elem = ssa_emit_load(proc, base); break; @@ -1565,8 +1565,8 @@ ssaValue *ssa_emit_global_string(ssaProcedure *proc, String str) { String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { Type *prev_src = src; // Type *prev_dst = dst; - src = get_base_type(type_deref(src)); - // dst = get_base_type(type_deref(dst)); + src = base_type(type_deref(src)); + // dst = base_type(type_deref(dst)); b32 src_is_ptr = src != prev_src; // b32 dst_is_ptr = dst != prev_dst; @@ -1599,8 +1599,8 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg } - Type *src = get_enum_base_type(get_base_type(src_type)); - Type *dst = get_enum_base_type(get_base_type(t)); + Type *src = get_enum_base_type(base_type(src_type)); + Type *dst = get_enum_base_type(base_type(t)); if (value->kind == ssaValue_Constant) { if (is_type_any(dst)) { @@ -1718,7 +1718,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg // NOTE(bill): This has to be done beofre `Pointer <-> Pointer` as it's // subtype polymorphism casting if (is_argument) { - Type *sb = get_base_type(type_deref(src)); + Type *sb = base_type(type_deref(src)); b32 src_is_ptr = src != sb; if (is_type_struct(sb)) { String field_name = lookup_polymorphic_field(proc->module->info, t, src); @@ -1840,8 +1840,8 @@ ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { return value; } - Type *src = get_base_type(src_type); - Type *dst = get_base_type(t); + Type *src = base_type(src_type); + Type *dst = base_type(t); if (are_types_identical(t, src_type)) return value; @@ -2080,17 +2080,17 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_ast_node(cl, CompoundLit, expr); ssa_emit_comment(proc, make_string("CompoundLit")); Type *type = type_of_expr(proc->module->info, expr); - Type *base_type = get_base_type(type); + Type *bt = base_type(type); ssaValue *v = ssa_add_local_generated(proc, type); Type *et = NULL; - switch (base_type->kind) { - case Type_Vector: et = base_type->Vector.elem; break; - case Type_Array: et = base_type->Array.elem; break; - case Type_Slice: et = base_type->Slice.elem; break; + switch (bt->kind) { + case Type_Vector: et = bt->Vector.elem; break; + case Type_Array: et = bt->Array.elem; break; + case Type_Slice: et = bt->Slice.elem; break; } - switch (base_type->kind) { + switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; case Type_Vector: { @@ -2105,8 +2105,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue *i = ssa_make_const_int(proc->module->allocator, index); result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i)); } - if (index == 1 && base_type->Vector.count > 1) { - isize index_count = base_type->Vector.count; + if (index == 1 && bt->Vector.count > 1) { + isize index_count = bt->Vector.count; i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count); for (isize i = 0; i < index_count; i++) { indices[i] = 0; @@ -2120,8 +2120,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } break; case Type_Record: { - GB_ASSERT(is_type_struct(base_type)); - auto *st = &base_type->Record; + GB_ASSERT(is_type_struct(bt)); + auto *st = &bt->Record; if (cl->elems != NULL && gb_array_count(cl->elems) > 0) { gb_for_array(field_index, cl->elems) { isize index = field_index; @@ -2131,11 +2131,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue if (elem->kind == AstNode_FieldValue) { ast_node(kv, FieldValue, elem); - Selection sel = lookup_field(proc->module->allocator, base_type, kv->field->Ident.string, false); + Selection sel = lookup_field(proc->module->allocator, bt, kv->field->Ident.string, false); index = sel.index[0]; field_expr = ssa_build_expr(proc, kv->value); } else { - Selection sel = lookup_field(proc->module->allocator, base_type, st->fields_in_src_order[field_index]->token.string, false); + Selection sel = lookup_field(proc->module->allocator, bt, st->fields_in_src_order[field_index]->token.string, false); index = sel.index[0]; field_expr = ssa_build_expr(proc, elem); } @@ -2164,7 +2164,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } break; case Type_Slice: { i64 count = gb_array_count(cl->elems); - Type *elem_type = base_type->Slice.elem; + Type *elem_type = bt->Slice.elem; Type *elem_ptr_type = make_type_pointer(proc->module->allocator, elem_type); ssaValue *array = ssa_add_local_generated(proc, make_type_array(proc->module->allocator, elem_type, count)); @@ -2334,7 +2334,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue AstNode *src_node = ce->args[1]; ssaValue *dst_slice = ssa_build_expr(proc, dst_node); ssaValue *src_slice = ssa_build_expr(proc, src_node); - Type *slice_type = get_base_type(ssa_type(dst_slice)); + Type *slice_type = base_type(ssa_type(dst_slice)); GB_ASSERT(slice_type->kind == Type_Slice); Type *elem_type = slice_type->Slice.elem; i64 size_of_elem = type_size_of(proc->module->sizes, proc->module->allocator, elem_type); @@ -2455,7 +2455,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssa_emit_comment(proc, make_string("ptr_sub")); ssaValue *ptr_a = ssa_build_expr(proc, ce->args[0]); ssaValue *ptr_b = ssa_build_expr(proc, ce->args[1]); - Type *ptr_type = get_base_type(ssa_type(ptr_a)); + Type *ptr_type = base_type(ssa_type(ptr_a)); GB_ASSERT(ptr_type->kind == Type_Pointer); isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem); Token sub = {Token_Sub}; @@ -2495,7 +2495,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssa_emit_comment(proc, make_string("min")); ssaValue *x = ssa_build_expr(proc, ce->args[0]); ssaValue *y = ssa_build_expr(proc, ce->args[1]); - Type *t = get_base_type(ssa_type(x)); + Type *t = base_type(ssa_type(x)); Token lt = {Token_Lt}; ssaValue *cond = ssa_emit_comp(proc, lt, x, y); return ssa_emit_select(proc, cond, x, y); @@ -2505,7 +2505,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssa_emit_comment(proc, make_string("max")); ssaValue *x = ssa_build_expr(proc, ce->args[0]); ssaValue *y = ssa_build_expr(proc, ce->args[1]); - Type *t = get_base_type(ssa_type(x)); + Type *t = base_type(ssa_type(x)); Token gt = {Token_Gt}; ssaValue *cond = ssa_emit_comp(proc, gt, x, y); return ssa_emit_select(proc, cond, x, y); @@ -2544,7 +2544,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue // NOTE(bill): Regular call ssaValue *value = ssa_build_expr(proc, ce->proc); - Type *proc_type_ = get_base_type(ssa_type(value)); + Type *proc_type_ = base_type(ssa_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); auto *type = &proc_type_->Proc; @@ -2553,7 +2553,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue isize arg_count = 0; gb_for_array(i, ce->args) { AstNode *a = ce->args[i]; - Type *at = get_base_type(type_of_expr(proc->module->info, a)); + Type *at = base_type(type_of_expr(proc->module->info, a)); if (at->kind == Type_Tuple) { arg_count += at->Tuple.variable_count; } else { @@ -2588,7 +2588,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue if (!vari_expand) { Type *variadic_type = pt->variables[i]->type; GB_ASSERT(is_type_slice(variadic_type)); - variadic_type = get_base_type(variadic_type)->Slice.elem; + variadic_type = base_type(variadic_type)->Slice.elem; for (; i < arg_count; i++) { args[i] = ssa_emit_conv(proc, args[i], variadic_type, true); } @@ -2603,7 +2603,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssa_emit_comment(proc, make_string("variadic call argument generation")); gbAllocator allocator = proc->module->allocator; Type *slice_type = pt->variables[type->param_count-1]->type; - Type *elem_type = get_base_type(slice_type)->Slice.elem; + Type *elem_type = base_type(slice_type)->Slice.elem; Type *elem_ptr_type = make_type_pointer(allocator, elem_type); ssaValue *slice = ssa_add_local_generated(proc, slice_type); isize slice_len = arg_count+1 - type->param_count; @@ -2716,7 +2716,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { Entity *e = entity_of_ident(proc->module->info, expr); if (e->kind == Entity_Constant) { - if (get_base_type(e->type) == t_string) { + if (base_type(e->type) == t_string) { // HACK TODO(bill): This is lazy but it works String str = e->Constant.value.value_string; ssaValue *global_array = ssa_add_global_string_array(proc->module, str); @@ -2752,7 +2752,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(se, SelectorExpr, expr); ssa_emit_comment(proc, make_string("SelectorExpr")); String selector = unparen_expr(se->selector)->Ident.string; - Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); + Type *type = base_type(type_of_expr(proc->module->info, se->expr)); if (type == t_invalid) { // NOTE(bill): Imports @@ -2807,7 +2807,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(ie, IndexExpr, expr); ssa_emit_comment(proc, make_string("IndexExpr")); - Type *t = get_base_type(type_of_expr(proc->module->info, ie->expr)); + Type *t = base_type(type_of_expr(proc->module->info, ie->expr)); gbAllocator a = proc->module->allocator; switch (t->kind) { @@ -2874,7 +2874,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { if (se->high != NULL) high = ssa_build_expr(proc, se->high); if (se->triple_indexed) max = ssa_build_expr(proc, se->max); ssaAddr base = ssa_build_addr(proc, se->expr); - Type *type = get_base_type(ssa_addr_type(base)); + Type *type = base_type(ssa_addr_type(base)); // TODO(bill): Cleanup like mad! @@ -3052,7 +3052,7 @@ void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) { ssa_module_add_value(m, e, t); map_set(&m->members, hash_string(name), t); - Type *bt = get_base_type(e->type); + Type *bt = base_type(e->type); if (bt->kind == Type_Record) { auto *s = &bt->Record; for (isize j = 0; j < s->other_field_count; j++) { @@ -3232,7 +3232,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { name = pd->foreign_name; } - Entity *f = *map_get(&info->foreign_procs, hash_string(name)); ssaValue *value = ssa_make_value_procedure(proc->module->allocator, proc->module, e, e->type, pd->type, pd->body, name); @@ -3240,8 +3239,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { ssa_module_add_value(proc->module, e, value); ssa_build_proc(value, proc); - if (e == f) { - // NOTE(bill): Don't do mutliple declarations in the IR + + if (value->Proc.tags & ProcTag_foreign) { + HashKey key = hash_string(name); + auto *prev_value = map_get(&proc->module->members, key); + if (prev_value == NULL) { + // NOTE(bill): Don't do mutliple declarations in the IR + map_set(&proc->module->members, key, value); + } + } else { gb_array_append(proc->children, &value->Proc); } } @@ -3685,13 +3691,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { - Type *base_type = type_deref(tag_var_entity->type); + Type *bt = type_deref(tag_var_entity->type); ssaValue *index = NULL; - Type *ut = get_base_type(union_type); + Type *ut = base_type(union_type); GB_ASSERT(ut->Record.kind == TypeRecord_Union); for (isize field_index = 1; field_index < ut->Record.field_count; field_index++) { - Entity *f = get_base_type(union_type)->Record.fields[field_index]; - if (are_types_identical(f->type, base_type)) { + Entity *f = base_type(union_type)->Record.fields[field_index]; + if (are_types_identical(f->type, bt)) { index = ssa_make_const_int(allocator, field_index); break; } @@ -3739,14 +3745,22 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(bs, BranchStmt, node); ssaBlock *block = NULL; - #define branch_case(x) case GB_JOIN2(Token_, x): \ - for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { \ - block = GB_JOIN3(t->, x, _); \ - } break switch (bs->token.kind) { - branch_case(break); - branch_case(continue); - branch_case(fallthrough); + case Token_break: + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->break_; + } + break; + case Token_continue: + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->continue_; + } + break; + case Token_fallthrough: + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->fallthrough_; + } + break; } // TODO(bill): Handle fallthrough scope exit correctly // if (block != NULL && bs->token.kind != Token_fallthrough) { @@ -3806,14 +3820,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { void ssa_emit_startup_runtime(ssaProcedure *proc) { - GB_ASSERT(proc->parent == NULL && proc->name == make_string("main")); + GB_ASSERT(proc->parent == NULL && proc->name == "main"); ssa_emit(proc, ssa_alloc_instr(proc, ssaInstr_StartupRuntime)); } void ssa_insert_code_before_proc(ssaProcedure* proc, ssaProcedure *parent) { if (parent == NULL) { - if (proc->name == make_string("main")) { + if (proc->name == "main") { ssa_emit_startup_runtime(proc); } } @@ -3834,7 +3848,6 @@ void ssa_build_proc(ssaValue *value, ssaProcedure *parent) { AstFile *f = *found; ssaDebugInfo *di_file = NULL; - ssaDebugInfo **di_file_found = map_get(&m->debug_info, hash_pointer(f)); if (di_file_found) { di_file = *di_file_found; @@ -3856,11 +3869,11 @@ void ssa_build_proc(ssaValue *value, ssaProcedure *parent) { defer (proc->module->stmt_state_flags = out); if (in & ProcTag_bounds_check) { - out |= ProcTag_bounds_check; - out &= ~ProcTag_no_bounds_check; + out |= StmtStateFlag_bounds_check; + out &= ~StmtStateFlag_no_bounds_check; } else if (in & ProcTag_no_bounds_check) { - out |= ProcTag_no_bounds_check; - out &= ~ProcTag_bounds_check; + out |= StmtStateFlag_no_bounds_check; + out &= ~StmtStateFlag_bounds_check; } } diff --git a/src/common.cpp b/src/common.cpp index c807e8565..b714f1588 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -55,7 +55,7 @@ struct BlockTimer { } ~BlockTimer() { finish = gb_utc_time_now(); - gb_printf_err("%s - %llu us\n", finish-start); + gb_printf_err("%llu us\n", finish-start); } }; @@ -63,7 +63,10 @@ struct BlockTimer { // Hasing struct HashKey { - u64 key; + union { + u64 key; + void *ptr; + }; b32 is_string; String string; // if String, s.len > 0 }; @@ -182,13 +185,13 @@ template void map_clear (Map *h); template void map_grow (Map *h); template void map_rehash (Map *h, isize new_count); -template typename MapEntry *multi_map_find_first(Map *h, HashKey key); -template typename MapEntry *multi_map_find_next (Map *h, typename MapEntry *e); +template MapEntry *multi_map_find_first(Map *h, HashKey key); +template MapEntry *multi_map_find_next (Map *h, MapEntry *e); template isize multi_map_count (Map *h, HashKey key); template void multi_map_get_all (Map *h, HashKey key, T *items); template void multi_map_insert (Map *h, HashKey key, T value); -template void multi_map_remove (Map *h, HashKey key, typename MapEntry *e); +template void multi_map_remove (Map *h, HashKey key, MapEntry *e); template void multi_map_remove_all(Map *h, HashKey key); @@ -232,7 +235,7 @@ gb_internal MapFindResult map__find(Map *h, HashKey key) { } template -gb_internal MapFindResult map__find(Map *h, typename MapEntry *e) { +gb_internal MapFindResult map__find(Map *h, MapEntry *e) { MapFindResult fr = {-1, -1, -1}; if (gb_array_count(h->hashes) > 0) { fr.hash_index = e->key.key % gb_array_count(h->hashes); @@ -359,7 +362,7 @@ gb_inline void map_clear(Map *h) { template -typename MapEntry *multi_map_find_first(Map *h, HashKey key) { +MapEntry *multi_map_find_first(Map *h, HashKey key) { isize i = map__find(h, key).entry_index; if (i < 0) { return NULL; @@ -368,7 +371,7 @@ typename MapEntry *multi_map_find_first(Map *h, HashKey key) { } template -typename MapEntry *multi_map_find_next(Map *h, typename MapEntry *e) { +MapEntry *multi_map_find_next(Map *h, MapEntry *e) { isize i = e->next; while (i >= 0) { if (hash_key_equal(h->entries[i].key, e->key)) { @@ -420,7 +423,7 @@ void multi_map_insert(Map *h, HashKey key, T value) { } template -void multi_map_remove(Map *h, HashKey key, typename MapEntry *e) { +void multi_map_remove(Map *h, HashKey key, MapEntry *e) { MapFindResult fr = map__find(h, e); if (fr.entry_index >= 0) { map__erase(h, fr); diff --git a/src/gb/gb.h b/src/gb/gb.h index 542677fce..df43cc75c 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6724,7 +6724,7 @@ isize gb_utf8_encode_rune(u8 buf[4], Rune r) { } if (i <= (1<<11)-1) { buf[0] = 0xc0 | cast(u8)(r>>6); - buf[1] = 0x80 | cast(u8)(r)&mask; + buf[1] = 0x80 | (cast(u8)(r)&mask); return 2; } @@ -6734,22 +6734,22 @@ isize gb_utf8_encode_rune(u8 buf[4], Rune r) { r = GB_RUNE_INVALID; buf[0] = 0xe0 | cast(u8)(r>>12); - buf[1] = 0x80 | cast(u8)(r>>6)&mask; - buf[2] = 0x80 | cast(u8)(r)&mask; + buf[1] = 0x80 | (cast(u8)(r>>6)&mask); + buf[2] = 0x80 | (cast(u8)(r)&mask); return 3; } if (i <= (1<<16)-1) { buf[0] = 0xe0 | cast(u8)(r>>12); - buf[1] = 0x80 | cast(u8)(r>>6)&mask; - buf[2] = 0x80 | cast(u8)(r)&mask; + buf[1] = 0x80 | (cast(u8)(r>>6)&mask); + buf[2] = 0x80 | (cast(u8)(r)&mask); return 3; } buf[0] = 0xf0 | cast(u8)(r>>18); - buf[1] = 0x80 | cast(u8)(r>>12)&mask; - buf[2] = 0x80 | cast(u8)(r>>6)&mask; - buf[3] = 0x80 | cast(u8)(r)&mask; + buf[1] = 0x80 | (cast(u8)(r>>12)&mask); + buf[2] = 0x80 | (cast(u8)(r>>6)&mask); + buf[3] = 0x80 | (cast(u8)(r)&mask); return 4; } diff --git a/src/main.cpp b/src/main.cpp index 602812854..6d516945e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,5 @@ +#define DISPLAY_TIMING + #include "common.cpp" #include "unicode.cpp" #include "tokenizer.cpp" @@ -49,7 +51,6 @@ i32 win32_exec_command_line_app(char *fmt, ...) { } } -// #define DISPLAY_TIMING #if defined(DISPLAY_TIMING) #define INIT_TIMER() f64 start_time = gb_time_now(), end_time = 0, total_time = 0 #define PRINT_TIMER(section) do { \ @@ -111,6 +112,7 @@ int main(int argc, char **argv) { gb_printf_err("using: %s [run] \n", argv[0]); return 1; } + init_string_buffer_memory(); String module_dir = get_module_dir(gb_heap_allocator()); diff --git a/src/parser.cpp b/src/parser.cpp index 01e310aa4..5964b0dae 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,5 +1,6 @@ struct AstNode; struct Scope; +struct DeclInfo; enum ParseFileError { ParseFile_None, @@ -21,7 +22,9 @@ struct AstFile { gbArena arena; Tokenizer tokenizer; gbArray(Token) tokens; - Token * cursor; // NOTE(bill): Current token, easy to peek forward and backwards if needed + isize curr_token_index; + Token curr_token; + Token prev_token; // previous non-comment // >= 0: In Expression // < 0: In Control Clause @@ -31,9 +34,10 @@ struct AstFile { AstNodeArray decls; b32 is_global_scope; - AstNode *curr_proc; - isize scope_level; - Scope * scope; // NOTE(bill): Created in checker + AstNode * curr_proc; + isize scope_level; + Scope * scope; // NOTE(bill): Created in checker + DeclInfo *decl_info; // NOTE(bill): Created in checker // TODO(bill): Error recovery // NOTE(bill): Error recovery @@ -931,20 +935,27 @@ gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token fi return result; } -gb_inline b32 next_token(AstFile *f) { - if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) { - f->cursor++; +b32 next_token(AstFile *f) { + if (f->curr_token_index+1 < gb_array_count(f->tokens)) { + if (f->curr_token.kind != Token_Comment) { + f->prev_token = f->curr_token; + } + + f->curr_token_index++; + f->curr_token = f->tokens[f->curr_token_index]; + if (f->curr_token.kind == Token_Comment) { + return next_token(f); + } return true; - } else { - syntax_error(f->cursor[0], "Token is EOF"); - return false; } + syntax_error(f->curr_token, "Token is EOF"); + return false; } gb_inline Token expect_token(AstFile *f, TokenKind kind) { - Token prev = f->cursor[0]; + Token prev = f->curr_token; if (prev.kind != kind) { - syntax_error(f->cursor[0], "Expected `%.*s`, got `%.*s`", + syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`", LIT(token_strings[kind]), LIT(token_strings[prev.kind])); } @@ -953,9 +964,9 @@ gb_inline Token expect_token(AstFile *f, TokenKind kind) { } gb_inline Token expect_operator(AstFile *f) { - Token prev = f->cursor[0]; + Token prev = f->curr_token; if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) { - syntax_error(f->cursor[0], "Expected an operator, got `%.*s`", + syntax_error(f->curr_token, "Expected an operator, got `%.*s`", LIT(token_strings[prev.kind])); } next_token(f); @@ -963,9 +974,9 @@ gb_inline Token expect_operator(AstFile *f) { } gb_inline Token expect_keyword(AstFile *f) { - Token prev = f->cursor[0]; + Token prev = f->curr_token; if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) { - syntax_error(f->cursor[0], "Expected a keyword, got `%.*s`", + syntax_error(f->curr_token, "Expected a keyword, got `%.*s`", LIT(token_strings[prev.kind])); } next_token(f); @@ -973,7 +984,7 @@ gb_inline Token expect_keyword(AstFile *f) { } gb_inline b32 allow_token(AstFile *f, TokenKind kind) { - Token prev = f->cursor[0]; + Token prev = f->curr_token; if (prev.kind == kind) { next_token(f); return true; @@ -990,23 +1001,34 @@ b32 is_blank_ident(String str) { } +// NOTE(bill): Go to next statement to prevent numerous error messages popping up void fix_advance_to_next_stmt(AstFile *f) { // TODO(bill): fix_advance_to_next_stmt -#if 0 +#if 1 for (;;) { - Token t = f->cursor[0]; + Token t = f->curr_token; switch (t.kind) { case Token_EOF: + case Token_Semicolon: return; - case Token_type: + case Token_if: + case Token_return: + case Token_for: + case Token_match: + case Token_defer: + case Token_asm: + case Token_using: + case Token_break: case Token_continue: case Token_fallthrough: - case Token_if: - case Token_for: - case Token_defer: - case Token_return: + + case Token_push_allocator: + case Token_push_context: + + case Token_Hash: + { if (token_pos_are_equal(t.pos, f->fix_prev_pos) && f->fix_count < PARSER_MAX_FIX_COUNT) { f->fix_count++; @@ -1017,7 +1039,8 @@ void fix_advance_to_next_stmt(AstFile *f) { f->fix_count = 0; // NOTE(bill): Reset return; } - + // NOTE(bill): Reaching here means there is a parsing bug + } break; } next_token(f); } @@ -1029,19 +1052,20 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) { return true; } - if (f->cursor[0].pos.line != f->cursor[-1].pos.line) { + if (f->curr_token.pos.line != f->prev_token.pos.line) { return true; } - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_EOF: case Token_CloseBrace: return true; } - syntax_error(f->cursor[0], + syntax_error(f->curr_token, "Expected `;` after %.*s, got `%.*s`", - LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); + LIT(ast_node_strings[s->kind]), LIT(token_strings[f->curr_token.kind])); + fix_advance_to_next_stmt(f); return false; } @@ -1053,7 +1077,7 @@ AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); AstNode *parse_identifier(AstFile *f) { - Token token = f->cursor[0]; + Token token = f->curr_token; if (token.kind == Token_Identifier) { next_token(f); } else { @@ -1088,10 +1112,10 @@ AstNode *parse_value(AstFile *f); AstNodeArray parse_element_list(AstFile *f) { AstNodeArray elems = make_ast_node_array(f); - while (f->cursor[0].kind != Token_CloseBrace && - f->cursor[0].kind != Token_EOF) { + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { AstNode *elem = parse_value(f); - if (f->cursor[0].kind == Token_Eq) { + if (f->curr_token.kind == Token_Eq) { Token eq = expect_token(f, Token_Eq); AstNode *value = parse_value(f); elem = make_field_value(f, elem, value, eq); @@ -1099,7 +1123,7 @@ AstNodeArray parse_element_list(AstFile *f) { gb_array_append(elems, elem); - if (f->cursor[0].kind != Token_Comma) { + if (f->curr_token.kind != Token_Comma) { break; } next_token(f); @@ -1112,7 +1136,7 @@ AstNode *parse_literal_value(AstFile *f, AstNode *type) { AstNodeArray elems = NULL; Token open = expect_token(f, Token_OpenBrace); f->expr_level++; - if (f->cursor[0].kind != Token_CloseBrace) { + if (f->curr_token.kind != Token_CloseBrace) { elems = parse_element_list(f); } f->expr_level--; @@ -1122,7 +1146,7 @@ AstNode *parse_literal_value(AstFile *f, AstNode *type) { } AstNode *parse_value(AstFile *f) { - if (f->cursor[0].kind == Token_OpenBrace) + if (f->curr_token.kind == Token_OpenBrace) return parse_literal_value(f, NULL); AstNode *value = parse_expr(f, false); @@ -1192,20 +1216,20 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n GB_ASSERT(foreign_name != NULL); GB_ASSERT(link_name != NULL); - while (f->cursor[0].kind == Token_Hash) { + while (f->curr_token.kind == Token_Hash) { AstNode *tag_expr = parse_tag_expr(f, NULL); ast_node(te, TagExpr, tag_expr); String tag_name = te->name.string; #define ELSE_IF_ADD_TAG(name) \ - else if (tag_name == make_string(#name)) { \ + else if (tag_name == #name) { \ check_proc_add_tag(f, tag_expr, tags, ProcTag_##name, tag_name); \ } - if (tag_name == make_string("foreign")) { + if (tag_name == "foreign") { check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name); - if (f->cursor[0].kind == Token_String) { - *foreign_name = f->cursor[0].string; + if (f->curr_token.kind == Token_String) { + *foreign_name = f->curr_token.string; // TODO(bill): Check if valid string if (!is_foreign_name_valid(*foreign_name)) { syntax_error(ast_node_token(tag_expr), "Invalid alternative foreign procedure name: `%.*s`", LIT(*foreign_name)); @@ -1213,10 +1237,10 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n next_token(f); } - } else if (tag_name == make_string("link_name")) { + } else if (tag_name == "link_name") { check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name); - if (f->cursor[0].kind == Token_String) { - *link_name = f->cursor[0].string; + if (f->curr_token.kind == Token_String) { + *link_name = f->curr_token.string; // TODO(bill): Check if valid string if (!is_foreign_name_valid(*link_name)) { syntax_error(ast_node_token(tag_expr), "Invalid alternative link procedure name `%.*s`", LIT(*link_name)); @@ -1244,29 +1268,29 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n } if ((*tags & ProcTag_foreign) && (*tags & ProcTag_link_name)) { - syntax_error(f->cursor[0], "You cannot apply both #foreign and #link_name to a procedure"); + syntax_error(f->curr_token, "You cannot apply both #foreign and #link_name to a procedure"); } if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) { - syntax_error(f->cursor[0], "You cannot apply both #inline and #no_inline to a procedure"); + syntax_error(f->curr_token, "You cannot apply both #inline and #no_inline to a procedure"); } if ((*tags & ProcTag_bounds_check) && (*tags & ProcTag_no_bounds_check)) { - syntax_error(f->cursor[0], "You cannot apply both #bounds_check and #no_bounds_check to a procedure"); + syntax_error(f->curr_token, "You cannot apply both #bounds_check and #no_bounds_check to a procedure"); } if (((*tags & ProcTag_bounds_check) || (*tags & ProcTag_no_bounds_check)) && (*tags & ProcTag_foreign)) { - syntax_error(f->cursor[0], "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body"); + syntax_error(f->curr_token, "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body"); } if ((*tags & ProcTag_stdcall) && (*tags & ProcTag_fastcall)) { - syntax_error(f->cursor[0], "You cannot apply one calling convention to a procedure"); + syntax_error(f->curr_token, "You cannot apply one calling convention to a procedure"); } } AstNode *parse_operand(AstFile *f, b32 lhs) { AstNode *operand = NULL; // Operand - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_Identifier: operand = parse_identifier(f); if (!lhs) { @@ -1278,7 +1302,7 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { case Token_Float: case Token_String: case Token_Rune: - operand = make_basic_lit(f, f->cursor[0]); + operand = make_basic_lit(f, f->curr_token); next_token(f); return operand; @@ -1296,9 +1320,9 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { case Token_Hash: { operand = parse_tag_expr(f, NULL); String name = operand->TagExpr.name.string; - if (name == make_string("rune")) { - if (f->cursor[0].kind == Token_String) { - Token *s = &f->cursor[0]; + if (name == "rune") { + if (f->curr_token.kind == Token_String) { + Token *s = &f->curr_token; if (gb_utf8_strnlen(s->string.text, s->string.len) != 1) { syntax_error(*s, "Invalid rune literal %.*s", LIT(s->string)); @@ -1308,12 +1332,12 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { expect_token(f, Token_String); } operand = parse_operand(f, lhs); - } else if (name == make_string("file")) { + } else if (name == "file") { Token token = operand->TagExpr.name; token.kind = Token_String; token.string = token.pos.file; return make_basic_lit(f, token); - } else if (name == make_string("line")) { + } else if (name == "line") { Token token = operand->TagExpr.name; token.kind = Token_Integer; char *str = gb_alloc_array(gb_arena_allocator(&f->arena), char, 20); @@ -1338,13 +1362,13 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { String link_name = {}; parse_proc_tags(f, &tags, &foreign_name, &link_name); if (tags & ProcTag_foreign) { - syntax_error(f->cursor[0], "#foreign cannot be applied to procedure literals"); + syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals"); } if (tags & ProcTag_link_name) { - syntax_error(f->cursor[0], "#link_name cannot be applied to procedure literals"); + syntax_error(f->curr_token, "#link_name cannot be applied to procedure literals"); } - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { return type; } else { AstNode *body; @@ -1367,10 +1391,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { } } - Token begin = f->cursor[0]; + Token begin = f->curr_token; syntax_error(begin, "Expected an operand"); fix_advance_to_next_stmt(f); - return make_bad_expr(f, begin, f->cursor[0]); + return make_bad_expr(f, begin, f->curr_token); } b32 is_literal_type(AstNode *node) { @@ -1394,21 +1418,21 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { f->expr_level++; open_paren = expect_token(f, Token_OpenParen); - while (f->cursor[0].kind != Token_CloseParen && - f->cursor[0].kind != Token_EOF && + while (f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_EOF && ellipsis.pos.line == 0) { - if (f->cursor[0].kind == Token_Comma) - syntax_error(f->cursor[0], "Expected an expression not a ,"); + if (f->curr_token.kind == Token_Comma) + syntax_error(f->curr_token, "Expected an expression not a ,"); - if (f->cursor[0].kind == Token_Ellipsis) { - ellipsis = f->cursor[0]; + if (f->curr_token.kind == Token_Ellipsis) { + ellipsis = f->curr_token; next_token(f); } gb_array_append(args, parse_expr(f, false)); - if (f->cursor[0].kind != Token_Comma) { - if (f->cursor[0].kind == Token_CloseParen) + if (f->curr_token.kind != Token_Comma) { + if (f->curr_token.kind == Token_CloseParen) break; } @@ -1426,7 +1450,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { b32 loop = true; while (loop) { - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_Prime: { Token op = expect_token(f, Token_Prime); @@ -1448,19 +1472,19 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { } break; case Token_Period: { - Token token = f->cursor[0]; + Token token = f->curr_token; next_token(f); if (lhs) { // TODO(bill): handle this } - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_Identifier: operand = make_selector_expr(f, token, operand, parse_identifier(f)); break; default: { - syntax_error(f->cursor[0], "Expected a selector"); + syntax_error(f->curr_token, "Expected a selector"); next_token(f); - operand = make_selector_expr(f, f->cursor[0], operand, NULL); + operand = make_selector_expr(f, f->curr_token, operand, NULL); } break; } } break; @@ -1475,17 +1499,17 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { f->expr_level++; open = expect_token(f, Token_OpenBracket); - if (f->cursor[0].kind != Token_Colon) + if (f->curr_token.kind != Token_Colon) indices[0] = parse_expr(f, false); isize colon_count = 0; Token colons[2] = {}; - while (f->cursor[0].kind == Token_Colon && colon_count < 2) { - colons[colon_count++] = f->cursor[0]; + while (f->curr_token.kind == Token_Colon && colon_count < 2) { + colons[colon_count++] = f->curr_token; next_token(f); - if (f->cursor[0].kind != Token_Colon && - f->cursor[0].kind != Token_CloseBracket && - f->cursor[0].kind != Token_EOF) { + if (f->curr_token.kind != Token_Colon && + f->curr_token.kind != Token_CloseBracket && + f->curr_token.kind != Token_EOF) { indices[colon_count] = parse_expr(f, false); } } @@ -1518,7 +1542,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { case Token_OpenBrace: { if (!lhs && is_literal_type(operand) && f->expr_level >= 0) { - if (f->cursor[0].pos.line == f->cursor[-1].pos.line) { + if (f->curr_token.pos.line == f->prev_token.pos.line) { // TODO(bill): This is a hack due to optional semicolons // TODO(bill): It's probably much better to solve this by changing // the syntax for struct literals and array literals @@ -1545,14 +1569,14 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { AstNode *parse_type(AstFile *f); AstNode *parse_unary_expr(AstFile *f, b32 lhs) { - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_Pointer: case Token_Add: case Token_Sub: case Token_Not: case Token_Xor: { AstNode *operand; - Token op = f->cursor[0]; + Token op = f->curr_token; next_token(f); operand = parse_unary_expr(f, lhs); return make_unary_expr(f, op, operand); @@ -1564,10 +1588,10 @@ AstNode *parse_unary_expr(AstFile *f, b32 lhs) { AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { AstNode *expression = parse_unary_expr(f, lhs); - for (i32 prec = token_precedence(f->cursor[0]); prec >= prec_in; prec--) { + for (i32 prec = token_precedence(f->curr_token); prec >= prec_in; prec--) { for (;;) { AstNode *right; - Token op = f->cursor[0]; + Token op = f->curr_token; i32 op_prec = token_precedence(op); if (op_prec != prec) break; @@ -1581,7 +1605,7 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { case Token_DoublePrime: { // TODO(bill): Properly define semantic for in-fix and post-fix calls AstNode *proc = parse_identifier(f); - /* if (f->cursor[0].kind == Token_OpenParen) { + /* if (f->curr_token.kind == Token_OpenParen) { AstNode *call = parse_call_expr(f, proc); gb_array_append(call->CallExpr.args, expression); for (isize i = gb_array_count(call->CallExpr.args)-1; i > 0; i--) { @@ -1629,8 +1653,8 @@ AstNodeArray parse_expr_list(AstFile *f, b32 lhs) { do { AstNode *e = parse_expr(f, lhs); gb_array_append(list, e); - if (f->cursor[0].kind != Token_Comma || - f->cursor[0].kind == Token_EOF) { + if (f->curr_token.kind != Token_Comma || + f->curr_token.kind == Token_EOF) { break; } next_token(f); @@ -1655,7 +1679,7 @@ AstNode *parse_simple_stmt(AstFile *f) { AstNode *statement = NULL; - Token token = f->cursor[0]; + Token token = f->curr_token; switch (token.kind) { case Token_Eq: case Token_AddEq: @@ -1673,14 +1697,14 @@ AstNode *parse_simple_stmt(AstFile *f) { case Token_CmpOrEq: { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a simple statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a simple statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } next_token(f); AstNodeArray rhs = parse_rhs_expr_list(f); if (gb_array_count(rhs) == 0) { syntax_error(token, "No right-hand side in assignment statement."); - return make_bad_stmt(f, token, f->cursor[0]); + return make_bad_stmt(f, token, f->curr_token); } return make_assign_stmt(f, token, lhs, rhs); } break; @@ -1691,16 +1715,16 @@ AstNode *parse_simple_stmt(AstFile *f) { if (lhs_count > 1) { syntax_error(token, "Expected 1 expression"); - return make_bad_stmt(f, token, f->cursor[0]); + return make_bad_stmt(f, token, f->curr_token); } - token = f->cursor[0]; + token = f->curr_token; switch (token.kind) { case Token_Increment: case Token_Decrement: if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a simple statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a simple statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } statement = make_inc_dec_stmt(f, token, lhs[0]); next_token(f); @@ -1714,8 +1738,8 @@ AstNode *parse_simple_stmt(AstFile *f) { AstNode *parse_block_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a block statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a block statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } AstNode *block_stmt = parse_body(f); return block_stmt; @@ -1728,8 +1752,8 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { if (statement->kind == AstNode_ExprStmt) return statement->ExprStmt.expr; - syntax_error(f->cursor[0], "Expected `%.*s`, found a simple statement.", LIT(kind)); - return make_bad_expr(f, f->cursor[0], f->cursor[1]); + syntax_error(f->curr_token, "Expected `%.*s`, found a simple statement.", LIT(kind)); + return make_bad_expr(f, f->curr_token, f->tokens[f->curr_token_index+1]); } AstNodeArray parse_identfier_list(AstFile *f) { @@ -1737,8 +1761,8 @@ AstNodeArray parse_identfier_list(AstFile *f) { do { gb_array_append(list, parse_identifier(f)); - if (f->cursor[0].kind != Token_Comma || - f->cursor[0].kind == Token_EOF) { + if (f->curr_token.kind != Token_Comma || + f->curr_token.kind == Token_EOF) { break; } next_token(f); @@ -1760,10 +1784,10 @@ AstNode *parse_type_attempt(AstFile *f) { AstNode *parse_type(AstFile *f) { AstNode *type = parse_type_attempt(f); if (type == NULL) { - Token token = f->cursor[0]; + Token token = f->curr_token; syntax_error(token, "Expected a type"); next_token(f); - return make_bad_expr(f, token, f->cursor[0]); + return make_bad_expr(f, token, f->curr_token); } return type; } @@ -1789,11 +1813,11 @@ AstNode *parse_field_decl(AstFile *f) { AstNodeArray names = parse_lhs_expr_list(f); if (gb_array_count(names) == 0) { - syntax_error(f->cursor[0], "Empty field declaration"); + syntax_error(f->curr_token, "Empty field declaration"); } if (gb_array_count(names) > 1 && is_using) { - syntax_error(f->cursor[0], "Cannot apply `using` to more than one of the same type"); + syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); is_using = false; } @@ -1801,16 +1825,16 @@ AstNode *parse_field_decl(AstFile *f) { expect_token(f, Token_Colon); AstNode *type = NULL; - if (f->cursor[0].kind == Token_Ellipsis) { - Token ellipsis = f->cursor[0]; + if (f->curr_token.kind == Token_Ellipsis) { + Token ellipsis = f->curr_token; next_token(f); type = parse_type_attempt(f); if (type == NULL) { - syntax_error(f->cursor[0], "variadic parameter is missing a type after `..`"); - type = make_bad_expr(f, ellipsis, f->cursor[0]); + syntax_error(f->curr_token, "variadic parameter is missing a type after `..`"); + type = make_bad_expr(f, ellipsis, f->curr_token); } else { if (gb_array_count(names) > 1) { - syntax_error(f->cursor[0], "mutliple variadic parameters, only `..`"); + syntax_error(f->curr_token, "mutliple variadic parameters, only `..`"); } else { type = make_ellipsis(f, ellipsis, type); } @@ -1820,7 +1844,7 @@ AstNode *parse_field_decl(AstFile *f) { } if (type == NULL) { - syntax_error(f->cursor[0], "Expected a type for this field declaration"); + syntax_error(f->curr_token, "Expected a type for this field declaration"); } AstNode *field = make_field(f, names, type, is_using); @@ -1829,11 +1853,11 @@ AstNode *parse_field_decl(AstFile *f) { AstNodeArray parse_parameter_list(AstFile *f) { AstNodeArray params = make_ast_node_array(f); - while (f->cursor[0].kind == Token_Identifier || - f->cursor[0].kind == Token_using) { + while (f->curr_token.kind == Token_Identifier || + f->curr_token.kind == Token_using) { AstNode *field = parse_field_decl(f); gb_array_append(params, field); - if (f->cursor[0].kind != Token_Comma) { + if (f->curr_token.kind != Token_Comma) { break; } next_token(f); @@ -1847,37 +1871,37 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow AstNodeArray decls = make_ast_node_array(f); isize decl_count = 0; - while (f->cursor[0].kind == Token_Identifier || - f->cursor[0].kind == Token_using) { + while (f->curr_token.kind == Token_Identifier || + f->curr_token.kind == Token_using) { b32 is_using = false; if (allow_token(f, Token_using)) { is_using = true; } AstNodeArray names = parse_lhs_expr_list(f); if (gb_array_count(names) == 0) { - syntax_error(f->cursor[0], "Empty field declaration"); + syntax_error(f->curr_token, "Empty field declaration"); } if (!using_allowed && is_using) { - syntax_error(f->cursor[0], "Cannot apply `using` to members of a union"); + syntax_error(f->curr_token, "Cannot apply `using` to members of a union"); is_using = false; } if (gb_array_count(names) > 1 && is_using) { - syntax_error(f->cursor[0], "Cannot apply `using` to more than one of the same type"); + syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); } AstNode *decl = NULL; - if (f->cursor[0].kind == Token_Colon) { + if (f->curr_token.kind == Token_Colon) { decl = parse_decl(f, names); if (decl->kind == AstNode_ProcDecl) { - syntax_error(f->cursor[0], "Procedure declarations are not allowed within a structure"); - decl = make_bad_decl(f, ast_node_token(names[0]), f->cursor[0]); + syntax_error(f->curr_token, "Procedure declarations are not allowed within a structure"); + decl = make_bad_decl(f, ast_node_token(names[0]), f->curr_token); } } else { - syntax_error(f->cursor[0], "Illegal structure field"); - decl = make_bad_decl(f, ast_node_token(names[0]), f->cursor[0]); + syntax_error(f->curr_token, "Illegal structure field"); + decl = make_bad_decl(f, ast_node_token(names[0]), f->curr_token); } expect_semicolon_after_stmt(f, decl); @@ -1887,7 +1911,7 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow if (decl->kind == AstNode_VarDecl) { decl->VarDecl.is_using = is_using && using_allowed; if (gb_array_count(decl->VarDecl.values) > 0) { - syntax_error(f->cursor[0], "Default variable assignments within a structure will be ignored (at the moment)"); + syntax_error(f->curr_token, "Default variable assignments within a structure will be ignored (at the moment)"); } } else { decl_count += 1; @@ -1901,7 +1925,7 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow } AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_volatile: next_token(f); return parse_identifier_or_type(f, flags | TypeFlag_volatile); @@ -1912,13 +1936,13 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { case Token_Identifier: { AstNode *e = parse_identifier(f); - while (f->cursor[0].kind == Token_Period) { - Token token = f->cursor[0]; + while (f->curr_token.kind == Token_Period) { + Token token = f->curr_token; next_token(f); AstNode *sel = parse_identifier(f); e = make_selector_expr(f, token, e, sel); } - if (f->cursor[0].kind == Token_OpenParen) { + if (f->curr_token.kind == Token_OpenParen) { // HACK NOTE(bill): For type_of_val(expr) e = parse_call_expr(f, e); } @@ -1937,10 +1961,10 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { Token token = expect_token(f, Token_OpenBracket); AstNode *count_expr = NULL; - if (f->cursor[0].kind == Token_Ellipsis) { - count_expr = make_ellipsis(f, f->cursor[0], NULL); + if (f->curr_token.kind == Token_Ellipsis) { + count_expr = make_ellipsis(f, f->curr_token, NULL); next_token(f); - } else if (f->cursor[0].kind != Token_CloseBracket) { + } else if (f->curr_token.kind != Token_CloseBracket) { count_expr = parse_expr(f, false); } expect_token(f, Token_CloseBracket); @@ -1967,9 +1991,9 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { b32 is_ordered = false; while (allow_token(f, Token_Hash)) { Token tag = expect_token(f, Token_Identifier); - if (tag.string == make_string("packed")) { + if (tag.string == "packed") { is_packed = true; - } else if (tag.string == make_string("ordered")) { + } else if (tag.string == "ordered") { is_ordered = true; } else { syntax_error(tag, "Expected a `#packed` or `#ordered` tag"); @@ -2019,7 +2043,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { AstNode *base_type = NULL; Token open, close; - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { base_type = parse_type(f); } @@ -2027,18 +2051,18 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { open = expect_token(f, Token_OpenBrace); - while (f->cursor[0].kind != Token_CloseBrace && - f->cursor[0].kind != Token_EOF) { + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { AstNode *name = parse_identifier(f); AstNode *value = NULL; Token eq = empty_token; - if (f->cursor[0].kind == Token_Eq) { + if (f->curr_token.kind == Token_Eq) { eq = expect_token(f, Token_Eq); value = parse_value(f); } AstNode *field = make_field_value(f, name, value, eq); gb_array_append(fields, field); - if (f->cursor[0].kind != Token_Comma) { + if (f->curr_token.kind != Token_Comma) { break; } next_token(f); @@ -2077,12 +2101,12 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { break; case Token_Eq: - if (f->cursor[-1].kind == Token_Colon) + if (f->prev_token.kind == Token_Colon) break; // fallthrough default: - syntax_error(f->cursor[0], - "Expected a type or identifier after `%.*s`, got `%.*s`", LIT(f->cursor[-1].string), LIT(f->cursor[0].string)); + syntax_error(f->curr_token, + "Expected a type or identifier after `%.*s`, got `%.*s`", LIT(f->prev_token.string), LIT(f->curr_token.string)); break; } @@ -2093,12 +2117,12 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { AstNodeArray parse_results(AstFile *f) { AstNodeArray results = make_ast_node_array(f); if (allow_token(f, Token_ArrowRight)) { - if (f->cursor[0].kind == Token_OpenParen) { + if (f->curr_token.kind == Token_OpenParen) { expect_token(f, Token_OpenParen); - while (f->cursor[0].kind != Token_CloseParen && - f->cursor[0].kind != Token_EOF) { + while (f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_EOF) { gb_array_append(results, parse_type(f)); - if (f->cursor[0].kind != Token_Comma) { + if (f->curr_token.kind != Token_Comma) { break; } next_token(f); @@ -2155,9 +2179,9 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { f->curr_proc = proc_type; defer (f->curr_proc = curr_proc); - if (f->cursor[0].kind == Token_OpenBrace) { + if (f->curr_token.kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { - syntax_error(f->cursor[0], "A procedure tagged as `#foreign` cannot have a body"); + syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body"); } body = parse_body(f); } @@ -2174,7 +2198,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { if (name->kind == AstNode_Ident) { String n = name->Ident.string; // NOTE(bill): Check for reserved identifiers - if (n == make_string("context")) { + if (n == "context") { syntax_error(ast_node_token(name), "`context` is a reserved identifier"); break; } @@ -2185,25 +2209,25 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { if (!allow_token(f, Token_type)) { type = parse_identifier_or_type(f); } - } else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) { - syntax_error(f->cursor[0], "Expected type separator `:` or `=`"); + } else if (f->curr_token.kind != Token_Eq && f->curr_token.kind != Token_Semicolon) { + syntax_error(f->curr_token, "Expected type separator `:` or `=`"); } b32 is_mutable = true; - if (f->cursor[0].kind == Token_Eq || - f->cursor[0].kind == Token_Colon) { - if (f->cursor[0].kind == Token_Colon) { + if (f->curr_token.kind == Token_Eq || + f->curr_token.kind == Token_Colon) { + if (f->curr_token.kind == Token_Colon) { is_mutable = false; } next_token(f); - if (f->cursor[0].kind == Token_type || - f->cursor[0].kind == Token_struct || - f->cursor[0].kind == Token_enum || - f->cursor[0].kind == Token_union || - f->cursor[0].kind == Token_raw_union) { - Token token = f->cursor[0]; + if (f->curr_token.kind == Token_type || + f->curr_token.kind == Token_struct || + f->curr_token.kind == Token_enum || + f->curr_token.kind == Token_union || + f->curr_token.kind == Token_raw_union) { + Token token = f->curr_token; if (token.kind == Token_type) { next_token(f); } @@ -2213,16 +2237,16 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { } if (type != NULL) { - syntax_error(f->cursor[-1], "Expected either `type` or nothing between : and :"); + syntax_error(f->prev_token, "Expected either `type` or nothing between : and :"); // NOTE(bill): Do not fail though } AstNode *type = parse_type(f); return make_type_decl(f, token, names[0], type); - } else if (f->cursor[0].kind == Token_proc && + } else if (f->curr_token.kind == Token_proc && is_mutable == false) { // NOTE(bill): Procedure declarations - Token proc_token = f->cursor[0]; + Token proc_token = f->curr_token; AstNode *name = names[0]; if (gb_array_count(names) != 1) { syntax_error(proc_token, "You can only declare one procedure at a time"); @@ -2234,24 +2258,24 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { } else { values = parse_rhs_expr_list(f); if (gb_array_count(values) > gb_array_count(names)) { - syntax_error(f->cursor[0], "Too many values on the right hand side of the declaration"); + syntax_error(f->curr_token, "Too many values on the right hand side of the declaration"); } else if (gb_array_count(values) < gb_array_count(names) && !is_mutable) { - syntax_error(f->cursor[0], "All constant declarations must be defined"); + syntax_error(f->curr_token, "All constant declarations must be defined"); } else if (gb_array_count(values) == 0) { - syntax_error(f->cursor[0], "Expected an expression for this declaration"); + syntax_error(f->curr_token, "Expected an expression for this declaration"); } } } if (is_mutable) { if (type == NULL && gb_array_count(values) == 0) { - syntax_error(f->cursor[0], "Missing variable type or initialization"); - return make_bad_decl(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "Missing variable type or initialization"); + return make_bad_decl(f, f->curr_token, f->curr_token); } } else { if (type == NULL && gb_array_count(values) == 0 && gb_array_count(names) > 0) { - syntax_error(f->cursor[0], "Missing constant value"); - return make_bad_decl(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "Missing constant value"); + return make_bad_decl(f, f->curr_token, f->curr_token); } } @@ -2268,8 +2292,8 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { AstNode *parse_if_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use an if statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use an if statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } Token token = expect_token(f, Token_if); @@ -2297,13 +2321,13 @@ AstNode *parse_if_stmt(AstFile *f) { f->expr_level = prev_level; if (cond == NULL) { - syntax_error(f->cursor[0], "Expected condition for if statement"); + syntax_error(f->curr_token, "Expected condition for if statement"); } body = parse_block_stmt(f); if (allow_token(f, Token_else)) { - switch (f->cursor[0].kind) { + switch (f->curr_token.kind) { case Token_if: else_stmt = parse_if_stmt(f); break; @@ -2311,8 +2335,8 @@ AstNode *parse_if_stmt(AstFile *f) { else_stmt = parse_block_stmt(f); break; default: - syntax_error(f->cursor[0], "Expected if statement block statement"); - else_stmt = make_bad_stmt(f, f->cursor[0], f->cursor[1]); + syntax_error(f->curr_token, "Expected if statement block statement"); + else_stmt = make_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]); break; } } @@ -2322,18 +2346,18 @@ AstNode *parse_if_stmt(AstFile *f) { AstNode *parse_return_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a return statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a return statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } Token token = expect_token(f, Token_return); AstNodeArray results = make_ast_node_array(f); - if (f->cursor[0].kind != Token_Semicolon && f->cursor[0].kind != Token_CloseBrace && - f->cursor[0].pos.line == token.pos.line) { + if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace && + f->curr_token.pos.line == token.pos.line) { results = parse_rhs_expr_list(f); } - if (f->cursor[0].kind != Token_CloseBrace) { + if (f->curr_token.kind != Token_CloseBrace) { expect_semicolon_after_stmt(f, results ? results[0] : NULL); } @@ -2342,8 +2366,8 @@ AstNode *parse_return_stmt(AstFile *f) { AstNode *parse_for_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a for statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a for statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } Token token = expect_token(f, Token_for); @@ -2353,13 +2377,13 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *end = NULL; AstNode *body = NULL; - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { isize prev_level = f->expr_level; f->expr_level = -1; - if (f->cursor[0].kind != Token_Semicolon) { + if (f->curr_token.kind != Token_Semicolon) { cond = parse_simple_stmt(f); if (is_ast_node_complex_stmt(cond)) { - syntax_error(f->cursor[0], + syntax_error(f->curr_token, "You are not allowed that type of statement in a for statement, it is too complex!"); } } @@ -2367,11 +2391,11 @@ AstNode *parse_for_stmt(AstFile *f) { if (allow_token(f, Token_Semicolon)) { init = cond; cond = NULL; - if (f->cursor[0].kind != Token_Semicolon) { + if (f->curr_token.kind != Token_Semicolon) { cond = parse_simple_stmt(f); } expect_token(f, Token_Semicolon); - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { end = parse_simple_stmt(f); } } @@ -2385,7 +2409,7 @@ AstNode *parse_for_stmt(AstFile *f) { } AstNode *parse_case_clause(AstFile *f) { - Token token = f->cursor[0]; + Token token = f->curr_token; AstNodeArray list = make_ast_node_array(f); if (allow_token(f, Token_case)) { list = parse_rhs_expr_list(f); @@ -2400,7 +2424,7 @@ AstNode *parse_case_clause(AstFile *f) { AstNode *parse_type_case_clause(AstFile *f) { - Token token = f->cursor[0]; + Token token = f->curr_token; AstNodeArray clause = make_ast_node_array(f); if (allow_token(f, Token_case)) { gb_array_append(clause, parse_expr(f, false)); @@ -2416,8 +2440,8 @@ AstNode *parse_type_case_clause(AstFile *f) { AstNode *parse_match_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a match statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a match statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } Token token = expect_token(f, Token_match); @@ -2441,8 +2465,8 @@ AstNode *parse_match_stmt(AstFile *f) { open = expect_token(f, Token_OpenBrace); AstNodeArray list = make_ast_node_array(f); - while (f->cursor[0].kind == Token_case || - f->cursor[0].kind == Token_default) { + while (f->curr_token.kind == Token_case || + f->curr_token.kind == Token_default) { gb_array_append(list, parse_type_case_clause(f)); } @@ -2452,16 +2476,16 @@ AstNode *parse_match_stmt(AstFile *f) { tag = convert_stmt_to_expr(f, tag, make_string("type match expression")); return make_type_match_stmt(f, token, tag, var, body); } else { - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { isize prev_level = f->expr_level; f->expr_level = -1; - if (f->cursor[0].kind != Token_Semicolon) { + if (f->curr_token.kind != Token_Semicolon) { tag = parse_simple_stmt(f); } if (allow_token(f, Token_Semicolon)) { init = tag; tag = NULL; - if (f->cursor[0].kind != Token_OpenBrace) { + if (f->curr_token.kind != Token_OpenBrace) { tag = parse_simple_stmt(f); } } @@ -2472,8 +2496,8 @@ AstNode *parse_match_stmt(AstFile *f) { open = expect_token(f, Token_OpenBrace); AstNodeArray list = make_ast_node_array(f); - while (f->cursor[0].kind == Token_case || - f->cursor[0].kind == Token_default) { + while (f->curr_token.kind == Token_case || + f->curr_token.kind == Token_default) { gb_array_append(list, parse_case_clause(f)); } @@ -2489,8 +2513,8 @@ AstNode *parse_match_stmt(AstFile *f) { AstNode *parse_defer_stmt(AstFile *f) { if (f->curr_proc == NULL) { - syntax_error(f->cursor[0], "You cannot use a defer statement in the file scope"); - return make_bad_stmt(f, f->cursor[0], f->cursor[0]); + syntax_error(f->curr_token, "You cannot use a defer statement in the file scope"); + return make_bad_stmt(f, f->curr_token, f->curr_token); } Token token = expect_token(f, Token_defer); @@ -2528,7 +2552,7 @@ AstNode *parse_asm_stmt(AstFile *f) { // TODO(bill): Finish asm statement and determine syntax - // if (f->cursor[0].kind != Token_CloseBrace) { + // if (f->curr_token.kind != Token_CloseBrace) { // expect_token(f, Token_Colon); // } @@ -2544,7 +2568,7 @@ AstNode *parse_asm_stmt(AstFile *f) { AstNode *parse_stmt(AstFile *f) { AstNode *s = NULL; - Token token = f->cursor[0]; + Token token = f->curr_token; switch (token.kind) { // Operands case Token_Identifier: @@ -2605,7 +2629,7 @@ AstNode *parse_stmt(AstFile *f) { if (!valid) { syntax_error(token, "Illegal use of `using` statement."); - return make_bad_stmt(f, token, f->cursor[0]); + return make_bad_stmt(f, token, f->curr_token); } @@ -2637,21 +2661,21 @@ AstNode *parse_stmt(AstFile *f) { case Token_Hash: { s = parse_tag_stmt(f, NULL); String tag = s->TagStmt.name.string; - if (tag == make_string("shared_global_scope")) { + if (tag == "shared_global_scope") { if (f->curr_proc == NULL) { f->is_global_scope = true; - return make_empty_stmt(f, f->cursor[0]); + return make_empty_stmt(f, f->curr_token); } syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope."); - return make_bad_decl(f, token, f->cursor[0]); - } else if (tag == make_string("import")) { + return make_bad_decl(f, token, f->curr_token); + } else if (tag == "import") { // TODO(bill): better error messages Token import_name = {}; Token file_path = expect_token(f, Token_String); if (allow_token(f, Token_as)) { // NOTE(bill): Custom import name - if (f->cursor[0].kind == Token_Period) { - import_name = f->cursor[0]; + if (f->curr_token.kind == Token_Period) { + import_name = f->curr_token; import_name.kind = Token_Identifier; next_token(f); } else { @@ -2664,7 +2688,7 @@ AstNode *parse_stmt(AstFile *f) { } syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); - } else if (tag == make_string("load")) { + } else if (tag == "load") { // TODO(bill): better error messages Token file_path = expect_token(f, Token_String); Token import_name = file_path; @@ -2675,14 +2699,14 @@ AstNode *parse_stmt(AstFile *f) { } syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); - } else if (tag == make_string("foreign_system_library")) { + } else if (tag == "foreign_system_library") { Token file_path = expect_token(f, Token_String); if (f->curr_proc == NULL) { return make_foreign_system_library(f, s->TagStmt.token, file_path); } syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); - } else if (tag == make_string("thread_local")) { + } else if (tag == "thread_local") { AstNode *var_decl = parse_simple_stmt(f); if (var_decl->kind != AstNode_VarDecl) { syntax_error(token, "#thread_local may only be applied to variable declarations"); @@ -2694,14 +2718,14 @@ AstNode *parse_stmt(AstFile *f) { } var_decl->VarDecl.tags |= VarDeclTag_thread_local; return var_decl; - } else if (tag == make_string("bounds_check")) { + } else if (tag == "bounds_check") { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together"); } return s; - } else if (tag == make_string("no_bounds_check")) { + } else if (tag == "no_bounds_check") { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_no_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_bounds_check) != 0) { @@ -2727,16 +2751,16 @@ AstNode *parse_stmt(AstFile *f) { "Expected a statement, got `%.*s`", LIT(token_strings[token.kind])); fix_advance_to_next_stmt(f); - return make_bad_stmt(f, token, f->cursor[0]); + return make_bad_stmt(f, token, f->curr_token); } AstNodeArray parse_stmt_list(AstFile *f) { AstNodeArray list = make_ast_node_array(f); - while (f->cursor[0].kind != Token_case && - f->cursor[0].kind != Token_default && - f->cursor[0].kind != Token_CloseBrace && - f->cursor[0].kind != Token_EOF) { + while (f->curr_token.kind != Token_case && + f->curr_token.kind != Token_default && + f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { AstNode *stmt = parse_stmt(f); if (stmt && stmt->kind != AstNode_EmptyStmt) { gb_array_append(list, stmt); @@ -2766,7 +2790,9 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) { } } - f->cursor = &f->tokens[0]; + f->curr_token_index = 0; + f->prev_token = f->tokens[f->curr_token_index]; + f->curr_token = f->tokens[f->curr_token_index]; // NOTE(bill): Is this big enough or too small? isize arena_size = gb_size_of(AstNode); diff --git a/src/string.cpp b/src/string.cpp index 6a08c5aa4..e15498cd1 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -14,7 +14,7 @@ typedef struct String { isize len; } String; // NOTE(bill): used for printf style arguments -#define LIT(x) (x).len, (x).text +#define LIT(x) ((int)(x).len), (x).text typedef struct String16 { @@ -46,6 +46,11 @@ gb_inline String make_string(char *text) { return make_string(cast(u8 *)cast(void *)text, gb_strlen(text)); } +template +gb_inline String make_string(char const (&text)[N]) { + return make_string(cast(u8 *)cast(void *)text, N-1); +} + gb_inline b32 are_strings_equal(String a, String b) { if (a.len == b.len) { return gb_memcompare(a.text, b.text, a.len) == 0; @@ -117,6 +122,12 @@ bool operator > (String a, String b) { return string_compare(a, b) > 0; } bool operator <=(String a, String b) { return string_compare(a, b) <= 0; } bool operator >=(String a, String b) { return string_compare(a, b) >= 0; } +template bool operator ==(String a, char const (&b)[N]) { return a == make_string(b); } +template bool operator !=(String a, char const (&b)[N]) { return a != make_string(b); } +template bool operator ==(char const (&a)[N], String b) { return make_string(a) == b; } +template bool operator !=(char const (&a)[N], String b) { return make_string(a) != b; } + + gb_inline isize string_extension_position(String str) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 487ab004c..ffa44ca89 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -1,6 +1,7 @@ #define TOKEN_KINDS \ TOKEN_KIND(Token_Invalid, "Invalid"), \ TOKEN_KIND(Token_EOF, "EOF"), \ + TOKEN_KIND(Token_Comment, "Comment"), \ \ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \ TOKEN_KIND(Token_Identifier, "Identifier"), \ @@ -317,8 +318,7 @@ struct Tokenizer { }; -#define tokenizer_err(t, msg, ...) tokenizer_err_(t, __FUNCTION__, msg, ##__VA_ARGS__) -void tokenizer_err_(Tokenizer *t, char *function, char *msg, ...) { +void tokenizer_err(Tokenizer *t, char *msg, ...) { va_list va; isize column = t->read_curr - t->line+1; if (column < 1) @@ -428,41 +428,8 @@ gb_inline void destroy_tokenizer(Tokenizer *t) { } void tokenizer_skip_whitespace(Tokenizer *t) { - for (;;) { - if (rune_is_whitespace(t->curr_rune)) { - advance_to_next_rune(t); - } else if (t->curr_rune == '/') { - if (t->read_curr[0] == '/') { // Line comment // - while (t->curr_rune != '\n') { - advance_to_next_rune(t); - } - } else if (t->read_curr[0] == '*') { // (Nested) Block comment /**/ - advance_to_next_rune(t); - advance_to_next_rune(t); - isize comment_scope = 1; - while (comment_scope > 0) { - if (t->curr_rune == '/') { - advance_to_next_rune(t); - if (t->curr_rune == '*') { - advance_to_next_rune(t); - comment_scope++; - } - } else if (t->curr_rune == '*') { - advance_to_next_rune(t); - if (t->curr_rune == '/') { - advance_to_next_rune(t); - comment_scope--; - } - } else { - advance_to_next_rune(t); - } - } - } else { - break; - } - } else { - break; - } + while (rune_is_whitespace(t->curr_rune)) { + advance_to_next_rune(t); } } @@ -787,13 +754,43 @@ Token tokenizer_get_token(Tokenizer *t) { case ':': token.kind = Token_Colon; break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; - case '/': token.kind = token_kind_variant2(t, Token_Quo, Token_QuoEq); break; case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break; case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break; + case '/': { + if (t->curr_rune == '/') { + while (t->curr_rune != '\n') { + advance_to_next_rune(t); + } + token.kind = Token_Comment; + } else if (t->curr_rune == '*') { + isize comment_scope = 1; + advance_to_next_rune(t); + while (comment_scope > 0) { + if (curr_rune == '/') { + advance_to_next_rune(t); + if (t->curr_rune == '*') { + advance_to_next_rune(t); + comment_scope++; + } + } else if (t->curr_rune == '*') { + advance_to_next_rune(t); + if (t->curr_rune == '/') { + advance_to_next_rune(t); + comment_scope--; + } + } else { + advance_to_next_rune(t); + } + } + token.kind = Token_Comment; + } else { + token.kind = token_kind_variant2(t, Token_Quo, Token_QuoEq); + } + } break; case '<': if (t->curr_rune == '-') { diff --git a/src/unicode.cpp b/src/unicode.cpp index d8a26924c..a9781d8f7 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -1,15 +1,15 @@ #pragma warning(push) #pragma warning(disable: 4245) -#include "utf8proc/utf8proc.h" -// #define UTF8PROC_IMPLEMENTATION -// #include "utf8proc/utf8proc_new.h" +// #include "utf8proc/utf8proc.h" +#include "utf8proc/utf8proc.c" #pragma warning(pop) // TODO(bill): Unicode support b32 rune_is_letter(Rune r) { - if (r < 0x80 && gb_char_is_alpha(cast(char)r) || r == '_') { + if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) || + r == '_') { return true; } switch (utf8proc_category(r)) { diff --git a/src/utf8proc/utf8proc.c b/src/utf8proc/utf8proc.c index f3ff862dd..7a6c984ac 100644 --- a/src/utf8proc/utf8proc.c +++ b/src/utf8proc/utf8proc.c @@ -458,12 +458,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, category == UTF8PROC_CATEGORY_ME) return 0; } if (options & UTF8PROC_CASEFOLD) { - if (property->casefold_seqindex != UINT16_MAX) { + if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) { return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass); } } if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { - if (property->decomp_seqindex != UINT16_MAX && + if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX && (!property->decomp_type || (options & UTF8PROC_COMPAT))) { return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass); } @@ -621,7 +621,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, starter_property = unsafe_get_property(*starter); } if (starter_property->comb_index < 0x8000 && - current_property->comb_index != UINT16_MAX && + (utf8proc_int16_t)current_property->comb_index != UINT16_MAX && current_property->comb_index >= 0x8000) { int sidx = starter_property->comb_index; int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];