]> ocean-lang.org Git - ocean/commitdiff
oceani: discard Vnolabel infavour of rules.
authorNeilBrown <neil@brown.name>
Sat, 20 Apr 2019 04:40:52 +0000 (14:40 +1000)
committerNeilBrown <neil@brown.name>
Sat, 20 Apr 2019 05:02:10 +0000 (15:02 +1000)
Instead Vnolabel as a type, change "bool_permitted" to
a set of rules (Rboolok) and add a new rule: Rnolabel.

This requires changes to type_err() and elsewhere.

Signed-off-by: NeilBrown <neil@brown.name>
csrc/oceani.mdc

index a8da9fbf8037804ef6b6ad87a0d50985be7cf28b..4f3977592947920ca2b5e4fe0d48a1ad95be69f0 100644 (file)
@@ -339,7 +339,9 @@ types.  So we provide a `printf`-like function which takes a format, a
 language (a `struct exec` which has not yet been introduced), and 2
 types. "`$1`" reports the first type, "`$2`" reports the second.  We
 will need a function to print the location, once we know how that is
-stored.
+stored.  As will be explained later, there are sometimes extra rules for
+type matching and they might affect error messages, we need to pass those
+in too.
 
 ###### forward decls
 
@@ -349,7 +351,7 @@ stored.
 
        static void type_err(struct parse_context *c,
                             char *fmt, struct exec *loc,
-                            enum vtype t1, enum vtype t2)
+                            enum vtype t1, int rules, enum vtype t2)
        {
                fprintf(stderr, "%s:", c->file_name);
                fput_loc(loc, stderr);
@@ -397,24 +399,18 @@ which hold the values.
 Values can be numbers, which we represent as multi-precision
 fractions, strings, Booleans and labels.  When analysing the program
 we also need to allow for places where no value is meaningful
-(`Vnone`) and where we don't know what type to expect yet (`Vunknown`
-which can be anything and `Vnolabel` which can be anything except a
-label).
+(`Vnone`) and where we don't know what type to expect yet (`Vunknown`).
 
 Values are never shared, they are always copied when used, and freed
 when no longer needed.
 
 When propagating type information around the program, we need to
 determine if two types are compatible, where `Vunknown` is compatible
-with anything, and `Vnolabel` is compatible with anything except a
-label.  A separate function to encode this rule will simplify some code
-later.
-
-There is an extra complication that this function needs to handle,
-which is described later when the Conditional Statement is introduced.
-In certain cases where a particular type is generally expected, a
-Boolean is also alway permitted.  To handle those cases, we explicitly tell
-`vtype_compat()` is a Boolean is permitted.
+with anything.  There are two special cases with type compatibility,
+both related to the Conditional Statement which will be described
+later.  In some cases a Boolean can be accepted as well as some other
+primary type, and in others any type is acceptable except a label (`Vlabel`).
+A separate function encode these cases will simplify some code later.
 
 When assigning command line arguments to variables, we need to be able
 to parse each type from a string.
@@ -430,7 +426,7 @@ to parse each type from a string.
 
 ###### ast
        struct value {
-               enum vtype {Vnolabel, Vunknown, Vnone, Vstr, Vnum, Vbool, Vlabel} vtype;
+               enum vtype {Vunknown, Vnone, Vstr, Vnum, Vbool, Vlabel} vtype;
                union {
                        struct text str;
                        mpq_t num;
@@ -439,15 +435,22 @@ to parse each type from a string.
                };
        };
 
-       char *vtype_names[] = {"nolabel", "unknown", "none", "string",
+       enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1};
+
+       char *vtype_names[] = {"unknown", "none", "string",
                               "number", "Boolean", "label"};
 
+###### format cases
+       case 'r':
+               if (rules & Rnolabel)
+                       fputs(" (labels not permitted)", stderr);
+               break;
+
 ###### ast functions
        static void free_value(struct value v)
        {
                switch (v.vtype) {
                case Vnone:
-               case Vnolabel:
                case Vunknown: break;
                case Vstr: free(v.str.txt); break;
                case Vnum: mpq_clear(v.num); break;
@@ -456,18 +459,16 @@ to parse each type from a string.
                }
        }
 
