]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: change SimpleStatement to be $*exec, not $*binode
[ocean] / csrc / oceani.mdc
index c2a19ce0c7744190c2fedba910f7205c851e83db..a4110da2a970c1b60a6ad2e0f3be4f6243a2c1e0 100644 (file)
@@ -446,7 +446,7 @@ Named type are stored in a simple linked list.  Objects of each type are
                int size, align;
                void (*init)(struct type *type, struct value *val);
                void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
-               void (*print)(struct type *type, struct value *val);
+               void (*print)(struct type *type, struct value *val, FILE *f);
                void (*print_type)(struct type *type, FILE *f);
                int (*cmp_order)(struct type *t1, struct type *t2,
                                 struct value *v1, struct value *v2);
@@ -543,12 +543,12 @@ Named type are stored in a simple linked list.  Objects of each type are
                return -1;                              // NOTEST
        }
 
-       static void print_value(struct type *type, struct value *v)
+       static void print_value(struct type *type, struct value *v, FILE *f)
        {
                if (type && type->print)
-                       type->print(type, v);
+                       type->print(type, v, f);
                else
-                       printf("*Unknown*");            // NOTEST
+                       fprintf(f, "*Unknown*");                // NOTEST
        }
 
 ###### forward decls
@@ -561,7 +561,7 @@ Named type are stored in a simple linked list.  Objects of each type are
                              struct value *vold, struct value *vnew);
        static int value_cmp(struct type *tl, struct type *tr,
                             struct value *left, struct value *right);
-       static void print_value(struct type *type, struct value *v);
+       static void print_value(struct type *type, struct value *v, FILE *f);
 
 ###### free context types
 
@@ -732,23 +732,23 @@ A separate function encoding these cases will simplify some code later.
                return cmp;
        }
 
-       static void _print_value(struct type *type, struct value *v)
+       static void _print_value(struct type *type, struct value *v, FILE *f)
        {
                switch (type->vtype) {
                case Vnone:                             // NOTEST
-                       printf("*no-value*"); break;    // NOTEST
+                       fprintf(f, "*no-value*"); break;        // NOTEST
                case Vlabel:                            // NOTEST
-                       printf("*label-%p*", v->label); break; // NOTEST
+                       fprintf(f, "*label-%p*", v->label); break; // NOTEST
                case Vstr:
-                       printf("%.*s", v->str.len, v->str.txt); break;
+                       fprintf(f, "%.*s", v->str.len, v->str.txt); break;
                case Vbool:
-                       printf("%s", v->bool ? "True":"False"); break;
+                       fprintf(f, "%s", v->bool ? "True":"False"); break;
                case Vnum:
                        {
                        mpf_t fl;
                        mpf_init2(fl, 20);
                        mpf_set_q(fl, v->num);
-                       gmp_printf("%Fg", fl);
+                       gmp_fprintf(f, "%Fg", fl);
                        mpf_clear(fl);
                        break;
                        }
@@ -1426,9 +1426,10 @@ stack.
 
        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;
@@ -1438,12 +1439,14 @@ stack.
                                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;
@@ -1742,7 +1745,7 @@ in `rval`.
        {
                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)
@@ -2346,7 +2349,7 @@ function will be needed.
                | ERROR ${ tok_err(c, "Syntax error in struct field", &$1); }$
 
        Field -> IDENTIFIER : Type = Expression ${ {
-                       int ok; // UNTESTED
+                       int ok;
 
                        $0 = calloc(1, sizeof(struct fieldlist));
                        $0->f.name = $1.txt;
@@ -2375,9 +2378,9 @@ function will be needed.
        static void structure_print_type(struct type *t, FILE *f);
 
 ###### value functions
-       static void structure_print_type(struct type *t, FILE *f)       // UNTESTED
-       {       // UNTESTED
-               int i;  // UNTESTED
+       static void structure_print_type(struct type *t, FILE *f)
+       {
+               int i;
 
                fprintf(f, "struct %.*s\n", t->name.len, t->name.txt);
 
@@ -2389,23 +2392,23 @@ function will be needed.
                                fprintf(f, " = ");
                                if (fl->type == Tstr)
                                        fprintf(f, "\"");       // UNTESTED
-                               print_value(fl->type, fl->init);
+                               print_value(fl->type, fl->init, f);
                                if (fl->type == Tstr)
                                        fprintf(f, "\"");       // UNTESTED
                        }
-                       printf("\n");
+                       fprintf(f, "\n");
                }
        }
 
 ###### print type decls
-       {       // UNTESTED
-               struct type *t; // UNTESTED
+       {
+               struct type *t;
                int target = -1;
 
                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;
@@ -2446,7 +2449,7 @@ be a ';' separated list)
        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
@@ -2461,8 +2464,28 @@ in the second it is given on a line starting with the word `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`.
 
-For constructing these lists we use a `List` binode, which will be
+##### 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 the lists we use a `List` binode, which will be
 further detailed when Expression Lists are introduced.
 
 ###### type union fields
@@ -2471,6 +2494,7 @@ further detailed when Expression Lists are introduced.
                struct binode *params;
                struct type *return_type;
                struct variable *scope;
+               int inline_result;      // return value is at start of 'local'
                int local_size;
        } function;
 
@@ -2521,7 +2545,7 @@ further detailed when Expression Lists are introduced.
                                 args, NULL, 0, NULL);
        }
 
-       static void function_print(struct type *type, struct value *val)
+       static void function_print(struct type *type, struct value *val, FILE *f)
        {
                print_exec(val->function, 1, 0);
        }
@@ -2541,7 +2565,20 @@ further detailed when Expression Lists are introduced.
                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");
        }
