static void type_err(struct parse_context *c,
char *fmt, struct exec *loc,
- enum vtype t1, int rules, enum vtype t2)
+ struct type *t1, int rules, struct type *t2)
{
fprintf(stderr, "%s:", c->file_name);
fput_loc(loc, stderr);
case '%': fputc(*fmt, stderr); break;
default: fputc('?', stderr); break;
case '1':
- fputs(vtype_names[t1], stderr);
+ fputs(t1 ? t1->name : "*unknown*", stderr);
break;
case '2':
- fputs(vtype_names[t2], stderr);
+ fputs(t2 ? t2->name : "*unknown*", stderr);
break;
## format cases
}
There are two key objects that we need to work with: executable
elements which comprise the program, and values which the program
works with. Between these are the variables in their various scopes
-which hold the values.
+which hold the values, and types which classify the values stored and
+manipulatd by executables.
+
+### Types
+
+Values come in a wide range of types, with more likely to be added.
+Each type needs to be able to parse and print its own values (for
+convenience at least) as well as to compare two values, at least for
+equality and possibly for order. For now, values might need to be
+duplicated and freed, though eventually such manipulations will be
+better integrated into the language.
+
+Rather than requiring every numeric type to support all numeric
+operations (add, multiple, etc), we allow types to be able to present
+as one of a few standard types: integer, float, and fraction. The
+existance of these conversion functions enable types to determine if
+they are compatible with other types.
+
+###### ast
+
+ struct type {
+ char *name;
+ struct value (*init)(struct type *type);
+ struct value (*parse)(struct type *type, char *str);
+ void (*print)(struct value val);
+ int (*cmp_order)(struct value v1, struct value v2);
+ int (*cmp_eq)(struct value v1, struct value v2);
+ struct value (*dup)(struct value val);
+ void (*free)(struct value val);
+ struct type *(*compat)(struct type *this, struct type *other);
+ long long (*to_int)(struct value *v);
+ double (*to_float)(struct value *v);
+ int (*to_mpq)(mpq_t *q, struct value *v);
+ ## type fields
+ };
### Values
Values can be numbers, which we represent as multi-precision
fractions, strings, Booleans and labels. When analysing the program
-we also need to allow for places where no value is meaningful
-(`Vnone`) and where we don't know what type to expect yet (`Vunknown`).
+we also need to allow for places where no value is meaningful (type
+`Tnone`) and where we don't know what type to expect yet (type is
+`NULL`).
Values are never shared, they are always copied when used, and freed
when no longer needed.
When propagating type information around the program, we need to
-determine if two types are compatible, where `Vunknown` is compatible
+determine if two types are compatible, where type `NULL` is compatible
with anything. There are two special cases with type compatibility,
both related to the Conditional Statement which will be described
later. In some cases a Boolean can be accepted as well as some other
myLDLIBS := libnumber.o libstring.o -lgmp
LDLIBS := $(filter-out $(myLDLIBS),$(LDLIBS)) $(myLDLIBS)
+###### type fields
+ enum vtype {Vnone, Vstr, Vnum, Vbool, Vlabel} vtype;
+
###### ast
struct value {
- enum vtype {Vunknown, Vnone, Vstr, Vnum, Vbool, Vlabel} vtype;
+ struct type *type;
union {
struct text str;
mpq_t num;
enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1};
- char *vtype_names[] = {"unknown", "none", "string",
- "number", "Boolean", "label"};
-
###### format cases
case 'r':
if (rules & Rnolabel)
break;
###### ast functions
- static void free_value(struct value v)
+ static void _free_value(struct value v)
{
- switch (v.vtype) {
- case Vnone:
- case Vunknown: break;
+ switch (v.type->vtype) {
+ case Vnone: break;
case Vstr: free(v.str.txt); break;
case Vnum: mpq_clear(v.num); break;
case Vlabel:
}
}
- static int vtype_compat(enum vtype require, enum vtype have, int rules)
+ static void free_value(struct value v)
+ {
+ if (v.type)
+ v.type->free(v);
+ }
+
+ static int vtype_compat(struct type *require, struct type *have, int rules)
{
- if ((rules & Rboolok) && have == Vbool)
+ if ((rules & Rboolok) && have == &Tbool)
return 1;
- if ((rules & Rnolabel) && have == Vlabel)
+ if ((rules & Rnolabel) && have == &Tlabel)
return 0;
- if (require == Vunknown || have == Vunknown)
+ if (!require || !have)
return 1;
return require == have;
###### value functions
- static void val_init(struct value *val, enum vtype type)
+ static struct value _val_init(struct type *type)
{
- val->vtype = type;
- switch(type) {
+ struct value rv;
+
+ rv.type = type;
+ switch(type->vtype) {
case Vnone:abort();
- case Vunknown: break;
case Vnum:
- mpq_init(val->num); break;
+ mpq_init(rv.num); break;
case Vstr:
- val->str.txt = malloc(1);
- val->str.len = 0;
+ rv.str.txt = malloc(1);
+ rv.str.len = 0;
break;
case Vbool:
- val->bool = 0;
+ rv.bool = 0;
break;
case Vlabel:
- val->label = val;
+ rv.label = NULL;
break;
}
+ return rv;
}
- static struct value dup_value(struct value v)
+ static struct value val_init(struct type *type)
+ {
+ struct value rv;
+
+ if (type)
+ return type->init(type);
+ rv.type = type;
+ return rv;
+ }
+
+ static struct value _dup_value(struct value v)
{
struct value rv;
- rv.vtype = v.vtype;
- switch (rv.vtype) {
+ rv.type = v.type;
+ switch (rv.type->vtype) {
case Vnone:
- case Vunknown: break;
+ break;
case Vlabel:
rv.label = v.label;
break;
return rv;
}
- static int value_cmp(struct value left, struct value right)
+ static struct value dup_value(struct value v)
+ {
+ if (v.type)
+ return v.type->dup(v);
+ return v;
+ }
+
+ static int _value_cmp(struct value left, struct value right)
{
int cmp;
- if (left.vtype != right.vtype)
- return left.vtype - right.vtype;
- switch (left.vtype) {
+ if (left.type != right.type)
+ return left.type - right.type;
+ switch (left.type->vtype) {
case Vlabel: cmp = left.label == right.label ? 0 : 1; break;
case Vnum: cmp = mpq_cmp(left.num, right.num); break;
case Vstr: cmp = text_cmp(left.str, right.str); break;
case Vbool: cmp = left.bool - right.bool; break;
- case Vnone:
- case Vunknown: cmp = 0;
+ case Vnone: cmp = 0;
}
return cmp;
}
+ static int value_cmp(struct value left, struct value right)
+ {
+ if (left.type && left.type->cmp_order)
+ return left.type->cmp_order(left, right);
+ if (left.type && left.type->cmp_eq)
+ return left.type->cmp_eq(left, right);
+ return -1;
+ }
+
static struct text text_join(struct text a, struct text b)
{
struct text rv;
return rv;
}
- static void print_value(struct value v)
+ static void _print_value(struct value v)
{
- switch (v.vtype) {
- case Vunknown:
- printf("*Unknown*"); break;
+ switch (v.type->vtype) {
case Vnone:
printf("*no-value*"); break;
case Vlabel:
}
}
- static int parse_value(struct value *vl, char *arg)
+ static void print_value(struct value v)
+ {
+ if (v.type && v.type->print)
+ v.type->print(v);
+ else
+ printf("*Unknown*");
+ }
+
+ static struct value _parse_value(struct type *type, char *arg)
{
+ struct value val;
struct text tx;
int neg = 0;
char tail[3] = "";
- switch(vl->vtype) {
+ val.type = type;
+ switch(type->vtype) {
case Vlabel:
- case Vunknown:
case Vnone:
- return 0;
+ val.type = NULL;
+ break;
case Vstr:
- vl->str.len = strlen(arg);
- vl->str.txt = malloc(vl->str.len);
- memcpy(vl->str.txt, arg, vl->str.len);
+ val.str.len = strlen(arg);
+ val.str.txt = malloc(val.str.len);
+ memcpy(val.str.txt, arg, val.str.len);
break;
case Vnum:
if (*arg == '-') {
arg++;
}
tx.txt = arg; tx.len = strlen(tx.txt);
- if (number_parse(vl->num, tail, tx) == 0)
- mpq_init(vl->num);
+ if (number_parse(val.num, tail, tx) == 0)
+ mpq_init(val.num);
else if (neg)
- mpq_neg(vl->num, vl->num);
+ mpq_neg(val.num, val.num);
if (tail[0]) {
printf("Unsupported suffix: %s\n", arg);
- return 0;
+ val.type = NULL;
}
break;
case Vbool:
if (strcasecmp(arg, "true") == 0 ||
strcmp(arg, "1") == 0)
- vl->bool = 1;
+ val.bool = 1;
else if (strcasecmp(arg, "false") == 0 ||
strcmp(arg, "0") == 0)
- vl->bool = 0;
+ val.bool = 0;
else {
printf("Bad bool: %s\n", arg);
- return 0;
+ val.type = NULL;
}
break;
}
- return 1;
+ return val;
}
+ static struct value parse_value(struct type *type, char *arg)
+ {
+ struct value rv;
+
+ if (type && type->parse)
+ return type->parse(type, arg);
+ rv.type = NULL;
+ return rv;
+ }
+
+ static void _free_value(struct value v);
+
+ #define BaseType \
+ .init = _val_init, \
+ .parse = _parse_value, \
+ .print = _print_value, \
+ .cmp_order = _value_cmp, \
+ .cmp_eq = _value_cmp, \
+ .dup = _dup_value, \
+ .free = _free_value, \
+
+ static struct type Tbool = {
+ BaseType
+ .name = "Boolean",
+ .vtype = Vbool,
+ };
+
+ static struct type Tstr = {
+ BaseType
+ .name = "string",
+ .vtype = Vstr,
+ };
+
+ static struct type Tnum = {
+ BaseType
+ .name = "number",
+ .vtype = Vnum,
+ };
+
+ static struct type Tnone = {
+ BaseType
+ .name = "none",
+ .vtype = Vnone,
+ };
+
+ static struct type Tlabel = {
+ BaseType
+ .name = "label",
+ .vtype = Vlabel,
+ };
+
### Variables
Variables are scoped named values. We store the names in a linked
v->scope = InScope;
v->in_scope = c->in_scope;
c->in_scope = v;
- val_init(&v->val, Vunknown);
+ v->val = val_init(NULL);
return v;
}
else if (v->previous &&
v->previous->scope == PendingScope)
v->scope = PendingScope;
- else if (v->val.vtype == Vlabel)
+ else if (v->val.type == &Tlabel)
v->scope = PendingScope;
else if (v->name->var == v)
v->scope = OutScope;
for (v2 = v;
v2 && v2->scope == PendingScope;
v2 = v2->previous)
- if (v2->val.vtype != Vlabel)
+ if (v2->val.type != &Tlabel)
v2->scope = OutScope;
break;
case OutScope: break;
}
break;
case CloseSequential:
- if (v->val.vtype == Vlabel)
+ if (v->val.type == &Tlabel)
v->scope = PendingScope;
switch (v->scope) {
case InScope:
for (v2 = v;
v2 && v2->scope == PendingScope;
v2 = v2->previous)
- if (v2->val.vtype == Vlabel) {
+ if (v2->val.type == &Tlabel) {
v2->scope = CondScope;
v2->min_depth = c->scope_depth;
} else
As discussed, analysis involves propagating type requirements around
the program and looking for errors.
-So `propagate_types` is passed an expected type (being a `vtype`
-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 `Vunknown`. 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.
+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.
###### core functions
- static enum vtype propagate_types(struct exec *prog, struct parse_context *c, int *ok,
- enum vtype type, int rules)
+ static struct type *propagate_types(struct exec *prog, struct parse_context *c, int *ok,
+ struct type *type, int rules)
{
- enum vtype t;
+ struct type *t;
if (!prog)
- return Vnone;
+ return &Tnone;
switch (prog->type) {
case Xbinode:
}
## propagate exec cases
}
- return Vnone;
+ return &Tnone;
}
#### Interpreting
which needs to look at command line arguments. The `program` will be
interpreted separately.
-Each `exec` can return a value, which may be `Vnone` but shouldn't be `Vunknown`.
+Each `exec` can return a value, which may be `Tnone` but must be non-NULL;
###### core functions
static struct value interp_exec(struct exec *e)
{
struct value rv;
- rv.vtype = Vnone;
+ rv.type = &Tnone;
if (!e)
return rv;
{
struct binode *b = cast(binode, e);
struct value left, right;
- left.vtype = right.vtype = Vnone;
+ left.type = right.type = &Tnone;
switch (b->op) {
## interp binode cases
}
$*val
Value -> True ${
$0 = new_pos(val, $1);
- $0->val.vtype = Vbool;
+ $0->val.type = &Tbool;
$0->val.bool = 1;
}$
| False ${
$0 = new_pos(val, $1);
- $0->val.vtype = Vbool;
+ $0->val.type = &Tbool;
$0->val.bool = 0;
}$
| NUMBER ${
$0 = new_pos(val, $1);
- $0->val.vtype = Vnum;
+ $0->val.type = &Tnum;
{
char tail[3];
if (number_parse($0->val.num, tail, $1.txt) == 0)
}$
| STRING ${
$0 = new_pos(val, $1);
- $0->val.vtype = Vstr;
+ $0->val.type = &Tstr;
{
char tail[3];
string_parse(&$1, '\\', &$0->val.str, tail);
}$
| MULTI_STRING ${
$0 = new_pos(val, $1);
- $0->val.vtype = Vstr;
+ $0->val.type = &Tstr;
{
char tail[3];
string_parse(&$1, '\\', &$0->val.str, tail);
case Xval:
{
struct val *v = cast(val, e);
- if (v->val.vtype == Vstr)
+ if (v->val.type == &Tstr)
printf("\"");
print_value(v->val);
- if (v->val.vtype == Vstr)
+ if (v->val.type == &Tstr)
printf("\"");
break;
}
case Xval:
{
struct val *val = cast(val, prog);
- if (!vtype_compat(type, val->val.vtype, rules)) {
+ if (!vtype_compat(type, val->val.type, rules)) {
type_err(c, "error: expected %1%r found %2",
- prog, type, rules, val->val.vtype);
+ prog, type, rules, val->val.type);
*ok = 0;
}
- return val->val.vtype;
+ return val->val.type;
}
###### interp exec cases
v = var_ref(config2context(config), $1.txt);
$0->var = v;
type_err(config2context(config), "error: variable '%v' redeclared",
- $0, Vnone, 0, Vnone);
+ $0, &Tnone, 0, &Tnone);
type_err(config2context(config), "info: this is where '%v' was first declared",
- v->where_decl, Vnone, 0, Vnone);
+ v->where_decl, &Tnone, 0, &Tnone);
}
} }$
| IDENTIFIER ::= ${ {
v = var_ref(config2context(config), $1.txt);
$0->var = v;
type_err(config2context(config), "error: variable '%v' redeclared",
- $0, Vnone, 0, Vnone);
+ $0, &Tnone, 0, &Tnone);
type_err(config2context(config), "info: this is where '%v' was first declared",
- v->where_decl, Vnone, 0, Vnone);
+ v->where_decl, &Tnone, 0, &Tnone);
}
} }$
/* This might be a label - allocate a var just in case */
v = var_decl(config2context(config), $1.txt);
if (v) {
- val_init(&v->val, Vlabel);
+ v->val = val_init(&Tlabel);
+ v->val.label = &v->val;
v->where_set = $0;
}
}
struct var *var = cast(var, prog);
struct variable *v = var->var;
if (!v) {
- type_err(c, "%d:BUG: no variable!!", prog, Vnone, 0, Vnone);
+ type_err(c, "%d:BUG: no variable!!", prog, &Tnone, 0, &Tnone);
*ok = 0;
- return Vnone;
+ return &Tnone;
}
if (v->merged)
v = v->merged;
- if (v->val.vtype == Vunknown) {
- if (type != Vunknown && *ok != 0) {
- val_init(&v->val, type);
+ if (v->val.type == NULL) {
+ if (type && *ok != 0) {
+ v->val = val_init(type);
v->where_set = prog;
*ok = 2;
}
return type;
}
- if (!vtype_compat(type, v->val.vtype, rules)) {
+ if (!vtype_compat(type, v->val.type, rules)) {
type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
- type, rules, v->val.vtype);
+ type, rules, v->val.type);
type_err(c, "info: this is where '%v' was set to %1", v->where_set,
- v->val.vtype, rules, Vnone);
+ v->val.type, rules, &Tnone);
*ok = 0;
}
- if (type == Vunknown)
- return v->val.vtype;
+ if (!type)
+ return v->val.type;
return type;
}
case And:
case Or:
case Not:
- /* both must be Vbool, result is Vbool */
- propagate_types(b->left, c, ok, Vbool, 0);
- propagate_types(b->right, c, ok, Vbool, 0);
- if (type != Vbool && type != Vunknown) {
+ /* both must be Tbool, result is Tbool */
+ propagate_types(b->left, c, ok, &Tbool, 0);
+ propagate_types(b->right, c, ok, &Tbool, 0);
+ if (type && type != &Tbool) {
type_err(c, "error: %1 operation found where %2 expected", prog,
- Vbool, 0, type);
+ &Tbool, 0, type);
*ok = 0;
}
- return Vbool;
+ return &Tbool;
###### interp binode cases
case And:
case GtrEq:
case Eql:
case NEql:
- /* Both must match but not labels, result is Vbool */
- t = propagate_types(b->left, c, ok, Vunknown, Rnolabel);
- if (t != Vunknown)
+ /* Both must match but not labels, result is Tbool */
+ t = propagate_types(b->left, c, ok, NULL, Rnolabel);
+ if (t)
propagate_types(b->right, c, ok, t, 0);
else {
- t = propagate_types(b->right, c, ok, Vunknown, Rnolabel);
- if (t != Vunknown)
+ t = propagate_types(b->right, c, ok, NULL, Rnolabel);
+ if (t)
t = propagate_types(b->left, c, ok, t, 0);
}
- if (!vtype_compat(type, Vbool, 0)) {
+ if (!vtype_compat(type, &Tbool, 0)) {
type_err(c, "error: Comparison returns %1 but %2 expected", prog,
- Vbool, rules, type);
+ &Tbool, rules, type);
*ok = 0;
}
- return Vbool;
+ return &Tbool;
###### interp binode cases
case Less:
left = interp_exec(b->left);
right = interp_exec(b->right);
cmp = value_cmp(left, right);
- rv.vtype = Vbool;
+ rv.type = &Tbool;
switch (b->op) {
case Less: rv.bool = cmp < 0; break;
case LessEq: rv.bool = cmp <= 0; break;
case Minus:
case Times:
case Divide:
- /* both must be numbers, result is Vnum */
+ /* both must be numbers, result is Tnum */
case Absolute:
case Negate:
/* as propagate_types ignores a NULL,
* unary ops fit here too */
- propagate_types(b->left, c, ok, Vnum, 0);
- propagate_types(b->right, c, ok, Vnum, 0);
- if (!vtype_compat(type, Vnum, 0)) {
+ propagate_types(b->left, c, ok, &Tnum, 0);
+ propagate_types(b->right, c, ok, &Tnum, 0);
+ if (!vtype_compat(type, &Tnum, 0)) {
type_err(c, "error: Arithmetic returns %1 but %2 expected", prog,
- Vnum, rules, type);
+ &Tnum, rules, type);
*ok = 0;
}
- return Vnum;
+ return &Tnum;
case Concat:
- /* both must be Vstr, result is Vstr */
- propagate_types(b->left, c, ok, Vstr, 0);
- propagate_types(b->right, c, ok, Vstr, 0);
- if (!vtype_compat(type, Vstr, 0)) {
+ /* both must be Tstr, result is Tstr */
+ propagate_types(b->left, c, ok, &Tstr, 0);
+ propagate_types(b->right, c, ok, &Tstr, 0);
+ if (!vtype_compat(type, &Tstr, 0)) {
type_err(c, "error: Concat returns %1 but %2 expected", prog,
- Vstr, rules, type);
+ &Tstr, rules, type);
*ok = 0;
}
- return Vstr;
+ return &Tstr;
case Bracket:
return propagate_types(b->right, c, ok, type, 0);
case Concat:
left = interp_exec(b->left);
right = interp_exec(b->right);
- rv.vtype = Vstr;
+ rv.type = &Tstr;
rv.str = text_join(left.str, right.str);
break;
###### propagate binode cases
case Block:
{
- /* If any statement returns something other then Vnone
- * or Vbool then all such must return same type.
- * As each statement may be Vnone or something else,
- * we must always pass Vunknown down, otherwise an incorrect
- * error might occur. We never return Vnone unless it is
+ /* If any statement returns something other then Tnone
+ * or Tbool then all such must return same type.
+ * As each statement may be Tnone or something else,
+ * we must always pass NULL (unknown) down, otherwise an incorrect
+ * error might occur. We never return Tnone unless it is
* passed in.
*/
struct binode *e;
for (e = b; e; e = cast(binode, e->right)) {
- t = propagate_types(e->left, c, ok, Vunknown, rules);
- if ((rules & Rboolok) && t == Vbool)
- t = Vunknown;
- if (t != Vunknown && t != Vnone && t != Vbool) {
- if (type == Vunknown)
+ t = propagate_types(e->left, c, ok, NULL, rules);
+ if ((rules & Rboolok) && t == &Tbool)
+ t = NULL;
+ if (t && t != &Tnone && t != &Tbool) {
+ if (!type)
type = t;
else if (t != type) {
type_err(c, "error: expected %1%r, found %2",
###### interp binode cases
case Block:
- while (rv.vtype == Vnone &&
+ while (rv.type == &Tnone &&
b) {
if (b->left)
rv = interp_exec(b->left);
case Print:
/* don't care but all must be consistent */
- propagate_types(b->left, c, ok, Vunknown, Rnolabel);
- propagate_types(b->right, c, ok, Vunknown, Rnolabel);
+ propagate_types(b->left, c, ok, NULL, Rnolabel);
+ propagate_types(b->right, c, ok, NULL, Rnolabel);
break;
###### interp binode cases
sep = ' ';
} else if (sep)
eol = 0;
- left.vtype = Vnone;
+ left.type = &Tnone;
if (eol)
printf("\n");
break;
calculation. There is a form of assignment which declares a new
variable as well as assigning a value. If a name is assigned before
it is declared, and error will be raised as the name is created as
-`Vlabel` and it is illegal to assign to such names.
+`Tlabel` and it is illegal to assign to such names.
###### Binode types
Assign,
case Assign:
case Declare:
- /* Both must match and not be labels, result is Vnone */
- t = propagate_types(b->left, c, ok, Vunknown, Rnolabel);
- if (t != Vunknown) {
+ /* Both must match and not be labels, result is Tnone */
+ t = propagate_types(b->left, c, ok, NULL, Rnolabel);
+ if (t) {
if (propagate_types(b->right, c, ok, 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, Vnone);
+ cast(var, b->left)->var->where_set, t, rules, &Tnone);
} else {
- t = propagate_types(b->right, c, ok, Vunknown, Rnolabel);
- if (t != Vunknown)
+ t = propagate_types(b->right, c, ok, NULL, Rnolabel);
+ if (t)
propagate_types(b->left, c, ok, t, 0);
}
- return Vnone;
+ return &Tnone;
break;
right = interp_exec(b->right);
free_value(v->val);
v->val = right;
- right.vtype = Vunknown;
+ right.type = NULL;
break;
}
###### propagate exec cases
case Xcond_statement:
{
- // forpart and dopart must return Vnone
- // thenpart must return Vnone if there is a dopart,
+ // forpart and dopart must return Tnone
+ // thenpart must return Tnone if there is a dopart,
// otherwise it is like elsepart.
// condpart must:
// be bool if there is not casepart
struct cond_statement *cs = cast(cond_statement, prog);
struct casepart *cp;
- t = propagate_types(cs->forpart, c, ok, Vnone, 0);
- if (!vtype_compat(Vnone, t, 0))
+ t = propagate_types(cs->forpart, c, ok, &Tnone, 0);
+ if (!vtype_compat(&Tnone, t, 0))
*ok = 0;
- t = propagate_types(cs->dopart, c, ok, Vnone, 0);
- if (!vtype_compat(Vnone, t, 0))
+ t = propagate_types(cs->dopart, c, ok, &Tnone, 0);
+ if (!vtype_compat(&Tnone, t, 0))
*ok = 0;
if (cs->dopart) {
- t = propagate_types(cs->thenpart, c, ok, Vnone, 0);
- if (!vtype_compat(Vnone, t, 0))
+ t = propagate_types(cs->thenpart, c, ok, &Tnone, 0);
+ if (!vtype_compat(&Tnone, t, 0))
*ok = 0;
}
if (cs->casepart == NULL)
- propagate_types(cs->condpart, c, ok, Vbool, 0);
+ propagate_types(cs->condpart, c, ok, &Tbool, 0);
else {
/* Condpart must match case values, with bool permitted */
- t = Vunknown;
+ t = NULL;
for (cp = cs->casepart;
- cp && (t == Vunknown); cp = cp->next)
- t = propagate_types(cp->value, c, ok, Vunknown, 0);
- if (t == Vunknown && cs->condpart)
- t = propagate_types(cs->condpart, c, ok, Vunknown, Rboolok);
+ cp && !t; cp = cp->next)
+ t = propagate_types(cp->value, c, ok, NULL, 0);
+ if (!t && cs->condpart)
+ t = propagate_types(cs->condpart, c, ok, NULL, Rboolok);
// Now we have a type (I hope) push it down
- if (t != Vunknown) {
+ 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);
}
}
// (if)then, else, and case parts must return expected type.
- if (!cs->dopart && type == Vunknown)
- type = propagate_types(cs->thenpart, c, ok, Vunknown, rules);
- if (type == Vunknown)
- type = propagate_types(cs->elsepart, c, ok, Vunknown, rules);
+ if (!cs->dopart && !type)
+ type = propagate_types(cs->thenpart, c, ok, NULL, rules);
+ if (!type)
+ type = propagate_types(cs->elsepart, c, ok, NULL, rules);
for (cp = cs->casepart;
- cp && type == Vunknown;
+ cp && !type;
cp = cp->next)
- type = propagate_types(cp->action, c, ok, Vunknown, rules);
- if (type != Vunknown) {
+ type = propagate_types(cp->action, c, ok, NULL, rules);
+ if (type) {
if (!cs->dopart)
propagate_types(cs->thenpart, c, ok, type, rules);
propagate_types(cs->elsepart, c, ok, type, rules);
propagate_types(cp->action, c, ok, type, rules);
return type;
} else
- return Vunknown;
+ return NULL;
}
###### interp exec cases
if (c->condpart)
cnd = interp_exec(c->condpart);
else
- cnd.vtype = Vnone;
- if (!(cnd.vtype == Vnone ||
- (cnd.vtype == Vbool && cnd.bool != 0)))
+ cnd.type = &Tnone;
+ if (!(cnd.type == &Tnone ||
+ (cnd.type == &Tbool && cnd.bool != 0)))
break;
- // cnd is Vnone or Vbool, doesn't need to be freed
+ // cnd is Tnone or Tbool, doesn't need to be freed
if (c->dopart)
interp_exec(c->dopart);
if (c->thenpart) {
v = interp_exec(c->thenpart);
- if (v.vtype != Vnone || !c->dopart)
+ if (v.type != &Tnone || !c->dopart)
return v;
free_value(v);
}
free_value(cnd);
if (c->elsepart)
return interp_exec(c->elsepart);
- v.vtype = Vnone;
+ v.type = &Tnone;
return v;
}
return 0;
do {
ok = 1;
- propagate_types(b->right, c, &ok, Vnone, 0);
+ propagate_types(b->right, c, &ok, &Tnone, 0);
} while (ok == 2);
if (!ok)
return 0;
for (b = cast(binode, b->left); b; b = cast(binode, b->right)) {
struct var *v = cast(var, b->left);
- if (v->var->val.vtype == Vunknown) {
+ if (!v->var->val.type) {
v->var->where_set = b;
- val_init(&v->var->val, Vstr);
+ v->var->val = val_init(&Tstr);
}
}
b = cast(binode, prog);
do {
ok = 1;
- propagate_types(b->right, c, &ok, Vnone, 0);
+ propagate_types(b->right, c, &ok, &Tnone, 0);
} while (ok == 2);
if (!ok)
return 0;
/* Make sure everything is still consistent */
- propagate_types(b->right, c, &ok, Vnone, 0);
+ propagate_types(b->right, c, &ok, &Tnone, 0);
return !!ok;
}
}
al = cast(binode, al->right);
free_value(*vl);
- if (!parse_value(vl, argv[0]))
+ *vl = parse_value(vl->type, argv[0]);
+ if (vl->type == NULL)
exit(1);
argv++;
}