]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: pass 'rules' into the 'compat' type function.
[ocean] / csrc / oceani.mdc
index e147baa1303ed29643c8f4b43c0c5c0bebd04fb8..a62534814a880fd01aa9c78cdfce316edbb81a37 100644 (file)
@@ -367,14 +367,14 @@ context so indicate that parsing failed.
        static void fput_loc(struct exec *loc, FILE *f);
        static void type_err(struct parse_context *c,
                             char *fmt, struct exec *loc,
-                            struct type *t1, int rules, struct type *t2);
+                            struct type *t1, enum val_rules rules, struct type *t2);
        static void tok_err(struct parse_context *c, char *fmt, struct token *t);
 
 ###### core functions
 
        static void type_err(struct parse_context *c,
                             char *fmt, struct exec *loc,
-                            struct type *t1, int rules, struct type *t2)
+                            struct type *t1, enum val_rules rules, struct type *t2)
        {
                fprintf(stderr, "%s:", c->file_name);
                fput_loc(loc, stderr);
@@ -589,30 +589,27 @@ expected to return, and returns the type that it does return, either of
 which can be `NULL` signifying "unknown".  A `prop_err` flag set is
 passed by reference.  It has `Efail` set when an error is found, and
 `Eretry` when the type for some element is set via propagation.  If
-any expression cannot be evaluated immediately, `Enoconst` is set.
+any expression cannot be evaluated a compile time, `Eruntime` is set.
 If the expression can be copied, `Emaycopy` is set.
 
-If it remains unchanged at `0`, then no more propagation is needed.
+If `Erval` is set, then the value cannot be assigned to because it is
+a temporary result.  If `Erval` is clear but `Econst` is set, then
+the value can only be assigned once, when the variable is declared.
 
 ###### ast
 
-       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
-       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2,
-                      Emaycopy = 1<<3};
-
-###### format cases
-       case 'r':
-               if (rules & Rnolabel)
-                       fputs(" (labels not permitted)", stderr);
-               break;
+       enum val_rules {Rboolok = 1<<0,};
+       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
+                      Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
 
 ###### forward decls
        static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr,
-                                           struct type *type, int rules);
+                                           struct type *type, enum val_rules rules);
 ###### core functions
 
        static struct type *__propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr,
-                                             struct type *type, int rules)
+                                             enum prop_err *perr_local,
+                                             struct type *type, enum val_rules rules)
        {
                struct type *t;
 
@@ -634,11 +631,13 @@ If it remains unchanged at `0`, then no more propagation is needed.
        }
 
        static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr,
