OBJ_FILES=\
build/onyxlex.o \
build/onyxparser.o \
+ build/onyxclone.o \
build/onyxtypes.o \
build/onyxbuiltins.o \
build/onyxsempass.o \
ifeq ($(RELEASE), 1)
FLAGS=-O3
else
- FLAGS=-g3 -Og
+ FLAGS=-g3
endif
build/%.o: src/%.c include/bh.h
#include "onyxlex.h"
#include "onyxtypes.h"
-
typedef struct AstNode AstNode;
typedef struct AstTyped AstTyped;
typedef struct AstEnumType AstEnumType;
typedef struct AstEnumValue AstEnumValue;
typedef struct AstTypeAlias AstTypeAlias;
+typedef struct AstTypeRawAlias AstTypeRawAlias;
typedef struct AstBinding AstBinding;
typedef struct AstMemRes AstMemRes;
typedef struct AstFunction AstFunction;
typedef struct AstOverloadedFunction AstOverloadedFunction;
+typedef struct AstPolyParam AstPolyParam;
+typedef struct AstPolyProc AstPolyProc;
+
typedef struct AstPackage AstPackage;
typedef struct Package Package;
Ast_Kind_Binding,
Ast_Kind_Function,
Ast_Kind_Overloaded_Function,
+ Ast_Kind_Polymorphic_Proc,
Ast_Kind_Block,
Ast_Kind_Local_Group,
Ast_Kind_Local,
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,
// Struct flags
Ast_Flag_Struct_Is_Union = BH_BIT(17),
+
+ Ast_Flag_No_Clone = BH_BIT(18),
} AstFlags;
typedef enum UnaryOp {
// 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; };
};
};
};
+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;
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,
AstType *type_alias;
AstEnumType *enum_type;
AstMemRes *mem_res;
+ AstPolyProc *poly_proc;
};
} Entity;
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;
// 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) {
// NOTE: Used wherever
ProgramInfo* program;
+ bh_arr(Entity) other_entities;
// NOTE: Used in symbol resolution phase
Package* curr_package;
// 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);
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 };
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(" ");
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) {
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
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) {
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;
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);
case Ast_Kind_Memres: break;
+ case Ast_Kind_Polymorphic_Proc: break;
+
+ case Ast_Kind_Error: break;
+
default:
retval = 1;
DEBUG_HERE;
}
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;
case Entity_Type_Use_Package: break;
+ case Entity_Type_Polymorphic_Proc: break;
+
default: DEBUG_HERE; break;
}
}
--- /dev/null
+#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
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);
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);
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;
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;
// 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);
// <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;
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 != ')')
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);
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);
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);
// 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;
AstParam curr_param = { 0 };
+ u32 param_idx = 0;
+ bh_arr(AstPolyParam) pv = *poly_vars;
+
b32 param_use = 0;
OnyxToken* symbol;
while (parser->curr->type != ')') {
}
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 == '=') {
if (parser->curr->type != ')')
expect_token(parser, ',');
+
+ param_idx++;
}
+ *poly_vars = pv;
+
consume_token(parser); // Skip the )
return;
}
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);
}
}
- 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>
}
}
- global_node->type_node = parse_type(parser);
+ global_node->type_node = parse_type(parser, NULL);
add_node_to_process(parser, (AstNode *) global_node);
}
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) {
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);
.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) {
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;
}
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);
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);
}
}
+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;
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;
}
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;
+#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;
"BINDING",
"FUNCTION",
"OVERLOADED_FUNCTION",
+ "POLYMORPHIC PROC",
"BLOCK",
"LOCAL GROUP",
"LOCAL",
"STRUCT TYPE",
"ENUM TYPE",
"TYPE_ALIAS",
+ "TYPE RAW ALIAS"
"TYPE_END (BAD)",
"STRUCT MEMBER",
"IF",
"FOR",
"WHILE",
- "BREAK",
- "CONTINUE",
+ "JUMP",
"DEFER",
"SWITCH",
"SWITCH CASE"
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; \
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;
+}
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);
}
default: {
+ DEBUG_HERE;
onyx_message_add(Msg_Type_Literal,
(OnyxFilePos) { 0 },
"location unknown");