]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: don't let error in one statement hides errors in next.
[ocean] / csrc / oceani.mdc
index a62534814a880fd01aa9c78cdfce316edbb81a37..f97652d025ca4c90ef8e183ac45bea0eed41a677 100644 (file)
@@ -37,9 +37,9 @@ boolean operators.
 
 Some operators that have only recently been added, and so have not
 generated all that much experience yet are "and then" and "or else" as
 
 Some operators that have only recently been added, and so have not
 generated all that much experience yet are "and then" and "or else" as
-short-circuit Boolean operators, and the "if ... else" trinary
-operator which can select between two expressions based on a third
-(which appears syntactically in the middle).
+short-circuit Boolean operators (which have since been remove), and the
+"if ...  else" trinary operator which can select between two expressions
+based on a third (which appears syntactically in the middle).
 
 The "func" clause currently only allows a "main" function to be
 declared.  That will be extended when proper function support is added.
 
 The "func" clause currently only allows a "main" function to be
 declared.  That will be extended when proper function support is added.
@@ -598,7 +598,7 @@ the value can only be assigned once, when the variable is declared.
 
 ###### ast
 
 
 ###### ast
 
-       enum val_rules {Rboolok = 1<<0,};
+       enum val_rules {Rboolok = 1<<0, Rrefok = 1<<1,};
        enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
                       Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
 
        enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
                       Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
 
