diff --git a/src/backend/vm.rs b/src/backend/vm.rs index b0df6c6e..201c5a4e 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -110,6 +110,8 @@ pub struct VM { pc: usize, /// Return value from last execution last_result: Option, + /// Simple field storage for objects (maps reference -> field -> value) + object_fields: HashMap>, } impl VM { @@ -121,6 +123,7 @@ impl VM { current_block: None, pc: 0, last_result: None, + object_fields: HashMap::new(), } } @@ -375,16 +378,17 @@ impl VM { }, MirInstruction::RefGet { dst, reference, field } => { - // For now, field access is simplified - we'll treat it as accessing a property - // In a real implementation, this would dereference the reference and access the field - let _ref_value = self.get_value(*reference)?; - - // Simplified: return a placeholder value for field access - // TODO: Implement proper Box field access - let field_value = match field.as_str() { - "length" => VMValue::Integer(0), // Default length - "size" => VMValue::Integer(0), // Default size - _ => VMValue::String(format!("field_{}", field)), // Default field value + // Get field value from object + let field_value = if let Some(fields) = self.object_fields.get(reference) { + if let Some(value) = fields.get(field) { + value.clone() + } else { + // Field not set yet, return default + VMValue::Integer(0) + } + } else { + // Object has no fields yet, return default + VMValue::Integer(0) }; self.values.insert(*dst, field_value); @@ -392,13 +396,19 @@ impl VM { }, MirInstruction::RefSet { reference, field, value } => { - // For now, field setting is simplified - // In a real implementation, this would dereference the reference and set the field - let _ref_value = self.get_value(*reference)?; - let _new_value = self.get_value(*value)?; + // Get the value to set + let new_value = self.get_value(*value)?; + + // Ensure object has field storage + if !self.object_fields.contains_key(reference) { + self.object_fields.insert(*reference, HashMap::new()); + } + + // Set the field + if let Some(fields) = self.object_fields.get_mut(reference) { + fields.insert(field.clone(), new_value); + } - // TODO: Implement proper Box field setting - // For now, this is a no-op that doesn't actually set anything Ok(ControlFlow::Continue) }, diff --git a/src/mir/builder.rs b/src/mir/builder.rs index 800f7ef6..0475cd6e 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -123,8 +123,11 @@ impl MirBuilder { }, ASTNode::Assignment { target, value, .. } => { - // For now, assume target is a variable identifier - if let ASTNode::Variable { name, .. } = target.as_ref() { + // Check if target is a field access for RefSet + if let ASTNode::FieldAccess { object, field, .. } = target.as_ref() { + self.build_field_assignment(*object.clone(), field.clone(), *value.clone()) + } else if let ASTNode::Variable { name, .. } = target.as_ref() { + // Plain variable assignment - existing behavior self.build_assignment(name.clone(), *value.clone()) } else { Err("Complex assignment targets not yet supported in MIR".to_string()) @@ -196,6 +199,10 @@ impl MirBuilder { self.build_field_access(*object.clone(), field.clone()) }, + ASTNode::New { class, arguments, .. } => { + self.build_new_expression(class.clone(), arguments.clone()) + }, + _ => { Err(format!("Unsupported AST node type: {:?}", ast)) } @@ -666,24 +673,56 @@ impl MirBuilder { // First, build the object expression to get its ValueId let object_value = self.build_expression(object)?; - // Create a reference to the object - let ref_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::RefNew { - dst: ref_id, - box_val: object_value, - })?; - - // Get the field from the reference + // Get the field from the object using RefGet let result_id = self.value_gen.next(); self.emit_instruction(MirInstruction::RefGet { dst: result_id, - reference: ref_id, + reference: object_value, field, })?; Ok(result_id) } + /// Build new expression: new ClassName(arguments) + fn build_new_expression(&mut self, class: String, arguments: Vec) -> Result { + // For Phase 6.1, we'll create a simple RefNew without processing arguments + // In a full implementation, arguments would be used for constructor calls + let dst = self.value_gen.next(); + + // For now, create a "box type" value representing the class + let type_value = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: type_value, + value: ConstValue::String(class), + })?; + + // Create the reference using RefNew + self.emit_instruction(MirInstruction::RefNew { + dst, + box_val: type_value, + })?; + + Ok(dst) + } + + /// Build field assignment: object.field = value + fn build_field_assignment(&mut self, object: ASTNode, field: String, value: ASTNode) -> Result { + // Build the object and value expressions + let object_value = self.build_expression(object)?; + let value_result = self.build_expression(value)?; + + // Set the field using RefSet + self.emit_instruction(MirInstruction::RefSet { + reference: object_value, + field, + value: value_result, + })?; + + // Return the assigned value + Ok(value_result) + } + /// Start a new basic block fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> { if let Some(ref mut function) = self.current_function {