case '%': fputc(*fmt, stderr); break;
default: fputc('?', stderr); break;
case '1':
- if (t1)
- fprintf(stderr, "%.*s", t1->name.len, t1->name.txt);
- else
- fputs("*unknown*", stderr);
+ type_print(t1, stderr);
break;
case '2':
- if (t2)
- fprintf(stderr, "%.*s", t2->name.len, t2->name.txt);
- else
- fputs("*unknown*", stderr);
- break;
+ type_print(t2, stderr);
break;
## format cases
}
struct text name;
struct type *next;
struct value (*init)(struct type *type);
+ struct value (*prepare)(struct type *type);
struct value (*parse)(struct type *type, char *str);
void (*print)(struct value val);
+ void (*print_type)(struct type *type, FILE *f);
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);
+ int (*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);
v.type->free(v);
}
+ static int type_compat(struct type *require, struct type *have, int rules)
+ {
+ if ((rules & Rboolok) && have == Tbool)
+ return 1;
+ if ((rules & Rnolabel) && have == Tlabel)
+ return 0;
+ if (!require || !have)
+ return 1;
+
+ if (require->compat)
+ return require->compat(require, have);
+
+ return require == have;
+ }
+
+ static void type_print(struct type *type, FILE *f)
+ {
+ if (!type)
+ fputs("*unknown*type*", f);
+ else if (type->name.len)
+ fprintf(f, "%.*s", type->name.len, type->name.txt);
+ else if (type->print_type)
+ type->print_type(type, f);
+ else
+ fputs("*invalid*type*", f);
+ }
+
+ static struct value val_prepare(struct type *type)
+ {
+ struct value rv;
+
+ if (type)
+ return type->prepare(type);
+ rv.type = type;
+ return rv;
+ }
+
static struct value val_init(struct type *type)
{
struct value rv;
}
}
- static int vtype_compat(struct type *require, struct type *have, int rules)
+###### value functions
+
+ static struct value _val_prepare(struct type *type)
{
- if ((rules & Rboolok) && have == Tbool)
- return 1;
- if ((rules & Rnolabel) && have == Tlabel)
- return 0;
- if (!require || !have)
- return 1;
+ struct value rv;
- return require == have;
+ rv.type = type;
+ switch(type->vtype) {
+ case Vnone:
+ break;
+ case Vnum:
+ memset(&rv.num, 0, sizeof(rv.num));
+ break;
+ case Vstr:
+ rv.str.txt = NULL;
+ rv.str.len = 0;
+ break;
+ case Vbool:
+ rv.bool = 0;
+ break;
+ case Vlabel:
+ rv.label = NULL;
+ break;
+ }
+ return rv;
}
-###### value functions
-
static struct value _val_init(struct type *type)
{
struct value rv;
static struct type base_prototype = {
.init = _val_init,
+ .prepare = _val_prepare,
.parse = _parse_value,
.print = _print_value,
.cmp_order = _value_cmp,
v->scope = InScope;
v->in_scope = c->in_scope;
c->in_scope = v;
- v->val = val_init(NULL);
+ v->val = val_prepare(NULL);
return v;
}
###### ast
- enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1};
+ enum val_rules {Rnolabel = 1<<0, Rboolok = 1<<1, Rnoconstant = 2<<1};
###### format cases
case 'r':
case Xval:
{
struct val *val = cast(val, prog);
- if (!vtype_compat(type, val->val.type, rules)) {
+ if (!type_compat(type, val->val.type, rules)) {
type_err(c, "error: expected %1%r found %2",
prog, type, rules, val->val.type);
*ok = 0;
if (v) {
v->where_decl = $0;
v->where_set = $0;
- v->val = val_init($<3);
+ v->val = val_prepare($<3);
} else {
v = var_ref(config2context(config), $1.txt);
$0->var = v;
if (v) {
v->where_decl = $0;
v->where_set = $0;
- v->val = val_init($<3);
+ v->val = val_prepare($<3);
v->constant = 1;
} else {
v = var_ref(config2context(config), $1.txt);
/* This might be a label - allocate a var just in case */
v = var_decl(config2context(config), $1.txt);
if (v) {
- v->val = val_init(Tlabel);
+ v->val = val_prepare(Tlabel);
v->val.label = &v->val;
v->where_set = $0;
}
}
if (v->merged)
v = v->merged;
+ if (v->constant && (rules & Rnoconstant)) {
+ type_err(c, "error: Cannot assign to a constant: %v",
+ prog, NULL, 0, NULL);
+ type_err(c, "info: name was defined as a constant here",
+ v->where_decl, NULL, 0, NULL);
+ *ok = 0;
+ return v->val.type;
+ }
if (v->val.type == NULL) {
if (type && *ok != 0) {
- v->val = val_init(type);
+ v->val = val_prepare(type);
v->where_set = prog;
*ok = 2;
}
return type;
}
- if (!vtype_compat(type, v->val.type, rules)) {
+ if (!type_compat(type, v->val.type, rules)) {
type_err(c, "error: expected %1%r but variable '%v' is %2", prog,
type, rules, v->val.type);
type_err(c, "info: this is where '%v' was set to %1", v->where_set,
if (t)
t = propagate_types(b->left, c, ok, t, 0);
}
- if (!vtype_compat(type, Tbool, 0)) {
+ if (!type_compat(type, Tbool, 0)) {
type_err(c, "error: Comparison returns %1 but %2 expected", prog,
Tbool, rules, type);
*ok = 0;
* unary ops fit here too */
propagate_types(b->left, c, ok, Tnum, 0);
propagate_types(b->right, c, ok, Tnum, 0);
- if (!vtype_compat(type, Tnum, 0)) {
+ if (!type_compat(type, Tnum, 0)) {
type_err(c, "error: Arithmetic returns %1 but %2 expected", prog,
Tnum, rules, type);
*ok = 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)) {
+ if (!type_compat(type, Tstr, 0)) {
type_err(c, "error: Concat returns %1 but %2 expected", prog,
Tstr, rules, type);
*ok = 0;
Declare,
###### SimpleStatement Grammar
- | Variable = Expression ${ {
- struct var *v = cast(var, $1);
-
+ | Variable = Expression ${
$0 = new(binode);
$0->op = Assign;
$0->left = $<1;
$0->right = $<3;
- if (v->var && v->var->constant) {
- type_err(config2context(config), "Cannot assign to a constant: %v",
- $0->left, NULL, 0, NULL);
- type_err(config2context(config), "name was defined as a constant here",
- v->var->where_decl, NULL, 0, NULL);
- }
- } }$
+ }$
| VariableDecl = Expression ${
$0 = new(binode);
$0->op = Declare;
do_indent(indent, "");
print_exec(b->left, indent, 0);
if (cast(var, b->left)->var->constant) {
- if (v->where_decl == v->where_set)
- printf("::%.*s ", v->val.type->name.len,
- v->val.type->name.txt);
- else
+ if (v->where_decl == v->where_set) {
+ printf("::");
+ type_print(v->val.type, stdout);
+ printf(" ");
+ } else
printf(" ::");
} else {
- if (v->where_decl == v->where_set)
- printf(":%.*s ", v->val.type->name.len,
- v->val.type->name.txt);
- else
+ if (v->where_decl == v->where_set) {
+ printf(":");
+ type_print(v->val.type, stdout);
+ printf(" ");
+ } else
printf(" :");
}
if (b->right) {
case Declare:
/* Both must match and not be labels,
* Type must support 'dup',
- * result is Tnone */
- t = propagate_types(b->left, c, ok, NULL, Rnolabel);
+ * For Assign, left must not be constant.
+ * result is Tnone
+ */
+ t = propagate_types(b->left, c, ok, NULL,
+ Rnolabel | (b->op == Assign ? Rnoconstant : 0));
if (!b->right)
return Tnone;
} else {
t = propagate_types(b->right, c, ok, NULL, Rnolabel);
if (t)
- propagate_types(b->left, c, ok, t, 0);
+ propagate_types(b->left, c, ok, t,
+ (b->op == Assign ? Rnoconstant : 0));
}
if (t && t->dup == NULL) {
type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL);
struct casepart *cp;
t = propagate_types(cs->forpart, c, ok, Tnone, 0);
- if (!vtype_compat(Tnone, t, 0))
+ if (!type_compat(Tnone, t, 0))
*ok = 0;
t = propagate_types(cs->dopart, c, ok, Tnone, 0);
- if (!vtype_compat(Tnone, t, 0))
+ if (!type_compat(Tnone, t, 0))
*ok = 0;
if (cs->dopart) {
t = propagate_types(cs->thenpart, c, ok, Tnone, 0);
- if (!vtype_compat(Tnone, t, 0))
+ if (!type_compat(Tnone, t, 0))
*ok = 0;
}
if (cs->casepart == NULL)
struct var *v = cast(var, b->left);
if (!v->var->val.type) {
v->var->where_set = b;
- v->var->val = val_init(Tstr);
+ v->var->val = val_prepare(Tstr);
}
}
b = cast(binode, prog);