@@ -1157,7 +1157,7 @@ A separate function encoding these cases will simplify some code later.
        {
                int cmp;
                if (tl != tr)
        {
                int cmp;
                if (tl != tr)
-                       return tl - tr; // NOTEST
+                       return tl - tr;
                switch (tl->vtype) {
                case Vlabel: cmp = left->label == right->label ? 0 : 1; break;
                case Vnum: cmp = mpq_cmp(left->num, right->num); break;
                switch (tl->vtype) {
                case Vlabel: cmp = left->label == right->label ? 0 : 1; break;
                case Vnum: cmp = mpq_cmp(left->num, right->num); break;
@@ -1274,13 +1274,13 @@ executable.
                $0->val.bool = 0;
        }$
        | NUMBER ${ {
                $0->val.bool = 0;
        }$
        | NUMBER ${ {
-               char tail[3];
+               char tail[3] = "";
                $0 = new_val(Tnum, $1);
                $0 = new_val(Tnum, $1);
-               if (number_parse($0->val.num, tail, $1.txt) == 0)
-                       mpq_init($0->val.num);  // UNTESTED
-                       if (tail[0])
-                               tok_err(c, "error: unsupported number suffix",
-                                       &$1);
+               if (number_parse($0->val.num, tail, $1.txt) == 0) {
+                       mpq_init($0->val.num);
+                       tok_err(c, "error: unsupported number format", &$NUM);
+               } else if (tail[0])
+                       tok_err(c, "error: unsupported number suffix", &$1);
        } }$
        | STRING ${ {
                char tail[3];
        } }$
        | STRING ${ {
                char tail[3];
@@ -2023,7 +2023,7 @@ tell if it was set or not later.
        {
                if (!v->global) {
                        if (!c->local || !v->type)
        {
                if (!v->global) {
                        if (!c->local || !v->type)
-                               return NULL;    // UNTESTED
+                               return NULL;    // NOTEST
                        if (v->frame_pos + v->type->size > c->local_size) {
                                printf("INVALID frame_pos\n");  // NOTEST
                                exit(2);                        // NOTEST
                        if (v->frame_pos + v->type->size > c->local_size) {
                                printf("INVALID frame_pos\n");  // NOTEST
                                exit(2);                        // NOTEST
@@ -2049,7 +2049,7 @@ tell if it was set or not later.
                        t->prepare_type(c, t, 1);       // NOTEST
 
                if (c->global_size & (t->align - 1))
                        t->prepare_type(c, t, 1);       // NOTEST
 
                if (c->global_size & (t->align - 1))
-                       c->global_size = (c->global_size + t->align) & ~(t->align-1);   // NOTEST
+                       c->global_size = (c->global_size + t->align) & ~(t->align-1);
                if (!v) {
                        v = &scratch;
                        v->type = t;
                if (!v) {
                        v = &scratch;
                        v->type = t;
@@ -2096,7 +2096,7 @@ stack.
                        if (v->merged != v)
                                continue;
                        if (!t)
                        if (v->merged != v)
                                continue;
                        if (!t)
-                               continue;
+                               continue;       // NOTEST
                        if (v->frame_pos >= 0)
                                continue;
                        while (done && done->scope_end < v->scope_start)
                        if (v->frame_pos >= 0)
                                continue;
                        while (done && done->scope_end < v->scope_start)
@@ -2293,9 +2293,7 @@ correctly.
                        *perr |= Eruntime;
                if (v->constant)
                        *perr |= Econst;
                        *perr |= Eruntime;
                if (v->constant)
                        *perr |= Econst;
-               if (!type)
-                       return v->type;
-               return type;
+               return v->type;
        }
 
 ###### interp exec cases
        }
 
 ###### interp exec cases
@@ -2400,16 +2398,16 @@ with a const size by whether they are prepared at parse time or not.
                struct value *vsize;
                mpz_t q;
                if (type->array.static_size)
                struct value *vsize;
                mpz_t q;
                if (type->array.static_size)
-                       return 1;       // UNTESTED
+                       return 1;       // NOTEST - guard against reentry
                if (type->array.unspec && parse_time)
                if (type->array.unspec && parse_time)
-                       return 1;       // UNTESTED
+                       return 1;       // NOTEST - unspec is still incomplete
                if (parse_time && type->array.vsize && !type->array.vsize->global)
                if (parse_time && type->array.vsize && !type->array.vsize->global)
-                       return 1;       // UNTESTED
+                       return 1;       // NOTEST - should be impossible
 
                if (type->array.vsize) {
                        vsize = var_value(c, type->array.vsize);
                        if (!vsize)
 
                if (type->array.vsize) {
                        vsize = var_value(c, type->array.vsize);
                        if (!vsize)
-                               return 1;       // UNTESTED
+                               return 1;       // NOTEST - should be impossible
                        mpz_init(q);
                        mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
                        type->array.size = mpz_get_si(q);
                        mpz_init(q);
                        mpz_tdiv_q(q, mpq_numref(vsize->num), mpq_denref(vsize->num));
                        type->array.size = mpz_get_si(q);
@@ -2418,7 +2416,7 @@ with a const size by whether they are prepared at parse time or not.
                if (!parse_time)
                        return 1;
                if (type->array.member->size <= 0)
                if (!parse_time)
                        return 1;
                if (type->array.member->size <= 0)
-                       return 0;       // UNTESTED
+                       return 0;       // NOTEST - error caught before here
 
                type->array.static_size = 1;
                type->size = type->array.size * type->array.member->size;
 
                type->array.static_size = 1;
                type->size = type->array.size * type->array.member->size;
@@ -2470,19 +2468,15 @@ with a const size by whether they are prepared at parse time or not.
                /* Both are arrays, so we can look at details */
                if (!type_compat(require->array.member, have->array.member, 0))
                        return 0;
                /* Both are arrays, so we can look at details */
                if (!type_compat(require->array.member, have->array.member, 0))
                        return 0;
-               if (have->array.unspec && require->array.unspec) {
-                       if (have->array.vsize && require->array.vsize &&
-                           have->array.vsize != require->array.vsize)  // UNTESTED
-                               /* sizes might not be the same */
-                               return 0;       // UNTESTED
-                       return 1;
-               }
+               if (have->array.unspec && require->array.unspec &&
+                   have->array.size != require->array.size)
+                       return 0;       // NOTEST
                if (have->array.unspec || require->array.unspec)
                if (have->array.unspec || require->array.unspec)
-                       return 1;       // UNTESTED
+                       return 1;
                if (require->array.vsize == NULL && have->array.vsize == NULL)
                        return require->array.size == have->array.size;
 
                if (require->array.vsize == NULL && have->array.vsize == NULL)
                        return require->array.size == have->array.size;
 
-               return require->array.vsize == have->array.vsize;       // UNTESTED
+               return require->array.vsize == have->array.vsize;
        }
 
        static void array_print_type(struct type *type, FILE *f)
        }
 
        static void array_print_type(struct type *type, FILE *f)
@@ -2556,29 +2550,18 @@ with a const size by whether they are prepared at parse time or not.
                $0->array.vsize = v;
        } }$
 
                $0->array.vsize = v;
        } }$
 
-###### Grammar
-       $*type
-       OptType -> Type ${ $0 = $<1; }$
-               | ${ $0 = NULL; }$
-
 ###### formal type grammar
 
 ###### formal type grammar
 
-       | [ IDENTIFIER :: OptType ] Type ${ {
-               struct variable *v = var_decl(c, $ID.txt);
-
-               v->type = $<OT;
-               v->constant = 1;
-               if (!v->type)
-                       v->type = Tnum;
-               $0 = add_anon_type(c, &array_prototype, "array[var]");
-               $0->array.member = $<6;
+       | [ ] Type ${ {
+               $0 = add_anon_type(c, &array_prototype, "array[]");
+               $0->array.member = $<Type;
                $0->array.size = 0;
                $0->array.unspec = 1;
                $0->array.size = 0;
                $0->array.unspec = 1;
-               $0->array.vsize = v;
+               $0->array.vsize = NULL;
        } }$
 
 ###### Binode types
        } }$
 
 ###### Binode types
-       Index,
+       Index, Length,
 
 ###### term grammar
 
 
 ###### term grammar
 
@@ -2590,6 +2573,13 @@ with a const size by whether they are prepared at parse time or not.
                $0 = b;
        } }$
 
                $0 = b;
        } }$
 
+       | Term [ ] ${ {
+               struct binode *b = new(binode);
+               b->op = Length;
+               b->left = $<Term;
+               $0 = b;
+       } }$
+
 ###### print binode cases
        case Index:
                print_exec(b->left, -1, bracket);
 ###### print binode cases
        case Index:
                print_exec(b->left, -1, bracket);
@@ -2598,6 +2588,11 @@ with a const size by whether they are prepared at parse time or not.
                printf("]");
                break;
 
                printf("]");
                break;
 
+       case Length:
+               print_exec(b->left, -1, bracket);
+               printf("[]");
+               break;
+
 ###### propagate binode cases
        case Index:
                /* left must be an array, right must be a number,
 ###### propagate binode cases
        case Index:
                /* left must be an array, right must be a number,
@@ -2617,6 +2612,20 @@ with a const size by whether they are prepared at parse time or not.
                }
                break;
 
                }
                break;
 
+       case Length:
+               /* left must be an array, result is a number
+                */
+               t = propagate_types(b->left, c, perr, NULL, 0);
+               if (!t || t->compat != array_compat) {
+                       type_err(c, "error: %1 cannot provide length", prog, t, 0, NULL);
+                       return NULL;
+               }
+               if (!type_compat(type, Tnum, rules))
+                       type_err(c, "error: have %1 but need %2", prog,
+                                        Tnum, rules, type);
+               return Tnum;
+               break;
+
 ###### interp binode cases
        case Index: {
                mpz_t q;
 ###### interp binode cases
        case Index: {
                mpz_t q;
@@ -2642,6 +2651,13 @@ with a const size by whether they are prepared at parse time or not.
                ltype = NULL;
                break;
        }
                ltype = NULL;
                break;
        }
+       case Length: {
+               lleft = linterp_exec(c, b->left, &ltype);
+               mpq_set_ui(rv.num, ltype->array.size, 1);
+               ltype = NULL;
+               rvtype = Tnum;
+               break;
+       }
 
 #### Structs
 
 
 #### Structs
 
@@ -2919,24 +2935,31 @@ function will be needed.
        }
 
 ###### top level grammar
        }
 
 ###### top level grammar
-       DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ {
-               struct type *t;
-               t = find_type(c, $ID.txt);
-               if (!t)
-                       t = add_type(c, $ID.txt, &structure_prototype);
-               else if (t->size >= 0) {
+       $*type
+       StructName -> IDENTIFIER ${ {
+               struct type *t = find_type(c, $ID.txt);
+
+               if (t && t->size >= 0) {
                        tok_err(c, "error: type already declared", &$ID);
                        tok_err(c, "info: this is location of declartion", &t->first_use);
                        tok_err(c, "error: type already declared", &$ID);
                        tok_err(c, "info: this is location of declartion", &t->first_use);
-                       /* Create a new one - duplicate */
-                       t = add_type(c, $ID.txt, &structure_prototype);
-               } else {
-                       struct type tmp = *t;
-                       *t = structure_prototype;
-                       t->name = tmp.name;
-                       t->next = tmp.next;
+                       t = NULL;
                }
                }
-               t->structure.field_list = $<FB;
+               if (!t)
+                       t = add_type(c, $ID.txt, NULL);
                t->first_use = $ID;
                t->first_use = $ID;
+               $0 = t;
+       } }$
+       $void
+       DeclareStruct -> struct StructName FieldBlock Newlines ${ {
+               struct type *t = $<SN;
+               struct type tmp = *t;
+
+               *t = structure_prototype;
+               t->name = tmp.name;
+               t->next = tmp.next;
+               t->first_use = tmp.first_use;
+
+               t->structure.field_list = $<FB;
        } }$
 
        $*fieldlist
        } }$
 
        $*fieldlist
@@ -2946,10 +2969,17 @@ function will be needed.
        | SimpleFieldList EOL ${ $0 = $<SFL; }$
 
        FieldLines -> SimpleFieldList Newlines ${ $0 = $<SFL; }$
        | SimpleFieldList EOL ${ $0 = $<SFL; }$
 
        FieldLines -> SimpleFieldList Newlines ${ $0 = $<SFL; }$
-       | FieldLines SimpleFieldList Newlines ${
-               $SFL->prev = $<FL;
-               $0 = $<SFL;
-       }$
+       | FieldLines SimpleFieldList Newlines ${ {
+               struct fieldlist *f = $<SFL;
+
+               if (f) {
+                       $0 = f;
+                       while (f->prev)
+                               f = f->prev;
+                       f->prev = $<FL;
+               } else
+                       $0 = $<FL;
+       } }$
 
        SimpleFieldList -> Field ${ $0 = $<F; }$
        | SimpleFieldList ; Field ${
 
        SimpleFieldList -> Field ${ $0 = $<F; }$
        | SimpleFieldList ; Field ${
@@ -2991,10 +3021,10 @@ function will be needed.
                        if (fl->type->print && fl->init) {
                                fprintf(f, " = ");
                                if (fl->type == Tstr)
                        if (fl->type->print && fl->init) {
                                fprintf(f, " = ");
                                if (fl->type == Tstr)
-                                       fprintf(f, "\"");       // UNTESTED
+                                       fprintf(f, "\"");
                                print_value(fl->type, fl->init, f);
                                if (fl->type == Tstr)
                                print_value(fl->type, fl->init, f);
                                if (fl->type == Tstr)
-                                       fprintf(f, "\"");       // UNTESTED
+                                       fprintf(f, "\"");
                        }
                        fprintf(f, "\n");
                }
                        }
                        fprintf(f, "\n");
                }
@@ -3123,6 +3153,9 @@ anything in the heap or on the stack.  A reference can be assigned
        static int reference_compat(struct type *require, struct type *have,
                                    enum val_rules rules)
        {
        static int reference_compat(struct type *require, struct type *have,
                                    enum val_rules rules)
        {
+               if (rules & Rrefok)
+                       if (require->reference.referent == have)
+                               return 1;
                if (have->compat != require->compat)
                        return 0;
                if (have->reference.referent != require->reference.referent)
                if (have->compat != require->compat)
                        return 0;
                if (have->reference.referent != require->reference.referent)
@@ -3150,7 +3183,6 @@ anything in the heap or on the stack.  A reference can be assigned
                return Tnone;
        }
 
                return Tnone;
        }
 
-
        static struct type reference_prototype = {
                .print_type = reference_print_type,
                .cmp_eq = reference_cmp,
        static struct type reference_prototype = {
                .print_type = reference_print_type,
                .cmp_eq = reference_cmp,
@@ -3320,7 +3352,7 @@ anything in the heap or on the stack.  A reference can be assigned
 ###### Expressions: dereference
 
 ###### Binode types
 ###### Expressions: dereference
 
 ###### Binode types
-       Deref,
+       Deref, AddressOf,
 
 ###### term grammar
 
 
 ###### term grammar
 
@@ -3336,6 +3368,9 @@ anything in the heap or on the stack.  A reference can be assigned
                print_exec(b->left, -1, bracket);
                printf("@");
                break;
                print_exec(b->left, -1, bracket);
                printf("@");
                break;
+       case AddressOf:
+               print_exec(b->left, -1, bracket);
+               break;
 
 ###### propagate binode cases
        case Deref:
 
 ###### propagate binode cases
        case Deref:
@@ -3349,13 +3384,30 @@ anything in the heap or on the stack.  A reference can be assigned
                        return t->reference.referent;
                break;
 
                        return t->reference.referent;
                break;
 
+       case AddressOf:
+               /* left must be lval, we create reference to it */
+               if (!type || type->free != reference_free)
+                       t = propagate_types(b->left, c, perr, type, 0); // NOTEST impossible
+               else
+                       t = propagate_types(b->left, c, perr,
+                                           type->reference.referent, 0);
+               if (t)
+                       t = find_anon_type(c, &reference_prototype, "@%.*s",
+                                       t->name.len, t->name.txt);
+               return t;
+
 ###### interp binode cases
 ###### interp binode cases
-       case Deref: {
+       case Deref:
                left = interp_exec(c, b->left, &ltype);
                lrv = left.ref;
                rvtype = ltype->reference.referent;
                break;
                left = interp_exec(c, b->left, &ltype);
                lrv = left.ref;
                rvtype = ltype->reference.referent;
                break;
-       }
+
+       case AddressOf:
+               rv.ref = linterp_exec(c, b->left, &rvtype);
+               rvtype = find_anon_type(c, &reference_prototype, "@%.*s",
+                                       rvtype->name.len, rvtype->name.txt);
+               break;
 
 
 #### Functions
 
 
 #### Functions
@@ -3455,6 +3507,14 @@ further detailed when Expression Lists are introduced.
                return 0;
        }
 
                return 0;
        }
 
+       static struct exec *take_addr(struct exec *e)
+       {
+               struct binode *rv = new(binode);
+               rv->op = AddressOf;
+               rv->left = e;
+               return rv;
+       }
+
        static void function_check_args(struct parse_context *c, enum prop_err *perr,
                                        struct type *require, struct exec *args)
        {
        static void function_check_args(struct parse_context *c, enum prop_err *perr,
                                        struct type *require, struct exec *args)
        {
@@ -3466,13 +3526,22 @@ further detailed when Expression Lists are introduced.
 
                while (param) {
                        struct var *pv = cast(var, param->left);
 
                while (param) {
                        struct var *pv = cast(var, param->left);
+                       struct type *t = pv->var->type, *t2;
                        if (!arg) {
                                type_err(c, "error: insufficient arguments to function.",
                                         args, NULL, 0, NULL);
                                break;
                        }
                        *perr = 0;
                        if (!arg) {
                                type_err(c, "error: insufficient arguments to function.",
                                         args, NULL, 0, NULL);
                                break;
                        }
                        *perr = 0;
-                       propagate_types(arg->left, c, perr, pv->var->type, 0);
+                       t2 = propagate_types(arg->left, c, perr, t, Rrefok);
+                       if (t->free == reference_free &&
+                           t->reference.referent == t2 &&
+                           !(*perr & Erval)) {
+                               arg->left = take_addr(arg->left);
+                       } else if (!(*perr & Efail) && !type_compat(t2, t, 0)) {
+                               type_err(c, "error: cannot pass rval when reference expected",
+                                        arg->left, NULL, 0, NULL);
+                       }
                        param = cast(binode, param->right);
                        arg = cast(binode, arg->right);
                }
                        param = cast(binode, param->right);
                        arg = cast(binode, arg->right);
                }
@@ -3483,6 +3552,7 @@ further detailed when Expression Lists are introduced.
 
        static void function_print(struct type *type, struct value *val, FILE *f)
        {
 
        static void function_print(struct type *type, struct value *val, FILE *f)
        {
+               fprintf(f, "\n");
                print_exec(val->function, 1, 0);
        }
 
                print_exec(val->function, 1, 0);
        }
 
@@ -3516,7 +3586,6 @@ further detailed when Expression Lists are introduced.
                        } else
                                type_print(type->function.return_type, f);
                }
                        } else
                                type_print(type->function.return_type, f);
                }