@@ -2708,7 +2745,7 @@ an executable.
                struct val *v = cast(val, e);
                if (v->vtype == Tstr)
                        printf("\"");
-               print_value(v->vtype, &v->val);
+               print_value(v->vtype, &v->val, stdout);
                if (v->vtype == Tstr)
                        printf("\"");
                break;
@@ -2771,6 +2808,10 @@ because it really is the same variable no matter where it appears.
 When a variable is used, we need to remember to follow the `->merged`
 link to find the primary instance.
 
+When a variable is declared, it may or may not be given an explicit
+type.  We need to record which so that we can report the parsed code
+correctly.
+
 ###### exec type
        Xvar,
 
@@ -2780,6 +2821,9 @@ link to find the primary instance.
                struct variable *var;
        };
 
+###### variable fields
+       int explicit_type;
+
 ###### Grammar
 
        $TERM : ::
@@ -2824,6 +2868,7 @@ link to find the primary instance.
                        v->where_decl = $0;
                        v->where_set = $0;
                        v->type = $<Type;
+                       v->explicit_type = 1;
                } else {
                        v = var_ref(c, $1.txt);
                        $0->var = v;
@@ -2842,6 +2887,7 @@ link to find the primary instance.
                        v->where_set = $0;
                        v->type = $<Type;
                        v->constant = 1;
+                       v->explicit_type = 1;
                } else {
                        v = var_ref(c, $1.txt);
                        $0->var = v;
@@ -2973,10 +3019,11 @@ there.
 ###### Binode types
        CondExpr,
 
-###### Grammar
+###### declare terminals
 
        $LEFT if $$ifelse
-       ## expr precedence
+
+###### Grammar
 
        $*exec
        Expression -> Expression if Expression else Expression $$ifelse ${ {
@@ -3095,7 +3142,7 @@ evaluate the second expression if not necessary.
        OrElse,
        Not,
 
-###### expr precedence
+###### declare terminals
        $LEFT or
        $LEFT and
        $LEFT not
@@ -3243,7 +3290,7 @@ expression operator, and the `CMPop` non-terminal will match one of them.
        Eql,
        NEql,
 
-###### expr precedence
+###### declare terminals
        $LEFT < > <= >= == != CMPop
 
 ###### expression grammar
@@ -3360,7 +3407,7 @@ should only insert brackets were needed for precedence.
        StringConv,
        Bracket,
 
-###### expr precedence
+###### declare terminals
        $LEFT + - Eop
        $LEFT * / % ++ Top
        $LEFT Uop $
@@ -3678,7 +3725,12 @@ arguments, form with the 'List' nodes.
                        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;
@@ -3737,6 +3789,12 @@ which does nothing and is represented as a `NULL` pointer in a `Block`
 list.  Other stand-alone statements will follow once the infrastructure
 is in-place.
 
+As many statements will use binodes, we declare a binode pointer 'b' in
+the common header for all reductions to use.
+
+###### Parser: reduce
+       struct binode *b;
+
 ###### Binode types
        Block,
 
@@ -3814,6 +3872,7 @@ is in-place.
                        }$
 
        $TERM pass
+       $*exec
        SimpleStatement -> pass ${ $0 = NULL; }$
                | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
                ## SimpleStatement Grammar
@@ -3897,28 +3956,28 @@ printed.
 ###### Binode types
        Print,
 
-##### expr precedence
+##### declare terminals
        $TERM print
 
 ###### SimpleStatement Grammar
 
        | print ExpressionList ${
-               $0 = new(binode);
-               $0->op = Print;
-               $0->right = NULL;
-               $0->left = reorder_bilist($<EL);
+               $0 = b = new(binode);
+               b->op = Print;
+               b->right = NULL;
+               b->left = reorder_bilist($<EL);
        }$
        | print ExpressionList , ${ {
-               $0 = new(binode);
-               $0->op = Print;
-               $0->right = reorder_bilist($<EL);
-               $0->left = NULL;
+               $0 = b = new(binode);
+               b->op = Print;
+               b->right = reorder_bilist($<EL);
+               b->left = NULL;
        } }$
        | print ${
-               $0 = new(binode);
-               $0->op = Print;
-               $0->left = NULL;
-               $0->right = NULL;
+               $0 = b = new(binode);
+               b->op = Print;
+               b->left = NULL;
+               b->right = NULL;
        }$
 
 ###### print binode cases
@@ -3957,7 +4016,7 @@ printed.
                        b2 = cast(binode, b->right);
                for (; b2; b2 = cast(binode, b2->right)) {
                        left = interp_exec(c, b2->left, &ltype);
-                       print_value(ltype, &left);
+                       print_value(ltype, &left, stdout);
                        free_value(ltype, &left);
                        if (b2->right)
                                putchar(' ');
@@ -3987,16 +4046,16 @@ it is declared, and error will be raised as the name is created as
 
 ###### SimpleStatement Grammar
        | Variable = Expression ${
-                       $0 = new(binode);
-                       $0->op = Assign;
-                       $0->left = $<1;
-                       $0->right = $<3;
+                       $0 = b= new(binode);
+                       b->op = Assign;
+                       b->left = $<1;
+                       b->right = $<3;
                }$
        | VariableDecl = Expression ${
-                       $0 = new(binode);
-                       $0->op = Declare;
-                       $0->left = $<1;
-                       $0->right =$<3;
+                       $0 = b= new(binode);
+                       b->op = Declare;
+                       b->left = $<1;
+                       b->right =$<3;
                }$
 
        | VariableDecl ${
@@ -4006,10 +4065,10 @@ it is declared, and error will be raised as the name is created as
                                         $1, NULL, 0, NULL);
                                free_var($1);
                        } else {
-                               $0 = new(binode);
-                               $0->op = Declare;
-                               $0->left = $<1;
-                               $0->right = NULL;
+                               $0 = b = new(binode);
+                               b->op = Declare;
+                               b->left = $<1;
+                               b->right = NULL;
                        }
                }$
 
@@ -4031,13 +4090,13 @@ it is declared, and error will be raised as the name is created as
                print_exec(b->left, indent, bracket);
                if (cast(var, b->left)->var->constant) {
                        printf("::");
-                       if (v->where_decl == v->where_set) {
+                       if (v->explicit_type) {
                                type_print(v->type, stdout);
                                printf(" ");
                        }
                } else {
                        printf(":");
-                       if (v->where_decl == v->where_set) {
+                       if (v->explicit_type) {
                                type_print(v->type, stdout);
                                printf(" ");
                        }
@@ -4076,7 +4135,7 @@ it is declared, and error will be raised as the name is created as
                                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;
 
@@ -4116,16 +4175,16 @@ function which has a return type, and the "condition" code blocks in
 ###### Binode types
        Use,
 
-###### expr precedence
+###### declare terminals
        $TERM use
 
 ###### SimpleStatement Grammar
        | use Expression ${
-               $0 = new_pos(binode, $1);
-               $0->op = Use;
-               $0->right = $<2;
-               if ($0->right->type == Xvar) {
-                       struct var *v = cast(var, $0->right);
+               $0 = b = new_pos(binode, $1);
+               b->op = Use;
+               b->right = $<2;
+               if (b->right->type == Xvar) {
+                       struct var *v = cast(var, b->right);
                        if (v->var->type == Tnone) {
                                /* Convert this to a label */
                                struct value *val;
@@ -4279,7 +4338,7 @@ casepart` to track a list of case parts.
 ###### ComplexStatement Grammar
        | CondStatement ${ $0 = $<1; }$
 
-###### expr precedence
+###### declare terminals
        $TERM for then while do
        $TERM else
        $TERM switch case
@@ -4803,7 +4862,7 @@ searching through for the Nth constant for decreasing N.
                                printf(" = ");
                                if (v->type == Tstr)
                                        printf("\"");
-                               print_value(v->type, val);
+                               print_value(v->type, val, stdout);
                                if (v->type == Tstr)
                                        printf("\"");
                                printf("\n");
@@ -4825,20 +4884,62 @@ is a bit more interesting at this level.
 
 ###### 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);
@@ -4857,22 +4958,31 @@ is a bit more interesting at this level.
 
        $*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
@@ -4898,7 +5008,7 @@ is a bit more interesting at this level.
                                if (brackets)
                                        print_exec(val->function, 0, brackets);
                                else
-                                       print_value(v->type, val);
+                                       print_value(v->type, val, stdout);
                                printf("/* frame size %d */\n", v->type->function.local_size);
                                target -= 1;
                        }
@@ -4913,22 +5023,24 @@ is a bit more interesting at this level.
                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);
                        }