]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: delay constant assignment test to type analysis.
[ocean] / csrc / oceani.mdc
index 7e74b8480c0073cd28c295f7abd50b36677d53c4..07606745a481a5b7ec174660a6a17e0c23086db0 100644 (file)
@@ -378,17 +378,10 @@ context so indicate that parsing failed.
                        case '%': fputc(*fmt, stderr); break;
                        default: fputc('?', stderr); break;
                        case '1':
-                               if (t1)
-                                       fprintf(stderr, "%.*s", t1->name.len, t1->name.txt);
-                               else
-                                       fputs("*unknown*", stderr);
+                               type_print(t1, stderr);
                                break;
                        case '2':
-                               if (t2)
-                                       fprintf(stderr, "%.*s", t2->name.len, t2->name.txt);
-                               else
-                                       fputs("*unknown*", stderr);
-                               break;
+                               type_print(t2, stderr);
                                break;
                        ## format cases
                        }
@@ -447,13 +440,15 @@ which are often passed around by value.
                struct text name;
                struct type *next;
                struct value (*init)(struct type *type);
+               struct value (*prepare)(struct type *type);
                struct value (*parse)(struct type *type, char *str);
                void (*print)(struct value val);
+               void (*print_type)(struct type *type, FILE *f);
                int (*cmp_order)(struct value v1, struct value v2);
                int (*cmp_eq)(struct value v1, struct value v2);
                struct value (*dup)(struct value val);
                void (*free)(struct value val);
-               struct type *(*compat)(struct type *this, struct type *other);
+               int (*compat)(struct type *this, struct type *other);
                long long (*to_int)(struct value *v);
                double (*to_float)(struct value *v);
                int (*to_mpq)(mpq_t *q, struct value *v);
@@ -504,6 +499,43 @@ which are often passed around by value.
                        v.type->free(v);
        }
 
+       static int type_compat(struct type *require, struct type *have, int rules)
+       {
+               if ((rules & Rboolok) && have == Tbool)
+                       return 1;
+               if ((rules & Rnolabel) && have == Tlabel)
+                       return 0;
+               if (!require || !have)
+                       return 1;
+
+               if (require->compat)
+                       return require->compat(require, have);
+
+               return require == have;
+       }
+
+       static void type_print(struct type *type, FILE *f)
+       {
+               if (!type)
+                       fputs("*unknown*type*", f);
+               else if (type->name.len)
+                       fprintf(f, "%.*s", type->name.len, type->name.txt);
+               else if (type->print_type)
+                       type->print_type(type, f);
+               else
+                       fputs("*invalid*type*", f);
+       }
+
+       static struct value val_prepare(struct type *type)
+       {
+               struct value rv;
+
+               if (type)
+                       return type->prepare(type);
+               rv.type = type;
+               return rv;
+       }
+
        static struct value val_init(struct type *type)
        {
                struct value rv;
@@ -609,20 +641,33 @@ to parse each type from a string.
                }
        }
 
-       static int vtype_compat(struct type *require, struct type *have, int rules)
+###### value functions
+
+       static struct value _val_prepare(struct type *type)
        {
-               if ((rules & Rboolok) && have == Tbool)
-                       return 1;
-               if ((rules & Rnolabel) && have == Tlabel)
-                       return 0;
-               if (!require || !have)
-                       return 1;
+               struct value rv;
 
-               return require == have;
+               rv.type = type;
+               switch(type->vtype) {
+               case Vnone:
+                       break;
+               case Vnum:
+                       memset(&rv.num, 0, sizeof(rv.num));
+                       break;
+               case Vstr:
+                       rv.str.txt = NULL;
+                       rv.str.len = 0;
+                       break;
+               case Vbool:
+                       rv.bool = 0;
+                       break;
+               case Vlabel:
+                       rv.label = NULL;
+                       break;
+               }
+               return rv;
        }
 
