struct value rval, *lval;
};
- static struct lrval _interp_exec(struct parse_context *c, struct exec *e);
+ /* If dest is passed, dtype must give the expected type, and
+ * result can go there, in which case type is returned as NULL.
+ */
+ static struct lrval _interp_exec(struct parse_context *c, struct exec *e,
+ struct value *dest, struct type *dtype);
static struct value interp_exec(struct parse_context *c, struct exec *e,
struct type **typeret)
{
- struct lrval ret = _interp_exec(c, e);
+ struct lrval ret = _interp_exec(c, e, NULL, NULL);
if (!ret.type) abort();
if (typeret)
static struct value *linterp_exec(struct parse_context *c, struct exec *e,
struct type **typeret)
{
- struct lrval ret = _interp_exec(c, e);
+ struct lrval ret = _interp_exec(c, e, NULL, NULL);
+ if (!ret.type) abort();
if (ret.lval)
*typeret = ret.type;
else
return ret.lval;
}
- static struct lrval _interp_exec(struct parse_context *c, struct exec *e)
+ /* dinterp_exec is used when the destination type is certain and
+ * the value has a place to go.
+ */
+ static void dinterp_exec(struct parse_context *c, struct exec *e,
+ struct value *dest, struct type *dtype,
+ int need_free)
+ {
+ struct lrval ret = _interp_exec(c, e, dest, dtype);
+ if (!ret.type)
+ return; // NOTEST
+ if (need_free)
+ free_value(dtype, dest);
+ if (ret.lval)
+ dup_value(dtype, ret.lval, dest);
+ else
+ memcpy(dest, &ret.rval, dtype->size);
+ }
+
+ static struct lrval _interp_exec(struct parse_context *c, struct exec *e,
+ struct value *dest, struct type *dtype)
{
+ /* If the result is copied to dest, ret.type is set to NULL */
struct lrval ret;
struct value rv = {}, *lrv = NULL;
struct type *rvtype;
}
## interp exec cases
}
- ret.lval = lrv;
- ret.rval = rv;
- ret.type = rvtype;
+ if (rvtype) {
+ ret.lval = lrv;
+ ret.rval = rv;
+ ret.type = rvtype;
+ }
## interp exec cleanup
return ret;
}
if (i >= 0 && i < ltype->array.size)
lrv = ptr + i * rvtype->size;
else
- val_init(ltype->array.member, &rv);
+ val_init(ltype->array.member, &rv); // UNSAFE
ltype = NULL;
break;
}
case Assign:
lleft = linterp_exec(c, b->left, <ype);
- right = interp_exec(c, b->right, &rtype);
- if (lleft) {
- free_value(ltype, lleft);
- dup_value(ltype, &right, lleft);
- ltype = NULL;
- }
+ if (lleft)
+ dinterp_exec(c, b->right, lleft, ltype, 1);
+ ltype = Tnone;
break;
case Declare:
val = var_value(c, v);
if (v->type->prepare_type)
v->type->prepare_type(c, v->type, 0);
- if (b->right) {
- right = interp_exec(c, b->right, &rtype);
- memcpy(val, &right, rtype->size);
- rtype = Tnone;
- } else {
+ if (b->right)
+ dinterp_exec(c, b->right, val, v->type, 0);
+ else
val_init(v->type, val);
- }
break;
}
rv = interp_exec(c, b->left, &rvtype);
if (rvtype == Tnone ||
(rvtype == Tbool && rv.bool != 0))
- // cnd is Tnone or Tbool, doesn't need to be freed
+ // rvtype is Tnone or Tbool, doesn't need to be freed
interp_exec(c, b->right, NULL);
break;