'::' declarations in procedure scope are treated the same as file scoped
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 29 Dec 2020 18:23:21 +0000 (12:23 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 29 Dec 2020 18:23:21 +0000 (12:23 -0600)
14 files changed:
core/alloc/heap.onyx
core/conv.onyx
core/string.onyx
core/string/builder.onyx
docs/bugs
docs/todo
include/onyxastnodes.h
include/onyxparser.h
onyx
progs/odin_example.onyx
progs/poly_solidify.onyx
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c

index 94ff85b6d54d03de263e78dc01dbbdb6d0691b92..538e4507efc07e269244bf17bc8803c22b158da2 100644 (file)
@@ -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;
index 9f5a3c8e9a8ef0da2b576dbaafb2381cabd2ef15..a89c0d33339860e2dad2e46cda636324fcf55b40 100644 (file)
@@ -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;
 
index b3c6804efc88d78e4c3fab64eee2f133300eba39..8bc25835cb85b554c3c97c83f65cb4e69b58e7c0 100644 (file)
@@ -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];
index 69ee4d5a8e33f07b8b508eeea2af02a12e1a1ae0..2280686fa7933372ab83ffcee10152b103524fbe 100644 (file)
@@ -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;
index 8ded95c4af7dc7273e27ff701d43c2e68a849bd2..10e43eaa64aff58a7387f63eba9539ca5c1402e5 100644 (file)
--- 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;
+    }
+    ```
index 6da2e1001e1cd36cfc9e87a32339ce1542173405..d6d7ed0740f23e35d979229609d89d917274d2cf 100644 (file)
--- 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
index 82a7e3f2c8db6db01e2f9c4e97c937775e9f4ff0..5789ebbc4c2da6ef558cda58df8225706adac967 100644 (file)
@@ -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           {
index 789119c223cb7c759b271b63de8cd437d46e96e7..1b0bfc2e957e9ab9da3ed0442ab3b2b8c246c4c9 100644 (file)
@@ -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 1bdc8ffc4851897745aa42d82427efa9bd97f8d3..78d3f0e22c150f22b2f38a686a7ead60dceb8a1f 100755 (executable)
Binary files a/onyx and b/onyx differ
index f13b3e9af854f30f936c7932bc71855f720d7502..9de1b6d246d2edd9e5ab9ad5843c653a65225473 100644 (file)
@@ -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();
index 8e16c2c559b1aefbe3179a29e55fc0dcc8bcfa3d..4bf9035289bc746e7ced37c0448ee814cb7b50e6 100644 (file)
@@ -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);
index cd7f18c55c47c4b7f48329957195b09edcf2ede6..0cfd8a5d21a26515084424663df906996a6bfb5e 100644 (file)
@@ -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;
        }
 }
index dbcc22fb2e8e4da26d8802473fda6a2eff5569dc..d6d64331abd8c61857ffaa6443bb0c9f1248ff2e 100644 (file)
@@ -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' <string>
 // <symbol> :: <expr>
 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) {
index 278a5d2563ad08a179fbbc3a2b8b743a3927180f..0b3a658423f0d0edea65c12299df4b08b66fb949 100644 (file)
@@ -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);