bugfixes and added '#callsite' for default members
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 7 Jun 2021 01:30:07 +0000 (20:30 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 7 Jun 2021 01:30:07 +0000 (20:30 -0500)
12 files changed:
bin/onyx
core/builtin.onyx
include/onyxastnodes.h
modules/ui/ui.onyx
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index daf1e170b4927e19390c5704a3ea109718bcaad3..dd29ce75741bcf6232bd1591728e77787ba9751b 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 10f457350b82c2128da98a117f0daec51df731c0..664a617e317b39f308b5308f12235a2b2b145efa 100644 (file)
@@ -168,3 +168,10 @@ Iterator :: struct (T: type_expr) {
     next:  (data: rawptr) -> (T, bool);
     close: (data: rawptr) -> void = null_proc;
 }
+
+
+CallSite :: struct {
+    file   : str;
+    line   : u32;
+    column : u32;
+}
\ No newline at end of file
index dae2a82a8aea49795ff07b46fcb02af1d09fe6ca..e1aaed020105dbd50bd6bb2ce5ced5bfc2170887 100644 (file)
@@ -81,6 +81,7 @@
     NODE(PolyProc)             \
                                \
     NODE(Note)                 \
+    NODE(CallSite)             \
                                \
     NODE(Package)          
 
@@ -180,6 +181,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Add_Overload,
     Ast_Kind_Directive_Operator,
     Ast_Kind_Directive_Export,
+    Ast_Kind_Call_Site,
 
     Ast_Kind_Note,
 
@@ -942,6 +944,16 @@ struct AstNote {
     AstNode_base;
 };
 
+struct AstCallSite {
+    AstTyped_base;
+
+    OnyxToken* callsite_token;
+
+    AstStrLit* filename;
+    AstNumLit* line;
+    AstNumLit* column;
+};
+
 typedef enum EntityState {
     Entity_State_Error,
     
@@ -1164,6 +1176,7 @@ extern Type     *builtin_vararg_type_type;
 extern AstTyped *builtin_context_variable;
 extern AstType  *builtin_allocator_type;
 extern AstType  *builtin_iterator_type;
+extern AstType  *builtin_callsite_type;
 
 typedef struct BuiltinSymbol {
     char*    package;
index 90bbff384092bbd317c916dbda76432da4b9bfbf..13a72342a76b0f68dc347074d3a400ae25262e4c 100644 (file)
@@ -43,7 +43,7 @@ get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
 }
 
 // 'x' and 'y' are the top-left coordinates of the text. 'y' is NOT the baseline.
-draw_text :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
+draw_text_raw :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
     gl.activeTexture(gl.TEXTURE0);
     gl.bindTexture(gl.TEXTURE_2D, font_texture);
     gfx.set_texture(0);
@@ -90,21 +90,26 @@ draw_rect :: proc {
 }
 
 @Themeing
-draw_button :: (use r: Rectangle, text: str) -> bool {
-    gfx.set_texture();
+draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme) -> bool {
+    height := Rectangle.height(r);
+    draw_text_raw(text, x0, y0, theme.font_size * height, theme.text_color);
+}
 
-    padding :: 10.0f    @RawPixels
+@Themeing
+draw_button :: (use r: Rectangle, text: str, theme := ^default_button_theme) -> bool {
+    gfx.set_texture();
 
+    border_width  := theme.border_width;
     width, height := Rectangle.dimensions(r);
 
-    gfx.rect(.{ x0, y0 }, .{ width, height }, .{ 0.2, 0.2, 0.2 });
-    gfx.rect(.{ x0 + padding, y0 + padding }, .{ width - padding * 2, height - padding * 2 }, .{ 0.1, 0.1, 0.1 });
+    gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
+    gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, theme.background_color);
 
-    font_size := height * .4;
+    font_size := height * theme.font_size;
     text_width := font->get_width(text, font_size);
     text_height := font->get_height(text, font_size);
 
-    draw_text(text, x0 + (width - text_width) / 2, y0 + (height - text_height) / 2, font_size, .{ 1, 1, 1 });
+    draw_text_raw(text, x0 + (width - text_width) / 2, y0 + (height - text_height) / 2, font_size, theme.text_color);
     return false;
 }
 
@@ -115,7 +120,7 @@ Rectangle :: struct {
     // x0,y0 ------------+
     //   |               |
     //   |               |
-    //   +------------ x1, y1
+    //   +------------ x1,y1
     //
 
     x0: f32 = 0;
@@ -127,7 +132,7 @@ Rectangle :: struct {
     height :: (use r: Rectangle) -> f32 do return math.abs(y1 - y0);
 
     dimensions :: (use r: Rectangle) -> (width: f32, height: f32) {
-        return math.abs(x1 - x0), math.abs(y1 - y0);
+        return width(r), height(r);
     }
 
     top_left     :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.min(y0, y1);
@@ -136,3 +141,27 @@ Rectangle :: struct {
 
 
 
+@Relocate
+Text_Theme :: struct {
+    text_color := gfx.Color4.{ 1, 1, 1 };
+    font_size  := .4f; // Percentage of height of button
+}
+
+@Relocate
+Button_Theme :: struct {
+    @Bug
+    // I accidentally left this as 'text_color', and there was not a compiler error, even through there
+    // should have been. Instead it looked like the wrong offset was being used for the members and that
+    // was affecting the generated code.
+    use text_theme := Text_Theme.{};
+
+    background_color := gfx.Color4.{ 0.1, 0.1, 0.1 };
+
+    border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
+    border_width := 10.0f; @InPixels
+}
+
+@Bug // there is a compile-time known bug if either of the 'Button_Theme's below are omitted.
+default_button_theme: Button_Theme = Button_Theme.{};
+default_text_theme:   Text_Theme   = Text_Theme.{};
\ No newline at end of file
index 04dd5f27a0c91862ec61ac38c5f3940b04580fe6..0a8abaf0d8931ef9bc9f08da885eef32ba35a4f0 100644 (file)
@@ -49,6 +49,7 @@ Type     *builtin_vararg_type_type;
 AstTyped *builtin_context_variable;
 AstType  *builtin_allocator_type;
 AstType  *builtin_iterator_type;
+AstType  *builtin_callsite_type;
 
 const BuiltinSymbol builtin_symbols[] = {
     { NULL, "void",       (AstNode *) &basic_type_void },
@@ -385,6 +386,12 @@ void initialize_builtins(bh_allocator a) {
         return;
     }
 
+    builtin_callsite_type = (AstType *) symbol_raw_resolve(p->scope, "CallSite");
+    if (builtin_callsite_type == NULL) {
+        onyx_report_error((OnyxFilePos) { 0 }, "'CallSite' struct not found in builtin package.");
+        return;
+    }
+
 
     fori (i, 0, Binary_Op_Count) {
         bh_arr_new(global_heap_allocator, operator_overloads[i], 4); 
index 44f5d097a89b327ff0cdd3b9add567e46884144e..305f95afa1bea641370f00d62137f246af6438de 100644 (file)
@@ -473,6 +473,41 @@ CheckStatus check_call(AstCall* call) {
         return Check_Error;
     }
 
+    // HACK HACK HACK
+    // :CallSiteIsGross
+    bh_arr_each(AstArgument *, arg, arg_arr) {
+        AstTyped** arg_value = &(*arg)->value;
+
+        if ((*arg_value)->kind == Ast_Kind_Call_Site) {
+            AstCallSite* callsite = (AstCallSite *) ast_clone(context.ast_alloc, *arg_value);
+            callsite->callsite_token = call->token;
+
+            // HACK CLEANUP
+            OnyxToken* str_token = bh_alloc(context.ast_alloc, sizeof(OnyxToken));
+            str_token->text  = bh_strdup(global_heap_allocator, (char *) call->token->pos.filename);
+            str_token->length = strlen(call->token->pos.filename);
+            str_token->pos = call->token->pos;
+            str_token->type = Token_Type_Literal_String;
+
+            AstStrLit* filename = bh_alloc_item(context.ast_alloc, AstStrLit);
+            memset(filename, 0, sizeof(AstStrLit));
+            filename->kind  = Ast_Kind_StrLit;
+            filename->token = str_token;
+            filename->addr  = 0;
+            
+            add_entities_for_node(NULL, (AstNode *) filename, NULL, NULL);
+            callsite->filename = filename;
+
+            callsite->line   = make_int_literal(context.ast_alloc, call->token->pos.line);
+            callsite->column = make_int_literal(context.ast_alloc, call->token->pos.column);
+
+            convert_numlit_to_type(callsite->line,   &basic_types[Basic_Kind_U32]);
+            convert_numlit_to_type(callsite->column, &basic_types[Basic_Kind_U32]);
+
+            *arg_value = (AstTyped *) callsite;
+        }
+    }
+
     // NOTE: If we are calling an intrinsic function, translate the
     // call into an intrinsic call node.
     if (callee->flags & Ast_Flag_Intrinsic) {
@@ -1509,6 +1544,8 @@ CheckStatus check_expression(AstTyped** pexpr) {
             CHECK(compound, (AstCompound *) expr);
             break;
 
+        case Ast_Kind_Call_Site: break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
@@ -1573,7 +1610,14 @@ CheckStatus check_statement(AstNode** pstmt) {
         case Ast_Kind_Local: {
             AstTyped* typed_stmt = (AstTyped *) stmt;
             fill_in_type(typed_stmt);
-            if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) return Check_Yield_Macro;
+            if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) {
+                if (!node_is_type((AstNode *) typed_stmt->type_node)) {
+                    onyx_report_error(stmt->token->pos, "Local's type is not a type.");
+                    return Check_Error;
+                }
+                
+                return Check_Yield_Macro;
+            }
             return Check_Success;
         }
 
@@ -1781,6 +1825,12 @@ CheckStatus check_function_header(AstFunction* func) {
         }
 
         if (local->type_node != NULL) CHECK(type, local->type_node);
+        if (local->type_node != NULL) {
+            if (!node_is_type((AstNode *) local->type_node)) {
+                onyx_report_error(local->token->pos, "Parameter type is not a type.");
+                return Check_Error;
+            }
+        }
 
         fill_in_type((AstTyped *) local);
         if (local->type == NULL) {
index 26c46732e9c197d9be5f3d572ac23946ee5d0021..4e5e3a9bb27c4b967a2591f77ecd80200a4cf76e 100644 (file)
@@ -90,6 +90,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Directive_Solidify: return sizeof(AstDirectiveSolidify);
         case Ast_Kind_Compound: return sizeof(AstCompound);
         case Ast_Kind_Named_Value: return sizeof(AstNamedValue);
+        case Ast_Kind_Call_Site: return sizeof(AstCallSite);
         case Ast_Kind_Count: return 0;
        }
 
index 8cebcf1f37c02428d8d8bb3f2de37a66e03565cf..38cec8f809132d494a22aadfc915972a8b32a16b 100644 (file)
@@ -642,11 +642,15 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 parse_arguments(parser, ')', &call_node->args);
 
                 // Wrap expressions in AstArgument
-                bh_arr_each(AstTyped *, arg, call_node->args.values)
+                bh_arr_each(AstTyped *, arg, call_node->args.values) {
+                    if ((*arg) == NULL) continue;
                     *arg = (AstTyped *) make_argument(parser->allocator, *arg);
+                }
 
-                bh_arr_each(AstNamedValue *, named_value, call_node->args.named_values)
+                bh_arr_each(AstNamedValue *, named_value, call_node->args.named_values) {
+                    if ((*named_value)->value == NULL) continue;
                     (*named_value)->value = (AstTyped *) make_argument(parser->allocator, (AstTyped *) (*named_value)->value);
+                }
 
                 retval = (AstTyped *) call_node;
                 break;
@@ -1862,8 +1866,20 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
             }
         }
 
-        if (curr_param.vararg_kind == VA_Kind_Not_VA && consume_token_if_next(parser, '='))
-            curr_param.default_value = parse_expression(parser, 0);
+        if (curr_param.vararg_kind == VA_Kind_Not_VA && consume_token_if_next(parser, '=')) {
+            OnyxToken* directive_token = parser->curr;
+
+            // :Callsite  currently #callsite is only valid as a default value for a funciton parameter.
+            if (parse_possible_directive(parser, "callsite")) {
+                AstCallSite* cs = make_node(AstCallSite, Ast_Kind_Call_Site);
+                cs->token = directive_token;
+                cs->type_node = builtin_callsite_type;
+                curr_param.default_value = (AstTyped *) cs;
+
+            } else {
+                curr_param.default_value = parse_expression(parser, 0);
+            }
+        }
 
         if (param_is_baked) {
             param_is_baked = 0;
index 73601791826e2b54167f0ab35f989d8c96a79bb7..8546ac7b17b66c86169e00bcf450c8678d3c584c 100644 (file)
@@ -92,29 +92,6 @@ static SymresStatus symres_struct_type(AstStructType* s_node) {
     if (s_node->flags & Ast_Flag_Type_Is_Resolved) return Symres_Success;
 
     s_node->flags |= Ast_Flag_Type_Is_Resolved;
-    
-    {
-        bh_table(i32) mem_set;
-        bh_table_init(global_heap_allocator, mem_set, bh_arr_length(s_node->members));
-
-        bh_arr_each(AstStructMember *, member, s_node->members) {
-            token_toggle_end((*member)->token);
-
-            if (bh_table_has(i32, mem_set, (*member)->token->text)) {
-                onyx_report_error((*member)->token->pos,
-                        "Duplicate struct member '%s'.",
-                        (*member)->token->text);
-
-                token_toggle_end((*member)->token);
-                return Symres_Error;
-            }
-
-            bh_table_put(i32, mem_set, (*member)->token->text, 1);
-            token_toggle_end((*member)->token);
-        }
-
-        bh_table_free(mem_set);
-    }
 
     if (s_node->scope) {
         // FIX: This is probably wrong for the long term.
index 800ff5381d2eb27b09062ae52ac7b22f409d05b3..4074c0c8f5d6763f5434177308b447561f9fff7f 100644 (file)
@@ -349,6 +349,10 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                     .used = (((*member)->flags & Ast_Flag_Struct_Mem_Used) != 0),
                 };
 
+                if (bh_table_has(StructMember, s_type->Struct.members, (*member)->token->text)) {
+                    onyx_report_error((*member)->token->pos, "Duplicate struct member, '%s'.", (*member)->token->text);
+                    return NULL;
+                }
                 bh_table_put(StructMember, s_type->Struct.members, (*member)->token->text, smem);
                 token_toggle_end((*member)->token);
 
@@ -366,6 +370,10 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                             .used = 0,
                         };
 
+                        if (bh_table_has(StructMember, s_type->Struct.members, (*psmem)->name)) {
+                            onyx_report_error((*member)->token->pos, "Duplicate struct member, '%s'.", (*psmem)->name);
+                            return NULL;
+                        }
                         bh_table_put(StructMember, s_type->Struct.members, (*psmem)->name, new_smem);
                     }
                 }
index 81a59d411aeffbfdb4baaaa18137f6bb7aa89fcd..8d1d9ac9b22281ed0a2439f2e1b714fa4b70e3f6 100644 (file)
@@ -182,6 +182,10 @@ AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol) {
                 package->package = package_lookup(package->package_name);
             }
 
+            if (package->package == NULL) {
+                return NULL;
+            }
+
             return symbol_raw_resolve(package->package->scope, symbol);
         } 
 
index ed1824d5ce9219665abac1119d67151b3c2fd9fc..732f9f243e47f0b2b9de10f3e4aa6f655e72e2f0 100644 (file)
@@ -2450,6 +2450,15 @@ EMIT_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Call_Site: {
+            AstCallSite* callsite = (AstCallSite *) expr;
+
+            emit_expression(mod, &code, (AstTyped *) callsite->filename);
+            emit_expression(mod, &code, (AstTyped *) callsite->line);
+            emit_expression(mod, &code, (AstTyped *) callsite->column);
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;