]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: add simple return type
[ocean] / csrc / oceani.mdc
index f257736edc328baf8ba313d28f3bd7826e4e5004..43616ec5be39b65fe3534a5e4356a70dcb445d9b 100644 (file)
@@ -691,7 +691,7 @@ A separate function encoding these cases will simplify some code later.
                }
        }
 
-       static void _dup_value(struct type *type, 
+       static void _dup_value(struct type *type,
                               struct value *vold, struct value *vnew)
        {
                switch (type->vtype) {
@@ -1031,7 +1031,7 @@ list of in_scope names.
 
 The storage of the value of a variable will be described later.  For now
 we just need to know that when a variable goes out of scope, it might
-need to be freed.  For this we need to be able to find it, so assume that 
+need to be freed.  For this we need to be able to find it, so assume that
 `var_value()` will provide that.
 
 ###### variable fields
@@ -1575,7 +1575,7 @@ propagation is needed.
 
 ###### ast
 
-       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 2<<1};
+       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
 
 ###### format cases
        case 'r':
@@ -2061,7 +2061,7 @@ function will be needed.
                        struct value *v;
                        v = (void*) val->ptr + type->structure.fields[i].offset;
                        if (type->structure.fields[i].init)
-                               dup_value(type->structure.fields[i].type, 
+                               dup_value(type->structure.fields[i].type,
                                          type->structure.fields[i].init,
                                          v);
                        else
@@ -2335,27 +2335,45 @@ 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 list, such as
+The parameters can be specified either in parentheses as a ';' separated
+list, such as
 
 ##### Example: function 1
 
-       func main(av:[ac::number]string)
+       func main(av:[ac::number]string; env:[envc::number]string)
                code block
 
-or as an indented list of one parameter per line
+or as an indented list of one parameter per line (though each line can
+be a ';' separated list)
 
 ##### Example: function 2
 
        func main
                argv:[argc::number]string
+               env:[envc::number]string
        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.
 
@@ -2363,6 +2381,7 @@ further detailed when Expression Lists are introduced.
 
        struct {
                struct binode *params;
+               struct type *return_type;
                int local_size;
        } function;
 
@@ -2430,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)
@@ -2477,14 +2501,22 @@ further detailed when Expression Lists are introduced.
                        }
                } }$
 
-
        $*binode
-       Args -> ${ $0 = NULL; }$
+       Args -> ArgsLine NEWLINE ${ $0 = $<AL; }$
+               | Args ArgsLine NEWLINE ${ {
+                       struct binode *b = $<AL;
+                       struct binode **bp = &b;
+                       while (*bp)
+                               bp = (struct binode **)&(*bp)->left;
+                       *bp = $<A;
+                       $0 = b;
+               } }$
+
+       ArgsLine -> ${ $0 = NULL; }$
                | Varlist ${ $0 = $<1; }$
                | Varlist ; ${ $0 = $<1; }$
-               | Varlist NEWLINE ${ $0 = $<1; }$
 
-       Varlist -> Varlist ; ArgDecl ${ // UNTESTED
+       Varlist -> Varlist ; ArgDecl ${
                        $0 = new(binode);
                        $0->op = List;
                        $0->left = $<Vl;
@@ -3518,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);
@@ -3529,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
@@ -3557,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;
@@ -3734,9 +3766,14 @@ is in-place.
 
                for (e = b; e; e = cast(binode, e->right)) {
                        t = propagate_types(e->left, c, ok, NULL, rules);
-                       if ((rules & Rboolok) && t == Tbool)
+                       if ((rules & Rboolok) && (t == Tbool || t == Tnone))
                                t = NULL;
-                       if (t && t != Tnone && t != Tbool) {
+                       if (t == Tnone && e->right)
+                               /* Only the final statement *must* return a value
+                                * when not Rboolok
+                                */
+                               t = NULL;
+                       if (t) {
                                if (!type)
                                        type = t;
                                else if (t != type)
@@ -3987,16 +4024,16 @@ 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,
 
 ###### expr precedence
-       $TERM use       
+       $TERM use
 
 ###### SimpleStatement Grammar
        | use Expression ${
@@ -4696,53 +4733,56 @@ 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.
+
+###### 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};
+               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);
+                       var_block_close(c, CloseSequential, code);
+               } else
+                       var_block_close(c, CloseSequential, NULL);
+               return name;
+       }
 
-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.
+###### declare terminals
+       $TERM return
 
 ###### top level grammar
 
        $*variable
-       DeclareFunction -> func FuncName ( OpenScope Args ) Block Newlines ${ {
-                       struct text funcname = { " func", 5};
-                       $0 = $<FN;
-                       if ($0) {
-                               struct value fn = {.function = $<Bl};
-                               $0->type = add_type(c, funcname, &function_prototype);
-                               $0->type->function.params = reorder_bilist($<Ar);
-                               global_alloc(c, $0->type, $0, &fn);
-                               var_block_close(c, CloseSequential, fn.function);
-                       } else
-                               var_block_close(c, CloseSequential, NULL);
-               } }$
-               | func FuncName then IN OpenScope OptNL Args OUT OptNL do Block Newlines ${ {
-                       // FIXME that 'then' should not be there.
-                       struct text funcname = { " func", 5};
-                       $0 = $<FN;
-                       if ($0) {
-                               struct value fn = {.function = $<Bl};
-                               $0->type = add_type(c, funcname, &function_prototype);
-                               $0->type->function.params = reorder_bilist($<Ar);
-                               global_alloc(c, $0->type, $0, &fn);
-                               var_block_close(c, CloseSequential, fn.function);
-                       } else
-                               var_block_close(c, CloseSequential, NULL);
-               } }$
-               | func FuncName NEWLINE OpenScope OptNL do Block Newlines ${ {
-                       struct text funcname = { " func", 5};
-                       $0 = $<FN;
-                       if ($0) {
-                               struct value fn = {.function = $<Bl};
-                               $0->type = add_type(c, funcname, &function_prototype);
-                               $0->type->function.params = NULL;
-                               global_alloc(c, $0->type, $0, &fn);
-                               var_block_close(c, CloseSequential, fn.function);
-                       } else
-                               var_block_close(c, CloseSequential, NULL);
-               } }$
+       DeclareFunction -> func FuncName ( OpenScope ArgsLine ) Block Newlines ${
+                       $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+               }$
+               | func FuncName IN OpenScope Args OUT OptNL do Block Newlines ${
+                       $0 = declare_function(c, $<FN, $<Ar, Tnone, $<Bl);
+               }$
+               | func FuncName NEWLINE OpenScope OptNL do Block Newlines ${
+                       $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
        {
@@ -4779,22 +4819,27 @@ analysis is a bit more interesting at this level.
        static int analyse_funcs(struct parse_context *c)
        {
                struct variable *v;
-               int ok = 1;
-               for (v = c->in_scope; ok && v; v = v->in_scope) {
+               int all_ok = 1;
+               for (v = c->in_scope; v; v = v->in_scope) {
                        struct value *val;
+                       int ok = 1;
                        if (v->depth != 0 || !v->type || !v->type->check_args)
                                continue;
                        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);
                }
-               return ok;
+               return all_ok;
        }
 
        static int analyse_main(struct type *type, struct parse_context *c)
@@ -4871,7 +4916,6 @@ analysis is a bit more interesting at this level.
                                array_init(v->var->type, vl);
                                for (i = 0; i < argc; i++) {
                                        struct value *vl2 = vl->array + i * v->var->type->array.member->size;
-                                       
 
                                        arg.str.txt = argv[i];
                                        arg.str.len = strlen(argv[i]);