diff options
| author | gingerBill <ginger.bill.22@gmail.com> | 2016-07-21 00:26:14 +0100 |
|---|---|---|
| committer | gingerBill <ginger.bill.22@gmail.com> | 2016-07-21 00:26:14 +0100 |
| commit | cbd82e3c02cbeff8fe3ba5198d6ca730f8c1eace (patch) | |
| tree | 00728d59925609e8fd081f5276e8b26117ec00e3 /src/checker/checker.cpp | |
| parent | aa6a2caecb759522914ba82cc506e60270ad1ab0 (diff) | |
Support import files as modules (i.e. import only once)
Diffstat (limited to 'src/checker/checker.cpp')
| -rw-r--r-- | src/checker/checker.cpp | 334 |
1 files changed, 161 insertions, 173 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 44ec1d6a5..b97764584 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -1,4 +1,4 @@ -#include "value.cpp" +#include "../exact_value.cpp" #include "entity.cpp" #include "type.cpp" @@ -18,7 +18,7 @@ enum AddressingMode { struct Operand { AddressingMode mode; Type *type; - Value value; + ExactValue value; AstNode *expression; BuiltinProcedureId builtin_id; @@ -27,7 +27,7 @@ struct Operand { struct TypeAndValue { AddressingMode mode; Type *type; - Value value; + ExactValue value; }; struct DeclarationInfo { @@ -44,10 +44,15 @@ struct DeclarationInfo { i32 mark; }; -DeclarationInfo *make_declaration_info(gbAllocator a, Scope *scope) { - DeclarationInfo *d = gb_alloc_item(a, DeclarationInfo); + +void init_declaration_info(DeclarationInfo *d, Scope *scope) { d->scope = scope; map_init(&d->deps, gb_heap_allocator()); +} + +DeclarationInfo *make_declaration_info(gbAllocator a, Scope *scope) { + DeclarationInfo *d = gb_alloc_item(a, DeclarationInfo); + init_declaration_info(d, scope); return d; } @@ -71,10 +76,10 @@ struct ExpressionInfo { b32 is_lhs; // Debug info AddressingMode mode; Type *type; // Type_Basic - Value value; + ExactValue value; }; -ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, Value value) { +ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, ExactValue value) { ExpressionInfo ei = {}; ei.is_lhs = is_lhs; ei.mode = mode; @@ -84,6 +89,7 @@ ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, } struct ProcedureInfo { + AstFile *file; Token token; DeclarationInfo *decl; Type * type; // Type_Procedure @@ -155,8 +161,9 @@ struct Checker { Map<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo Map<DeclarationInfo *> entities; // Key: Entity * + AstFile * curr_ast_file; BaseTypeSizes sizes; - Scope * file_scope; + Scope * global_scope; gbArray(ProcedureInfo) procedures; // NOTE(bill): Procedures to check gbArena arena; @@ -168,21 +175,20 @@ struct Checker { gbArray(Type *) procedure_stack; b32 in_defer; // TODO(bill): Actually handle correctly -#define MAX_CHECKER_ERROR_COUNT 10 isize error_prev_line; isize error_prev_column; isize error_count; }; -gb_global Scope *global_scope = NULL; +gb_global Scope *universal_scope = NULL; Scope *make_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); s->parent = parent; map_init(&s->elements, gb_heap_allocator()); - if (parent != NULL && parent != global_scope) { + if (parent != NULL && parent != universal_scope) { DLIST_APPEND(parent->first_child, parent->last_child, s); } return s; @@ -258,12 +264,12 @@ void add_global_entity(Entity *entity) { if (gb_memchr(name.text, ' ', name.len)) { return; // NOTE(bill): `untyped thing` } - if (scope_insert_entity(global_scope, entity)) { + if (scope_insert_entity(universal_scope, entity)) { GB_PANIC("Compiler error: double declaration"); } } -void add_global_constant(gbAllocator a, String name, Type *type, Value value) { +void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) { Token token = {Token_Identifier}; token.string = name; Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type); @@ -271,10 +277,10 @@ void add_global_constant(gbAllocator a, String name, Type *type, Value value) { add_global_entity(entity); } -void init_global_scope(void) { +void init_universal_scope(void) { // NOTE(bill): No need to free these gbAllocator a = gb_heap_allocator(); - global_scope = make_scope(NULL, a); + universal_scope = make_scope(NULL, a); // Types for (isize i = 0; i < gb_count_of(basic_types); i++) { @@ -289,9 +295,9 @@ void init_global_scope(void) { } // Constants - add_global_constant(a, make_string("true"), &basic_types[Basic_UntypedBool], make_value_bool(true)); - add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool], make_value_bool(false)); - add_global_constant(a, make_string("null"), &basic_types[Basic_UntypedPointer], make_value_pointer(NULL)); + add_global_constant(a, make_string("true"), &basic_types[Basic_UntypedBool], make_exact_value_bool(true)); + add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool], make_exact_value_bool(false)); + add_global_constant(a, make_string("null"), &basic_types[Basic_UntypedPointer], make_exact_value_pointer(NULL)); // Builtin Procedures for (isize i = 0; i < gb_count_of(builtin_procedures); i++) { @@ -329,12 +335,17 @@ void init_checker(Checker *c, Parser *parser) { // NOTE(bill): Is this big enough or too small? isize item_size = gb_max(gb_max(gb_size_of(Entity), gb_size_of(Type)), gb_size_of(Scope)); - isize arena_size = 2 * item_size * gb_array_count(c->parser->tokens); + isize total_token_count = 0; + for (isize i = 0; i < gb_array_count(c->parser->files); i++) { + AstFile *f = &c->parser->files[i]; + total_token_count += gb_array_count(f->tokens); + } + isize arena_size = 2 * item_size * total_token_count; gb_arena_init_from_allocator(&c->arena, a, arena_size); c->allocator = gb_arena_allocator(&c->arena); - c->file_scope = make_scope(global_scope, c->allocator); - c->curr_scope = c->file_scope; + c->global_scope = make_scope(universal_scope, c->allocator); + c->curr_scope = c->global_scope; } void destroy_checker(Checker *c) { @@ -344,7 +355,7 @@ void destroy_checker(Checker *c) { map_destroy(&c->scopes); map_destroy(&c->untyped); map_destroy(&c->entities); - destroy_scope(c->file_scope); + destroy_scope(c->global_scope); gb_array_free(c->procedure_stack); gb_array_free(c->procedures); @@ -353,8 +364,8 @@ void destroy_checker(Checker *c) { -#define print_checker_error(p, token, fmt, ...) print_checker_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__) -void print_checker_error_(Checker *c, char *function, Token token, char *fmt, ...) { +#define checker_err(p, token, fmt, ...) checker_err_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__) +void checker_err_(Checker *c, char *function, Token token, char *fmt, ...) { // NOTE(bill): Duplicate error, skip it @@ -368,20 +379,20 @@ void print_checker_error_(Checker *c, char *function, Token token, char *fmt, .. va_list va; va_start(va, fmt); - gb_printf_err("%s(%td:%td) %s\n", - c->parser->tokenizer.fullpath, token.line, token.column, + gb_printf_err("%.*s(%td:%td) %s\n", + LIT(c->curr_ast_file->tokenizer.fullpath), token.line, token.column, gb_bprintf_va(fmt, va)); va_end(va); } c->error_count++; // NOTE(bill): If there are too many errors, just quit - if (c->error_count > MAX_CHECKER_ERROR_COUNT) { - gb_exit(1); - return; - } } +TypeAndValue *type_and_value_of_expression(Checker *c, AstNode *expression) { + TypeAndValue *found = map_get(&c->types, hash_pointer(expression)); + return found; +} Entity *entity_of_identifier(Checker *c, AstNode *identifier) { @@ -397,7 +408,7 @@ Entity *entity_of_identifier(Checker *c, AstNode *identifier) { } Type *type_of_expression(Checker *c, AstNode *expression) { - TypeAndValue *found = map_get(&c->types, hash_pointer(expression)); + TypeAndValue *found = type_and_value_of_expression(c, expression); if (found) return found->type; if (expression->kind == AstNode_Identifier) { @@ -410,19 +421,19 @@ Type *type_of_expression(Checker *c, AstNode *expression) { } -void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, Value value) { +void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, ExactValue value) { map_set(&c->untyped, hash_pointer(expression), make_expression_info(lhs, mode, basic_type, value)); } -void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, Value value) { +void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) { GB_ASSERT(expression != NULL); GB_ASSERT(type != NULL); if (mode == Addressing_Invalid) return; if (mode == Addressing_Constant) { - GB_ASSERT(value.kind != Value_Invalid); + GB_ASSERT(value.kind != ExactValue_Invalid); GB_ASSERT(type == &basic_types[Basic_Invalid] || is_type_constant_type(type)); } @@ -443,7 +454,7 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { if (!are_strings_equal(entity->token.string, make_string("_"))) { Entity *insert_entity = scope_insert_entity(scope, entity); if (insert_entity) { - print_checker_error(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string)); + checker_err(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string)); return; } } @@ -463,14 +474,15 @@ void add_file_entity(Checker *c, AstNode *identifier, Entity *e, DeclarationInfo GB_ASSERT(are_strings_equal(identifier->identifier.token.string, e->token.string)); - add_entity(c, c->file_scope, identifier, e); + add_entity(c, c->global_scope, identifier, e); map_set(&c->entities, hash_pointer(e), d); e->order = gb_array_count(c->entities.entries); } -void check_procedure_later(Checker *c, Token token, DeclarationInfo *decl, Type *type, AstNode *body) { +void check_procedure_later(Checker *c, AstFile *file, Token token, DeclarationInfo *decl, Type *type, AstNode *body) { ProcedureInfo info = {}; + info.file = file; info.token = token; info.decl = decl; info.type = type; @@ -506,6 +518,12 @@ void pop_procedure(Checker *c) { } +void add_curr_ast_file(Checker *c, AstFile *file) { + c->error_prev_line = 0; + c->error_prev_column = 0; + c->curr_ast_file = file; +} + @@ -523,162 +541,115 @@ GB_COMPARE_PROC(entity_order_cmp) { return p->order < q->order ? -1 : p->order > q->order; } -void check_file(Checker *c, AstNode *file_node) { - -// Collect Entities - for (AstNode *decl = file_node; decl != NULL; decl = decl->next) { - if (!is_ast_node_declaration(decl)) - continue; - - switch (decl->kind) { - case AstNode_BadDeclaration: - break; - - case AstNode_VariableDeclaration: { - auto *vd = &decl->variable_declaration; - - switch (vd->kind) { - case Declaration_Immutable: { - for (AstNode *name = vd->name_list, *value = vd->value_list; - name != NULL && value != NULL; - name = name->next, value = value->next) { - GB_ASSERT(name->kind == AstNode_Identifier); - Value v = {Value_Invalid}; - Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v); - DeclarationInfo *di = make_declaration_info(c->allocator, c->file_scope); - di->type_expr = vd->type_expression; - di->init_expr = value; - add_file_entity(c, name, e, di); - } - - isize lhs_count = vd->name_list_count; - isize rhs_count = vd->value_list_count; - - if (rhs_count == 0 && vd->type_expression == NULL) { - print_checker_error(c, ast_node_token(decl), "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - print_checker_error(c, ast_node_token(decl), "Extra initial expression"); - } - } break; - - case Declaration_Mutable: { - isize entity_count = vd->name_list_count; - isize entity_index = 0; - Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - DeclarationInfo *di = NULL; - if (vd->value_list_count == 1) { - di = make_declaration_info(gb_heap_allocator(), c->file_scope); - di->entities = entities; - di->entity_count = entity_count; - di->type_expr = vd->type_expression; - di->init_expr = vd->value_list; - } - - AstNode *value = vd->value_list; - for (AstNode *name = vd->name_list; name != NULL; name = name->next) { - Entity *e = make_entity_variable(c->allocator, c->file_scope, name->identifier.token, NULL); - entities[entity_index++] = e; - - DeclarationInfo *d = di; - if (d == NULL) { - AstNode *init_expr = value; - d = make_declaration_info(gb_heap_allocator(), c->file_scope); - d->type_expr = vd->type_expression; - d->init_expr = init_expr; +void check_parsed_files(Checker *c) { + // Collect Entities + for (isize i = 0; i < gb_array_count(c->parser->files); i++) { + AstFile *f = &c->parser->files[i]; + add_curr_ast_file(c, f); + for (AstNode *decl = f->declarations; decl != NULL; decl = decl->next) { + if (!is_ast_node_declaration(decl)) + continue; + + switch (decl->kind) { + case AstNode_BadDeclaration: + break; + + case AstNode_VariableDeclaration: { + auto *vd = &decl->variable_declaration; + + switch (vd->kind) { + case Declaration_Immutable: { + for (AstNode *name = vd->name_list, *value = vd->value_list; + name != NULL && value != NULL; + name = name->next, value = value->next) { + GB_ASSERT(name->kind == AstNode_Identifier); + ExactValue v = {ExactValue_Invalid}; + Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v); + DeclarationInfo *di = make_declaration_info(c->allocator, c->global_scope); + di->type_expr = vd->type_expression; + di->init_expr = value; + add_file_entity(c, name, e, di); } - add_file_entity(c, name, e, d); + isize lhs_count = vd->name_list_count; + isize rhs_count = vd->value_list_count; - if (value != NULL) - value = value->next; - } + if (rhs_count == 0 && vd->type_expression == NULL) { + checker_err(c, ast_node_token(decl), "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + checker_err(c, ast_node_token(decl), "Extra initial expression"); + } + } break; + + case Declaration_Mutable: { + isize entity_count = vd->name_list_count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + DeclarationInfo *di = NULL; + if (vd->value_list_count == 1) { + di = make_declaration_info(gb_heap_allocator(), c->global_scope); + di->entities = entities; + di->entity_count = entity_count; + di->type_expr = vd->type_expression; + di->init_expr = vd->value_list; + } -#if 0 - for (AstNode *name = vd->name_list; name != NULL; name = name->next) { - Entity *entity = NULL; - Token token = name->identifier.token; - if (name->kind == AstNode_Identifier) { - String str = token.string; - Entity *found = NULL; - // NOTE(bill): Ignore assignments to `_` - b32 can_be_ignored = are_strings_equal(str, make_string("_")); - if (!can_be_ignored) { - found = current_scope_lookup_entity(c->file_scope, str); - } - if (found == NULL) { - entity = make_entity_variable(c->allocator, c->file_scope, token, NULL); - if (!can_be_ignored) { - new_entities[new_entity_count++] = entity; - } - add_entity_definition(c, name, entity); - } else { - entity = found; + AstNode *value = vd->value_list; + for (AstNode *name = vd->name_list; name != NULL; name = name->next) { + Entity *e = make_entity_variable(c->allocator, c->global_scope, name->identifier.token, NULL); + entities[entity_index++] = e; + + DeclarationInfo *d = di; + if (d == NULL) { + AstNode *init_expr = value; + d = make_declaration_info(gb_heap_allocator(), c->global_scope); + d->type_expr = vd->type_expression; + d->init_expr = init_expr; } - } else { - print_checker_error(c, token, "A variable declaration must be an identifier"); - } - if (entity == NULL) - entity = make_entity_dummy_variable(c, token); - entities[entity_index++] = entity; - } - Type *init_type = NULL; - if (vd->type_expression) { - init_type = check_type(c, vd->type_expression, NULL); - if (init_type == NULL) - init_type = &basic_types[Basic_Invalid]; - } + add_file_entity(c, name, e, d); - for (isize i = 0; i < entity_count; i++) { - Entity *e = entities[i]; - GB_ASSERT(e != NULL); - if (e->variable.visited) { - e->type = &basic_types[Basic_Invalid]; - continue; + if (value != NULL) + value = value->next; } - e->variable.visited = true; - - if (e->type == NULL) - e->type = init_type; + } break; } - check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration")); -#endif } break; - } + case AstNode_TypeDeclaration: { + AstNode *identifier = decl->type_declaration.name; + Entity *e = make_entity_type_name(c->allocator, c->global_scope, identifier->identifier.token, NULL); + DeclarationInfo *d = make_declaration_info(c->allocator, e->parent); + d->type_expr = decl->type_declaration.type_expression; + add_file_entity(c, identifier, e, d); + } break; - } break; - - case AstNode_TypeDeclaration: { - AstNode *identifier = decl->type_declaration.name; - Entity *e = make_entity_type_name(c->allocator, c->file_scope, identifier->identifier.token, NULL); - DeclarationInfo *d = make_declaration_info(c->allocator, e->parent); - d->type_expr = decl->type_declaration.type_expression; - add_file_entity(c, identifier, e, d); - } break; + case AstNode_ProcedureDeclaration: { + AstNode *identifier = decl->procedure_declaration.name; + Token token = identifier->identifier.token; + Entity *e = make_entity_procedure(c->allocator, c->global_scope, token, NULL); + add_entity(c, c->global_scope, identifier, e); + DeclarationInfo *d = make_declaration_info(c->allocator, e->parent); + d->proc_decl = decl; + map_set(&c->entities, hash_pointer(e), d); + e->order = gb_array_count(c->entities.entries); - case AstNode_ProcedureDeclaration: { - AstNode *identifier = decl->procedure_declaration.name; - Token token = identifier->identifier.token; - Entity *e = make_entity_procedure(c->allocator, c->file_scope, token, NULL); - add_entity(c, c->file_scope, identifier, e); - DeclarationInfo *d = make_declaration_info(c->allocator, e->parent); - d->proc_decl = decl; - map_set(&c->entities, hash_pointer(e), d); - e->order = gb_array_count(c->entities.entries); + } break; - } break; + case AstNode_ImportDeclaration: + // NOTE(bill): ignore + break; - default: - print_checker_error(c, ast_node_token(decl), "Only declarations are allowed at file scope"); - break; + default: + checker_err(c, ast_node_token(decl), "Only declarations are allowed at file scope"); + break; + } } } -// Order entities - { + { // Order entities gbArray(Entity *) entities; isize count = gb_array_count(c->entities.entries); gb_array_init_reserve(entities, gb_heap_allocator(), count); @@ -698,10 +669,27 @@ void check_file(Checker *c, AstNode *file_node) { } + // Check procedure bodies for (isize i = 0; i < gb_array_count(c->procedures); i++) { ProcedureInfo *pi = &c->procedures[i]; + add_curr_ast_file(c, pi->file); check_procedure_body(c, pi->token, pi->decl, pi->type, pi->body); } + + + { // Add untyped expression values + isize count = gb_array_count(c->untyped.entries); + for (isize i = 0; i < count; i++) { + auto *entry = c->untyped.entries + i; + u64 key = entry->key; + AstNode *expr = cast(AstNode *)cast(uintptr)key; + ExpressionInfo *info = &entry->value; + if (is_type_typed(info->type)) { + GB_PANIC("%s (type %s) is typed!", expression_to_string(expr), info->type); + } + add_type_and_value(c, expr, info->mode, info->type, info->value); + } + } } |