diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 37a5c2249..0ce662570 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -640,7 +640,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -void check_var_decl(CheckerContext *ctx, Entity *e, Entity **entities, isize entity_count, Ast *type_expr, Array const &init_expr_list) { +void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -651,7 +651,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Entity **entities, isize ent e->flags |= EntityFlag_Visited; AttributeContext ac = make_attribute_context(e->Variable.link_prefix); - ac.init_expr_list_count = init_expr_list.count; + ac.init_expr_list_count = init_expr != nullptr ? 1 : 0; DeclInfo *decl = decl_info_of_entity(e); if (decl != nullptr) { @@ -682,7 +682,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Entity **entities, isize ent if (e->Variable.is_foreign) { - if (init_expr_list.count > 0) { + if (init_expr != nullptr) { error(e->token, "A foreign variable declaration cannot have a default value"); } init_entity_foreign_library(ctx, e); @@ -716,20 +716,16 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Entity **entities, isize ent } } - if (init_expr_list.count == 0) { + if (init_expr == nullptr) { if (type_expr == nullptr) { e->type = t_invalid; } return; } - if (type_expr != nullptr) { - for (isize i = 0; i < entity_count; i++) { - entities[i]->type = e->type; - } - } - - check_init_variables(ctx, entities, entity_count, init_expr_list, context_name); + Operand o = {}; + check_expr(ctx, &o, init_expr); + check_init_variable(ctx, e, &o, str_lit("variable declaration")); } void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) { @@ -895,7 +891,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ switch (e->kind) { case Entity_Variable: - check_var_decl(&c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list); + check_var_decl(&c, e, d->type_expr, d->init_expr); break; case Entity_Constant: check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 382cf1020..ada8a177d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -44,7 +44,6 @@ int valid_index_and_score_cmp(void const *a, void const *b) { - #define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); @@ -5206,6 +5205,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(bl, BasicLit, node); + // NOTE(bill, 2018-06-17): Placing this in the parser is slower than + // placing it here for some reason. So don't move it to the parsing + // stage if you _think_ it will be faster, only do it if you _know_ it + // will be faster. Type *t = t_invalid; switch (bl->token.kind) { case Token_Integer: t = t_untyped_integer; break; @@ -5231,6 +5234,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_end; case_ast_node(bd, BasicDirective, node); + o->mode = Addressing_Constant; if (bd->name == "file") { o->type = t_untyped_string; o->value = exact_value_string(bd->token.pos.file); @@ -5254,7 +5258,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } else { GB_PANIC("Unknown basic directive"); } - o->mode = Addressing_Constant; case_end; case_ast_node(pg, ProcGroup, node); @@ -5296,7 +5299,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } check_close_scope(&ctx); - o->mode = Addressing_Value; o->type = type; case_end; diff --git a/src/checker.cpp b/src/checker.cpp index 77713f36a..f6700eb0c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -25,6 +25,7 @@ bool is_operand_undef(Operand o) { gb_global Scope *universal_scope = nullptr; +gb_global AstPackage *builtin_package = nullptr; void scope_reset(Scope *scope) { if (scope == nullptr) return; @@ -531,13 +532,22 @@ void add_global_type_entity(String name, Type *type) { -void init_universal_scope(void) { +void init_universal(void) { BuildContext *bc = &build_context; // NOTE(bill): No need to free these gbAllocator a = heap_allocator(); universal_scope = create_scope(nullptr, a); universal_scope->is_package = true; + + builtin_package = gb_alloc_item(a, AstPackage); + builtin_package->name = str_lit("builtin"); + builtin_package->kind = Package_Normal; + builtin_package->scope = universal_scope; + universal_scope->package = builtin_package; + + + // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]); @@ -2009,19 +2019,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { return; } - // NOTE(bill): You need to store the entity information here unline a constant declaration - isize entity_cap = vd->names.count; - isize entity_count = 0; - Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap); - DeclInfo *di = nullptr; - if (vd->values.count > 0) { - di = make_decl_info(heap_allocator(), c->scope, c->decl); - di->entities = entities; - di->type_expr = vd->type; - di->init_expr = vd->values[0]; - di->init_expr_list = vd->values; - } - for_array(i, vd->names) { Ast *name = vd->names[i]; Ast *value = nullptr; @@ -2052,24 +2049,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { e->Variable.is_export = true; } - entities[entity_count++] = e; - - DeclInfo *d = di; - if (d == nullptr || i > 0) { - Ast *init_expr = value; - d = make_decl_info(heap_allocator(), e->scope, c->decl); - d->type_expr = vd->type; - d->init_expr = init_expr; - } + Ast *init_expr = value; + DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl); + d->type_expr = vd->type; + d->init_expr = init_expr; d->attributes = vd->attributes; add_entity_and_decl_info(c, name, e, d); } - if (di != nullptr) { - di->entity_count = entity_count; - } - check_arity_match(c, vd, true); } else { for_array(i, vd->names) { @@ -2380,6 +2368,9 @@ void add_import_dependency_node(Checker *c, Ast *decl, Map *M switch (decl->kind) { case_ast_node(id, ImportDecl, decl); String path = id->fullpath; + if (path == "builtin") { + return; + } HashKey key = hash_string(path); AstPackage **found = map_get(&c->info.packages, key); if (found == nullptr) { @@ -2538,32 +2529,35 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { decl->been_handled = true; ast_node(id, ImportDecl, decl); + Token token = id->relpath; Scope *parent_scope = ctx->scope; GB_ASSERT(parent_scope->is_file); auto *pkgs = &ctx->checker->info.packages; - Token token = id->relpath; - HashKey key = hash_string(id->fullpath); - AstPackage **found = map_get(pkgs, key); - if (found == nullptr) { - for_array(pkg_index, pkgs->entries) { - AstPackage *pkg = pkgs->entries[pkg_index].value; - gb_printf_err("%.*s\n", LIT(pkg->fullpath)); + Scope *scope = nullptr; + + if (id->fullpath == "builtin") { + scope = universal_scope; + } else { + HashKey key = hash_string(id->fullpath); + AstPackage **found = map_get(pkgs, key); + if (found == nullptr) { + for_array(pkg_index, pkgs->entries) { + AstPackage *pkg = pkgs->entries[pkg_index].value; + gb_printf_err("%.*s\n", LIT(pkg->fullpath)); + } + gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column); + GB_PANIC("Unable to find scope for package: %.*s", LIT(id->fullpath)); + } else { + AstPackage *pkg = *found; + ptr_set_add(&ctx->checker->checked_packages, pkg); + scope = pkg->scope; } - gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column); - GB_PANIC("Unable to find scope for package: %.*s", LIT(id->fullpath)); } - AstPackage *pkg = *found; - Scope *scope = pkg->scope; GB_ASSERT(scope->is_package); - // TODO(bill): Should this be allowed or not? - // if (scope->is_global) { - // error(token, "Importing a runtime package is disallowed and unnecessary"); - // return; - // } if (ptr_set_exists(&parent_scope->imported, scope)) { // error(token, "Multiple import of the same file within this scope"); @@ -2615,7 +2609,6 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { } } - ptr_set_add(&ctx->checker->checked_packages, pkg); scope->has_been_imported = true; } @@ -3093,11 +3086,7 @@ void calculate_global_init_order(Checker *c) { } ptr_set_add(&emitted, d); - if (d->entities == nullptr) { - d->entities = gb_alloc_array(c->allocator, Entity *, 1); - d->entities[0] = e; - d->entity_count = 1; - } + d->entity = e; array_add(&info->variable_init_order, d); } @@ -3105,13 +3094,8 @@ void calculate_global_init_order(Checker *c) { gb_printf("Variable Initialization Order:\n"); for_array(i, info->variable_init_order) { DeclInfo *d = info->variable_init_order[i]; - for (isize j = 0; j < d->entity_count; j++) { - Entity *e = d->entities[j]; - if (j == 0) gb_printf("\t"); - if (j > 0) gb_printf(", "); - gb_printf("'%.*s' %td", LIT(e->token.string), e->order_in_src); - } - gb_printf("\n"); + Entity *e = d->entity; + gb_printf("\t'%.*s' %td\n", LIT(e->token.string), e->order_in_src); } gb_printf("\n"); } @@ -3200,15 +3184,15 @@ void check_parsed_files(Checker *c) { TIME_SECTION("collect entities"); // Collect Entities for_array(i, c->parser->packages) { - AstPackage *p = c->parser->packages[i]; + AstPackage *pkg = c->parser->packages[i]; CheckerContext ctx = make_checker_context(c); defer (destroy_checker_context(&ctx)); - ctx.pkg = p; + ctx.pkg = pkg; ctx.collect_delayed_decls = false; - for_array(j, p->files) { - AstFile *f = p->files[j]; + for_array(j, pkg->files) { + AstFile *f = pkg->files[j]; create_scope_from_file(&ctx, f); HashKey key = hash_string(f->fullpath); map_set(&c->info.files, key, f); diff --git a/src/checker.hpp b/src/checker.hpp index d20ef2ce5..b9231bc89 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -180,18 +180,17 @@ void check_decl_attributes(CheckerContext *c, Array const &attributes, De // DeclInfo is used to store information of certain declarations to allow for "any order" usage struct DeclInfo { - DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment - Scope * scope; + DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment + Scope * scope; - Entity ** entities; - isize entity_count; + Entity *entity; Ast * type_expr; Ast * init_expr; - Array init_expr_list; + // Array init_expr_list; Array attributes; Ast * proc_lit; // Ast_ProcLit - Type * gen_proc_type; // Precalculated + Type * gen_proc_type; // Precalculated PtrSet deps; PtrSet type_info_deps; @@ -204,16 +203,16 @@ struct ProcInfo { Token token; DeclInfo *decl; Type * type; // Type_Procedure - Ast * body; // Ast_BlockStmt + Ast * body; // Ast_BlockStmt u64 tags; bool generated_from_polymorphic; - Ast * poly_def_node; + Ast * poly_def_node; }; struct Scope { - Ast * node; + Ast * node; Scope * parent; Scope * prev, *next; Scope * first_child; @@ -298,6 +297,7 @@ struct CheckerInfo { Map type_info_map; // Key: Type * + AstPackage * builtin_package; AstPackage * runtime_package; Scope * init_scope; Entity * entry_point; diff --git a/src/ir.cpp b/src/ir.cpp index 94b41332a..a9a26b5ce 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4188,8 +4188,8 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu Entity *e = entity_of_ident(ident); GB_ASSERT(e != nullptr); - if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity_count > 0) { - procedure = e->parent_proc_decl->entities[0]->token.string; + if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { + procedure = e->parent_proc_decl->entity->token.string; } else { procedure = str_lit(""); } @@ -8343,57 +8343,55 @@ void ir_gen_tree(irGen *s) { for_array(i, info->variable_init_order) { DeclInfo *d = info->variable_init_order[i]; - for (isize j = 0; j < d->entity_count; j++) { - Entity *e = d->entities[j]; + Entity *e = d->entity; - if (!e->scope->is_file) { - continue; - } + if (!e->scope->is_file) { + continue; + } - if (!ir_min_dep_entity(m, e)) { - continue; - } - DeclInfo *decl = decl_info_of_entity(e); - if (decl == nullptr) { - continue; - } - GB_ASSERT(e->kind == Entity_Variable); + if (!ir_min_dep_entity(m, e)) { + continue; + } + DeclInfo *decl = decl_info_of_entity(e); + if (decl == nullptr) { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); - bool is_foreign = e->Variable.is_foreign; - bool is_export = e->Variable.is_export; - bool no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + bool no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; - String name = e->token.string; - if (!no_name_mangle) { - name = ir_mangle_name(s, e); - } - ir_add_entity_name(m, e, name); + String name = e->token.string; + if (!no_name_mangle) { + name = ir_mangle_name(s, e); + } + ir_add_entity_name(m, e, name); - irValue *g = ir_value_global(a, e, nullptr); - g->Global.name = name; - g->Global.thread_local_model = e->Variable.thread_local_model; - g->Global.is_foreign = is_foreign; - g->Global.is_export = is_export; + irValue *g = ir_value_global(a, e, nullptr); + g->Global.name = name; + g->Global.thread_local_model = e->Variable.thread_local_model; + g->Global.is_foreign = is_foreign; + g->Global.is_export = is_export; - irGlobalVariable var = {}; - var.var = g; - var.decl = decl; + irGlobalVariable var = {}; + var.var = g; + var.decl = decl; - if (decl->init_expr != nullptr && !is_type_any(e->type)) { - TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - if (tav.mode != Addressing_Invalid) { - if (tav.value.kind != ExactValue_Invalid) { - ExactValue v = tav.value; - g->Global.value = ir_add_module_constant(m, tav.type, v); - } + if (decl->init_expr != nullptr && !is_type_any(e->type)) { + TypeAndValue tav = type_and_value_of_expr(decl->init_expr); + if (tav.mode != Addressing_Invalid) { + if (tav.value.kind != ExactValue_Invalid) { + ExactValue v = tav.value; + g->Global.value = ir_add_module_constant(m, tav.type, v); } } - - array_add(&global_variables, var); - - ir_module_add_value(m, e, g); - map_set(&m->members, hash_string(name), g); } + + array_add(&global_variables, var); + + ir_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); } for_array(i, info->entities) { diff --git a/src/main.cpp b/src/main.cpp index 749c4aae9..9559a3dc6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -791,7 +791,7 @@ int main(int arg_count, char **arg_ptr) { return 1; } - init_universal_scope(); + init_universal(); // TODO(bill): prevent compiling without a linker timings_start_section(&timings, str_lit("parse files")); diff --git a/src/parser.cpp b/src/parser.cpp index 52edf2ee7..fe992eda8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2446,7 +2446,7 @@ Ast *parse_value_decl(AstFile *f, Array names, CommentGroup *docs) { } if (values.data == nullptr) { - values = array_make(heap_allocator()); + values.allocator = heap_allocator(); } if (f->expr_level >= 0) { @@ -2462,6 +2462,12 @@ Ast *parse_value_decl(AstFile *f, Array names, CommentGroup *docs) { } } + if (f->curr_proc == nullptr) { + if (values.count > 0 && names.count != values.count) { + syntax_error(values[0], "Expected %td expressions on the right hand side, got %td", names.count, values.count); + } + } + return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment); } @@ -4094,8 +4100,13 @@ bool determine_path_from_string(Parser *p, Ast *node, String base_dir, String or #endif } - String fullpath = string_trim_whitespace(get_fullpath_relative(a, base_dir, file_str)); - *path = fullpath; + + if (file_str == "builtin") { + *path = str_lit("builtin"); + } else { + String fullpath = string_trim_whitespace(get_fullpath_relative(a, base_dir, file_str)); + *path = fullpath; + } return true; } @@ -4155,6 +4166,9 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array import_path = string_trim_whitespace(import_path); id->fullpath = import_path; + if (import_path == "builtin") { + continue; + } try_add_import_path(p, import_path, original_string, ast_token(node).pos); } else if (node->kind == Ast_ForeignImportDecl) { ast_node(fl, ForeignImportDecl, node); @@ -4284,6 +4298,8 @@ bool parse_file(Parser *p, AstFile *f) { error(package_name, "Invalid package name '_'"); } else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") { error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); + } else if (package_name.string == "builtin") { + error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); } } f->package_name = package_name.string; @@ -4418,8 +4434,8 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } - TokenPos init_pos = {}; + TokenPos init_pos = {}; if (!build_context.generate_docs) { String s = get_fullpath_core(heap_allocator(), str_lit("runtime")); try_add_import_path(p, s, s, init_pos, Package_Runtime); diff --git a/src/parser.hpp b/src/parser.hpp index 9226ea95a..14eee643a 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -573,3 +573,4 @@ gbAllocator ast_allocator(void) { } Ast *alloc_ast_node(AstFile *f, AstKind kind); +