Merge pull request #24 from c3lang/develop

Support named parameters, default parameters and varargs.
This commit is contained in:
Christoffer Lerno
2020-04-09 16:49:10 +02:00
committed by GitHub
5 changed files with 88 additions and 13 deletions

View File

@@ -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));

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;
}