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, bh_arr(AstPolyParam)* polymorphic_vars);
+static AstType* parse_type(OnyxParser* parser);
static AstStructType* parse_struct(OnyxParser* parser);
-static void parse_function_params(OnyxParser* parser, AstFunction* func, bh_arr(AstPolyParam)* poly_vars);
+static void parse_function_params(OnyxParser* parser, AstFunction* func);
static b32 parse_possible_directive(OnyxParser* parser, const char* dir);
static AstFunction* parse_function_definition(OnyxParser* parser);
static AstTyped* parse_global_declaration(OnyxParser* parser);
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, NULL);
+ cast_node->type_node = parse_type(parser);
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, NULL);
+ so_node->so_type = (AstType *) parse_type(parser);
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, NULL);
+ ao_node->ao_type = (AstType *) parse_type(parser);
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, NULL);
+ type_node = parse_type(parser);
}
AstLocal* local = make_node(AstLocal, Ast_Kind_Local);
// <symbol>
// '^' <type>
-static AstType* parse_type(OnyxParser* parser, bh_arr(AstPolyParam)* poly_vars) {
+static AstType* parse_type(OnyxParser* parser) {
AstType* root = NULL;
AstType** next_insertion = &root;
while (parser->curr->type != ')') {
if (parser->hit_unexpected_token) return root;
- AstType* param_type = parse_type(parser, poly_vars);
+ AstType* param_type = parse_type(parser);
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, poly_vars);
+ return_type = parse_type(parser);
}
u64 param_count = bh_arr_length(params);
else if (parser->curr->type == '$') {
bh_arr(AstPolyParam) pv = NULL;
- if (poly_vars == NULL)
+ if (parser->polymorph_context.poly_params == NULL)
onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
else
- pv = *poly_vars;
+ pv = *parser->polymorph_context.poly_params;
consume_token(parser);
if (pv != NULL) {
bh_arr_push(pv, ((AstPolyParam) {
.poly_sym = symbol_node,
- .type_expr = root,
+
+ // These will be filled out by function_params()
+ .type_expr = NULL,
.idx = -1,
}));
- *poly_vars = pv;
+ *parser->polymorph_context.poly_params = pv;
}
}
mem->token = expect_token(parser, Token_Type_Symbol);
expect_token(parser, ':');
- mem->type_node = parse_type(parser, NULL);
+ mem->type_node = parse_type(parser);
if (parser->curr->type == '=') {
consume_token(parser);
// e
// '(' (<symbol>: <type>,?)* ')'
-static void parse_function_params(OnyxParser* parser, AstFunction* func, bh_arr(AstPolyParam)* poly_vars) {
+static void parse_function_params(OnyxParser* parser, AstFunction* func) {
if (parser->curr->type != '(')
return;
AstParam curr_param = { 0 };
u32 param_idx = 0;
- bh_arr(AstPolyParam) pv = *poly_vars;
+ assert(parser->polymorph_context.poly_params != NULL);
b32 param_use = 0;
OnyxToken* symbol;
}
if (parser->curr->type != '=') {
- u32 old_len = bh_arr_length(pv);
- curr_param.local->type_node = parse_type(parser, &pv);
+ i32 old_len = bh_arr_length(*parser->polymorph_context.poly_params);
+ curr_param.local->type_node = parse_type(parser);
+
+ i32 new_len = bh_arr_length(*parser->polymorph_context.poly_params);
+ i32 new_poly_params = new_len - old_len;
- if (old_len != bh_arr_length(pv)) {
- bh_arr_last(pv).idx = param_idx;
+ fori (i, 0, new_poly_params) {
+ (*parser->polymorph_context.poly_params)[old_len + i].type_expr = curr_param.local->type_node;
+ (*parser->polymorph_context.poly_params)[old_len + i].idx = param_idx;
}
}
param_idx++;
}
- *poly_vars = pv;
-
consume_token(parser); // Skip the )
return;
}
bh_arr(AstPolyParam) polymorphic_vars = NULL;
bh_arr_new(global_heap_allocator, polymorphic_vars, 4);
- parse_function_params(parser, func_def, &polymorphic_vars);
+ parser->polymorph_context.poly_params = &polymorphic_vars;
+ parse_function_params(parser, func_def);
+ parser->polymorph_context.poly_params = NULL;
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, NULL);
+ return_type = parse_type(parser);
}
func_def->return_type = return_type;
}
}
- global_node->type_node = parse_type(parser, NULL);
+ global_node->type_node = parse_type(parser);
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, NULL);
+ alias->to = parse_type(parser);
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, NULL);
+ memres->type_node = parse_type(parser);
if (parser->curr->type == '=') {
consume_token(parser);
};
+ parser.polymorph_context = (PolymorphicContext) {
+ .root_node = NULL,
+ .poly_params = NULL,
+ };
+
bh_arr_new(parser.results.allocator, parser.results.includes, 4);
bh_arr_new(parser.results.allocator, parser.results.nodes_to_process, 4);
}
}
+typedef struct PolySolveElem {
+ AstType* type_expr;
+ Type* actual;
+} PolySolveElem;
+
static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
- while (1) {
- if (type_expr == (AstType *) target) return actual;
+ bh_arr(PolySolveElem) elem_queue = NULL;
+ bh_arr_new(global_heap_allocator, elem_queue, 4);
+
+ Type* result = NULL;
+
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = type_expr,
+ .actual = actual
+ }));
+
+ while (!bh_arr_is_empty(elem_queue)) {
+ PolySolveElem elem = elem_queue[0];
+ bh_arr_deleten(elem_queue, 0, 1);
- switch (type_expr->kind) {
+ if (elem.type_expr == (AstType *) target) {
+ result = elem.actual;
+ break;
+ }
+
+ switch (elem.type_expr->kind) {
case Ast_Kind_Pointer_Type: {
- if (actual->kind != Type_Kind_Pointer) return NULL;
+ if (elem.actual->kind != Type_Kind_Pointer) break;
- type_expr = ((AstPointerType *) type_expr)->elem;
- actual = actual->Pointer.elem;
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = ((AstPointerType *) elem.type_expr)->elem,
+ .actual = elem.actual->Pointer.elem,
+ }));
break;
}
case Ast_Kind_Slice_Type: {
- if (actual->kind != Type_Kind_Slice) return NULL;
+ if (elem.actual->kind != Type_Kind_Slice) break;
- type_expr = ((AstSliceType *) type_expr)->elem;
- actual = actual->Slice.ptr_to_data->Pointer.elem;
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = ((AstSliceType *) elem.type_expr)->elem,
+ .actual = elem.actual->Slice.ptr_to_data->Pointer.elem,
+ }));
break;
}
case Ast_Kind_DynArr_Type: {
- if (actual->kind != Type_Kind_DynArray) return NULL;
+ if (elem.actual->kind != Type_Kind_DynArray) break;
- type_expr = ((AstDynArrType *) type_expr)->elem;
- actual = actual->DynArray.ptr_to_data->Pointer.elem;
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = ((AstDynArrType *) elem.type_expr)->elem,
+ .actual = elem.actual->DynArray.ptr_to_data->Pointer.elem,
+ }));
break;
}
- default:
- return NULL;
+ case Ast_Kind_Function_Type: {
+ if (elem.actual->kind != Type_Kind_Function) break;
+
+ AstFunctionType* ft = (AstFunctionType *) elem.type_expr;
+
+ fori (i, 0, ft->param_count) {
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = ft->params[i],
+ .actual = elem.actual->Function.params[i],
+ }));
+ }
+
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = ft->return_type,
+ .actual = elem.actual->Function.return_type,
+ }));
+
+ break;
+ }
+
+ default: break;
}
}
- return NULL;
+solving_done:
+ bh_arr_free(elem_queue);
+
+ return result;
}
AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos) {
Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
if (resolved_type == NULL) {
- if (pp_lookup == PPLM_By_Call) {
- onyx_report_error(pos, "Unable to match polymorphic procedure type.");
- }
- else if (pp_lookup == PPLM_By_Function_Type) {
- onyx_report_error(pos, "Unable to match polymorphic procedure type.");
- }
+ onyx_report_error(pos, "Unable to match polymorphic procedure type with actual type, '%s'.", type_get_name(actual_type));
return NULL;
}