From 84994383b2207e0f67662ed1bf75c7f5d10767b5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 5 Dec 2021 09:13:51 +1100 Subject: [PATCH] oceani: change the 'ok' flag to 'perr' with well defined bits. I'll want to extend the information gathered by propagate_types() to report if a value can be computed immediately. So generalize 'ok' (which contains a magic value) to a set of flags that can be reported. Signed-off-by: NeilBrown --- csrc/oceani.mdc | 171 ++++++++++++++++++++++++------------------------ 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 180c36f..d40cf9a 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -583,15 +583,16 @@ program and looking for errors. So `propagate_types` is passed an expected type (being a `struct type` 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". 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 remains unchanged at `1`, then no more -propagation is needed. +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. ###### ast enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 1<<2}; + enum prop_err {Efail = 1<<0, Eretry = 1<<1}; ###### format cases case 'r': @@ -600,11 +601,11 @@ propagation is needed. break; ###### forward decls - static struct type *propagate_types(struct exec *prog, struct parse_context *c, int *ok, + static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, struct type *type, int rules); ###### core functions - static struct type *__propagate_types(struct exec *prog, struct parse_context *c, int *ok, + static struct type *__propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, struct type *type, int rules) { struct type *t; @@ -626,13 +627,13 @@ propagation is needed. return Tnone; } - static struct type *propagate_types(struct exec *prog, struct parse_context *c, int *ok, + static struct type *propagate_types(struct exec *prog, struct parse_context *c, enum prop_err *perr, struct type *type, int rules) { - struct type *ret = __propagate_types(prog, c, ok, type, rules); + struct type *ret = __propagate_types(prog, c, perr, type, rules); if (c->parse_error) - *ok = 0; + *perr |= Efail; return ret; } @@ -2129,10 +2130,10 @@ correctly. type_err(c, "error: variable used but not declared: %v", prog, NULL, 0, NULL); if (v->type == NULL) { - if (type && *ok != 0) { + if (type && !(*perr & Efail)) { v->type = type; v->where_set = prog; - *ok = 2; + *perr |= Eretry; } return type; } @@ -2445,8 +2446,8 @@ with a const size by whether they are prepared at parse time or not. /* left must be an array, right must be a number, * result is the member type of the array */ - propagate_types(b->right, c, ok, Tnum, 0); - t = propagate_types(b->left, c, ok, NULL, rules & Rnoconstant); + propagate_types(b->right, c, perr, Tnum, 0); + t = propagate_types(b->left, c, perr, NULL, rules & Rnoconstant); if (!t || t->compat != array_compat) { type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL); return NULL; @@ -2606,7 +2607,7 @@ function will be needed. return; for (f = t->structure.field_list; f; f=f->prev) { - int ok; + enum prop_err perr; cnt += 1; if (f->f.type->prepare_type) @@ -2614,10 +2615,10 @@ function will be needed. if (f->init == NULL) continue; do { - ok = 1; - propagate_types(f->init, c, &ok, f->f.type, 0); - } while (ok == 2); - if (!ok) + perr = 0; + propagate_types(f->init, c, &perr, f->f.type, 0); + } while (perr & Eretry); + if (perr & Efail) c->parse_error = 1; // NOTEST } @@ -2708,7 +2709,7 @@ function will be needed. case Xfieldref: { struct fieldref *f = cast(fieldref, prog); - struct type *st = propagate_types(f->left, c, ok, NULL, 0); + struct type *st = propagate_types(f->left, c, perr, NULL, 0); if (!st) type_err(c, "error: unknown type for field access", f->left, // UNTESTED @@ -2914,7 +2915,7 @@ further detailed when Expression Lists are introduced. struct exec *function; ###### type functions - void (*check_args)(struct parse_context *c, int *ok, + void (*check_args)(struct parse_context *c, enum prop_err *perr, struct type *require, struct exec *args); ###### value functions @@ -2931,7 +2932,7 @@ further detailed when Expression Lists are introduced. return 0; } - static void function_check_args(struct parse_context *c, int *ok, + static void function_check_args(struct parse_context *c, enum prop_err *perr, struct type *require, struct exec *args) { /* This should be 'compat', but we don't have a 'tuple' type to @@ -2947,8 +2948,8 @@ further detailed when Expression Lists are introduced. args, NULL, 0, NULL); break; } - *ok = 1; - propagate_types(arg->left, c, ok, pv->var->type, 0); + *perr = 0; + propagate_types(arg->left, c, perr, pv->var->type, 0); param = cast(binode, param->right); arg = cast(binode, arg->right); } @@ -3147,7 +3148,7 @@ it in the "SimpleStatement Grammar" which will be described later. prog, NULL, 0, NULL); return NULL; } - v->var->type->check_args(c, ok, v->var->type, args); + v->var->type->check_args(c, perr, v->var->type, args); return v->var->type->function.return_type; } @@ -3260,9 +3261,9 @@ there. struct binode *b2 = cast(binode, b->right); struct type *t2; - propagate_types(b->left, c, ok, Tbool, 0); - t = propagate_types(b2->left, c, ok, type, Rnolabel); - t2 = propagate_types(b2->right, c, ok, type ?: t, Rnolabel); + propagate_types(b->left, c, perr, Tbool, 0); + t = propagate_types(b2->left, c, perr, type, Rnolabel); + t2 = propagate_types(b2->right, c, perr, type ?: t, Rnolabel); return t ?: t2; } @@ -3429,8 +3430,8 @@ evaluate the second expression if not necessary. case OrElse: case Not: /* both must be Tbool, result is Tbool */ - propagate_types(b->left, c, ok, Tbool, 0); - propagate_types(b->right, c, ok, Tbool, 0); + propagate_types(b->left, c, perr, Tbool, 0); + propagate_types(b->right, c, perr, Tbool, 0); if (type && type != Tbool) type_err(c, "error: %1 operation found where %2 expected", prog, Tbool, 0, type); @@ -3544,13 +3545,13 @@ expression operator, and the `CMPop` non-terminal will match one of them. case Eql: case NEql: /* Both must match but not be labels, result is Tbool */ - t = propagate_types(b->left, c, ok, NULL, Rnolabel); + t = propagate_types(b->left, c, perr, NULL, Rnolabel); if (t) - propagate_types(b->right, c, ok, t, 0); + propagate_types(b->right, c, perr, t, 0); else { - t = propagate_types(b->right, c, ok, NULL, Rnolabel); // UNTESTED + t = propagate_types(b->right, c, perr, NULL, Rnolabel); // UNTESTED if (t) // UNTESTED - t = propagate_types(b->left, c, ok, t, 0); // UNTESTED + t = propagate_types(b->left, c, perr, t, 0); // UNTESTED } if (!type_compat(type, Tbool, 0)) type_err(c, "error: Comparison returns %1 but %2 expected", prog, @@ -3714,8 +3715,8 @@ parentheses around an expression converts it into a Term, case Negate: /* as propagate_types ignores a NULL, * unary ops fit here too */ - propagate_types(b->left, c, ok, Tnum, 0); - propagate_types(b->right, c, ok, Tnum, 0); + propagate_types(b->left, c, perr, Tnum, 0); + propagate_types(b->right, c, perr, Tnum, 0); if (!type_compat(type, Tnum, 0)) type_err(c, "error: Arithmetic returns %1 but %2 expected", prog, Tnum, rules, type); @@ -3723,8 +3724,8 @@ parentheses around an expression converts it into a Term, case Concat: /* both must be Tstr, result is Tstr */ - propagate_types(b->left, c, ok, Tstr, 0); - propagate_types(b->right, c, ok, Tstr, 0); + propagate_types(b->left, c, perr, Tstr, 0); + propagate_types(b->right, c, perr, Tstr, 0); if (!type_compat(type, Tstr, 0)) type_err(c, "error: Concat returns %1 but %2 expected", prog, Tstr, rules, type); @@ -3732,7 +3733,7 @@ parentheses around an expression converts it into a Term, case StringConv: /* op must be string, result is number */ - propagate_types(b->left, c, ok, Tstr, 0); + propagate_types(b->left, c, perr, Tstr, 0); if (!type_compat(type, Tnum, 0)) type_err(c, // UNTESTED "error: Can only convert string to number, not %1", @@ -3740,7 +3741,7 @@ parentheses around an expression converts it into a Term, return Tnum; case Bracket: - return propagate_types(b->right, c, ok, type, 0); + return propagate_types(b->right, c, perr, type, 0); ###### interp binode cases @@ -4007,7 +4008,7 @@ the common header for all reductions to use. struct binode *e; for (e = b; e; e = cast(binode, e->right)) { - t = propagate_types(e->left, c, ok, NULL, rules); + t = propagate_types(e->left, c, perr, NULL, rules); if ((rules & Rboolok) && (t == Tbool || t == Tnone)) t = NULL; if (t == Tnone && e->right) @@ -4096,7 +4097,7 @@ printed. else b = cast(binode, b->right); while (b) { - propagate_types(b->left, c, ok, NULL, Rnolabel); + propagate_types(b->left, c, perr, NULL, Rnolabel); b = cast(binode, b->right); } break; @@ -4213,20 +4214,20 @@ it is declared, and error will be raised as the name is created as * For Assign, left must not be constant. * result is Tnone */ - t = propagate_types(b->left, c, ok, NULL, + t = propagate_types(b->left, c, perr, NULL, Rnolabel | (b->op == Assign ? Rnoconstant : 0)); if (!b->right) return Tnone; if (t) { - if (propagate_types(b->right, c, ok, t, 0) != t) + if (propagate_types(b->right, c, perr, 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, rules, NULL); } else { - t = propagate_types(b->right, c, ok, NULL, Rnolabel); + t = propagate_types(b->right, c, perr, NULL, Rnolabel); if (t) - propagate_types(b->left, c, ok, t, + propagate_types(b->left, c, perr, t, (b->op == Assign ? Rnoconstant : 0)); } if (t && t->dup == NULL && t->name.txt[0] != ' ') // HACK @@ -4303,7 +4304,7 @@ function which has a return type, and the "condition" code blocks in case Use: /* result matches value */ - return propagate_types(b->right, c, ok, type, 0); + return propagate_types(b->right, c, perr, type, 0); ###### interp binode cases @@ -4690,10 +4691,10 @@ casepart` to track a list of case parts. ###### propagate binode cases case Loop: - t = propagate_types(b->right, c, ok, Tnone, 0); + t = propagate_types(b->right, c, perr, Tnone, 0); if (!type_compat(Tnone, t, 0)) - *ok = 0; // UNTESTED - return propagate_types(b->left, c, ok, type, rules); + *perr |= Efail; // UNTESTED + return propagate_types(b->left, c, perr, type, rules); ###### propagate exec cases case Xcond_statement: @@ -4711,51 +4712,51 @@ casepart` to track a list of case parts. struct cond_statement *cs = cast(cond_statement, prog); struct casepart *cp; - t = propagate_types(cs->forpart, c, ok, Tnone, 0); + t = propagate_types(cs->forpart, c, perr, Tnone, 0); if (!type_compat(Tnone, t, 0)) - *ok = 0; // UNTESTED + *perr |= Efail; // UNTESTED if (cs->looppart) { - t = propagate_types(cs->thenpart, c, ok, Tnone, 0); + t = propagate_types(cs->thenpart, c, perr, Tnone, 0); if (!type_compat(Tnone, t, 0)) - *ok = 0; // UNTESTED + *perr |= Efail; // UNTESTED } if (cs->casepart == NULL) { - propagate_types(cs->condpart, c, ok, Tbool, 0); - propagate_types(cs->looppart, c, ok, Tbool, 0); + propagate_types(cs->condpart, c, perr, Tbool, 0); + propagate_types(cs->looppart, c, perr, Tbool, 0); } else { /* Condpart must match case values, with bool permitted */ t = NULL; for (cp = cs->casepart; cp && !t; cp = cp->next) - t = propagate_types(cp->value, c, ok, NULL, 0); + t = propagate_types(cp->value, c, perr, NULL, 0); if (!t && cs->condpart) - t = propagate_types(cs->condpart, c, ok, NULL, Rboolok); // UNTESTED + t = propagate_types(cs->condpart, c, perr, NULL, Rboolok); // UNTESTED if (!t && cs->looppart) - t = propagate_types(cs->looppart, c, ok, NULL, Rboolok); // UNTESTED + t = propagate_types(cs->looppart, c, perr, NULL, Rboolok); // UNTESTED // Now we have a type (I hope) push it down if (t) { for (cp = cs->casepart; cp; cp = cp->next) - propagate_types(cp->value, c, ok, t, 0); - propagate_types(cs->condpart, c, ok, t, Rboolok); - propagate_types(cs->looppart, c, ok, t, Rboolok); + propagate_types(cp->value, c, perr, t, 0); + propagate_types(cs->condpart, c, perr, t, Rboolok); + propagate_types(cs->looppart, c, perr, t, Rboolok); } } // (if)then, else, and case parts must return expected type. if (!cs->looppart && !type) - type = propagate_types(cs->thenpart, c, ok, NULL, rules); + type = propagate_types(cs->thenpart, c, perr, NULL, rules); if (!type) - type = propagate_types(cs->elsepart, c, ok, NULL, rules); + type = propagate_types(cs->elsepart, c, perr, NULL, rules); for (cp = cs->casepart; cp && !type; cp = cp->next) // UNTESTED - type = propagate_types(cp->action, c, ok, NULL, rules); // UNTESTED + type = propagate_types(cp->action, c, perr, NULL, rules); // UNTESTED if (type) { if (!cs->looppart) - propagate_types(cs->thenpart, c, ok, type, rules); - propagate_types(cs->elsepart, c, ok, type, rules); + propagate_types(cs->thenpart, c, perr, type, rules); + propagate_types(cs->elsepart, c, perr, type, rules); for (cp = cs->casepart; cp ; cp = cp->next) - propagate_types(cp->action, c, ok, type, rules); + propagate_types(cp->action, c, perr, type, rules); return type; } else return NULL; @@ -4943,15 +4944,15 @@ constants. c->constlist = reorder_bilist(c->constlist); for (b = cast(binode, c->constlist); b; b = cast(binode, b->right)) { - int ok; + enum prop_err perr; struct binode *vb = cast(binode, b->left); struct var *v = cast(var, vb->left); do { - ok = 1; - propagate_types(vb->right, c, &ok, + perr = 0; + propagate_types(vb->right, c, &perr, v->var->type, 0); - } while (ok == 2); - if (!ok) + } while (perr & Eretry); + if (perr & Efail) c->parse_error = 1; else { struct value res = interp_exec( @@ -5141,20 +5142,20 @@ is a bit more interesting at this level. for (v = c->in_scope; v; v = v->in_scope) { struct value *val; struct type *ret; - int ok = 1; + enum prop_err perr; if (v->depth != 0 || !v->type || !v->type->check_args) continue; ret = v->type->function.inline_result ? Tnone : v->type->function.return_type; val = var_value(c, v); do { - ok = 1; - propagate_types(val->function, c, &ok, ret, 0); - } while (ok == 2); - if (ok) + perr = 0; + propagate_types(val->function, c, &perr, ret, 0); + } while (!(perr & Efail) && (perr & Eretry)); + if (!(perr & Efail)) /* Make sure everything is still consistent */ - propagate_types(val->function, c, &ok, ret, 0); - if (!ok) + propagate_types(val->function, c, &perr, ret, 0); + if (perr & Efail) all_ok = 0; if (!v->type->function.inline_result && !v->type->function.return_type->dup) { @@ -5171,7 +5172,7 @@ is a bit more interesting at this level. { struct binode *bp = type->function.params; struct binode *b; - int ok = 1; + enum prop_err perr; int arg = 0; struct type *argv_type; @@ -5180,15 +5181,15 @@ is a bit more interesting at this level. argv_type->array.unspec = 1; for (b = bp; b; b = cast(binode, b->right)) { - ok = 1; + perr = 0; switch (arg++) { case 0: /* argv */ - propagate_types(b->left, c, &ok, argv_type, 0); + propagate_types(b->left, c, &perr, argv_type, 0); break; default: /* invalid */ // NOTEST - propagate_types(b->left, c, &ok, Tnone, 0); // NOTEST + propagate_types(b->left, c, &perr, Tnone, 0); // NOTEST } - if (!ok) + if (perr & Efail) c->parse_error = 1; } -- 2.43.0