From: Brendan Hansen Date: Fri, 28 Aug 2020 21:58:32 +0000 (-0500) Subject: Started the basics of polymorphic procedures. code clean and bugfixes to follow. X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=6d2aaea51209a242dd1d2eb506c336b262641f01;p=onyx.git Started the basics of polymorphic procedures. code clean and bugfixes to follow. --- diff --git a/Makefile b/Makefile index 50247792..177c8395 100644 --- 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 diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 6e8cd47d..3caeed36 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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) { diff --git a/include/onyxsempass.h b/include/onyxsempass.h index dc131d8e..5a61171a 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -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 74d31f39..266cba25 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index aacdbb48..3dc37daa 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -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 diff --git a/src/onyx.c b/src/onyx.c index 3234249c..4a867397 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -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; diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 4f159ec9..8fbadea2 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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 index 00000000..f6c4b0f8 --- /dev/null +++ b/src/onyxclone.c @@ -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 diff --git a/src/onyxparser.c b/src/onyxparser.c index e3163ced..587318b3 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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) { // // '^' -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 // '(' (: ,?)* ')' -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' @@ -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); diff --git a/src/onyxsempass.c b/src/onyxsempass.c index a29be082..7324468e 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -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; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index a715b943..aa891fad 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; } diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 275f6d9c..388c2957 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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; diff --git a/src/onyxutils.c b/src/onyxutils.c index e8152d23..7498c0ea 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -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; +} diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 2adcbfb0..e82a2015 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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");