From: Brendan Hansen Date: Mon, 22 Jun 2020 16:54:34 +0000 (-0500) Subject: Splitting up code for easier maintainability X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=23ac46e9723b6eb11d1fbc885a814ecd05a8118e;p=onyx.git Splitting up code for easier maintainability --- diff --git a/Makefile b/Makefile index bf09e282..817e8f10 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ OBJ_FILES=\ build/onyxlex.o \ build/onyxparser.o \ build/onyxsempass.o \ + build/onyxsymres.o \ build/onyxmsgs.o \ build/onyxutils.o \ build/onyxwasm.o \ diff --git a/include/onyxsempass.h b/include/onyxsempass.h index fc5f4eca..c2e6bcf7 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -23,6 +23,10 @@ typedef struct OnyxSemPassState { bh_table(SemPassSymbol *) symbols; } OnyxSemPassState; +// NOTE: Resolving all symbols in the tree +void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node); + +// NOTE: Full semantic pass OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs); void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node); diff --git a/onyx b/onyx index 8ad5333c..dc020938 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/new_minimal.onyx b/progs/new_minimal.onyx index 55cb5174..3114932b 100644 --- a/progs/new_minimal.onyx +++ b/progs/new_minimal.onyx @@ -6,9 +6,13 @@ diff_square :: proc (a i32, b i32) -> i32 { d :: a + b; // Constant { - c : i32 = a * 2; + c : i32 = a * 2 + foo(5, 2); d : i32 = (c + a) * 2; } return c * d; } + +foo :: proc (a i32, b i32) -> i32 { + return a * 5 + b * 7; +} diff --git a/src/onyxsempass.c b/src/onyxsempass.c index dd2568be..7a36627e 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -17,296 +17,6 @@ OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc return state; } -static void symbol_introduce(OnyxSemPassState* state, OnyxAstNode* symbol); -static void symbol_remove(OnyxSemPassState* state, OnyxAstNode* symbol); -static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol); -static void scope_enter(OnyxSemPassState* state, OnyxAstNodeScope* scope); -static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state); -static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func); -static void symres_local(OnyxSemPassState* state, OnyxAstNodeLocal** local); -static void symres_call(OnyxSemPassState* state, OnyxAstNode* call); -static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr); -static void symres_assignment(OnyxSemPassState* state, OnyxAstNode* assign); -static void symres_return(OnyxSemPassState* state, OnyxAstNode* ret); -static void symres_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode); -static void symres_statement_chain(OnyxSemPassState* state, OnyxAstNode* walker, OnyxAstNode** trailer); -static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt); -static void symres_block(OnyxSemPassState* state, OnyxAstNodeBlock* block); -static void symres_function_definition(OnyxSemPassState* state, OnyxAstNodeFuncDef* func); - -static void symbol_introduce(OnyxSemPassState* state, OnyxAstNode* symbol) { - onyx_token_null_toggle(*symbol->token); - - SemPassSymbol* sp_sym = (SemPassSymbol *) bh_alloc_item(state->allocator, SemPassSymbol); - sp_sym->node = symbol; - sp_sym->shadowed = NULL; - - if (bh_table_has(SemPassSymbol *, state->symbols, symbol->token->token)) { - sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); - } - - bh_table_put(SemPassSymbol *, state->symbols, symbol->token->token, sp_sym); - - if (symbol->kind == ONYX_AST_NODE_KIND_LOCAL) { - OnyxAstNodeLocal* local = &symbol->as_local; - local->prev_local = state->curr_scope->last_local; - state->curr_scope->last_local = local; - } - - onyx_token_null_toggle(*symbol->token); -} - -static void symbol_remove(OnyxSemPassState* state, OnyxAstNode* symbol) { - onyx_token_null_toggle(*symbol->token); - - SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); - - if (sp_sym->shadowed) { - bh_table_put(SemPassSymbol *, state->symbols, symbol->token->token, sp_sym->shadowed); - } else { - bh_table_delete(SemPassSymbol *, state->symbols, symbol->token->token); - } - - onyx_token_null_toggle(*symbol->token); -} - -static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol) { - onyx_token_null_toggle(*symbol->token); - - if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->token)) { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL, - symbol->token->pos, - symbol->token->token); - - onyx_token_null_toggle(*symbol->token); - return NULL; - } - - SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); - - onyx_token_null_toggle(*symbol->token); - return sp_sym->node; -} - -static void scope_enter(OnyxSemPassState* state, OnyxAstNodeScope* scope) { - scope->prev_scope = state->curr_scope; - state->curr_scope = scope; -} - -static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state) { - // NOTE: Can't leave a scope if there is no scope - assert(state->curr_scope != NULL); - - for (OnyxAstNodeLocal *walker = state->curr_scope->last_local; walker != NULL; walker = walker->prev_local) { - symbol_remove(state, (OnyxAstNode *) walker); - } - - state->curr_scope = state->curr_scope->prev_scope; - return state->curr_scope; -} - -static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) { - onyx_token_null_toggle(*func->token); - - // NOTE: If the function hasn't already been defined - if (!bh_table_has(SemPassSymbol *, state->symbols, func->token->token)) { - SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol); - sp_sym->node = (OnyxAstNode *) func; - sp_sym->shadowed = NULL; - bh_table_put(SemPassSymbol *, state->symbols, func->token->token, sp_sym); - } else { - onyx_message_add(state->msgs, - ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, - func->token->pos, - func->token->token); - - // NOTE: I really wish C had defer... - onyx_token_null_toggle(*func->token); - return 0; - } - - onyx_token_null_toggle(*func->token); - return 1; -} - -static void symres_local(OnyxSemPassState* state, OnyxAstNodeLocal** local) { - symbol_introduce(state, (OnyxAstNode *) *local); -} - -static void symres_call(OnyxSemPassState* state, OnyxAstNode* stmt) { - OnyxAstNodeCall* call = &stmt->as_call; - - OnyxAstNode* callee = symbol_resolve(state, call->callee); - if (callee) call->callee = callee; - else DEBUG_HERE; - - symres_statement_chain(state, call->arguments, &call->arguments); -} - -static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr) { - switch ((*expr)->kind) { - case ONYX_AST_NODE_KIND_ADD: - case ONYX_AST_NODE_KIND_MINUS: - case ONYX_AST_NODE_KIND_MULTIPLY: - case ONYX_AST_NODE_KIND_DIVIDE: - case ONYX_AST_NODE_KIND_MODULUS: - case ONYX_AST_NODE_KIND_EQUAL: - case ONYX_AST_NODE_KIND_NOT_EQUAL: - case ONYX_AST_NODE_KIND_LESS: - case ONYX_AST_NODE_KIND_LESS_EQUAL: - case ONYX_AST_NODE_KIND_GREATER: - case ONYX_AST_NODE_KIND_GREATER_EQUAL: - symres_expression(state, &(*expr)->left); - symres_expression(state, &(*expr)->right); - break; - - case ONYX_AST_NODE_KIND_NEGATE: - symres_expression(state, &(*expr)->left); - break; - - case ONYX_AST_NODE_KIND_CAST: - if ((*expr)->type == NULL) { - DEBUG_HERE; - return; - } - symres_expression(state, &(*expr)->left); - break; - - case ONYX_AST_NODE_KIND_CALL: symres_call(state, *expr); break; - - case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &(*expr)->as_block); - - case ONYX_AST_NODE_KIND_SYMBOL: - *expr = symbol_resolve(state, *expr); - break; - - // NOTE: This is a good case, since it means the symbol is already resolved - case ONYX_AST_NODE_KIND_LOCAL: break; - - case ONYX_AST_NODE_KIND_LITERAL: break; - - default: - DEBUG_HERE; - break; - } -} - -static void symres_assignment(OnyxSemPassState* state, OnyxAstNode* assign) { - OnyxAstNode* lval = symbol_resolve(state, assign->left); - if (lval == NULL) return; - assign->left = lval; - - symres_expression(state, &assign->right); -} - -static void symres_return(OnyxSemPassState* state, OnyxAstNode* ret) { - if (ret->left) - symres_expression(state, &ret->left); -} - -static void symres_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode) { - symres_expression(state, &ifnode->cond); - if (ifnode->true_block) { - if (ifnode->true_block->kind == ONYX_AST_NODE_KIND_BLOCK) - symres_block(state, &ifnode->true_block->as_block); - - else if (ifnode->true_block->kind == ONYX_AST_NODE_KIND_IF) - symres_if(state, &ifnode->true_block->as_if); - - else DEBUG_HERE; - } - - if (ifnode->false_block) { - if (ifnode->false_block->kind == ONYX_AST_NODE_KIND_BLOCK) - symres_block(state, &ifnode->false_block->as_block); - - else if (ifnode->false_block->kind == ONYX_AST_NODE_KIND_IF) - symres_if(state, &ifnode->false_block->as_if); - - else DEBUG_HERE; - } -} - -// NOTE: Returns 1 if the statment should be removed -static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt) { - switch (stmt->kind) { - case ONYX_AST_NODE_KIND_LOCAL: symres_local(state, (OnyxAstNodeLocal **) &stmt); return 1; - case ONYX_AST_NODE_KIND_ASSIGNMENT: symres_assignment(state, stmt); return 0; - case ONYX_AST_NODE_KIND_RETURN: symres_return(state, stmt); return 0; - case ONYX_AST_NODE_KIND_IF: symres_if(state, &stmt->as_if); return 0; - case ONYX_AST_NODE_KIND_CALL: symres_call(state, stmt); return 0; - case ONYX_AST_NODE_KIND_ARGUMENT: symres_expression(state, (OnyxAstNode **) &stmt->left); return 0; - case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &stmt->as_block); return 0; - - default: return 0; - } -} - -static void symres_statement_chain(OnyxSemPassState* state, OnyxAstNode* walker, OnyxAstNode** trailer) { - while (walker) { - if (symres_statement(state, walker)) { - *trailer = walker->next; - - OnyxAstNode* tmp = walker->next; - walker->next = NULL; - walker = tmp; - } else { - trailer = &walker->next; - walker = walker->next; - } - } -} - -static void symres_block(OnyxSemPassState* state, OnyxAstNodeBlock* block) { - scope_enter(state, block->scope); - if (block->body) - symres_statement_chain(state, block->body, &block->body); - scope_leave(state); -} - -static void symres_function_definition(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) { - forll(OnyxAstNodeParam, param, func->params, next) { - symbol_introduce(state, (OnyxAstNode *) param); - } - - symres_block(state, func->body); - - forll(OnyxAstNodeParam, param, func->params, next) { - symbol_remove(state, (OnyxAstNode *) param); - } -} - void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node) { - OnyxAstNode* walker = root_node; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - if (!define_function(state, &walker->as_funcdef)) return; - break; - - case ONYX_AST_NODE_KIND_FOREIGN: - if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - if (!define_function(state, &walker->as_foreign.import->as_funcdef)) return; - } - break; - - default: break; - } - - walker = walker->next; - } - - // NOTE: First, resolve all symbols - walker = root_node; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - symres_function_definition(state, &walker->as_funcdef); - break; - default: break; - } - - walker = walker->next; - } + onyx_resolve_symbols(state, root_node); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c new file mode 100644 index 00000000..edccbecf --- /dev/null +++ b/src/onyxsymres.c @@ -0,0 +1,296 @@ +#define BH_DEBUG +#include "onyxsempass.h" + +static void symbol_introduce(OnyxSemPassState* state, OnyxAstNode* symbol); +static void symbol_remove(OnyxSemPassState* state, OnyxAstNode* symbol); +static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol); +static void scope_enter(OnyxSemPassState* state, OnyxAstNodeScope* scope); +static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state); +static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func); +static void symres_local(OnyxSemPassState* state, OnyxAstNodeLocal** local); +static void symres_call(OnyxSemPassState* state, OnyxAstNode* call); +static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr); +static void symres_assignment(OnyxSemPassState* state, OnyxAstNode* assign); +static void symres_return(OnyxSemPassState* state, OnyxAstNode* ret); +static void symres_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode); +static void symres_statement_chain(OnyxSemPassState* state, OnyxAstNode* walker, OnyxAstNode** trailer); +static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt); +static void symres_block(OnyxSemPassState* state, OnyxAstNodeBlock* block); +static void symres_function_definition(OnyxSemPassState* state, OnyxAstNodeFuncDef* func); + +static void symbol_introduce(OnyxSemPassState* state, OnyxAstNode* symbol) { + onyx_token_null_toggle(*symbol->token); + + SemPassSymbol* sp_sym = (SemPassSymbol *) bh_alloc_item(state->allocator, SemPassSymbol); + sp_sym->node = symbol; + sp_sym->shadowed = NULL; + + if (bh_table_has(SemPassSymbol *, state->symbols, symbol->token->token)) { + sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); + } + + bh_table_put(SemPassSymbol *, state->symbols, symbol->token->token, sp_sym); + + if (symbol->kind == ONYX_AST_NODE_KIND_LOCAL) { + OnyxAstNodeLocal* local = &symbol->as_local; + local->prev_local = state->curr_scope->last_local; + state->curr_scope->last_local = local; + } + + onyx_token_null_toggle(*symbol->token); +} + +static void symbol_remove(OnyxSemPassState* state, OnyxAstNode* symbol) { + onyx_token_null_toggle(*symbol->token); + + SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); + + if (sp_sym->shadowed) { + bh_table_put(SemPassSymbol *, state->symbols, symbol->token->token, sp_sym->shadowed); + } else { + bh_table_delete(SemPassSymbol *, state->symbols, symbol->token->token); + } + + onyx_token_null_toggle(*symbol->token); +} + +static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol) { + onyx_token_null_toggle(*symbol->token); + + if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->token)) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL, + symbol->token->pos, + symbol->token->token); + + onyx_token_null_toggle(*symbol->token); + return NULL; + } + + SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->token); + + onyx_token_null_toggle(*symbol->token); + return sp_sym->node; +} + +static void scope_enter(OnyxSemPassState* state, OnyxAstNodeScope* scope) { + scope->prev_scope = state->curr_scope; + state->curr_scope = scope; +} + +static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state) { + // NOTE: Can't leave a scope if there is no scope + assert(state->curr_scope != NULL); + + for (OnyxAstNodeLocal *walker = state->curr_scope->last_local; walker != NULL; walker = walker->prev_local) { + symbol_remove(state, (OnyxAstNode *) walker); + } + + state->curr_scope = state->curr_scope->prev_scope; + return state->curr_scope; +} + +static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) { + onyx_token_null_toggle(*func->token); + + // NOTE: If the function hasn't already been defined + if (!bh_table_has(SemPassSymbol *, state->symbols, func->token->token)) { + SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol); + sp_sym->node = (OnyxAstNode *) func; + sp_sym->shadowed = NULL; + bh_table_put(SemPassSymbol *, state->symbols, func->token->token, sp_sym); + } else { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, + func->token->pos, + func->token->token); + + // NOTE: I really wish C had defer... + onyx_token_null_toggle(*func->token); + return 0; + } + + onyx_token_null_toggle(*func->token); + return 1; +} + +static void symres_local(OnyxSemPassState* state, OnyxAstNodeLocal** local) { + symbol_introduce(state, (OnyxAstNode *) *local); +} + +static void symres_call(OnyxSemPassState* state, OnyxAstNode* stmt) { + OnyxAstNodeCall* call = &stmt->as_call; + + OnyxAstNode* callee = symbol_resolve(state, call->callee); + if (callee) call->callee = callee; + else DEBUG_HERE; + + symres_statement_chain(state, call->arguments, &call->arguments); +} + +static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr) { + switch ((*expr)->kind) { + case ONYX_AST_NODE_KIND_ADD: + case ONYX_AST_NODE_KIND_MINUS: + case ONYX_AST_NODE_KIND_MULTIPLY: + case ONYX_AST_NODE_KIND_DIVIDE: + case ONYX_AST_NODE_KIND_MODULUS: + case ONYX_AST_NODE_KIND_EQUAL: + case ONYX_AST_NODE_KIND_NOT_EQUAL: + case ONYX_AST_NODE_KIND_LESS: + case ONYX_AST_NODE_KIND_LESS_EQUAL: + case ONYX_AST_NODE_KIND_GREATER: + case ONYX_AST_NODE_KIND_GREATER_EQUAL: + symres_expression(state, &(*expr)->left); + symres_expression(state, &(*expr)->right); + break; + + case ONYX_AST_NODE_KIND_NEGATE: + symres_expression(state, &(*expr)->left); + break; + + case ONYX_AST_NODE_KIND_CAST: + if ((*expr)->type == NULL) { + DEBUG_HERE; + return; + } + symres_expression(state, &(*expr)->left); + break; + + case ONYX_AST_NODE_KIND_CALL: symres_call(state, *expr); break; + + case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &(*expr)->as_block); + + case ONYX_AST_NODE_KIND_SYMBOL: + *expr = symbol_resolve(state, *expr); + break; + + // NOTE: This is a good case, since it means the symbol is already resolved + case ONYX_AST_NODE_KIND_LOCAL: break; + + case ONYX_AST_NODE_KIND_LITERAL: break; + + default: + DEBUG_HERE; + break; + } +} + +static void symres_assignment(OnyxSemPassState* state, OnyxAstNode* assign) { + OnyxAstNode* lval = symbol_resolve(state, assign->left); + if (lval == NULL) return; + assign->left = lval; + + symres_expression(state, &assign->right); +} + +static void symres_return(OnyxSemPassState* state, OnyxAstNode* ret) { + if (ret->left) + symres_expression(state, &ret->left); +} + +static void symres_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode) { + symres_expression(state, &ifnode->cond); + if (ifnode->true_block) { + if (ifnode->true_block->kind == ONYX_AST_NODE_KIND_BLOCK) + symres_block(state, &ifnode->true_block->as_block); + + else if (ifnode->true_block->kind == ONYX_AST_NODE_KIND_IF) + symres_if(state, &ifnode->true_block->as_if); + + else DEBUG_HERE; + } + + if (ifnode->false_block) { + if (ifnode->false_block->kind == ONYX_AST_NODE_KIND_BLOCK) + symres_block(state, &ifnode->false_block->as_block); + + else if (ifnode->false_block->kind == ONYX_AST_NODE_KIND_IF) + symres_if(state, &ifnode->false_block->as_if); + + else DEBUG_HERE; + } +} + +// NOTE: Returns 1 if the statment should be removed +static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt) { + switch (stmt->kind) { + case ONYX_AST_NODE_KIND_LOCAL: symres_local(state, (OnyxAstNodeLocal **) &stmt); return 1; + case ONYX_AST_NODE_KIND_ASSIGNMENT: symres_assignment(state, stmt); return 0; + case ONYX_AST_NODE_KIND_RETURN: symres_return(state, stmt); return 0; + case ONYX_AST_NODE_KIND_IF: symres_if(state, &stmt->as_if); return 0; + case ONYX_AST_NODE_KIND_CALL: symres_call(state, stmt); return 0; + case ONYX_AST_NODE_KIND_ARGUMENT: symres_expression(state, (OnyxAstNode **) &stmt->left); return 0; + case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &stmt->as_block); return 0; + + default: return 0; + } +} + +static void symres_statement_chain(OnyxSemPassState* state, OnyxAstNode* walker, OnyxAstNode** trailer) { + while (walker) { + if (symres_statement(state, walker)) { + *trailer = walker->next; + + OnyxAstNode* tmp = walker->next; + walker->next = NULL; + walker = tmp; + } else { + trailer = &walker->next; + walker = walker->next; + } + } +} + +static void symres_block(OnyxSemPassState* state, OnyxAstNodeBlock* block) { + scope_enter(state, block->scope); + if (block->body) + symres_statement_chain(state, block->body, &block->body); + scope_leave(state); +} + +static void symres_function_definition(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) { + forll(OnyxAstNodeParam, param, func->params, next) { + symbol_introduce(state, (OnyxAstNode *) param); + } + + symres_block(state, func->body); + + forll(OnyxAstNodeParam, param, func->params, next) { + symbol_remove(state, (OnyxAstNode *) param); + } +} + +void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node) { + OnyxAstNode* walker = root_node; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + if (!define_function(state, &walker->as_funcdef)) return; + break; + + case ONYX_AST_NODE_KIND_FOREIGN: + if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + if (!define_function(state, &walker->as_foreign.import->as_funcdef)) return; + } + break; + + default: break; + } + + walker = walker->next; + } + + // NOTE: First, resolve all symbols + walker = root_node; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + symres_function_definition(state, &walker->as_funcdef); + break; + default: break; + } + + walker = walker->next; + } +}