-               fprintf(f, "\n");
        }
 
        static void function_free_type(struct type *t)
        }
 
        static void function_free_type(struct type *t)
@@ -3803,7 +3872,7 @@ there.
                struct binode *b2 = cast(binode, b->right);
                left = interp_exec(c, b->left, &ltype);
                if (left.bool)
                struct binode *b2 = cast(binode, b->right);
                left = interp_exec(c, b->left, &ltype);
                if (left.bool)
-                       rv = interp_exec(c, b2->left, &rvtype); // UNTESTED
+                       rv = interp_exec(c, b2->left, &rvtype);
                else
                        rv = interp_exec(c, b2->right, &rvtype);
                }
                else
                        rv = interp_exec(c, b2->right, &rvtype);
                }
@@ -3863,15 +3932,12 @@ lists.  In that case a separate function is used to print them.
 ### Expressions: Boolean
 
 The next class of expressions to use the `binode` will be Boolean
 ### Expressions: Boolean
 
 The next class of expressions to use the `binode` will be Boolean
-expressions.  "`and then`" and "`or else`" are similar to `and` and `or`
-have same corresponding precendence.  The difference is that they don't
+expressions.  `and` and `or` are short-circuit operators that don't
 evaluate the second expression if not necessary.
 
 ###### Binode types
        And,
 evaluate the second expression if not necessary.
 
 ###### Binode types
        And,
