calling the array setter when required

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-11-11 21:27:02 +01:00
parent feec2d74ee
commit a78cdd5366

80
ast.c
View file

@ -1244,6 +1244,10 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
ast_expression_codegen *cgen;
ir_value *left, *right;
ast_array_index *ai;
ast_value *arr;
ast_value *idx;
if (lvalue && self->expression.outl) {
*out = self->expression.outl;
return true;
@ -1254,20 +1258,72 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
return true;
}
cgen = self->dest->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
self->expression.outl = left;
if (ast_istype(self->dest, ast_array_index))
{
cgen = self->source->expression.codegen;
/* rvalue! */
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
ai = (ast_array_index*)self->dest;
idx = (ast_value*)ai->index;
if (!ir_block_create_store_op(func->curblock, self->op, left, right))
return false;
self->expression.outr = right;
if (ast_istype(ai->index, ast_value) && idx->isconst)
ai = NULL;
}
if (ai) {
/* we need to call the setter */
ir_value *iridx, *funval;
ir_instr *call;
if (lvalue) {
asterror(ast_ctx(self), "array-subscript assignment cannot produce lvalues");
return false;
}
arr = (ast_value*)ai->array;
if (!ast_istype(ai->array, ast_value) || !arr->setter) {
asterror(ast_ctx(self), "value has no setter (%s)", arr->name);
return false;
}
cgen = idx->expression.codegen;
if (!(*cgen)((ast_expression*)(idx), func, false, &iridx))
return false;
cgen = arr->setter->expression.codegen;
if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
return false;
cgen = self->source->expression.codegen;
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
if (!call)
return false;
if (!ir_call_param(call, iridx))
return false;
if (!ir_call_param(call, right))
return false;
self->expression.outr = right;
}
else
{
/* regular code */
cgen = self->dest->expression.codegen;
/* lvalue! */
if (!(*cgen)((ast_expression*)(self->dest), func, true, &left))
return false;
self->expression.outl = left;
cgen = self->source->expression.codegen;
/* rvalue! */
if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
return false;
if (!ir_block_create_store_op(func->curblock, self->op, left, right))
return false;
self->expression.outr = right;
}
/* Theoretically, an assinment returns its left side as an
* lvalue, if we don't need an lvalue though, we return