-                                           struct type *type, int rules)
+                                           struct type *type, enum val_rules rules)
        {
                int pre_err = c->parse_error;
-               struct type *ret = __propagate_types(prog, c, perr, type, rules);
+               enum prop_err perr_local = 0;
+               struct type *ret = __propagate_types(prog, c, perr, &perr_local, type, rules);
 
+               *perr |= perr_local & (Efail | Eretry);
                if (c->parse_error > pre_err)
                        *perr |= Efail;
                return ret;
@@ -992,7 +991,7 @@ which might be reported in error messages.
 ###### forward decls
 
        static void free_value(struct type *type, struct value *v);
-       static int type_compat(struct type *require, struct type *have, int rules);
+       static int type_compat(struct type *require, struct type *have, enum val_rules rules);
        static void type_print(struct type *type, FILE *f);
        static void val_init(struct type *type, struct value *v);
        static void dup_value(struct type *type,
@@ -1057,21 +1056,20 @@ A separate function encoding these cases will simplify some code later.
 
 ###### type functions
 
-       int (*compat)(struct type *this, struct type *other);
+       int (*compat)(struct type *this, struct type *other, enum val_rules rules);
 
 ###### ast functions
 
-       static int type_compat(struct type *require, struct type *have, int rules)
+       static int type_compat(struct type *require, struct type *have,
+                              enum val_rules rules)
        {
                if ((rules & Rboolok) && have == Tbool)
                        return 1;       // NOTEST
-               if ((rules & Rnolabel) && have == Tlabel)
-                       return 0;       // NOTEST
                if (!require || !have)
                        return 1;
 
                if (require->compat)
-                       return require->compat(require, have);
+                       return require->compat(require, have, rules);
 
                return require == have;
        }
@@ -1319,8 +1317,9 @@ executable.
        {
                struct val *val = cast(val, prog);
                if (!type_compat(type, val->vtype, rules))
-                       type_err(c, "error: expected %1%r found %2",
+                       type_err(c, "error: expected %1 found %2",
                                   prog, type, rules, val->vtype);
+               *perr |= Erval;
                return val->vtype;
        }
 
@@ -1441,8 +1440,9 @@ match "case".
                struct label *l = cast(label, prog);
                l->value = label_lookup(c, l->name);
                if (!type_compat(type, Tlabel, rules))
-                       type_err(c, "error: expected %1%r found %2",
+                       type_err(c, "error: expected %1 found %2",
                                 prog, type, rules, Tlabel);
+               *perr |= Erval;
                return Tlabel;
        }
 ###### interp exec cases
@@ -2274,13 +2274,6 @@ correctly.
                        return Tnone;                                   // NOTEST
                }
                v = v->merged;
-               if (v->constant && (rules & Rnoconstant)) {
-                       type_err(c, "error: Cannot assign to a constant: %v",
-                                prog, NULL, 0, NULL);
-                       type_err(c, "info: name was defined as a constant here",
-                                v->where_decl, NULL, 0, NULL);
-                       return v->type;
-               }
                if (v->type == Tnone && v->where_decl == prog)
                        type_err(c, "error: variable used but not declared: %v",
                                 prog, NULL, 0, NULL);
@@ -2291,13 +2284,15 @@ correctly.
                                *perr |= Eretry;
                        }
                } else if (!type_compat(type, v->type, rules)) {
-                       type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
+                       type_err(c, "error: expected %1 but variable '%v' is %2", prog,
                                 type, rules, v->type);
                        type_err(c, "info: this is where '%v' was set to %1", v->where_set,
                                 v->type, rules, NULL);
                }
                if (!v->global || v->frame_pos < 0)
-                       *perr |= Enoconst;
+                       *perr |= Eruntime;
+               if (v->constant)
+                       *perr |= Econst;
                if (!type)
                        return v->type;
                return type;
@@ -2467,7 +2462,8 @@ with a const size by whether they are prepared at parse time or not.
                        free(ptr);
        }
 
-       static int array_compat(struct type *require, struct type *have)
+       static int array_compat(struct type *require, struct type *have,
+                               enum val_rules rules)
        {
                if (have->compat != require->compat)
                        return 0;
@@ -2607,8 +2603,8 @@ with a const size by whether they are prepared at parse time or not.
                /* left must be an array, right must be a number,
                 * result is the member type of the array
                 */
-               propagate_types(b->right, c, perr, Tnum, 0);
-               t = propagate_types(b->left, c, perr, NULL, rules & Rnoconstant);
+               propagate_types(b->right, c, perr_local, Tnum, 0);
+               t = propagate_types(b->left, c, perr, NULL, 0);
                if (!t || t->compat != array_compat) {
                        type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL);
                        return NULL;
@@ -3124,7 +3120,8 @@ anything in the heap or on the stack.  A reference can be assigned
                /* Nothing to do here */
        }
 
-       static int reference_compat(struct type *require, struct type *have)
+       static int reference_compat(struct type *require, struct type *have,
+                                   enum val_rules rules)
        {
                if (have->compat != require->compat)
                        return 0;
@@ -3265,6 +3262,7 @@ anything in the heap or on the stack.  A reference can be assigned
                                r->reftype = type;
                                *perr |= Eretry;
                        }
+                       *perr |= Erval;
                        return type;
                case RefNil:
                        if (type && type->free != reference_free)
@@ -3274,9 +3272,10 @@ anything in the heap or on the stack.  A reference can be assigned
                                r->reftype = type;
                                *perr |= Eretry;
                        }
+                       *perr |= Erval;
                        return type;
                case RefFree:
-                       t = propagate_types(r->right, c, perr, NULL, 0);
+                       t = propagate_types(r->right, c, perr_local, NULL, 0);
                        if (t && t->free != reference_free)
                                type_err(c, "error: @free can only be assigned a reference, not %1",
                                         prog, t, 0, NULL);
@@ -3343,6 +3342,7 @@ anything in the heap or on the stack.  A reference can be assigned
                /* left must be a reference, and we return what it refers to */
                /* FIXME how can I pass the expected type down? */
                t = propagate_types(b->left, c, perr, NULL, 0);
