feat: add object field mutation support with dot-assignment syntax and setter methods

Add parser support for direct field mutation via `obj.field = expr` syntax, enabling mutable object state after creation. Extend the OOP test suite with dedicated mutation tests (`oop_mutation_test.rc`) and advanced examples (`oop_advanced.rc`) covering BankAccount, Player, and Rectangle classes. Update `oop_working.rc` with mutation test cases and revise TUTORIAL.md documentation to describe field mutation, setter methods, and complete OOP examples with mutation. Add Makefile targets for running the new mutation and advanced tests.
This commit is contained in:
2025-11-23 22:23:17 +00:00
parent 0ea0f8e9eb
commit 8c5de5ee9d
6 changed files with 654 additions and 11 deletions
+57 -1
View File
@@ -534,7 +534,63 @@ long expression() {
if (pc >= MAX_TOK) return 0;
if (tokens[pc].type == Id) {
if (pc + 1 >= MAX_TOK) return 0;
if (tokens[pc+1].type == '[') {
if (tokens[pc+1].type == '.') {
int save_pc = pc;
int temp_pc = pc + 1;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == '.') {
temp_pc++;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == Id) {
temp_pc++;
if (temp_pc < MAX_TOK && tokens[temp_pc].type == '=') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Unknown object variable");
if (idx < 0 || idx >= loc_cnt) return 0;
long obj_ptr = memory[locals[idx].addr];
if (obj_ptr == 0) {
error("Null pointer dereference in assignment");
return 0;
}
Object *obj = (Object*)obj_ptr;
if (obj < objects || obj >= objects + MAX_OBJECTS) {
error("Invalid object pointer in assignment");
return 0;
}
pc++;
match('.');
if (pc >= MAX_TOK || tokens[pc].type != Id) {
error("Expected field name after '.'");
return 0;
}
Token *field_name = &tokens[pc];
pc++;
match('=');
int class_idx = obj->class_idx;
if (class_idx < 0 || class_idx >= class_count) {
error("Invalid class index");
return 0;
}
extern int find_class_field(int class_idx, char *name, int len);
int field_idx = find_class_field(class_idx, field_name->text, field_name->val);
if (field_idx < 0) {
error("Unknown field");
return 0;
}
int offset = classes[class_idx].fields[field_idx].offset;
if (offset < 0 || offset >= classes[class_idx].size) {
error("Invalid field offset");
return 0;
}
long val = expression();
obj->field_data[offset] = val;
return val;
}
}
}
} else if (tokens[pc+1].type == '[') {
int idx = find_local(tokens[pc].text, tokens[pc].val);
if (idx == -1) error("Assign to unknown var");
if (idx < 0 || idx >= loc_cnt) return 0;