From: Brendan Hansen Date: Wed, 26 Aug 2020 03:41:05 +0000 (-0500) Subject: added default parameters; will need to be bug tested thoroughly X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=76e4c094e7dbf51d4bbfaf7893252531bb7f9b97;p=onyx.git added default parameters; will need to be bug tested thoroughly --- diff --git a/core/alloc.onyx b/core/alloc.onyx index eb01f0ca..0f5694da 100644 --- a/core/alloc.onyx +++ b/core/alloc.onyx @@ -3,43 +3,9 @@ package memory #include_file "memory" #include_file "intrinsics" -use package builtin { __heap_start } +use package builtin use package intrinsics { memory_size, memory_grow } -// Need to define this somewhere -null :: cast(rawptr) 0; - -AllocAction :: enum { - Alloc; - Free; - Resize; -} - -alloc_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr; - -Allocator :: struct { - data: rawptr; - func: alloc_proc; -} - -alloc :: proc (use a: Allocator, size: u32) -> rawptr { - return func(data, AllocAction.Alloc, size, 16, null); -} - -resize :: proc (use a: Allocator, ptr: rawptr, size: u32) -> rawptr { - return func(data, AllocAction.Resize, size, 16, ptr); -} - -free :: proc (use a: Allocator, ptr: rawptr) { - func(data, AllocAction.Free, 0, 0, ptr); -} - - - - - - - heap_allocator : Allocator; #private diff --git a/core/builtin.onyx b/core/builtin.onyx index 58fdd589..08522136 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -2,3 +2,37 @@ package builtin string :: #type []u8; cstring :: #type ^u8; + +Buffer :: #type []void; + +null :: cast(rawptr) 0; + +AllocAction :: enum { + Alloc; + Free; + Resize; +} + +allocator_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr; + +Allocator :: struct { + data: rawptr; + func: allocator_proc; +} + +alloc :: proc (use a: Allocator, size: u32) -> rawptr { + return func(data, AllocAction.Alloc, size, 16, null); +} + +resize :: proc (use a: Allocator, ptr: rawptr, size: u32) -> rawptr { + return func(data, AllocAction.Resize, size, 16, ptr); +} + +free :: proc (use a: Allocator, ptr: rawptr) { + func(data, AllocAction.Free, 0, 0, ptr); +} + +context : struct { + allocator : Allocator; + temp_allocator : Allocator; +} \ No newline at end of file diff --git a/core/string.onyx b/core/string.onyx index 0668398f..401978a2 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -1,11 +1,9 @@ package core -use package builtin { string, cstring } +use package builtin use package memory use package wasi -Buffer :: #type []void; - string_make :: proc #overloaded { string_make_from_cstring } #private @@ -179,11 +177,7 @@ u64_to_string :: proc (n_: u64, base: u64, buf: Buffer) -> string { return string.{ data = c + 1, count = len }; } -string_builder_add_u64 :: proc (use sb: ^StringBuilder, n: u64) -> ^StringBuilder { - return string_builder_add_u64_with_base(sb, n, 10l); -} - -string_builder_add_u64_with_base :: proc (use sb: ^StringBuilder, n: u64, base: u64) -> ^StringBuilder { +string_builder_add_u64 :: proc (use sb: ^StringBuilder, n: u64, base := 10l) -> ^StringBuilder { buf : [256] u8; s := u64_to_string(n, base, Buffer.{ cast(rawptr) buf, 256 }); return string_builder_add_string(sb, s); @@ -192,7 +186,6 @@ string_builder_add_u64_with_base :: proc (use sb: ^StringBuilder, n: u64, base: string_builder_append :: proc #overloaded { string_builder_add_string, string_builder_add_cstring, - string_builder_add_u64_with_base, string_builder_add_u64, } diff --git a/docs/plan b/docs/plan index f928a5a3..7407f897 100644 --- a/docs/plan +++ b/docs/plan @@ -213,6 +213,9 @@ HOW: [X] initializers on switch statements + [X] default parameters + - Must be the last parameters + [ ] #file and #line directives - string and u32 respectively that represent the current file and line number where the directive is diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index f7a103bf..512160ae 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -54,6 +54,7 @@ typedef struct AstInclude AstInclude; typedef struct AstUsePackage AstUsePackage; typedef struct AstAlias AstAlias; typedef struct AstGlobal AstGlobal; +typedef struct AstParam AstParam; typedef struct AstFunction AstFunction; typedef struct AstOverloadedFunction AstOverloadedFunction; @@ -440,12 +441,16 @@ struct AstGlobal { }; }; }; +struct AstParam { AstLocal *local; AstTyped *default_value; }; struct AstFunction { AstTyped_base; Scope *scope; + + bh_arr(AstParam) params; + AstType* return_type; + AstBlock *body; - AstLocal *params; bh_arr(AstLocal *) locals; union { diff --git a/include/onyxsempass.h b/include/onyxsempass.h index 7dbed0a3..dc131d8e 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -36,6 +36,8 @@ void onyx_resolve_symbols(); // NOTE: Inferring and checking types in the tree void onyx_type_check(); +b32 check_expression(AstTyped** expr); + // NOTE: Full semantic pass void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc); void onyx_sempass(ProgramInfo* program); diff --git a/include/onyxtypes.h b/include/onyxtypes.h index 1bfd25a5..38c4595e 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -56,7 +56,8 @@ typedef struct StructMember { TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; }) \ TYPE_KIND(Function, struct { \ Type *return_type; \ - u64 param_count; \ + u32 param_count; \ + u32 needed_param_count; \ Type* params[]; \ }) \ TYPE_KIND(Struct, struct { \ @@ -109,7 +110,7 @@ u32 type_size_of(Type* type); u32 type_alignment_of(Type* type); Type* type_build_from_ast(bh_allocator alloc, struct AstType* type_node); -Type* type_build_function_type(bh_allocator alloc, struct AstFunction* func, struct AstType* return_type); +Type* type_build_function_type(bh_allocator alloc, struct AstFunction* func); Type* type_make_pointer(bh_allocator alloc, Type* to); Type* type_make_slice(bh_allocator alloc, Type* of); diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index 6a4c4606..6356d84f 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -30,7 +30,7 @@ contexts: scope: constant.type.onyx - match: '\b(true|false|null)\b' - scope: constant.boolean.onyx + scope: constant.numeric.onyx # Numbers - match: '\b(-)?[0-9.]+(f|l)?\b' diff --git a/onyx b/onyx index 77225f13..87ede097 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index 55af2806..94ee0f15 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -19,7 +19,7 @@ use package memory use package wasi use package intrinsics -print_u64_with_base :: proc (n_: u64, base: u64) { +print_u64_with_base :: proc (n_: u64, base := 10l) { n := n_; str: [256] u8; for i: 0, 256 do str[i] = #char "\0"; @@ -159,7 +159,7 @@ timer_end :: proc (start_time: Timestamp) -> Timestamp { return (curr_time - start_time) / 1000000l; } -is_prime :: proc (n: u32) -> bool { +is_prime :: proc (n := 0) -> bool { sqrt :: cast(i32) (sqrt_f32(cast(f32) n)); for i: 2, sqrt + 1 do if n % i == 0 do return false; return true; @@ -284,6 +284,9 @@ main :: proc (args: []cstring) { print("Unexpected token: "); print_u64_with_base(cast(u64) tokens.data[i].data[0], 16l); print("\n"); + + // This breaks out of the for loop + break break; } } } @@ -335,5 +338,15 @@ main :: proc (args: []cstring) { ss := string_substr("Hello, World!", "World"); if ss.count > 0 do print(ss); print("\n"); + + foobar(10, 1230); } +foobar :: proc (a: i32, b := 1, c := 5l) { + print_u64_with_base(cast(u64) a); + print("\n"); + print_u64_with_base(cast(u64) b, 16l); + print("\n"); + print_u64_with_base(c); + print("\n"); +} \ No newline at end of file diff --git a/src/onyxchecker.c b/src/onyxchecker.c index d8f95052..2d75f55b 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -3,7 +3,7 @@ #include "onyxparser.h" #include "onyxutils.h" -#define CHECK(kind, ...) static b32 check_ ## kind (__VA_ARGS__) +#define CHECK(kind, ...) b32 check_ ## kind (__VA_ARGS__) CHECK(block, AstBlock* block); CHECK(statement_chain, AstNode* start); @@ -41,7 +41,7 @@ static inline void fill_in_type(AstTyped* node) { node->type = type_build_from_ast(semstate.allocator, node->type_node); } -CHECK(return, AstReturn* retnode) { +b32 check_return(AstReturn* retnode) { if (retnode->expr) { if (check_expression(&retnode->expr)) return 1; @@ -64,7 +64,7 @@ CHECK(return, AstReturn* retnode) { return 0; } -CHECK(if, AstIfWhile* ifnode) { +b32 check_if(AstIfWhile* ifnode) { if (ifnode->assignment != NULL) check_statement((AstNode *) ifnode->assignment); if (check_expression(&ifnode->cond)) return 1; @@ -82,7 +82,7 @@ CHECK(if, AstIfWhile* ifnode) { return 0; } -CHECK(while, AstIfWhile* whilenode) { +b32 check_while(AstIfWhile* whilenode) { if (whilenode->assignment != NULL) check_statement((AstNode *) whilenode->assignment); if (check_expression(&whilenode->cond)) return 1; @@ -100,7 +100,7 @@ CHECK(while, AstIfWhile* whilenode) { return 0; } -CHECK(for, AstFor* fornode) { +b32 check_for(AstFor* fornode) { if (check_expression(&fornode->start)) return 1; if (check_expression(&fornode->end)) return 1; if (check_expression(&fornode->step)) return 1; @@ -157,7 +157,7 @@ CHECK(for, AstFor* fornode) { return 0; } -CHECK(switch, AstSwitch* switchnode) { +b32 check_switch(AstSwitch* switchnode) { if (switchnode->assignment != NULL) check_statement((AstNode *) switchnode->assignment); if (check_expression(&switchnode->expr)) return 1; @@ -217,7 +217,7 @@ static AstTyped* match_overloaded_function(AstCall* call, AstOverloadedFunction* TypeFunction* ol_type = &overload->type->Function; - if (ol_type->param_count != call->arg_count) continue; + if (call->arg_count < ol_type->needed_param_count) continue; AstArgument* arg = call->arguments; Type** param_type = ol_type->params; @@ -243,7 +243,7 @@ no_match: return NULL; } -CHECK(call, AstCall* call) { +b32 check_call(AstCall* call) { AstFunction* callee = (AstFunction *) call->callee; if (callee->kind == Ast_Kind_Symbol) { @@ -298,6 +298,30 @@ CHECK(call, AstCall* call) { return 1; } + if (callee->kind == Ast_Kind_Function) { + if (call->arg_count < bh_arr_length(callee->params)) { + AstArgument** last_arg = &call->arguments; + while (*last_arg && (*last_arg)->next != NULL) + last_arg = (AstArgument **) &(*last_arg)->next; + + while (call->arg_count < bh_arr_length(callee->params) + && callee->params[call->arg_count].default_value != NULL) { + AstTyped* dv = callee->params[call->arg_count].default_value; + + AstArgument* new_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); + new_arg->token = dv->token; + new_arg->value = dv; + new_arg->type = dv->type; + new_arg->next = NULL; + + (*last_arg)->next = (AstNode *) new_arg; + last_arg = (AstArgument **) &(*last_arg)->next; + + call->arg_count++; + } + } + } + // NOTE: If we calling an intrinsic function, translate the // call into an intrinsic call node. if (callee->flags & Ast_Flag_Intrinsic) { @@ -363,23 +387,22 @@ CHECK(call, AstCall* call) { call->type = callee->type->Function.return_type; - Type** formal_param = &callee->type->Function.params[0]; + Type **formal_params = callee->type->Function.params; actual_param = call->arguments; i32 arg_pos = 0; - while (formal_param != NULL && actual_param != NULL) { - if (!types_are_compatible(*formal_param, actual_param->type)) { + while (arg_pos < callee->type->Function.param_count && actual_param != NULL) { + if (!types_are_compatible(formal_params[arg_pos], actual_param->type)) { onyx_message_add(Msg_Type_Function_Param_Mismatch, actual_param->token->pos, callee->token->text, callee->token->length, - type_get_name(*formal_param), + type_get_name(formal_params[arg_pos]), arg_pos, type_get_name(actual_param->type)); return 1; } arg_pos++; - formal_param++; actual_param = (AstArgument *) actual_param->next; } @@ -390,7 +413,7 @@ CHECK(call, AstCall* call) { return 1; } - if (arg_pos > callee->type->Function.param_count) { + if (actual_param != NULL) { onyx_message_add(Msg_Type_Literal, call->token->pos, "too many arguments to function call"); @@ -402,7 +425,7 @@ CHECK(call, AstCall* call) { return 0; } -CHECK(binop_assignment, AstBinaryOp* binop, b32 assignment_is_ok) { +b32 check_binop_assignment(AstBinaryOp* binop, b32 assignment_is_ok) { if (!assignment_is_ok) { onyx_message_add(Msg_Type_Literal, binop->token->pos, @@ -483,7 +506,7 @@ CHECK(binop_assignment, AstBinaryOp* binop, b32 assignment_is_ok) { return 0; } -CHECK(binaryop_compare, AstBinaryOp** pbinop) { +b32 check_binaryop_compare(AstBinaryOp** pbinop) { AstBinaryOp* binop = *pbinop; if (binop->left->type == NULL) { @@ -531,7 +554,7 @@ CHECK(binaryop_compare, AstBinaryOp** pbinop) { return 0; } -CHECK(binaryop_bool, AstBinaryOp** pbinop) { +b32 check_binaryop_bool(AstBinaryOp** pbinop) { AstBinaryOp* binop = *pbinop; if (binop->left->type == NULL) { @@ -564,7 +587,7 @@ CHECK(binaryop_bool, AstBinaryOp** pbinop) { return 0; } -CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok) { +b32 check_binaryop(AstBinaryOp** pbinop, b32 assignment_is_ok) { AstBinaryOp* binop = *pbinop; if (check_expression(&binop->left)) return 1; @@ -684,7 +707,7 @@ CHECK(binaryop, AstBinaryOp** pbinop, b32 assignment_is_ok) { return 0; } -CHECK(unaryop, AstUnaryOp** punop) { +b32 check_unaryop(AstUnaryOp** punop) { AstUnaryOp* unaryop = *punop; if (check_expression(&unaryop->expr)) return 1; @@ -702,7 +725,7 @@ CHECK(unaryop, AstUnaryOp** punop) { return 0; } -CHECK(struct_literal, AstStructLiteral* sl) { +b32 check_struct_literal(AstStructLiteral* sl) { fill_in_type((AstTyped *) sl); TypeStruct* st = &sl->type->Struct; @@ -733,7 +756,7 @@ CHECK(struct_literal, AstStructLiteral* sl) { return 0; } -CHECK(address_of, AstAddressOf* aof) { +b32 check_address_of(AstAddressOf* aof) { if (check_expression(&aof->expr)) return 1; if (aof->expr->kind != Ast_Kind_Array_Access @@ -754,7 +777,7 @@ CHECK(address_of, AstAddressOf* aof) { return 0; } -CHECK(dereference, AstDereference* deref) { +b32 check_dereference(AstDereference* deref) { if (check_expression(&deref->expr)) return 1; if (!type_is_pointer(deref->expr->type)) { @@ -776,7 +799,7 @@ CHECK(dereference, AstDereference* deref) { return 0; } -CHECK(array_access, AstArrayAccess* aa) { +b32 check_array_access(AstArrayAccess* aa) { if (check_expression(&aa->addr)) return 1; if (check_expression(&aa->expr)) return 1; @@ -811,7 +834,7 @@ CHECK(array_access, AstArrayAccess* aa) { return 0; } -CHECK(slice, AstSlice* sl) { +b32 check_slice(AstSlice* sl) { if (check_expression(&sl->addr)) return 1; if (check_expression(&sl->lo)) return 1; if (check_expression(&sl->hi)) return 1; @@ -857,7 +880,7 @@ CHECK(slice, AstSlice* sl) { return 0; } -CHECK(field_access, AstFieldAccess** pfield) { +b32 check_field_access(AstFieldAccess** pfield) { AstFieldAccess* field = *pfield; if (check_expression(&field->expr)) return 1; @@ -886,19 +909,19 @@ CHECK(field_access, AstFieldAccess** pfield) { return 0; } -CHECK(size_of, AstSizeOf* so) { +b32 check_size_of(AstSizeOf* so) { so->size = type_size_of(type_build_from_ast(semstate.allocator, so->so_type)); return 0; } -CHECK(align_of, AstAlignOf* ao) { +b32 check_align_of(AstAlignOf* ao) { ao->alignment = type_alignment_of(type_build_from_ast(semstate.allocator, ao->ao_type)); return 0; } -CHECK(expression, AstTyped** pexpr) { +b32 check_expression(AstTyped** pexpr) { AstTyped* expr = *pexpr; if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) { onyx_message_add(Msg_Type_Literal, @@ -968,6 +991,18 @@ CHECK(expression, AstTyped** pexpr) { break; case Ast_Kind_Function: + // NOTE: Will need something like this at some point + // AstFunction* func = (AstFunction *) expr; + // bh_arr_each(AstParam, param, func->params) { + // if (param->default_value != NULL) { + // onyx_message_add(Msg_Type_Literal, + // func->token->pos, + // "cannot use functions with default parameters in this way"); + // retval = 1; + // break; + // } + // } + expr->flags |= Ast_Flag_Function_Used; break; @@ -987,7 +1022,7 @@ CHECK(expression, AstTyped** pexpr) { return retval; } -CHECK(global, AstGlobal* global) { +b32 check_global(AstGlobal* global) { fill_in_type((AstTyped *) global); if (global->type == NULL) { @@ -1002,7 +1037,7 @@ CHECK(global, AstGlobal* global) { return 0; } -CHECK(statement, AstNode* stmt) { +b32 check_statement(AstNode* stmt) { switch (stmt->kind) { case Ast_Kind_Jump: return 0; @@ -1037,7 +1072,7 @@ CHECK(statement, AstNode* stmt) { } } -CHECK(statement_chain, AstNode* start) { +b32 check_statement_chain(AstNode* start) { while (start) { if (check_statement(start)) return 1; start = start->next; @@ -1046,7 +1081,7 @@ CHECK(statement_chain, AstNode* start) { return 0; } -CHECK(block, AstBlock* block) { +b32 check_block(AstBlock* block) { if (check_statement_chain(block->body)) return 1; bh_table_each_start(AstTyped *, block->scope->symbols); @@ -1063,7 +1098,7 @@ CHECK(block, AstBlock* block) { return 0; } -CHECK(function, AstFunction* func) { +b32 check_function(AstFunction* func) { semstate.expected_return_type = func->type->Function.return_type; if (func->body) { return check_block(func->body); @@ -1072,7 +1107,7 @@ CHECK(function, AstFunction* func) { return 0; } -CHECK(overloaded_function, AstOverloadedFunction* func) { +b32 check_overloaded_function(AstOverloadedFunction* func) { bh_arr_each(AstTyped *, node, func->overloads) { if ((*node)->kind == Ast_Kind_Overloaded_Function) { onyx_message_add(Msg_Type_Literal, @@ -1094,7 +1129,7 @@ CHECK(overloaded_function, AstOverloadedFunction* func) { return 0; } -CHECK(struct, AstStructType* s_node) { +b32 check_struct(AstStructType* s_node) { bh_table(i32) mem_set; bh_table_init(global_heap_allocator, mem_set, bh_arr_length(s_node->members)); @@ -1129,30 +1164,40 @@ CHECK(struct, AstStructType* s_node) { return 0; } -CHECK(function_header, AstFunction* func) { - AstLocal *param = func->params; - while (param != NULL) { - fill_in_type((AstTyped *) param); +b32 check_function_header(AstFunction* func) { + b32 expect_default_param = 0; - if (param->type == NULL) { + bh_arr_each(AstParam, param, func->params) { + AstLocal* local = param->local; + + if (expect_default_param && param->default_value == NULL) { + onyx_message_add(Msg_Type_Literal, + local->token->pos, + "all parameters must have default values after the first default valued parameter."); + return 1; + } + + if (param->default_value != NULL) expect_default_param = 1; + + fill_in_type((AstTyped *) local); + + if (local->type == NULL) { onyx_message_add(Msg_Type_Literal, - param->token->pos, + local->token->pos, "function parameter types must be known"); return 1; } - if (param->type->kind != Type_Kind_Array - && type_size_of(param->type) == 0) { + if (local->type->kind != Type_Kind_Array + && type_size_of(local->type) == 0) { onyx_message_add(Msg_Type_Literal, - param->token->pos, + local->token->pos, "function parameters must have non-void types"); return 1; } - - param = (AstLocal *) param->next; } - fill_in_type((AstTyped *) func); + func->type = type_build_function_type(semstate.node_allocator, func); if ((func->flags & Ast_Flag_Exported) != 0) { if ((func->flags & Ast_Flag_Foreign) != 0) { @@ -1187,7 +1232,7 @@ CHECK(function_header, AstFunction* func) { return 0; } -CHECK(memres, AstMemRes* memres) { +b32 check_memres(AstMemRes* memres) { fill_in_type((AstTyped *) memres); if (memres->initial_value != NULL) { @@ -1215,7 +1260,7 @@ CHECK(memres, AstMemRes* memres) { return 0; } -CHECK(node, AstNode* node) { +b32 check_node(AstNode* node) { switch (node->kind) { case Ast_Kind_Function: return check_function((AstFunction *) node); case Ast_Kind_Overloaded_Function: return check_overloaded_function((AstOverloadedFunction *) node); diff --git a/src/onyxparser.c b/src/onyxparser.c index e798391c..520bd6e8 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -37,7 +37,7 @@ static AstBlock* parse_block(OnyxParser* parser); static AstNode* parse_statement(OnyxParser* parser); static AstType* parse_type(OnyxParser* parser); static AstStructType* parse_struct(OnyxParser* parser); -static AstLocal* parse_function_params(OnyxParser* parser); +static void parse_function_params(OnyxParser* parser, AstFunction* func); static b32 parse_possible_directive(OnyxParser* parser, const char* dir); static AstFunction* parse_function_definition(OnyxParser* parser); static AstTyped* parse_global_declaration(OnyxParser* parser); @@ -1343,25 +1343,23 @@ static AstStructType* parse_struct(OnyxParser* parser) { // e // '(' (: ,?)* ')' -static AstLocal* parse_function_params(OnyxParser* parser) { +static void parse_function_params(OnyxParser* parser, AstFunction* func) { if (parser->curr->type != '(') - return NULL; + return; expect_token(parser, '('); if (parser->curr->type == ')') { consume_token(parser); - return NULL; + return; } - AstLocal* first_param = NULL; - AstLocal* curr_param = NULL; - AstLocal* trailer = NULL; + AstParam curr_param = { 0 }; b32 param_use = 0; OnyxToken* symbol; while (parser->curr->type != ')') { - if (parser->hit_unexpected_token) return first_param; + if (parser->hit_unexpected_token) return; if (parser->curr->type == Token_Type_Keyword_Use) { consume_token(parser); @@ -1371,29 +1369,35 @@ static AstLocal* parse_function_params(OnyxParser* parser) { symbol = expect_token(parser, Token_Type_Symbol); expect_token(parser, ':'); - curr_param = make_node(AstLocal, Ast_Kind_Param); - curr_param->token = symbol; - curr_param->flags |= Ast_Flag_Const; - curr_param->type_node = parse_type(parser); + curr_param.local = make_node(AstLocal, Ast_Kind_Param); + curr_param.local->token = symbol; + curr_param.local->flags |= Ast_Flag_Const; if (param_use) { - curr_param->flags |= Ast_Flag_Param_Use; + curr_param.local->flags |= Ast_Flag_Param_Use; param_use = 0; } - if (first_param == NULL) first_param = curr_param; + if (parser->curr->type != '=') { + curr_param.local->type_node = parse_type(parser); + } + + if (parser->curr->type == '=') { + consume_token(parser); + + curr_param.default_value = parse_expression(parser); + } - curr_param->next = NULL; - if (trailer) trailer->next = (AstNode *) curr_param; + bh_arr_push(func->params, curr_param); - trailer = curr_param; + curr_param.default_value = NULL; if (parser->curr->type != ')') expect_token(parser, ','); } consume_token(parser); // Skip the ) - return first_param; + return; } // e @@ -1415,9 +1419,11 @@ static b32 parse_possible_directive(OnyxParser* parser, const char* dir) { // 'proc' * ('->' )? static AstFunction* parse_function_definition(OnyxParser* parser) { AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function); - bh_arr_new(global_heap_allocator, func_def->locals, 4); func_def->token = expect_token(parser, Token_Type_Keyword_Proc); + bh_arr_new(global_heap_allocator, func_def->locals, 4); + bh_arr_new(global_heap_allocator, func_def->params, 4); + while (parser->curr->type == '#') { if (parse_possible_directive(parser, "overloaded")) { AstOverloadedFunction* ofunc = make_node(AstOverloadedFunction, Ast_Kind_Overloaded_Function); @@ -1484,8 +1490,7 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { } } - AstLocal* params = parse_function_params(parser); - func_def->params = params; + parse_function_params(parser, func_def); AstType* return_type = (AstType *) &basic_type_void; if (parser->curr->type == Token_Type_Right_Arrow) { @@ -1493,27 +1498,7 @@ static AstFunction* parse_function_definition(OnyxParser* parser) { return_type = parse_type(parser); } - - u64 param_count = 0; - for (AstLocal* param = params; - param != NULL; - param = (AstLocal *) param->next) - param_count++; - - AstFunctionType* type_node = bh_alloc(parser->allocator, sizeof(AstFunctionType) + param_count * sizeof(AstType *)); - type_node->kind = Ast_Kind_Function_Type; - type_node->param_count = param_count; - type_node->return_type = return_type; - - u32 i = 0; - for (AstLocal* param = params; - param != NULL; - param = (AstLocal *) param->next) { - type_node->params[i] = param->type_node; - i++; - } - - func_def->type_node = (AstType *) type_node; + func_def->return_type = return_type; func_def->body = parse_block(parser); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index ba6776fe..bb0d3875 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -463,42 +463,65 @@ static void symres_function(AstFunction* func) { if (func->scope == NULL) func->scope = scope_create(semstate.node_allocator, semstate.curr_scope); + bh_arr_each(AstParam, param, func->params) { + if (param->default_value != NULL) { + symres_expression(¶m->default_value); + if (check_expression(¶m->default_value)) return; + } + } + + func->return_type = symres_type(func->return_type); + scope_enter(func->scope); - for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) { - param->type_node = symres_type(param->type_node); - param->type = type_build_from_ast(semstate.allocator, param->type_node); + bh_arr_each(AstParam, param, func->params) { + if (param->local->type_node != NULL) { + param->local->type_node = symres_type(param->local->type_node); + param->local->type = type_build_from_ast(semstate.allocator, param->local->type_node); + + if (param->default_value != NULL) { + if (!types_are_compatible(param->local->type, param->default_value->type)) { + onyx_message_add(Msg_Type_Assignment_Mismatch, + param->local->token->pos, + type_get_name(param->local->type), + type_get_name(param->default_value->type)); + return; + } + } + } else { + param->local->type = param->default_value->type; + } - if (param->type == NULL) break; + if (param->local->type == NULL) break; - symbol_introduce(semstate.curr_scope, param->token, (AstNode *) param); + symbol_introduce(semstate.curr_scope, param->local->token, (AstNode *) param->local); - if (param->flags & Ast_Flag_Param_Use) { - if (type_is_struct(param->type)) { + if (param->local->flags & Ast_Flag_Param_Use) { + if (type_is_struct(param->local->type)) { AstStructType* st; - if (param->type->kind == Type_Kind_Struct) { - st = (AstStructType *) param->type_node; + if (param->local->type->kind == Type_Kind_Struct) { + st = (AstStructType *) param->local->type_node; } else { - st = (AstStructType *) ((AstPointerType *) param->type_node)->elem; + st = (AstStructType *) ((AstPointerType *) param->local->type_node)->elem; } bh_arr_each(AstStructMember *, mem, st->members) { AstFieldAccess* fa = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access); fa->token = (*mem)->token; fa->type_node = (*mem)->type_node; - fa->expr = (AstTyped *) param; + fa->expr = (AstTyped *) param->local; token_toggle_end((*mem)->token); symbol_raw_introduce(semstate.curr_scope, (*mem)->token->text, - param->token->pos, + param->local->token->pos, (AstNode *) fa); token_toggle_end((*mem)->token); } } else { onyx_message_add(Msg_Type_Literal, - param->token->pos, + param->local->token->pos, "can only 'use' structures or pointers to structures."); } } diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 602c5dc9..a3e93e54 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -369,27 +369,22 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { } } -// NOTE: Kinda hacky way of building the functions type -Type* type_build_function_type(bh_allocator alloc, AstFunction* func, AstType* return_type) { - u64 param_count = 0; - for (AstLocal* param = func->params; - param != NULL; - param = (AstLocal *) param->next) - param_count++; - - AstFunctionType* old_ftype = (AstFunctionType *) func->type_node; +Type* type_build_function_type(bh_allocator alloc, AstFunction* func) { + u64 param_count = bh_arr_length(func->params); + Type* func_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * param_count); func_type->kind = Type_Kind_Function; func_type->Function.param_count = param_count; - func_type->Function.return_type = type_build_from_ast(alloc, return_type); + func_type->Function.needed_param_count = 0; + func_type->Function.return_type = type_build_from_ast(alloc, func->return_type); if (param_count > 0) { i32 i = 0; - for (AstLocal* param = func->params; - param != NULL; - param = (AstLocal *) param->next) { - func_type->Function.params[i++] = param->type; + bh_arr_each(AstParam, param, func->params) { + if (param->default_value == NULL) + func_type->Function.needed_param_count++; + func_type->Function.params[i++] = param->local->type; } } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 2da94b78..77e94198 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -1988,13 +1988,13 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { if (fd->body != NULL) { // NOTE: Generate the local map u64 localidx = 0; - for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->next) { - if (param->type->kind == Type_Kind_Struct) { - bh_imap_put(&mod->local_map, (u64) param, localidx | LOCAL_IS_WASM); - localidx += param->type->Struct.mem_count; + bh_arr_each(AstParam, param, fd->params) { + if (param->local->type->kind == Type_Kind_Struct) { + bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM); + localidx += param->local->type->Struct.mem_count; } else { - bh_imap_put(&mod->local_map, (u64) param, localidx++ | LOCAL_IS_WASM); + bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM); } }