]> ocean-lang.org Git - ocean/commitdiff
oceani: change labels to look like enum values, not variables.
authorNeilBrown <neil@brown.name>
Mon, 13 Dec 2021 22:34:25 +0000 (09:34 +1100)
committerNeilBrown <neil@brown.name>
Mon, 13 Dec 2021 22:34:25 +0000 (09:34 +1100)
A label now looks like ".foo".  This makes it a completely separate
namespace from variables.

When we introduce enums, the values will also look like ".foo" an we
know which enum is intended based on context.
Each switch/while will potentially create a local enum type for the
labels.

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

index 655a2c95057a3cc686ddac87003acc10bbb88e91..2ac2f56d620a67ce6883cb3518a7a022298e64e9 100644 (file)
@@ -382,19 +382,19 @@ Here I break it into two parts, keeping the array code separate.
                while
                        mid := (lo + hi) / 2
                        if mid == target:
-                               use Found
+                               use .Found
                        if mid < target:
                                lo = mid
                        else
                                hi = mid
                        if hi - lo < 1:
                                lo = mid
-                               use GiveUp
+                               use .GiveUp
                        use True
                do pass
-               case Found:
+               case .Found:
                        print "Yay, I found", target
-               case GiveUp:
+               case .GiveUp:
                        print "Closest I found was", lo
 
 ###### output: sayhello,55,33,hello,True
@@ -874,6 +874,7 @@ various places that `type_err()` are called.
                b = b + 1
 
                if 3 * 4 and not True: print "Weird"
+               d:number = .fred
 
 ###### output: type_err1
        .tmp.code:3:25: error: expected string found number
@@ -883,6 +884,8 @@ various places that `type_err()` are called.
        .tmp.code:6:8: error: Cannot assign to a constant: b
        .tmp.code:5:8: info: name was defined as a constant here
        .tmp.code:8:11: error: Arithmetic returns number but Boolean expected
+       .tmp.code:9:20: error: expected number found label
+       .tmp.code:9:8: info: variable 'd' was set as number here.
        oceani: type error in program - not running.
 
 ###### test: type_err2
index 1e2bfde472dc7ac727cb7ee2ab14137c6c8794e5..e147baa1303ed29643c8f4b43c0c5c0bebd04fb8 100644 (file)
@@ -1092,7 +1092,7 @@ A separate function encoding these cases will simplify some code later.
        struct text str;
        mpq_t num;
        unsigned char bool;
-       void *label;
+       int label;
 
 ###### ast functions
        static void _free_value(struct type *type, struct value *v)
@@ -1125,8 +1125,8 @@ A separate function encoding these cases will simplify some code later.
                        val->bool = 0;
                        break;
                case Vlabel:
-                       val->label = NULL;
-                       break;
+                       val->label = 0; // NOTEST
+                       break;          // NOTEST
                }
        }
 
@@ -1137,8 +1137,8 @@ A separate function encoding these cases will simplify some code later.
                case Vnone:             // NOTEST
                        break;          // NOTEST
                case Vlabel:
-                       vnew->label = vold->label;
-                       break;
+                       vnew->label = vold->label;      // NOTEST
+                       break;          // NOTEST
                case Vbool:
                        vnew->bool = vold->bool;
                        break;
@@ -1176,7 +1176,7 @@ A separate function encoding these cases will simplify some code later.
                case Vnone:                             // NOTEST
                        fprintf(f, "*no-value*"); break;        // NOTEST
                case Vlabel:                            // NOTEST
-                       fprintf(f, "*label-%p*", v->label); break; // NOTEST
+                       fprintf(f, "*label-%d*", v->label); break; // NOTEST
                case Vstr:
                        fprintf(f, "%.*s", v->str.len, v->str.txt); break;
                case Vbool:
@@ -1261,10 +1261,11 @@ executable.
                return v;
        }
 
-###### Grammar
-
+###### declare terminals
        $TERM True False
 
+###### Grammar
+
        $*val
        Value ->  True ${
                $0 = new_val(Tbool, $1);
@@ -1361,6 +1362,98 @@ executable.
                return rv;
        }
 
