From: NeilBrown Date: Sat, 20 Apr 2019 06:18:18 +0000 (+1000) Subject: oceani: make set of types extensible. X-Git-Tag: JamisonCreek-3~44 X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=commitdiff_plain;h=da44daa2e2ee5e33928e978fae462befa49bc84a oceani: make set of types extensible. Rather than a enum listing allowed types, we now have a 'struct type' which can contain any type. For now it just has an enum and function pointer to the existing function, but that can be extended. Signed-off-by: NeilBrown --- diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 3fd4d74..062eaed 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -351,7 +351,7 @@ in too. 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); @@ -365,10 +365,10 @@ in too. 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 } @@ -392,20 +392,55 @@ to store these elements. 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 @@ -424,9 +459,12 @@ to parse each type from a string. 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; @@ -437,9 +475,6 @@ to parse each type from a string. 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) @@ -447,11 +482,10 @@ to parse each type from a string. 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: @@ -459,13 +493,19 @@ to parse each type from a string. } } - 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; @@ -473,34 +513,46 @@ to parse each type from a string. ###### 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; @@ -520,22 +572,37 @@ to parse each type from a string. 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; @@ -546,11 +613,9 @@ to parse each type from a string. 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: @@ -571,21 +636,31 @@ to parse each type from a string. } } - 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 == '-') { @@ -593,31 +668,82 @@ to parse each type from a string. 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 @@ -924,7 +1050,7 @@ all pending-scope variables become conditionally scoped. 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; } @@ -976,7 +1102,7 @@ all pending-scope variables become conditionally scoped. 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; @@ -993,14 +1119,14 @@ all pending-scope variables become conditionally scoped. 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: @@ -1015,7 +1141,7 @@ all pending-scope variables become conditionally scoped. 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 @@ -1184,22 +1310,23 @@ also want to know what sort of bracketing to use. 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: @@ -1212,7 +1339,7 @@ remains unchanged at `1`, then no more propagation is needed. } ## propagate exec cases } - return Vnone; + return &Tnone; } #### Interpreting @@ -1223,14 +1350,14 @@ within the `exec` tree. The exception to this is the whole `program` 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; @@ -1239,7 +1366,7 @@ Each `exec` can return a value, which may be `Vnone` but shouldn't be `Vunknown` { 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 } @@ -1278,17 +1405,17 @@ an executable. $*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) @@ -1300,7 +1427,7 @@ an executable. }$ | STRING ${ $0 = new_pos(val, $1); - $0->val.vtype = Vstr; + $0->val.type = &Tstr; { char tail[3]; string_parse(&$1, '\\', &$0->val.str, tail); @@ -1311,7 +1438,7 @@ an executable. }$ | 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); @@ -1325,10 +1452,10 @@ an executable. 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; } @@ -1337,12 +1464,12 @@ an executable. 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 @@ -1413,9 +1540,9 @@ link to find the primary instance. 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 ::= ${ { @@ -1429,9 +1556,9 @@ link to find the primary instance. 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); } } }$ @@ -1442,7 +1569,8 @@ link to find the primary instance. /* 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; } } @@ -1480,29 +1608,29 @@ link to find the primary instance. 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; } @@ -1590,15 +1718,15 @@ and `BFact`s. 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: @@ -1694,21 +1822,21 @@ expression operator. 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: @@ -1722,7 +1850,7 @@ expression operator. 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; @@ -1839,30 +1967,30 @@ precedence is handled better I might be able to discard this. 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); @@ -1903,7 +2031,7 @@ precedence is handled better I might be able to discard this. 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; @@ -2049,21 +2177,21 @@ list. ###### 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", @@ -2077,7 +2205,7 @@ list. ###### interp binode cases case Block: - while (rv.vtype == Vnone && + while (rv.type == &Tnone && b) { if (b->left) rv = interp_exec(b->left); @@ -2152,8 +2280,8 @@ same solution. 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 @@ -2173,7 +2301,7 @@ same solution. sep = ' '; } else if (sep) eol = 0; - left.vtype = Vnone; + left.type = &Tnone; if (eol) printf("\n"); break; @@ -2187,7 +2315,7 @@ will be correct so the interpreter just needs to perform the 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, @@ -2239,19 +2367,19 @@ it is declared, and error will be raised as the name is created as 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; @@ -2266,7 +2394,7 @@ it is declared, and error will be raised as the name is created as right = interp_exec(b->right); free_value(v->val); v->val = right; - right.vtype = Vunknown; + right.type = NULL; break; } @@ -2677,8 +2805,8 @@ defined. ###### 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 @@ -2690,44 +2818,44 @@ defined. 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); @@ -2735,7 +2863,7 @@ defined. propagate_types(cp->action, c, ok, type, rules); return type; } else - return Vunknown; + return NULL; } ###### interp exec cases @@ -2751,17 +2879,17 @@ defined. 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); } @@ -2779,7 +2907,7 @@ defined. free_value(cnd); if (c->elsepart) return interp_exec(c->elsepart); - v.vtype = Vnone; + v.type = &Tnone; return v; } @@ -2862,28 +2990,28 @@ analysis is a bit more interesting at this level. 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; } @@ -2906,7 +3034,8 @@ analysis is a bit more interesting at this level. } 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++; }