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':
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;
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;
}
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;
}
/* 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;
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)
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
}
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
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
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
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);
}
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;
}
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;
}
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);
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,
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);
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);
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",
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
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)
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;
* 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
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
###### 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:
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;
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(
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) {
{
struct binode *bp = type->function.params;
struct binode *b;
- int ok = 1;
+ enum prop_err perr;
int arg = 0;
struct type *argv_type;
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;
}