Implement core AST lowering for New/FieldAccess to MIR Ref ops with basic VM field storage
Co-authored-by: moe-charm <217100418+moe-charm@users.noreply.github.com>
This commit is contained in:
@ -110,6 +110,8 @@ pub struct VM {
|
|||||||
pc: usize,
|
pc: usize,
|
||||||
/// Return value from last execution
|
/// Return value from last execution
|
||||||
last_result: Option<VMValue>,
|
last_result: Option<VMValue>,
|
||||||
|
/// Simple field storage for objects (maps reference -> field -> value)
|
||||||
|
object_fields: HashMap<ValueId, HashMap<String, VMValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VM {
|
impl VM {
|
||||||
@ -121,6 +123,7 @@ impl VM {
|
|||||||
current_block: None,
|
current_block: None,
|
||||||
pc: 0,
|
pc: 0,
|
||||||
last_result: None,
|
last_result: None,
|
||||||
|
object_fields: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,16 +378,17 @@ impl VM {
|
|||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::RefGet { dst, reference, field } => {
|
MirInstruction::RefGet { dst, reference, field } => {
|
||||||
// For now, field access is simplified - we'll treat it as accessing a property
|
// Get field value from object
|
||||||
// In a real implementation, this would dereference the reference and access the field
|
let field_value = if let Some(fields) = self.object_fields.get(reference) {
|
||||||
let _ref_value = self.get_value(*reference)?;
|
if let Some(value) = fields.get(field) {
|
||||||
|
value.clone()
|
||||||
// Simplified: return a placeholder value for field access
|
} else {
|
||||||
// TODO: Implement proper Box field access
|
// Field not set yet, return default
|
||||||
let field_value = match field.as_str() {
|
VMValue::Integer(0)
|
||||||
"length" => VMValue::Integer(0), // Default length
|
}
|
||||||
"size" => VMValue::Integer(0), // Default size
|
} else {
|
||||||
_ => VMValue::String(format!("field_{}", field)), // Default field value
|
// Object has no fields yet, return default
|
||||||
|
VMValue::Integer(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.values.insert(*dst, field_value);
|
self.values.insert(*dst, field_value);
|
||||||
@ -392,13 +396,19 @@ impl VM {
|
|||||||
},
|
},
|
||||||
|
|
||||||
MirInstruction::RefSet { reference, field, value } => {
|
MirInstruction::RefSet { reference, field, value } => {
|
||||||
// For now, field setting is simplified
|
// Get the value to set
|
||||||
// In a real implementation, this would dereference the reference and set the field
|
let new_value = self.get_value(*value)?;
|
||||||
let _ref_value = self.get_value(*reference)?;
|
|
||||||
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)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -123,8 +123,11 @@ impl MirBuilder {
|
|||||||
},
|
},
|
||||||
|
|
||||||
ASTNode::Assignment { target, value, .. } => {
|
ASTNode::Assignment { target, value, .. } => {
|
||||||
// For now, assume target is a variable identifier
|
// Check if target is a field access for RefSet
|
||||||
if let ASTNode::Variable { name, .. } = target.as_ref() {
|
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())
|
self.build_assignment(name.clone(), *value.clone())
|
||||||
} else {
|
} else {
|
||||||
Err("Complex assignment targets not yet supported in MIR".to_string())
|
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())
|
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))
|
Err(format!("Unsupported AST node type: {:?}", ast))
|
||||||
}
|
}
|
||||||
@ -666,24 +673,56 @@ impl MirBuilder {
|
|||||||
// First, build the object expression to get its ValueId
|
// First, build the object expression to get its ValueId
|
||||||
let object_value = self.build_expression(object)?;
|
let object_value = self.build_expression(object)?;
|
||||||
|
|
||||||
// Create a reference to the object
|
// Get the field from the object using RefGet
|
||||||
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
|
|
||||||
let result_id = self.value_gen.next();
|
let result_id = self.value_gen.next();
|
||||||
self.emit_instruction(MirInstruction::RefGet {
|
self.emit_instruction(MirInstruction::RefGet {
|
||||||
dst: result_id,
|
dst: result_id,
|
||||||
reference: ref_id,
|
reference: object_value,
|
||||||
field,
|
field,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(result_id)
|
Ok(result_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build new expression: new ClassName(arguments)
|
||||||
|
fn build_new_expression(&mut self, class: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||||
|
// 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<ValueId, String> {
|
||||||
|
// 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
|
/// Start a new basic block
|
||||||
fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> {
|
fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> {
|
||||||
if let Some(ref mut function) = self.current_function {
|
if let Some(ref mut function) = self.current_function {
|
||||||
|
|||||||
Reference in New Issue
Block a user