temp_state : ring.RingState;
temp_allocator : Allocator;
-
-alloc_slice :: proc (sl: ^[] $T, count: i32) {
- sl.data = calloc(sizeof T * count);
- sl.count = count;
-}
-
init :: proc () {
heap.init();
s := cast(^u8) start;
for i: 0 .. length do s[i] = value;
}
+
+alloc_slice :: proc (sl: ^[] $T, count: i32) {
+ sl.data = calloc(sizeof T * count);
+ sl.count = count;
+}
\ No newline at end of file
// HACK: NullProcHack
Ast_Flag_Proc_Is_Null = BH_BIT(22),
+
+ Ast_Flag_From_Polymorphism = BH_BIT(23),
} AstFlags;
typedef enum UnaryOp {
// NOTE: Useful not inlined functions
AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
AstNode* ast_clone(bh_allocator a, void* n);
+AstFunction* clone_function_header(bh_allocator a, AstFunction* func);
+
void promote_numlit_to_larger(AstNumLit* num);
b32 convert_numlit_to_type(AstNumLit* num, Type* type);
+
b32 type_check_or_auto_cast(AstTyped** pnode, Type* type);
Type* resolve_expression_type(AstTyped* node);
+
b32 cast_is_legal(Type* from_, Type* to_, char** err_msg);
char* get_function_name(AstFunction* func);
typedef enum PolyProcLookupMethod {
PPLM_By_Call,
PPLM_By_Function_Type,
+ PPLM_By_Value_Array,
} PolyProcLookupMethod;
AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos);
AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
+AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual);
AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
void onyx_report_error(OnyxFilePos pos, char * format, ...);
void onyx_errors_print();
b32 onyx_has_errors();
+void onyx_clear_errors();
#endif
break;
}
- case Ast_Kind_Struct_Type:
- case Ast_Kind_Poly_Struct_Type: {
+ case Ast_Kind_Struct_Type: {
ent.type = Entity_Type_Struct_Member_Default;
ent.type_alias = (AstType *) node;
entity_heap_insert(&compiler_state->prog_info.entities, ent);
// fallthrough
}
+
+ case Ast_Kind_Poly_Struct_Type:
case Ast_Kind_Type_Alias: {
ent.type = Entity_Type_Type_Alias;
ent.type_alias = (AstType *) node;
CheckStatus check_function_header(AstFunction* func);
CheckStatus check_memres_type(AstMemRes* memres);
CheckStatus check_memres(AstMemRes* memres);
+CheckStatus check_type_alias(AstTypeAlias* type_alias);
static inline void fill_in_type(AstTyped* node);
}
static AstTyped* match_overloaded_function(bh_arr(AstTyped *) arg_arr, bh_arr(AstTyped *) overloads) {
bh_arr_each(AstTyped *, node, overloads) {
- AstFunction* overload = (AstFunction *) *node;
+ AstFunction* overload = NULL;
+ if ((*node)->kind == Ast_Kind_Function) {
+ overload = (AstFunction *) *node;
+ }
+ else if ((*node)->kind == Ast_Kind_Polymorphic_Proc) {
+ overload = polymorphic_proc_build_only_header((AstPolyProc *) *node, PPLM_By_Value_Array, arg_arr);
+ }
+
+ if (overload == NULL) continue;
fill_in_type((AstTyped *) overload);
TypeFunction* ol_type = &overload->type->Function;
-
if (bh_arr_length(arg_arr) < (i32) ol_type->needed_param_count) continue;
Type** param_type = ol_type->params;
param_type++;
}
- return (AstTyped *) overload;
+ return (AstTyped *) *node;
no_match:
continue;
// NOTE: Check arguments
bh_arr_each (AstArgument *, actual, arg_arr) {
CHECK(expression, (AstTyped **) actual);
+ (*actual)->type = (*actual)->value->type;
if ((*actual)->value->kind == Ast_Kind_Overloaded_Function) {
onyx_report_error((*actual)->token->pos,
return Check_Error;
}
- if ((*node)->kind != Ast_Kind_Function) {
- onyx_report_error((*node)->token->pos, "Overload option not function. Got '%s'",
+ if ((*node)->kind != Ast_Kind_Function && (*node)->kind != Ast_Kind_Polymorphic_Proc) {
+ onyx_report_error((*node)->token->pos, "Overload option not procedure. Got '%s'",
onyx_ast_node_kind_string((*node)->kind));
return Check_Error;
return Check_Success;
}
+CheckStatus check_type_alias(AstTypeAlias* type_alias) {
+ AstType* to = type_alias->to;
+
+ if (to->kind == Ast_Kind_Poly_Call_Type) {
+ AstPolyCallType* pc_node = (AstPolyCallType *) to;
+ bh_arr_each(AstNode *, param, pc_node->params) {
+ if (!node_is_type(*param)) {
+ CHECK(expression, (AstTyped **) param);
+ resolve_expression_type((AstTyped *) *param);
+ }
+ }
+ }
+
+ return Check_Success;
+}
+
CheckStatus check_node(AstNode* node) {
switch (node->kind) {
case Ast_Kind_Function: return check_function((AstFunction *) node);
case Entity_Type_Type_Alias:
if (ent->type_alias->kind == Ast_Kind_Struct_Type)
cs = check_struct((AstStructType *) ent->type_alias);
+ else if (ent->type_alias->kind == Ast_Kind_Type_Alias)
+ check_type_alias((AstTypeAlias *) ent->type_alias);
break;
case Entity_Type_Memory_Reservation_Type:
return nn;
}
+
+AstFunction* clone_function_header(bh_allocator a, AstFunction* func) {
+ if (func->kind != Ast_Kind_Function) return NULL;
+
+ if (func->flags & Ast_Flag_Foreign) return func;
+
+ AstFunction* new_func = onyx_ast_node_new(a, sizeof(AstFunction), func->kind);
+ memmove(new_func, func, sizeof(AstFunction));
+
+ new_func->return_type = (AstType *) ast_clone(a, func->return_type);
+
+ new_func->params = NULL;
+ bh_arr_new(global_heap_allocator, new_func->params, bh_arr_length(func->params));
+ bh_arr_each(AstParam, param, func->params) {
+ AstParam new_param;
+ new_param.local = (AstLocal *) ast_clone(a, param->local);
+ new_param.default_value = (AstTyped *) ast_clone(a, param->default_value);
+ new_param.vararg_kind = param->vararg_kind;
+ bh_arr_push(new_func->params, new_param);
+ }
+
+ return new_func;
+}
\ No newline at end of file
b32 onyx_has_errors() {
return bh_arr_length(errors.errors) > 0;
}
+
+void onyx_clear_errors() {
+ bh_printf("ERRORS WERE CLEARED!!!\n");
+ bh_arr_set_length(errors.errors, 0);
+}
\ No newline at end of file
}
}
- if (func->operator_overload != (BinaryOp) -1) {
+ if ((func->flags & Ast_Flag_From_Polymorphism) == 0 && func->operator_overload != (BinaryOp) -1) {
if (bh_arr_length(func->params) != 2) {
onyx_report_error(func->token->pos, "Expected 2 exactly arguments for binary operator overload.");
}
static void symres_polyproc(AstPolyProc* pp) {
pp->poly_scope = semstate.curr_scope;
+
+ if (pp->base_func->operator_overload != (BinaryOp) -1) {
+ if (bh_arr_length(pp->base_func->params) != 2) {
+ onyx_report_error(pp->base_func->token->pos, "Expected 2 exactly arguments for binary operator overload.");
+ }
+
+ if (binop_is_assignment(pp->base_func->operator_overload)) {
+ onyx_report_error(pp->base_func->token->pos, "'%s' is not currently overloadable.", binaryop_string[pp->base_func->operator_overload]);
+ }
+
+ bh_arr_push(operator_overloads[pp->base_func->operator_overload], (AstTyped *) pp);
+ }
}
void symres_entity(Entity* ent) {
return result;
}
-AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos) {
- if (pp->concrete_funcs == NULL) {
- bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
- }
-
+static bh_arr(AstPolySolution) find_polymorphic_slns(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, char** err_msg) {
bh_arr(AstPolySolution) slns = NULL;
bh_arr_new(global_heap_allocator, slns, bh_arr_length(pp->poly_params));
if (pp_lookup == PPLM_By_Call) {
if (param->idx >= ((AstCall *) actual)->arg_count) {
- onyx_report_error(pos, "Not enough arguments to polymorphic procedure.");
- return NULL;
+ if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure.";
+ goto sln_not_found;
}
bh_arr(AstArgument *) arg_arr = ((AstCall *) actual)->arg_arr;
actual_type = resolve_expression_type(arg_arr[param->idx]->value);
}
+ else if (pp_lookup == PPLM_By_Value_Array) {
+ bh_arr(AstTyped *) arg_arr = (bh_arr(AstTyped *)) actual;
+
+ if ((i32) param->idx >= bh_arr_length(arg_arr)) {
+ if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure.";
+ goto sln_not_found;
+ }
+
+ actual_type = resolve_expression_type(arg_arr[param->idx]);
+ }
+
else if (pp_lookup == PPLM_By_Function_Type) {
Type* ft = (Type*) actual;
if (param->idx >= ft->Function.param_count) {
- onyx_report_error(pos, "Incompatible polymorphic argument to function paramter.");
- return NULL;
+ if (err_msg) *err_msg = "Incompatible polymorphic argument to function paramter.";
+ goto sln_not_found;
}
actual_type = ft->Function.params[param->idx];
}
else {
- onyx_report_error(pos, "Cannot resolve polymorphic function type.");
- return NULL;
+ if (err_msg) *err_msg = "Cannot resolve polymorphic function type.";
+ goto sln_not_found;
}
PolySolveResult resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
switch (resolved.kind) {
case PSK_Undefined:
- onyx_report_error(pos,
+ if (err_msg) *err_msg = bh_aprintf(global_heap_allocator,
"Unable to solve for polymoprhic variable '%b', using the type '%s'.",
param->poly_sym->token->text,
param->poly_sym->token->length,
type_get_name(actual_type));
- return NULL;
+ goto sln_not_found;
case PSK_Type:
bh_arr_push(slns, ((AstPolySolution) {
}
}
+ return slns;
+
+sln_not_found:
+ bh_arr_free(slns);
+ return NULL;
+}
+
+AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos) {
+ if (pp->concrete_funcs == NULL) {
+ bh_table_init(global_heap_allocator, pp->concrete_funcs, 8);
+ }
+
+ char *err_msg = NULL;
+ bh_arr(AstPolySolution) slns = find_polymorphic_slns(pp, pp_lookup, actual, &err_msg);
+ if (slns == NULL) {
+ if (err_msg != NULL) onyx_report_error(pos, err_msg);
+ else onyx_report_error(pos, "Some kind of error occured when generating a polymorphic procedure. You hopefully will not see this");
+ }
+
AstFunction* result = polymorphic_proc_solidify(pp, slns, pos);
bh_arr_free(slns);
bh_table_put(AstFunction *, pp->concrete_funcs, unique_key, func);
func->flags |= Ast_Flag_Function_Used;
+ func->flags |= Ast_Flag_From_Polymorphism;
Entity func_header_entity = {
.state = Entity_State_Resolve_Symbols,
}
}
+AstFunction* polymorphic_proc_build_only_header(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual) {
+ bh_arr(AstPolySolution) slns = find_polymorphic_slns(pp, pp_lookup, actual, NULL);
+ if (slns == NULL) return NULL;
+
+ Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, (OnyxFilePos) { 0 });
+ insert_poly_slns_into_scope(poly_scope, slns);
+
+ // NOTE: This function is only going to have the header of it correctly created.
+ // Nothing should happen to this function's body or else the original will be corrupted.
+ // - brendanfh 2021/01/10
+ AstFunction* new_func = clone_function_header(semstate.node_allocator, pp->base_func);
+ new_func->flags |= Ast_Flag_From_Polymorphism;
+
+ Entity func_header_entity = {
+ .state = Entity_State_Resolve_Symbols,
+ .type = Entity_Type_Function_Header,
+ .function = new_func,
+ .package = NULL,
+ .scope = poly_scope,
+ };
+
+ entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen);
+ if (onyx_has_errors()) {
+ onyx_clear_errors();
+ return NULL;
+ }
+
+ return new_func;
+}
+
char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) {
char name_buf[256];
fori (i, 0, 256) name_buf[i] = 0;
EMIT_FUNC(struct_lval, AstTyped* lval);
EMIT_FUNC(struct_store, Type* type, u64 offset);
EMIT_FUNC(struct_literal, AstStructLiteral* sl);
+EMIT_FUNC(array_store, Type* type, u32 offset);
EMIT_FUNC(array_literal, AstArrayLiteral* al);
EMIT_FUNC(range_literal, AstRangeLiteral* range);
EMIT_FUNC(expression, AstTyped* expr);
Type* rtype = assign->right->type;
assert(rtype->kind == Type_Kind_Array);
- Type* elem_type = rtype;
- u32 elem_count = 1;
- while (elem_type->kind == Type_Kind_Array) {
- elem_count *= elem_type->Array.count;
- elem_type = elem_type->Array.elem;
- }
- u32 elem_size = type_size_of(elem_type);
-
if (assign->right->kind == Ast_Kind_Array_Literal) {
+ Type* elem_type = rtype;
+ u32 elem_count = 1;
+ while (elem_type->kind == Type_Kind_Array) {
+ elem_count *= elem_type->Array.count;
+ elem_type = elem_type->Array.elem;
+ }
+ u32 elem_size = type_size_of(elem_type);
+
u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
emit_location(mod, &code, assign->left);
local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
} else {
- u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
- u64 rptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
-
emit_location(mod, &code, assign->left);
- WIL(WI_LOCAL_SET, lptr_local);
-
emit_expression(mod, &code, assign->right);
- WIL(WI_LOCAL_SET, rptr_local);
-
- // NOTE: Currently, we inline the copying of the array; But if the array has
- // many elements, this could result in a LOT of instructions. Maybe for lengths
- // greater than like 16 we output a loop that copies them?
- // - brendanfh 2020/12/16
- fori (i, 0, elem_count) {
- if (!type_is_structlike(elem_type))
- WIL(WI_LOCAL_GET, lptr_local);
-
- if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == rptr_local)
- bh_arr_last(code).type = WI_LOCAL_TEE;
- else
- WIL(WI_LOCAL_GET, rptr_local);
- emit_load_instruction(mod, &code, elem_type, i * elem_size);
-
- if (!type_is_structlike(elem_type)) {
- emit_store_instruction(mod, &code, elem_type, i * elem_size);
- } else {
- WIL(WI_LOCAL_GET, lptr_local);
- emit_store_instruction(mod, &code, elem_type, i * elem_size);
- }
- }
-
- local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
- local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+ emit_array_store(mod, &code, rtype, 0);
}
*pcode = code;
return;
}
+ if (type->kind == Type_Kind_Array) {
+ emit_array_store(mod, pcode, type, offset);
+ return;
+ }
+
if (type->kind == Type_Kind_Enum) {
type = type->Enum.backing;
}
*pcode = code;
}
+EMIT_FUNC(array_store, Type* type, u32 offset) {
+ assert(type->kind == Type_Kind_Array);
+ bh_arr(WasmInstruction) code = *pcode;
+
+ Type* elem_type = type;
+ u32 elem_count = 1;
+ while (elem_type->kind == Type_Kind_Array) {
+ elem_count *= elem_type->Array.count;
+ elem_type = elem_type->Array.elem;
+ }
+ u32 elem_size = type_size_of(elem_type);
+
+ u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+ u64 rptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+ WIL(WI_LOCAL_SET, rptr_local);
+ WIL(WI_LOCAL_SET, lptr_local);
+
+ // NOTE: Currently, we inline the copying of the array; But if the array has
+ // many elements, this could result in a LOT of instructions. Maybe for lengths
+ // greater than like 16 we output a loop that copies them?
+ // - brendanfh 2020/12/16
+ fori (i, 0, elem_count) {
+ if (!type_is_structlike(elem_type))
+ WIL(WI_LOCAL_GET, lptr_local);
+
+ if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == rptr_local)
+ bh_arr_last(code).type = WI_LOCAL_TEE;
+ else
+ WIL(WI_LOCAL_GET, rptr_local);
+ emit_load_instruction(mod, &code, elem_type, i * elem_size);
+
+ if (!type_is_structlike(elem_type)) {
+ emit_store_instruction(mod, &code, elem_type, i * elem_size + offset);
+ } else {
+ WIL(WI_LOCAL_GET, lptr_local);
+ emit_store_instruction(mod, &code, elem_type, i * elem_size + offset);
+ }
+ }
+
+ local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+ local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+
+ *pcode = code;
+ return;
+}
+
EMIT_FUNC(array_literal, AstArrayLiteral* al) {
bh_arr(WasmInstruction) code = *pcode;
u64 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top);
// HACK: slightly... There will be space for 5 instructions
- code[0] = (WasmInstruction) { WI_GLOBAL_GET, { .l = stack_top_idx } };
- code[1] = (WasmInstruction) { WI_LOCAL_TEE, { .l = mod->stack_base_idx} };
- code[2] = (WasmInstruction) { WI_I32_CONST, { .l = stacksize } };
- code[3] = (WasmInstruction) { WI_I32_ADD, 0 };
- code[4] = (WasmInstruction) { WI_GLOBAL_SET, { .l = stack_top_idx } };
-
+ if (stacksize == 0) {
+ code[0] = (WasmInstruction) { WI_GLOBAL_GET, { .l = stack_top_idx } };
+ code[1] = (WasmInstruction) { WI_LOCAL_SET, { .l = mod->stack_base_idx} };
+ code[2] = (WasmInstruction) { WI_NOP, 0 };
+ code[3] = (WasmInstruction) { WI_NOP, 0 };
+ code[4] = (WasmInstruction) { WI_NOP, 0 };
+ } else {
+ code[0] = (WasmInstruction) { WI_GLOBAL_GET, { .l = stack_top_idx } };
+ code[1] = (WasmInstruction) { WI_LOCAL_TEE, { .l = mod->stack_base_idx} };
+ code[2] = (WasmInstruction) { WI_I32_CONST, { .l = stacksize } };
+ code[3] = (WasmInstruction) { WI_I32_ADD, 0 };
+ code[4] = (WasmInstruction) { WI_GLOBAL_SET, { .l = stack_top_idx } };
+ }
*pcode = code;
}
i32 leb_len;
u8* leb;
+ if (instr->type == WI_NOP) return;
+
if (instr->type & SIMD_INSTR_MASK) {
bh_buffer_write_byte(buff, 0xFD);
leb = uint_to_uleb128((u64) (instr->type &~ SIMD_INSTR_MASK), &leb_len);
simulate :: proc (cups: [] i32, moves := 100) {
cw : [] i32;
- alloc.alloc_slice(^cw, cups.count);
+ memory.alloc_slice(^cw, cups.count);
defer cfree(cw.data);
for i: 0 .. cups.count do cw[cups[i]] = cups[w(i + 1)];