starting to work on macros; not functional yet
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 12 Aug 2021 12:41:49 +0000 (07:41 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 12 Aug 2021 12:41:49 +0000 (07:41 -0500)
14 files changed:
bin/onyx
include/onyxastnodes.h
include/onyxlex.h
misc/onyx.sublime-syntax
misc/onyx.vim
src/onyxastnodes.c
src/onyxchecker.c
src/onyxentities.c
src/onyxerrors.c
src/onyxlex.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index 2ec57ae7e0ad4d9bdfcfe122639e148bd52fe4c0..16ae4856388725f7fc759d7c8bf5e0737322824f 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index cda6fcf39b0c609bb4c2995ab9a51c4c8e87167d..63e52ab3ed5bd6383b8cddd0431adf89f3247f77 100644 (file)
@@ -87,6 +87,7 @@
                                \
     NODE(CodeBlock)            \
     NODE(DirectiveInsert)      \
+    NODE(Macro)                \
                                \
     NODE(Package)          
 
@@ -191,6 +192,7 @@ typedef enum AstKind {
 
     Ast_Kind_Code_Block,
     Ast_Kind_Directive_Insert,
+    Ast_Kind_Macro,
 
     Ast_Kind_Note,
 
@@ -481,6 +483,16 @@ typedef enum VarArgKind {
     VA_Kind_Untyped,
 } VarArgKind;
 
+typedef enum BlockRule {
+    Block_Rule_New_Scope         = BH_BIT(1),
+    Block_Rule_New_Binding_Scope = BH_BIT(2), // Unused
+    Block_Rule_Clear_Defer       = BH_BIT(3),
+
+    Block_Rule_Normal     = Block_Rule_New_Scope | Block_Rule_New_Binding_Scope | Block_Rule_Clear_Defer,
+    Block_Rule_Macro      = Block_Rule_New_Scope | Block_Rule_New_Binding_Scope,
+    Block_Rule_Code_Block = Block_Rule_New_Scope,
+} BlockRule;
+
 typedef struct Arguments Arguments;
 struct Arguments {
     bh_arr(AstTyped *) values;
@@ -637,10 +649,12 @@ struct AstUse           {
 // Structure Nodes
 struct AstBlock         {
     AstNode_base;
+
     AstNode *body;
-    Scope *scope;
 
+    Scope *scope;
     Scope *binding_scope;
+    BlockRule rules;
 };
 struct AstDefer         { AstNode_base; AstNode *stmt; };
 struct AstFor           {
@@ -1026,6 +1040,12 @@ struct AstDirectiveInsert {
     AstTyped *code_expr;
 };
 
+struct AstMacro {
+    AstTyped_base;
+
+    AstTyped* body;
+};
+
 typedef enum EntityState {
     Entity_State_Error,
     
@@ -1061,6 +1081,7 @@ typedef enum EntityType {
     Entity_Type_Memory_Reservation_Type,
     Entity_Type_Use,
     Entity_Type_Polymorphic_Proc,
+    Entity_Type_Macro,
     Entity_Type_Foreign_Function_Header,
     Entity_Type_Foreign_Global_Header,
     Entity_Type_Function_Header,
@@ -1109,6 +1130,7 @@ typedef struct Entity {
         AstEnumType           *enum_type;
         AstMemRes             *mem_res;
         AstPolyProc           *poly_proc;
+        AstMacro              *macro;
         AstUse                *use;
     };
 } Entity;
index bbb2d9a64360521b908daf010148aa8b68847075..7c4789aeadd8121e3d1fa218be04c6fae8f6ca4a 100644 (file)
@@ -37,6 +37,7 @@ typedef enum TokenType {
     Token_Type_Keyword_Case,
     Token_Type_Keyword_Switch,
     Token_Type_Keyword_Fallthrough,
+    Token_Type_Keyword_Macro,
 
     Token_Type_Right_Arrow,
     Token_Type_Left_Arrow,
index 6f7a4d7eebc9d379952d902f64a6da096df55de7..a5666d386eafd8ea6619698d89bea8553ca2c2e9 100644 (file)
@@ -26,7 +26,7 @@ contexts:
     # strings in YAML. When using single quoted strings, only single quotes
     # need to be escaped: this is done by using two single quotes next to each
     # other.
-    - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case)\b'
+    - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case|macro)\b'
       scope: keyword.control.onyx
 
     - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|str|cstr|range|type_expr|any)\b'
@@ -70,6 +70,11 @@ contexts:
         1: entity.name.type
         2: keyword.control.onyx
 
+    - match: '([a-zA-Z_][a-zA-Z0-9_]*)\s*::\s*(macro)'
+      captures:
+        1: entity.name.function
+        2: keyword.control.onyx
+
     - match: '([a-zA-Z_][a-zA-Z0-9_]*)\s*::\s*(enum)'
       captures:
         1: entity.name.enum
index 08f089104fedb3caabe55288dcdaa91b58dd95b9..a6a79a512eb897453dc84c7a6cd7c00a2bbd50f3 100644 (file)
@@ -10,7 +10,7 @@ endif
 let s:cpo_save = &cpo
 set cpo&vim
 
-syn keyword onyxKeyword package struct enum proc use global
+syn keyword onyxKeyword package struct enum proc use global macro
 syn keyword onyxKeyword if elseif else
 syn keyword onyxKeyword for while do
 syn keyword onyxKeyword switch case
index 5aef4393e340d55d8f119596078cb1bb98b46dfe..45f4f04c227362b1af52350bc9f08cdd6c8cf07f 100644 (file)
@@ -88,7 +88,8 @@ static const char* ast_node_names[] = {
     "CALL SITE",
 
     "CODE BLOCK",
-    "DIRECTIVE INSERT"
+    "DIRECTIVE INSERT",
+    "MACRO",
 
     "NOTE",
 
@@ -142,6 +143,7 @@ const char* entity_type_strings[Entity_Type_Count] = {
     "Memory Reservation Type",
     "Use",
     "Polymorphic Proc",
+    "Macro",
     "Foreign_Function Header",
     "Foreign_Global Header",
     "Function Header",
index b167dd0471217d4d191a80c94372e79249935e0b..6d753d294090464b182528e3dae6c563fcbc8e54 100644 (file)
@@ -29,7 +29,7 @@ CheckStatus check_if(AstIfWhile* ifnode);
 CheckStatus check_while(AstIfWhile* whilenode);
 CheckStatus check_for(AstFor* fornode);
 CheckStatus check_switch(AstSwitch* switchnode);
-CheckStatus check_call(AstCall* call);
+CheckStatus check_call(AstCall** pcall);
 CheckStatus check_binaryop(AstBinaryOp** pbinop);
 CheckStatus check_unaryop(AstUnaryOp** punop);
 CheckStatus check_struct_literal(AstStructLiteral* sl);
@@ -413,7 +413,7 @@ typedef enum ArgState {
     AS_Expecting_Untyped_VA,
 } ArgState;
 
-CheckStatus check_call(AstCall* call) {
+CheckStatus check_call(AstCall** pcall) {
     // All the things that need to be done when checking a call node.
     //      1. Ensure the callee is not a symbol
     //      2. Check the callee expression (since it could be a variable or a field access, etc)
@@ -424,11 +424,14 @@ CheckStatus check_call(AstCall* call) {
     //      7. Fill in arguments
     //      8. If callee is an intrinsic, turn call into an Intrinsic_Call node
     //      9. Check types of formal and actual params against each other, handling varargs
-
+    AstCall* call = *pcall;
+    
     if (call->flags & Ast_Flag_Has_Been_Checked) return Check_Success;
 
+    u32 current_checking_level_store = current_checking_level;
     CHECK(expression, &call->callee);
     CHECK(arguments, &call->args);
+    current_checking_level = current_checking_level_store;
 
     // SPEED CLEANUP: Keeping an original copy for basically no reason except that sometimes you
     // need to know the baked argument values in code generation.
@@ -438,11 +441,28 @@ CheckStatus check_call(AstCall* call) {
 
     while (call->callee->kind == Ast_Kind_Alias) call->callee = ((AstAlias *) call->callee)->alias;
 
-    if (call->callee->kind == Ast_Kind_Overloaded_Function) {
+    AstTyped *effective_callee = call->callee;
+
+    // If we are "calling" a macro, the callee on the call node should not be replaced
+    // as then it would remove the macro from the callee, which would turn it into a
+    // normal function call.
+    b32 calling_a_macro = 0;
+
+    if (effective_callee->kind == Ast_Kind_Macro) {
+        calling_a_macro = 1;
+        if (current_checking_level == EXPRESSION_LEVEL) {
+            onyx_report_error(call->token->pos, "Macros calls are not allowed at the expression level yet.");
+            return Check_Error;
+        }
+
+        effective_callee = ((AstMacro * ) effective_callee)->body;
+    }
+
+    if (effective_callee->kind == Ast_Kind_Overloaded_Function) {
         b32 should_yield = 0;
-        AstTyped* new_callee = find_matching_overload_by_arguments(((AstOverloadedFunction *) call->callee)->overloads, &call->args, &should_yield);
+        AstTyped* new_callee = find_matching_overload_by_arguments(((AstOverloadedFunction *) effective_callee)->overloads, &call->args, &should_yield);
         if (new_callee == NULL) {
-            if (call->callee->entity->state > Entity_State_Check_Types && !should_yield) {
+            if (effective_callee->entity->state > Entity_State_Check_Types && !should_yield) {
                 report_unable_to_match_overload(call);
                 return Check_Error;
 
@@ -451,19 +471,21 @@ CheckStatus check_call(AstCall* call) {
             }
         }
 
-        call->callee = new_callee;
+        effective_callee = new_callee;
+        if (!calling_a_macro) call->callee = new_callee;
     }
 
-    if (call->callee->kind == Ast_Kind_Polymorphic_Proc) {
-        AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) call->callee, PPLM_By_Arguments, &call->args, call->token);
+    if (effective_callee->kind == Ast_Kind_Polymorphic_Proc) {
+        AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) effective_callee, PPLM_By_Arguments, &call->args, call->token);
         if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro;
         if (new_callee == NULL) return Check_Error;
 
         arguments_remove_baked(&call->args);
-        call->callee = new_callee;
+        effective_callee = new_callee;
+        if (!calling_a_macro) call->callee = new_callee;
     }
 
-    AstFunction* callee = (AstFunction *) call->callee;
+    AstFunction* callee = (AstFunction *) effective_callee;
 
     // NOTE: Build callee's type
     fill_in_type((AstTyped *) callee);
@@ -476,7 +498,6 @@ CheckStatus check_call(AstCall* call) {
         return Check_Error;
     }
 
-
     // CLEANUP maybe make function_get_expected_arguments?
     i32 non_vararg_param_count = (i32) callee->type->Function.param_count;
     if (non_vararg_param_count > 0 &&
@@ -644,7 +665,8 @@ CheckStatus check_call(AstCall* call) {
                 }
 
                 arg_arr[arg_pos]->va_kind = VA_Kind_Untyped;
-                break;
+                break;CheckStatus check_compound(AstCompound* compound);
+
             }
         }
 
@@ -665,7 +687,12 @@ type_checking_done:
         return Check_Error;
     }
 
-    callee->flags |= Ast_Flag_Function_Used;
+    if (!calling_a_macro) {
+        callee->flags |= Ast_Flag_Function_Used;
+
+    } else {
+        // Macro expansion
+    }
 
     return Check_Success;
 }
@@ -967,7 +994,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) {
         AstCall *implicit_call = binaryop_try_operator_overload(binop);
 
         if (implicit_call != NULL) {
-            CHECK(call, implicit_call);
+            CHECK(call, &implicit_call);
 
             // NOTE: Not a binary op
             *pbinop = (AstBinaryOp *) implicit_call;
@@ -1365,7 +1392,7 @@ CheckStatus check_subscript(AstSubscript** psub) {
         AstCall *implicit_call = binaryop_try_operator_overload(binop);
 
         if (implicit_call != NULL) {
-            CHECK(call, implicit_call);
+            CHECK(call, &implicit_call);
 
             // NOTE: Not an array access
             *psub = (AstSubscript *) implicit_call;
@@ -1519,7 +1546,7 @@ CheckStatus check_method_call(AstBinaryOp** mcall) {
     }    
     (*mcall)->flags |= Ast_Flag_Has_Been_Checked;
 
-    CHECK(call, call_node);
+    CHECK(call, &call_node);
     call_node->next = (*mcall)->next;
 
     *mcall = (AstBinaryOp *) call_node;
@@ -1568,6 +1595,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
         return Check_Success;
     }
 
+    if (expr->kind == Ast_Kind_Macro) {
+        return Check_Success;
+    }
+
     fill_in_type(expr);
     current_checking_level = EXPRESSION_LEVEL;
 
@@ -1576,7 +1607,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
         case Ast_Kind_Binary_Op: retval = check_binaryop((AstBinaryOp **) pexpr); break;
         case Ast_Kind_Unary_Op:  retval = check_unaryop((AstUnaryOp **) pexpr); break;
 
-        case Ast_Kind_Call:     retval = check_call((AstCall *expr); break;
+        case Ast_Kind_Call:     retval = check_call((AstCall **) pexpr); break;
         case Ast_Kind_Argument: retval = check_argument((AstArgument **) pexpr); break;
         case Ast_Kind_Block:    retval = check_block((AstBlock *) expr); break;
 
@@ -1742,7 +1773,7 @@ CheckStatus check_insert_directive(AstDirectiveInsert** pinsert) {
     AstNode* cloned_block = ast_clone(context.ast_alloc, code_block->code);
     cloned_block->next = insert->next;
 
-    if (cloned_block->kind == Ast_Kind_Block) {
+    /*if (cloned_block->kind == Ast_Kind_Block) {
         AstNode* next = insert->next;
         insert->next = (AstNode *) ((AstBlock *) cloned_block)->body;
 
@@ -1751,8 +1782,9 @@ CheckStatus check_insert_directive(AstDirectiveInsert** pinsert) {
         last_stmt->next = next;
 
     } else {
+        */
         *(AstNode **) pinsert = cloned_block;
-    }
+    //}
 
     insert->flags |= Ast_Flag_Has_Been_Checked;
 
@@ -1775,6 +1807,11 @@ CheckStatus check_statement(AstNode** pstmt) {
         case Ast_Kind_Switch:     return check_switch((AstSwitch *) stmt);
         case Ast_Kind_Block:      return check_block((AstBlock *) stmt);
         case Ast_Kind_Defer:      return check_statement(&((AstDefer *) stmt)->stmt);
+        case Ast_Kind_Call: {
+            CHECK(call, (AstCall **) pstmt);
+            stmt->flags |= Ast_Flag_Expr_Ignored;
+            return Check_Success;
+        }
 
         case Ast_Kind_Binary_Op:
             CHECK(binaryop, (AstBinaryOp **) pstmt);
@@ -2161,6 +2198,14 @@ CheckStatus check_process_directive(AstNode* directive) {
     return Check_Success;
 }
 
+CheckStatus check_macro(AstMacro* macro) {
+    if (macro->body->kind == Ast_Kind_Function) {
+        CHECK(function_header, (AstFunction *) macro->body);
+    }
+
+    return Check_Success;
+}
+
 CheckStatus check_node(AstNode* node) {
     switch (node->kind) {
         case Ast_Kind_Function:             return check_function((AstFunction *) node);
@@ -2170,7 +2215,7 @@ CheckStatus check_node(AstNode* node) {
         case Ast_Kind_If:                   return check_if((AstIfWhile *) node);
         case Ast_Kind_Static_If:            return check_if((AstIfWhile *) node);
         case Ast_Kind_While:                return check_while((AstIfWhile *) node);
-        case Ast_Kind_Call:                 return check_call((AstCall *node);
+        case Ast_Kind_Call:                 return check_call((AstCall **) &node);
         case Ast_Kind_Binary_Op:            return check_binaryop((AstBinaryOp **) &node);
         default:                            return check_expression((AstTyped **) &node);
     }
@@ -2189,6 +2234,7 @@ void check_entity(Entity* ent) {
         case Entity_Type_Memory_Reservation_Type:  cs = check_memres_type(ent->mem_res); break;
         case Entity_Type_Memory_Reservation:       cs = check_memres(ent->mem_res); break;
         case Entity_Type_Static_If:                cs = check_static_if(ent->static_if); break;
+        case Entity_Type_Macro:                    cs = check_macro(ent->macro);
 
         case Entity_Type_Expression:
             cs = check_expression(&ent->expr);
index 3ba43d5614c914d78d9d15de7316b48fc6665e74..2c52c1f2ca39f76088d39554012a869c96f1d55f 100644 (file)
@@ -287,6 +287,13 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s
             ENTITY_INSERT(ent);
             break;
         }
+
+        case Ast_Kind_Macro: {
+            ent.type = Entity_Type_Macro;
+            ent.macro = (AstMacro *) node;
+            ENTITY_INSERT(ent);
+            break;
+        }
         
         case Ast_Kind_Polymorphic_Proc: {
             ent.type = Entity_Type_Polymorphic_Proc;
index 5c25f63ef3c97dc744e8e05f45134160d649b06b..0dbffbe1397d31325526f6d8c4c1ced35ae0f55c 100644 (file)
@@ -72,7 +72,6 @@ b32 onyx_has_errors() {
 }
 
 void onyx_clear_errors() {
-    bh_printf("ERRORS WERE CLEARED!!!\n");
     bh_arr_set_length(errors.errors, 0);
 }
 
index 59370246b301cc32ba0ea6ea0fc98d55009a2692..433c3b9db9d1cde3473c50af0208059b8ea6db5d 100644 (file)
@@ -35,6 +35,7 @@ static const char* token_type_names[] = {
     "switch",
     "case",
     "fallthrough",
+    "macro",
 
     "->",
     "<-",
@@ -334,6 +335,9 @@ whitespace_skipped:
     case 'i':
         LITERAL_TOKEN("if",          1, Token_Type_Keyword_If);
         break;
+    case 'm':
+        LITERAL_TOKEN("macro",       1, Token_Type_Keyword_Macro);
+        break;
     case 'p':
         LITERAL_TOKEN("package",     1, Token_Type_Keyword_Package);
         LITERAL_TOKEN("proc",        1, Token_Type_Keyword_Proc);
index 36f3a78350e535bfed75dbf226aae66e2e5d8f7e..d6e615836dd745842295828696c14a929b5343eb 100644 (file)
@@ -469,12 +469,14 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        #if 0
         case Token_Type_Keyword_Proc: {
             OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
             onyx_report_warning(proc_token->pos, "Warning: 'proc' is a deprecated keyword.");
             retval = (AstTyped *) parse_function_definition(parser, proc_token);
             break;
         }
+        #endif
 
         case Token_Type_Keyword_Package: {
             retval = (AstTyped *) parse_package_expression(parser);
@@ -616,6 +618,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
 
                 if (parser->curr->type == '{') {
                     code_block->code = (AstNode *) parse_block(parser, 1);
+                    ((AstBlock *) code_block->code)->rules = Block_Rule_Code_Block;
 
                 } else {
                     code_block->code = (AstNode *) parse_expression(parser, 0);
@@ -1435,6 +1438,7 @@ static AstNode* parse_statement(OnyxParser* parser) {
 
 static AstBlock* parse_block(OnyxParser* parser, b32 make_a_new_scope) {
     AstBlock* block = make_node(AstBlock, Ast_Kind_Block);
+    block->rules = Block_Rule_Normal;
 
     // NOTE: --- is for an empty block
     if (parser->curr->type == Token_Type_Empty_Block) {
@@ -2018,11 +2022,6 @@ static AstOverloadedFunction* parse_overloaded_function(OnyxParser* parser, Onyx
 }
 
 static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* token) {
-    // :TemporaryForProcRemoval
-    if (parser->curr->type == '{') {
-        return (AstFunction *) parse_overloaded_function(parser, token);
-    }
-
     AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
     func_def->token = token;
 
@@ -2076,17 +2075,16 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok
         pp->poly_params = polymorphic_vars;
         pp->base_func = func_def;
         
-        ENTITY_SUBMIT(pp);
         return (AstFunction *) pp;
+
     } else {
         bh_arr_free(polymorphic_vars);
-        
-        ENTITY_SUBMIT(func_def);
         return func_def;
     }
 }
 
 static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret) {
+    #if 0
     if (parser->curr->type == Token_Type_Keyword_Proc) {
         OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
         onyx_report_warning(proc_token->pos, "Warning: 'proc' is a deprecated keyword.");
@@ -2094,6 +2092,7 @@ static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret
         *ret = (AstTyped *) func_node;
         return 1;
     }
+    #endif
 
     if (parser->curr->type == '(') {
         OnyxToken* matching_paren = find_matching_paren(parser->curr);
@@ -2120,6 +2119,7 @@ static b32 parse_possible_function_definition(OnyxParser* parser, AstTyped** ret
 
         OnyxToken* proc_token = parser->curr;
         AstFunction* func_node = parse_function_definition(parser, proc_token);
+        ENTITY_SUBMIT(func_node);
         *ret = (AstTyped *) func_node;
         return 1;
     }
@@ -2251,7 +2251,17 @@ static AstIf* parse_static_if_stmt(OnyxParser* parser, b32 parse_block_as_statem
     return static_if_node;
 }
 
+static AstMacro* parse_macro(OnyxParser* parser) {
+    AstMacro* macro = make_node(AstMacro, Ast_Kind_Macro);
+    macro->token = expect_token(parser, Token_Type_Keyword_Macro);
+    macro->body  = (AstTyped *) parse_function_definition(parser, macro->token);
+
+    ENTITY_SUBMIT(macro);
+    return macro;
+}
+
 static AstTyped* parse_top_level_expression(OnyxParser* parser) {
+    #if 0
     if (parser->curr->type == Token_Type_Keyword_Proc) {
         OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
         onyx_report_warning(proc_token->pos, "Warning: 'proc' is a deprecated keyword.");
@@ -2259,10 +2269,12 @@ static AstTyped* parse_top_level_expression(OnyxParser* parser) {
 
         return (AstTyped *) func_node;
     }
+    #endif
     
     if (parser->curr->type == Token_Type_Keyword_Global) return parse_global_declaration(parser);
     if (parser->curr->type == Token_Type_Keyword_Struct) return (AstTyped *) parse_struct(parser);
     if (parser->curr->type == Token_Type_Keyword_Enum)   return (AstTyped *) parse_enum_declaration(parser);
+    if (parser->curr->type == Token_Type_Keyword_Macro)  return (AstTyped *) parse_macro(parser);
     
     if (parse_possible_directive(parser, "type")) {
         AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
@@ -2304,6 +2316,15 @@ static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol
 
         proc->base_func->name = symbol;
 
+    } else if (node->kind == Ast_Kind_Macro) {
+        AstMacro* macro = (AstMacro *) node;
+
+        AstFunction* func = (AstFunction *) macro->body;
+        if (func->kind == Ast_Kind_Polymorphic_Proc)
+            func = (AstFunction *) ((AstPolyProc *) func)->base_func;
+
+        func->name = symbol;
+
     } else if (node->kind == Ast_Kind_Global) {
         AstGlobal* global = (AstGlobal *) node;
 
index 592029796c101cc17ea87867b71a19f024be31ac..89b6d4883b7943177551e89dbcace7d3ec9521ef 100644 (file)
@@ -6,7 +6,6 @@
 
 // Variables used during the symbol resolution phase.
 static Scope*       curr_scope    = NULL;
-bh_arr(AstBlock *)  block_stack   = NULL;
 static b32 report_unresolved_symbols = 1;
 
 // Everything related to waiting on is imcomplete at the moment.
@@ -57,6 +56,7 @@ static SymresStatus symres_memres_type(AstMemRes** memres);
 static SymresStatus symres_memres(AstMemRes** memres);
 static SymresStatus symres_struct_defaults(AstType* st);
 static SymresStatus symres_static_if(AstIf* static_if);
+static SymresStatus symres_macro(AstMacro* macro);
 
 static void scope_enter(Scope* new_scope) {
     curr_scope = new_scope;
@@ -524,6 +524,7 @@ static SymresStatus symres_if(AstIfWhile* ifnode) {
 
         SYMRES(expression, &ifnode->cond);
 
+        // NOTE: These are statements because "elseif" means the `false_stmt` has an if node.
         if (ifnode->true_stmt != NULL)  SYMRES(statement, (AstNode **) &ifnode->true_stmt, NULL);
         if (ifnode->false_stmt != NULL) SYMRES(statement, (AstNode **) &ifnode->false_stmt, NULL);
 
@@ -819,20 +820,22 @@ static SymresStatus symres_statement_chain(AstNode** walker) {
 }
 
 static SymresStatus symres_block(AstBlock* block) {
-    if (block->scope == NULL)
-        block->scope = scope_create(context.ast_alloc, curr_scope, block->token->pos);
+    if (block->rules & Block_Rule_New_Scope) {
+        if (block->scope == NULL)
+            block->scope = scope_create(context.ast_alloc, curr_scope, block->token->pos);
 
-    scope_enter(block->scope);
-    bh_arr_push(block_stack, block);
+        scope_enter(block->scope);
+    }
 
     if (block->binding_scope != NULL)
-        scope_include(block->scope, block->binding_scope, block->token->pos);
+        scope_include(curr_scope, block->binding_scope, block->token->pos);
 
     if (block->body)
         SYMRES(statement_chain, &block->body);
 
-    bh_arr_pop(block_stack);
-    scope_leave();
+    if (block->rules & Block_Rule_New_Scope)
+        scope_leave();
+
     return Symres_Success;
 }
 
@@ -1151,9 +1154,15 @@ static SymresStatus symres_process_directive(AstNode* directive) {
     return Symres_Success;
 }
 
-void symres_entity(Entity* ent) {
-    if (block_stack == NULL) bh_arr_new(global_heap_allocator, block_stack, 16);
+static SymresStatus symres_macro(AstMacro* macro) {
+    if (macro->body->kind == Ast_Kind_Function) {
+        SYMRES(function_header, (AstFunction *) macro->body);
+    }
 
+    return Symres_Success;
+}
+
+void symres_entity(Entity* ent) {
     Scope* old_scope = NULL;
     if (ent->scope) {
         old_scope = curr_scope;
@@ -1198,8 +1207,8 @@ void symres_entity(Entity* ent) {
         case Entity_Type_Polymorphic_Proc:        ss = symres_polyproc(ent->poly_proc); break;
         case Entity_Type_String_Literal:          ss = symres_expression(&ent->expr); break;
         case Entity_Type_Struct_Member_Default:   ss = symres_struct_defaults((AstType *) ent->type_alias); break;
-        case Entity_Type_Process_Directive:       ss = symres_process_directive((AstNode *) ent->expr);
-                                                  break;
+        case Entity_Type_Process_Directive:       ss = symres_process_directive((AstNode *) ent->expr); break;
+        case Entity_Type_Macro:                   ss = symres_macro(ent->macro); break;
 
         default: break;
     }
index beedd9d96fc413f474c6fd22b22217fe9c1dfd0e..3f048d315d1226ae82ff885c217a894dbe2fc861 100644 (file)
@@ -921,7 +921,6 @@ AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
         AstPolyProc* new_pp = onyx_ast_node_new(context.ast_alloc, sizeof(AstPolyProc), Ast_Kind_Polymorphic_Proc);
         new_pp->token = pp->token;                            // TODO: Change this to be the solidify->token
         new_pp->base_func = pp->base_func;
-        new_pp->poly_scope = new_pp->poly_scope; // CLEANUP: This doesn't seem correct??
         new_pp->flags = pp->flags;
         new_pp->poly_params = pp->poly_params;
 
index 0bc1cb45bb08916c0e0de36023bff7c24f612bb2..1114c59c78ed9113446505d097c81e6f13dc3b85 100644 (file)
@@ -280,6 +280,8 @@ EMIT_FUNC(function_body, AstFunction* fd) {
 EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) {
     bh_arr(WasmInstruction) code = *pcode;
 
+    generate_block_headers = generate_block_headers && (block->rules & Block_Rule_New_Scope);
+
     if (generate_block_headers)
         emit_enter_structured_block(mod, &code, SBT_Breakable_Block);
 
@@ -287,8 +289,8 @@ EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) {
         emit_statement(mod, &code, stmt);
     }
 
-    emit_deferred_stmts(mod, &code);
-    emit_free_local_allocations(mod, &code);
+    if (block->rules & Block_Rule_Clear_Defer) emit_deferred_stmts(mod, &code);
+    if (block->rules & Block_Rule_New_Scope)   emit_free_local_allocations(mod, &code);
 
     if (generate_block_headers)
         emit_leave_structured_block(mod, &code);
@@ -1200,7 +1202,7 @@ EMIT_FUNC_NO_ARGS(deferred_stmts) {
 
     u64 depth = bh_arr_length(mod->structured_jump_target);
 
-    while (bh_arr_length(mod->deferred_stmts) > 0 && bh_arr_last(mod->deferred_stmts).depth == depth) {
+    while (bh_arr_length(mod->deferred_stmts) > 0 && bh_arr_last(mod->deferred_stmts).depth >= depth) {
         emit_deferred_stmt(mod, pcode, bh_arr_last(mod->deferred_stmts));
         bh_arr_pop(mod->deferred_stmts);
     }