From b24e0b84da4cdd01999f87f132119083b2761b50 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 13 Nov 2021 10:10:44 +1100 Subject: [PATCH] oceani: add simple return type This allow a simple typed value to be returned from a function using the 'use' statement. It probably doesn't work for structs - don't try it. Signed-off-by: NeilBrown --- csrc/oceani-tests.mdc | 38 +++++++++++++++++++- csrc/oceani.mdc | 80 +++++++++++++++++++++++++++++++------------ 2 files changed, 95 insertions(+), 23 deletions(-) diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index 8f10b89..396b13e 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -616,7 +616,7 @@ Time to test if structure declarations and accesses work correctly. Test functions. They don't return anything, so we need to get them to print ###### test list - oceani_tests += functions + oceani_tests += functions func_ret_type ###### test: functions @@ -655,6 +655,34 @@ Test functions. They don't return anything, so we need to get them to print 3 2 . 1 .. done 4 3 . 2 .. 1 ... done +###### test: func_ret_type + + func double(n:number):number + use n+n + + func answer + prefix:string + suffix:string + return string + do + use prefix ++ suffix + + func noarg_returns + return Boolean + do + use 22/7 == 3.14159 + + func main() + for j:=10; then j = j - 3; while j > -5: + print answer("dou","ble"), j, "is", double(j) + +###### output: func_ret_type + double 10 is 20 + double 7 is 14 + double 4 is 8 + double 1 is 2 + double -2 is -4 + ## Test code with syntax errors Syntax errors aren't handled well yet - the result is almost always a @@ -959,7 +987,15 @@ Test for type errors with functions if test1 == test2: pass + func test4(a:number):string + use a * a + + func test5(a:number):string + print a + ###### output: func_err_args + .tmp.code:28:14: error: expected string, found none + .tmp.code:25:8: error: expected string, found number .tmp.code:15:14: error: insufficient arguments to function. .tmp.code:16:14: error: expected number found string .tmp.code:16:22: error: expected string found number diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index beb4fc9..43616ec 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -2335,10 +2335,9 @@ function will be needed. #### 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 @@ -2359,6 +2358,22 @@ be a ';' separated list) 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. @@ -2366,6 +2381,7 @@ further detailed when Expression Lists are introduced. struct { struct binode *params; + struct type *return_type; int local_size; } function; @@ -2433,7 +2449,12 @@ further detailed when Expression Lists are introduced. 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) @@ -3529,7 +3550,7 @@ arguments, form with the 'List' nodes. 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); @@ -3540,7 +3561,7 @@ arguments, form with the 'List' nodes. 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 @@ -3568,7 +3589,7 @@ arguments, form with the 'List' nodes. 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; @@ -4003,10 +4024,10 @@ it is declared, and error will be raised as the name is created as ### 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, @@ -4712,17 +4733,17 @@ The code in an Ocean program is all stored in function declarations. 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}; @@ -4730,6 +4751,7 @@ analysis is a bit more interesting at this level. 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 @@ -4737,17 +4759,29 @@ analysis is a bit more interesting at this level. return name; } +###### declare terminals + $TERM return + ###### top level grammar $*variable DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${ - $0 = declare_function(c, $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); -- 2.43.0