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;
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