aboutsummaryrefslogtreecommitdiff
path: root/src/check_stmt.cpp
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-06-22 01:14:45 +0100
committerGinger Bill <bill@gingerbill.org>2017-06-22 01:14:45 +0100
commit8197c02dcf964be404cd199858e84e9e8f3905e5 (patch)
tree177393f565eddb1178423d776cb275d56cfcffee /src/check_stmt.cpp
parent9faf0020cc04c9c27fc7a7e7e41edce6df31376e (diff)
Default result values for procedure types; Named result values in `return` statements
Diffstat (limited to 'src/check_stmt.cpp')
-rw-r--r--src/check_stmt.cpp148
1 files changed, 126 insertions, 22 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index c4ad2570e..fcd601446 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -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;
+ }
+
+ GB_ASSERT(e->kind == Entity_Variable);
+ if (e->Variable.default_value.kind != ExactValue_Invalid ||
+ e->Variable.default_is_nil) {
+ result_count_excluding_defaults--;
+ continue;
+ }
+ 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);
}
- if (rs->results.count == 0) {
- error(node, "Expected %td return values, got 0", result_count);
+ } 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 {
- // 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)));
- // }
- }
- } else if (rs->results.count > 0) {
- error(rs->results[0], "No return values expected");
+ 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);