fix increment operators on objects

This commit is contained in:
2026-02-10 17:17:36 -06:00
parent f44fb502be
commit f1a5072ff2
4 changed files with 203 additions and 2 deletions

View File

@@ -843,19 +843,83 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
int slot = mach_find_var(cs, name);
if (slot >= 0) {
if (is_postfix) {
/* Return old value, then increment */
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
mach_emit(cs, MACH_ABC(inc_op, slot, slot, 0));
} else {
/* Increment, then return new value */
mach_emit(cs, MACH_ABC(inc_op, slot, slot, 0));
if (dest != slot)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, slot, 0));
}
return dest;
}
} else if (level > 0 && name) {
/* Closure variable */
int save = cs->freereg;
MachCompState *target = cs;
for (int i = 0; i < level; i++) target = target->parent;
int slot = mach_find_var(target, name);
int val_r = mach_reserve_reg(cs);
mach_emit(cs, MACH_ABC(MACH_GETUP, val_r, level, slot));
if (is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(inc_op, val_r, val_r, 0));
if (!is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(MACH_SETUP, val_r, level, slot));
mach_free_reg_to(cs, save);
return dest;
}
}
/* Property access: obj.prop++ */
if (op_kind && strcmp(op_kind, ".") == 0) {
int save = cs->freereg;
cJSON *obj_expr = cJSON_GetObjectItemCaseSensitive(operand, "expression");
if (!obj_expr) obj_expr = cJSON_GetObjectItemCaseSensitive(operand, "left");
cJSON *prop = cJSON_GetObjectItemCaseSensitive(operand, "name");
if (!prop) prop = cJSON_GetObjectItemCaseSensitive(operand, "right");
const char *prop_name = NULL;
if (cJSON_IsString(prop)) prop_name = cJSON_GetStringValue(prop);
else if (prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(prop, "value"));
if (!prop_name && prop) prop_name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(prop, "name"));
if (!prop_name) prop_name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(operand, "value"));
if (prop_name) {
int obj_r = mach_compile_expr(cs, obj_expr, -1);
if (cs->freereg <= obj_r) cs->freereg = obj_r + 1;
int ki = mach_cpool_add_str(cs, prop_name);
int val_r = mach_reserve_reg(cs);
mach_emit(cs, MACH_ABC(MACH_GETFIELD, val_r, obj_r, ki));
if (is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(inc_op, val_r, val_r, 0));
if (!is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(MACH_SETFIELD, obj_r, ki, val_r));
mach_free_reg_to(cs, save);
return dest;
}
}
/* Computed property access: obj[idx]++ */
if (op_kind && strcmp(op_kind, "[") == 0) {
int save = cs->freereg;
cJSON *obj_expr = cJSON_GetObjectItemCaseSensitive(operand, "expression");
if (!obj_expr) obj_expr = cJSON_GetObjectItemCaseSensitive(operand, "left");
cJSON *idx_expr = cJSON_GetObjectItemCaseSensitive(operand, "index");
if (!idx_expr) idx_expr = cJSON_GetObjectItemCaseSensitive(operand, "right");
int obj_r = mach_compile_expr(cs, obj_expr, -1);
if (cs->freereg <= obj_r) cs->freereg = obj_r + 1;
int idx_r = mach_compile_expr(cs, idx_expr, -1);
if (cs->freereg <= idx_r) cs->freereg = idx_r + 1;
int val_r = mach_reserve_reg(cs);
mach_emit(cs, MACH_ABC(MACH_GETINDEX, val_r, obj_r, idx_r));
if (is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(inc_op, val_r, val_r, 0));
if (!is_postfix)
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, val_r, 0));
mach_emit(cs, MACH_ABC(MACH_SETINDEX, obj_r, idx_r, val_r));
mach_free_reg_to(cs, save);
return dest;
}
/* Fallback: just compile operand */
return mach_compile_expr(cs, operand, dest);
}