From: Brendan Hansen Date: Thu, 16 Jul 2020 00:27:48 +0000 (-0500) Subject: MAJOR CHANGES TO THE LANGUAGE X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2a0c9b18927812692cda8d84af71a736c0c64663;p=onyx.git MAJOR CHANGES TO THE LANGUAGE Removed some keywords and changed the way somethings work --- diff --git a/docs/thoughts b/docs/thoughts index 639488db..b9402481 100644 --- a/docs/thoughts +++ b/docs/thoughts @@ -1,18 +1,104 @@ -Memory design: - - Pointers will work very similar to how they do in C - - A pointer is a u32 - - Pointers will be notated: - ^u32 <- Pointer to u32 - - - Pointer operations will be: - * will take the address of a value - - This operation will not be defined well for a while - - You can't take the address of a local since it doesn't exist in memory - - << will take the value out of a pointer - - Example use: - {{{ - ptr: ^i32 = 0; // Address starting at 0 - ptr_ptr := ^ptr; - }}} +Memory design: + - Pointers will work very similar to how they do in C + - A pointer is a u32 + - Pointers will be notated: + ^u32 <- Pointer to u32 + + - Pointer operations will be: + * will take the address of a value + - This operation will not be defined well for a while + - You can't take the address of a local since it doesn't exist in memory + + << will take the value out of a pointer + + Example use: + {{{ + ptr: ^i32 = 0; // Address starting at 0 + ptr_ptr := ^ptr; + }}} + + + + + +Treating top level declarations differently: + Currently, top level declarations are treated special, as they would correspond to + the structure of the WASM that would be generated. For example, + + inc :: proc (a: i32) -> i32 { return a + 1; } + + would be turned into an AstFunction node with a token of 'inc', and, + + global :: 5 + + would be turned into a AstGlobal node with a token of 'global'. + + The problem I have with this approach is it creates an inconsistency when thinking + about what is going on in the various stages in the compiler. + + A better approach would be to have a AstBinding node, that represents a binding + from a symbol, stored on the token member, to another Ast Node. The node definition + would be: + + struct AstBinding { AstTyped base; AstNode* node; } + + For a function definition such as 'inc' above, the node structure would look like: + + AstBinding (inc) + .node -> AstFunction + .params -> AstLocal (a) -> NULL + .body -> ... + + This way, in symbol resolution, the top level bindings are added to the table and + there are no special cases. + + Other nuances: + + global :: 5 - This would replace all instances of 'global' with the integer constant + 5. This would not make a global in WASM. + + global := 5 - This would work as expected but will make generating the WASM more difficult. + This feature may wait to come back. + + global :: i32 - This would work as a type alias. 'global' would have the type node as it's 'node' + + print :: proc #foriegn "host" "print" (...) --- + + +Explicit overriden functions: + Considered syntax: + + foo_i32 :: proc (val: i32) -> i32 --- + foo_i64 :: proc (val: i64) -> i64 --- + foo_f32 :: proc (val: f32) -> f32 --- + foo_f64 :: proc (val: f64) -> f64 --- + + foo :: proc #overload { + foo_i32, foo_i64, foo_f32, foo_f64 + } + + foo(10); // calls foo_i32 + foo(2.0f); // calls foo_f32 + + + min_f32 :: proc #intrinsic (a: f32, b:f32) -> f32 --- + min_f64 :: proc #intrinsic (a: f64, b:f64) -> f64 --- + + min_i32 :: proc (a: i32, b: i32) -> i32 { + least := a; + if b < a { least = b; } + + return least; + } + + min_i64 :: proc (a: i64, b: i64) -> i64 { + least := a; + if b < a { least = b; } + + return least; + } + + min :: proc #overload { min_i32, min_i64, min_f32, min_f64 } + + min(2, 5); + min(4.5, 10.4); diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index a39b876c..ba6fe398 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -11,28 +11,33 @@ typedef struct AstBinOp AstBinaryOp; typedef struct AstAssign AstAssign; typedef struct AstNumLit AstNumLit; typedef struct AstLocal AstLocal; -typedef struct AstLocalGroup AstLocalGroup; typedef struct AstReturn AstReturn; -typedef struct AstBlock AstBlock; -typedef struct AstIf AstIf; -typedef struct AstWhile AstWhile; -typedef struct AstFunction AstFunction; -typedef struct AstForeign AstForeign; -typedef struct AstGlobal AstGlobal; typedef struct AstCall AstCall; typedef struct AstIntrinsicCall AstIntrinsicCall; typedef struct AstArgument AstArgument; -typedef struct AstUse AstUse; + +typedef struct AstBlock AstBlock; +typedef struct AstIf AstIf; +typedef struct AstWhile AstWhile; +typedef struct AstLocalGroup AstLocalGroup; typedef struct AstType AstType; typedef struct AstBasicType AstBasicType; typedef struct AstPointerType AstPointerType; +typedef struct AstFunctionType AstFunctionType; + +typedef struct AstBinding AstBinding; +typedef struct AstFunction AstFunction; +typedef struct AstForeign AstForeign; +typedef struct AstGlobal AstGlobal; +typedef struct AstUse AstUse; typedef enum AstKind { Ast_Kind_Error, Ast_Kind_Program, Ast_Kind_Use, + Ast_Kind_Binding, Ast_Kind_Function, Ast_Kind_Foreign, Ast_Kind_Block, @@ -44,9 +49,12 @@ typedef enum AstKind { Ast_Kind_Unary_Op, Ast_Kind_Binary_Op, + Ast_Kind_Type_Start, Ast_Kind_Type, Ast_Kind_Basic_Type, Ast_Kind_Pointer_Type, + Ast_Kind_Function_Type, + Ast_Kind_Type_End, Ast_Kind_Literal, Ast_Kind_Param, @@ -76,6 +84,7 @@ typedef enum AstFlags { // Function flags Ast_Flag_Inline = BH_BIT(8), Ast_Flag_Intrinsic = BH_BIT(9), + Ast_Flag_Foreign = BH_BIT(10), } AstFlags; typedef enum UnaryOp { @@ -137,10 +146,10 @@ struct AstTyped { // Expression Nodes struct AstBinOp { AstTyped base; BinaryOp operation; AstTyped *left, *right; }; struct AstUnaryOp { AstTyped base; UnaryOp operation; AstTyped *expr; }; -struct AstAssign { AstNode base; AstTyped* lval; AstTyped* expr; }; +struct AstAssign { AstNode base; AstTyped* lval; AstTyped* expr; }; struct AstNumLit { AstTyped base; union { i32 i; i64 l; f32 f; f64 d; } value; }; struct AstLocal { AstTyped base; AstLocal *prev_local; }; -struct AstReturn { AstNode base; AstTyped* expr; }; +struct AstReturn { AstNode base; AstTyped* expr; }; struct AstCall { AstTyped base; AstArgument *arguments; AstNode *callee; }; struct AstArgument { AstTyped base; AstTyped *value; }; @@ -166,12 +175,26 @@ struct AstIf { struct AstType { AstKind kind; u32 flags; char* name; }; struct AstBasicType { AstType base; Type* type; }; struct AstPointerType { AstType base; AstType* elem; }; +struct AstFunctionType { AstType base; bh_arr(AstType *) params; AstType* results; }; // Top level nodes -struct AstFunction { AstTyped base; AstBlock *body; AstLocal *params; }; -struct AstForeign { AstNode base; OnyxToken *mod_token, *name_token; AstNode *import; }; +struct AstBinding { AstTyped base; AstNode* node; }; +struct AstForeign { AstNode base; OnyxToken *mod_token, *name_token; AstNode *import; }; struct AstGlobal { AstTyped base; AstTyped *initial_value; }; -struct AstUse { AstNode base; OnyxToken *filename; }; +struct AstUse { AstNode base; OnyxToken *filename; }; +struct AstFunction { + AstTyped base; + + AstBlock *body; + AstLocal *params; + + // NOTE: Used when a function is exported with a specific name + char* exported_name; + + // NOTE: Used when the function is declared as foreign + OnyxToken* foreign_module; + OnyxToken* foreign_name; +}; typedef enum OnyxIntrinsic { ONYX_INTRINSIC_UNDEFINED, @@ -206,9 +229,10 @@ typedef enum OnyxIntrinsic { struct AstIntrinsicCall { AstTyped base; AstArgument *arguments; OnyxIntrinsic intrinsic; }; typedef struct OnyxProgram { - bh_arr(AstGlobal *) globals; + bh_arr(AstBinding *) top_level_bindings; + bh_arr(AstNode *) nodes_to_process; + bh_arr(AstFunction *) functions; - bh_arr(AstForeign *) foreigns; } OnyxProgram; diff --git a/include/onyxparser.h b/include/onyxparser.h index fbf30cbb..fba6bfaf 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -7,20 +7,34 @@ #include "onyxmsgs.h" #include "onyxastnodes.h" +typedef struct ParseResults { + // NOTE: The allocator used to make the arrays below + bh_allocator allocator; + + bh_arr(AstUse *) uses; + bh_arr(AstBinding *) bindings; + + // NOTE: Contains all the nodes that will need some processing (symbol resolution, type checking) + bh_arr(AstNode *) nodes_to_process; +} ParseResults; + typedef struct OnyxParser { - OnyxTokenizer *tokenizer; // NOTE: not used since all tokens are lexed before parsing starts + bh_allocator allocator; + + // NOTE: not used since all tokens are lexed before parsing starts + OnyxTokenizer *tokenizer; OnyxToken *prev_token; OnyxToken *curr_token; OnyxMessages *msgs; - bh_allocator allocator; + ParseResults results; } OnyxParser; const char* onyx_ast_node_kind_string(AstKind kind); void* onyx_ast_node_new(bh_allocator alloc, i32 size, AstKind kind); OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs); void onyx_parser_free(OnyxParser* parser); -bh_arr(AstNode *) onyx_parse(OnyxParser *parser); +ParseResults onyx_parse(OnyxParser *parser); #endif // #ifndef ONYXPARSER_H diff --git a/misc/onyx.vim b/misc/onyx.vim index ca189a5e..23ebf5b7 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -10,9 +10,9 @@ endif let s:cpo_save = &cpo set cpo&vim -syn keyword onyxKeyword struct proc use export foreign +syn keyword onyxKeyword struct proc use syn keyword onyxKeyword if elseif else -syn keyword onyxKeyword for while loop return do +syn keyword onyxKeyword for while do syn keyword onyxKeyword break continue return syn keyword onyxKeyword as diff --git a/onyx b/onyx index be28846f..9fb8a4b9 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/basic.onyx b/progs/basic.onyx index d8e5bcb8..e7a0c5f0 100644 --- a/progs/basic.onyx +++ b/progs/basic.onyx @@ -4,7 +4,9 @@ pointer_test :: proc { p := 0 as ^i32; } -print :: foreign "host" "print" proc (val: i32) --- +print :: proc + #foreign "host" "print" + (val: i32) --- test :: proc (a: bool) -> bool { return !a; @@ -16,10 +18,22 @@ foo :: proc (n: i32) -> i32 { return or_i32(a, b); } -export main :: proc { +// THOUGHT: This could be a WASM global that is immutable and it +// would be accessed using global.get +// OR +// This could be immediately substituted in the expression tree. i.e. +// 4 + global => 4 + (5 * 2 + 6) +global :: 5 * 2 + 6 + +// WASM globals would be declared as such: +// wasm_global :: global i32 + +main :: proc #export { a := 16; print(clz_i32(a)); + print(4 + global); + b := 1 + foo(2); print(b); diff --git a/progs/other.onyx b/progs/other.onyx index 7bab1efb..70b9a52e 100644 --- a/progs/other.onyx +++ b/progs/other.onyx @@ -4,7 +4,7 @@ other_value :: proc (n: i32) -> i32 { return 8675309 + something_else(n) + global_value; } -export fib :: proc (n: i32) -> i32 { +fib :: proc #export (n: i32) -> i32 { if n == 0 { return 1; } if n == 1 { return 1; } @@ -24,7 +24,7 @@ export fib :: proc (n: i32) -> i32 { return a; } -export factorial :: proc (n: i32) -> i32 { +factorial :: proc #export (n: i32) -> i32 { if n <= 1 { return 1; } f := 1; diff --git a/progs/print_funcs.onyx b/progs/print_funcs.onyx index bb2a3d60..3ac27828 100644 --- a/progs/print_funcs.onyx +++ b/progs/print_funcs.onyx @@ -1,5 +1,5 @@ -print_bool :: foreign "host" "print" proc (value: bool) --- -print_i32 :: foreign "host" "print" proc (value: i32) --- -print_f32 :: foreign "host" "print" proc (value: f32) --- -print_i64 :: foreign "host" "print" proc (value: i64) --- -print_f64 :: foreign "host" "print" proc (value: f64) --- +print_bool :: proc #foreign "host" "print" (value: bool) --- +print_i32 :: proc #foreign "host" "print" (value: i32) --- +print_f32 :: proc #foreign "host" "print" (value: f32) --- +print_i64 :: proc #foreign "host" "print" (value: i64) --- +print_f64 :: proc #foreign "host" "print" (value: f64) --- diff --git a/progs/test.onyx b/progs/test.onyx index db16c2b9..6214b278 100644 --- a/progs/test.onyx +++ b/progs/test.onyx @@ -6,17 +6,46 @@ something_else :: proc (n: i32) -> i32 { return 100 * n + global_value; } -global_value := 100 - -export in_unit_circle :: proc (x: f32, y: f32) -> bool { +in_unit_circle :: proc #export (x: f32, y: f32) -> bool { return (x * x) + (y * y) < 1.0f; } +echo :: proc (n: i32) -> i32 { + print_i32(n); + return n; +} + +global_value :: echo(fib(4) * 2); + +local_brute :: proc { + + a := 123; + b := 123.0f; + c := 123.0; + + { + a := 5.0f; + b := 12.3; + + print_f32(a); + print_f64(b); + } + + print_i32(a); + print_f32(b); + print_f64(c); +} + +main3 :: proc #export { + local_brute(); +} + + // This is the entry point -export main2 :: proc { +main2 :: proc #export { i := 0; while i < 10 { - res :: fib(i); + res :: clz_i32(fib(i)); print_i32(res); i += 1; } @@ -61,7 +90,7 @@ export main2 :: proc { // z : f32; // } -export main :: proc { +main :: proc #export { print_i32(clz_i32(16)); print_f32(sqrt_f32(2.0f)); @@ -69,10 +98,9 @@ export main :: proc { print_bool(in_unit_circle(0.5f, 0.5f)); big_num := fib(factorial(4)); - something :: other_value(0); - global_value = 1000; - something_else :: other_value(0); + something :: other_value(0); + something_else :: other_value(1); condition := big_num < something; diff --git a/src/onyx.c b/src/onyx.c index 7c2abd82..b7c24e29 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -106,7 +106,7 @@ static void compile_opts_free(OnyxCompileOptions* opts) { bh_arr_free(opts->files); } -static bh_arr(AstNode *) parse_source_file(CompilerState* compiler_state, bh_file_contents* file_contents) { +static ParseResults parse_source_file(CompilerState* compiler_state, bh_file_contents* file_contents) { // NOTE: Maybe don't want to recreate the tokenizer and parser for every file if (compiler_state->options->verbose_output) bh_printf("[Lexing] %s\n", file_contents->filename); @@ -142,35 +142,9 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char* bh_table_put(bh_file_contents, compiler_state->loaded_files, (char *) filename, fc); fc = bh_table_get(bh_file_contents, compiler_state->loaded_files, (char *) filename); - bh_arr(AstNode *) top_nodes = parse_source_file(compiler_state, &fc); + ParseResults results = parse_source_file(compiler_state, &fc); - bh_arr(AstUse *) uses = NULL; - - bh_arr_each(AstNode *, node, top_nodes) { - switch ((*node)->kind) { - case Ast_Kind_Use: - bh_arr_push(uses, (AstUse *) *node); - break; - - case Ast_Kind_Global: - bh_arr_push(compiler_state->program.globals, (AstGlobal *) (*node)); - break; - - case Ast_Kind_Foreign: - bh_arr_push(compiler_state->program.foreigns, (AstForeign *) (*node)); - break; - - case Ast_Kind_Function: - bh_arr_push(compiler_state->program.functions, (AstFunction *) (*node)); - break; - - default: - assert(("Invalid top level node", 0)); - break; - } - } - - bh_arr_each(AstUse *, use_node, uses) { + bh_arr_each(AstUse *, use_node, results.uses) { char* formatted_name = bh_aprintf( global_heap_allocator, "%b.onyx", @@ -179,7 +153,11 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char* bh_arr_push(compiler_state->queued_files, formatted_name); } - bh_arr_free(uses); + bh_arr_each(AstBinding *, binding_node, results.bindings) + bh_arr_push(compiler_state->program.top_level_bindings, *binding_node); + + bh_arr_each(AstNode *, node, results.nodes_to_process) + bh_arr_push(compiler_state->program.nodes_to_process, *node); if (onyx_message_has_errors(&compiler_state->msgs)) { return ONYX_COMPILER_PROGRESS_FAILED_PARSE; @@ -191,8 +169,7 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char* static void compiler_state_init(CompilerState* compiler_state, OnyxCompileOptions* opts) { compiler_state->options = opts; - bh_arr_new(global_heap_allocator, compiler_state->program.foreigns, 4); - bh_arr_new(global_heap_allocator, compiler_state->program.globals, 4); + bh_arr_new(global_heap_allocator, compiler_state->program.top_level_bindings, 4); bh_arr_new(global_heap_allocator, compiler_state->program.functions, 4); bh_arena_init(&compiler_state->msg_arena, opts->allocator, 4096); @@ -289,9 +266,10 @@ int main(int argc, char *argv[]) { OnyxCompileOptions compile_opts = compile_opts_parse(global_heap_allocator, argc, argv); CompilerState compile_state = { .program = { - .foreigns = NULL, - .globals = NULL, - .functions = NULL + .top_level_bindings = NULL, + .nodes_to_process = NULL, + + .functions = NULL, }, .wasm_mod = { 0 } }; diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 531ebd32..365a11c9 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -1,26 +1,26 @@ #define BH_DEBUG #include "onyxsempass.h" -static void check_function(OnyxSemPassState* state, AstFunction* func); -static void check_block(OnyxSemPassState* state, AstBlock* block); -static void check_statement_chain(OnyxSemPassState* state, AstNode* start); -static void check_statement(OnyxSemPassState* state, AstNode* stmt); -static void check_assignment(OnyxSemPassState* state, AstAssign* assign); -static void check_return(OnyxSemPassState* state, AstReturn* retnode); -static void check_if(OnyxSemPassState* state, AstIf* ifnode); -static void check_while(OnyxSemPassState* state, AstWhile* whilenode); -static void check_call(OnyxSemPassState* state, AstCall* call); -static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop); -static void check_expression(OnyxSemPassState* state, AstTyped* expr); -static void check_global(OnyxSemPassState* state, AstGlobal* global); - -static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { +static b32 check_function(OnyxSemPassState* state, AstFunction* func); +static b32 check_block(OnyxSemPassState* state, AstBlock* block); +static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start); +static b32 check_statement(OnyxSemPassState* state, AstNode* stmt); +static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign); +static b32 check_return(OnyxSemPassState* state, AstReturn* retnode); +static b32 check_if(OnyxSemPassState* state, AstIf* ifnode); +static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode); +static b32 check_call(OnyxSemPassState* state, AstCall* call); +static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop); +static b32 check_expression(OnyxSemPassState* state, AstTyped* expr); +static b32 check_global(OnyxSemPassState* state, AstGlobal* global); + +static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign) { if (assign->lval->kind == Ast_Kind_Symbol) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, assign->lval->token->pos, assign->lval->token->text, assign->lval->token->length); - return; + return 1; } if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type != NULL) { @@ -28,7 +28,7 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { ONYX_MESSAGE_TYPE_ASSIGN_CONST, assign->base.token->pos, assign->lval->token->text, assign->lval->token->length); - return; + return 1; } if ((assign->lval->flags & Ast_Flag_Lval) == 0) { @@ -36,14 +36,14 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { ONYX_MESSAGE_TYPE_NOT_LVAL, assign->base.token->pos, assign->lval->token->text, assign->lval->token->length); - return; + return 1; } if (assign->lval->type == NULL) { assign->lval->type = type_build_from_ast(state->node_allocator, assign->lval->type_node); } - check_expression(state, assign->expr); + if (check_expression(state, assign->expr)) return 1; if (assign->lval->type == NULL) { assign->lval->type = assign->expr->type; @@ -54,14 +54,16 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) { assign->base.token->pos, type_get_name(assign->lval->type), type_get_name(assign->expr->type)); - return; + return 1; } } + + return 0; } -static void check_return(OnyxSemPassState* state, AstReturn* retnode) { +static b32 check_return(OnyxSemPassState* state, AstReturn* retnode) { if (retnode->expr) { - check_expression(state, retnode->expr); + if (check_expression(state, retnode->expr)) return 1; if (!types_are_compatible(retnode->expr->type, state->expected_return_type)) { onyx_message_add(state->msgs, @@ -69,6 +71,7 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) { retnode->expr->token->pos, type_get_name(retnode->expr->type), type_get_name(state->expected_return_type)); + return 1; } } else { if (state->expected_return_type->Basic.size > 0) { @@ -76,12 +79,15 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) { ONYX_MESSAGE_TYPE_LITERAL, retnode->base.token->pos, "returning from non-void function without value"); + return 1; } } + + return 0; } -static void check_if(OnyxSemPassState* state, AstIf* ifnode) { - check_expression(state, ifnode->cond); +static b32 check_if(OnyxSemPassState* state, AstIf* ifnode) { + if (check_expression(state, ifnode->cond)) return 1; if (ifnode->cond->type == NULL || ifnode->cond->type->kind != Type_Kind_Basic @@ -91,15 +97,17 @@ static void check_if(OnyxSemPassState* state, AstIf* ifnode) { ONYX_MESSAGE_TYPE_LITERAL, ifnode->cond->token->pos, "expected boolean type for condition"); - return; + return 1; } - if (ifnode->true_block.as_if) check_statement(state, (AstNode *) ifnode->true_block.as_block); - if (ifnode->false_block.as_if) check_statement(state, (AstNode *) ifnode->false_block.as_block); + if (ifnode->true_block.as_if) if (check_statement(state, (AstNode *) ifnode->true_block.as_block)) return 1; + if (ifnode->false_block.as_if) if (check_statement(state, (AstNode *) ifnode->false_block.as_block)) return 1; + + return 0; } -static void check_while(OnyxSemPassState* state, AstWhile* whilenode) { - check_expression(state, whilenode->cond); +static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode) { + if (check_expression(state, whilenode->cond)) return 1; if (whilenode->cond->type == NULL || whilenode->cond->type->kind != Type_Kind_Basic @@ -109,13 +117,13 @@ static void check_while(OnyxSemPassState* state, AstWhile* whilenode) { ONYX_MESSAGE_TYPE_LITERAL, whilenode->cond->token->pos, "expected boolean type for condition"); - return; + return 1; } - check_block(state, whilenode->body); + return check_block(state, whilenode->body); } -static void check_call(OnyxSemPassState* state, AstCall* call) { +static b32 check_call(OnyxSemPassState* state, AstCall* call) { AstFunction* callee = (AstFunction *) call->callee; if (callee->base.kind == Ast_Kind_Symbol) { @@ -123,7 +131,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, callee->base.token->pos, callee->base.token->text, callee->base.token->length); - return; + return 1; } if (callee->base.kind != Ast_Kind_Function) { @@ -131,7 +139,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION, call->base.token->pos, callee->base.token->text, callee->base.token->length); - return; + return 1; } // NOTE: If we calling an intrinsic function, translate the @@ -207,7 +215,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { i32 arg_pos = 0; while (formal_param != NULL && actual_param != NULL) { - check_expression(state, (AstTyped *) actual_param); + if (check_expression(state, (AstTyped *) actual_param)) return 1; if (formal_param->base.type == NULL) { formal_param->base.type = type_build_from_ast(state->node_allocator, formal_param->base.type_node); @@ -221,7 +229,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { type_get_name(formal_param->base.type), arg_pos, type_get_name(actual_param->base.type)); - return; + return 1; } arg_pos++; @@ -234,7 +242,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { ONYX_MESSAGE_TYPE_LITERAL, call->base.token->pos, "too few arguments to function call"); - return; + return 1; } if (formal_param == NULL && actual_param != NULL) { @@ -242,20 +250,22 @@ static void check_call(OnyxSemPassState* state, AstCall* call) { ONYX_MESSAGE_TYPE_LITERAL, call->base.token->pos, "too many arguments to function call"); - return; + return 1; } + + return 0; } -static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { - check_expression(state, binop->left); - check_expression(state, binop->right); +static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { + if (check_expression(state, binop->left)) return 1; + if (check_expression(state, binop->right)) return 1; if (binop->left->type == NULL) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, binop->base.token->pos, NULL, 0); - return; + return 1; } if (binop->right->type == NULL) { @@ -263,7 +273,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, binop->base.token->pos, NULL, 0); - return; + return 1; } if (type_is_pointer(binop->left->type) @@ -272,7 +282,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { ONYX_MESSAGE_TYPE_LITERAL, binop->base.token->pos, "binary operations are not supported for pointers (yet)."); - return; + return 1; } if (!types_are_compatible(binop->left->type, binop->right->type)) { @@ -281,7 +291,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { binop->base.token->pos, type_get_name(binop->left->type), type_get_name(binop->right->type)); - return; + return 1; } if (binop->operation >= Binary_Op_Equal @@ -290,39 +300,44 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) { } else { binop->base.type = binop->left->type; } + + return 0; } -static void check_expression(OnyxSemPassState* state, AstTyped* expr) { +static b32 check_expression(OnyxSemPassState* state, AstTyped* expr) { + if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + (OnyxFilePos) { 0 }, + "type used as part of an expression"); + return 1; + } + if (expr->type == NULL) { expr->type = type_build_from_ast(state->node_allocator, expr->type_node); } + i32 retval = 0; switch (expr->kind) { - case Ast_Kind_Binary_Op: - check_binaryop(state, (AstBinaryOp *) expr); - break; + case Ast_Kind_Binary_Op: retval = check_binaryop(state, (AstBinaryOp *) expr); break; case Ast_Kind_Unary_Op: - check_expression(state, ((AstUnaryOp *) expr)->expr); + retval = check_expression(state, ((AstUnaryOp *) expr)->expr); if (((AstUnaryOp *) expr)->operation != Unary_Op_Cast) { expr->type = ((AstUnaryOp *) expr)->expr->type; } break; - case Ast_Kind_Call: - check_call(state, (AstCall *) expr); - break; - - case Ast_Kind_Block: - check_block(state, (AstBlock *) expr); - break; + case Ast_Kind_Call: retval = check_call(state, (AstCall *) expr); break; + case Ast_Kind_Block: retval = check_block(state, (AstBlock *) expr); break; case Ast_Kind_Symbol: onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL, expr->token->pos, expr->token->text, expr->token->length); + retval = 1; break; case Ast_Kind_Local: @@ -332,6 +347,7 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { ONYX_MESSAGE_TYPE_LITERAL, expr->token->pos, "local variable with unknown type"); + retval = 1; } break; @@ -341,11 +357,12 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { ONYX_MESSAGE_TYPE_LITERAL, expr->token->pos, "global with unknown type"); + retval = 1; } break; case Ast_Kind_Argument: - check_expression(state, ((AstArgument *) expr)->value); + retval = check_expression(state, ((AstArgument *) expr)->value); expr->type = ((AstArgument *) expr)->value->type; break; @@ -356,14 +373,17 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) { break; default: + retval = 1; DEBUG_HERE; break; } + + return retval; } -static void check_global(OnyxSemPassState* state, AstGlobal* global) { +static b32 check_global(OnyxSemPassState* state, AstGlobal* global) { if (global->initial_value) { - check_expression(state, global->initial_value); + if (check_expression(state, global->initial_value)) return 1; if (global->base.type == NULL) { global->base.type = type_build_from_ast(state->node_allocator, global->base.type_node); @@ -377,7 +397,7 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) { global->base.token->text, global->base.token->length, type_get_name(global->base.type), type_get_name(global->initial_value->type)); - return; + return 1; } } else { if (global->initial_value->type) @@ -390,31 +410,36 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) { ONYX_MESSAGE_TYPE_LITERAL, global->base.token->pos, "global variable with unknown type"); + return 1; } + + return 0; } -static void check_statement(OnyxSemPassState* state, AstNode* stmt) { +static b32 check_statement(OnyxSemPassState* state, AstNode* stmt) { switch (stmt->kind) { - case Ast_Kind_Assignment: check_assignment(state, (AstAssign *) stmt); break; - case Ast_Kind_Return: check_return(state, (AstReturn *) stmt); break; - case Ast_Kind_If: check_if(state, (AstIf *) stmt); break; - case Ast_Kind_While: check_while(state, (AstWhile *) stmt); break; - case Ast_Kind_Call: check_call(state, (AstCall *) stmt); break; - case Ast_Kind_Block: check_block(state, (AstBlock *) stmt); break; - - default: break; + case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) stmt); + case Ast_Kind_Return: return check_return(state, (AstReturn *) stmt); + case Ast_Kind_If: return check_if(state, (AstIf *) stmt); + case Ast_Kind_While: return check_while(state, (AstWhile *) stmt); + case Ast_Kind_Call: return check_call(state, (AstCall *) stmt); + case Ast_Kind_Block: return check_block(state, (AstBlock *) stmt); + + default: return 0; } } -static void check_statement_chain(OnyxSemPassState* state, AstNode* start) { +static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start) { while (start) { - check_statement(state, start); + if (check_statement(state, start)) return 1; start = start->next; } + + return 0; } -static void check_block(OnyxSemPassState* state, AstBlock* block) { - check_statement_chain(state, block->body); +static b32 check_block(OnyxSemPassState* state, AstBlock* block) { + if (check_statement_chain(state, block->body)) return 1; forll(AstLocal, local, block->locals->last_local, prev_local) { if (local->base.type == NULL) { @@ -422,12 +447,14 @@ static void check_block(OnyxSemPassState* state, AstBlock* block) { ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE, local->base.token->pos, local->base.token->text, local->base.token->length); - return; + return 1; } } + + return 0; } -static void check_function(OnyxSemPassState* state, AstFunction* func) { +static b32 check_function(OnyxSemPassState* state, AstFunction* func) { for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { if (param->base.type == NULL) { param->base.type = type_build_from_ast(state->node_allocator, param->base.type_node); @@ -438,7 +465,7 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) { ONYX_MESSAGE_TYPE_LITERAL, param->base.token->pos, "function parameter types must be known"); - return; + return 1; } if (param->base.type->Basic.size == 0) { @@ -446,29 +473,80 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) { ONYX_MESSAGE_TYPE_LITERAL, param->base.token->pos, "function parameters must have non-void types"); - return; + return 1; } } + // NOTE: Acutally the return type if (func->base.type == NULL) { func->base.type = type_build_from_ast(state->node_allocator, func->base.type_node); } + if ((func->base.flags & Ast_Flag_Exported) != 0) { + if ((func->base.flags & Ast_Flag_Foreign) != 0) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + func->base.token->pos, + "exporting a foreign function"); + return 1; + } + + if ((func->base.flags & Ast_Flag_Intrinsic) != 0) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + func->base.token->pos, + "exporting a intrinsic function"); + return 1; + } + + if ((func->base.flags & Ast_Flag_Inline) != 0) { + onyx_message_add(state->msgs, + ONYX_MESSAGE_TYPE_LITERAL, + func->base.token->pos, + "exporting a inlined function"); + return 1; + } + } + state->expected_return_type = func->base.type; if (func->body) { - check_block(state, func->body); + return check_block(state, func->body); + } + + return 0; +} + +static b32 check_node(OnyxSemPassState* state, AstNode* node) { + switch (node->kind) { + case Ast_Kind_Function: return check_function(state, (AstFunction *) node); + case Ast_Kind_Block: return check_block(state, (AstBlock *) node); + case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) node); + case Ast_Kind_Return: return check_return(state, (AstReturn *) node); + case Ast_Kind_If: return check_if(state, (AstIf *) node); + case Ast_Kind_While: return check_while(state, (AstWhile *) node); + case Ast_Kind_Call: return check_call(state, (AstCall *) node); + case Ast_Kind_Binary_Op: return check_binaryop(state, (AstBinaryOp *) node); + default: return check_expression(state, (AstTyped *) node); } } void onyx_type_check(OnyxSemPassState* state, OnyxProgram* program) { - bh_arr_each(AstForeign *, foreign, program->foreigns) - if ((*foreign)->import->kind == Ast_Kind_Function) - check_function(state, (AstFunction *) (*foreign)->import); + // bh_arr_each(AstForeign *, foreign, program->foreigns) + // if ((*foreign)->import->kind == Ast_Kind_Function) + // check_function(state, (AstFunction *) (*foreign)->import); - bh_arr_each(AstGlobal *, global, program->globals) - check_global(state, *global); + // bh_arr_each(AstGlobal *, global, program->globals) + // check_global(state, *global); - bh_arr_each(AstFunction *, function, program->functions) - check_function(state, *function); + // bh_arr_each(AstFunction *, function, program->functions) + // check_function(state, *function); + + bh_arr_each(AstNode *, node, program->nodes_to_process) { + check_node(state, *node); + + if ((*node)->kind == Ast_Kind_Function) { + bh_arr_push(program->functions, (AstFunction *) *node); + } + } } diff --git a/src/onyxlex.c b/src/onyxlex.c index 8368a011..6987e51b 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -129,12 +129,12 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) { } LITERAL_TOKEN("struct", 1, Token_Type_Keyword_Struct); - LITERAL_TOKEN("export", 1, Token_Type_Keyword_Export); +// LITERAL_TOKEN("export", 1, Token_Type_Keyword_Export); LITERAL_TOKEN("use", 1, Token_Type_Keyword_Use); LITERAL_TOKEN("if", 1, Token_Type_Keyword_If); LITERAL_TOKEN("elseif", 1, Token_Type_Keyword_Elseif); LITERAL_TOKEN("else", 1, Token_Type_Keyword_Else); - LITERAL_TOKEN("foreign", 1, Token_Type_Keyword_Foreign); + // LITERAL_TOKEN("foreign", 1, Token_Type_Keyword_Foreign); LITERAL_TOKEN("return", 1, Token_Type_Keyword_Return); LITERAL_TOKEN("proc", 1, Token_Type_Keyword_Proc); LITERAL_TOKEN("as", 1, Token_Type_Keyword_Cast); diff --git a/src/onyxparser.c b/src/onyxparser.c index 3a0113ad..c99608b5 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -27,19 +27,20 @@ static void parser_next_token(OnyxParser* parser); static void parser_prev_token(OnyxParser* parser); static b32 is_terminating_token(TokenType token_type); static OnyxToken* expect(OnyxParser* parser, TokenType token_type); -static AstNumLit* parse_numeric_literal(OnyxParser* parser); -static AstTyped* parse_factor(OnyxParser* parser); -static AstTyped* parse_expression(OnyxParser* parser); -static AstIf* parse_if_stmt(OnyxParser* parser); -static AstWhile* parse_while_stmt(OnyxParser* parser); -static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret); -static AstReturn* parse_return_statement(OnyxParser* parser); -static AstBlock* parse_block(OnyxParser* parser); -static AstNode* parse_statement(OnyxParser* parser); -static AstType* parse_type(OnyxParser* parser); -static AstLocal* parse_function_params(OnyxParser* parser); + +static AstNumLit* parse_numeric_literal(OnyxParser* parser); +static AstTyped* parse_factor(OnyxParser* parser); +static AstTyped* parse_expression(OnyxParser* parser); +static AstIf* parse_if_stmt(OnyxParser* parser); +static AstWhile* parse_while_stmt(OnyxParser* parser); +static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret); +static AstReturn* parse_return_statement(OnyxParser* parser); +static AstBlock* parse_block(OnyxParser* parser); +static AstNode* parse_statement(OnyxParser* parser); +static AstType* parse_type(OnyxParser* parser); +static AstLocal* parse_function_params(OnyxParser* parser); static AstFunction* parse_function_definition(OnyxParser* parser); -static AstNode* parse_top_level_statement(OnyxParser* parser); +static AstNode* parse_top_level_statement(OnyxParser* parser); static void parser_next_token(OnyxParser* parser) { parser->prev_token = parser->curr_token; @@ -236,6 +237,16 @@ static AstTyped* parse_factor(OnyxParser* parser) { break; } + case Token_Type_Keyword_Proc: + { + AstFunction* func_node = parse_function_definition(parser); + + bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node); + + retval = (AstTyped *) func_node; + break; + } + default: onyx_message_add(parser->msgs, ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, @@ -736,6 +747,26 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { func_def->base.flags |= Ast_Flag_Inline; } + else if (parse_possible_directive(parser, "foreign")) { + func_def->foreign_module = expect(parser, Token_Type_Literal_String); + func_def->foreign_name = expect(parser, Token_Type_Literal_String); + + func_def->base.flags |= Ast_Flag_Foreign; + } + + else if (parse_possible_directive(parser, "export")) { + func_def->base.flags |= Ast_Flag_Exported; + + if (parser->curr_token->type == Token_Type_Literal_String) { + OnyxToken* str_token = expect(parser, Token_Type_Literal_String); + func_def->exported_name = + bh_aprintf(global_heap_allocator, + "%b", + str_token->text, + str_token->length); + } + } + else { OnyxToken* directive_token = expect(parser, '#'); OnyxToken* symbol_token = expect(parser, Token_Type_Symbol); @@ -764,50 +795,52 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { return func_def; } -static AstNode* parse_foreign(OnyxParser* parser) { - expect(parser, Token_Type_Keyword_Foreign); - - AstForeign* foreign = make_node(AstForeign, Ast_Kind_Foreign); - foreign->mod_token = expect(parser, Token_Type_Literal_String); - foreign->name_token = expect(parser, Token_Type_Literal_String); - - if (parser->curr_token->type == Token_Type_Keyword_Proc) { - foreign->import = (AstNode *) parse_function_definition(parser); - - } else { - AstType* type = parse_type(parser); - - AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); - global->base.type_node = type; - global->base.flags |= Ast_Flag_Lval; - - foreign->import = (AstNode *) global; - } - - return (AstNode *) foreign; -} - -static AstNode* parse_top_level_constant_symbol(OnyxParser* parser) { - if (parser->curr_token->type == Token_Type_Keyword_Proc) { - return (AstNode *) parse_function_definition(parser); - - } else if (parser->curr_token->type == Token_Type_Keyword_Struct) { - // Handle struct case - assert(0); - - } else if (parser->curr_token->type == Token_Type_Keyword_Foreign) { - return (AstNode *) parse_foreign(parser); - - } else { - // Global constant with initial value - AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); - global->initial_value = parse_expression(parser); - global->base.flags |= Ast_Flag_Const; - global->base.flags |= Ast_Flag_Lval; - global->base.flags |= Ast_Flag_Comptime; - - return (AstNode *) global; - } +// static AstNode* parse_foreign(OnyxParser* parser) { +// expect(parser, Token_Type_Keyword_Foreign); +// +// AstForeign* foreign = make_node(AstForeign, Ast_Kind_Foreign); +// foreign->mod_token = expect(parser, Token_Type_Literal_String); +// foreign->name_token = expect(parser, Token_Type_Literal_String); +// +// if (parser->curr_token->type == Token_Type_Keyword_Proc) { +// foreign->import = (AstNode *) parse_function_definition(parser); +// +// } else { +// AstType* type = parse_type(parser); +// +// AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); +// global->base.type_node = type; +// global->base.flags |= Ast_Flag_Lval; +// +// foreign->import = (AstNode *) global; +// } +// +// return (AstNode *) foreign; +// } + +static AstTyped* parse_top_level_constant_symbol(OnyxParser* parser) { +// if (parser->curr_token->type == Token_Type_Keyword_Proc) { +// return (AstNode *) parse_function_definition(parser); +// +// } else if (parser->curr_token->type == Token_Type_Keyword_Struct) { +// // Handle struct case +// assert(0); +// +// } else if (parser->curr_token->type == Token_Type_Keyword_Foreign) { +// return (AstNode *) parse_foreign(parser); +// +// } else { +// // Global constant with initial value +// AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); +// global->initial_value = parse_expression(parser); +// global->base.flags |= Ast_Flag_Const; +// global->base.flags |= Ast_Flag_Lval; +// global->base.flags |= Ast_Flag_Comptime; +// +// return (AstNode *) global; +// } + + return parse_expression(parser); } static AstNode* parse_top_level_statement(OnyxParser* parser) { @@ -821,75 +854,28 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) { return (AstNode *) use_node; } - case Token_Type_Keyword_Export: - { - expect(parser, Token_Type_Keyword_Export); - if (parser->curr_token->type != Token_Type_Symbol) { - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_EXPECTED_TOKEN, - parser->curr_token->pos, - onyx_get_token_type_name(Token_Type_Symbol), - onyx_get_token_type_name(parser->curr_token->type)); - break; - } - - AstNode* top_level_decl = parse_top_level_statement(parser); - top_level_decl->flags |= Ast_Flag_Exported; - return top_level_decl; - } - case Token_Type_Symbol: { OnyxToken* symbol = parser->curr_token; parser_next_token(parser); + expect(parser, ':'); expect(parser, ':'); - AstType* type = NULL; - - if (parser->curr_token->type == Token_Type_Symbol) { - type = parse_type(parser); - } - - if (parser->curr_token->type == ':') { - parser_next_token(parser); - - AstNode* node = parse_top_level_constant_symbol(parser); - - if (node->kind == Ast_Kind_Global) { - ((AstGlobal *) node)->base.type_node = type; - } - - if (node->kind == Ast_Kind_Foreign) { - ((AstForeign *) node)->import->token = symbol; - - } else { - node->token = symbol; - } - - return node; - - } else if (parser->curr_token->type == '=') { - parser_next_token(parser); - - AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global); - global->base.token = symbol; - global->base.flags |= Ast_Flag_Lval; - global->initial_value = parse_expression(parser); - global->base.type_node = type; - - return (AstNode *) global; + AstTyped* node = parse_top_level_constant_symbol(parser); + if (node->kind == Ast_Kind_Function) { + node->token = symbol; } else { - onyx_token_null_toggle(parser->curr_token); - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN, - parser->curr_token->pos, - parser->curr_token->text); - onyx_token_null_toggle(parser->curr_token); + // HACK + bh_arr_push(parser->results.nodes_to_process, (AstNode *) node); } - return &error_node; + AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding); + binding->base.token = symbol; + binding->node = (AstNode *) node; + + return (AstNode *) binding; } default: break; @@ -919,28 +905,44 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Onyx parser.allocator = alloc; parser.tokenizer = tokenizer; parser.curr_token = tokenizer->tokens; - parser.prev_token = NULL; parser.msgs = msgs; + parser.prev_token = NULL; + parser.msgs = msgs; + + parser.results = (ParseResults) { + .allocator = global_heap_allocator, + + .uses = NULL, + .bindings = NULL, + .nodes_to_process = NULL, + }; + + bh_arr_new(parser.results.allocator, parser.results.uses, 4); + bh_arr_new(parser.results.allocator, parser.results.bindings, 4); + bh_arr_new(parser.results.allocator, parser.results.nodes_to_process, 4); + return parser; } void onyx_parser_free(OnyxParser* parser) { } -bh_arr(AstNode *) onyx_parse(OnyxParser *parser) { - bh_arr(AstNode *) top_level_nodes = NULL; - bh_arr_new(global_heap_allocator, top_level_nodes, 4); - +ParseResults onyx_parse(OnyxParser *parser) { while (parser->curr_token->type != Token_Type_End_Stream) { AstNode* curr_stmt = parse_top_level_statement(parser); - // Building a linked list of statements down the "next" chain if (curr_stmt != NULL && curr_stmt != &error_node) { while (curr_stmt != NULL) { - bh_arr_push(top_level_nodes, curr_stmt); + + switch (curr_stmt->kind) { + case Ast_Kind_Use: bh_arr_push(parser->results.uses, (AstUse *) curr_stmt); break; + case Ast_Kind_Binding: bh_arr_push(parser->results.bindings, (AstBinding *) curr_stmt); break; + default: assert(("Invalid top level node", 0)); + } + curr_stmt = curr_stmt->next; } } } - return top_level_nodes; + return parser->results; } diff --git a/src/onyxsempass.c b/src/onyxsempass.c index 7f2b4bc8..9c8d225c 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -23,61 +23,61 @@ OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc // WASM, this function may not be needed. It brings all of the locals // defined in sub-scopes up to the function-block level. This is a // requirement of WASM, but not of other targets. -static void collapse_scopes(OnyxProgram* program) { - bh_arr(AstBlock*) traversal_queue = NULL; - bh_arr_new(global_scratch_allocator, traversal_queue, 4); - bh_arr_set_length(traversal_queue, 0); - - bh_arr_each(AstFunction *, func, program->functions) { - AstLocalGroup* top_locals = (*func)->body->locals; - - bh_arr_push(traversal_queue, (*func)->body); - while (!bh_arr_is_empty(traversal_queue)) { - AstBlock* block = traversal_queue[0]; - - if (block->base.kind == Ast_Kind_If) { - AstIf* if_node = (AstIf *) block; - if (if_node->true_block.as_block != NULL) - bh_arr_push(traversal_queue, if_node->true_block.as_block); - - if (if_node->false_block.as_block != NULL) - bh_arr_push(traversal_queue, if_node->false_block.as_block); - - } else { - - if (block->locals != top_locals && block->locals->last_local != NULL) { - AstLocal* last_local = block->locals->last_local; - while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local; - - last_local->prev_local = top_locals->last_local; - top_locals->last_local = block->locals->last_local; - block->locals->last_local = NULL; - } - - AstNode* walker = block->body; - while (walker) { - if (walker->kind == Ast_Kind_Block) { - bh_arr_push(traversal_queue, (AstBlock *) walker); - - } else if (walker->kind == Ast_Kind_While) { - bh_arr_push(traversal_queue, ((AstWhile *) walker)->body); - - } else if (walker->kind == Ast_Kind_If) { - if (((AstIf *) walker)->true_block.as_block != NULL) - bh_arr_push(traversal_queue, ((AstIf *) walker)->true_block.as_block); - - if (((AstIf *) walker)->false_block.as_block != NULL) - bh_arr_push(traversal_queue, ((AstIf *) walker)->false_block.as_block); - } - - walker = walker->next; - } - } - - bh_arr_deleten(traversal_queue, 0, 1); - } - } -} +// static void collapse_scopes(OnyxProgram* program) { +// bh_arr(AstBlock*) traversal_queue = NULL; +// bh_arr_new(global_scratch_allocator, traversal_queue, 4); +// bh_arr_set_length(traversal_queue, 0); +// +// bh_arr_each(AstFunction *, func, program->functions) { +// AstLocalGroup* top_locals = (*func)->body->locals; +// +// bh_arr_push(traversal_queue, (*func)->body); +// while (!bh_arr_is_empty(traversal_queue)) { +// AstBlock* block = traversal_queue[0]; +// +// if (block->base.kind == Ast_Kind_If) { +// AstIf* if_node = (AstIf *) block; +// if (if_node->true_block.as_block != NULL) +// bh_arr_push(traversal_queue, if_node->true_block.as_block); +// +// if (if_node->false_block.as_block != NULL) +// bh_arr_push(traversal_queue, if_node->false_block.as_block); +// +// } else { +// +// if (block->locals != top_locals && block->locals->last_local != NULL) { +// AstLocal* last_local = block->locals->last_local; +// while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local; +// +// last_local->prev_local = top_locals->last_local; +// top_locals->last_local = block->locals->last_local; +// block->locals->last_local = NULL; +// } +// +// AstNode* walker = block->body; +// while (walker) { +// if (walker->kind == Ast_Kind_Block) { +// bh_arr_push(traversal_queue, (AstBlock *) walker); +// +// } else if (walker->kind == Ast_Kind_While) { +// bh_arr_push(traversal_queue, ((AstWhile *) walker)->body); +// +// } else if (walker->kind == Ast_Kind_If) { +// if (((AstIf *) walker)->true_block.as_block != NULL) +// bh_arr_push(traversal_queue, ((AstIf *) walker)->true_block.as_block); +// +// if (((AstIf *) walker)->false_block.as_block != NULL) +// bh_arr_push(traversal_queue, ((AstIf *) walker)->false_block.as_block); +// } +// +// walker = walker->next; +// } +// } +// +// bh_arr_deleten(traversal_queue, 0, 1); +// } +// } +// } void onyx_sempass(OnyxSemPassState* state, OnyxProgram* program) { onyx_resolve_symbols(state, program); @@ -86,5 +86,5 @@ void onyx_sempass(OnyxSemPassState* state, OnyxProgram* program) { onyx_type_check(state, program); if (onyx_message_has_errors(state->msgs)) return; - collapse_scopes(program); + // collapse_scopes(program); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 1460832f..c363c396 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -1,13 +1,14 @@ #define BH_DEBUG #include "onyxsempass.h" -static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol); +static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol); static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type); -static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol); -static void symbol_remove(OnyxSemPassState* state, AstNode* symbol); -static AstNode* symbol_resolve(OnyxSemPassState* state, AstNode* symbol); +static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol); +static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn); +static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn); static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_group); static void local_group_leave(OnyxSemPassState* state); + static void symres_local(OnyxSemPassState* state, AstLocal** local); static void symres_call(OnyxSemPassState* state, AstCall* call); static void symres_expression(OnyxSemPassState* state, AstTyped** expr); @@ -16,23 +17,23 @@ static void symres_return(OnyxSemPassState* state, AstReturn* ret); static void symres_if(OnyxSemPassState* state, AstIf* ifnode); static void symres_while(OnyxSemPassState* state, AstWhile* whilenode); static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, AstNode** trailer); -static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt); +static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt); static void symres_block(OnyxSemPassState* state, AstBlock* block); static void symres_function(OnyxSemPassState* state, AstFunction* func); static AstType* symres_type(OnyxSemPassState* state, AstType* type); -static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol) { - onyx_token_null_toggle(symbol->token); +static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) { + onyx_token_null_toggle(tkn); 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->text)) { - sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text); + if (bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) { + sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, tkn->text); } - bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym); + bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym); if (symbol->kind == Ast_Kind_Local) { AstLocal* local = (AstLocal *) symbol; @@ -40,39 +41,39 @@ static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol) { state->curr_local_group->last_local = local; } - onyx_token_null_toggle(symbol->token); + onyx_token_null_toggle(tkn); } -static void symbol_remove(OnyxSemPassState* state, AstNode* symbol) { - onyx_token_null_toggle(symbol->token); +static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn) { + onyx_token_null_toggle(tkn); - SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text); + SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text); if (sp_sym->shadowed) { - bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym->shadowed); + bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym->shadowed); } else { - bh_table_delete(SemPassSymbol *, state->symbols, symbol->token->text); + bh_table_delete(SemPassSymbol *, state->symbols, tkn->text); } - onyx_token_null_toggle(symbol->token); + onyx_token_null_toggle(tkn); } -static AstNode* symbol_resolve(OnyxSemPassState* state, AstNode* symbol) { - onyx_token_null_toggle(symbol->token); +static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn) { + onyx_token_null_toggle(tkn); - if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->text)) { + if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL, - symbol->token->pos, - symbol->token->text); + tkn->pos, + tkn->text); - onyx_token_null_toggle(symbol->token); - return symbol; + onyx_token_null_toggle(tkn); + return NULL; } - SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text); + SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text); - onyx_token_null_toggle(symbol->token); + onyx_token_null_toggle(tkn); return sp_sym->node; } @@ -85,7 +86,7 @@ static void local_group_leave(OnyxSemPassState* state) { assert(state->curr_local_group != NULL); for (AstLocal *walker = state->curr_local_group->last_local; walker != NULL; walker = walker->prev_local) { - symbol_remove(state, (AstNode *) walker); + symbol_remove(state, walker->base.token); } state->curr_local_group = state->curr_local_group->prev_group; @@ -98,27 +99,27 @@ static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* b bh_table_put(SemPassSymbol *, state->symbols, basic_type->base.name, sp_sym); } -static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol) { - onyx_token_null_toggle(symbol->token); +static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) { + onyx_token_null_toggle(tkn); // NOTE: If the function hasn't already been defined - if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->text)) { + if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) { SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol); sp_sym->node = symbol; sp_sym->shadowed = NULL; - bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym); + bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym); } else { onyx_message_add(state->msgs, ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS, - symbol->token->pos, - symbol->token->text); + tkn->pos, + tkn->text); // NOTE: I really wish C had defer... - onyx_token_null_toggle(symbol->token); + onyx_token_null_toggle(tkn); return 0; } - onyx_token_null_toggle(symbol->token); + onyx_token_null_toggle(tkn); return 1; } @@ -126,7 +127,7 @@ static AstType* symres_type(OnyxSemPassState* state, AstType* type) { if (type == NULL) return NULL; if (type->kind == Ast_Kind_Symbol) { - return (AstType *) symbol_resolve(state, (AstNode *) type); + return (AstType *) symbol_resolve(state, ((AstNode *) type)->token); } // NOTE: Already resolved @@ -143,11 +144,11 @@ static AstType* symres_type(OnyxSemPassState* state, AstType* type) { static void symres_local(OnyxSemPassState* state, AstLocal** local) { (*local)->base.type_node = symres_type(state, (*local)->base.type_node); - symbol_introduce(state, (AstNode *) *local); + symbol_introduce(state, (*local)->base.token, (AstNode *) *local); } static void symres_call(OnyxSemPassState* state, AstCall* call) { - AstNode* callee = symbol_resolve(state, call->callee); + AstNode* callee = symbol_resolve(state, call->callee->token); if (callee) call->callee = callee; else DEBUG_HERE; @@ -178,7 +179,7 @@ static void symres_expression(OnyxSemPassState* state, AstTyped** expr) { case Ast_Kind_Block: symres_block(state, (AstBlock *) *expr); break; case Ast_Kind_Symbol: - *expr = (AstTyped *) symbol_resolve(state, (AstNode *) *expr); + *expr = (AstTyped *) symbol_resolve(state, ((AstNode *) *expr)->token); break; // NOTE: This is a good case, since it means the symbol is already resolved @@ -195,7 +196,7 @@ static void symres_expression(OnyxSemPassState* state, AstTyped** expr) { } static void symres_assignment(OnyxSemPassState* state, AstAssign* assign) { - AstTyped* lval = (AstTyped *) symbol_resolve(state, (AstNode *) assign->lval); + AstTyped* lval = (AstTyped *) symbol_resolve(state, assign->lval->token); if (lval == NULL) return; assign->lval = lval; @@ -277,7 +278,7 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) { for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { param->base.type_node = symres_type(state, param->base.type_node); - symbol_introduce(state, (AstNode *) param); + symbol_introduce(state, param->base.token, (AstNode *) param); } if (func->base.type_node != NULL) { @@ -289,7 +290,27 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) { symres_block(state, func->body); for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) { - symbol_remove(state, (AstNode *) param); + symbol_remove(state, param->base.token); + } +} + +static void symres_top_node(OnyxSemPassState* state, AstNode** node) { + switch ((*node)->kind) { + case Ast_Kind_Call: + case Ast_Kind_Unary_Op: + case Ast_Kind_Binary_Op: + case Ast_Kind_Literal: + case Ast_Kind_Symbol: + symres_expression(state, (AstTyped **) node); + break; + + case Ast_Kind_Function: + symres_function(state, (AstFunction *) *node); + break; + + default: + DEBUG_HERE; + break; } } @@ -311,26 +332,29 @@ void onyx_resolve_symbols(OnyxSemPassState* state, OnyxProgram* program) { symbol_basic_type_introduce(state, &basic_type_rawptr); // NOTE: Introduce all global symbols - bh_arr_each(AstGlobal *, global, program->globals) - if (!symbol_unique_introduce(state, (AstNode *) *global)) return; + // bh_arr_each(AstGlobal *, global, program->globals) + // if (!symbol_unique_introduce(state, (AstNode *) *global)) return; - bh_arr_each(AstFunction *, function, program->functions) - if (!symbol_unique_introduce(state, (AstNode *) *function)) return; + // bh_arr_each(AstFunction *, function, program->functions) + // if (!symbol_unique_introduce(state, (AstNode *) *function)) return; - bh_arr_each(AstForeign *, foreign, program->foreigns) { - AstKind import_kind = (*foreign)->import->kind; + // bh_arr_each(AstForeign *, foreign, program->foreigns) { + // AstKind import_kind = (*foreign)->import->kind; - if (import_kind == Ast_Kind_Function || import_kind == Ast_Kind_Global) - if (!symbol_unique_introduce(state, (*foreign)->import)) return; - } + // if (import_kind == Ast_Kind_Function || import_kind == Ast_Kind_Global) + // if (!symbol_unique_introduce(state, (*foreign)->import)) return; + // } - // NOTE: Then, resolve all symbols in all functions - bh_arr_each(AstForeign *, foreign, program->foreigns) { - if ((*foreign)->import->kind == Ast_Kind_Function) { - symres_function(state, (AstFunction *) (*foreign)->import); - } - } + // // NOTE: Then, resolve all symbols in all functions + // bh_arr_each(AstForeign *, foreign, program->foreigns) { + // if ((*foreign)->import->kind == Ast_Kind_Function) { + // symres_function(state, (AstFunction *) (*foreign)->import); + // } + // } + + bh_arr_each(AstBinding *, binding, program->top_level_bindings) + if (!symbol_unique_introduce(state, (*binding)->base.token, (*binding)->node)) return; - bh_arr_each(AstFunction *, function, program->functions) - symres_function(state, *function); + bh_arr_each(AstNode *, node, program->nodes_to_process) + symres_top_node(state, node); } diff --git a/src/onyxutils.c b/src/onyxutils.c index b98f5dd8..26a384f3 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -13,6 +13,7 @@ static const char* ast_node_names[] = { "PROGRAM", "USE", + "BINDING", "FUNCTION", "FOREIGN", "BLOCK", @@ -24,7 +25,12 @@ static const char* ast_node_names[] = { "UN_OP", "BIN_OP", + "TYPE_START (BAD)" "TYPE", + "POINTER_TYPE", + "FUNCTION_TYPE", + "TYPE_END (BAD)" + "LITERAL", "PARAM", "ARGUMENT", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 7c817808..b67b091e 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -219,23 +219,24 @@ static WasmType onyx_type_to_wasm_type(Type* type) { #define WI(instr) bh_arr_push(code, ((WasmInstruction){ instr, 0x00 })); #define WID(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, data })); - -static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstFunction* fd); -static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBlock* block); -static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstNode* stmt); -static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* lval); -static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstAssign* assign); -static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIf* if_node); -static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstWhile* while_node); -static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBinaryOp* binop); -static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* unop); -static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstCall* call); -static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIntrinsicCall* call); -static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* expr); -static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* cast); -static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstReturn* ret); - -static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstFunction* fd) { +#define COMPILE_FUNC(kind, ...) static void compile_ ## kind (OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, __VA_ARGS__) + +COMPILE_FUNC(function_body, AstFunction* fd); +COMPILE_FUNC(block, AstBlock* block); +COMPILE_FUNC(statement, AstNode* stmt); +COMPILE_FUNC(assign_lval, AstTyped* lval); +COMPILE_FUNC(assignment, AstAssign* assign); +COMPILE_FUNC(if, AstIf* if_node); +COMPILE_FUNC(while, AstWhile* while_node); +COMPILE_FUNC(binop, AstBinaryOp* binop); +COMPILE_FUNC(unaryop, AstUnaryOp* unop); +COMPILE_FUNC(call, AstCall* call); +COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call); +COMPILE_FUNC(expression, AstTyped* expr); +COMPILE_FUNC(cast, AstUnaryOp* cast); +COMPILE_FUNC(return, AstReturn* ret); + +COMPILE_FUNC(function_body, AstFunction* fd) { if (fd->body == NULL) return; bh_arr(WasmInstruction) code = *pcode; @@ -249,7 +250,7 @@ static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* *pcode = code; } -static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBlock* block) { +COMPILE_FUNC(block, AstBlock* block) { bh_arr(WasmInstruction) code = *pcode; bh_arr_push(mod->structured_jump_target, 1); @@ -265,7 +266,7 @@ static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A *pcode = code; } -static void compile_structured_jump(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, b32 jump_backward) { +COMPILE_FUNC(structured_jump, b32 jump_backward) { bh_arr(WasmInstruction) code = *pcode; i32 labelidx = 0; @@ -291,7 +292,7 @@ static void compile_structured_jump(OnyxWasmModule* mod, bh_arr(WasmInstruction) *pcode = code; } -static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstNode* stmt) { +COMPILE_FUNC(statement, AstNode* stmt) { bh_arr(WasmInstruction) code = *pcode; switch (stmt->kind) { @@ -315,7 +316,7 @@ static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcod *pcode = code; } -static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* lval) { +COMPILE_FUNC(assign_lval, AstTyped* lval) { bh_arr(WasmInstruction) code = *pcode; if (lval->kind == Ast_Kind_Local || lval->kind == Ast_Kind_Param) { @@ -335,7 +336,7 @@ static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pc *pcode = code; } -static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIf* if_node) { +COMPILE_FUNC(if, AstIf* if_node) { bh_arr(WasmInstruction) code = *pcode; compile_expression(mod, &code, if_node->cond); @@ -378,7 +379,7 @@ static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstI *pcode = code; } -static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstWhile* while_node) { +COMPILE_FUNC(while, AstWhile* while_node) { bh_arr(WasmInstruction) code = *pcode; WID(WI_BLOCK_START, 0x40); @@ -406,7 +407,7 @@ static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A *pcode = code; } -static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstAssign* assign) { +COMPILE_FUNC(assignment, AstAssign* assign) { bh_arr(WasmInstruction) code = *pcode; compile_expression(mod, &code, assign->expr); @@ -433,7 +434,7 @@ static const WasmInstructionType binop_map[][4] = { /* GTE */ { WI_I32_GE_S, WI_I64_GE_S, WI_F32_GE, WI_F64_GE }, }; -static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBinaryOp* binop) { +COMPILE_FUNC(binop, AstBinaryOp* binop) { bh_arr(WasmInstruction) code = *pcode; b32 is_sign_significant = 0; @@ -480,7 +481,7 @@ static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A *pcode = code; } -static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* unop) { +COMPILE_FUNC(unaryop, AstUnaryOp* unop) { bh_arr(WasmInstruction) code = *pcode; switch (unop->operation) { @@ -527,7 +528,7 @@ static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, *pcode = code; } -static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstCall* call) { +COMPILE_FUNC(call, AstCall* call) { bh_arr(WasmInstruction) code = *pcode; for (AstArgument *arg = call->arguments; @@ -542,7 +543,7 @@ static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, As *pcode = code; } -static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIntrinsicCall* call) { +COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call) { bh_arr(WasmInstruction) code = *pcode; i32 place_arguments_normally = 1; @@ -613,7 +614,7 @@ static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* *pcode = code; } -static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* expr) { +COMPILE_FUNC(expression, AstTyped* expr) { bh_arr(WasmInstruction) code = *pcode; switch (expr->kind) { @@ -696,7 +697,7 @@ static const WasmInstructionType cast_map[][6] = { /* F64 */ { WI_I32_FROM_F64_S, WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64, WI_NOP, }, }; -static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* cast) { +COMPILE_FUNC(cast, AstUnaryOp* cast) { bh_arr(WasmInstruction) code = *pcode; compile_expression(mod, &code, cast->expr); @@ -739,7 +740,7 @@ static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, As *pcode = code; } -static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstReturn* ret) { +COMPILE_FUNC(return, AstReturn* ret) { bh_arr(WasmInstruction) code = *pcode; if (ret->expr) { @@ -799,6 +800,18 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { i32 type_idx = generate_type_idx(mod, fd); + if (fd->base.flags & Ast_Flag_Foreign) { + WasmImport import = { + .kind = WASM_FOREIGN_FUNCTION, + .idx = type_idx, + .mod = fd->foreign_module, + .name = fd->foreign_name, + }; + + bh_arr_push(mod->imports, import); + return; + } + WasmFunc wasm_func = { .type_idx = type_idx, .locals = { @@ -979,36 +992,40 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs) { void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxProgram* program) { // NOTE: First, introduce all indicies for globals and functions - bh_arr_each(AstForeign *, foreign, program->foreigns) { - AstKind import_kind = (*foreign)->import->kind; + // bh_arr_each(AstForeign *, foreign, program->foreigns) { + // AstKind import_kind = (*foreign)->import->kind; - if (import_kind == Ast_Kind_Function) { - module->next_func_idx++; - bh_imap_put(&module->func_map, (u64) (*foreign)->import, module->next_import_func_idx++); - } - else if (import_kind == Ast_Kind_Global) { - module->next_global_idx++; - bh_imap_put(&module->global_map, (u64) (*foreign)->import, module->next_import_global_idx++); - } + // if (import_kind == Ast_Kind_Function) { + // module->next_func_idx++; + // bh_imap_put(&module->func_map, (u64) (*foreign)->import, module->next_import_func_idx++); + // } + // else if (import_kind == Ast_Kind_Global) { + // module->next_global_idx++; + // bh_imap_put(&module->global_map, (u64) (*foreign)->import, module->next_import_global_idx++); + // } - compile_foreign(module, *foreign); + // compile_foreign(module, *foreign); + // } + + bh_arr_each(AstFunction *, function, program->functions) { + if ((*function)->base.flags & Ast_Flag_Foreign) { + bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++); + } } bh_arr_each(AstFunction *, function, program->functions) { + if ((*function)->base.flags & Ast_Flag_Foreign) continue; + if (((*function)->base.flags & Ast_Flag_Intrinsic) == 0) bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++); } - bh_arr_each(AstGlobal *, global, program->globals) - bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++); - - // NOTE: Then, compile everything bh_arr_each(AstFunction *, function, program->functions) compile_function(module, *function); - bh_arr_each(AstGlobal *, global, program->globals) - compile_global_declaration(module, *global); + // bh_arr_each(AstGlobal *, global, program->globals) + // compile_global_declaration(module, *global); } void onyx_wasm_module_free(OnyxWasmModule* module) {