aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp324
1 files changed, 75 insertions, 249 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index 878435d67..21ca4c398 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -675,55 +675,44 @@ Entity *add_global_entity(Entity *entity, Scope *scope=builtin_pkg->scope) {
return entity;
}
-void add_global_constant(String name, Type *type, ExactValue value) {
+void add_global_constant(char const *name, Type *type, ExactValue value) {
Entity *entity = alloc_entity(Entity_Constant, nullptr, make_token_ident(name), type);
entity->Constant.value = value;
add_global_entity(entity);
}
-void add_global_string_constant(String name, String value) {
+void add_global_string_constant(char const *name, String const &value) {
add_global_constant(name, t_untyped_string, exact_value_string(value));
}
+void add_global_bool_constant(char const *name, bool value) {
+ add_global_constant(name, t_untyped_bool, exact_value_bool(value));
+}
void add_global_type_entity(String name, Type *type) {
add_global_entity(alloc_entity_type_name(nullptr, make_token_ident(name), type));
}
-
-void init_universal(void) {
- BuildContext *bc = &build_context;
-
- // NOTE(bill): No need to free these
- // gbAllocator a = heap_allocator();
+AstPackage *create_builtin_package(char const *name) {
gbAllocator a = permanent_allocator();
+ AstPackage *pkg = gb_alloc_item(a, AstPackage);
+ pkg->name = make_string_c(name);
+ pkg->kind = Package_Normal;
- builtin_pkg = gb_alloc_item(a, AstPackage);
- builtin_pkg->name = str_lit("builtin");
- builtin_pkg->kind = Package_Normal;
-
- builtin_pkg->scope = create_scope(nullptr);
- builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
- builtin_pkg->scope->pkg = builtin_pkg;
-
- intrinsics_pkg = gb_alloc_item(a, AstPackage);
- intrinsics_pkg->name = str_lit("intrinsics");
- intrinsics_pkg->kind = Package_Normal;
-
- intrinsics_pkg->scope = create_scope(nullptr);
- intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
- intrinsics_pkg->scope->pkg = intrinsics_pkg;
-
- config_pkg = gb_alloc_item(a, AstPackage);
- config_pkg->name = str_lit("config");
- config_pkg->kind = Package_Normal;
+ pkg->scope = create_scope(nullptr);
+ pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
+ pkg->scope->pkg = pkg;
+ return pkg;
+}
- config_pkg->scope = create_scope(nullptr);
- config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
- config_pkg->scope->pkg = config_pkg;
+void init_universal(void) {
+ BuildContext *bc = &build_context;
+ builtin_pkg = create_builtin_package("builtin");
+ intrinsics_pkg = create_builtin_package("intrinsics");
+ config_pkg = create_builtin_package("config");
// Types
for (isize i = 0; i < gb_count_of(basic_types); i++) {
@@ -740,23 +729,23 @@ void init_universal(void) {
}
// Constants
- add_global_constant(str_lit("true"), t_untyped_bool, exact_value_bool(true));
- add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false));
-
add_global_entity(alloc_entity_nil(str_lit("nil"), t_untyped_nil));
+ add_global_bool_constant("true", true);
+ add_global_bool_constant("false", false);
+
// TODO(bill): Set through flags in the compiler
- add_global_string_constant(str_lit("ODIN_OS"), bc->ODIN_OS);
- add_global_string_constant(str_lit("ODIN_ARCH"), bc->ODIN_ARCH);
- add_global_string_constant(str_lit("ODIN_ENDIAN"), bc->ODIN_ENDIAN);
- add_global_string_constant(str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR);
- add_global_string_constant(str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
- add_global_string_constant(str_lit("ODIN_ROOT"), bc->ODIN_ROOT);
- add_global_constant(str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG));
- add_global_constant(str_lit("ODIN_DISABLE_ASSERT"), t_untyped_bool, exact_value_bool(bc->ODIN_DISABLE_ASSERT));
- add_global_constant(str_lit("ODIN_DEFAULT_TO_NIL_ALLOCATOR"), t_untyped_bool, exact_value_bool(bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR));
- add_global_constant(str_lit("ODIN_NO_DYNAMIC_LITERALS"), t_untyped_bool, exact_value_bool(bc->no_dynamic_literals));
- add_global_constant(str_lit("ODIN_TEST"), t_untyped_bool, exact_value_bool(bc->command_kind == Command_test));
+ add_global_string_constant("ODIN_OS", bc->ODIN_OS);
+ add_global_string_constant("ODIN_ARCH", bc->ODIN_ARCH);
+ add_global_string_constant("ODIN_ENDIAN", bc->ODIN_ENDIAN);
+ add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
+ add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
+ add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
+ add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG);
+ add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT);
+ add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR);
+ add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals);
+ add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test);
// Builtin Procedures
@@ -801,8 +790,6 @@ void init_universal(void) {
}
GB_ASSERT(type != nullptr);
-
-
Entity *entity = alloc_entity_constant(nullptr, make_token_ident(name), type, value);
entity->state = EntityState_Resolved;
if (scope_insert(config_pkg->scope, entity)) {
@@ -960,7 +947,11 @@ Entity *entity_of_node(Ast *expr) {
expr = unparen_expr(expr);
switch (expr->kind) {
case_ast_node(ident, Ident, expr);
- return ident->entity;
+ Entity *e = ident->entity;
+ if (e && e->flags & EntityFlag_Overridden) {
+ // GB_PANIC("use of an overriden entity: %.*s", LIT(e->token.string));
+ }
+ return e;
case_end;
case_ast_node(se, SelectorExpr, expr);
Ast *s = unselector_expr(se->selector);
@@ -973,7 +964,6 @@ Entity *entity_of_node(Ast *expr) {
return nullptr;
}
-
DeclInfo *decl_info_of_entity(Entity *e) {
if (e != nullptr) {
return e->decl_info;
@@ -1870,7 +1860,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
continue;
}
- if (e->file == nullptr || !e->file->is_test) {
+ // if (e->file == nullptr || !e->file->is_test) {
+ if (e->file == nullptr) {
continue;
}
@@ -2675,206 +2666,6 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) {
if (name == "private") {
// NOTE(bill): Handled elsewhere `check_collect_value_decl`
return true;
- } else if (name == "index_get") {
- if (value != nullptr) {
- Operand o = {};
- check_expr_or_type(c, &o, value);
- Entity *e = entity_of_node(value);
- if (e != nullptr && e->kind == Entity_Procedure) {
- if (ac->deferred_procedure.entity != nullptr) {
- error(elem, "Previous usage of the '%.*s' attribute", LIT(name));
- }
-
- bool valid = true;
-
- {
- Type *pt = base_type(e->type);
- GB_ASSERT(pt->kind == Type_Proc);
-
- if (pt->Proc.result_count == 0) {
- error(value, "'%s' attribute must return something", LIT(name));
- valid = false;
- }
-
- if (pt->Proc.param_count < 2) {
- error(value, "'%s' attribute must allow for 2 parameters", LIT(name));
- valid = false;
- } else {
- isize minimum_param_count = 0;
- for_array(i, pt->Proc.params->Tuple.variables) {
- Entity *param = pt->Proc.params->Tuple.variables[i];
- if (param->kind == Entity_Variable) {
- if (param->Variable.param_value.kind == ParameterValue_Invalid) {
- minimum_param_count += 1;
- } else {
- break;
- }
- } else if (param->kind == Entity_Constant) {
- minimum_param_count += 1;
- } else {
- break;
- }
- }
-
- if (minimum_param_count > 2) {
- error(value, "'%s' attribute must allow for at a minimum 2 parameters", LIT(name));
- valid = false;
- }
- }
- }
-
- if (valid) {
- if (ac->atom_op_table == nullptr) {
- ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
- }
- ac->atom_op_table->op[TypeAtomOp_index_get] = e;
- }
- return true;
- }
- }
- error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
- return false;
- } else if (name == "index_set") {
- if (value != nullptr) {
- Operand o = {};
- check_expr_or_type(c, &o, value);
- Entity *e = entity_of_node(value);
- if (e != nullptr && e->kind == Entity_Procedure) {
- if (ac->deferred_procedure.entity != nullptr) {
- error(elem, "Previous usage of the '%.*s' attribute", LIT(name));
- }
-
- bool valid = true;
-
- {
- Type *pt = base_type(e->type);
- GB_ASSERT(pt->kind == Type_Proc);
-
- if (pt->Proc.param_count < 3) {
- error(value, "'%s' attribute must allow for 3 parameters", LIT(name));
- valid = false;
- } else {
- isize minimum_param_count = 0;
- for_array(i, pt->Proc.params->Tuple.variables) {
- Entity *param = pt->Proc.params->Tuple.variables[i];
- if (param->kind == Entity_Variable) {
- if (param->Variable.param_value.kind == ParameterValue_Invalid) {
- minimum_param_count += 1;
- } else {
- break;
- }
- } else if (param->kind == Entity_Constant) {
- minimum_param_count += 1;
- } else {
- break;
- }
- }
-
- if (minimum_param_count > 3) {
- error(value, "'%s' attribute must allow for at a minimum 3 parameters", LIT(name));
- valid = false;
- }
- }
-
- if (pt->Proc.variadic || pt->Proc.c_vararg) {
- error(value, "'%s' attribute does not allow variadic procedures", LIT(name));
- valid = false;
- }
- }
-
- if (valid) {
- if (ac->atom_op_table == nullptr) {
- ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
- }
- ac->atom_op_table->op[TypeAtomOp_index_set] = e;
- }
- return true;
- }
- }
- error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
- return false;
- } else if (name == "slice") {
- if (value != nullptr) {
- Operand o = {};
- check_expr_or_type(c, &o, value);
- Entity *e = entity_of_node(value);
- if (e != nullptr && e->kind == Entity_Procedure) {
- if (ac->deferred_procedure.entity != nullptr) {
- error(elem, "Previous usage of the '%.*s' attribute", LIT(name));
- }
-
- bool valid = true;
-
- {
- Type *pt = base_type(e->type);
- GB_ASSERT(pt->kind == Type_Proc);
-
- if (pt->Proc.param_count < 1) {
- error(value, "'%s' attribute must allow for 1 parameter", LIT(name));
- valid = false;
- } else {
- isize minimum_param_count = 0;
- for_array(i, pt->Proc.params->Tuple.variables) {
- Entity *param = pt->Proc.params->Tuple.variables[i];
- if (param->kind == Entity_Variable) {
- if (param->Variable.param_value.kind == ParameterValue_Invalid) {
- minimum_param_count += 1;
- } else {
- break;
- }
- } else if (param->kind == Entity_Constant) {
- minimum_param_count += 1;
- } else {
- break;
- }
- }
-
- if (minimum_param_count > 1) {
- error(value, "'%s' attribute must allow for at a minimum 1 parameter", LIT(name));
- valid = false;
- }
- {
- Entity *param = pt->Proc.params->Tuple.variables[0];
- Type *param_type = base_type(param->type);
- if (is_type_pointer(param_type) && !is_type_rawptr(param_type)) {
- // okay
- } else {
- error(value, "'%s' attribute's first parameter must be a pointer", LIT(name));
- valid = false;
- }
-
- }
- }
-
- if (pt->Proc.variadic || pt->Proc.c_vararg) {
- error(value, "'%s' attribute does not allow variadic procedures", LIT(name));
- valid = false;
- }
-
- if (pt->Proc.result_count != 1) {
- error(value, "'%s' attribute must return 1 result", LIT(name));
- valid = false;
- } else {
- Type *rt = pt->Proc.results->Tuple.variables[0]->type;
- rt = base_type(rt);
- if (!is_type_slice(rt)) {
- error(value, "'%s' attribute must return a slice", LIT(name));
- valid = false;
- }
- }
- }
-
- if (valid) {
- if (ac->atom_op_table == nullptr) {
- ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
- }
- ac->atom_op_table->op[TypeAtomOp_slice] = e;
- }
- return true;
- }
- }
- error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
- return false;
}
return false;
}
@@ -4498,6 +4289,38 @@ void check_unchecked_bodies(Checker *c) {
}
}
+void check_test_names(Checker *c) {
+ if (build_context.test_names.entries.count == 0) {
+ return;
+ }
+
+ AstPackage *pkg = c->info.init_package;
+ Scope *s = pkg->scope;
+
+ for_array(i, build_context.test_names.entries) {
+ String name = build_context.test_names.entries[i].value;
+ Entity *e = scope_lookup(s, name);
+ if (e == nullptr) {
+ Token tok = {};
+ if (pkg->files.count != 0) {
+ tok = pkg->files[0]->tokens[0];
+ }
+ error(tok, "Unable to find the test '%.*s' in 'package %.*s' ", LIT(name), LIT(pkg->name));
+ }
+ }
+
+ for (isize i = 0; i < c->info.testing_procedures.count; /**/) {
+ Entity *e = c->info.testing_procedures[i];
+ String name = e->token.string;
+ if (!string_set_exists(&build_context.test_names, name)) {
+ array_ordered_remove(&c->info.testing_procedures, i);
+ } else {
+ i += 1;
+ }
+ }
+
+}
+
void check_parsed_files(Checker *c) {
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
@@ -4572,6 +4395,9 @@ void check_parsed_files(Checker *c) {
TIME_SECTION("generate minimum dependency set");
generate_minimum_dependency_set(c, c->info.entry_point);
+ TIME_SECTION("check test names");
+ check_test_names(c);
+
TIME_SECTION("calculate global init order");
// Calculate initialization order of global variables
calculate_global_init_order(c);