]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: allow global constants to be used before declared.
[ocean] / csrc / oceani.mdc
index 725719e2558a19c5f1c2f5c4456b97c002a20c4f..9720d222fac37ffced3f0494c446e3af2203eb19 100644 (file)
@@ -586,13 +586,15 @@ pointer 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 `NULL` signifying "unknown".  A `prop_err` flag set is
 passed by reference.  It has `Efail` set when an error is found, and
 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 it
-remains unchanged at `0`, then no more propagation is needed.
+`Eretry` when the type for some element is set via propagation.  If
+any expression cannot be evaluated immediately, `Enoconst` is set.
+
+If it remains unchanged at `0`, then no more propagation is needed.
 
 ###### ast
 
        enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
 
 ###### ast
 
        enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2};
-       enum prop_err {Efail = 1<<0, Eretry = 1<<1};
+       enum prop_err {Efail = 1<<0, Eretry = 1<<1, Enoconst = 1<<2};
 
 ###### format cases
        case 'r':
 
 ###### format cases
        case 'r':
@@ -1873,7 +1875,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;
+                               return NULL;    // UNTESTED
                        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
@@ -2074,7 +2076,11 @@ correctly.
                struct variable *v = var_ref(c, $1.txt);
                $0 = new_pos(var, $1);
                if (v == NULL) {
                struct variable *v = var_ref(c, $1.txt);
                $0 = new_pos(var, $1);
                if (v == NULL) {
-                       /* This might be a label - allocate a var just in case */
+                       /* This might be a global const or a label
+                        * Allocate a var with impossible type Tnone,
+                        * which will be adjusted when we find out what it is,
+                        * or will trigger an error.
+                        */
                        v = var_decl(c, $1.txt);
                        if (v) {
                                v->type = Tnone;
                        v = var_decl(c, $1.txt);
                        if (v) {
                                v->type = Tnone;
@@ -2136,14 +2142,14 @@ correctly.
                                v->where_set = prog;
                                *perr |= Eretry;
                        }
                                v->where_set = prog;
                                *perr |= Eretry;
                        }
-                       return type;
-               }
-               if (!type_compat(type, v->type, rules)) {
+               } else if (!type_compat(type, v->type, rules)) {
                        type_err(c, "error: expected %1%r 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);
                }
                        type_err(c, "error: expected %1%r 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;
                if (!type)
                        return v->type;
                return type;
                if (!type)
                        return v->type;
                return type;
@@ -2254,11 +2260,13 @@ with a const size by whether they are prepared at parse time or not.
                        return;
                if (type->array.unspec && parse_time)
                        return;
                        return;
                if (type->array.unspec && parse_time)
                        return;
+               if (parse_time && type->array.vsize && !type->array.vsize->global)
+                       return;
 
                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;
+                               return; // UNTESTED
                        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);
@@ -3149,6 +3157,7 @@ it in the "SimpleStatement Grammar" which will be described later.
                                 prog, NULL, 0, NULL);
                        return NULL;
                }
                                 prog, NULL, 0, NULL);
                        return NULL;
                }
+               *perr |= Enoconst;
                v->var->type->check_args(c, perr, v->var->type, args);
                return v->var->type->function.return_type;
        }
                v->var->type->check_args(c, perr, v->var->type, args);
                return v->var->type->function.return_type;
        }
@@ -4920,9 +4929,17 @@ constants.
                        v->global = 1;
                } else {
                        v = var_ref(c, $1.txt);
                        v->global = 1;
                } else {
                        v = var_ref(c, $1.txt);
-                       tok_err(c, "error: name already declared", &$1);
-                       type_err(c, "info: this is where '%v' was first declared",
-                                v->where_decl, NULL, 0, NULL);
+                       if (v->type == Tnone) {
+                               v->where_decl = var;
+                               v->where_set = var;
+                               v->type = $<CT;
+                               v->constant = 1;
+                               v->global = 1;
+                       } else {
+                               tok_err(c, "error: name already declared", &$1);
+                               type_err(c, "info: this is where '%v' was first declared",
+                                        v->where_decl, NULL, 0, NULL);
+                       }
                }
                var->var = v;
 
                }
                var->var = v;
 
@@ -4942,23 +4959,46 @@ constants.
        static void resolve_consts(struct parse_context *c)
        {
                struct binode *b;
        static void resolve_consts(struct parse_context *c)
        {
                struct binode *b;
+               int retry = 1;
+               enum { none, some, cannot } progress = none;
+
                c->constlist = reorder_bilist(c->constlist);
                c->constlist = reorder_bilist(c->constlist);
-               for (b = cast(binode, c->constlist); b;
-                    b = cast(binode, b->right)) {
-                       enum prop_err perr;
-                       struct binode *vb = cast(binode, b->left);
-                       struct var *v = cast(var, vb->left);
-                       do {
-                               perr = 0;
-                               propagate_types(vb->right, c, &perr,
-                                               v->var->type, 0);
-                       } while (perr & Eretry);
-                       if (perr & Efail)
-                               c->parse_error += 1;
-                       else {
-                               struct value res = interp_exec(
-                                       c, vb->right, &v->var->type);
-                               global_alloc(c, v->var->type, v->var, &res);
+               while (retry) {
+                       retry = 0;
+                       for (b = cast(binode, c->constlist); b;
+                            b = cast(binode, b->right)) {
+                               enum prop_err perr;
+                               struct binode *vb = cast(binode, b->left);
+                               struct var *v = cast(var, vb->left);
+                               if (v->var->frame_pos >= 0)
+                                       continue;
+                               do {
+                                       perr = 0;
+                                       propagate_types(vb->right, c, &perr,
+                                                       v->var->type, 0);
+                               } while (perr & Eretry);
+                               if (perr & Efail)
+                                       c->parse_error += 1;
+                               else if (!(perr & Enoconst)) {
+                                       progress = some;
+                                       struct value res = interp_exec(
+                                               c, vb->right, &v->var->type);
+                                       global_alloc(c, v->var->type, v->var, &res);
+                               } else {
+                                       if (progress == cannot)
+                                               type_err(c, "error: const %v cannot be resolved.",
+                                                        v, NULL, 0, NULL);
+                                       else
+                                               retry = 1;
+                               }
+                       }
+                       switch (progress) {
+                       case cannot:
+                               retry = 0; break;
+                       case none:
+                               progress = cannot; break;
+                       case some:
+                               progress = none; break;
                        }
                }
        }
                        }
                }
        }