static void scope_finalize(struct parse_context *c, struct type *ft)
{
- int size = 0;
+ int size = ft->function.local_size;
struct variable *next = ft->function.scope;
struct variable *done = NULL;
+
while (next) {
struct variable *v = next;
struct type *t = v->type;
continue;
if (!t)
continue;
+ if (v->frame_pos >= 0)
+ continue;
while (done && done->scope_end < v->scope_start)
done = done->in_scope;
if (done)
pos = done->frame_pos + done->type->size;
else
- pos = 0;
+ pos = ft->function.local_size;
if (pos & (t->align - 1))
pos = (pos + t->align) & ~(t->align-1);
v->frame_pos = pos;
{
struct lrval ret = _interp_exec(c, e, dest, dtype);
if (!ret.type)
- return; // NOTEST
+ return;
if (need_free)
free_value(dtype, dest);
if (ret.lval)
while (target != 0) {
int i = 0;
for (t = context.typelist; t ; t=t->next)
- if (t->print_type_decl && !t->check_args) {
+ if (t->print_type_decl && !t->check_args && t->name.txt[0] != ' ') {
i += 1;
if (i == target)
break;
do
code block
-In the first case a return type can follow the paentheses after a colon,
+In the first case a return type can follow the parentheses after a colon,
in the second it is given on a line starting with the word `return`.
##### Example: functions that return
do
code block
+Rather than returning a type, the function can specify a set of local
+variables to return as a struct. The values of these variables when the
+function exits will be provided to the caller. For this the return type
+is replaced with a block of result declarations, either in parentheses
+or bracketed by `return` and `do`.
+
+##### Example: functions returning multiple variables
+
+ func to_cartesian(rho:number; theta:number):(x:number; y:number)
+ x = .....
+ y = .....
+
+ func to_polar
+ x:number; y:number
+ return
+ rho:number
+ theta:number
+ do
+ rho = ....
+ theta = ....
-For constructing these lists we use a `List` binode, which will be
+For constructing the lists we use a `List` binode, which will be
further detailed when Expression Lists are introduced.
###### type union fields
struct binode *params;
struct type *return_type;
struct variable *scope;
+ int inline_result; // return value is at start of 'local'
int local_size;
} function;
fprintf(f, ")");
if (type->function.return_type != Tnone) {
fprintf(f, ":");
- type_print(type->function.return_type, f);
+ if (type->function.inline_result) {
+ int i;
+ struct type *t = type->function.return_type;
+ fprintf(f, " (");
+ for (i = 0; i < t->structure.nfields; i++) {
+ struct field *fl = t->structure.fields + i;
+ if (i)
+ fprintf(f, "; ");
+ fprintf(f, "%.*s:", fl->name.len, fl->name.txt);
+ type_print(fl->type, f);
+ }
+ fprintf(f, ")");
+ } else
+ type_print(type->function.return_type, f);
}
fprintf(f, "\n");
}
arg = cast(binode, arg->right);
}
c->local = local; c->local_size = t->function.local_size;
- rv = interp_exec(c, fbody->function, &rvtype);
+ if (t->function.inline_result && dtype) {
+ _interp_exec(c, fbody->function, NULL, NULL);
+ memcpy(dest, local, dtype->size);
+ rvtype = ret.type = NULL;
+ } else
+ rv = interp_exec(c, fbody->function, &rvtype);
c->local = oldlocal; c->local_size = old_size;
free(local);
break;
propagate_types(b->left, c, ok, t,
(b->op == Assign ? Rnoconstant : 0));
}
- if (t && t->dup == NULL)
+ if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK
type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
return Tnone;
###### ast functions
+ static struct type *handle_results(struct parse_context *c,
+ struct binode *results)
+ {
+ /* Create a 'struct' type from the results list, which
+ * is a list for 'struct var'
+ */
+ struct text result_type_name = { " function_result", 5 };
+ struct type *t = add_type(c, result_type_name, &structure_prototype);
+ int cnt = 0;
+ struct binode *b;
+
+ for (b = results; b; b = cast(binode, b->right))
+ cnt += 1;
+ t->structure.nfields = cnt;
+ t->structure.fields = calloc(cnt, sizeof(struct field));
+ cnt = 0;
+ for (b = results; b; b = cast(binode, b->right)) {
+ struct var *v = cast(var, b->left);
+ struct field *f = &t->structure.fields[cnt++];
+ int a = v->var->type->align;
+ f->name = v->var->name->name;
+ f->type = v->var->type;
+ f->init = NULL;
+ f->offset = t->size;
+ v->var->frame_pos = f->offset;
+ t->size += ((f->type->size - 1) | (a-1)) + 1;
+ if (a > t->align)
+ t->align = a;
+ variable_unlink_exec(v->var);
+ }
+ free_binode(results);
+ return t;
+ }
+
static struct variable *declare_function(struct parse_context *c,
struct variable *name,
struct binode *args,
struct type *ret,
+ struct binode *results,
struct exec *code)
{
struct text funcname = {" func", 5};
if (name) {
struct value fn = {.function = code};
- name->type = add_type(c, funcname, &function_prototype);
- name->type->function.params = reorder_bilist(args);
- name->type->function.return_type = ret;
- global_alloc(c, name->type, name, &fn);
+ struct type *t;
var_block_close(c, CloseFunction, code);
+ t = add_type(c, funcname, &function_prototype);
+ name->type = t;
+ t->function.params = reorder_bilist(args);
+ if (!ret) {
+ ret = handle_results(c, reorder_bilist(results));
+ t->function.inline_result = 1;
+ t->function.local_size = ret->size;
+ }
+ t->function.return_type = ret;
+ global_alloc(c, t, name, &fn);
name->type->function.scope = c->out_scope;
} else {
free_binode(args);
$*variable
DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, NULL, $<Bl);
}$
| func FuncName IN OpenScope Args OUT OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, NULL, $<Bl);
}$
| func FuncName NEWLINE OpenScope OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, NULL, Tnone, $<Bl);
+ $0 = declare_function(c, $<FN, NULL, Tnone, NULL, $<Bl);
}$
| func FuncName ( OpenScope ArgsLine ) : Type Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, NULL, $<Bl);
+ }$
+ | func FuncName ( OpenScope ArgsLine ) : ( ArgsLine ) Block Newlines ${
+ $0 = declare_function(c, $<FN, $<AL, NULL, $<AL2, $<Bl);
}$
| func FuncName IN OpenScope Args OUT OptNL return Type Newlines do Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, NULL, $<Bl);
}$
| func FuncName NEWLINE OpenScope return Type Newlines do Block Newlines ${
- $0 = declare_function(c, $<FN, NULL, $<Ty, $<Bl);
+ $0 = declare_function(c, $<FN, NULL, $<Ty, NULL, $<Bl);
+ }$
+ | func FuncName IN OpenScope Args OUT OptNL return IN Args OUT OptNL do Block Newlines ${
+ $0 = declare_function(c, $<FN, $<Ar, NULL, $<Ar2, $<Bl);
+ }$
+ | func FuncName NEWLINE OpenScope return IN Args OUT OptNL do Block Newlines ${
+ $0 = declare_function(c, $<FN, NULL, NULL, $<Ar, $<Bl);
}$
###### print func decls
int all_ok = 1;
for (v = c->in_scope; v; v = v->in_scope) {
struct value *val;
+ struct type *ret;
int ok = 1;
if (v->depth != 0 || !v->type || !v->type->check_args)
continue;
+ ret = v->type->function.inline_result ?
+ Tnone : v->type->function.return_type;
val = var_value(c, v);
do {
ok = 1;
- propagate_types(val->function, c, &ok,
- v->type->function.return_type, 0);
+ propagate_types(val->function, c, &ok, ret, 0);
} while (ok == 2);
if (ok)
/* Make sure everything is still consistent */
- propagate_types(val->function, c, &ok,
- v->type->function.return_type, 0);
+ propagate_types(val->function, c, &ok, ret, 0);
if (!ok)
all_ok = 0;
- if (!v->type->function.return_type->dup) {
+ if (!v->type->function.inline_result &&
+ !v->type->function.return_type->dup) {
type_err(c, "error: function cannot return value of type %1",
v->where_decl, v->type->function.return_type, 0, NULL);
}