+               *perr &= ~Erval;
                if (!t || t->free != reference_free)
                        type_err(c, "error: Cannot dereference %1", b, t, 0, NULL);
                else
@@ -3448,7 +3448,8 @@ further detailed when Expression Lists are introduced.
                val->function = NULL;
        }
 
-       static int function_compat(struct type *require, struct type *have)
+       static int function_compat(struct type *require, struct type *have,
+                                  enum val_rules rules)
        {
                // FIXME can I do anything here yet?
                return 0;
@@ -3673,10 +3674,11 @@ it in the "SimpleStatement Grammar" which will be described later.
                                 prog, NULL, 0, NULL);
                        return NULL;
                }
-               *perr |= Enoconst;
-               v->var->type->check_args(c, perr, v->var->type, args);
+               *perr |= Eruntime;
+               v->var->type->check_args(c, perr_local, v->var->type, args);
                if (v->var->type->function.inline_result)
                        *perr |= Emaycopy;
+               *perr |= Erval;
                return v->var->type->function.return_type;
        }
 
@@ -3789,9 +3791,9 @@ there.
                struct binode *b2 = cast(binode, b->right);
                struct type *t2;
 
-               propagate_types(b->left, c, perr, Tbool, 0);
-               t = propagate_types(b2->left, c, perr, type, Rnolabel);
-               t2 = propagate_types(b2->right, c, perr, type ?: t, Rnolabel);
+               propagate_types(b->left, c, perr_local, Tbool, 0);
+               t = propagate_types(b2->left, c, perr, type, 0);
+               t2 = propagate_types(b2->right, c, perr, type ?: t, 0);
                return t ?: t2;
        }
 
@@ -3963,6 +3965,7 @@ evaluate the second expression if not necessary.
                if (type && type != Tbool)
                        type_err(c, "error: %1 operation found where %2 expected", prog,
                                   Tbool, 0, type);
+               *perr |= Erval;
                return Tbool;
 
 ###### interp binode cases
@@ -4073,17 +4076,18 @@ expression operator, and the `CMPop` non-terminal will match one of them.
        case Eql:
        case NEql:
                /* Both must match but not be labels, result is Tbool */
-               t = propagate_types(b->left, c, perr, NULL, Rnolabel);
+               t = propagate_types(b->left, c, perr, NULL, 0);
                if (t)
                        propagate_types(b->right, c, perr, t, 0);
                else {
-                       t = propagate_types(b->right, c, perr, NULL, Rnolabel); // UNTESTED
+                       t = propagate_types(b->right, c, perr, NULL, 0);        // UNTESTED
                        if (t)  // UNTESTED
                                t = propagate_types(b->left, c, perr, t, 0);    // UNTESTED
                }
                if (!type_compat(type, Tbool, 0))
                        type_err(c, "error: Comparison returns %1 but %2 expected", prog,
                                    Tbool, rules, type);
+               *perr |= Erval;
                return Tbool;
 
 ###### interp binode cases
@@ -4261,6 +4265,7 @@ parentheses around an expression converts it into a Term,
                if (!type_compat(type, Tnum, 0))
                        type_err(c, "error: Arithmetic returns %1 but %2 expected", prog,
                                   Tnum, rules, type);
+               *perr |= Erval;
                return Tnum;
 
        case Concat:
@@ -4270,6 +4275,7 @@ parentheses around an expression converts it into a Term,
                if (!type_compat(type, Tstr, 0))
                        type_err(c, "error: Concat returns %1 but %2 expected", prog,
                                   Tstr, rules, type);
+               *perr |= Erval;
                return Tstr;
 
        case StringConv:
@@ -4279,6 +4285,7 @@ parentheses around an expression converts it into a Term,
                        type_err(c,     // UNTESTED
                          "error: Can only convert string to number, not %1",
                                prog, type, 0, NULL);
+               *perr |= Erval;
                return Tnum;
 
        case Test:
@@ -4287,6 +4294,7 @@ parentheses around an expression converts it into a Term,
                if (!t || !t->test)
                        type_err(c, "error: '?' requires a testable value, not %1",
                                 prog, t, 0, NULL);
+               *perr |= Erval;
                return Tbool;
 
        case Choose:
@@ -4298,10 +4306,11 @@ parentheses around an expression converts it into a Term,
                if (t && t->test == NULL)
                        type_err(c, "error: \"??\" requires a testable value, not %1",
                                 prog, t, 0, NULL);
