#### Functions
A function is a chunk of code which can be passed parameters and can
-return results (though results are not yet implemented). Each function
-has a type which includes the set of parameters and the return value.
-As yet these types cannot be declared separately from the function
-itself.
+return results. Each function has a type which includes the set of
+parameters and the return value. As yet these types cannot be declared
+separately from the function itself.
The parameters can be specified either in parentheses as a ';' separated
list, such as
do
code block
+In the first case a return type can follow the paentheses after a colon,
+in the second it is given on a line starting with the word `return`.
+
+##### Example: functions that return
+
+ func add(a:number; b:number): number
+ code block
+
+ func catenate
+ a: string
+ b: string
+ return string
+ do
+ code block
+
+
For constructing these lists we use a `List` binode, which will be
further detailed when Expression Lists are introduced.
struct {
struct binode *params;
+ struct type *return_type;
int local_size;
} function;
if (b->right)
fprintf(f, "; ");
}
- fprintf(f, ")\n");
+ fprintf(f, ")");
+ if (type->function.return_type != Tnone) {
+ fprintf(f, ":");
+ type_print(type->function.return_type, f);
+ }
+ fprintf(f, "\n");
}
static void function_free_type(struct type *t)
case Funcall: {
/* Every arg must match formal parameter, and result
- * is return type of function (currently Tnone).
+ * is return type of function
*/
struct binode *args = cast(binode, b->right);
struct var *v = cast(var, b->left);
return NULL;
}
v->var->type->check_args(c, ok, v->var->type, args);
- return Tnone;
+ return v->var->type->function.return_type;
}
###### interp binode cases
arg = cast(binode, arg->right);
}
c->local = local; c->local_size = t->function.local_size;
- right = interp_exec(c, fbody->function, &rtype);
+ rv = interp_exec(c, fbody->function, &rvtype);
c->local = oldlocal; c->local_size = old_size;
free(local);
break;
### The `use` statement
-The `use` statement is the last "simple" statement. It is needed when
-the condition in a conditional statement is a block. `use` works much
-like `return` in C, but only completes the `condition`, not the whole
-function.
+The `use` statement is the last "simple" statement. It is needed when a
+statement block can return a value. This includes the body of a
+function which has a return type, and the "condition" code blocks in
+`if`, `while`, and `switch` statements.
###### Binode types
Use,
One of the functions must be named `main` and it must accept an array of
strings as a parameter - the command line arguments.
-As this is the top level, several things are handled a bit
-differently.
-The function is not interpreted by `interp_exec` as that isn't
-passed the argument list which the program requires. Similarly type
-analysis is a bit more interesting at this level.
+As this is the top level, several things are handled a bit differently.
+The function is not interpreted by `interp_exec` as that isn't passed
+the argument list which the program requires. Similarly type analysis
+is a bit more interesting at this level.
###### ast functions
static struct variable *declare_function(struct parse_context *c,
struct variable *name,
struct binode *args,
+ struct type *ret,
struct exec *code)
{
struct text funcname = {" func", 5};
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);
var_block_close(c, CloseSequential, code);
} else
return name;
}
+###### declare terminals
+ $TERM return
+
###### top level grammar
$*variable
DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
}$
| func FuncName IN OpenScope Args OUT OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, $<Ar, $<Bl);
+ $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
}$
| func FuncName NEWLINE OpenScope OptNL do Block Newlines ${
- $0 = declare_function(c, $<FN, NULL, $<Bl);
+ $0 = declare_function(c, $<FN, NULL, Tnone, $<Bl);
+ }$
+ | func FuncName ( OpenScope ArgsLine ) : Type Block Newlines ${
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ }$
+ | func FuncName IN OpenScope Args OUT OptNL return Type Newlines do Block Newlines ${
+ $0 = declare_function(c, $<FN, $<Ar, $<Ty, $<Bl);
+ }$
+ | func FuncName NEWLINE OpenScope return Type Newlines do Block Newlines ${
+ $0 = declare_function(c, $<FN, NULL, $<Ty, $<Bl);
}$
###### print func decls
val = var_value(c, v);
do {
ok = 1;
- propagate_types(val->function, c, &ok, Tnone, 0);
+ propagate_types(val->function, c, &ok,
+ v->type->function.return_type, 0);
} while (ok == 2);
if (ok)
/* Make sure everything is still consistent */
- propagate_types(val->function, c, &ok, Tnone, 0);
+ propagate_types(val->function, c, &ok,
+ v->type->function.return_type, 0);
if (!ok)
all_ok = 0;
v->type->function.local_size = scope_finalize(c);