mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-14 15:11:25 -07:00
Allow for default arguments after a variadic parameter
This commit is contained in:
+18
-3
@@ -4156,6 +4156,22 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
|
||||
param_count = param_tuple->variables.count;
|
||||
if (variadic) {
|
||||
for (isize i = param_count-1; i >= 0; i--) {
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (e->kind == Entity_TypeName) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (e->kind == Entity_Variable) {
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid ||
|
||||
e->Variable.default_is_nil ||
|
||||
e->Variable.default_is_location) {
|
||||
param_count--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
param_count--;
|
||||
}
|
||||
}
|
||||
@@ -4262,9 +4278,8 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
|
||||
continue;
|
||||
}
|
||||
if (variadic) {
|
||||
o = operands[operand_index];
|
||||
}
|
||||
|
||||
|
||||
i64 s = 0;
|
||||
if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
|
||||
if (show_error) {
|
||||
|
||||
+32
-13
@@ -1210,7 +1210,7 @@ Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand opera
|
||||
}
|
||||
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
|
||||
if (_params == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1250,6 +1250,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
|
||||
|
||||
bool is_variadic = false;
|
||||
isize variadic_index = -1;
|
||||
bool is_c_vararg = false;
|
||||
Array<Entity *> variables = {};
|
||||
array_init(&variables, c->allocator, variable_count);
|
||||
@@ -1270,7 +1271,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
bool detemine_type_from_operand = false;
|
||||
Type *specialization = nullptr;
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
bool is_constant_value = (p->flags&FieldFlag_const) != 0;
|
||||
|
||||
|
||||
@@ -1304,6 +1305,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
add_entity_use(c, e->identifier, e);
|
||||
} else {
|
||||
error(default_value, "Default parameter must be a constant");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1315,12 +1317,21 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
} else {
|
||||
if (type_expr->kind == AstNode_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
#if 1
|
||||
is_variadic = true;
|
||||
variadic_index = variables.count;
|
||||
if (p->names.count != 1) {
|
||||
error(param, "Invalid AST: Invalid variadic parameter with multiple names");
|
||||
success = false;
|
||||
}
|
||||
#else
|
||||
if (i+1 == params.count) {
|
||||
is_variadic = true;
|
||||
} else {
|
||||
error(param, "Invalid AST: Invalid variadic parameter");
|
||||
success = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (type_expr->kind == AstNode_TypeType) {
|
||||
ast_node(tt, TypeType, type_expr);
|
||||
@@ -1360,8 +1371,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
if (default_value != nullptr) {
|
||||
if (type_expr->kind == AstNode_TypeType) {
|
||||
error(default_value, "A type parameter may not have a default value");
|
||||
continue;
|
||||
} else if (is_constant_value) {
|
||||
error(default_value, "A constant parameter may not have a default value");
|
||||
continue;
|
||||
} else {
|
||||
Operand o = {};
|
||||
if (default_value->kind == AstNode_BasicDirective &&
|
||||
@@ -1404,23 +1417,22 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
check_is_assignable_to(c, &o, type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (type == nullptr) {
|
||||
error(params[i], "Invalid parameter type");
|
||||
error(param, "Invalid parameter type");
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
if (is_type_untyped_undef(type)) {
|
||||
error(params[i], "Cannot determine parameter type from ---");
|
||||
error(param, "Cannot determine parameter type from ---");
|
||||
} else {
|
||||
error(params[i], "Cannot determine parameter type from a nil");
|
||||
error(param, "Cannot determine parameter type from a nil");
|
||||
}
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_empty_union(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(params[i], "Invalid use of an empty union `%s`", str);
|
||||
error(param, "Invalid use of an empty union `%s`", str);
|
||||
gb_string_free(str);
|
||||
type = t_invalid;
|
||||
}
|
||||
@@ -1429,7 +1441,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
if (p->flags&FieldFlag_c_vararg) {
|
||||
if (p->type == nullptr ||
|
||||
p->type->kind != AstNode_Ellipsis) {
|
||||
error(params[i], "`#c_vararg` can only be applied to variadic type fields");
|
||||
error(param, "`#c_vararg` can only be applied to variadic type fields");
|
||||
p->flags &= ~FieldFlag_c_vararg; // Remove the flag
|
||||
} else {
|
||||
is_c_vararg = true;
|
||||
@@ -1438,10 +1450,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
|
||||
if (is_constant_value) {
|
||||
if (is_type_param) {
|
||||
error(p->type, "`$` is not needed for a `type` parameter");
|
||||
error(param, "`$` is not needed for a `type` parameter");
|
||||
}
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
error(p->type, "`#no_alias` can only be applied to variable fields of pointer type");
|
||||
error(param, "`#no_alias` can only be applied to variable fields of pointer type");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
|
||||
@@ -1505,7 +1517,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
if (!is_type_pointer(type)) {
|
||||
error(params[i], "`#no_alias` can only be applied to fields of pointer type");
|
||||
error(name, "`#no_alias` can only be applied to fields of pointer type");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
}
|
||||
@@ -1549,11 +1561,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
|
||||
|
||||
if (is_variadic) {
|
||||
GB_ASSERT(variadic_index >= 0);
|
||||
}
|
||||
|
||||
if (is_variadic) {
|
||||
GB_ASSERT(params.count > 0);
|
||||
// NOTE(bill): Change last variadic parameter to be a slice
|
||||
// Custom Calling convention for variadic parameters
|
||||
Entity *end = variables[variable_count-1];
|
||||
Entity *end = variables[variadic_index];
|
||||
end->type = make_type_slice(c->allocator, end->type);
|
||||
end->flags |= EntityFlag_Ellipsis;
|
||||
if (is_c_vararg) {
|
||||
@@ -1581,6 +1597,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
if (success_) *success_ = success;
|
||||
if (specialization_count_) *specialization_count_ = specialization_count;
|
||||
if (is_variadic_) *is_variadic_ = is_variadic;
|
||||
if (variadic_index_) *variadic_index_ = variadic_index;
|
||||
|
||||
return tuple;
|
||||
}
|
||||
@@ -1904,9 +1921,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
}
|
||||
|
||||
bool variadic = false;
|
||||
isize variadic_index = -1;
|
||||
bool success = true;
|
||||
isize specialization_count = 0;
|
||||
Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands);
|
||||
Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
|
||||
Type *results = check_get_results(c, c->context.scope, pt->results);
|
||||
|
||||
|
||||
@@ -1941,6 +1959,7 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
type->Proc.results = results;
|
||||
type->Proc.result_count = cast(i32)result_count;
|
||||
type->Proc.variadic = variadic;
|
||||
type->Proc.variadic_index = variadic_index;
|
||||
type->Proc.calling_convention = cc;
|
||||
type->Proc.is_polymorphic = pt->generic;
|
||||
type->Proc.specialization_count = specialization_count;
|
||||
|
||||
+100
-50
@@ -1821,6 +1821,11 @@ Type *ir_addr_type(irAddr addr) {
|
||||
return type_deref(t);
|
||||
}
|
||||
|
||||
irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos);
|
||||
irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node);
|
||||
irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
|
||||
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
|
||||
|
||||
irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
|
||||
irValue *map_key, irValue *map_value) {
|
||||
map_type = base_type(map_type);
|
||||
@@ -1832,17 +1837,15 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T
|
||||
irValue *ptr = ir_add_local_generated(proc, ir_type(v));
|
||||
ir_emit_store(proc, ptr, v);
|
||||
|
||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
|
||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
args[2] = ir_emit_conv(proc, ptr, t_rawptr);
|
||||
|
||||
return ir_emit_global_call(proc, "__dynamic_map_set", args, 3);
|
||||
args[3] = ir_emit_source_code_location(proc, nullptr);
|
||||
return ir_emit_global_call(proc, "__dynamic_map_set", args, 4);
|
||||
}
|
||||
|
||||
|
||||
irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
|
||||
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
|
||||
|
||||
irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) {
|
||||
if (addr.addr == nullptr) {
|
||||
@@ -3943,12 +3946,25 @@ irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, Token
|
||||
gbAllocator a = proc->module->allocator;
|
||||
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||
args[0] = ir_find_or_add_entity_string(proc->module, pos.file);
|
||||
args[1] = ir_const_i64(a, pos.line);
|
||||
args[2] = ir_const_i64(a, pos.column);
|
||||
args[1] = ir_const_int(a, pos.line);
|
||||
args[2] = ir_const_int(a, pos.column);
|
||||
args[3] = ir_find_or_add_entity_string(proc->module, procedure);
|
||||
return ir_emit_global_call(proc, "make_source_code_location", args, 4);
|
||||
}
|
||||
|
||||
|
||||
irValue *ir_emit_source_code_location(irProcedure *proc, AstNode *node) {
|
||||
String proc_name = {};
|
||||
if (proc->entity) {
|
||||
proc_name = proc->entity->token.string;
|
||||
}
|
||||
TokenPos pos = {};
|
||||
if (node) {
|
||||
pos = ast_node_token(node).pos;
|
||||
}
|
||||
return ir_emit_source_code_location(proc, proc_name, pos);
|
||||
}
|
||||
|
||||
void ir_emit_increment(irProcedure *proc, irValue *addr) {
|
||||
GB_ASSERT(is_type_pointer(ir_type(addr)));
|
||||
Type *type = type_deref(ir_type(addr));
|
||||
@@ -4182,10 +4198,11 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
|
||||
|
||||
irValue *map = ir_add_local_generated(proc, type);
|
||||
irValue *header = ir_gen_map_header(proc, map, base_type(type));
|
||||
irValue **args = gb_alloc_array(a, irValue *, 2);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 3);
|
||||
args[0] = header;
|
||||
args[1] = cap;
|
||||
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
||||
args[2] = ir_emit_source_code_location(proc, ce->args[0]);
|
||||
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3);
|
||||
|
||||
return ir_emit_load(proc, map);
|
||||
} else if (is_type_dynamic_array(type)) {
|
||||
@@ -4202,13 +4219,14 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
|
||||
ir_emit_slice_bounds_check(proc, ast_node_token(ce->args[0]), v_zero, len, cap, false);
|
||||
|
||||
irValue *array = ir_add_local_generated(proc, type);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 5);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 6);
|
||||
args[0] = ir_emit_conv(proc, array, t_rawptr);
|
||||
args[1] = ir_const_int(a, type_size_of(a, elem_type));
|
||||
args[2] = ir_const_int(a, type_align_of(a, elem_type));
|
||||
args[3] = len;
|
||||
args[4] = cap;
|
||||
ir_emit_global_call(proc, "__dynamic_array_make", args, 5);
|
||||
args[5] = ir_emit_source_code_location(proc, ce->args[0]);
|
||||
ir_emit_global_call(proc, "__dynamic_array_make", args, 6);
|
||||
|
||||
if (ir_type_has_default_values(elem_type)) {
|
||||
ir_init_data_with_defaults(proc, ir_dynamic_array_elem(proc, ir_emit_load(proc, array)), len);
|
||||
@@ -5006,10 +5024,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
GB_ASSERT(value != nullptr);
|
||||
Type *proc_type_ = base_type(ir_type(value));
|
||||
GB_ASSERT(proc_type_->kind == Type_Proc);
|
||||
TypeProc *type = &proc_type_->Proc;
|
||||
TypeProc *pt = &proc_type_->Proc;
|
||||
|
||||
if (is_call_expr_field_value(ce)) {
|
||||
isize param_count = type->param_count;
|
||||
isize param_count = pt->param_count;
|
||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count);
|
||||
|
||||
for_array(arg_index, ce->args) {
|
||||
@@ -5017,7 +5035,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
ast_node(fv, FieldValue, arg);
|
||||
GB_ASSERT(fv->field->kind == AstNode_Ident);
|
||||
String name = fv->field->Ident.token.string;
|
||||
isize index = lookup_procedure_parameter(type, name);
|
||||
isize index = lookup_procedure_parameter(pt, name);
|
||||
GB_ASSERT(index >= 0);
|
||||
TypeAndValue tav = type_and_value_of_expr(proc->module->info, fv->value);
|
||||
if (tav.mode == Addressing_Type) {
|
||||
@@ -5026,9 +5044,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
args[index] = ir_build_expr(proc, fv->value);
|
||||
}
|
||||
}
|
||||
TypeTuple *pt = &type->params->Tuple;
|
||||
TypeTuple *params = &pt->params->Tuple;
|
||||
for (isize i = 0; i < param_count; i++) {
|
||||
Entity *e = pt->variables[i];
|
||||
Entity *e = params->variables[i];
|
||||
if (e->kind == Entity_TypeName) {
|
||||
args[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||
} else if (e->kind == Entity_Constant) {
|
||||
@@ -5063,10 +5081,29 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count));
|
||||
bool variadic = type->variadic;
|
||||
i64 param_count = 0;
|
||||
if (pt->params) {
|
||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
||||
param_count = pt->params->Tuple.variables.count;
|
||||
}
|
||||
|
||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(param_count, arg_count));
|
||||
isize variadic_index = pt->variadic_index;
|
||||
bool variadic = pt->variadic && variadic_index >= 0;
|
||||
bool vari_expand = ce->ellipsis.pos.line != 0;
|
||||
bool is_c_vararg = type->c_vararg;
|
||||
bool is_c_vararg = pt->c_vararg;
|
||||
|
||||
String proc_name = {};
|
||||
if (proc->entity != nullptr) {
|
||||
proc_name = proc->entity->token.string;
|
||||
}
|
||||
TokenPos pos = ast_node_token(ce->proc).pos;
|
||||
|
||||
TypeTuple *param_tuple = nullptr;
|
||||
if (pt->params) {
|
||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
||||
param_tuple = &pt->params->Tuple;
|
||||
}
|
||||
|
||||
for_array(i, ce->args) {
|
||||
AstNode *arg = ce->args[i];
|
||||
@@ -5088,32 +5125,23 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
i64 param_count = type->param_count;
|
||||
|
||||
if (type->param_count > 0) {
|
||||
GB_ASSERT_MSG(type->params != nullptr, "%s %td", expr_to_string(expr), type->param_count);
|
||||
TypeTuple *pt = &type->params->Tuple;
|
||||
param_count = type->param_count;
|
||||
if (param_count > 0) {
|
||||
GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
|
||||
GB_ASSERT(param_count < 1000000);
|
||||
|
||||
if (arg_count < param_count) {
|
||||
String procedure = {};
|
||||
if (proc->entity != nullptr) {
|
||||
procedure = proc->entity->token.string;
|
||||
}
|
||||
TokenPos pos = ast_node_token(ce->proc).pos;
|
||||
|
||||
isize end = param_count;
|
||||
if (variadic) {
|
||||
end--;
|
||||
end = variadic_index;
|
||||
}
|
||||
while (arg_index < end) {
|
||||
Entity *e = pt->variables[arg_index];
|
||||
Entity *e = param_tuple->variables[arg_index];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else if (e->Variable.default_is_location) {
|
||||
args[arg_index++] = ir_emit_source_code_location(proc, procedure, pos);
|
||||
args[arg_index++] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||
} else {
|
||||
args[arg_index++] = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
@@ -5124,13 +5152,13 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
GB_ASSERT(variadic);
|
||||
GB_ASSERT(!vari_expand);
|
||||
isize i = 0;
|
||||
for (; i < param_count-1; i++) {
|
||||
Entity *e = pt->variables[i];
|
||||
for (; i < variadic_index; i++) {
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||
}
|
||||
}
|
||||
Type *variadic_type = pt->variables[i]->type;
|
||||
Type *variadic_type = param_tuple->variables[i]->type;
|
||||
GB_ASSERT(is_type_slice(variadic_type));
|
||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
||||
if (!is_type_any(variadic_type)) {
|
||||
@@ -5144,14 +5172,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
} else if (variadic) {
|
||||
isize i = 0;
|
||||
for (; i < param_count-1; i++) {
|
||||
Entity *e = pt->variables[i];
|
||||
for (; i < variadic_index; i++) {
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||
}
|
||||
}
|
||||
if (!vari_expand) {
|
||||
Type *variadic_type = pt->variables[i]->type;
|
||||
Type *variadic_type = param_tuple->variables[i]->type;
|
||||
GB_ASSERT(is_type_slice(variadic_type));
|
||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
||||
for (; i < arg_count; i++) {
|
||||
@@ -5160,7 +5188,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
} else {
|
||||
for (i64 i = 0; i < param_count; i++) {
|
||||
Entity *e = pt->variables[i];
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
GB_ASSERT(args[i] != nullptr);
|
||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||
@@ -5171,15 +5199,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
if (variadic && !vari_expand && !is_c_vararg) {
|
||||
ir_emit_comment(proc, str_lit("variadic call argument generation"));
|
||||
gbAllocator allocator = proc->module->allocator;
|
||||
Type *slice_type = pt->variables[param_count-1]->type;
|
||||
Type *slice_type = param_tuple->variables[variadic_index]->type;
|
||||
Type *elem_type = base_type(slice_type)->Slice.elem;
|
||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||
isize slice_len = arg_count+1 - param_count;
|
||||
isize slice_len = arg_count+1 - (variadic_index+1);
|
||||
|
||||
if (slice_len > 0) {
|
||||
irValue *base_array = ir_add_local_generated(proc, make_type_array(allocator, elem_type, slice_len));
|
||||
|
||||
for (isize i = param_count-1, j = 0; i < arg_count; i++, j++) {
|
||||
for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
|
||||
irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j);
|
||||
ir_emit_store(proc, addr, args[i]);
|
||||
}
|
||||
@@ -5190,7 +5218,20 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
|
||||
arg_count = param_count;
|
||||
args[arg_count-1] = ir_emit_load(proc, slice);
|
||||
args[variadic_index] = ir_emit_load(proc, slice);
|
||||
}
|
||||
}
|
||||
|
||||
if (variadic && variadic_index+1 < param_count) {
|
||||
for (isize i = variadic_index+1; i < param_count; i++) {
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
args[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else if (e->Variable.default_is_location) {
|
||||
args[i] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||
} else {
|
||||
args[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5695,6 +5736,12 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
case Type_Slice: et = bt->Slice.elem; break;
|
||||
}
|
||||
|
||||
String proc_name = {};
|
||||
if (proc->entity) {
|
||||
proc_name = proc->entity->token.string;
|
||||
}
|
||||
TokenPos pos = ast_node_token(expr).pos;
|
||||
|
||||
switch (bt->kind) {
|
||||
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
|
||||
|
||||
@@ -5776,10 +5823,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
gbAllocator a = proc->module->allocator;
|
||||
{
|
||||
irValue **args = gb_alloc_array(a, irValue *, 2);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 3);
|
||||
args[0] = ir_gen_map_header(proc, v, type);
|
||||
args[1] = ir_const_int(a, 2*cl->elems.count);
|
||||
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
|
||||
args[2] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 3);
|
||||
}
|
||||
for_array(field_index, cl->elems) {
|
||||
AstNode *elem = cl->elems[field_index];
|
||||
@@ -5801,12 +5849,13 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
irValue *size = ir_const_int(a, type_size_of(a, elem));
|
||||
irValue *align = ir_const_int(a, type_align_of(a, elem));
|
||||
{
|
||||
irValue **args = gb_alloc_array(a, irValue *, 4);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 5);
|
||||
args[0] = ir_emit_conv(proc, v, t_rawptr);
|
||||
args[1] = size;
|
||||
args[2] = align;
|
||||
args[3] = ir_const_int(a, 2*cl->elems.count);
|
||||
ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
|
||||
args[4] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||
ir_emit_global_call(proc, "__dynamic_array_reserve", args, 5);
|
||||
}
|
||||
|
||||
i64 item_count = cl->elems.count;
|
||||
@@ -5820,13 +5869,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
|
||||
{
|
||||
irValue **args = gb_alloc_array(a, irValue *, 5);
|
||||
irValue **args = gb_alloc_array(a, irValue *, 6);
|
||||
args[0] = ir_emit_conv(proc, v, t_rawptr);
|
||||
args[1] = size;
|
||||
args[2] = align;
|
||||
args[3] = ir_emit_conv(proc, items, t_rawptr);
|
||||
args[4] = ir_const_int(a, item_count);
|
||||
ir_emit_global_call(proc, "__dynamic_array_append", args, 5);
|
||||
args[5] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||
ir_emit_global_call(proc, "__dynamic_array_append", args, 6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+50
-38
@@ -2616,8 +2616,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
|
||||
bool prefix_ellipsis = false;
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
prefix_ellipsis = true;
|
||||
ellipsis = f->curr_token;
|
||||
advance_token(f);
|
||||
ellipsis = expect_token(f, Token_Ellipsis);
|
||||
}
|
||||
|
||||
AstNode *arg = parse_expr(f, false);
|
||||
@@ -2627,10 +2626,6 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
|
||||
if (prefix_ellipsis) {
|
||||
syntax_error(ellipsis, "`...` must be applied to value rather than the field name");
|
||||
}
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
ellipsis = f->curr_token;
|
||||
advance_token(f);
|
||||
}
|
||||
|
||||
AstNode *value = parse_value(f);
|
||||
arg = ast_field_value(f, arg, value, eq);
|
||||
@@ -3339,12 +3334,13 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token)
|
||||
|
||||
|
||||
enum FieldPrefixKind {
|
||||
FieldPrefix_Invalid,
|
||||
FieldPrefix_Unknown = -1,
|
||||
FieldPrefix_Invalid = 0,
|
||||
|
||||
FieldPrefix_Using,
|
||||
FieldPrefix_NoAlias,
|
||||
FieldPrefix_CVarArg,
|
||||
FieldPrefix_Const,
|
||||
FieldPrefix_using,
|
||||
FieldPrefix_no_alias,
|
||||
FieldPrefix_c_var_arg,
|
||||
FieldPrefix_const,
|
||||
};
|
||||
|
||||
FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||
@@ -3353,23 +3349,22 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||
return FieldPrefix_Invalid;
|
||||
|
||||
case Token_using:
|
||||
return FieldPrefix_Using;
|
||||
return FieldPrefix_using;
|
||||
|
||||
|
||||
case Token_Hash: {
|
||||
case Token_Hash:
|
||||
advance_token(f);
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident:
|
||||
if (f->curr_token.string == "no_alias") {
|
||||
return FieldPrefix_NoAlias;
|
||||
return FieldPrefix_no_alias;
|
||||
} else if (f->curr_token.string == "c_vararg") {
|
||||
return FieldPrefix_CVarArg;
|
||||
return FieldPrefix_c_var_arg;
|
||||
} else if (f->curr_token.string == "const") {
|
||||
return FieldPrefix_Const;
|
||||
return FieldPrefix_const;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
return FieldPrefix_Unknown;
|
||||
}
|
||||
return FieldPrefix_Invalid;
|
||||
}
|
||||
@@ -3386,24 +3381,30 @@ u32 parse_field_prefixes(AstFile *f) {
|
||||
if (kind == FieldPrefix_Invalid) {
|
||||
break;
|
||||
}
|
||||
if (kind == FieldPrefix_Unknown) {
|
||||
syntax_error(f->curr_token, "Unknown prefix kind `#%.*s`", LIT(f->curr_token.string));
|
||||
advance_token(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case FieldPrefix_Using: using_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_Const: const_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_using: using_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_no_alias: no_alias_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_c_var_arg: c_vararg_count += 1; advance_token(f); break;
|
||||
case FieldPrefix_const: const_count += 1; advance_token(f); break;
|
||||
}
|
||||
}
|
||||
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
|
||||
if (no_alias_count > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list");
|
||||
if (c_vararg_count > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list");
|
||||
if (const_count > 1) syntax_error(f->curr_token, "Multiple `$` in this field list");
|
||||
if (const_count > 1) syntax_error(f->curr_token, "Multiple `#const` in this field list");
|
||||
|
||||
|
||||
u32 field_flags = 0;
|
||||
if (using_count > 0) field_flags |= FieldFlag_using;
|
||||
if (no_alias_count > 0) field_flags |= FieldFlag_no_alias;
|
||||
if (c_vararg_count > 0) field_flags |= FieldFlag_c_vararg;
|
||||
if (const_count > 0) field_flags |= FieldFlag_const;
|
||||
if (const_count > 0) field_flags |= FieldFlag_const;
|
||||
return field_flags;
|
||||
}
|
||||
|
||||
@@ -3534,10 +3535,10 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
u32 flags = parse_field_prefixes(f);
|
||||
AstNode *param = parse_var_type(f, allow_ellipsis, allow_type_token);
|
||||
if (param->kind == AstNode_Ellipsis) {
|
||||
if (seen_ellipsis) syntax_error(param, "Extra variadic parameter");
|
||||
if (seen_ellipsis) syntax_error(param, "Extra variadic parameter after ellipsis");
|
||||
seen_ellipsis = true;
|
||||
} else if (seen_ellipsis) {
|
||||
syntax_error(param, "Extra parameter have variadic parameters");
|
||||
syntax_error(param, "Extra parameter after ellipsis");
|
||||
}
|
||||
AstNodeAndFlags naf = {param, flags};
|
||||
array_add(&list, naf);
|
||||
@@ -3566,12 +3567,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
||||
}
|
||||
if (type != nullptr && type->kind == AstNode_Ellipsis) {
|
||||
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter");
|
||||
seen_ellipsis = true;
|
||||
} else if (seen_ellipsis) {
|
||||
syntax_error(f->curr_token, "Extra variadic parameter");
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
@@ -3584,6 +3580,16 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
syntax_error(f->curr_token, "Default parameters can only be applied to single values");
|
||||
}
|
||||
|
||||
if (type != nullptr && type->kind == AstNode_Ellipsis) {
|
||||
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
|
||||
seen_ellipsis = true;
|
||||
if (names.count != 1) {
|
||||
syntax_error(type, "Variadic parameters can only have one field name");
|
||||
}
|
||||
} else if (seen_ellipsis && default_value == nullptr) {
|
||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||
}
|
||||
|
||||
parse_expect_field_separator(f, type);
|
||||
AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
||||
array_add(¶ms, param);
|
||||
@@ -3608,12 +3614,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
type = parse_var_type(f, allow_ellipsis, allow_type_token);
|
||||
}
|
||||
if (type != nullptr && type->kind == AstNode_Ellipsis) {
|
||||
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter");
|
||||
seen_ellipsis = true;
|
||||
} else if (seen_ellipsis) {
|
||||
syntax_error(f->curr_token, "Extra variadic parameter");
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
@@ -3626,6 +3627,17 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
syntax_error(f->curr_token, "Default parameters can only be applied to single values");
|
||||
}
|
||||
|
||||
if (type != nullptr && type->kind == AstNode_Ellipsis) {
|
||||
if (seen_ellipsis) syntax_error(type, "Extra variadic parameter after ellipsis");
|
||||
seen_ellipsis = true;
|
||||
if (names.count != 1) {
|
||||
syntax_error(type, "Variadic parameters can only have one field name");
|
||||
}
|
||||
} else if (seen_ellipsis && default_value == nullptr) {
|
||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||
}
|
||||
|
||||
|
||||
bool ok = parse_expect_field_separator(f, param);
|
||||
AstNode *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
||||
array_add(¶ms, param);
|
||||
|
||||
+2
-1
@@ -31,7 +31,7 @@ enum BasicKind {
|
||||
Basic_uintptr,
|
||||
Basic_rawptr,
|
||||
Basic_string, // ^u8 + int
|
||||
Basic_any, // ^Type_Info + rawptr
|
||||
Basic_any, // rawptr + ^Type_Info
|
||||
|
||||
Basic_UntypedBool,
|
||||
Basic_UntypedInteger,
|
||||
@@ -153,6 +153,7 @@ struct TypeStruct {
|
||||
Type * abi_compat_result_type; \
|
||||
bool return_by_pointer; \
|
||||
bool variadic; \
|
||||
i32 variadic_index; \
|
||||
bool require_results; \
|
||||
bool c_vararg; \
|
||||
bool is_polymorphic; \
|
||||
|
||||
Reference in New Issue
Block a user