}
-static AstNumLit* make_int_literal(bh_allocator a, i64 i) {
+AstNumLit* make_int_literal(bh_allocator a, i64 i) {
AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
if (bh_abs(i) >= ((u64) 1 << 32))
num->type_node = (AstType *) &basic_type_i64;
expect_token(parser, '=');
AstType* poly_type = parse_type(parser);
+ PolySolutionKind sln_kind = PSK_Type;
+ if (!node_is_type((AstNode *) poly_type)) sln_kind = PSK_Value;
+
bh_arr_push(solid->known_polyvars, ((AstPolySolution) {
+ .kind = sln_kind,
.poly_sym = poly_var,
.ast_type = poly_type,
.type = NULL
return block;
}
+static void parse_polymorphic_variable(OnyxParser* parser, AstType*** next_insertion) {
+ bh_arr(AstPolyParam) pv = NULL;
+
+ if (parser->polymorph_context.poly_params == NULL)
+ onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
+ else
+ pv = *parser->polymorph_context.poly_params;
+
+ 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,
+
+ // These will be filled out by function_params()
+ .type_expr = NULL,
+ .idx = -1,
+ }));
+
+ *parser->polymorph_context.poly_params = pv;
+ }
+}
+
// <symbol>
// '^' <type>
static AstType* parse_type(OnyxParser* parser) {
}
else if (parser->curr->type == '[') {
- AstSliceType *new;
+ AstType *new;
OnyxToken *open_bracket = expect_token(parser, '[');
if (parser->curr->type == ']') {
} else {
new = make_node(AstArrayType, Ast_Kind_Array_Type);
new->token = open_bracket;
- ((AstArrayType *) new)->count_expr = parse_expression(parser);
+
+ if (parser->curr->type == '$') {
+ AstType** insertion = (AstType **) &((AstArrayType *) new)->count_expr;
+ parse_polymorphic_variable(parser, &insertion);
+ } else {
+ ((AstArrayType *) new)->count_expr = parse_expression(parser);
+ }
}
expect_token(parser, ']');
*next_insertion = (AstType *) new;
- next_insertion = &new->elem;
+ next_insertion = &((AstSliceType *) new)->elem;
}
else if (parser->curr->type == Token_Type_Keyword_Proc) {
}
else if (parser->curr->type == '$') {
- bh_arr(AstPolyParam) pv = NULL;
-
- if (parser->polymorph_context.poly_params == NULL)
- onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
- else
- pv = *parser->polymorph_context.poly_params;
-
- 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,
-
- // These will be filled out by function_params()
- .type_expr = NULL,
- .idx = -1,
- }));
-
- *parser->polymorph_context.poly_params = pv;
- }
+ parse_polymorphic_variable(parser, &next_insertion);
}
else if (parser->curr->type == Token_Type_Symbol) {
next_insertion = NULL;
}
+ else if (parse_possible_directive(parser, "value")) {
+ // :ValueDirectiveHack
+ *next_insertion = (AstType *) parse_expression(parser);
+ next_insertion = NULL;
+ break;
+ }
+
else {
onyx_report_error(parser->curr->pos, "unexpected token '%b'.", parser->curr->text, parser->curr->length);
consume_token(parser);
}
}
+typedef struct PolySolveResult {
+ PolySolutionKind kind;
+ union {
+ AstTyped* value;
+ Type* actual;
+ };
+} PolySolveResult;
+
typedef struct PolySolveElem {
AstType* type_expr;
- Type* actual;
+
+ PolySolutionKind kind;
+ union {
+ AstTyped* value;
+ Type* actual;
+ };
} PolySolveElem;
-static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
+static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
bh_arr(PolySolveElem) elem_queue = NULL;
bh_arr_new(global_heap_allocator, elem_queue, 4);
- Type* result = NULL;
+ PolySolveResult result = { -1, { NULL } };
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = type_expr,
bh_arr_deleten(elem_queue, 0, 1);
if (elem.type_expr == (AstType *) target) {
- result = elem.actual;
+ result.kind = elem.kind;
+ if (result.kind == PSK_Type) {
+ result.actual = elem.actual;
+ } else {
+ result.value = elem.value;
+ }
break;
}
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ((AstPointerType *) elem.type_expr)->elem,
+ .kind = PSK_Type,
.actual = elem.actual->Pointer.elem,
}));
break;
}
case Ast_Kind_Array_Type: {
- // TODO: Add check for same size array
if (elem.actual->kind != Type_Kind_Array) break;
+ bh_arr_push(elem_queue, ((PolySolveElem) {
+ .type_expr = (AstType*) ((AstArrayType *) elem.type_expr)->count_expr,
+ .kind = PSK_Value,
+ .value = (AstTyped *) make_int_literal(semstate.node_allocator, elem.actual->Array.count)
+ }));
+
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ((AstArrayType *) elem.type_expr)->elem,
+ .kind = PSK_Type,
.actual = elem.actual->Array.elem,
}));
break;
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ((AstSliceType *) elem.type_expr)->elem,
+ .kind = PSK_Type,
.actual = elem.actual->Slice.ptr_to_data->Pointer.elem,
}));
break;
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ((AstDynArrType *) elem.type_expr)->elem,
+ .kind = PSK_Type,
.actual = elem.actual->DynArray.ptr_to_data->Pointer.elem,
}));
break;
case Ast_Kind_VarArg_Type:
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ((AstVarArgType *) elem.type_expr)->elem,
+ .kind = PSK_Type,
.actual = actual,
}));
break;
fori (i, 0, (i64) ft->param_count) {
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ft->params[i],
+ .kind = PSK_Type,
.actual = elem.actual->Function.params[i],
}));
}
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = ft->return_type,
+ .kind = PSK_Type,
.actual = elem.actual->Function.return_type,
}));
fori (i, 0, bh_arr_length(pt->params)) {
bh_arr_push(elem_queue, ((PolySolveElem) {
.type_expr = pt->params[i],
+ .kind = PSK_Type,
.actual = elem.actual->Struct.poly_args[i],
}));
}
return NULL;
}
- Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
+ PolySolveResult resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
- if (resolved_type == NULL) {
- onyx_report_error(pos, "Unable to match polymorphic procedure type with actual type, '%s'.", type_get_name(actual_type));
- return NULL;
- }
+ switch (resolved.kind) {
+ case -1:
+ onyx_report_error(pos,
+ "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;
+
+ case PSK_Type:
+ bh_arr_push(slns, ((AstPolySolution) {
+ .kind = PSK_Type,
+ .poly_sym = param->poly_sym,
+ .type = resolved.actual,
+ }));
+ break;
- bh_arr_push(slns, ((AstPolySolution) {
- .poly_sym = param->poly_sym,
- .type = resolved_type
- }));
+ case PSK_Value:
+ bh_arr_push(slns, ((AstPolySolution) {
+ .kind = PSK_Value,
+ .poly_sym = param->poly_sym,
+ .value = resolved.value,
+ }));
+ break;
+ }
}
AstFunction* result = polymorphic_proc_solidify(pp, slns, pos);
return result;
}
+// NOTE: This might return a volatile string. Do not store it without copying it.
+static char* build_poly_solution_key(AstPolySolution* sln) {
+ static char buffer[128];
+
+ if (sln->kind == PSK_Type) {
+ return (char *) type_get_unique_name(sln->type);
+ }
+
+ else if (sln->kind == PSK_Value) {
+ fori (i, 0, 128) buffer[i] = 0;
+
+ if (sln->value->kind == Ast_Kind_NumLit) {
+ strncat(buffer, "NUMLIT:", 127);
+ strncat(buffer, bh_bprintf("%l", ((AstNumLit *) sln->value)->value.l), 127);
+
+ } else {
+ // HACK: For now, the value pointer is just used. This means that
+ // sometimes, even through the solution is the same, it won't be
+ // stored the same.
+ bh_snprintf(buffer, 128, "%p", sln->value);
+ }
+
+ return buffer;
+ }
+
+ return NULL;
+}
+
// NOTE: This returns a volatile string. Do not store it without copying it.
static char* build_polyproc_unique_key(bh_arr(AstPolySolution) slns) {
static char key_buf[1024];
strncat(key_buf, sln->poly_sym->token->text, 1023);
strncat(key_buf, "=", 1023);
- strncat(key_buf, type_get_unique_name(sln->type), 1023);
+ strncat(key_buf, build_poly_solution_key(sln), 1023);
strncat(key_buf, ";", 1023);
token_toggle_end(sln->poly_sym->token);
Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, pos);
bh_arr_each(AstPolySolution, sln, slns) {
- AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
- raw->to = sln->type;
+ AstNode *node = NULL;
+
+ switch (sln->kind) {
+ case PSK_Type:
+ node = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
+ ((AstTypeRawAlias *) node)->to = sln->type;
+ break;
+
+ case PSK_Value:
+ // CLEANUP: Maybe clone this?
+ node = (AstNode *) sln->value;
+ break;
+ }
- symbol_introduce(poly_scope, sln->poly_sym->token, (AstNode *) raw);
+ symbol_introduce(poly_scope, sln->poly_sym->token, node);
}
AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func);