-       AndThen,
        Or,
        Or,
-       OrElse,
        Not,
 
 ###### declare terminals
        Not,
 
 ###### declare terminals
@@ -3887,14 +3953,6 @@ evaluate the second expression if not necessary.
                b->right = $<3;
                $0 = b;
        } }$
                b->right = $<3;
                $0 = b;
        } }$
-       | Expression or else Expression ${ {
-               struct binode *b = new(binode);
-               b->op = OrElse;
-               b->left = $<1;
-               b->right = $<4;
-               $0 = b;
-       } }$
-
        | Expression and Expression ${ {
                struct binode *b = new(binode);
                b->op = And;
        | Expression and Expression ${ {
                struct binode *b = new(binode);
                b->op = And;
@@ -3902,14 +3960,6 @@ evaluate the second expression if not necessary.
                b->right = $<3;
                $0 = b;
        } }$
                b->right = $<3;
                $0 = b;
        } }$
-       | Expression and then Expression ${ {
-               struct binode *b = new(binode);
-               b->op = AndThen;
-               b->left = $<1;
-               b->right = $<4;
-               $0 = b;
-       } }$
-
        | not Expression ${ {
                struct binode *b = new(binode);
                b->op = Not;
        | not Expression ${ {
                struct binode *b = new(binode);
                b->op = Not;
@@ -3925,13 +3975,6 @@ evaluate the second expression if not necessary.
                print_exec(b->right, -1, bracket);
                if (bracket) printf(")");
                break;
                print_exec(b->right, -1, bracket);
                if (bracket) printf(")");
                break;
-       case AndThen:
-               if (bracket) printf("(");
-               print_exec(b->left, -1, bracket);
-               printf(" and then ");
-               print_exec(b->right, -1, bracket);
-               if (bracket) printf(")");
-               break;
        case Or:
                if (bracket) printf("(");
                print_exec(b->left, -1, bracket);
        case Or:
                if (bracket) printf("(");
                print_exec(b->left, -1, bracket);
@@ -3939,13 +3982,6 @@ evaluate the second expression if not necessary.
                print_exec(b->right, -1, bracket);
                if (bracket) printf(")");
                break;
                print_exec(b->right, -1, bracket);
                if (bracket) printf(")");
                break;
-       case OrElse:
-               if (bracket) printf("(");
-               print_exec(b->left, -1, bracket);
-               printf(" or else ");
-               print_exec(b->right, -1, bracket);
-               if (bracket) printf(")");
-               break;
        case Not:
                if (bracket) printf("(");
                printf("not ");
        case Not:
                if (bracket) printf("(");
                printf("not ");
@@ -3955,9 +3991,7 @@ evaluate the second expression if not necessary.
 
 ###### propagate binode cases
        case And:
 
 ###### propagate binode cases
        case And:
-       case AndThen:
        case Or:
        case Or:
-       case OrElse:
        case Not:
                /* both must be Tbool, result is Tbool */
                propagate_types(b->left, c, perr, Tbool, 0);
        case Not:
                /* both must be Tbool, result is Tbool */
                propagate_types(b->left, c, perr, Tbool, 0);
@@ -3970,21 +4004,11 @@ evaluate the second expression if not necessary.
 
 ###### interp binode cases
        case And:
 
 ###### interp binode cases
        case And:
-               rv = interp_exec(c, b->left, &rvtype);
-               right = interp_exec(c, b->right, &rtype);
-               rv.bool = rv.bool && right.bool;
-               break;
-       case AndThen:
                rv = interp_exec(c, b->left, &rvtype);
                if (rv.bool)
                        rv = interp_exec(c, b->right, NULL);
                break;
        case Or:
                rv = interp_exec(c, b->left, &rvtype);
                if (rv.bool)
                        rv = interp_exec(c, b->right, NULL);
                break;
        case Or:
-               rv = interp_exec(c, b->left, &rvtype);
-               right = interp_exec(c, b->right, &rtype);
-               rv.bool = rv.bool || right.bool;
-               break;
-       case OrElse:
                rv = interp_exec(c, b->left, &rvtype);
                if (!rv.bool)
                        rv = interp_exec(c, b->right, NULL);
                rv = interp_exec(c, b->left, &rvtype);
                if (!rv.bool)
                        rv = interp_exec(c, b->right, NULL);
@@ -4080,9 +4104,9 @@ expression operator, and the `CMPop` non-terminal will match one of them.
                if (t)
                        propagate_types(b->right, c, perr, t, 0);
                else {
                if (t)
                        propagate_types(b->right, c, perr, t, 0);
                else {
-                       t = propagate_types(b->right, c, perr, NULL, 0);        // UNTESTED
-                       if (t)  // UNTESTED
-                               t = propagate_types(b->left, c, perr, t, 0);    // UNTESTED
+                       t = propagate_types(b->right, c, perr, NULL, 0);        // NOTEST
+                       if (t)  // NOTEST
+                               t = propagate_types(b->left, c, perr, t, 0);    // NOTEST
                }
                if (!type_compat(type, Tbool, 0))
                        type_err(c, "error: Comparison returns %1 but %2 expected", prog,
                }
                if (!type_compat(type, Tbool, 0))
                        type_err(c, "error: Comparison returns %1 but %2 expected", prog,
@@ -4244,9 +4268,10 @@ parentheses around an expression converts it into a Term,
                if (bracket) printf(")");
                break;
        case Bracket:
                if (bracket) printf(")");
                break;
        case Bracket:
-               printf("(");
+               /* Avoid double brackets... */
+               if (!bracket) printf("(");
                print_exec(b->right, indent, bracket);
                print_exec(b->right, indent, bracket);
-               printf(")");
+               if (!bracket) printf(")");
                break;
 
 ###### propagate binode cases
                break;
 
 ###### propagate binode cases
@@ -4282,7 +4307,7 @@ parentheses around an expression converts it into a Term,
                /* op must be string, result is number */
                propagate_types(b->left, c, perr, Tstr, 0);
                if (!type_compat(type, Tnum, 0))
                /* op must be string, result is number */
                propagate_types(b->left, c, perr, Tstr, 0);
                if (!type_compat(type, Tnum, 0))
-                       type_err(c,     // UNTESTED
+                       type_err(c,
                          "error: Can only convert string to number, not %1",
                                prog, type, 0, NULL);
                *perr |= Erval;
                          "error: Can only convert string to number, not %1",
                                prog, type, 0, NULL);
                *perr |= Erval;
@@ -4372,19 +4397,19 @@ parentheses around an expression converts it into a Term,
                rvtype = Tnum;
 
                struct text tx = right.str;
                rvtype = Tnum;
 
                struct text tx = right.str;
-               char tail[3];
+               char tail[3] = "";
                int neg = 0;
                if (tx.txt[0] == '-') {
                int neg = 0;
                if (tx.txt[0] == '-') {
-                       neg = 1;        // UNTESTED
-                       tx.txt++;       // UNTESTED
-                       tx.len--;       // UNTESTED
+                       neg = 1;
+                       tx.txt++;
+                       tx.len--;
                }
                if (number_parse(rv.num, tail, tx) == 0)
                }
                if (number_parse(rv.num, tail, tx) == 0)
-                       mpq_init(rv.num);       // UNTESTED
+                       mpq_init(rv.num);
                else if (neg)
                else if (neg)
-                       mpq_neg(rv.num, rv.num);        // UNTESTED
+                       mpq_neg(rv.num, rv.num);
                if (tail[0])
                if (tail[0])
-                       printf("Unsupported suffix: %.*s\n", tx.len, tx.txt);   // UNTESTED
+                       printf("Unsupported suffix: %.*s\n", tx.len, tx.txt);
 
                break;
        case Test:
 
                break;
        case Test:
@@ -4484,7 +4509,8 @@ the common header for all reductions to use.
        Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
        |        { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
        |        SimpleStatements ; ${ $0 = reorder_bilist($<SS); }$
        Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
        |        { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
        |        SimpleStatements ; ${ $0 = reorder_bilist($<SS); }$
-       |        SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
+       |        SimpleStatements EOL ${ $0 = reorder_bilist($<SS); 
+               }$
        |        IN OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
        OpenBlock -> OpenScope { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
        |        IN OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
        OpenBlock -> OpenScope { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
@@ -4493,7 +4519,7 @@ the common header for all reductions to use.
        |        OpenScope SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
        |        IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
        |        OpenScope SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
        |        IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
-       UseBlock -> { OpenScope IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
+       UseBlock -> { IN OpenScope OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
        |        { OpenScope SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
        |        IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
        |        { OpenScope SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
        |        IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
 
@@ -4507,7 +4533,7 @@ the common header for all reductions to use.
 
        ComplexStatements -> ComplexStatements ComplexStatement ${
                if ($2 == NULL) {
 
        ComplexStatements -> ComplexStatements ComplexStatement ${
                if ($2 == NULL) {
-                       $0 = $<1;
+                       $0 = $<1;       // NOTEST - impossible
                } else {
                        $0 = new(binode);
                        $0->op = Block;
                } else {
                        $0 = new(binode);
                        $0->op = Block;
@@ -4517,7 +4543,7 @@ the common header for all reductions to use.
        }$
        | ComplexStatement ${
                if ($1 == NULL) {
        }$
        | ComplexStatement ${
                if ($1 == NULL) {
-                       $0 = NULL;
+                       $0 = NULL;      // NOTEST - impossible
                } else {
                        $0 = new(binode);
                        $0->op = Block;
                } else {
                        $0 = new(binode);
                        $0->op = Block;
@@ -4557,25 +4583,13 @@ the common header for all reductions to use.
 
 ###### print binode cases
        case Block:
 
 ###### print binode cases
        case Block:
-               if (indent < 0) {
-                       // simple statement
-                       if (b->left == NULL)    // UNTESTED
-                               printf("pass"); // UNTESTED
-                       else
-                               print_exec(b->left, indent, bracket);   // UNTESTED
-                       if (b->right) { // UNTESTED
-                               printf("; ");   // UNTESTED
-                               print_exec(b->right, indent, bracket);  // UNTESTED
-                       }
-               } else {
-                       // block, one per line
-                       if (b->left == NULL)
-                               do_indent(indent, "pass\n");
-                       else
-                               print_exec(b->left, indent, bracket);
-                       if (b->right)
-                               print_exec(b->right, indent, bracket);
-               }
+               // block, one per line
+               if (b->left == NULL)
+                       do_indent(indent, "pass\n");
+               else
+                       print_exec(b->left, indent, bracket);
+               if (b->right)
+                       print_exec(b->right, indent, bracket);
                break;
 
 ###### propagate binode cases
                break;
 
 ###### propagate binode cases
@@ -4591,7 +4605,9 @@ the common header for all reductions to use.
                struct binode *e;
 
                for (e = b; e; e = cast(binode, e->right)) {
                struct binode *e;
 
                for (e = b; e; e = cast(binode, e->right)) {
-                       t = propagate_types(e->left, c, perr, NULL, rules);
+                       *perr |= *perr_local;
+                       *perr_local = 0;
+                       t = propagate_types(e->left, c, perr_local, NULL, rules);
                        if ((rules & Rboolok) && (t == Tbool || t == Tnone))
                                t = NULL;
                        if (t == Tnone && e->right)
                        if ((rules & Rboolok) && (t == Tbool || t == Tnone))
                                t = NULL;
                        if (t == Tnone && e->right)
@@ -4792,7 +4808,7 @@ be declared at any time.
 
        case Assign:
        case Declare:
 
        case Assign:
        case Declare:
-               /* Both must match and not be labels,
+               /* Both must match, or left may be ref and right an lval
                 * Type must support 'dup',
                 * For Assign, left must not be constant.
                 * result is Tnone
                 * Type must support 'dup',
                 * For Assign, left must not be constant.
                 * result is Tnone
@@ -4803,10 +4819,19 @@ be declared at any time.
                        return Tnone;
 
                if (t) {
                        return Tnone;
 
                if (t) {
-                       if (propagate_types(b->right, c, perr_local, t, 0) != t)
-                               if (b->left->type == Xvar)
-                                       type_err(c, "info: variable '%v' was set as %1 here.",
-                                                cast(var, b->left)->var->where_set, t, rules, NULL);
+                       struct type *t2 = propagate_types(b->right, c, perr_local,
+                                                         t, Rrefok);
+                       if (!t2 || t2 == t || (*perr_local & Efail))
+                               ; // No more effort needed
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                !(*perr_local & Erval))
+                               b->right = take_addr(b->right);
+                       else if (t->free == reference_free &&
+                                t->reference.referent == t2 &&
+                                (*perr_local & Erval))
+                               type_err(c, "error: Cannot assign an rval to a reference.",
+                                        b, NULL, 0, NULL);
                } else {
                        t = propagate_types(b->right, c, perr_local, NULL, 0);
                        if (t)
                } else {
                        t = propagate_types(b->right, c, perr_local, NULL, 0);
                        if (t)
@@ -4827,6 +4852,9 @@ be declared at any time.
                }
                if (t && t->dup == NULL && !(*perr_local & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
                }
                if (t && t->dup == NULL && !(*perr_local & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
+               if (b->left->type == Xvar && (*perr_local & Efail))
+                       type_err(c, "info: variable '%v' was set as %1 here.",
+                                cast(var, b->left)->var->where_set, t, rules, NULL);
                return Tnone;
 
                break;
                return Tnone;
 
                break;
@@ -4848,10 +4876,10 @@ be declared at any time.
                val = var_value(c, v);
                if (v->type->prepare_type)
                        v->type->prepare_type(c, v->type, 0);
                val = var_value(c, v);
                if (v->type->prepare_type)
                        v->type->prepare_type(c, v->type, 0);
-               if (b->right)
-                       dinterp_exec(c, b->right, val, v->type, 0);
-               else
+               if (!b->right)
                        val_init(v->type, val);
                        val_init(v->type, val);
+               else
+                       dinterp_exec(c, b->right, val, v->type, 0);
                break;
        }
 
                break;
        }
 
@@ -5275,9 +5303,7 @@ casepart` to track a list of case parts.
 
 ###### propagate binode cases
        case Loop:
 
 ###### propagate binode cases
        case Loop:
-               t = propagate_types(b->right, c, perr_local, Tnone, 0);
-               if (!type_compat(Tnone, t, 0))
-                       *perr |= Efail; // UNTESTED
+               propagate_types(b->right, c, perr_local, Tnone, 0);
                return propagate_types(b->left, c, perr, type, rules);
 
 ###### propagate exec cases
                return propagate_types(b->left, c, perr, type, rules);
 
 ###### propagate exec cases
@@ -5297,13 +5323,9 @@ casepart` to track a list of case parts.
                struct casepart *cp;
 
                t = propagate_types(cs->forpart, c, perr, Tnone, 0);
                struct casepart *cp;
 
                t = propagate_types(cs->forpart, c, perr, Tnone, 0);
-               if (!type_compat(Tnone, t, 0))
-                       *perr |= Efail; // UNTESTED
 
                if (cs->looppart) {
                        t = propagate_types(cs->thenpart, c, perr, Tnone, 0);
 
                if (cs->looppart) {
                        t = propagate_types(cs->thenpart, c, perr, Tnone, 0);
-                       if (!type_compat(Tnone, t, 0))
-                               *perr |= Efail; // UNTESTED
                }
                if (cs->casepart == NULL) {
                        propagate_types(cs->condpart, c, perr, Tbool, 0);
                }
                if (cs->casepart == NULL) {
                        propagate_types(cs->condpart, c, perr, Tbool, 0);
@@ -5315,9 +5337,9 @@ casepart` to track a list of case parts.
                             cp && !t; cp = cp->next)
                                t = propagate_types(cp->value, c, perr, NULL, 0);
                        if (!t && cs->condpart)
                             cp && !t; cp = cp->next)
                                t = propagate_types(cp->value, c, perr, NULL, 0);
                        if (!t && cs->condpart)
-                               t = propagate_types(cs->condpart, c, perr, NULL, Rboolok);      // UNTESTED
+                               t = propagate_types(cs->condpart, c, perr, NULL, Rboolok);      // NOTEST
                        if (!t && cs->looppart)
                        if (!t && cs->looppart)
-                               t = propagate_types(cs->looppart, c, perr, NULL, Rboolok);      // UNTESTED
+                               t = propagate_types(cs->looppart, c, perr, NULL, Rboolok);      // NOTEST
                        // Now we have a type (I hope) push it down
                        if (t) {
                                for (cp = cs->casepart; cp; cp = cp->next)
                        // Now we have a type (I hope) push it down
                        if (t) {
                                for (cp = cs->casepart; cp; cp = cp->next)
@@ -5333,8 +5355,8 @@ casepart` to track a list of case parts.
                        type = propagate_types(cs->elsepart, c, perr, NULL, rules);
                for (cp = cs->casepart;
                     cp && !type;
                        type = propagate_types(cs->elsepart, c, perr, NULL, rules);
                for (cp = cs->casepart;
                     cp && !type;
-                    cp = cp->next)     // UNTESTED
-                       type = propagate_types(cp->action, c, perr, NULL, rules);       // UNTESTED
+                    cp = cp->next)     // NOTEST
+                       type = propagate_types(cp->action, c, perr, NULL, rules);       // NOTEST
                if (type) {
                        if (!cs->looppart)
                                propagate_types(cs->thenpart, c, perr, type, rules);
                if (type) {
                        if (!cs->looppart)
                                propagate_types(cs->thenpart, c, perr, type, rules);
@@ -5432,7 +5454,7 @@ various declarations in the parse context.
        | DeclarationList Declaration
 
        Declaration -> ERROR Newlines ${
        | DeclarationList Declaration
 
        Declaration -> ERROR Newlines ${
-               tok_err(c,      // UNTESTED
+               tok_err(c,      // NOTEST
                        "error: unhandled parse error", &$1);
        }$
        | DeclareConstant
                        "error: unhandled parse error", &$1);
        }$
        | DeclareConstant
@@ -5738,10 +5760,13 @@ is a bit more interesting at this level.
                                struct value *val = var_value(&context, v);
                                printf("func %.*s", v->name->name.len, v->name->name.txt);
                                v->type->print_type_decl(v->type, stdout);
                                struct value *val = var_value(&context, v);
                                printf("func %.*s", v->name->name.len, v->name->name.txt);
                                v->type->print_type_decl(v->type, stdout);
-                               if (brackets)
-                                       print_exec(val->function, 0, brackets);
-                               else
+                               if (brackets) {
+                                       printf(" {\n");
+                                       print_exec(val->function, 1, brackets);
+                                       printf("}\n");
+                               } else {
                                        print_value(v->type, val, stdout);
                                        print_value(v->type, val, stdout);
+                               }
                                printf("/* frame size %d */\n", v->type->function.local_size);
                                target -= 1;
                        }
                                printf("/* frame size %d */\n", v->type->function.local_size);
                                target -= 1;
                        }
@@ -5843,15 +5868,12 @@ is a bit more interesting at this level.
                        struct value *vl = var_value(c, v->var);
                        struct value arg;
                        struct type *t;
                        struct value *vl = var_value(c, v->var);
                        struct value arg;
                        struct type *t;
-                       mpq_t argcq;
                        int i;
 
                        switch (anum++) {
                        case 0: /* argv */
                                t = v->var->type;
                        int i;
 
                        switch (anum++) {
                        case 0: /* argv */
                                t = v->var->type;
-                               mpq_init(argcq);
-                               mpq_set_ui(argcq, argc, 1);
-                               memcpy(var_value(c, t->array.vsize), &argcq, sizeof(argcq));
+                               t->array.size = argc;
                                t->prepare_type(c, t, 0);
                                array_init(v->var->type, vl);
                                for (i = 0; i < argc; i++) {
                                t->prepare_type(c, t, 0);
                                array_init(v->var->type, vl);
                                for (i = 0; i < argc; i++) {
@@ -5905,7 +5927,7 @@ things which will likely grow as the languages grows.
                name:string
                alive:Boolean
 
                name:string
                alive:Boolean
 
-       func main(argv:[argc::]string)
+       func main(argv:[]string)
                print "Hello World, what lovely oceans you have!"
                print "Are there", five, "?"
                print pi, pie, "but", cake
                print "Hello World, what lovely oceans you have!"
                print "Are there", five, "?"
                print pi, pie, "but", cake
@@ -5933,7 +5955,7 @@ things which will likely grow as the languages grows.
                a : number
                a = A;
                b:number = B
                a : number
                a = A;
                b:number = B
-               if a > 0 and then b > 0:
+               if a > 0 and b > 0:
                        while a != b:
                                if a < b:
                                        b = b - a
                        while a != b:
                                if a < b:
                                        b = b - a