+#### Labels
+
+Labels are a temporary concept until I implement enums.  There are an
+anonymous enum which is declared by usage.  Thet are only allowed in
+`use` statements and corresponding `case` entries.  They appear as a
+period followed by an identifier.  All identifiers that are "used" must
+have a "case".
+
+For now, we have a global list of labels, and don't check that all "use"
+match "case".
+
+###### exec type
+       Xlabel,
+
+###### ast
+       struct label {
+               struct exec;
+               struct text name;
+               int value;
+       };
+###### free exec cases
+       case Xlabel:
+               free(e);
+               break;
+###### print exec cases
+       case Xlabel: {
+               struct label *l = cast(label, e);
+               printf(".%.*s", l->name.len, l->name.txt);
+               break;
+       }
+
+###### ast
+       struct labels {
+               struct labels *next;
+               struct text name;
+               int value;
+       };
+###### parse context
+       struct labels *labels;
+       int next_label;
+###### ast functions
+       static int label_lookup(struct parse_context *c, struct text name)
+       {
+               struct labels *l, **lp = &c->labels;
+               while (*lp && text_cmp((*lp)->name, name) < 0)
+                       lp = &(*lp)->next;
+               if (*lp && text_cmp((*lp)->name, name) == 0)
+                       return (*lp)->value;
+               l = calloc(1, sizeof(*l));
+               l->next = *lp;
+               l->name = name;
+               if (c->next_label == 0)
+                       c->next_label = 2;
+               l->value = c->next_label;
+               c->next_label += 1;
+               *lp = l;
+               return l->value;
+       }
+
+###### free context storage
+       while (context.labels) {
+               struct labels *l = context.labels;
+               context.labels = l->next;
+               free(l);
+       }
+
+###### declare terminals
+       $TERM .
+###### term grammar
+       | . IDENTIFIER ${ {
+               struct label *l = new_pos(label, $ID);
+               l->name = $ID.txt;
+               $0 = l;
+       } }$
+###### propagate exec cases
+       case Xlabel: {
+               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",
+                                prog, type, rules, Tlabel);
+               return Tlabel;
+       }
+###### interp exec cases
+       case Xlabel : {
+               struct label *l = cast(label, e);
+               rv.label = l->value;
+               rvtype = Tlabel;
+               break;
+       }
+
+
 ### Variables
 
 Variables are scoped named values.  We store the names in a linked list
@@ -1838,9 +1931,6 @@ all pending-scope variables become conditionally scoped.
                                                 v->previous->scope == PendingScope)
                                                /* all previous branches used name */
                                                v->scope = PendingScope;
-                                       else if (v->type == Tlabel)
-                                               /* Labels remain pending even when not used */
-                                               v->scope = PendingScope;        // UNTESTED
                                        else
                                                v->scope = OutScope;
                                        if (ct == CloseElse) {
@@ -1871,8 +1961,6 @@ all pending-scope variables become conditionally scoped.
                                        v->scope = InScope;
                                /* fallthrough */
                        case CloseSequential:
-                               if (v->type == Tlabel)
-                                       v->scope = PendingScope;
                                switch (v->scope) {
                                case InScope:
                                        v->scope = OutScope;
@@ -1886,10 +1974,7 @@ all pending-scope variables become conditionally scoped.
                                        for (v2 = v;
                                             v2 && v2->scope == PendingScope;
                                             v2 = v2->previous)
-                                               if (v2->type == Tlabel)
-                                                       v2->scope = CondScope;
-                                               else
-                                                       v2->scope = OutScope;
+                                               v2->scope = OutScope;
                                        break;
                                case CondScope:
                                case OutScope: break;
@@ -1976,7 +2061,7 @@ tell if it was set or not later.
                if (init)
                        memcpy(ret, init, t->size);
                else
-                       val_init(t, ret);
+                       val_init(t, ret);       // NOTEST
                return ret;
        }
 
@@ -2784,7 +2869,7 @@ function will be needed.
                break;
 
 ###### declare terminals
-       $TERM struct .
+       $TERM struct
 
 ###### term grammar
 
@@ -4617,9 +4702,9 @@ An assignment will assign a value to a variable, providing it hasn't
 been declared as a constant.  The analysis phase ensures that the type
 will be correct so the interpreter just needs to perform the
 calculation.  There is a form of assignment which declares a new
-variable as well as assigning a value.  If a name is assigned before
-it is declared, and error will be raised as the name is created as
-`Tlabel` and it is illegal to assign to such names.
+variable as well as assigning a value.  If a name is used before
+it is declared, it is assumed to be a global constant which are allowed to
+be declared at any time.
 
 ###### Binode types
        Assign,
@@ -4767,17 +4852,6 @@ function which has a return type, and the "condition" code blocks in
                $0 = b = new_pos(binode, $1);
                b->op = Use;
                b->right = $<2;
-               if (b->right->type == Xvar) {
-                       struct var *v = cast(var, b->right);
-                       if (v->var->type == Tnone) {
-                               /* Convert this to a label */
-                               struct value *val;
-
-                               v->var->type = Tlabel;
-                               val = global_alloc(c, Tlabel, v->var, NULL);
-                               val->label = val;
-                       }
-               }
        }$
 
 ###### print binode cases
@@ -5869,19 +5943,19 @@ things which will likely grow as the languages grows.
                while
                        mid := (lo + hi) / 2
                        if mid == target:
-                               use Found
+                               use .Found
                        if mid < target:
                                lo = mid
                        else
                                hi = mid
                        if hi - lo < 1:
                                lo = mid
-                               use GiveUp
+                               use .GiveUp
                        use True
                do pass
-               case Found:
+               case .Found:
                        print "Yay, I found", target
-               case GiveUp:
+               case .GiveUp:
                        print "Closest I found was", lo
 
                size::= 10