struct AstNumLit { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; };
struct AstStrLit { AstTyped_base; u64 addr; u64 length; };
struct AstLocal { AstTyped_base; };
-struct AstArgument { AstTyped_base; AstTyped *value; VarArgKind va_kind; };
+struct AstArgument { AstTyped_base; AstTyped *value; VarArgKind va_kind; b32 is_baked : 1; };
struct AstAddressOf { AstTyped_base; AstTyped *expr; };
struct AstDereference { AstTyped_base; AstTyped *expr; };
struct AstArrayAccess { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
OnyxToken* name;
+
+ // NOTE: This is NULL, unless this function was generated from a polymorphic
+ // procedure call. Then it is set to the token of the call node.
+ OnyxToken* generated_from;
+
union {
// NOTE: Used when a function is exported with a specific name
OnyxToken* exported_name;
};
};
};
+
+struct AstOverloadedFunction {
+ AstTyped_base;
+
+ bh_arr(AstTyped *) overloads;
+};
+
+struct AstPackage {
+ AstNode_base;
+
+ Package* package;
+};
+
+//
+// Polymorphic procedures
+//
+
+typedef enum PolyParamKind {
+ // Dont love these names
+ PPK_Undefined,
+ PPK_Poly_Type,
+ PPK_Baked_Value,
+} PolyParamKind;
+
+typedef enum PolySolutionKind {
+ PSK_Undefined,
+ PSK_Type,
+ PSK_Value,
+} PolySolutionKind;
+
struct AstPolyParam {
+ PolyParamKind kind;
+
+ // The parameter index where the polymorphic variable occurs.
+ u32 idx;
+
// The symbol node that represents the polymorphic variable.
AstNode* poly_sym;
// symbol.
AstType* type_expr;
- // The parameter index where the polymorphic variable occurs.
- u64 idx;
+ // Used for baked values. The expected type of the parameter.
+ Type* type;
};
-typedef enum PolySolutionKind {
- PSK_Undefined,
- PSK_Type,
- PSK_Value,
-} PolySolutionKind;
-
struct AstPolySolution {
PolySolutionKind kind;
AstNode* poly_sym;
AstTyped* value;
};
};
+
struct AstSolidifiedFunction {
AstFunction* func;
Scope* poly_scope;
};
+
struct AstPolyProc {
AstNode_base;
AstFunction* base_func;
bh_table(AstSolidifiedFunction) concrete_funcs;
};
-struct AstOverloadedFunction {
- AstTyped_base;
-
- bh_arr(AstTyped *) overloads;
-};
-struct AstPackage {
- AstNode_base;
-
- Package* package;
-};
extern AstNode empty_node;
void arguments_ensure_length(Arguments* args, u32 count);
void arguments_clone(Arguments* dest, Arguments* src);
void arguments_deep_clone(bh_allocator a, Arguments* dest, Arguments* src);
+void arguments_removed_baked(Arguments* args);
typedef enum PolyProcLookupMethod {
PPLM_By_Call,
bh_arr_each(AstTyped *, val, src->values)
bh_arr_push(dest->values, (AstTyped *) ast_clone(a, (AstNode *) *val));
+}
+
+void arguments_removed_baked(Arguments* args) {
+ fori (i, 0, bh_arr_length(args->values)) {
+ if (args->values[i]->kind != Ast_Kind_Argument) continue;
+ if (!((AstArgument *) args->values[i])->is_baked) continue;
+
+ bh_arr_deleten(args->values, i, 1);
+ i--;
+ }
+
+ fori (i, 0, bh_arr_length(args->named_values)) {
+ if (args->named_values[i]->value->kind != Ast_Kind_Argument) continue;
+ if (!((AstArgument *) args->named_values[i]->value)->is_baked) continue;
+
+ bh_arr_deleten(args->named_values, i, 1);
+ i--;
+ }
}
\ No newline at end of file
return Check_Success;
}
+static i32 non_baked_argument_count(Arguments* args) {
+ i32 count = 0;
+
+ bh_arr_each(AstTyped *, actual, args->values) {
+ assert((*actual)->kind == Ast_Kind_Argument);
+ if (!((AstArgument *) (*actual))->is_baked) count++;
+ }
+
+ bh_arr_each(AstNamedValue *, named_value, args->named_values) {
+ assert((*named_value)->value->kind == Ast_Kind_Argument);
+ if (!((AstArgument *) (*named_value)->value)->is_baked) count++;
+ }
+
+ return count;
+}
+
typedef enum ArgState {
AS_Expecting_Exact,
AS_Expecting_Typed_VA,
if (call->callee == NULL) return Check_Error;
callee = (AstFunction *) call->callee;
+ arguments_removed_baked(&call->args);
}
// NOTE: Build callee's type
}
- {
- // CLEANUP maybe make function_get_expected_arguments?
- i32 non_vararg_param_count = (i32) callee->type->Function.param_count;
- if (non_vararg_param_count > 0 &&
- callee->type->Function.params[callee->type->Function.param_count - 1] == builtin_vararg_type_type)
- non_vararg_param_count--;
+ // CLEANUP maybe make function_get_expected_arguments?
+ i32 non_vararg_param_count = (i32) callee->type->Function.param_count;
+ if (non_vararg_param_count > 0 &&
+ callee->type->Function.params[callee->type->Function.param_count - 1] == builtin_vararg_type_type)
+ non_vararg_param_count--;
- i32 arg_count = bh_max(
- bh_arr_length(call->args.values) + bh_arr_length(call->args.named_values),
- non_vararg_param_count);
+ i32 arg_count = bh_max(non_vararg_param_count, non_baked_argument_count(&call->args));
- arguments_ensure_length(&call->args, arg_count);
+ arguments_ensure_length(&call->args, arg_count);
- char* err_msg = NULL;
- fill_in_arguments(&call->args, (AstNode *) callee, &err_msg);
+ char* err_msg = NULL;
+ fill_in_arguments(&call->args, (AstNode *) callee, &err_msg);
- if (err_msg != NULL) {
- onyx_report_error(call->token->pos, err_msg);
- return Check_Error;
- }
+ if (err_msg != NULL) {
+ onyx_report_error(call->token->pos, err_msg);
+ return Check_Error;
}
bh_arr(AstArgument *) arg_arr = (bh_arr(AstArgument *)) call->args.values;
return Check_Error;
}
- if (arg_pos < (u32) bh_arr_length(arg_arr)) {
+ if (arg_pos < arg_count) {
onyx_report_error(call->token->pos, "Too many arguments to function call.");
return Check_Error;
}
CheckStatus check_expression(AstTyped** pexpr) {
AstTyped* expr = *pexpr;
if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) {
- if (expr->token) {
- onyx_report_error(expr->token->pos, "Type used as part of an expression.");
- }
- else {
- onyx_report_error((OnyxFilePos) { 0 }, "Type used as part of an expression somewhere in the program.");
- }
- return Check_Error;
+ return Check_Success;
+ // if (expr->token) {
+ // onyx_report_error(expr->token->pos, "Type used as part of an expression.");
+ // }
+ // else {
+ // onyx_report_error((OnyxFilePos) { 0 }, "Type used as part of an expression somewhere in the program.");
+ // }
+ // return Check_Error;
}
fill_in_type(expr);
return float_node;
}
+// e
+// '#' <symbol>
+static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
+ if (parser->curr->type != '#') return 0;
+
+ expect_token(parser, '#');
+ OnyxToken* sym = expect_token(parser, Token_Type_Symbol);
+
+ b32 match = (strlen(dir) == (u64) sym->length) && (strncmp(dir, sym->text, sym->length) == 0);
+ if (!match) {
+ unconsume_token(parser);
+ unconsume_token(parser);
+ }
+ return match;
+}
+
static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
if (parser->curr->type != '.'
|| peek_token(1)->type != '{') return 0;
bh_arr(AstPolyParam) pv = NULL;
if (parser->polymorph_context.poly_params == NULL)
- onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
+ onyx_report_error(parser->curr->pos, "Polymorphic variable not valid here.");
else
pv = *parser->polymorph_context.poly_params;
if (pv != NULL) {
bh_arr_push(pv, ((AstPolyParam) {
+ .kind = PPK_Poly_Type,
.poly_sym = symbol_node,
// These will be filled out by function_params()
assert(parser->polymorph_context.poly_params != NULL);
b32 param_use = 0;
+ b32 param_is_baked = 0;
OnyxToken* symbol;
while (parser->curr->type != ')') {
if (parser->hit_unexpected_token) return;
param_use = 1;
}
+ if (parser->curr->type == '$') {
+ consume_token(parser);
+ param_is_baked = 1;
+ }
+
symbol = expect_token(parser, Token_Type_Symbol);
expect_token(parser, ':');
i32 old_len = 0, new_len = 0;
if (curr_param.vararg_kind != VA_Kind_Untyped) {
+ // CLEANUP: This is mess and it is hard to follow what is going on here.
+ // I think with recent rewrites, this should be easier to do.
old_len = bh_arr_length(*parser->polymorph_context.poly_params);
curr_param.local->type_node = parse_type(parser);
new_len = bh_arr_length(*parser->polymorph_context.poly_params);
bh_arr_push(func->params, curr_param);
+ if (param_is_baked) {
+ param_is_baked = 0;
+
+ assert(parser->polymorph_context.poly_params != NULL);
+
+ bh_arr(AstPolyParam) pv = *parser->polymorph_context.poly_params;
+ bh_arr_push(pv, ((AstPolyParam) {
+ .kind = PPK_Baked_Value,
+ .idx = param_idx,
+
+ .poly_sym = (AstNode *) curr_param.local,
+ .type_expr = curr_param.local->type_node,
+ }));
+
+ *parser->polymorph_context.poly_params = pv;
+ }
+
curr_param.default_value = NULL;
if (parser->curr->type != ')')
return;
}
-// e
-// '#' <symbol>
-static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
- if (parser->curr->type != '#') return 0;
-
- expect_token(parser, '#');
- OnyxToken* sym = expect_token(parser, Token_Type_Symbol);
-
- b32 match = (strlen(dir) == (u64) sym->length) && (strncmp(dir, sym->text, sym->length) == 0);
- if (!match) {
- unconsume_token(parser);
- unconsume_token(parser);
- }
- return match;
-}
-
// 'proc' <func_params> ('->' <type>)? <directive>* <block>
static AstFunction* parse_function_definition(OnyxParser* parser) {
OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
static void symres_polyproc(AstPolyProc* pp) {
pp->poly_scope = semstate.curr_scope;
+ bh_arr_each(AstPolyParam, param, pp->poly_params) {
+ if (param->kind != PPK_Baked_Value) continue;
+
+ param->type_expr = symres_type(param->type_expr);
+ }
+
+ // CLEANUP: This was copied from symres_function_header.
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.");
return result;
}
-static Type* lookup_actual_type_in_arguments(AstPolyProc* pp, AstPolyParam* param, Arguments* args, char** err_msg) {
+static AstTyped* lookup_param_in_arguments(AstPolyProc* pp, AstPolyParam* param, Arguments* args, char** err_msg) {
bh_arr(AstTyped *) arg_arr = args->values;
bh_arr(AstNamedValue *) named_values = args->named_values;
bh_arr_each(AstNamedValue *, named_value, named_values) {
if (token_equals(param_name, (*named_value)->token)) {
- return resolve_expression_type((AstTyped *) (*named_value)->value);
+ return (AstTyped *) (*named_value)->value;
}
}
if (err_msg) *err_msg = "Not enough arguments to polymorphic procedure. This error message may not be entirely right.";
} else {
- return resolve_expression_type((AstTyped *) arg_arr[param->idx]);
+ return (AstTyped *) arg_arr[param->idx];
}
return NULL;
}
if (already_solved) continue;
- Type* actual_type = NULL;
+ // CLEANUP CLEANUP CLEANUP
+ PolySolveResult resolved;
- if (pp_lookup == PPLM_By_Call) {
- AstCall* call = (AstCall *) actual;
+ if (param->kind == PPK_Poly_Type) {
+ Type* actual_type = NULL;
- actual_type = lookup_actual_type_in_arguments(pp, param, &call->args, err_msg);
- if (actual_type == NULL) goto sln_not_found;
- }
+ if (pp_lookup == PPLM_By_Call) {
+ AstCall* call = (AstCall *) actual;
- else if (pp_lookup == PPLM_By_Arguments) {
- Arguments* args = (Arguments *) actual;
+ AstTyped* typed_param = lookup_param_in_arguments(pp, param, &call->args, err_msg);
+ if (typed_param == NULL) goto sln_not_found;
- actual_type = lookup_actual_type_in_arguments(pp, param, args, err_msg);
- if (actual_type == NULL) goto sln_not_found;
- }
+ actual_type = resolve_expression_type(typed_param);
+ if (actual_type == NULL) goto sln_not_found;
+ }
+
+ else if (pp_lookup == PPLM_By_Arguments) {
+ Arguments* args = (Arguments *) actual;
+
+ AstTyped* typed_param = lookup_param_in_arguments(pp, param, args, err_msg);
+ if (typed_param == NULL) goto sln_not_found;
+
+ actual_type = resolve_expression_type(typed_param);
+ if (actual_type == NULL) goto sln_not_found;
+ }
+
+ else if (pp_lookup == PPLM_By_Function_Type) {
+ Type* ft = (Type*) actual;
+ if (param->idx >= ft->Function.param_count) {
+ if (err_msg) *err_msg = "Incompatible polymorphic argument to function parameter.";
+ goto sln_not_found;
+ }
- else if (pp_lookup == PPLM_By_Function_Type) {
- Type* ft = (Type*) actual;
- if (param->idx >= ft->Function.param_count) {
- if (err_msg) *err_msg = "Incompatible polymorphic argument to function parameter.";
+ actual_type = ft->Function.params[param->idx];
+ }
+
+ else {
+ if (err_msg) *err_msg = "Cannot resolve polymorphic function type.";
goto sln_not_found;
}
- actual_type = ft->Function.params[param->idx];
- }
+ resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
- else {
- if (err_msg) *err_msg = "Cannot resolve polymorphic function type.";
- goto sln_not_found;
- }
+ } else if (param->kind == PPK_Baked_Value) {
+ AstTyped* value = NULL;
+
+ if (pp_lookup == PPLM_By_Call) {
+ AstCall* call = (AstCall *) actual;
+
+ value = lookup_param_in_arguments(pp, param, &call->args, err_msg);
+ if (value == NULL) goto sln_not_found;
+ }
+
+ else if (pp_lookup == PPLM_By_Arguments) {
+ Arguments* args = (Arguments *) actual;
+
+ value = lookup_param_in_arguments(pp, param, args, err_msg);
+ if (value == NULL) goto sln_not_found;
+ }
+
+ else if (pp_lookup == PPLM_By_Function_Type) {
+ *err_msg = "Function type cannot be used to solved for baked parameter value.";
+ goto sln_not_found;
+ }
+
+ else {
+ if (err_msg) *err_msg = "Cannot resolve polymorphic function type.";
+ goto sln_not_found;
+ }
+
+ AstTyped* orig_value = value;
+ if (value->kind == Ast_Kind_Argument) {
+ value = ((AstArgument *) value)->value;
+ }
+
+ if (param->type_expr == (AstType *) &type_expr_symbol) {
+ if (!node_is_type((AstNode *) value)) {
+ *err_msg = "Expected type expression.";
+ goto sln_not_found;
+ }
- PolySolveResult resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
+ resolved = ((PolySolveResult) {
+ .kind = PSK_Type,
+ .actual = type_build_from_ast(semstate.node_allocator, (AstType *) value),
+ });
+
+ } else {
+ // CLEANUP
+ if ((value->flags & Ast_Flag_Comptime) == 0) {
+ *err_msg = "Expected compile-time known argument.";
+ goto sln_not_found;
+ }
+
+ if (param->type == NULL)
+ param->type = type_build_from_ast(semstate.node_allocator, param->type_expr);
+
+ if (!type_check_or_auto_cast(&value, param->type)) {
+ *err_msg = "Expected parameter of a different type. This error message should be wayyy better.";
+ goto sln_not_found;
+ }
+
+ resolved = ((PolySolveResult) {
+ .kind = PSK_Value,
+ .value = value,
+ });
+ }
+
+ if (orig_value->kind == Ast_Kind_Argument) {
+ ((AstArgument *) orig_value)->is_baked = 1;
+ }
+ }
switch (resolved.kind) {
case PSK_Undefined:
if (err_msg) *err_msg = bh_aprintf(global_heap_allocator,
- "Unable to solve for polymoprhic variable '%b', using the type '%s'.",
+ "Unable to solve for polymoprhic variable '%b'.",
param->poly_sym->token->text,
- param->poly_sym->token->length,
- type_get_name(actual_type));
+ param->poly_sym->token->length);
+ // type_get_name(actual_type));
goto sln_not_found;
case PSK_Type:
if (slns == NULL) {
if (err_msg != NULL) onyx_report_error(tkn->pos, err_msg);
else onyx_report_error(tkn->pos, "Some kind of error occured when generating a polymorphic procedure. You hopefully will not see this");
+
+ return NULL;
}
AstFunction* result = polymorphic_proc_solidify(pp, slns, tkn);
solidified_func.func->generated_from = tkn;
+ // HACK HACK HACK
+ u32 removed_params = 0;
+ bh_arr_each(AstPolyParam, param, pp->poly_params) {
+ if (param->kind != PPK_Baked_Value) continue;
+
+ bh_arr_deleten(solidified_func.func->params, param->idx - removed_params, 1);
+ removed_params++;
+ }
+
if (!add_solidified_function_entities(solidified_func, 0)) {
onyx_report_error(tkn->pos, "Error in polymorphic procedure header generated from this call site.");
return NULL;
bh_arr_each(AstTyped *, parg, call->args.values) {
AstArgument* arg = (AstArgument *) *parg;
+ if (arg->is_baked) continue;
b32 place_on_stack = 0;
b32 arg_is_compound = type_is_compound(arg->value->type);