]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: allow global constants to be used before declared.
[ocean] / csrc / oceani.mdc
index d40cf9a42f5335a3f30ebf263fb8c82ab9c37d01..9720d222fac37ffced3f0494c446e3af2203eb19 100644 (file)
@@ -246,7 +246,7 @@ structures can be used.
                prepare_types(&context);
                if (!context.parse_error && !analyse_funcs(&context)) {
                        fprintf(stderr, "oceani: type error in program - not running.\n");
-                       context.parse_error = 1;
+                       context.parse_error += 1;
                }
 
                if (doprint) {
@@ -395,14 +395,14 @@ context so indicate that parsing failed.
                        }
                }
                fputs("\n", stderr);
-               c->parse_error = 1;
+               c->parse_error += 1;
        }
 
        static void tok_err(struct parse_context *c, char *fmt, struct token *t)
        {
                fprintf(stderr, "%s:%d:%d: %s: %.*s\n", c->file_name, t->line, t->col, fmt,
                        t->txt.len, t->txt.txt);
-               c->parse_error = 1;
+               c->parse_error += 1;
        }
 
 ## Entities: declared and predeclared.
@@ -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
-`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};
-       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':
@@ -630,9 +632,10 @@ 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)
        {
+               int pre_err = c->parse_error;
                struct type *ret = __propagate_types(prog, c, perr, type, rules);
 
-               if (c->parse_error)
+               if (c->parse_error > pre_err)
                        *perr |= Efail;
                return ret;
        }
@@ -1872,7 +1875,7 @@ tell if it was set or not later.
        {
                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
@@ -2073,7 +2076,11 @@ correctly.
                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;
@@ -2135,14 +2142,14 @@ correctly.
                                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);
                }
+               if (!v->global || v->frame_pos < 0)
+                       *perr |= Enoconst;
                if (!type)
                        return v->type;
                return type;
@@ -2253,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;
+               if (parse_time && type->array.vsize && !type->array.vsize->global)
+                       return;
 
                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);
@@ -2619,7 +2628,7 @@ function will be needed.
                                propagate_types(f->init, c, &perr, f->f.type, 0);
                        } while (perr & Eretry);
                        if (perr & Efail)
-                               c->parse_error = 1;     // NOTEST
+                               c->parse_error += 1;    // NOTEST
                }
 
                t->structure.nfields = cnt;
@@ -3148,6 +3157,7 @@ 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);
                return v->var->type->function.return_type;
        }
@@ -4919,9 +4929,17 @@ constants.
                        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;
 
@@ -4941,23 +4959,46 @@ constants.
        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);
-               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;
                        }
                }
        }
@@ -5190,7 +5231,7 @@ is a bit more interesting at this level.
                                propagate_types(b->left, c, &perr, Tnone, 0);   // NOTEST
                        }
                        if (perr & Efail)
-                               c->parse_error = 1;
+                               c->parse_error += 1;
                }
 
                return !c->parse_error;
@@ -5211,12 +5252,12 @@ is a bit more interesting at this level.
                        progp = var_value(c, mainv);
                if (!progp || !progp->function) {
                        fprintf(stderr, "oceani: no main function found.\n");
-                       c->parse_error = 1;
+                       c->parse_error += 1;
                        return;
                }
                if (!analyse_main(mainv->type, c)) {
                        fprintf(stderr, "oceani: main has wrong type.\n");
-                       c->parse_error = 1;
+                       c->parse_error += 1;
                        return;
                }
                al = mainv->type->function.params;