mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-29 19:00:06 +00:00
Default result values for procedure types; Named result values in return statements
This commit is contained in:
+72
-7
@@ -1221,15 +1221,64 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
isize variable_index = 0;
|
||||
for_array(i, results) {
|
||||
ast_node(field, Field, results[i]);
|
||||
Type *type = check_type(c, field->type);
|
||||
AstNode *default_value = unparen_expr(field->default_value);
|
||||
ExactValue value = {};
|
||||
bool default_is_nil = false;
|
||||
|
||||
Type *type = NULL;
|
||||
if (field->type == NULL) {
|
||||
Operand o = {};
|
||||
check_expr(c, &o, default_value);
|
||||
if (is_operand_nil(o)) {
|
||||
default_is_nil = true;
|
||||
} else if (o.mode != Addressing_Constant) {
|
||||
error(default_value, "Default parameter must be a constant");
|
||||
} else {
|
||||
value = o.value;
|
||||
}
|
||||
|
||||
type = default_type(o.type);
|
||||
} else {
|
||||
type = check_type(c, field->type);
|
||||
|
||||
if (default_value != NULL) {
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, default_value, type);
|
||||
|
||||
if (is_operand_nil(o)) {
|
||||
default_is_nil = true;
|
||||
} else if (o.mode != Addressing_Constant) {
|
||||
error(default_value, "Default parameter must be a constant");
|
||||
} else {
|
||||
value = o.value;
|
||||
}
|
||||
check_is_assignable_to(c, &o, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == NULL) {
|
||||
error(results[i], "Invalid parameter type");
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
error(results[i], "Cannot determine parameter type from a nil");
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
|
||||
if (field->names.count == 0) {
|
||||
Token token = ast_node_token(field->type);
|
||||
token.string = str_lit("");
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
variables[variable_index++] = param;
|
||||
} else {
|
||||
for_array(j, field->names) {
|
||||
Token token = ast_node_token(field->type);
|
||||
Token token = ast_node_token(results[i]);
|
||||
if (field->type != NULL) {
|
||||
token = ast_node_token(field->type);
|
||||
}
|
||||
token.string = str_lit("");
|
||||
|
||||
AstNode *name = field->names[j];
|
||||
@@ -1240,6 +1289,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
}
|
||||
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
variables[variable_index++] = param;
|
||||
}
|
||||
}
|
||||
@@ -5002,6 +5053,20 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
isize lookup_procedure_result(TypeProc *pt, String result_name) {
|
||||
isize result_count = pt->result_count;
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
String name = e->token.string;
|
||||
if (name == "_") {
|
||||
continue;
|
||||
}
|
||||
if (name == result_name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
@@ -5013,7 +5078,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
CallArgumentError err = CallArgumentError_None;
|
||||
|
||||
isize param_count = pt->param_count;
|
||||
bool *params_visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||
bool *visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||
|
||||
for_array(i, ce->args) {
|
||||
AstNode *arg = ce->args[i];
|
||||
@@ -5036,7 +5101,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
err = CallArgumentError_ParameterNotFound;
|
||||
continue;
|
||||
}
|
||||
if (params_visited[index]) {
|
||||
if (visited[index]) {
|
||||
if (show_error) {
|
||||
error(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name));
|
||||
}
|
||||
@@ -5044,7 +5109,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
continue;
|
||||
}
|
||||
|
||||
params_visited[index] = true;
|
||||
visited[index] = true;
|
||||
Operand *o = &operands[i];
|
||||
Entity *e = pt->params->Tuple.variables[index];
|
||||
|
||||
@@ -5076,7 +5141,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
param_count_to_check--;
|
||||
}
|
||||
for (isize i = 0; i < param_count_to_check; i++) {
|
||||
if (!params_visited[i]) {
|
||||
if (!visited[i]) {
|
||||
Entity *e = pt->params->Tuple.variables[i];
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
@@ -5095,7 +5160,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||
if (show_error) {
|
||||
gbString str = type_to_string(e->type);
|
||||
error(call, "Parameter `%.*s` of type `%s` is missing in procedure call",
|
||||
LIT(e->token.string), str);
|
||||
LIT(e->token.string), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
err = CallArgumentError_ParameterMissing;
|
||||
|
||||
+126
-22
@@ -786,37 +786,141 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool first_is_field_value = false;
|
||||
if (rs->results.count > 0) {
|
||||
bool fail = false;
|
||||
first_is_field_value = (rs->results[0]->kind == AstNode_FieldValue);
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
bool mix = false;
|
||||
if (first_is_field_value) {
|
||||
mix = arg->kind != AstNode_FieldValue;
|
||||
} else {
|
||||
mix = arg->kind == AstNode_FieldValue;
|
||||
}
|
||||
if (mix) {
|
||||
error(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed");
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Type *proc_type = c->proc_stack[c->proc_stack.count-1];
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
isize result_count = 0;
|
||||
if (proc_type->Proc.results) {
|
||||
if (pt->results) {
|
||||
result_count = proc_type->Proc.results->Tuple.variable_count;
|
||||
}
|
||||
|
||||
if (result_count > 0) {
|
||||
Entity **variables = NULL;
|
||||
if (proc_type->Proc.results != NULL) {
|
||||
TypeTuple *tuple = &proc_type->Proc.results->Tuple;
|
||||
variables = tuple->variables;
|
||||
|
||||
isize result_count_excluding_defaults = result_count;
|
||||
for (isize i = result_count-1; i >= 0; i--) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
if (e->kind == Entity_TypeName) {
|
||||
break;
|
||||
}
|
||||
if (rs->results.count == 0) {
|
||||
error(node, "Expected %td return values, got 0", result_count);
|
||||
} else {
|
||||
// TokenPos pos = rs->token.pos;
|
||||
// if (pos.line == 10) {
|
||||
// gb_printf_err("%s\n", type_to_string(variables[0]->type));
|
||||
// }
|
||||
check_init_variables(c, variables, result_count,
|
||||
rs->results, str_lit("return statement"));
|
||||
// if (pos.line == 10) {
|
||||
// AstNode *x = rs->results[0];
|
||||
// gb_printf_err("%s\n", expr_to_string(x));
|
||||
// gb_printf_err("%s\n", type_to_string(type_of_expr(&c->info, x)));
|
||||
// }
|
||||
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid ||
|
||||
e->Variable.default_is_nil) {
|
||||
result_count_excluding_defaults--;
|
||||
continue;
|
||||
}
|
||||
} else if (rs->results.count > 0) {
|
||||
error(rs->results[0], "No return values expected");
|
||||
break;
|
||||
}
|
||||
|
||||
Array<Operand> operands = {};
|
||||
defer (array_free(&operands));
|
||||
|
||||
if (first_is_field_value) {
|
||||
array_init_count(&operands, heap_allocator(), rs->results.count);
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
check_expr(c, &operands[i], fv->value);
|
||||
}
|
||||
} else {
|
||||
array_init(&operands, heap_allocator(), 2*rs->results.count);
|
||||
check_unpack_arguments(c, -1, &operands, rs->results, false);
|
||||
}
|
||||
|
||||
|
||||
if (first_is_field_value) {
|
||||
bool *visited = gb_alloc_array(c->allocator, bool, result_count);
|
||||
|
||||
for_array(i, rs->results) {
|
||||
AstNode *arg = rs->results[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
if (fv->field->kind != AstNode_Ident) {
|
||||
gbString expr_str = expr_to_string(fv->field);
|
||||
error(arg, "Invalid parameter name `%s` in return statement", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
continue;
|
||||
}
|
||||
String name = fv->field->Ident.string;
|
||||
isize index = lookup_procedure_result(pt, name);
|
||||
if (index < 0) {
|
||||
error(arg, "No result named `%.*s` for this procedure type", LIT(name));
|
||||
continue;
|
||||
}
|
||||
if (visited[index]) {
|
||||
error(arg, "Duplicate result `%.*s` in return statement", LIT(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
visited[index] = true;
|
||||
Operand *o = &operands[i];
|
||||
Entity *e = pt->results->Tuple.variables[index];
|
||||
check_assignment(c, &operands[i], e->type, str_lit("return statement"));
|
||||
}
|
||||
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
if (!visited[i]) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->Variable.default_is_nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gbString str = type_to_string(e->type);
|
||||
error(node, "Return value `%.*s` of type `%s` is missing in return statement",
|
||||
LIT(e->token.string), str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO(bill): Cleanup this checking of variables
|
||||
if (result_count == 0 && rs->results.count > 0) {
|
||||
error(rs->results[0], "No return values expected");
|
||||
} else if (operands.count > result_count) {
|
||||
error(node, "Expected a maximum of %td return values, got %td", result_count, operands.count);
|
||||
} else if (operands.count < result_count_excluding_defaults) {
|
||||
error(node, "Expected %td return values, got %td", result_count_excluding_defaults, operands.count);
|
||||
} else if (result_count_excluding_defaults == 0) {
|
||||
return;
|
||||
} else if (rs->results.count == 0) {
|
||||
error(node, "Expected %td return values, got 0", result_count_excluding_defaults);
|
||||
} else {
|
||||
isize max_count = rs->results.count;
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
check_assignment(c, &operands[i], e->type, str_lit("return statement"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case_end;
|
||||
|
||||
case_ast_node(fs, ForStmt, node);
|
||||
|
||||
@@ -117,6 +117,39 @@ f64 float_from_string(String string) {
|
||||
i++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (len-i > 2 &&
|
||||
str[i] == '0' &&
|
||||
str[i+1] == 'h') {
|
||||
i += 2;
|
||||
u8 *text = string.text;
|
||||
isize len = string.len;
|
||||
if (has_prefix) {
|
||||
text += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
u64 base = 16;
|
||||
|
||||
u64 result = {0};
|
||||
for (isize i = 0; i < len; i++) {
|
||||
Rune r = cast(Rune)text[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u64 v = bit128__digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result *= base;
|
||||
result += v;
|
||||
}
|
||||
|
||||
|
||||
return *cast(f64 *)&result;
|
||||
}
|
||||
#endif
|
||||
|
||||
f64 value = 0.0;
|
||||
for (; i < len; i++) {
|
||||
Rune r = cast(Rune)str[i];
|
||||
|
||||
+82
-8
@@ -6120,21 +6120,81 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
case_ast_node(rs, ReturnStmt, node);
|
||||
ir_emit_comment(proc, str_lit("ReturnStmt"));
|
||||
irValue *v = NULL;
|
||||
TypeTuple *return_type_tuple = &proc->type->Proc.results->Tuple;
|
||||
TypeTuple *tuple = &proc->type->Proc.results->Tuple;
|
||||
isize return_count = proc->type->Proc.result_count;
|
||||
if (return_count == 0) {
|
||||
isize res_count = rs->results.count;
|
||||
|
||||
if (res_count > 0 &&
|
||||
rs->results[0]->kind == AstNode_FieldValue) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
Array<irValue *> results;
|
||||
array_init_count(&results, proc->module->tmp_allocator, return_count);
|
||||
|
||||
for_array(arg_index, rs->results) {
|
||||
AstNode *arg = rs->results[arg_index];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
GB_ASSERT(fv->field->kind == AstNode_Ident);
|
||||
String name = fv->field->Ident.string;
|
||||
isize index = lookup_procedure_result(&proc->type->Proc, name);
|
||||
GB_ASSERT(index >= 0);
|
||||
irValue *expr = ir_build_expr(proc, fv->value);
|
||||
results[index] = expr;
|
||||
}
|
||||
for (isize i = 0; i < return_count; i++) {
|
||||
Entity *e = tuple->variables[i];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (results[i] == NULL) {
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
results[i] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
results[i] = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
} else {
|
||||
results[i] = ir_emit_conv(proc, results[i], e->type);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.count == 1) {
|
||||
v = results[0];
|
||||
} else {
|
||||
GB_ASSERT(results.count == return_count);
|
||||
|
||||
Type *ret_type = proc->type->Proc.results;
|
||||
v = ir_add_local_generated(proc, ret_type);
|
||||
for_array(i, results) {
|
||||
irValue *field = ir_emit_struct_ep(proc, v, i);
|
||||
irValue *res = results[i];
|
||||
ir_emit_store(proc, field, res);
|
||||
}
|
||||
|
||||
v = ir_emit_load(proc, v);
|
||||
}
|
||||
} else if (return_count == 0) {
|
||||
// No return values
|
||||
} else if (return_count == 1) {
|
||||
Entity *e = return_type_tuple->variables[0];
|
||||
v = ir_build_expr(proc, rs->results[0]);
|
||||
v = ir_emit_conv(proc, v, e->type);
|
||||
Entity *e = tuple->variables[0];
|
||||
if (res_count == 0) {
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
v = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
v = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
} else {
|
||||
v = ir_build_expr(proc, rs->results[0]);
|
||||
v = ir_emit_conv(proc, v, e->type);
|
||||
}
|
||||
} else {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
Array<irValue *> results;
|
||||
array_init(&results, proc->module->tmp_allocator, return_count);
|
||||
|
||||
for_array(res_index, rs->results) {
|
||||
isize total_index = 0;
|
||||
isize res_index = 0;
|
||||
for (; res_index < res_count; res_index++) {
|
||||
irValue *res = ir_build_expr(proc, rs->results[res_index]);
|
||||
Type *t = ir_type(res);
|
||||
if (t->kind == Type_Tuple) {
|
||||
@@ -6142,16 +6202,31 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
Entity *e = t->Tuple.variables[i];
|
||||
irValue *v = ir_emit_struct_ev(proc, res, i);
|
||||
array_add(&results, v);
|
||||
total_index++;
|
||||
}
|
||||
} else {
|
||||
array_add(&results, res);
|
||||
total_index++;
|
||||
}
|
||||
}
|
||||
while (total_index < return_count) {
|
||||
Entity *e = tuple->variables[total_index];
|
||||
irValue *res = NULL;
|
||||
if (e->Variable.default_value.kind != ExactValue_Invalid) {
|
||||
res = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
|
||||
} else {
|
||||
res = ir_value_nil(proc->module->allocator, e->type);
|
||||
}
|
||||
array_add(&results, res);
|
||||
total_index++;
|
||||
}
|
||||
|
||||
GB_ASSERT(results.count == return_count);
|
||||
|
||||
Type *ret_type = proc->type->Proc.results;
|
||||
v = ir_add_local_generated(proc, ret_type);
|
||||
for_array(i, results) {
|
||||
Entity *e = return_type_tuple->variables[i];
|
||||
Entity *e = tuple->variables[i];
|
||||
irValue *res = ir_emit_conv(proc, results[i], e->type);
|
||||
irValue *field = ir_emit_struct_ep(proc, v, i);
|
||||
ir_emit_store(proc, field, res);
|
||||
@@ -6159,7 +6234,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
|
||||
v = ir_emit_load(proc, v);
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
ir_emit_return(proc, v);
|
||||
|
||||
+90
-25
@@ -3158,7 +3158,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
|
||||
return parse_body(f);
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters);
|
||||
|
||||
|
||||
AstNode *parse_results(AstFile *f) {
|
||||
@@ -3170,7 +3170,7 @@ AstNode *parse_results(AstFile *f) {
|
||||
CommentGroup empty_group = {};
|
||||
Token begin_token = f->curr_token;
|
||||
Array<AstNode *> empty_names = {};
|
||||
Array<AstNode *> list = make_ast_node_array(f);
|
||||
Array<AstNode *> list = make_ast_node_array(f, 1);
|
||||
AstNode *type = parse_type(f);
|
||||
array_add(&list, ast_field(f, empty_names, type, NULL, 0, empty_group, empty_group));
|
||||
return ast_field_list(f, begin_token, list);
|
||||
@@ -3178,7 +3178,7 @@ AstNode *parse_results(AstFile *f) {
|
||||
|
||||
AstNode *list = NULL;
|
||||
expect_token(f, Token_OpenParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_CloseParen);
|
||||
list = parse_field_list(f, NULL, 0, Token_CloseParen, true);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
return list;
|
||||
}
|
||||
@@ -3188,7 +3188,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
|
||||
AstNode *results = NULL;
|
||||
|
||||
expect_token(f, Token_OpenParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
|
||||
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen, true);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
results = parse_results(f);
|
||||
|
||||
@@ -3357,7 +3357,7 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
|
||||
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
|
||||
TokenKind separator = Token_Comma;
|
||||
Token start_token = f->curr_token;
|
||||
|
||||
@@ -3370,13 +3370,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
isize total_name_count = 0;
|
||||
bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
|
||||
bool is_procedure = allowed_flags == FieldFlag_Signature;
|
||||
|
||||
while (f->curr_token.kind != follow &&
|
||||
f->curr_token.kind != Token_Colon &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
u32 flags = parse_field_prefixes(f);
|
||||
AstNode *param = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
AstNode *param = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
AstNodeAndFlags naf = {param, flags};
|
||||
array_add(&list, naf);
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
@@ -3403,12 +3402,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
type = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
if (!is_procedure) {
|
||||
if (!allow_default_parameters) {
|
||||
syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
|
||||
}
|
||||
}
|
||||
@@ -3439,12 +3438,12 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
AstNode *default_value = NULL;
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
expect_token_after(f, Token_Colon, "field list");
|
||||
type = parse_var_type(f, allow_ellipsis, is_procedure);
|
||||
type = parse_var_type(f, allow_ellipsis, allow_default_parameters);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
// TODO(bill): Should this be true==lhs or false==rhs?
|
||||
default_value = parse_expr(f, false);
|
||||
if (!is_procedure) {
|
||||
if (!allow_default_parameters) {
|
||||
syntax_error(f->curr_token, "Default parameters are only allowed for procedures");
|
||||
}
|
||||
}
|
||||
@@ -3486,7 +3485,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
|
||||
|
||||
|
||||
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
|
||||
return parse_field_list(f, field_count_, flags, Token_CloseBrace);
|
||||
return parse_field_list(f, field_count_, flags, Token_CloseBrace, false);
|
||||
}
|
||||
|
||||
AstNode *parse_type_or_ident(AstFile *f) {
|
||||
@@ -3821,7 +3820,14 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Expected condition for if statement");
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_else)) {
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -3831,6 +3837,13 @@ AstNode *parse_if_stmt(AstFile *f) {
|
||||
case Token_OpenBrace:
|
||||
else_stmt = parse_block_stmt(f, false);
|
||||
break;
|
||||
case Token_ArrowRight: {
|
||||
Token arrow = expect_token(f, Token_ArrowRight);
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected if statement block statement");
|
||||
else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
|
||||
@@ -3858,7 +3871,14 @@ AstNode *parse_when_stmt(AstFile *f) {
|
||||
syntax_error(f->curr_token, "Expected condition for when statement");
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, true);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, true);
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_else)) {
|
||||
switch (f->curr_token.kind) {
|
||||
@@ -3868,6 +3888,13 @@ AstNode *parse_when_stmt(AstFile *f) {
|
||||
case Token_OpenBrace:
|
||||
else_stmt = parse_block_stmt(f, true);
|
||||
break;
|
||||
case Token_ArrowRight: {
|
||||
Token arrow = expect_token(f, Token_ArrowRight);
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
syntax_error(f->curr_token, "Expected when statement block statement");
|
||||
else_stmt = ast_bad_stmt(f, f->curr_token, f->tokens[f->curr_token_index+1]);
|
||||
@@ -3890,11 +3917,22 @@ AstNode *parse_return_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
Token token = expect_token(f, Token_return);
|
||||
Array<AstNode *> results;
|
||||
if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
|
||||
results = parse_rhs_expr_list(f);
|
||||
} else {
|
||||
results = make_ast_node_array(f);
|
||||
Array<AstNode *> results = make_ast_node_array(f);
|
||||
|
||||
while (f->curr_token.kind != Token_Semicolon) {
|
||||
AstNode *arg = parse_expr(f, false);
|
||||
if (f->curr_token.kind == Token_Eq) {
|
||||
Token eq = expect_token(f, Token_Eq);
|
||||
AstNode *value = parse_value(f);
|
||||
arg = ast_field_value(f, arg, value, eq);
|
||||
}
|
||||
|
||||
array_add(&results, arg);
|
||||
if (f->curr_token.kind != Token_Comma ||
|
||||
f->curr_token.kind == Token_EOF) {
|
||||
break;
|
||||
}
|
||||
next_token(f);
|
||||
}
|
||||
|
||||
AstNode *end = NULL;
|
||||
@@ -3952,7 +3990,8 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_range && f->curr_token.kind == Token_Semicolon) {
|
||||
if (!is_range && (f->curr_token.kind == Token_Semicolon ||
|
||||
f->curr_token.kind == Token_ArrowRight)) {
|
||||
next_token(f);
|
||||
init = cond;
|
||||
cond = NULL;
|
||||
@@ -3960,7 +3999,8 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
cond = parse_simple_stmt(f, StmtAllowFlag_None);
|
||||
}
|
||||
expect_semicolon(f, cond);
|
||||
if (f->curr_token.kind != Token_OpenBrace) {
|
||||
if (f->curr_token.kind != Token_OpenBrace &&
|
||||
f->curr_token.kind != Token_ArrowRight) {
|
||||
post = parse_simple_stmt(f, StmtAllowFlag_None);
|
||||
}
|
||||
}
|
||||
@@ -3968,7 +4008,14 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
f->expr_level = prev_level;
|
||||
}
|
||||
|
||||
body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
if (is_range) {
|
||||
GB_ASSERT(cond->kind == AstNode_AssignStmt);
|
||||
@@ -4002,7 +4049,7 @@ AstNode *parse_for_stmt(AstFile *f) {
|
||||
|
||||
AstNode *parse_case_clause(AstFile *f, bool is_type) {
|
||||
Token token = f->curr_token;
|
||||
Array<AstNode *> list = make_ast_node_array(f);
|
||||
Array<AstNode *> list = {};
|
||||
expect_token(f, Token_case);
|
||||
bool prev_allow_range = f->allow_range;
|
||||
f->allow_range = !is_type;
|
||||
@@ -4224,23 +4271,41 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
|
||||
case Token_push_allocator: {
|
||||
next_token(f);
|
||||
AstNode *body = NULL;
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
f->expr_level = prev_level;
|
||||
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
return ast_push_allocator(f, token, expr, body);
|
||||
} break;
|
||||
|
||||
case Token_push_context: {
|
||||
next_token(f);
|
||||
AstNode *body = NULL;
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
AstNode *expr = parse_expr(f, false);
|
||||
f->expr_level = prev_level;
|
||||
|
||||
AstNode *body = parse_block_stmt(f, false);
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
body = parse_stmt(f);
|
||||
if (body->kind == AstNode_BlockStmt) {
|
||||
syntax_error(body, "Expected a normal statement rather than a block statement");
|
||||
}
|
||||
} else {
|
||||
body = parse_block_stmt(f, false);
|
||||
}
|
||||
|
||||
return ast_push_context(f, token, expr, body);
|
||||
} break;
|
||||
|
||||
|
||||
+8
-1
@@ -546,7 +546,14 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} else {
|
||||
} /* else if (t->curr_rune == 'h') { // Hexadecimal Float
|
||||
token.kind = Token_Float;
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
if (t->curr - prev <= 2) {
|
||||
token.kind = Token_Invalid;
|
||||
}
|
||||
} */ else {
|
||||
seen_decimal_point = false;
|
||||
scan_mantissa(t, 10);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user