Started the basics of polymorphic procedures. code clean and bugfixes to follow.
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 28 Aug 2020 21:58:32 +0000 (16:58 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 28 Aug 2020 21:58:32 +0000 (16:58 -0500)
14 files changed:
Makefile
include/onyxastnodes.h
include/onyxsempass.h
onyx
progs/wasi_test.onyx
src/onyx.c
src/onyxchecker.c
src/onyxclone.c [new file with mode: 0644]
src/onyxparser.c
src/onyxsempass.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index 5024779245de6187b97cb3a6b616ef7bf245e5a0..177c8395c7cbb5f6629180f4644f4c60a2a190bf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ RELEASE=0
 OBJ_FILES=\
        build/onyxlex.o \
        build/onyxparser.o \
+       build/onyxclone.o \
        build/onyxtypes.o \
        build/onyxbuiltins.o \
        build/onyxsempass.o \
@@ -22,7 +23,7 @@ TARGET=./onyx
 ifeq ($(RELEASE), 1)
        FLAGS=-O3
 else
-       FLAGS=-g3 -Og
+       FLAGS=-g3
 endif
 
 build/%.o: src/%.c include/bh.h
index 6e8cd47d0014753fa660c8b6cf7a808ae21aeab3..3caeed36673cfb4ef1b7b8c3204c15e202ebad0a 100644 (file)
@@ -4,7 +4,6 @@
 #include "onyxlex.h"
 #include "onyxtypes.h"
 
-
 typedef struct AstNode AstNode;
 typedef struct AstTyped AstTyped;
 
@@ -47,6 +46,7 @@ typedef struct AstStructMember AstStructMember;
 typedef struct AstEnumType AstEnumType;
 typedef struct AstEnumValue AstEnumValue;
 typedef struct AstTypeAlias AstTypeAlias;
+typedef struct AstTypeRawAlias AstTypeRawAlias;
 
 typedef struct AstBinding AstBinding;
 typedef struct AstMemRes AstMemRes;
@@ -58,6 +58,9 @@ typedef struct AstParam AstParam;
 typedef struct AstFunction AstFunction;
 typedef struct AstOverloadedFunction AstOverloadedFunction;
 
+typedef struct AstPolyParam AstPolyParam;
+typedef struct AstPolyProc AstPolyProc;
+
 typedef struct AstPackage AstPackage;
 typedef struct Package Package;
 
@@ -82,6 +85,7 @@ typedef enum AstKind {
     Ast_Kind_Binding,
     Ast_Kind_Function,
     Ast_Kind_Overloaded_Function,
+    Ast_Kind_Polymorphic_Proc,
     Ast_Kind_Block,
     Ast_Kind_Local_Group,
     Ast_Kind_Local,
@@ -101,6 +105,7 @@ typedef enum AstKind {
     Ast_Kind_Struct_Type,
     Ast_Kind_Enum_Type,
     Ast_Kind_Type_Alias,
+    Ast_Kind_Type_Raw_Alias,
     Ast_Kind_Type_End,
 
     Ast_Kind_Struct_Member,
@@ -168,6 +173,8 @@ typedef enum AstFlags {
 
     // Struct flags
     Ast_Flag_Struct_Is_Union   = BH_BIT(17),
+
+    Ast_Flag_No_Clone          = BH_BIT(18),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -409,8 +416,9 @@ struct AstEnumType {
     // NOTE: Used to cache the actual type for the same reason as above.
     Type *etcache;
 };
-struct AstEnumValue { AstTyped_base; AstNumLit* value; };
-struct AstTypeAlias { AstType_base; AstType* to; };
+struct AstEnumValue    { AstTyped_base; AstNumLit* value; };
+struct AstTypeAlias    { AstType_base; AstType* to; };
+struct AstTypeRawAlias { AstType_base; Type* to; };
 
 // Top level nodes
 struct AstBinding       { AstTyped_base; AstNode* node; };
@@ -465,12 +473,15 @@ struct AstFunction      {
         };
     };
 };
+struct AstPolyParam { AstNode* poly_sym; AstType* type_expr; u64 idx; };
 struct AstPolyProc {
     AstNode_base;
 
     Scope *poly_scope;
+    bh_arr(AstPolyParam) poly_params;
 
-    AstFunction* func;
+    AstFunction* base_func;
+    bh_table(AstFunction *) concrete_funcs;
 };
 struct AstOverloadedFunction {
     AstTyped_base;
@@ -493,6 +504,7 @@ typedef enum EntityType {
     Entity_Type_Enum,
     Entity_Type_Type_Alias,
     Entity_Type_Memory_Reservation,
+    Entity_Type_Polymorphic_Proc,
     Entity_Type_Function_Header,
     Entity_Type_Global_Header,
     Entity_Type_Expression,
@@ -516,6 +528,7 @@ typedef struct Entity {
         AstType               *type_alias;
         AstEnumType           *enum_type;
         AstMemRes             *mem_res;
+        AstPolyProc           *poly_proc;
     };
 } Entity;
 
@@ -538,7 +551,7 @@ typedef struct ProgramInfo {
     u32 foreign_global_count;
 } ProgramInfo;
 
-
+i32 sort_entities(const void* e1, const void* e2);
 
 // NOTE: Basic internal types constructed in the parser
 extern AstBasicType basic_type_void;
@@ -572,7 +585,9 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog);
 
 // NOTE: Useful not inlined functions
 AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
+AstNode* ast_clone(bh_allocator a, void* n);
 void promote_numlit_to_larger(AstNumLit* num);
+AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call);
 
 // NOTE: Useful inlined functions
 static inline b32 is_lval(AstNode* node) {
index dc131d8e3b0eb6aa98e1603449b30022af557b22..5a61171a0d0bb225389cb23d2efee94ad3dff0ae 100644 (file)
@@ -14,6 +14,7 @@ typedef struct SemState {
 
     // NOTE: Used wherever
     ProgramInfo* program;
+    bh_arr(Entity) other_entities;
 
     // NOTE: Used in symbol resolution phase
     Package*           curr_package;
@@ -33,10 +34,14 @@ extern SemState semstate;
 // NOTE: Resolving all symbols in the tree
 void onyx_resolve_symbols();
 
+void symres_function(AstFunction* func);
+
 // NOTE: Inferring and checking types in the tree
 void onyx_type_check();
 
 b32 check_expression(AstTyped** expr);
+b32 check_function_header(AstFunction* func);
+b32 check_function(AstFunction* func);
 
 // NOTE: Full semantic pass
 void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc);
diff --git a/onyx b/onyx
index 74d31f3930a03e03b390397a086f2c907692aeb0..266cba25507d8cfc8bfed300bca9711496cc217b 100755 (executable)
Binary files a/onyx and b/onyx differ
index aacdbb4807cbe22262a6a39f1e25f8db8d961695..3dc37daa47a75e0fe5b020b58f5da4c4b3f0c171 100644 (file)
@@ -23,40 +23,40 @@ use package random
 use package file
 use package stdio
 
-print_rights :: proc (rights: Rights) {
-    print(cast(u32) rights, 2);
-    print("\n");
-
-    if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
-    if rights & Rights.Read != cast(Rights) 0 do print("Read\n");
-    if rights & Rights.Seek != cast(Rights) 0 do print("Seek\n");
-    if rights & Rights.FdStatSetFlags != cast(Rights) 0 do print("FdStatSetFlags\n");
-    if rights & Rights.Sync != cast(Rights) 0 do print("Sync\n");
-    if rights & Rights.Tell != cast(Rights) 0 do print("Tell\n");
-    if rights & Rights.Write != cast(Rights) 0 do print("Write\n");
-    if rights & Rights.Advise != cast(Rights) 0 do print("Advise\n");
-    if rights & Rights.Allocate != cast(Rights) 0 do print("Allocate\n");
-    if rights & Rights.PathCreateDirectory != cast(Rights) 0 do print("PathCreateDirectory\n");
-    if rights & Rights.PathCreateFile != cast(Rights) 0 do print("PathCreateFile\n");
-    if rights & Rights.PathLinkSource != cast(Rights) 0 do print("PathLinkSource\n");
-    if rights & Rights.PathLinkTarget != cast(Rights) 0 do print("PathLinkTarget\n");
-    if rights & Rights.PathOpen != cast(Rights) 0 do print("PathOpen\n");
-    if rights & Rights.ReadDir != cast(Rights) 0 do print("ReadDir\n");
-    if rights & Rights.PathReadlink != cast(Rights) 0 do print("PathReadlink\n");
-    if rights & Rights.PathRenameSource != cast(Rights) 0 do print("PathRenameSource\n");
-    if rights & Rights.PathRenameTarget != cast(Rights) 0 do print("PathRenameTarget\n");
-    if rights & Rights.PathFilestatGet != cast(Rights) 0 do print("PathFilestatGet\n");
-    if rights & Rights.PathFilestateSetSize != cast(Rights) 0 do print("PathFilestateSetSize\n");
-    if rights & Rights.PathFilestateSetTimes != cast(Rights) 0 do print("PathFilestateSetTimes\n");
-    if rights & Rights.FilestatGet != cast(Rights) 0 do print("FilestatGet\n");
-    if rights & Rights.FilestatSetSize != cast(Rights) 0 do print("FilestatSetSize\n");
-    if rights & Rights.FilestatSetTimes != cast(Rights) 0 do print("FilestatSetTimes\n");
-    if rights & Rights.PathSymlink != cast(Rights) 0 do print("PathSymlink\n");
-    if rights & Rights.PathRemoveDirectory != cast(Rights) 0 do print("PathRemoveDirectory\n");
-    if rights & Rights.PathUnlinkFile != cast(Rights) 0 do print("PathUnlinkFile\n");
-    if rights & Rights.PollFDReadWrite != cast(Rights) 0 do print("PollFDReadWrite\n");
-    if rights & Rights.SockShutdown != cast(Rights) 0 do print("SockShutdown\n");
-}
+// print_rights :: proc (rights: Rights) {
+//     print(cast(u32) rights, 2);
+//     print("\n");
+// 
+//     if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n");
+//     if rights & Rights.Read != cast(Rights) 0 do print("Read\n");
+//     if rights & Rights.Seek != cast(Rights) 0 do print("Seek\n");
+//     if rights & Rights.FdStatSetFlags != cast(Rights) 0 do print("FdStatSetFlags\n");
+//     if rights & Rights.Sync != cast(Rights) 0 do print("Sync\n");
+//     if rights & Rights.Tell != cast(Rights) 0 do print("Tell\n");
+//     if rights & Rights.Write != cast(Rights) 0 do print("Write\n");
+//     if rights & Rights.Advise != cast(Rights) 0 do print("Advise\n");
+//     if rights & Rights.Allocate != cast(Rights) 0 do print("Allocate\n");
+//     if rights & Rights.PathCreateDirectory != cast(Rights) 0 do print("PathCreateDirectory\n");
+//     if rights & Rights.PathCreateFile != cast(Rights) 0 do print("PathCreateFile\n");
+//     if rights & Rights.PathLinkSource != cast(Rights) 0 do print("PathLinkSource\n");
+//     if rights & Rights.PathLinkTarget != cast(Rights) 0 do print("PathLinkTarget\n");
+//     if rights & Rights.PathOpen != cast(Rights) 0 do print("PathOpen\n");
+//     if rights & Rights.ReadDir != cast(Rights) 0 do print("ReadDir\n");
+//     if rights & Rights.PathReadlink != cast(Rights) 0 do print("PathReadlink\n");
+//     if rights & Rights.PathRenameSource != cast(Rights) 0 do print("PathRenameSource\n");
+//     if rights & Rights.PathRenameTarget != cast(Rights) 0 do print("PathRenameTarget\n");
+//     if rights & Rights.PathFilestatGet != cast(Rights) 0 do print("PathFilestatGet\n");
+//     if rights & Rights.PathFilestateSetSize != cast(Rights) 0 do print("PathFilestateSetSize\n");
+//     if rights & Rights.PathFilestateSetTimes != cast(Rights) 0 do print("PathFilestateSetTimes\n");
+//     if rights & Rights.FilestatGet != cast(Rights) 0 do print("FilestatGet\n");
+//     if rights & Rights.FilestatSetSize != cast(Rights) 0 do print("FilestatSetSize\n");
+//     if rights & Rights.FilestatSetTimes != cast(Rights) 0 do print("FilestatSetTimes\n");
+//     if rights & Rights.PathSymlink != cast(Rights) 0 do print("PathSymlink\n");
+//     if rights & Rights.PathRemoveDirectory != cast(Rights) 0 do print("PathRemoveDirectory\n");
+//     if rights & Rights.PathUnlinkFile != cast(Rights) 0 do print("PathUnlinkFile\n");
+//     if rights & Rights.PollFDReadWrite != cast(Rights) 0 do print("PollFDReadWrite\n");
+//     if rights & Rights.SockShutdown != cast(Rights) 0 do print("SockShutdown\n");
+// }
 
 readline :: proc (buf: ^u8, bufsize: u32) -> u32 {
     iov := IOVec.{ buf, bufsize };
@@ -137,8 +137,8 @@ output_s :: proc (sb: ^StringBuilder, s: ^S) -> ^StringBuilder {
     return sb;
 }
 
-print_arr :: proc (sb: ^StringBuilder, arr: []i32) {
-    sb  |> string_builder_clear();
+print_arr :: proc (sb: ^StringBuilder, arr: [] $T) {
+    sb |> string_builder_clear();
 
     for i: 0, arr.count {
         sb |> sba(cast(u64) arr[i]) |> sba(" ");
@@ -278,6 +278,21 @@ main :: proc (args: []cstring) {
     print_u64(cast(u64) sl.count);
 
     print_u64(cast(u64) fib(20));
+    print("\n");
+
+    print(add(20l, 5l));
+    print("\n");
+    print(cast(u64) add(20.0f, 5.0f));
+    print("\n");
+
+    slice := make_slice(cast(^u32) 1234, 5678);
+    print(cast(u64) slice.data);
+    print("\n");
+    print(cast(u64) get_slice_length(^slice));
+    print("\n");
+
+    print(multi_poly(5.4f, 10l));
+    print("\n");
 }
 
 foobar :: proc (a: i32, b := 1, c := 5l) {
@@ -301,6 +316,16 @@ fib :: proc (n: i32) -> i32 {
     return 0;
 }
 
-// make_slice :: proc (ptr: ^$T, count: u32) -> [] T {
-//     return ptr[0 : count];
-// }
\ No newline at end of file
+add :: proc (a: $T, b: T) -> T {
+    return a + b;
+}
+
+multi_poly :: proc (a: $T, b: $R) -> R {
+    return cast(R) (a + cast(T) b);
+}
+
+make_slice :: proc (ptr: ^$T, count: u32) -> [] T {
+    return ptr[4 : count];
+}
+
+get_slice_length :: proc (s: ^[] $T) -> u32 do return s.count;
\ No newline at end of file
index 3234249cdcd3d4ccffd62b7ff52dacc16cd29323..4a86739724bd39705464b8bb410c61717182f962 100644 (file)
@@ -199,10 +199,6 @@ static ParseResults parse_source_file(CompilerState* compiler_state, bh_file_con
     return onyx_parse(&parser);
 }
 
-static i32 sort_entities(const void* e1, const void* e2) {
-    return ((Entity *)e1)->type - ((Entity *)e2)->type;
-}
-
 static void merge_parse_results(CompilerState* compiler_state, ParseResults* results) {
     bh_arr_each(AstInclude *, include, results->includes) {
         if ((*include)->kind == Ast_Kind_Include_File) {
@@ -296,6 +292,13 @@ static void merge_parse_results(CompilerState* compiler_state, ParseResults* res
                 break;
             }
 
+            case Ast_Kind_Polymorphic_Proc: {
+                ent.type = Entity_Type_Polymorphic_Proc;
+                ent.poly_proc = (AstPolyProc *) node;
+                bh_arr_push(compiler_state->prog_info.entities, ent);
+                break;
+            }
+
             default: {
                 ent.type = Entity_Type_Expression;
                 ent.expr = (AstTyped *) node;
index 4f159ec9954ef05003c9e521d7a0f909e792b928..8fbadea223a68e00aae1a0ac5e54de4db1bf8151 100644 (file)
@@ -288,6 +288,13 @@ b32 check_call(AstCall* call) {
         if (callee == NULL) return 1;
     }
 
+    if (callee->kind == Ast_Kind_Polymorphic_Proc) {
+        call->callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) call->callee, call);
+        if (call->callee == NULL) return 1;
+
+        callee = (AstFunction *) call->callee;
+    }
+
     // NOTE: Build callee's type
     fill_in_type((AstTyped *) callee);
 
@@ -1037,6 +1044,10 @@ b32 check_expression(AstTyped** pexpr) {
 
         case Ast_Kind_Memres: break;
 
+        case Ast_Kind_Polymorphic_Proc: break;
+
+        case Ast_Kind_Error: break;
+
         default:
             retval = 1;
             DEBUG_HERE;
@@ -1189,7 +1200,7 @@ b32 check_struct(AstStructType* s_node) {
 }
 
 b32 check_function_header(AstFunction* func) {
-    b32 expect_default_param = 0;    
+    b32 expect_default_param = 0;
 
     bh_arr_each(AstParam, param, func->params) {
         AstLocal* local = param->local;
@@ -1346,6 +1357,8 @@ void onyx_type_check() {
 
             case Entity_Type_Use_Package: break;
 
+            case Entity_Type_Polymorphic_Proc: break;
+
             default: DEBUG_HERE; break;
         }
     }
diff --git a/src/onyxclone.c b/src/onyxclone.c
new file mode 100644 (file)
index 0000000..f6c4b0f
--- /dev/null
@@ -0,0 +1,309 @@
+#include "onyxastnodes.h"
+#include "onyxparser.h"
+#include "onyxutils.h"
+
+static inline b32 should_clone(AstNode* node) {
+       if (node->flags & Ast_Flag_No_Clone) return 0;
+
+       switch (node->kind) {
+               // List of nodes that should not be copied
+               case Ast_Kind_Global:
+               case Ast_Kind_Memres:
+               case Ast_Kind_NumLit:
+               case Ast_Kind_StrLit:
+               case Ast_Kind_Package:
+               case Ast_Kind_Function_Type:
+               case Ast_Kind_Struct_Type:
+               case Ast_Kind_Enum_Type:
+               case Ast_Kind_Enum_Value:
+               case Ast_Kind_Overloaded_Function:
+               case Ast_Kind_Polymorphic_Proc:
+               return 0;
+
+               default: return 1;
+       }
+}
+
+static inline i32 ast_kind_to_size(AstKind kind) {
+       switch (kind) {
+        case Ast_Kind_Error: return sizeof(AstNode);
+        case Ast_Kind_Program: return sizeof(AstNode);
+        case Ast_Kind_Package: return sizeof(AstPackage);
+        case Ast_Kind_Include_File: return sizeof(AstInclude);
+        case Ast_Kind_Include_Folder: return sizeof(AstInclude);
+        case Ast_Kind_Use_Package: return sizeof(AstUsePackage);
+        case Ast_Kind_Alias: return sizeof(AstAlias);
+        case Ast_Kind_Memres: return sizeof(AstMemRes);
+        case Ast_Kind_Binding: return sizeof(AstBinding);
+        case Ast_Kind_Function: return sizeof(AstFunction);
+        case Ast_Kind_Overloaded_Function: return sizeof(AstOverloadedFunction);
+        case Ast_Kind_Polymorphic_Proc: return sizeof(AstPolyProc);
+        case Ast_Kind_Block: return sizeof(AstBlock);
+        case Ast_Kind_Local_Group: return sizeof(AstNode);
+        case Ast_Kind_Local: return sizeof(AstLocal);
+        case Ast_Kind_Global: return sizeof(AstGlobal);
+        case Ast_Kind_Symbol: return sizeof(AstNode);
+        case Ast_Kind_Unary_Op: return sizeof(AstUnaryOp);
+        case Ast_Kind_Binary_Op: return sizeof(AstBinaryOp);
+        case Ast_Kind_Type_Start: return 0;
+        case Ast_Kind_Type: return sizeof(AstType);
+        case Ast_Kind_Basic_Type: return sizeof(AstBasicType);
+        case Ast_Kind_Pointer_Type: return sizeof(AstPointerType);
+        case Ast_Kind_Function_Type: return sizeof(AstFunctionType);
+        case Ast_Kind_Array_Type: return sizeof(AstArrayType);
+        case Ast_Kind_Slice_Type: return sizeof(AstSliceType);
+        case Ast_Kind_Struct_Type: return sizeof(AstStructType);
+        case Ast_Kind_Enum_Type: return sizeof(AstEnumType);
+        case Ast_Kind_Type_Alias: return sizeof(AstTypeAlias);
+        case Ast_Kind_Type_End: return 0;
+        case Ast_Kind_Struct_Member: return sizeof(AstStructMember);
+        case Ast_Kind_Enum_Value: return sizeof(AstEnumValue);
+        case Ast_Kind_NumLit: return sizeof(AstNumLit);
+        case Ast_Kind_StrLit: return sizeof(AstStrLit);
+        case Ast_Kind_Param: return sizeof(AstLocal);
+        case Ast_Kind_Argument: return sizeof(AstArgument);
+        case Ast_Kind_Call: return sizeof(AstCall);
+        case Ast_Kind_Intrinsic_Call: return sizeof(AstIntrinsicCall);
+        case Ast_Kind_Return: return sizeof(AstReturn);
+        case Ast_Kind_Address_Of: return sizeof(AstAddressOf);
+        case Ast_Kind_Dereference: return sizeof(AstDereference);
+        case Ast_Kind_Array_Access: return sizeof(AstArrayAccess);
+        case Ast_Kind_Slice: return sizeof(AstSlice);
+        case Ast_Kind_Field_Access: return sizeof(AstFieldAccess);
+        case Ast_Kind_Ufc: return sizeof(AstBinaryOp);
+        case Ast_Kind_Size_Of: return sizeof(AstSizeOf);
+        case Ast_Kind_Align_Of: return sizeof(AstAlignOf);
+        case Ast_Kind_File_Contents: return sizeof(AstFileContents);
+        case Ast_Kind_Struct_Literal: return sizeof(AstStructLiteral);
+        case Ast_Kind_If: return sizeof(AstIfWhile);
+        case Ast_Kind_For: return sizeof(AstFor);
+        case Ast_Kind_While: return sizeof(AstIfWhile);
+        case Ast_Kind_Jump: return sizeof(AstJump);
+        case Ast_Kind_Defer: return sizeof(AstDefer);
+        case Ast_Kind_Switch: return sizeof(AstSwitch);
+        case Ast_Kind_Switch_Case: return sizeof(AstSwitchCase);
+        case Ast_Kind_Count: return 0;
+       }
+}
+
+AstNode* ast_clone_list(bh_allocator a, void* n) {
+       AstNode* node = (AstNode *) n;
+       if (node == NULL) return NULL;
+
+       AstNode* root = ast_clone(a, node);
+       AstNode* curr = root->next;
+       AstNode** insertion = &root->next;
+
+       while (curr != NULL) {
+               curr = ast_clone(a, curr);
+               *insertion = curr;
+               insertion = &curr->next;
+               curr = curr->next;
+       }
+
+       return root;
+}
+
+// NOTE: Using void* to avoid a lot of unnecessary casting
+AstNode* ast_clone(bh_allocator a, void* n) {
+       AstNode* node = (AstNode *) n;
+
+       if (node == NULL) return NULL;
+       if (!should_clone(node)) return node;
+
+       i32 node_size = ast_kind_to_size(node->kind);
+       // bh_printf("Cloning %s with size %d\n", onyx_ast_node_kind_string(node->kind), node_size);
+
+       AstNode* nn = onyx_ast_node_new(a, node_size, node->kind);
+       memmove(nn, node, node_size);
+
+       switch (node->kind) {
+               case Ast_Kind_Binary_Op:
+                       ((AstBinaryOp *) nn)->left  = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->left);
+                       ((AstBinaryOp *) nn)->right = (AstTyped *) ast_clone(a, ((AstBinaryOp *) node)->right);
+                       break;
+
+               case Ast_Kind_Unary_Op:
+                       ((AstUnaryOp *) nn)->expr = (AstTyped *) ast_clone(a, ((AstUnaryOp *) node)->expr);
+                       ((AstUnaryOp *) nn)->type_node = (AstType *) ast_clone(a, ((AstUnaryOp *) node)->type_node);
+                       break;
+
+               case Ast_Kind_Local:
+                       ((AstLocal *) nn)->type_node = (AstType *) ast_clone(a, ((AstLocal *) node)->type_node);
+                       break;
+
+               case Ast_Kind_Call:
+                       ((AstCall *) nn)->arguments = (AstArgument *) ast_clone_list(a, ((AstCall *) node)->arguments);
+                       break;
+
+               case Ast_Kind_Argument:
+                       ((AstArgument *) nn)->value = (AstTyped *) ast_clone(a, ((AstArgument *) node)->value);
+                       break;
+
+               case Ast_Kind_Address_Of:
+                       ((AstAddressOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstAddressOf *) node)->expr);
+                       break;
+
+               case Ast_Kind_Dereference:
+                       ((AstDereference *) nn)->expr = (AstTyped *) ast_clone(a, ((AstDereference *) node)->expr);
+                       break;
+
+               case Ast_Kind_Array_Access:
+                       ((AstArrayAccess *) nn)->addr = (AstTyped *) ast_clone(a, ((AstArrayAccess *) node)->addr);
+                       ((AstArrayAccess *) nn)->expr = (AstTyped *) ast_clone(a, ((AstArrayAccess *) node)->expr);
+                       break;
+
+               case Ast_Kind_Slice:
+                       ((AstSlice *) nn)->lo = (AstTyped *) ast_clone(a, ((AstSlice *) node)->lo);
+                       ((AstSlice *) nn)->hi = (AstTyped *) ast_clone(a, ((AstSlice *) node)->hi);
+                       ((AstSlice *) nn)->addr = (AstTyped *) ast_clone(a, ((AstSlice *) node)->addr);
+                       break;
+
+               case Ast_Kind_Field_Access:
+                       ((AstFieldAccess *) nn)->expr = (AstTyped *) ast_clone(a, ((AstFieldAccess *) node)->expr);
+                       break;
+
+               case Ast_Kind_Size_Of:
+                       ((AstSizeOf *) nn)->so_type = (AstType *) ast_clone(a, ((AstSizeOf *) node)->so_type);
+                       break;
+
+               case Ast_Kind_Align_Of:
+                       ((AstAlignOf *) nn)->ao_type = (AstType *) ast_clone(a, ((AstAlignOf *) node)->ao_type);
+                       break;
+
+               case Ast_Kind_Struct_Literal: {
+                       AstStructLiteral* st = (AstStructLiteral *) node;
+                       AstStructLiteral* dt = (AstStructLiteral *) nn;
+
+                       dt->stnode = (AstTyped *) ast_clone(a, st->stnode);
+
+                       dt->named_values = NULL;
+                       dt->values = NULL;
+                       bh_arr_new(global_heap_allocator, dt->named_values, bh_arr_length(st->named_values));
+                       bh_arr_new(global_heap_allocator, dt->values, bh_arr_length(st->values));
+
+                       bh_arr_each(AstStructMember *, smem, st->named_values)
+                               bh_arr_push(dt->named_values, (AstStructMember *) ast_clone(a, *smem));
+
+                       bh_arr_each(AstTyped *, val, st->values)
+                               bh_arr_push(dt->values, (AstTyped *) ast_clone(a, *val));
+
+                       break;
+               }
+
+               case Ast_Kind_Return:
+                       ((AstReturn *) nn)->expr = (AstTyped *) ast_clone(a, ((AstReturn *) node)->expr);
+                       break;
+
+               case Ast_Kind_Block:
+                       ((AstBlock *) nn)->body = ast_clone_list(a, ((AstBlock *) node)->body);
+                       ((AstBlock *) nn)->locals = NULL;
+                       break;
+
+               case Ast_Kind_Defer:
+                       ((AstDefer *) nn)->stmt = ast_clone(a, ((AstDefer *) node)->stmt);
+                       break;
+
+               case Ast_Kind_For:
+                       ((AstFor *) nn)->var = (AstLocal *) ast_clone(a, ((AstFor *) node)->var);
+                       ((AstFor *) nn)->start = (AstTyped *) ast_clone(a, ((AstFor *) node)->start);
+                       ((AstFor *) nn)->end = (AstTyped *) ast_clone(a, ((AstFor *) node)->end);
+                       ((AstFor *) nn)->step = (AstTyped *) ast_clone(a, ((AstFor *) node)->step);
+                       ((AstFor *) nn)->stmt = (AstBlock *) ast_clone(a, ((AstFor *) node)->stmt);
+                       break;
+
+               case Ast_Kind_If:
+               case Ast_Kind_While:
+                       ((AstIfWhile *) nn)->local = (AstLocal *) ast_clone(a, ((AstIfWhile *) node)->local);
+                       ((AstIfWhile *) nn)->assignment = (AstBinaryOp *) ast_clone(a, ((AstIfWhile *) node)->assignment);
+                       ((AstIfWhile *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfWhile *) node)->cond);                     
+                       ((AstIfWhile *) nn)->true_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->true_stmt);
+                       ((AstIfWhile *) nn)->false_stmt = (AstBlock *) ast_clone(a, ((AstIfWhile *) node)->false_stmt);
+                       break;
+
+               case Ast_Kind_Switch: {
+                       AstSwitch* dw = (AstSwitch *) nn;
+                       AstSwitch* sw = (AstSwitch *) node;
+
+                       dw->local = (AstLocal *) ast_clone(a, sw->local);
+                       dw->assignment = (AstBinaryOp *) ast_clone(a, sw->assignment);
+                       dw->expr = (AstTyped *) ast_clone(a, sw->expr);
+
+                       dw->default_case = (AstBlock *) ast_clone(a, sw->default_case);
+                       
+                       dw->cases = NULL;
+                       bh_arr_new(global_heap_allocator, dw->cases, bh_arr_length(sw->cases));
+
+                       bh_arr_each(AstSwitchCase, c, sw->cases) {
+                               AstSwitchCase sc;
+                               sc.value = (AstTyped *) ast_clone(a, c->value);
+                               sc.block = (AstBlock *) ast_clone(a, c->block);
+                               bh_arr_push(dw->cases, sc);
+                       }
+                       break;
+               }
+
+               case Ast_Kind_Pointer_Type:
+                       ((AstPointerType *) nn)->elem = (AstType *) ast_clone(a, ((AstPointerType *) node)->elem);
+                       break;
+
+               case Ast_Kind_Array_Type:
+                       ((AstArrayType *) nn)->count_expr = (AstTyped *) ast_clone(a, ((AstArrayType *) node)->count_expr);
+                       ((AstArrayType *) nn)->elem = (AstType *) ast_clone(a, ((AstArrayType *) node)->elem);
+                       break;
+
+               case Ast_Kind_Slice_Type:
+                       ((AstSliceType *) nn)->elem = (AstType *) ast_clone(a, ((AstSliceType *) node)->elem);
+                       break;
+
+               case Ast_Kind_Type_Alias:
+                       ((AstTypeAlias *) nn)->to = (AstType *) ast_clone(a, ((AstTypeAlias *) node)->to);
+                       break;
+
+               case Ast_Kind_Binding:
+                       bh_printf("Cloning binding: %b\n", node->token->text, node->token->length);
+                       ((AstTyped *) nn)->type_node = (AstType *) ast_clone(a, ((AstTyped *) node)->type_node);
+                       ((AstBinding *) nn)->node = ast_clone(a, ((AstBinding *) node)->node);
+                       break;
+
+               case Ast_Kind_Function: {
+                       AstFunction* df = (AstFunction *) nn;
+                       AstFunction* sf = (AstFunction *) node;
+
+                       if (sf->flags & Ast_Flag_Foreign) return node;
+
+                       df->return_type = (AstType *) ast_clone(a, sf->return_type);
+                       df->body = (AstBlock *) ast_clone(a, sf->body);
+
+                       df->params = NULL;
+                       bh_arr_new(global_heap_allocator, df->params, bh_arr_length(sf->params));
+
+                       bh_arr_each(AstParam, param, sf->params) {
+                               AstParam new_param;
+                               new_param.local = (AstLocal *) ast_clone(a, param->local);
+                               new_param.default_value = (AstTyped *) ast_clone(a, param->default_value);
+                               bh_arr_push(df->params, new_param);
+                       }
+
+                       break;
+               }
+
+               case Ast_Kind_NumLit:
+               case Ast_Kind_StrLit:
+               case Ast_Kind_File_Contents:
+               case Ast_Kind_Jump:
+               case Ast_Kind_Type:
+               case Ast_Kind_Basic_Type:
+               case Ast_Kind_Struct_Member:
+                       return nn;
+
+               //default: {
+               //      AstNode* new_node = make_node(a, AstNode, node->kind);
+               //      new_node->token = node->token;
+               //      new_node->flags = node->flags;
+               //      new_node->next = ast_clone(a, node->next);
+               //}
+       }
+
+       return nn;
+}
\ No newline at end of file
index e3163cedb9025dabe50111ad5ee29d9510bf06b8..587318b3abf7fd4bba4b670b4fa1c23168629682 100644 (file)
@@ -35,9 +35,9 @@ static b32            parse_possible_symbol_declaration(OnyxParser* parser, AstN
 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 AstType*       parse_type(OnyxParser* parser, bh_arr(AstPolyParam)* polymorphic_vars);
 static AstStructType* parse_struct(OnyxParser* parser);
-static void           parse_function_params(OnyxParser* parser, AstFunction* func);
+static void           parse_function_params(OnyxParser* parser, AstFunction* func, bh_arr(AstPolyParam)* poly_vars);
 static b32            parse_possible_directive(OnyxParser* parser, const char* dir);
 static AstFunction*   parse_function_definition(OnyxParser* parser);
 static AstTyped*      parse_global_declaration(OnyxParser* parser);
@@ -319,7 +319,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
             cast_node->token = expect_token(parser, Token_Type_Keyword_Cast);
             expect_token(parser, '(');
-            cast_node->type_node = parse_type(parser);
+            cast_node->type_node = parse_type(parser, NULL);
             expect_token(parser, ')');
             cast_node->operation = Unary_Op_Cast;
             cast_node->expr = parse_factor(parser);
@@ -331,7 +331,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
         case Token_Type_Keyword_Sizeof: {
             AstSizeOf* so_node = make_node(AstSizeOf, Ast_Kind_Size_Of);
             so_node->token = expect_token(parser, Token_Type_Keyword_Sizeof);
-            so_node->so_type = (AstType *) parse_type(parser);
+            so_node->so_type = (AstType *) parse_type(parser, NULL);
             so_node->type_node = (AstType *) &basic_type_i32;
 
             retval = (AstTyped *) so_node;
@@ -341,7 +341,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
         case Token_Type_Keyword_Alignof: {
             AstAlignOf* ao_node = make_node(AstAlignOf, Ast_Kind_Align_Of);
             ao_node->token = expect_token(parser, Token_Type_Keyword_Alignof);
-            ao_node->ao_type = (AstType *) parse_type(parser);
+            ao_node->ao_type = (AstType *) parse_type(parser, NULL);
             ao_node->type_node = (AstType *) &basic_type_i32;
 
             retval = (AstTyped *) ao_node;
@@ -925,7 +925,7 @@ static b32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret)
     // NOTE: var: type
     if (parser->curr->type != ':'
             && parser->curr->type != '=') {
-        type_node = parse_type(parser);
+        type_node = parse_type(parser, NULL);
     }
 
     AstLocal* local = make_node(AstLocal, Ast_Kind_Local);
@@ -1166,7 +1166,7 @@ static AstBlock* parse_block(OnyxParser* parser) {
 
 // <symbol>
 // '^' <type>
-static AstType* parse_type(OnyxParser* parser) {
+static AstType* parse_type(OnyxParser* parser, bh_arr(AstPolyParam)* poly_vars) {
     AstType* root = NULL;
     AstType** next_insertion = &root;
 
@@ -1210,7 +1210,7 @@ static AstType* parse_type(OnyxParser* parser) {
             while (parser->curr->type != ')') {
                 if (parser->hit_unexpected_token) return root;
 
-                AstType* param_type = parse_type(parser);
+                AstType* param_type = parse_type(parser, NULL);
                 bh_arr_push(params, param_type);
 
                 if (parser->curr->type != ')')
@@ -1221,7 +1221,7 @@ static AstType* parse_type(OnyxParser* parser) {
             AstType* return_type = (AstType *) &basic_type_void;
             if (parser->curr->type == Token_Type_Right_Arrow) {
                 consume_token(parser);
-                return_type = parse_type(parser);
+                return_type = parse_type(parser, NULL);
             }
 
             u64 param_count = bh_arr_length(params);
@@ -1239,6 +1239,32 @@ static AstType* parse_type(OnyxParser* parser) {
             next_insertion = NULL;
         }
 
+        else if (parser->curr->type == '$') {
+            if (poly_vars == NULL) {
+                onyx_message_add(Msg_Type_Literal,
+                        parser->curr->pos,
+                        "polymorphic variable not valid here.");
+            }
+            bh_arr(AstPolyParam) pv = *poly_vars;
+            consume_token(parser);
+
+            AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
+            symbol_node->token = expect_token(parser, Token_Type_Symbol);
+
+            *next_insertion = (AstType *) symbol_node;
+            next_insertion = NULL;
+
+            if (pv != NULL) {
+                bh_arr_push(pv, ((AstPolyParam) {
+                    .poly_sym = symbol_node,
+                    .type_expr = root,
+                    .idx = -1,
+                }));
+
+                *poly_vars = pv;
+            }
+        }
+
         else if (parser->curr->type == Token_Type_Symbol) {
             AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
             symbol_node->token = expect_token(parser, Token_Type_Symbol);
@@ -1325,7 +1351,7 @@ static AstStructType* parse_struct(OnyxParser* parser) {
 
         mem->token = expect_token(parser, Token_Type_Symbol);
         expect_token(parser, ':');
-        mem->type_node = parse_type(parser);
+        mem->type_node = parse_type(parser, NULL);
 
         if (parser->curr->type == '=') {
             consume_token(parser);
@@ -1344,7 +1370,7 @@ static AstStructType* parse_struct(OnyxParser* parser) {
 
 // e
 // '(' (<symbol>: <type>,?)* ')'
-static void parse_function_params(OnyxParser* parser, AstFunction* func) {
+static void parse_function_params(OnyxParser* parser, AstFunction* func, bh_arr(AstPolyParam)* poly_vars) {
     if (parser->curr->type != '(')
         return;
 
@@ -1357,6 +1383,9 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
 
     AstParam curr_param = { 0 };
 
+    u32 param_idx = 0;
+    bh_arr(AstPolyParam) pv = *poly_vars;
+
     b32 param_use = 0;
     OnyxToken* symbol;
     while (parser->curr->type != ')') {
@@ -1380,7 +1409,12 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
         }
 
         if (parser->curr->type != '=') {
-            curr_param.local->type_node = parse_type(parser);
+            u32 old_len = bh_arr_length(pv);
+            curr_param.local->type_node = parse_type(parser, &pv);
+
+            if (old_len != bh_arr_length(pv)) {
+                bh_arr_last(pv).idx = param_idx;
+            }
         }
 
         if (parser->curr->type == '=') {
@@ -1395,8 +1429,12 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
 
         if (parser->curr->type != ')')
             expect_token(parser, ',');
+
+        param_idx++;
     }
 
+    *poly_vars = pv;
+
     consume_token(parser); // Skip the )
     return;
 }
@@ -1425,6 +1463,9 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
     bh_arr_new(global_heap_allocator, func_def->locals, 4);
     bh_arr_new(global_heap_allocator, func_def->params, 4);
 
+    bh_arr(AstPolyParam) polymorphic_vars = NULL;
+    bh_arr_new(global_heap_allocator, polymorphic_vars, 4);
+
     while (parser->curr->type == '#') {
         if (parse_possible_directive(parser, "overloaded")) {
             AstOverloadedFunction* ofunc = make_node(AstOverloadedFunction, Ast_Kind_Overloaded_Function);
@@ -1491,19 +1532,29 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
         }
     }
 
-    parse_function_params(parser, func_def);
+    parse_function_params(parser, func_def, &polymorphic_vars);
 
     AstType* return_type = (AstType *) &basic_type_void;
     if (parser->curr->type == Token_Type_Right_Arrow) {
         expect_token(parser, Token_Type_Right_Arrow);
 
-        return_type = parse_type(parser);
+        return_type = parse_type(parser, NULL);
     }
     func_def->return_type = return_type;
 
     func_def->body = parse_block(parser);
 
-    return func_def;
+    if (bh_arr_length(polymorphic_vars) > 0) {
+        AstPolyProc* pp = make_node(AstPolyProc, Ast_Kind_Polymorphic_Proc);
+        pp->token = func_def->token;
+        pp->poly_params = polymorphic_vars;
+        pp->base_func = func_def;
+
+        return (AstFunction *) pp;
+    } else {
+        bh_arr_free(polymorphic_vars);
+        return func_def;
+    }
 }
 
 // 'global' <type>
@@ -1538,7 +1589,7 @@ static AstTyped* parse_global_declaration(OnyxParser* parser) {
         }
     }
 
-    global_node->type_node = parse_type(parser);
+    global_node->type_node = parse_type(parser, NULL);
 
     add_node_to_process(parser, (AstNode *) global_node);
 
@@ -1621,7 +1672,7 @@ static AstTyped* parse_top_level_expression(OnyxParser* parser) {
     }
     else if (parse_possible_directive(parser, "type")) {
         AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
-        alias->to = parse_type(parser);
+        alias->to = parse_type(parser, NULL);
         return (AstTyped *) alias;
     }
     else if (parser->curr->type == Token_Type_Keyword_Enum) {
@@ -1749,7 +1800,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
                     memres->initial_value = parse_expression(parser);
 
                 } else {
-                    memres->type_node = parse_type(parser);
+                    memres->type_node = parse_type(parser, NULL);
 
                     if (parser->curr->type == '=') {
                         consume_token(parser);
index a29be08210dadc6ffcde2e05aa02a6f7ceb74629..7324468e7251eb61aed3b0f6f36154f974dd88b3 100644 (file)
@@ -13,11 +13,13 @@ void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc) {
         .curr_scope = NULL,
 
         .block_stack = NULL,
+        .other_entities = NULL,
 
         .defer_allowed = 1,
     };
 
     bh_arr_new(global_heap_allocator, semstate.block_stack, 4);
+    bh_arr_new(global_heap_allocator, semstate.other_entities, 4);
 }
 
 void onyx_sempass(ProgramInfo* program) {
@@ -27,5 +29,14 @@ void onyx_sempass(ProgramInfo* program) {
     if (onyx_message_has_errors()) return;
 
     onyx_type_check(program);
+
+    if (bh_arr_length(semstate.other_entities) > 0) {
+        bh_arr_each(Entity, e, semstate.other_entities)
+            bh_arr_push(semstate.program->entities, *e);
+
+        qsort(semstate.program->entities, bh_arr_length(semstate.program->entities), sizeof(Entity), sort_entities);
+        bh_arr_clear(semstate.other_entities);
+    }
+    
     if (onyx_message_has_errors()) return;
 }
index a715b943676df1f9fd52d0da2d9c29b5049a68aa..aa891fad1edb54b09db9d764a507f1e825a7200b 100644 (file)
@@ -23,7 +23,7 @@ static void symres_switch(AstSwitch* switchnode);
 static void symres_statement_chain(AstNode** walker);
 static b32  symres_statement(AstNode** stmt);
 static void symres_block(AstBlock* block);
-static void symres_function(AstFunction* func);
+void symres_function(AstFunction* func);
 static void symres_global(AstGlobal* global);
 static void symres_overloaded_function(AstOverloadedFunction* ofunc);
 static void symres_use_package(AstUsePackage* package);
@@ -461,7 +461,7 @@ static void symres_block(AstBlock* block) {
     scope_leave();
 }
 
-static void symres_function(AstFunction* func) {
+void symres_function(AstFunction* func) {
     if (func->scope == NULL)
         func->scope = scope_create(semstate.node_allocator, semstate.curr_scope);
 
@@ -647,6 +647,10 @@ static void symres_memres(AstMemRes** memres) {
     }
 }
 
+static void symres_polyproc(AstPolyProc* pp) {
+    pp->poly_scope = scope_create(semstate.node_allocator, semstate.curr_scope);
+}
+
 void onyx_resolve_symbols() {
 
     semstate.curr_scope = semstate.program->global_scope;
@@ -666,6 +670,7 @@ void onyx_resolve_symbols() {
             case Entity_Type_Type_Alias:          entity->type_alias = symres_type(entity->type_alias); break;
             case Entity_Type_Enum:                symres_enum(entity->enum_type); break;
             case Entity_Type_Memory_Reservation:  symres_memres(&entity->mem_res); break;
+            case Entity_Type_Polymorphic_Proc:    symres_polyproc(entity->poly_proc); break;
 
             default: break;
         }
index 275f6d9c5e34beb701052c9496d19d41fdca0d92..388c29575857411b19d24ff4c009f3077e5c2fe7 100644 (file)
@@ -373,6 +373,9 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
         case Ast_Kind_Type_Alias:
             return type_build_from_ast(alloc, ((AstTypeAlias *) type_node)->to);
 
+        case Ast_Kind_Type_Raw_Alias:
+            return ((AstTypeRawAlias *) type_node)->to;
+
         case Ast_Kind_Symbol:
             assert(("symbol node in type expression", 0));
             return NULL;
index e8152d23a85805019f983f3321d58b15a725e87f..7498c0eadc2c2289bc64a81f86b7f826227f3b87 100644 (file)
@@ -1,8 +1,13 @@
+#define BH_DEBUG
+
 #include "onyxutils.h"
 #include "onyxlex.h"
 #include "onyxastnodes.h"
 #include "onyxmsgs.h"
 #include "onyxparser.h"
+#include "onyxastnodes.h"
+#include "onyxsempass.h"
+
 
 bh_scratch global_scratch;
 bh_allocator global_scratch_allocator;
@@ -25,6 +30,7 @@ static const char* ast_node_names[] = {
     "BINDING",
     "FUNCTION",
     "OVERLOADED_FUNCTION",
+    "POLYMORPHIC PROC",
     "BLOCK",
     "LOCAL GROUP",
     "LOCAL",
@@ -44,6 +50,7 @@ static const char* ast_node_names[] = {
     "STRUCT TYPE",
     "ENUM TYPE",
     "TYPE_ALIAS",
+    "TYPE RAW ALIAS"
     "TYPE_END (BAD)",
 
     "STRUCT MEMBER",
@@ -70,8 +77,7 @@ static const char* ast_node_names[] = {
     "IF",
     "FOR",
     "WHILE",
-    "BREAK",
-    "CONTINUE",
+    "JUMP",
     "DEFER",
     "SWITCH",
     "SWITCH CASE"
@@ -196,6 +202,10 @@ AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn) {
     return res;
 }
 
+void scope_clear(Scope* scope) {
+    bh_table_clear(scope->symbols);
+}
+
 #define REDUCE_BINOP_ALL(op) \
     if (type_is_small_integer(res->type) || type_is_bool(res->type)) { \
         res->value.i = left->value.i op right->value.i; \
@@ -330,3 +340,89 @@ void promote_numlit_to_larger(AstNumLit* num) {
         num->value.d = val;
     }
 }
+
+static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
+    while (1) {
+        if (type_expr == (AstType *) target) return actual;
+
+        switch (type_expr->kind) {
+            case Ast_Kind_Pointer_Type: {
+                type_expr = ((AstPointerType *) type_expr)->elem;
+                actual = actual->Pointer.elem;
+                break;
+            }
+
+            case Ast_Kind_Slice_Type: {
+                type_expr = ((AstSliceType *) type_expr)->elem;
+                actual = actual->Slice.ptr_to_data->Pointer.elem;
+                break;
+            }
+
+            default:
+                return NULL;
+        }
+    }
+
+    return NULL;
+}
+
+AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, AstCall* call) {
+    if (pp->concrete_funcs == NULL) {
+        bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
+    }
+
+    scope_clear(pp->poly_scope);
+
+    // Currently, not going to do any cacheing
+
+    bh_arr_each(AstPolyParam, param, pp->poly_params) {
+        AstArgument* arg = call->arguments;
+        if (param->idx >= call->arg_count) {
+            onyx_message_add(Msg_Type_Literal,
+                    call->token->pos,
+                    "not enough arguments to polymorphic procedure.");
+            return NULL;
+        }
+
+        fori (i, 0, param->idx) arg = (AstArgument *) arg->next;
+        Type* arg_type = arg->type;
+
+        Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, arg_type);
+
+        if (resolved_type == NULL) {
+            onyx_message_add(Msg_Type_Literal,
+                    call->token->pos,
+                    "unable to match polymorphic procedure type.");
+            return NULL;
+        }
+
+        AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
+        raw->to = resolved_type;
+
+        symbol_introduce(pp->poly_scope, param->poly_sym->token, (AstNode *) raw);
+    }
+
+    semstate.curr_scope = pp->poly_scope;
+
+    AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func);
+    symres_function(func);
+    if (check_function_header(func)) return NULL;
+    if (check_function(func)) return NULL;
+
+    bh_arr_push(semstate.other_entities, ((Entity) {
+        .type = Entity_Type_Function_Header,
+        .function = func,
+        .package = NULL,
+    }));
+    bh_arr_push(semstate.other_entities, ((Entity) {
+        .type = Entity_Type_Function,
+        .function = func,
+        .package = NULL,
+    }));
+
+    return func;
+}
+
+i32 sort_entities(const void* e1, const void* e2) {
+    return ((Entity *)e1)->type - ((Entity *)e2)->type;
+}
index 2adcbfb0914a3532258837f5bc83364bcca3e07a..e82a2015c93706dceffbd0ea9c3e73c9a3c5c2fd 100644 (file)
@@ -1376,6 +1376,7 @@ COMPILE_FUNC(location, AstTyped* expr) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (expr->kind) {
+        case Ast_Kind_Param:
         case Ast_Kind_Local: {
             u64 offset = 0;
             compile_local_location(mod, &code, (AstLocal *) expr, &offset);
@@ -1428,6 +1429,7 @@ COMPILE_FUNC(location, AstTyped* expr) {
         }
 
         default: {
+            DEBUG_HERE;
             onyx_message_add(Msg_Type_Literal,
                     (OnyxFilePos) { 0 },
                     "location unknown");