X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=blobdiff_plain;f=csrc%2Foceani.mdc;h=9720d222fac37ffced3f0494c446e3af2203eb19;hp=725719e2558a19c5f1c2f5c4456b97c002a20c4f;hb=e4967da39aff091cd9dfa187cf77c84ba8643293;hpb=272629ad8689864feba7ae632e838c37c81b6f9f diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 725719e..9720d22 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -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': @@ -1873,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 @@ -2074,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; @@ -2136,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; @@ -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; + 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); @@ -3149,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; } @@ -4920,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 = $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; @@ -4942,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; } } }