-###### value functions
-
        static struct value _val_init(struct type *type)
        {
                struct value rv;
@@ -764,6 +809,7 @@ to parse each type from a string.
 
        static struct type base_prototype = {
                .init = _val_init,
+               .prepare = _val_prepare,
                .parse = _parse_value,
                .print = _print_value,
                .cmp_order = _value_cmp,
@@ -1099,7 +1145,7 @@ all pending-scope variables become conditionally scoped.
                v->scope = InScope;
                v->in_scope = c->in_scope;
                c->in_scope = v;
-               v->val = val_init(NULL);
+               v->val = val_prepare(NULL);
                return v;
        }
 
@@ -1369,7 +1415,7 @@ propagation is needed.
 
 ###### ast
 
-       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1};
+       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 2<<1};
 
 ###### format cases
        case 'r':
@@ -1523,7 +1569,7 @@ an executable.
                case Xval:
                {
                        struct val *val = cast(val, prog);
-                       if (!vtype_compat(type, val->val.type, rules)) {
+                       if (!type_compat(type, val->val.type, rules)) {
                                type_err(c, "error: expected %1%r found %2",
                                           prog, type, rules, val->val.type);
                                *ok = 0;
@@ -1627,7 +1673,7 @@ link to find the primary instance.
                if (v) {
                        v->where_decl = $0;
                        v->where_set = $0;
-                       v->val = val_init($<3);
+                       v->val = val_prepare($<3);
                } else {
                        v = var_ref(config2context(config), $1.txt);
                        $0->var = v;
@@ -1644,7 +1690,7 @@ link to find the primary instance.
                if (v) {
                        v->where_decl = $0;
                        v->where_set = $0;
-                       v->val = val_init($<3);
+                       v->val = val_prepare($<3);
                        v->constant = 1;
                } else {
                        v = var_ref(config2context(config), $1.txt);
@@ -1663,7 +1709,7 @@ link to find the primary instance.
                        /* This might be a label - allocate a var just in case */
                        v = var_decl(config2context(config), $1.txt);
                        if (v) {
-                               v->val = val_init(Tlabel);
+                               v->val = val_prepare(Tlabel);
                                v->val.label = &v->val;
                                v->where_set = $0;
                        }
@@ -1719,15 +1765,23 @@ link to find the primary instance.
                }
                if (v->merged)
                        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);
+                       *ok = 0;
+                       return v->val.type;
+               }
                if (v->val.type == NULL) {
                        if (type && *ok != 0) {
-                               v->val = val_init(type);
+                               v->val = val_prepare(type);
                                v->where_set = prog;
                                *ok = 2;
                        }
                        return type;
                }
-               if (!vtype_compat(type, v->val.type, rules)) {
+               if (!type_compat(type, v->val.type, rules)) {
                        type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
                                 type, rules, v->val.type);
                        type_err(c, "info: this is where '%v' was set to %1", v->where_set,
@@ -1936,7 +1990,7 @@ expression operator.
                        if (t)
                                t = propagate_types(b->left, c, ok, t, 0);
                }
-               if (!vtype_compat(type, Tbool, 0)) {
+               if (!type_compat(type, Tbool, 0)) {
                        type_err(c, "error: Comparison returns %1 but %2 expected", prog,
                                    Tbool, rules, type);
                        *ok = 0;
@@ -2079,7 +2133,7 @@ precedence is handled better I might be able to discard this.
                 * unary ops fit here too */
                propagate_types(b->left, c, ok, Tnum, 0);
                propagate_types(b->right, c, ok, Tnum, 0);
-               if (!vtype_compat(type, Tnum, 0)) {
+               if (!type_compat(type, Tnum, 0)) {
                        type_err(c, "error: Arithmetic returns %1 but %2 expected", prog,
                                   Tnum, rules, type);
                        *ok = 0;
@@ -2090,7 +2144,7 @@ precedence is handled better I might be able to discard this.
                /* both must be Tstr, result is Tstr */
                propagate_types(b->left, c, ok, Tstr, 0);
                propagate_types(b->right, c, ok, Tstr, 0);
-               if (!vtype_compat(type, Tstr, 0)) {
+               if (!type_compat(type, Tstr, 0)) {
                        type_err(c, "error: Concat returns %1 but %2 expected", prog,
                                   Tstr, rules, type);
                        *ok = 0;
@@ -2442,20 +2496,12 @@ it is declared, and error will be raised as the name is created as
        Declare,
 
 ###### SimpleStatement Grammar
-       | Variable = Expression ${ {
-                       struct var *v = cast(var, $1);
-
+       | Variable = Expression ${
                        $0 = new(binode);
                        $0->op = Assign;
                        $0->left = $<1;
                        $0->right = $<3;
-                       if (v->var && v->var->constant) {
-                               type_err(config2context(config), "Cannot assign to a constant: %v",
-                                        $0->left, NULL, 0, NULL);
-                               type_err(config2context(config), "name was defined as a constant here",
-                                        v->var->where_decl, NULL, 0, NULL);
-                       }
-               } }$
+               }$
        | VariableDecl = Expression ${
                        $0 = new(binode);
                        $0->op = Declare;
@@ -2492,16 +2538,18 @@ it is declared, and error will be raised as the name is created as
                do_indent(indent, "");
                print_exec(b->left, indent, 0);
                if (cast(var, b->left)->var->constant) {
-                       if (v->where_decl == v->where_set)
-                               printf("::%.*s ", v->val.type->name.len,
-                                      v->val.type->name.txt);
-                       else
+                       if (v->where_decl == v->where_set) {
+                               printf("::");
+                               type_print(v->val.type, stdout);
+                               printf(" ");
+                       } else
                                printf(" ::");
                } else {
-                       if (v->where_decl == v->where_set)
-                               printf(":%.*s ", v->val.type->name.len,
-                                      v->val.type->name.txt);
-                       else
+                       if (v->where_decl == v->where_set) {
+                               printf(":");
+                               type_print(v->val.type, stdout);
+                               printf(" ");
+                       } else
                                printf(" :");
                }
                if (b->right) {
@@ -2519,8 +2567,11 @@ it is declared, and error will be raised as the name is created as
        case Declare:
                /* Both must match and not be labels,
                 * Type must support 'dup',
-                * result is Tnone */
-               t = propagate_types(b->left, c, ok, NULL, Rnolabel);
+                * For Assign, left must not be constant.
+                * result is Tnone
+                */
+               t = propagate_types(b->left, c, ok, NULL,
+                                   Rnolabel | (b->op == Assign ? Rnoconstant : 0));
                if (!b->right)
                        return Tnone;
 
@@ -2532,7 +2583,8 @@ it is declared, and error will be raised as the name is created as
                } else {
                        t = propagate_types(b->right, c, ok, NULL, Rnolabel);
                        if (t)
-                               propagate_types(b->left, c, ok, t, 0);
+                               propagate_types(b->left, c, ok, t,
+                                               (b->op == Assign ? Rnoconstant : 0));
                }
                if (t && t->dup == NULL) {
                        type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
@@ -2992,14 +3044,14 @@ defined.
                struct casepart *cp;
 
                t = propagate_types(cs->forpart, c, ok, Tnone, 0);
-               if (!vtype_compat(Tnone, t, 0))
+               if (!type_compat(Tnone, t, 0))
                        *ok = 0;
                t = propagate_types(cs->dopart, c, ok, Tnone, 0);
-               if (!vtype_compat(Tnone, t, 0))
+               if (!type_compat(Tnone, t, 0))
                        *ok = 0;
                if (cs->dopart) {
                        t = propagate_types(cs->thenpart, c, ok, Tnone, 0);
-                       if (!vtype_compat(Tnone, t, 0))
+                       if (!type_compat(Tnone, t, 0))
                                *ok = 0;
                }
                if (cs->casepart == NULL)
@@ -3172,7 +3224,7 @@ analysis is a bit more interesting at this level.
                        struct var *v = cast(var, b->left);
                        if (!v->var->val.type) {
                                v->var->where_set = b;
-                               v->var->val = val_init(Tstr);
+                               v->var->val = val_prepare(Tstr);
                        }
                }
                b = cast(binode, prog);