-       static int vtype_compat(enum vtype require, enum vtype have, int bool_permitted)
+       static int vtype_compat(enum vtype require, enum vtype have, int rules)
        {
-               if (bool_permitted && have == Vbool)
+               if ((rules & Rboolok) && have == Vbool)
                        return 1;
-               switch (require) {
-               case Vnolabel:
-                       return have != Vlabel;
-               case Vunknown:
+               if ((rules & Rnolabel) && have == Vlabel)
+                       return 0;
+               if (require == Vunknown || have == Vunknown)
                        return 1;
-               default:
-                       return have == Vunknown || require == have;
-               }
+
+               return require == have;
        }
 
 ###### value functions
@@ -477,7 +478,6 @@ to parse each type from a string.
                val->vtype = type;
                switch(type) {
                case Vnone:abort();
-               case Vnolabel:
                case Vunknown: break;
                case Vnum:
                        mpq_init(val->num); break;
@@ -500,7 +500,6 @@ to parse each type from a string.
                rv.vtype = v.vtype;
                switch (rv.vtype) {
                case Vnone:
-               case Vnolabel:
                case Vunknown: break;
                case Vlabel:
                        rv.label = v.label;
@@ -532,7 +531,6 @@ to parse each type from a string.
                case Vstr: cmp = text_cmp(left.str, right.str); break;
                case Vbool: cmp = left.bool - right.bool; break;
                case Vnone:
-               case Vnolabel:
                case Vunknown: cmp = 0;
                }
                return cmp;
@@ -554,7 +552,6 @@ to parse each type from a string.
                case Vunknown:
                        printf("*Unknown*"); break;
                case Vnone:
-               case Vnolabel:
                        printf("*no-value*"); break;
                case Vlabel:
                        printf("*label-%p*", v.label); break;
@@ -581,7 +578,6 @@ to parse each type from a string.
                char tail[3] = "";
 
                switch(vl->vtype) {
-               case Vnolabel:
                case Vlabel:
                case Vunknown:
                case Vnone:
@@ -1189,7 +1185,7 @@ As discussed, analysis involves propagating type requirements around
 the program and looking for errors.
 
 So `propagate_types` is passed an expected type (being a `vtype`
-together with a `bool_permitted` flag) that the `exec` is expected to
+together with some `val_rules` flags) that the `exec` is expected to
 return, and returns the type that it does return, either of which can
 be `Vunknown`.  An `ok` flag is passed by reference. It is set to `0`
 when an error is found, and `2` when any change is made.  If it
@@ -1198,7 +1194,7 @@ remains unchanged at `1`, then no more propagation is needed.
 ###### core functions
 
        static enum vtype propagate_types(struct exec *prog, struct parse_context *c, int *ok,
-                                         enum vtype type, int bool_permitted)
+                                         enum vtype type, int rules)
        {
                enum vtype t;
 
@@ -1341,9 +1337,9 @@ an executable.
                case Xval:
                {
                        struct val *val = cast(val, prog);
-                       if (!vtype_compat(type, val->val.vtype, bool_permitted)) {
-                               type_err(c, "error: expected %1 found %2",
-                                          prog, type, val->val.vtype);
+                       if (!vtype_compat(type, val->val.vtype, rules)) {
+                               type_err(c, "error: expected %1%r found %2",
+                                          prog, type, rules, val->val.vtype);
                                *ok = 0;
                        }
                        return val->val.vtype;
@@ -1417,9 +1413,9 @@ link to find the primary instance.
                        v = var_ref(config2context(config), $1.txt);
                        $0->var = v;
                        type_err(config2context(config), "error: variable '%v' redeclared",
-                                $0, Vnone, Vnone);
+                                $0, Vnone, 0, Vnone);
                        type_err(config2context(config), "info: this is where '%v' was first declared",
-                                v->where_decl, Vnone, Vnone);
+                                v->where_decl, Vnone, 0, Vnone);
                }
        } }$
            | IDENTIFIER ::= ${ {
@@ -1433,9 +1429,9 @@ link to find the primary instance.
                        v = var_ref(config2context(config), $1.txt);
                        $0->var = v;
                        type_err(config2context(config), "error: variable '%v' redeclared",
-                                $0, Vnone, Vnone);
+                                $0, Vnone, 0, Vnone);
                        type_err(config2context(config), "info: this is where '%v' was first declared",
-                                v->where_decl, Vnone, Vnone);
+                                v->where_decl, Vnone, 0, Vnone);
                }
        } }$
 
