From: Brendan Hansen Date: Tue, 29 Dec 2020 18:23:21 +0000 (-0600) Subject: '::' declarations in procedure scope are treated the same as file scoped X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=46f9a1543acae27ed71221154d6e36425cd2839c;p=onyx.git '::' declarations in procedure scope are treated the same as file scoped --- diff --git a/core/alloc/heap.onyx b/core/alloc/heap.onyx index 94ff85b6..538e4507 100644 --- a/core/alloc/heap.onyx +++ b/core/alloc/heap.onyx @@ -60,7 +60,7 @@ heap_alloc :: proc (size_: u32, align: u32) -> rawptr { return cast(rawptr) (cast(u32) ret + sizeof heap_block); } - new_pages :: ((size - heap_state.remaining_space) >> 16) + 1; + new_pages := ((size - heap_state.remaining_space) >> 16) + 1; if memory_grow(new_pages) == -1 { // out of memory return null; @@ -102,7 +102,7 @@ heap_resize :: proc (ptr: rawptr, new_size: u32, align: u32) -> rawptr { // If we are at the end of the allocation space, just extend it if hb_ptr.size + cast(u32) ptr >= cast(u32) heap_state.next_alloc { if new_size - old_size >= heap_state.remaining_space { - new_pages :: ((new_size - old_size - heap_state.remaining_space) >> 16) + 1; + new_pages := ((new_size - old_size - heap_state.remaining_space) >> 16) + 1; if memory_grow(new_pages) == -1 { // out of memory return null; diff --git a/core/conv.onyx b/core/conv.onyx index 9f5a3c8e..a89c0d33 100644 --- a/core/conv.onyx +++ b/core/conv.onyx @@ -12,12 +12,13 @@ i64_to_str :: proc (n_: i64, base: u64, buf: [] u8) -> str { c := ^buf[buf.count - 1]; len := 0; - s :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + // BUGFIX: Make this work with '::'; + BASE64_MAP := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; while n > 0 { - m :: n % base; + m := n % base; - *c = s[cast(u32) m]; + *c = BASE64_MAP[cast(u32) m]; len += 1; c -= 1; diff --git a/core/string.onyx b/core/string.onyx index b3c6804e..8bc25835 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -1,7 +1,7 @@ package core.string make :: proc (s: cstr) -> str { - len :: length(s); + len := length(s); return str.{ count = len, data = s }; } @@ -39,8 +39,8 @@ copy :: proc (orig: str, dest: str) { } concat :: proc (s1: str, s2: str) -> str { - len1 :: length(s1); - len2 :: length(s2); + len1 := length(s1); + len2 := length(s2); data := cast(^u8) calloc(len1 + len2); for i: 0 .. len1 do data[i] = s1[i]; diff --git a/core/string/builder.onyx b/core/string/builder.onyx index 69ee4d5a..2280686f 100644 --- a/core/string/builder.onyx +++ b/core/string/builder.onyx @@ -27,7 +27,7 @@ clear :: proc (use sb: ^Builder) -> ^Builder { } add_str :: proc (use sb: ^Builder, s: str) -> ^Builder { - len_total :: data.count + s.count; + len_total := data.count + s.count; if data.capacity < len_total do #context_scope { context.allocator = alloc; diff --git a/docs/bugs b/docs/bugs index 8ded95c4..10e43eaa 100644 --- a/docs/bugs +++ b/docs/bugs @@ -1,29 +1,29 @@ List of known bugs: [ ] Using an auto-cast on an argument when calling an overloaded proc leads - to an unexpected error. Take the following example: - ``` - overloaded :: proc { - proc (x: f32, y: str) ---, - proc (x: i32, y: i32) ---, - } - - foo :: proc () { - x: i32 = 1234; - overloaded(~~x, 4); - } - ``` - Compiles with the following error: - ``` - (/home/brendan/dev/c/onyx/a.onyx:8,15) unable to match overloaded function with provided argument types: (f32, unsized int) - 8 | overloaded(~~x, 4); - ``` - - This is because in trying the first overload, the auto-cast is consumed - and converted to a cast(f32). Then, when it doesn't match the first one - and it tries the second, the parameter types are f32 and unsized int, - which is doesn't match the second one, when the original parameters would - have matched correctly. + to an unexpected error. Take the following example: + ``` + overloaded :: proc { + proc (x: f32, y: str) ---, + proc (x: i32, y: i32) ---, + } + + foo :: proc () { + x: i32 = 1234; + overloaded(~~x, 4); + } + ``` + Compiles with the following error: + ``` + (/home/brendan/dev/c/onyx/a.onyx:8,15) unable to match overloaded function with provided argument types: (f32, unsized int) + 8 | overloaded(~~x, 4); + ``` + + This is because in trying the first overload, the auto-cast is consumed + and converted to a cast(f32). Then, when it doesn't match the first one + and it tries the second, the parameter types are f32 and unsized int, + which is doesn't match the second one, when the original parameters would + have matched correctly. [ ] `defer` statements are not executed at the end of a loop if the loop is exited using a `break` statement, or a `continue` statement. The semantics @@ -39,49 +39,72 @@ List of known bugs: an infinite loop. [ ] The following code causes an infinite loop somewhere. - ``` - get_neighbor_count :: proc (grid: ^map.Map(Vec2, Cell), pos: Vec2) -> u32 { - count := 0; + ``` + get_neighbor_count :: proc (grid: ^map.Map(Vec2, Cell), pos: Vec2) -> u32 { + count := 0; - for ^dir: Hex_Directions { - pos := Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y }; - cell := map.get(grid, pos, Cell.{}); - if cell.alive do count += 1; - } + for ^dir: Hex_Directions { + pos := Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y }; + cell := map.get(grid, pos, Cell.{}); + if cell.alive do count += 1; + } - return count; - } - ``` + return count; + } + ``` [ ] Polymorphic structs do not recognize default values for members. +[ ] `use` on struct members does not work correctly if the type is a union. + ``` + BadUnion :: struct { + use container : struct #union { + int: i32; + float: f32; + }; + } + + test :: proc () do print(sizeof BadUnion == 4); + ``` + +[ ] `use` on struct members breaks struct literals. + ``` + Vec2 :: struct { x: i32; y: i32; } + Entity :: struct { use pos: Vec2; } + + e := Entity.{ pos = Vec2.{ 1, 2 } }; + + // This does work already. + e2 := Entity.{ x = 1, y = 2 }; + ``` + [X] `TileData :: [TILE_DATA_WIDTH * TILE_DATA_HEIGHT] bool;` results in a segfault because it is an invalid top level node, but that is not checked before it is tried to be used. [X] `TileData :: #type [TILE_DATA_WIDTH * TILE_DATA_HEIGHT] bool;` produces the - following error: - ``` - (/home/brendan/dev/onyx/aoc/day20.onyx:25,19) Array type expects type 'i32' for size, got 'unsized int'. - 25 | TileData :: #type [TILE_DATA_WIDTH * TILE_DATA_HEIGHT] bool; - ``` + following error: + ``` + (/home/brendan/dev/onyx/aoc/day20.onyx:25,19) Array type expects type 'i32' for size, got 'unsized int'. + 25 | TileData :: #type [TILE_DATA_WIDTH * TILE_DATA_HEIGHT] bool; + ``` - This because the expression for the array size is not reducing and getting - converted to the fixed size integer. I suspect this is because for sizeof - and alignof expression, `fill_in_type` is not used, and that function has - the logic to handle the array subscript reduction and type resolution. + This because the expression for the array size is not reducing and getting + converted to the fixed size integer. I suspect this is because for sizeof + and alignof expression, `fill_in_type` is not used, and that function has + the logic to handle the array subscript reduction and type resolution. [X] The following struct is causing a seg fault in the compiler. I believe it - is because of the duplicate struct member names and failing to get the position - in the file to report the error. - ``` - Tile :: struct { - id : u32; - orientation : TileOrientation; - data : [] bool; - edges : [] u32; - - pos_x : u32 = 0; - pos_x : u32 = 0; - } - ``` + is because of the duplicate struct member names and failing to get the position + in the file to report the error. + ``` + Tile :: struct { + id : u32; + orientation : TileOrientation; + data : [] bool; + edges : [] u32; + + pos_x : u32 = 0; + pos_x : u32 = 0; + } + ``` diff --git a/docs/todo b/docs/todo index 6da2e100..d6d7ed07 100644 --- a/docs/todo +++ b/docs/todo @@ -112,6 +112,24 @@ Language Cohesion: [ ] Add macros. + [ ] enum #flags should be able to be used as so: + ``` + SomeEnum :: enum #flags { + Property1; + Property2; + Property3; + } + + val : SomeEnum = ~~0; + val.Property1 = true; + val.Property3 = true; + + // This should also be allowed. + val |= SomeEnum.Property2; + + if val.Property2 { ... } + ``` + [X] #solidify polymoprhic procedures. API Expansion: @@ -140,3 +158,19 @@ Usability: [ ] Make README on GitHub better, and actually describe what to do [ ] Make compiler work on Windows [ ] Make compiler work on MacOS + [ ] Add examples for the following language features: + - Slices + - Dynamic Arrays + - Structs and unions + - Enums + - switch statements + - for loops + - Maps + - varargs + - `use` keyword + - pipe operator + - Overloaded procedures + - Polymorphic procedures + - WASM directives (#export, #foreign) + - #solidify directive + - SIMD diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 82a7e3f2..5789ebbc 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -532,7 +532,8 @@ struct AstBlock { AstNode *body; Scope *scope; - bh_arr(AstTyped *) allocate_exprs; + bh_arr(AstTyped *) allocate_exprs; + bh_arr(AstBinding *) bindings; }; struct AstDefer { AstNode_base; AstNode *stmt; }; struct AstFor { diff --git a/include/onyxparser.h b/include/onyxparser.h index 789119c2..1b0bfc2e 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -42,6 +42,8 @@ typedef struct OnyxParser { PolymorphicContext polymorph_context; + bh_arr(AstBlock *) block_stack; + b32 hit_unexpected_token : 1; } OnyxParser; diff --git a/onyx b/onyx index 1bdc8ffc..78d3f0e2 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/odin_example.onyx b/progs/odin_example.onyx index f13b3e9a..9de1b6d2 100644 --- a/progs/odin_example.onyx +++ b/progs/odin_example.onyx @@ -75,7 +75,26 @@ compress :: proc (arr: [5] $T, f : proc (T, T) -> T) -> T { return val; } +BadUnion :: struct { + use container : struct #union { + int: i32; + float: f32; + }; +} + +Vec2 :: struct { x: i32; y: i32; } +Entity :: struct { use pos: Vec2; } + main :: proc (args: [] cstr) { + a : BadUnion; + a.int = 1234; + a.float = 0.5; + printf("%i == 4\n", sizeof BadUnion); + printf("%p\n", a.int); + printf("%f\n", a.float); + + e := Entity.{ pos = Vec2.{ 1, 2 } }; + { foo : [5] [2] u32; foo = f(); diff --git a/progs/poly_solidify.onyx b/progs/poly_solidify.onyx index 8e16c2c5..4bf90352 100644 --- a/progs/poly_solidify.onyx +++ b/progs/poly_solidify.onyx @@ -27,7 +27,7 @@ main :: proc (args: [] cstr) { defer array.free(^arr); - for i: 0 .. 10 do array.push(^arr, i); + for i: 0 .. 10 do array.push(^arr, ~~i); print_array(arr); array_map(arr, double); diff --git a/src/onyxclone.c b/src/onyxclone.c index cd7f18c5..0cfd8a5d 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -88,6 +88,7 @@ static inline i32 ast_kind_to_size(AstNode* node) { case Ast_Kind_Defer: return sizeof(AstDefer); case Ast_Kind_Switch: return sizeof(AstSwitch); case Ast_Kind_Switch_Case: return sizeof(AstSwitchCase); + case Ast_Kind_Directive_Solidify: return sizeof(AstDirectiveSolidify); case Ast_Kind_Count: return 0; } } diff --git a/src/onyxparser.c b/src/onyxparser.c index dbcc22fb..d6d64331 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -45,6 +45,7 @@ static AstFunction* parse_function_definition(OnyxParser* parser); static AstTyped* parse_global_declaration(OnyxParser* parser); static AstEnumType* parse_enum_declaration(OnyxParser* parser); static AstTyped* parse_top_level_expression(OnyxParser* parser); +static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol); static AstNode* parse_top_level_statement(OnyxParser* parser); static AstPackage* parse_package_name(OnyxParser* parser); @@ -1004,12 +1005,18 @@ static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret) if ((parser->curr + 1)->type != ':') return 0; OnyxToken* symbol = expect_token(parser, Token_Type_Symbol); - consume_token(parser); - AstType* type_node = NULL; + expect_token(parser, ':'); + + if (parser->curr->type == ':') { + AstBinding* binding = parse_top_level_binding(parser, symbol); + + bh_arr_push(parser->block_stack[0]->bindings, binding); + return 1; + } // NOTE: var: type - if (parser->curr->type != ':' - && parser->curr->type != '=') { + AstType* type_node = NULL; + if (parser->curr->type != '=') { type_node = parse_type(parser); } @@ -1018,11 +1025,7 @@ static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret) local->type_node = type_node; *ret = (AstNode *) local; - if (parser->curr->type == '=' || parser->curr->type == ':') { - if (parser->curr->type == ':') { - local->flags |= Ast_Flag_Const; - } - + if (parser->curr->type == '=') { AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op); assignment->operation = Binary_Op_Assign; local->next = (AstNode *) assignment; @@ -1310,21 +1313,26 @@ static AstBlock* parse_block(OnyxParser* parser) { AstBlock* block = make_node(AstBlock, Ast_Kind_Block); bh_arr_new(global_heap_allocator, block->allocate_exprs, 4); + bh_arr_push(parser->block_stack, block); + // NOTE: --- is for an empty block if (parser->curr->type == Token_Type_Empty_Block) { block->token = expect_token(parser, Token_Type_Empty_Block); + bh_arr_pop(parser->block_stack); return block; } if (parser->curr->type == Token_Type_Keyword_Do) { block->token = expect_token(parser, Token_Type_Keyword_Do); block->body = parse_statement(parser); + bh_arr_pop(parser->block_stack); return block; } if (parser->curr->type != '{') { expect_token(parser, '{'); find_token(parser, '}'); + bh_arr_pop(parser->block_stack); return block; } block->token = expect_token(parser, '{'); @@ -1346,6 +1354,7 @@ static AstBlock* parse_block(OnyxParser* parser) { expect_token(parser, '}'); + bh_arr_pop(parser->block_stack); return block; } @@ -1954,6 +1963,62 @@ static AstTyped* parse_top_level_expression(OnyxParser* parser) { } } +static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol) { + expect_token(parser, ':'); + + AstTyped* node = parse_top_level_expression(parser); + if (parser->hit_unexpected_token || node == NULL) + return NULL; + + if (node->kind == Ast_Kind_Function) { + AstFunction* func = (AstFunction *) node; + + if (func->exported_name == NULL) + func->exported_name = symbol; + + func->name = symbol; + + } else if (node->kind == Ast_Kind_Polymorphic_Proc) { + AstPolyProc* proc = (AstPolyProc *) node; + + if (proc->base_func->exported_name == NULL) + proc->base_func->exported_name = symbol; + + proc->base_func->name = symbol; + + } else if (node->kind == Ast_Kind_Global) { + AstGlobal* global = (AstGlobal *) node; + + if (global->exported_name == NULL) + global->exported_name = symbol; + + global->name = symbol; + + } else if (node->kind != Ast_Kind_Overloaded_Function + && node->kind != Ast_Kind_StrLit) { + + if (node->kind == Ast_Kind_Struct_Type + || node->kind == Ast_Kind_Enum_Type + || node->kind == Ast_Kind_Poly_Struct_Type) { + ((AstStructType *)node)->name = bh_aprintf(global_heap_allocator, + "%b", symbol->text, symbol->length); + } + + if (node->kind == Ast_Kind_Type_Alias) { + node->token = symbol; + } + + // HACK + add_node_to_process(parser, (AstNode *) node); + } + + AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding); + binding->token = symbol; + binding->node = (AstNode *) node; + + return binding; +} + // 'use' // :: static AstNode* parse_top_level_statement(OnyxParser* parser) { @@ -1984,61 +2049,11 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { expect_token(parser, ':'); if (parser->curr->type == ':') { - expect_token(parser, ':'); - - AstTyped* node = parse_top_level_expression(parser); - if (parser->hit_unexpected_token || node == NULL) - return NULL; - - node->flags |= private_kind; - - if (node->kind == Ast_Kind_Function) { - AstFunction* func = (AstFunction *) node; - - if (func->exported_name == NULL) - func->exported_name = symbol; - - func->name = symbol; - - } else if (node->kind == Ast_Kind_Polymorphic_Proc) { - AstPolyProc* proc = (AstPolyProc *) node; - - if (proc->base_func->exported_name == NULL) - proc->base_func->exported_name = symbol; - - proc->base_func->name = symbol; - - } else if (node->kind == Ast_Kind_Global) { - AstGlobal* global = (AstGlobal *) node; - - if (global->exported_name == NULL) - global->exported_name = symbol; - - global->name = symbol; - - } else if (node->kind != Ast_Kind_Overloaded_Function - && node->kind != Ast_Kind_StrLit) { - - if (node->kind == Ast_Kind_Struct_Type - || node->kind == Ast_Kind_Enum_Type - || node->kind == Ast_Kind_Poly_Struct_Type) { - ((AstStructType *)node)->name = bh_aprintf(global_heap_allocator, - "%b", symbol->text, symbol->length); - } - - if (node->kind == Ast_Kind_Type_Alias) { - node->token = symbol; - } - - // HACK - add_node_to_process(parser, (AstNode *) node); - } - - AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding); - binding->token = symbol; - binding->node = (AstNode *) node; + AstBinding* binding = parse_top_level_binding(parser, symbol); + binding->node->flags |= private_kind; return (AstNode *) binding; + } else { AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres); memres->token = symbol; @@ -2197,12 +2212,12 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Prog parser.prev = NULL; parser.program = program; parser.hit_unexpected_token = 0; + parser.block_stack = NULL; parser.results = (ParseResults) { .allocator = global_heap_allocator, .nodes_to_process = NULL, - }; parser.polymorph_context = (PolymorphicContext) { @@ -2210,12 +2225,14 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Prog .poly_params = NULL, }; + bh_arr_new(global_heap_allocator, parser.block_stack, 4); bh_arr_new(parser.results.allocator, parser.results.nodes_to_process, 4); return parser; } void onyx_parser_free(OnyxParser* parser) { + bh_arr_free(parser->block_stack); } ParseResults onyx_parse(OnyxParser *parser) { diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 278a5d25..0b3a6584 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -667,6 +667,9 @@ static void symres_block(AstBlock* block) { scope_enter(block->scope); bh_arr_push(semstate.block_stack, block); + bh_arr_each(AstBinding *, binding, block->bindings) + symbol_introduce(semstate.curr_scope, (*binding)->token, (*binding)->node); + if (block->body) symres_statement_chain(&block->body);