From 3a189b9c1ca273105ba030322e151efd85825482 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 25 Aug 2016 19:52:51 +0100 Subject: [PATCH] Save before Demo 001 --- examples/demo.odin | 21 ++--- src/checker/checker.cpp | 39 ++++++++++ src/checker/expr.cpp | 168 ++++++++++++---------------------------- src/checker/stmt.cpp | 40 +++++++--- src/checker/type.cpp | 8 +- src/parser.cpp | 4 +- src/tokenizer.cpp | 2 +- 7 files changed, 140 insertions(+), 142 deletions(-) diff --git a/examples/demo.odin b/examples/demo.odin index ce6ed4346..01c77a809 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -3,18 +3,18 @@ #load "game.odin" main :: proc() { - // _ = hellope(); - // procedures(); - // variables(); - // constants(); - // types(); - // data_control(); - // using_fields(); + _ = hellope(); + procedures(); + variables(); + constants(); + types(); + data_control(); + using_fields(); - - run_game(); + // run_game(); } + hellope :: proc() -> int { print_string("Hellope, 世界\n"); return 1; @@ -35,7 +35,7 @@ hellope :: proc() -> int { apple, banana, carrot: bool; box, carboard: bool = true, false; -hellope_value: int = hellope(); // The procedure is ran just before `main` +// hellope_value: int = hellope(); // The procedure is ran just before `main` variables :: proc() { i: int; // initialized with zero value @@ -711,3 +711,4 @@ using_fields :: proc() { print_f32(t.pos._xy.x); print_nl(); } } + diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index fb2b9139e..8390442ae 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -190,6 +190,21 @@ struct Checker { gb_global Scope *universal_scope = NULL; +struct CycleChecker { + gbArray(Entity *) path; // Entity_TypeName +}; + +CycleChecker *cycle_checker_add(CycleChecker *cc, Entity *e) { + GB_ASSERT(cc != NULL); + if (cc->path == NULL) { + gb_array_init(cc->path, gb_heap_allocator()); + } + GB_ASSERT(e != NULL && e->kind == Entity_TypeName); + gb_array_append(cc->path, e); + return cc; +} + + Scope *make_scope(Scope *parent, gbAllocator allocator) { Scope *s = gb_alloc_item(allocator, Scope); @@ -561,6 +576,30 @@ void add_curr_ast_file(Checker *c, AstFile *file) { +struct CycleCheck { + gbArray(Entity *) path; // HACK(bill): Memory Leak +}; + +void cycle_check_add(CycleCheck *cc, Entity *entity) { + if (cc == NULL) + return; + if (cc->path == NULL) { + gb_array_init(cc->path, gb_heap_allocator()); + } + GB_ASSERT(entity->kind == Entity_TypeName); + gb_array_append(cc->path, entity); +} + +void check_type_name_cycles(Checker *c, CycleCheck *cc, Entity *e) { + GB_ASSERT(e->kind == Entity_TypeName); + Type *t = e->type; + // if (t->kind == Type_Named) { + // if (t->Named.type_name == e) { + // gb_printf("Illegal cycle %.*s!!!\n", LIT(e->token.string)); + // } + // } +} + void check_parsed_files(Checker *c) { // Collect Entities diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 2b560ae8c..a3aa6eb10 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -4,12 +4,12 @@ void check_expr (Checker *c, Operand *operand, AstNode *e void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); ExpressionKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); -Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL); +Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); void check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); void convert_to_typed (Checker *c, Operand *operand, Type *target_type); gbString expr_to_string (AstNode *expression); -void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); +void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker = NULL); void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); void update_expr_type (Checker *c, AstNode *e, Type *type, b32 final); @@ -45,7 +45,9 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map } -void check_fields(Checker *c, AstNode *node, AstNode *field_list, Entity **fields, isize field_count, String context) { +void check_fields(Checker *c, AstNode *node, + AstNode *field_list, Entity **fields, isize field_count, + CycleChecker *cycle_checker, String context) { Map entity_map = {}; map_init(&entity_map, gb_heap_allocator()); defer (map_destroy(&entity_map)); @@ -53,7 +55,7 @@ void check_fields(Checker *c, AstNode *node, AstNode *field_list, Entity **field isize field_index = 0; for (AstNode *field = field_list; field != NULL; field = field->next) { ast_node(f, Field, field); - Type *type = check_type(c, f->type); + Type *type = check_type(c, f->type, NULL, cycle_checker); if (f->is_using) { if (f->name_count > 1) { @@ -93,7 +95,7 @@ void check_fields(Checker *c, AstNode *node, AstNode *field_list, Entity **field } } -void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { +void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecker *cycle_checker) { GB_ASSERT(node->kind == AstNode_StructType); GB_ASSERT(struct_type->kind == Type_Struct); ast_node(st, StructType, node); @@ -107,13 +109,13 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { } Entity **fields = gb_alloc_array(c->allocator, Entity *, st->field_count); - check_fields(c, node, st->field_list, fields, field_count, make_string("structure")); + check_fields(c, node, st->field_list, fields, field_count, cycle_checker, make_string("structure")); struct_type->Struct.fields = fields; struct_type->Struct.field_count = field_count; struct_type->Struct.is_packed = st->is_packed; } -void check_union_type(Checker *c, Type *union_type, AstNode *node) { +void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { GB_ASSERT(node->kind == AstNode_UnionType); GB_ASSERT(union_type->kind == Type_Union); ast_node(ut, UnionType, node); @@ -127,7 +129,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) { } Entity **fields = gb_alloc_array(c->allocator, Entity *, ut->field_count); - check_fields(c, node, ut->field_list, fields, field_count, make_string("union")); + check_fields(c, node, ut->field_list, fields, field_count, cycle_checker, make_string("union")); union_type->Union.fields = fields; union_type->Union.field_count = field_count; } @@ -273,7 +275,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } -void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { +void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, CycleChecker *cycle_checker = NULL) { GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -286,10 +288,18 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { } add_entity_use(&c->info, n, e); + CycleChecker local_cycle_checker = {}; + if (cycle_checker == NULL) { + cycle_checker = &local_cycle_checker; + } + defer (if (local_cycle_checker.path != NULL) { + gb_array_free(local_cycle_checker.path); + }); + if (e->type == NULL) { auto *found = map_get(&c->info.entities, hash_pointer(e)); if (found != NULL) { - check_entity_decl(c, e, *found, named_type); + check_entity_decl(c, e, *found, named_type, cycle_checker); } else { GB_PANIC("Internal Compiler Error: DeclInfo not found!"); } @@ -300,10 +310,12 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { return; } + Type *type = e->type; + switch (e->kind) { case Entity_Constant: add_declaration_dependency(c, e); - if (e->type == t_invalid) + if (type == t_invalid) return; o->value = e->Constant.value; GB_ASSERT(o->value.kind != ExactValue_Invalid); @@ -313,14 +325,30 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { case Entity_Variable: add_declaration_dependency(c, e); e->Variable.used = true; - if (e->type == t_invalid) + if (type == t_invalid) return; o->mode = Addressing_Variable; break; - case Entity_TypeName: + case Entity_TypeName: { o->mode = Addressing_Type; - break; +#if 0 + // TODO(bill): Fix cyclical dependancy checker + gb_for_array(i, cycle_checker->path) { + Entity *prev = cycle_checker->path[i]; + if (prev == e) { + error(&c->error_collector, e->token, "Illegal declaration cycle for %.*s", LIT(e->token.string)); + for (isize j = i; j < gb_array_count(cycle_checker->path); j++) { + Entity *ref = cycle_checker->path[j]; + error(&c->error_collector, ref->token, "\t%.*s refers to", LIT(ref->token.string)); + } + error(&c->error_collector, e->token, "\t%.*s", LIT(e->token.string)); + type = t_invalid; + break; + } + } +#endif + } break; case Entity_Procedure: add_declaration_dependency(c, e); @@ -337,7 +365,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { break; } - o->type = e->type; + o->type = type; } i64 check_array_count(Checker *c, AstNode *e) { @@ -365,105 +393,7 @@ i64 check_array_count(Checker *c, AstNode *e) { return 0; } -Type *check_type_expr_extra(Checker *c, AstNode *e, Type *named_type) { - gbString err_str = NULL; - defer (gb_string_free(err_str)); - - switch (e->kind) { - case_ast_node(i, Ident, e); - Operand o = {}; - check_identifier(c, &o, e, named_type); - switch (o.mode) { - case Addressing_Type: { - Type *t = o.type; - set_base_type(named_type, t); - return t; - } break; - - case Addressing_Invalid: - break; - - case Addressing_NoValue: - err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err_str); - break; - default: - err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` used as a type when not a type", err_str); - break; - } - case_end; - - case_ast_node(pe, ParenExpr, e); - return check_type(c, pe->expr, named_type); - case_end; - - - case_ast_node(at, ArrayType, e); - if (at->count != NULL) { - Type *t = make_type_array(c->allocator, - check_type(c, at->elem), - check_array_count(c, at->count)); - set_base_type(named_type, t); - return t; - } else { - Type *t = make_type_slice(c->allocator, check_type(c, at->elem)); - set_base_type(named_type, t); - return t; - } - case_end; - - case_ast_node(vt, VectorType, e); - Type *elem = check_type(c, vt->elem); - Type *be = get_base_type(elem); - if (!is_type_vector(be) && - !(is_type_boolean(be) || is_type_numeric(be))) { - err_str = type_to_string(elem); - error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be a boolean, numerical, or vector. Got `%s`", err_str); - break; - } else { - i64 count = check_array_count(c, vt->count); - Type *t = make_type_vector(c->allocator, elem, count); - set_base_type(named_type, t); - return t; - } - case_end; - - case_ast_node(st, StructType, e); - Type *t = make_type_struct(c->allocator); - set_base_type(named_type, t); - check_struct_type(c, t, e); - return t; - case_end; - - case_ast_node(pt, PointerType, e); - Type *t = make_type_pointer(c->allocator, check_type(c, pt->type)); - set_base_type(named_type, t); - return t; - case_end; - - case_ast_node(pt, ProcType, e); - Type *t = alloc_type(c->allocator, Type_Proc); - set_base_type(named_type, t); - check_open_scope(c, e); - check_procedure_type(c, t, e); - check_close_scope(c); - return t; - case_end; - - default: - err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err_str); - break; - } - - Type *t = t_invalid; - set_base_type(named_type, t); - return t; -} - - -Type *check_type(Checker *c, AstNode *e, Type *named_type) { +Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_checker) { ExactValue null_value = {ExactValue_Invalid}; Type *type = NULL; gbString err_str = NULL; @@ -472,7 +402,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) { switch (e->kind) { case_ast_node(i, Ident, e); Operand operand = {}; - check_identifier(c, &operand, e, named_type); + check_identifier(c, &operand, e, named_type, cycle_checker); switch (operand.mode) { case Addressing_Type: { type = operand.type; @@ -505,13 +435,13 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) { case_end; case_ast_node(pe, ParenExpr, e); - return check_type(c, pe->expr, named_type); + return check_type(c, pe->expr, named_type, cycle_checker); case_end; case_ast_node(at, ArrayType, e); if (at->count != NULL) { type = make_type_array(c->allocator, - check_type(c, at->elem), + check_type(c, at->elem, NULL, cycle_checker), check_array_count(c, at->count)); set_base_type(named_type, type); } else { @@ -538,14 +468,14 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) { case_ast_node(st, StructType, e); type = make_type_struct(c->allocator); set_base_type(named_type, type); - check_struct_type(c, type, e); + check_struct_type(c, type, e, cycle_checker); goto end; case_end; case_ast_node(st, UnionType, e); type = make_type_union(c->allocator); set_base_type(named_type, type); - check_union_type(c, type, e); + check_union_type(c, type, e, cycle_checker); goto end; case_end; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index e4dc5f7f3..7b9664595 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -359,16 +359,30 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e check_init_constant(c, e, &operand); } -void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *named_type) { +void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker) { GB_ASSERT(e->type == NULL); Type *named = make_type_named(c->allocator, e->token.string, NULL, e); named->Named.type_name = e; - set_base_type(named_type, named); + if (def != NULL && def->kind == Type_Named) { + def->Named.base = named; + } e->type = named; - check_type(c, type_expr, named); + CycleChecker local_cycle_checker = {}; + if (cycle_checker == NULL) { + cycle_checker = &local_cycle_checker; + } + defer (if (local_cycle_checker.path != NULL) { + gb_array_free(local_cycle_checker.path); + }); - set_base_type(named, get_base_type(get_base_type(named))); + check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e)); + + + named->Named.base = get_base_type(named->Named.base); + if (named->Named.base == t_invalid) { + gb_printf("%s\n", type_to_string(named)); + } } void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) { @@ -486,7 +500,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count -void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { +void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) { if (e->type != NULL) return; switch (e->kind) { @@ -498,9 +512,17 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { c->context.decl = d; check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); break; - case Entity_TypeName: - check_type_decl(c, e, d->type_expr, named_type); - break; + case Entity_TypeName: { + CycleChecker local_cycle_checker = {}; + if (cycle_checker == NULL) { + cycle_checker = &local_cycle_checker; + } + check_type_decl(c, e, d->type_expr, named_type, cycle_checker); + + if (local_cycle_checker.path != NULL) { + gb_array_free(local_cycle_checker.path); + } + } break; case Entity_Procedure: check_proc_decl(c, e, d, true); break; @@ -875,7 +897,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { ast_node(name, Ident, td->name); Entity *e = make_entity_type_name(c->allocator, c->context.scope, name->token, NULL); add_entity(c, c->context.scope, td->name, e); - check_type_decl(c, e, td->type, NULL); + check_type_decl(c, e, td->type, NULL, NULL); case_end; } } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index fe5aaf5ce..26bb2dc40 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -143,7 +143,10 @@ struct Type { }; Type *get_base_type(Type *t) { - while (t->kind == Type_Named) { + for (;;) { + if (t == NULL || t->kind != Type_Named) { + break; + } t = t->Named.base; } return t; @@ -583,6 +586,8 @@ gb_global i64 basic_type_sizes[] = { 8, // Basic_f64 }; + + i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index); @@ -668,6 +673,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); + switch (t->kind) { case Type_Basic: { GB_ASSERT(is_type_typed(t)); diff --git a/src/parser.cpp b/src/parser.cpp index 1691e76de..a79cae37e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1057,7 +1057,7 @@ b32 is_foreign_name_valid(String name) { case '_': break; default: - if (!rune_is_letter(rune)) + if (!gb_char_is_alpha(cast(char)rune)) return false; break; } @@ -1069,7 +1069,7 @@ b32 is_foreign_name_valid(String name) { case '_': break; default: - if (!rune_is_letter(rune) && !rune_is_digit(rune)) { + if (!gb_char_is_alphanumeric(cast(char)rune)) { return false; } break; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a5d8c8c82..38b2164d8 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -157,7 +157,7 @@ gb_no_inline void error(ErrorCollector *ec, Token token, char *fmt, ...) { va_list va; va_start(va, fmt); - gb_printf_err("%.*s(%td:%td) Error: %s\n", + gb_printf_err("%.*s(%td:%td) %s\n", LIT(token.pos.file), token.pos.line, token.pos.column, gb_bprintf_va(fmt, va)); va_end(va);