aboutsummaryrefslogtreecommitdiff
path: root/src/checker/expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker/expr.cpp')
-rw-r--r--src/checker/expr.cpp102
1 files changed, 85 insertions, 17 deletions
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp
index ca3667108..dd49e5452 100644
--- a/src/checker/expr.cpp
+++ b/src/checker/expr.cpp
@@ -459,10 +459,12 @@ void check_enum_type(Checker *c, Type *enum_type, AstNode *node) {
enum_type->Record.other_field_count = et->field_count;
}
-Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize field_count) {
+Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize field_count, b32 *is_variadic_) {
if (field_list == NULL || field_count == 0)
return NULL;
+ b32 is_variadic = false;
+
Type *tuple = make_type_tuple(c->allocator);
Entity **variables = gb_alloc_array(c->allocator, Entity *, field_count);
@@ -471,6 +473,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize fiel
ast_node(f, Field, field);
AstNode *type_expr = f->type;
if (type_expr) {
+ if (type_expr->kind == AstNode_Ellipsis) {
+ type_expr = type_expr->Ellipsis.expr;
+ if (field->next == NULL) {
+ is_variadic = true;
+ } else {
+ error(&c->error_collector, ast_node_token(field), "Invalid AST: Invalid variadic parameter");
+ }
+ }
+
Type *type = check_type(c, type_expr);
for (AstNode *name = f->name_list; name != NULL; name = name->next) {
if (name->kind == AstNode_Ident) {
@@ -478,14 +489,24 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize fiel
add_entity(c, scope, name, param);
variables[variable_index++] = param;
} else {
- error(&c->error_collector, ast_node_token(name), "Invalid parameter (invalid AST)");
+ error(&c->error_collector, ast_node_token(name), "Invalid AST: Invalid parameter");
}
}
}
}
+
+ if (is_variadic && field_count > 0) {
+ // NOTE(bill): Change last variadic parameter to be a slice
+ // Custom Calling convention for variadic parameters
+ Entity *end = variables[field_count-1];
+ end->type = make_type_slice(c->allocator, end->type);
+ }
+
tuple->Tuple.variables = variables;
tuple->Tuple.variable_count = field_count;
+ if (is_variadic_) *is_variadic_ = is_variadic;
+
return tuple;
}
@@ -520,7 +541,8 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
// gb_printf("%td -> %td\n", param_count, result_count);
- Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count);
+ b32 variadic = false;
+ Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count, &variadic);
Type *results = check_get_results(c, c->context.scope, pt->result_list, result_count);
type->Proc.scope = c->context.scope;
@@ -528,6 +550,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
type->Proc.param_count = pt->param_count;
type->Proc.results = results;
type->Proc.result_count = pt->result_count;
+ type->Proc.variadic = variadic;
}
@@ -772,10 +795,19 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
goto end;
case_end;
- default:
+ default: {
+ if (e->kind == AstNode_CallExpr) {
+ Operand o = {};
+ check_expr_or_type(c, &o, e);
+ if (o.mode == Addressing_Type) {
+ type = o.type;
+ goto end;
+ }
+ }
+
err_str = expr_to_string(e);
error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err_str);
- break;
+ } break;
}
type = t_invalid;
@@ -1894,7 +1926,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
case BuiltinProc_size_of_val:
// size_of_val :: proc(val: Type) -> int
- check_assignment(c, operand, NULL, make_string("argument of `size_of`"));
+ check_assignment(c, operand, NULL, make_string("argument of `size_of_val`"));
if (operand->mode == Addressing_Invalid)
return false;
@@ -1917,7 +1949,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
case BuiltinProc_align_of_val:
// align_of_val :: proc(val: Type) -> int
- check_assignment(c, operand, NULL, make_string("argument of `align_of`"));
+ check_assignment(c, operand, NULL, make_string("argument of `align_of_val`"));
if (operand->mode == Addressing_Invalid)
return false;
@@ -1996,6 +2028,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
operand->type = t_int;
} break;
+ case BuiltinProc_type_of_val:
+ // type_of_val :: proc(val: Type) -> type(Type)
+ check_assignment(c, operand, NULL, make_string("argument of `type_of_val`"));
+ if (operand->mode == Addressing_Invalid)
+ return false;
+ operand->mode = Addressing_Type;
+ break;
+
case BuiltinProc_assert:
// assert :: proc(cond: bool)
@@ -2519,14 +2559,20 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
isize error_code = 0;
isize param_index = 0;
isize param_count = 0;
+ b32 variadic = proc_type->Proc.variadic;
- if (proc_type->Proc.params)
+ if (proc_type->Proc.params) {
param_count = proc_type->Proc.params->Tuple.variable_count;
+ }
- if (ce->arg_list_count == 0 && param_count == 0)
- return;
+ if (ce->arg_list_count == 0) {
+ if (variadic && param_count-1 == 0)
+ return;
+ if (param_count == 0)
+ return;
+ }
- if (ce->arg_list_count > param_count) {
+ if (ce->arg_list_count > param_count && !variadic) {
error_code = +1;
} else {
Entity **sig_params = proc_type->Proc.params->Tuple.variables;
@@ -2537,19 +2583,40 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
continue;
if (operand->type->kind != Type_Tuple) {
check_not_tuple(c, operand);
- check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true);
+ isize index = param_index;
+ b32 end_variadic = false;
+ if (variadic && param_index >= param_count-1) {
+ index = param_count-1;
+ end_variadic = true;
+ }
+ Type *arg_type = sig_params[index]->type;
+ if (end_variadic && is_type_slice(arg_type)) {
+ arg_type = get_base_type(arg_type)->Slice.elem;
+ }
+ check_assignment(c, operand, arg_type, make_string("argument"), true);
param_index++;
} else {
auto *tuple = &operand->type->Tuple;
isize i = 0;
for (;
- i < tuple->variable_count && param_index < param_count;
- i++, param_index++) {
+ i < tuple->variable_count && (param_index < param_count && !variadic);
+ i++) {
Entity *e = tuple->variables[i];
operand->type = e->type;
operand->mode = Addressing_Value;
check_not_tuple(c, operand);
- check_assignment(c, operand, sig_params[param_index]->type, make_string("argument"), true);
+ isize index = param_index;
+ b32 end_variadic = false;
+ if (variadic && param_index >= param_count-1) {
+ index = param_count-1;
+ end_variadic = true;
+ }
+ Type *arg_type = sig_params[index]->type;
+ if (end_variadic && is_type_slice(arg_type)) {
+ arg_type = get_base_type(arg_type)->Slice.elem;
+ }
+ check_assignment(c, operand, arg_type, make_string("argument"), true);
+ param_index++;
}
if (i < tuple->variable_count && param_index == param_count) {
@@ -2558,12 +2625,13 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
}
}
- if (param_index >= param_count)
+ if (!variadic && param_index >= param_count)
break;
}
- if (param_index < param_count) {
+ if ((!variadic && param_index < param_count) ||
+ (variadic && param_index < param_count-1)) {
error_code = -1;
} else if (call_arg != NULL && call_arg->next != NULL) {
error_code = +1;