diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index f858530ab..e35e12d85 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -326,7 +326,7 @@ func int boba(int y, int j) } return x; } -func int test(int x) +func int test(int x = 100) { x = x + 1; x = x +% 1; @@ -512,10 +512,16 @@ func int testPointers(int x, int j = 0, double foo = 3.2) z - &y > 0 ? 1 : z - &y; return 1; } + +func void testDefault(int x = 2, int y = 100, int z = -100) +{ + printf("x = %d, y = %d, z = %d\n", x, y, z); +} func int main(int x) { printf("Helo!\n"); - testPointers(2, 3, 2.3); + testDefault(y = 99); + testPointers(2, 3); int efd = 9; uint fefoek = 1; printf("Helo: %d\n", efd + cast(fefoek, int)); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index b676f03d5..f817e6b66 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -281,6 +281,7 @@ typedef struct _FunctionSignature { CallConvention convention : 4; bool variadic : 1; + bool has_default : 1; bool throw_any : 1; TypeInfo *rtype; Decl** params; diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index c09622bca..07f441fe3 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -300,7 +300,7 @@ static Expr *parse_call_expr(Context *context, Expr *left) Expr *call = EXPR_NEW_EXPR(EXPR_CALL, left); call->call_expr.function = left; call->call_expr.arguments = params; - + RANGE_EXTEND_PREV(call); return call; } diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 12ead3405..de3746006 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -161,8 +161,9 @@ static inline bool sema_analyse_struct_union(Context *context, Decl *decl) } -static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function) +static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function, bool *has_default) { + *has_default = false; assert(param->decl_kind == DECL_VAR); assert(param->var.kind == VARDECL_PARAM); if (!sema_resolve_type_info(context, param->var.type_info)) @@ -184,6 +185,7 @@ static inline bool sema_analyse_function_param(Context *context, Decl *param, bo SEMA_ERROR(expr, "Only constant expressions may be used as default values."); return false; } + *has_default = true; } return true; } @@ -212,12 +214,14 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi Decl *param = signature->params[i]; assert(param->resolve_status == RESOLVE_NOT_DONE); param->resolve_status = RESOLVE_RUNNING; - if (!sema_analyse_function_param(context, param, is_function)) + bool has_default; + if (!sema_analyse_function_param(context, param, is_function, &has_default)) { decl_poison(param); all_ok = false; continue; } + signature->has_default = signature->has_default || has_default; param->resolve_status = RESOLVE_DONE; if (i > 0 && all_ok) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 650d311c4..f43bdf609 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -223,30 +223,94 @@ static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr * static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *expr) { TODO }; +static inline int find_index_of_named_parameter(Decl** func_params, Expr *expr) +{ + if (expr->expr_kind != EXPR_IDENTIFIER || expr->identifier_expr.path) + { + SEMA_ERROR(expr, "Expected the name of a function parameter here, enclose the assignment expression in ()."); + return -1; + } + const char *name = expr->identifier_expr.identifier; + VECEACH(func_params, i) + { + if (func_params[i]->name == name) return (int)i; + } + SEMA_ERROR(expr, "There's no parameter with the name '%s', if you want an assignment expression, enclose it in ().", name); + return -1; +} + static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr *expr, Decl *decl) { - Expr **args =expr->call_expr.arguments; - Decl **func_params = decl->func.function_signature.params; - unsigned error_params = decl->func.function_signature.throw_any || decl->func.function_signature.throws; + Expr **args = expr->call_expr.arguments; + FunctionSignature *signature = &decl->func.function_signature; + Decl **func_params = signature->params; + unsigned error_params = signature->throw_any || signature->throws; if (error_params) { TODO } - unsigned num_args = vec_size(args); - // unsigned num_params = vec_size(func_params); - // TODO handle named parameters, handle default parameters, varargs etc unsigned func_param_count = vec_size(func_params); + unsigned num_args = vec_size(args); + unsigned entries_needed = func_param_count > num_args ? func_param_count : num_args; + Expr **actual_args = VECNEW(Expr*, entries_needed); + for (unsigned i = 0; i < entries_needed; i++) vec_add(actual_args, NULL); + memset(actual_args, 0, entries_needed * sizeof(Expr*)); + bool uses_named_parameters = false; + for (unsigned i = 0; i < num_args; i++) { Expr *arg = args[i]; - if (func_param_count >= i) + // Named parameters + if (arg->expr_kind == EXPR_BINARY && arg->binary_expr.operator == BINARYOP_ASSIGN) { - if (!sema_analyse_expr_of_required_type(context, NULL, arg)) return false; + uses_named_parameters = true; + int index = find_index_of_named_parameter(func_params, arg->binary_expr.left); + if (index < 0) return false; + if (actual_args[index]) + { + SEMA_ERROR(arg, "The parameter '%s' was already set once.", func_params[index]->name); + return false; + } + if (!sema_analyse_expr_of_required_type(context, func_params[index]->type, arg->binary_expr.right)) return false; + actual_args[index] = arg->binary_expr.right; continue; } + + if (i >= func_param_count) + { + if (!signature->variadic) + { + SEMA_ERROR(expr, "Too many parameters for this function."); + return false; + } + if (!sema_analyse_expr_of_required_type(context, NULL, arg)) return false; + actual_args[i] = arg; + continue; + } + + if (uses_named_parameters) + { + SEMA_ERROR(expr, "A regular parameter cannot follow a named parameter."); + return false; + } if (!sema_analyse_expr_of_required_type(context, func_params[i]->type, arg)) return false; + actual_args[i] = arg; + } + for (unsigned i = 0; i < entries_needed; i++) + { + if (actual_args[i]) continue; + + if (func_params[i]->var.init_expr) + { + actual_args[i] = func_params[i]->var.init_expr; + continue; + } + + SEMA_ERROR(expr, "Parameter '%s' was not set.", func_params[i]->name); + return false; } expr->type = decl->func.function_signature.rtype->type; + expr->call_expr.arguments = actual_args; return true; }