added default parameters; will need to be bug tested thoroughly
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 26 Aug 2020 03:41:05 +0000 (22:41 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 26 Aug 2020 03:41:05 +0000 (22:41 -0500)
15 files changed:
core/alloc.onyx
core/builtin.onyx
core/string.onyx
docs/plan
include/onyxastnodes.h
include/onyxsempass.h
include/onyxtypes.h
misc/onyx.sublime-syntax
onyx
progs/wasi_test.onyx
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxwasm.c

index eb01f0cae2794bc4da852c153f4e84ce81d4949d..0f5694dabb510984c4c53c661b7f30a81e1bf531 100644 (file)
@@ -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
index 58fdd589dddb69f114593dd9c6a8361c437aa5fb..08522136d93d265a43d34395c518bd8bf4acb94e 100644 (file)
@@ -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
index 0668398f610e63e7bd9e97562c752032c9ae9bc4..401978a241cdaf9948f7b8f17a5c78b2c55ecdb1 100644 (file)
@@ -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,
 }
 
index f928a5a39c6da990d46a125867efaca01ad3e551..7407f8977c91cbc6bc917b556ddf7872c91ef59e 100644 (file)
--- 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
 
index f7a103bfae7648065e3c8e52363b3a37a46a3446..512160aeab3c6999c1035530680fe752406405aa 100644 (file)
@@ -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 {
index 7dbed0a3756eb4155d0af63d802262978d203dea..dc131d8e3b0eb6aa98e1603449b30022af557b22 100644 (file)
@@ -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);
index 1bfd25a5568ae3c2610387567274f2948ab6ceef..38c4595e76eaeae412b4672340b654cb73be75e3 100644 (file)
@@ -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);
index 6a4c460636eeec64ed798fc692c7981fd123743e..6356d84f162c8f8ad1efdcfbb9360025c76809ff 100644 (file)
@@ -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 77225f13f1ea77ff40f8280966f62d2d24b257cd..87ede097129ea42770a83e387043ef4b6e8266e2 100755 (executable)
Binary files a/onyx and b/onyx differ
index 55af2806fa18040d20ec5e3e63738637979538a2..94ee0f1575fa7bb9dc6a8a936c28e0a68e790b7e 100644 (file)
@@ -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
index d8f950529a4643851a586651245115df73eb61d5..2d75f55b19fe4b5c77c4700bfe3797eb48cc9f8b 100644 (file)
@@ -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);
index e798391c1b8486a1abfb785d25144a7ccc294c2b..520bd6e83b6fbbe07504be90e91821e8e1e64ea0 100644 (file)
@@ -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
 // '(' (<symbol>: <type>,?)* ')'
-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' <directive>* <func_params> ('->' <type>)? <block>
 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);
 
index ba6776fe4c7908461543ab5c681d4a6ffe5d2c5c..bb0d3875f0a094e0463796f191a34fa26b5acabd 100644 (file)
@@ -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(&param->default_value);
+            if (check_expression(&param->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.");
             }
         }
index 602c5dc94e90cda675e680e8e10b1eb016540ca6..a3e93e540c1d094d8806d800d25b8e2bed0881e5 100644 (file)
@@ -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;
         }
     }
 
index 2da94b78b707c7038e0798b5266cf2e475807fd5..77e941980c45a1dad89f416ae367515b484c1e6a 100644 (file)
@@ -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);
             }
         }