@@ -1484,28 +1480,28 @@ link to find the primary instance.
                struct var *var = cast(var, prog);
                struct variable *v = var->var;
                if (!v) {
-                       type_err(c, "%d:BUG: no variable!!", prog, Vnone, Vnone);
+                       type_err(c, "%d:BUG: no variable!!", prog, Vnone, 0, Vnone);
                        *ok = 0;
                        return Vnone;
                }
                if (v->merged)
                        v = v->merged;
                if (v->val.vtype == Vunknown) {
-                       if (type > Vunknown && *ok != 0) {
+                       if (type != Vunknown && *ok != 0) {
                                val_init(&v->val, type);
                                v->where_set = prog;
                                *ok = 2;
                        }
                        return type;
                }
-               if (!vtype_compat(type, v->val.vtype, bool_permitted)) {
-                       type_err(c, "error: expected %1 but variable '%v' is %2", prog,
-                                type, v->val.vtype);
+               if (!vtype_compat(type, v->val.vtype, rules)) {
+                       type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
+                                type, rules, v->val.vtype);
                        type_err(c, "info: this is where '%v' was set to %1", v->where_set,
-                                v->val.vtype, Vnone);
+                                v->val.vtype, rules, Vnone);
                        *ok = 0;
                }
-               if (type <= Vunknown)
+               if (type == Vunknown)
                        return v->val.vtype;
                return type;
        }
@@ -1597,9 +1593,9 @@ and `BFact`s.
                /* both must be Vbool, result is Vbool */
                propagate_types(b->left, c, ok, Vbool, 0);
                propagate_types(b->right, c, ok, Vbool, 0);
-               if (type != Vbool && type > Vunknown) {
+               if (type != Vbool && type != Vunknown) {
                        type_err(c, "error: %1 operation found where %2 expected", prog,
-                                  Vbool, type);
+                                  Vbool, 0, type);
                        *ok = 0;
                }
                return Vbool;
@@ -1699,17 +1695,17 @@ expression operator.
        case Eql:
        case NEql:
                /* Both must match but not labels, result is Vbool */
-               t = propagate_types(b->left, c, ok, Vnolabel, 0);
-               if (t > Vunknown)
+               t = propagate_types(b->left, c, ok, Vunknown, Rnolabel);
+               if (t != Vunknown)
                        propagate_types(b->right, c, ok, t, 0);
                else {
-                       t = propagate_types(b->right, c, ok, Vnolabel, 0);
-                       if (t > Vunknown)
+                       t = propagate_types(b->right, c, ok, Vunknown, Rnolabel);
+                       if (t != Vunknown)
                                t = propagate_types(b->left, c, ok, t, 0);
                }
                if (!vtype_compat(type, Vbool, 0)) {
                        type_err(c, "error: Comparison returns %1 but %2 expected", prog,
-                                   Vbool, type);
+                                   Vbool, rules, type);
                        *ok = 0;
                }
                return Vbool;
@@ -1852,7 +1848,7 @@ precedence is handled better I might be able to discard this.
                propagate_types(b->right, c, ok, Vnum, 0);
                if (!vtype_compat(type, Vnum, 0)) {
                        type_err(c, "error: Arithmetic returns %1 but %2 expected", prog,
-                                  Vnum, type);
+                                  Vnum, rules, type);
                        *ok = 0;
                }
                return Vnum;
@@ -1863,7 +1859,7 @@ precedence is handled better I might be able to discard this.
                propagate_types(b->right, c, ok, Vstr, 0);
                if (!vtype_compat(type, Vstr, 0)) {
                        type_err(c, "error: Concat returns %1 but %2 expected", prog,
-                                  Vstr, type);
+                                  Vstr, rules, type);
                        *ok = 0;
                }
                return Vstr;
