###### ast
- enum val_rules {Rboolok = 1<<0,};
+ enum val_rules {Rboolok = 1<<0, Rrefok = 1<<1,};
enum prop_err {Efail = 1<<0, Eretry = 1<<1, Eruntime = 1<<2,
Emaycopy = 1<<3, Erval = 1<<4, Econst = 1<<5};
static int reference_compat(struct type *require, struct type *have,
enum val_rules rules)
{
+ if (rules & Rrefok)
+ if (require->reference.referent == have)
+ return 1;
if (have->compat != require->compat)
return 0;
if (have->reference.referent != require->reference.referent)
return Tnone;
}
-
static struct type reference_prototype = {
.print_type = reference_print_type,
.cmp_eq = reference_cmp,
| @ IDENTIFIER ${ {
struct type *t = find_type(c, $ID.txt);
if (!t) {
- t = add_type(c, $ID.txt, NULL); // UNTESTED
- t->first_use = $ID; // UNTESTED
+ t = add_type(c, $ID.txt, NULL);
+ t->first_use = $ID;
}
$0 = find_anon_type(c, &reference_prototype, "@%.*s",
$ID.txt.len, $ID.txt.txt);
be declared at any time.
###### Binode types
- Assign,
- Declare,
+ Assign, AssignRef,
+ Declare, DeclareRef,
###### declare terminals
$TERM =
###### print binode cases
case Assign:
+ case AssignRef:
do_indent(indent, "");
print_exec(b->left, -1, bracket);
printf(" = ");
break;
case Declare:
+ case DeclareRef:
{
struct variable *v = cast(var, b->left)->var;
do_indent(indent, "");
###### propagate binode cases
case Assign:
+ case AssignRef:
case Declare:
- /* Both must match and not be labels,
+ case DeclareRef:
+ /* Both must match, or left may be ref and right an lval
* Type must support 'dup',
* For Assign, left must not be constant.
* result is Tnone
return Tnone;
if (t) {
- propagate_types(b->right, c, perr_local, t, 0);
+ struct type *t2 = propagate_types(b->right, c, perr_local,
+ t, Rrefok);
+ if (!t2 || t2 == t || (*perr_local & Efail))
+ ; // No more effort needed
+ else if (t->free == reference_free &&
+ t->reference.referent == t2 &&
+ !(*perr_local & Erval)) {
+ if (b->op == Assign)
+ b->op = AssignRef;
+ if (b->op == Declare)
+ b->op = DeclareRef;
+ }
+ else if (t->free == reference_free &&
+ t->reference.referent == t2 &&
+ (*perr_local & Erval))
+ type_err(c, "error: Cannot assign an rval to a reference.",
+ b, NULL, 0, NULL);
} else {
t = propagate_types(b->right, c, perr_local, NULL, 0);
if (t)
if (*perr & Erval)
type_err(c, "error: cannot assign to an rval", b,
NULL, 0, NULL);
- else if (b->op == Assign && (*perr & Econst)) {
+ else if ((b->op == Assign || b->op == AssignRef) && (*perr & Econst)) {
type_err(c, "error: Cannot assign to a constant: %v",
b->left, NULL, 0, NULL);
if (b->left->type == Xvar) {
###### interp binode cases
case Assign:
+ case AssignRef:
lleft = linterp_exec(c, b->left, <ype);
- if (lleft)
+ if (!lleft)
+ // FIXME lleft==NULL probably means illegal array ref
+ // should that cause a runtime error
+ ;
+ else if (b->op == AssignRef)
+ lleft->ref = linterp_exec(c, b->right, &rtype);
+ else
dinterp_exec(c, b->right, lleft, ltype, 1);
ltype = Tnone;
break;
case Declare:
+ case DeclareRef:
{
struct variable *v = cast(var, b->left)->var;
struct value *val;
val = var_value(c, v);
if (v->type->prepare_type)
v->type->prepare_type(c, v->type, 0);
- if (b->right)
- dinterp_exec(c, b->right, val, v->type, 0);
- else
+ if (!b->right)
val_init(v->type, val);
+ else if (b->op == DeclareRef)
+ val->ref = linterp_exec(c, b->right, &rtype);
+ else
+ dinterp_exec(c, b->right, val, v->type, 0);
break;
}