+               *perr |= Erval;
                return t;
 
        case Bracket:
-               return propagate_types(b->right, c, perr, type, 0);
+               return propagate_types(b->right, c, perr, type, rules);
 
 ###### interp binode cases
 
@@ -4594,7 +4603,7 @@ the common header for all reductions to use.
                                if (!type)
                                        type = t;
                                else if (t != type)
-                                       type_err(c, "error: expected %1%r, found %2",
+                                       type_err(c, "error: expected %1, found %2",
                                                 e->left, type, rules, t);
                        }
                }
@@ -4671,7 +4680,7 @@ printed.
                else
                        b = cast(binode, b->right);
                while (b) {
-                       propagate_types(b->left, c, perr, NULL, Rnolabel);
+                       propagate_types(b->left, c, perr_local, NULL, 0);
                        b = cast(binode, b->right);
                }
                break;
@@ -4788,23 +4797,35 @@ be declared at any time.
                 * For Assign, left must not be constant.
                 * result is Tnone
                 */
-               t = propagate_types(b->left, c, perr, NULL,
-                                   Rnolabel | (b->op == Assign ? Rnoconstant : 0));
+               *perr &= ~(Erval | Econst);
+               t = propagate_types(b->left, c, perr, NULL, 0);
                if (!b->right)
                        return Tnone;
 
                if (t) {
-                       if (propagate_types(b->right, c, perr, t, 0) != 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);
                } else {
-                       t = propagate_types(b->right, c, perr, NULL, Rnolabel);
+                       t = propagate_types(b->right, c, perr_local, NULL, 0);
                        if (t)
-                               propagate_types(b->left, c, perr, t,
-                                               (b->op == Assign ? Rnoconstant : 0));
+                               propagate_types(b->left, c, perr, t, 0);
+               }
+               if (*perr & Erval)
+                       type_err(c, "error: cannot assign to an rval", b,
+                                NULL, 0, NULL);
+               else if (b->op == Assign && (*perr & Econst)) {
+                       type_err(c, "error: Cannot assign to a constant: %v",
+                                b->left, NULL, 0, NULL);
+                       if (b->left->type == Xvar) {
+                               struct var *var = cast(var, b->left);
+                               struct variable *v = var->var;
+                               type_err(c, "info: name was defined as a constant here",
+                                        v->where_decl, NULL, 0, NULL);
+                       }
                }
-               if (t && t->dup == NULL && !(*perr & Emaycopy))
+               if (t && t->dup == NULL && !(*perr_local & Emaycopy))
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
                return Tnone;
 
@@ -5254,7 +5275,7 @@ casepart` to track a list of case parts.
 
 ###### propagate binode cases
        case Loop:
-               t = propagate_types(b->right, c, perr, Tnone, 0);
+               t = propagate_types(b->right, c, perr_local, Tnone, 0);
                if (!type_compat(Tnone, t, 0))
                        *perr |= Efail; // UNTESTED
                return propagate_types(b->left, c, perr, type, rules);
@@ -5532,7 +5553,7 @@ constants.
                                } while (perr & Eretry);
                                if (perr & Efail)
                                        c->parse_error += 1;
-                               else if (!(perr & Enoconst)) {
+                               else if (!(perr & Eruntime)) {
                                        progress = some;
                                        struct value res = interp_exec(
                                                c, vb->right, &v->var->type);
@@ -5640,8 +5661,8 @@ is a bit more interesting at this level.
                        struct value fn = {.function = code};
                        struct type *t;
                        var_block_close(c, CloseFunction, code);
-                       t = add_anon_type(c, &function_prototype, 
-                                         "func %.*s", name->name->name.len, 
+                       t = add_anon_type(c, &function_prototype,
+                                         "func %.*s", name->name->name.len,
                                          name->name->name.txt);
                        name->type = t;
                        t->function.params = reorder_bilist(args);
@@ -5753,7 +5774,7 @@ is a bit more interesting at this level.
                                all_ok = 0;
                        if (!v->type->function.inline_result &&
                            !v->type->function.return_type->dup) {
-                               type_err(c, "error: function cannot return value of type %1", 
+                               type_err(c, "error: function cannot return value of type %1",
                                         v->where_decl, v->type->function.return_type, 0, NULL);
                        }