@@ -2063,15 +2059,15 @@ list.
                struct binode *e;
 
                for (e = b; e; e = cast(binode, e->right)) {
-                       t = propagate_types(e->left, c, ok, Vunknown, bool_permitted);
-                       if (bool_permitted && t == Vbool)
+                       t = propagate_types(e->left, c, ok, Vunknown, rules);
+                       if ((rules & Rboolok) && t == Vbool)
                                t = Vunknown;
                        if (t != Vunknown && t != Vnone && t != Vbool) {
                                if (type == Vunknown)
                                        type = t;
                                else if (t != type) {
-                                       type_err(c, "error: expected %1, found %2",
-                                                e->left, type, t);
+                                       type_err(c, "error: expected %1%r, found %2",
+                                                e->left, type, rules, t);
                                        *ok = 0;
                                }
                        }
@@ -2156,8 +2152,8 @@ same solution.
 
        case Print:
                /* don't care but all must be consistent */
-               propagate_types(b->left, c, ok, Vnolabel, 0);
-               propagate_types(b->right, c, ok, Vnolabel, 0);
+               propagate_types(b->left, c, ok, Vunknown, Rnolabel);
+               propagate_types(b->right, c, ok, Vunknown, Rnolabel);
                break;
 
 ###### interp binode cases
@@ -2244,15 +2240,15 @@ it is declared, and error will be raised as the name is created as
        case Assign:
        case Declare:
                /* Both must match and not be labels, result is Vnone */
-               t = propagate_types(b->left, c, ok, Vnolabel, 0);
-               if (t > Vunknown) {
+               t = propagate_types(b->left, c, ok, Vunknown, Rnolabel);
+               if (t != Vunknown) {
                        if (propagate_types(b->right, c, ok, 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, Vnone);
+                                                cast(var, b->left)->var->where_set, t, rules, Vnone);
                } else {
-                       t = propagate_types(b->right, c, ok, Vnolabel, 0);
-                       if (t > Vunknown)
+                       t = propagate_types(b->right, c, ok, Vunknown, Rnolabel);
+                       if (t != Vunknown)
                                propagate_types(b->left, c, ok, t, 0);
                }
                return Vnone;
@@ -2371,7 +2367,7 @@ This is different both from the `ifpart` code block which is expected to
 return a Boolean, or the `switchpart` code block which is expected to
 return the same type as the casepart values.  The correct analysis of
 the type of the `whilepart` code block is the reason for the
-`bool_permitted` flag which is passed to `propagate_types()`.
+`Rboolok` flag which is passed to `propagate_types()`.
 
 The `cond_statement` cannot fit into a `binode` so a new `exec` is
 defined.
@@ -2714,29 +2710,29 @@ defined.
                             cp && (t == Vunknown); cp = cp->next)
                                t = propagate_types(cp->value, c, ok, Vunknown, 0);
                        if (t == Vunknown && cs->condpart)
-                               t = propagate_types(cs->condpart, c, ok, Vunknown, 1);
+                               t = propagate_types(cs->condpart, c, ok, Vunknown, Rboolok);
                        // Now we have a type (I hope) push it down
                        if (t != Vunknown) {
                                for (cp = cs->casepart; cp; cp = cp->next)
                                        propagate_types(cp->value, c, ok, t, 0);
-                               propagate_types(cs->condpart, c, ok, t, 1);
+                               propagate_types(cs->condpart, c, ok, t, Rboolok);
                        }
                }
                // (if)then, else, and case parts must return expected type.
                if (!cs->dopart && type == Vunknown)
-                       type = propagate_types(cs->thenpart, c, ok, Vunknown, bool_permitted);
+                       type = propagate_types(cs->thenpart, c, ok, Vunknown, rules);
                if (type == Vunknown)
-                       type = propagate_types(cs->elsepart, c, ok, Vunknown, bool_permitted);
+                       type = propagate_types(cs->elsepart, c, ok, Vunknown, rules);
                for (cp = cs->casepart;
                     cp && type == Vunknown;
                     cp = cp->next)
-                       type = propagate_types(cp->action, c, ok, Vunknown, bool_permitted);
-               if (type > Vunknown) {
+                       type = propagate_types(cp->action, c, ok, Vunknown, rules);
+               if (type != Vunknown) {
                        if (!cs->dopart)
-                               propagate_types(cs->thenpart, c, ok, type, bool_permitted);
-                       propagate_types(cs->elsepart, c, ok, type, bool_permitted);
+                               propagate_types(cs->thenpart, c, ok, type, rules);
+                       propagate_types(cs->elsepart, c, ok, type, rules);
                        for (cp = cs->casepart; cp ; cp = cp->next)
-                               propagate_types(cp->action, c, ok, type, bool_permitted);
+                               propagate_types(cp->action, c, ok, type, rules);
                        return type;
                } else
                        return Vunknown;