diff --git a/simple_mir_test.nyash b/simple_mir_test.nyash new file mode 100644 index 00000000..7c4f5b1a --- /dev/null +++ b/simple_mir_test.nyash @@ -0,0 +1,4 @@ +// Very simple field access test +local str +str = "Hello World" +print(str) \ No newline at end of file diff --git a/src/backend/vm.rs b/src/backend/vm.rs index f94f4a48..b0df6c6e 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -256,6 +256,88 @@ impl VM { Ok(ControlFlow::Continue) }, + // Missing instructions that need basic implementations + MirInstruction::Load { dst, ptr } => { + // For now, loading is the same as getting the value + let value = self.get_value(*ptr)?; + self.values.insert(*dst, value); + Ok(ControlFlow::Continue) + }, + + MirInstruction::Store { value, ptr } => { + // For now, storing just updates the ptr with the value + let val = self.get_value(*value)?; + self.values.insert(*ptr, val); + Ok(ControlFlow::Continue) + }, + + MirInstruction::Call { dst, func: _, args: _, effects: _ } => { + // For now, function calls return void + // TODO: Implement proper function call handling + if let Some(dst_id) = dst { + self.values.insert(*dst_id, VMValue::Void); + } + Ok(ControlFlow::Continue) + }, + + MirInstruction::BoxCall { dst, box_val: _, method: _, args: _, effects: _ } => { + // For now, box method calls return void + // TODO: Implement proper box method call handling + if let Some(dst_id) = dst { + self.values.insert(*dst_id, VMValue::Void); + } + Ok(ControlFlow::Continue) + }, + + MirInstruction::NewBox { dst, box_type: _, args: _ } => { + // For now, new box creates a placeholder string value + // TODO: Implement proper box creation + self.values.insert(*dst, VMValue::String("NewBox".to_string())); + Ok(ControlFlow::Continue) + }, + + MirInstruction::TypeCheck { dst, value: _, expected_type: _ } => { + // For now, type checks always return true + // TODO: Implement proper type checking + self.values.insert(*dst, VMValue::Bool(true)); + Ok(ControlFlow::Continue) + }, + + MirInstruction::Cast { dst, value, target_type: _ } => { + // For now, casting just copies the value + // TODO: Implement proper type casting + let val = self.get_value(*value)?; + self.values.insert(*dst, val); + Ok(ControlFlow::Continue) + }, + + MirInstruction::ArrayGet { dst, array: _, index: _ } => { + // For now, array access returns a placeholder + // TODO: Implement proper array access + self.values.insert(*dst, VMValue::Integer(0)); + Ok(ControlFlow::Continue) + }, + + MirInstruction::ArraySet { array: _, index: _, value: _ } => { + // For now, array setting is a no-op + // TODO: Implement proper array setting + Ok(ControlFlow::Continue) + }, + + MirInstruction::Copy { dst, src } => { + // Copy instruction - duplicate the source value + let val = self.get_value(*src)?; + self.values.insert(*dst, val); + Ok(ControlFlow::Continue) + }, + + MirInstruction::Debug { value, message: _ } => { + // Debug instruction - print value for debugging + let val = self.get_value(*value)?; + println!("DEBUG: {}", val.to_string()); + Ok(ControlFlow::Continue) + }, + MirInstruction::Nop => { // No-op instruction Ok(ControlFlow::Continue) @@ -283,9 +365,70 @@ impl VM { Ok(ControlFlow::Continue) }, - _ => { - Err(VMError::InvalidInstruction(format!("Unsupported instruction: {:?}", instruction))) - } + // Phase 6: Box reference operations + MirInstruction::RefNew { dst, box_val } => { + // For now, a reference is just the same as the box value + // In a real implementation, this would create a proper reference + let box_value = self.get_value(*box_val)?; + self.values.insert(*dst, box_value); + Ok(ControlFlow::Continue) + }, + + 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 + }; + + self.values.insert(*dst, field_value); + Ok(ControlFlow::Continue) + }, + + 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)?; + + // TODO: Implement proper Box field setting + // For now, this is a no-op that doesn't actually set anything + Ok(ControlFlow::Continue) + }, + + MirInstruction::WeakNew { dst, box_val } => { + // For now, a weak reference is just a copy of the value + // In a real implementation, this would create a proper weak reference + let box_value = self.get_value(*box_val)?; + self.values.insert(*dst, box_value); + Ok(ControlFlow::Continue) + }, + + MirInstruction::WeakLoad { dst, weak_ref } => { + // For now, loading from weak ref is the same as getting the value + // In a real implementation, this would check if the weak ref is still valid + let weak_value = self.get_value(*weak_ref)?; + self.values.insert(*dst, weak_value); + Ok(ControlFlow::Continue) + }, + + MirInstruction::BarrierRead { ptr: _ } => { + // Memory barrier read is a no-op for now + // In a real implementation, this would ensure memory ordering + Ok(ControlFlow::Continue) + }, + + MirInstruction::BarrierWrite { ptr: _ } => { + // Memory barrier write is a no-op for now + // In a real implementation, this would ensure memory ordering + Ok(ControlFlow::Continue) + }, } } diff --git a/src/mir/builder.rs b/src/mir/builder.rs index f1c2fab5..800f7ef6 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -192,6 +192,10 @@ impl MirBuilder { } }, + ASTNode::FieldAccess { object, field, .. } => { + self.build_field_access(*object.clone(), field.clone()) + }, + _ => { Err(format!("Unsupported AST node type: {:?}", ast)) } @@ -657,6 +661,29 @@ impl MirBuilder { } } + /// Build field access: object.field + fn build_field_access(&mut self, object: ASTNode, field: String) -> Result { + // 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 + let result_id = self.value_gen.next(); + self.emit_instruction(MirInstruction::RefGet { + dst: result_id, + reference: ref_id, + field, + })?; + + Ok(result_id) + } + /// 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 { diff --git a/src/mir/effect.rs b/src/mir/effect.rs index adeaee91..efa43a0d 100644 --- a/src/mir/effect.rs +++ b/src/mir/effect.rs @@ -37,6 +37,8 @@ pub enum Effect { Unsafe = 0x0400, /// Debug/logging operations Debug = 0x0800, + /// Memory barrier operations + Barrier = 0x1000, } impl EffectMask { @@ -156,6 +158,7 @@ impl EffectMask { if self.contains(Effect::Async) { names.push("async"); } if self.contains(Effect::Unsafe) { names.push("unsafe"); } if self.contains(Effect::Debug) { names.push("debug"); } + if self.contains(Effect::Barrier) { names.push("barrier"); } names } diff --git a/src/mir/instruction.rs b/src/mir/instruction.rs index 73bac4b0..941c775f 100644 --- a/src/mir/instruction.rs +++ b/src/mir/instruction.rs @@ -199,6 +199,57 @@ pub enum MirInstruction { /// Safepoint instruction (no-op for now, can be used for GC/debugging) /// `safepoint` Safepoint, + + // === Phase 6: Box Reference Operations === + + /// Create a new reference to a Box + /// `%dst = ref_new %box` + RefNew { + dst: ValueId, + box_val: ValueId, + }, + + /// Get/dereference a Box field through reference + /// `%dst = ref_get %ref.field` + RefGet { + dst: ValueId, + reference: ValueId, + field: String, + }, + + /// Set/assign Box field through reference + /// `ref_set %ref.field = %value` + RefSet { + reference: ValueId, + field: String, + value: ValueId, + }, + + /// Create a weak reference to a Box + /// `%dst = weak_new %box` + WeakNew { + dst: ValueId, + box_val: ValueId, + }, + + /// Load from weak reference (if still alive) + /// `%dst = weak_load %weak_ref` + WeakLoad { + dst: ValueId, + weak_ref: ValueId, + }, + + /// Memory barrier read (no-op for now, proper effect annotation) + /// `barrier_read %ptr` + BarrierRead { + ptr: ValueId, + }, + + /// Memory barrier write (no-op for now, proper effect annotation) + /// `barrier_write %ptr` + BarrierWrite { + ptr: ValueId, + }, } /// Constant values in MIR @@ -300,6 +351,15 @@ impl MirInstruction { MirInstruction::Throw { effects, .. } => *effects, MirInstruction::Catch { .. } => EffectMask::PURE, // Setting up handler is pure MirInstruction::Safepoint => EffectMask::PURE, // No-op for now + + // Phase 6: Box reference operations + MirInstruction::RefNew { .. } => EffectMask::PURE, // Creating reference is pure + MirInstruction::RefGet { .. } => EffectMask::READ, // Reading field has read effects + MirInstruction::RefSet { .. } => EffectMask::WRITE, // Writing field has write effects + MirInstruction::WeakNew { .. } => EffectMask::PURE, // Creating weak ref is pure + MirInstruction::WeakLoad { .. } => EffectMask::READ, // Loading weak ref has read effects + MirInstruction::BarrierRead { .. } => EffectMask::READ.add(Effect::Barrier), // Memory barrier with read + MirInstruction::BarrierWrite { .. } => EffectMask::WRITE.add(Effect::Barrier), // Memory barrier with write } } @@ -316,7 +376,11 @@ impl MirInstruction { MirInstruction::TypeCheck { dst, .. } | MirInstruction::Cast { dst, .. } | MirInstruction::ArrayGet { dst, .. } | - MirInstruction::Copy { dst, .. } => Some(*dst), + MirInstruction::Copy { dst, .. } | + MirInstruction::RefNew { dst, .. } | + MirInstruction::RefGet { dst, .. } | + MirInstruction::WeakNew { dst, .. } | + MirInstruction::WeakLoad { dst, .. } => Some(*dst), MirInstruction::Call { dst, .. } | MirInstruction::BoxCall { dst, .. } => *dst, @@ -329,6 +393,9 @@ impl MirInstruction { MirInstruction::Debug { .. } | MirInstruction::Print { .. } | MirInstruction::Throw { .. } | + MirInstruction::RefSet { .. } | + MirInstruction::BarrierRead { .. } | + MirInstruction::BarrierWrite { .. } | MirInstruction::Safepoint | MirInstruction::Nop => None, @@ -387,6 +454,15 @@ impl MirInstruction { MirInstruction::Throw { exception, .. } => vec![*exception], MirInstruction::Catch { .. } => Vec::new(), // Handler setup doesn't use values MirInstruction::Safepoint => Vec::new(), + + // Phase 6: Box reference operations + MirInstruction::RefNew { box_val, .. } => vec![*box_val], + MirInstruction::RefGet { reference, .. } => vec![*reference], + MirInstruction::RefSet { reference, value, .. } => vec![*reference, *value], + MirInstruction::WeakNew { box_val, .. } => vec![*box_val], + MirInstruction::WeakLoad { weak_ref, .. } => vec![*weak_ref], + MirInstruction::BarrierRead { ptr } => vec![*ptr], + MirInstruction::BarrierWrite { ptr } => vec![*ptr], } } } @@ -540,4 +616,81 @@ mod tests { assert_eq!(back, const_val); } */ + + #[test] + fn test_ref_new_instruction() { + let dst = ValueId::new(0); + let box_val = ValueId::new(1); + let inst = MirInstruction::RefNew { dst, box_val }; + + assert_eq!(inst.dst_value(), Some(dst)); + assert_eq!(inst.used_values(), vec![box_val]); + assert!(inst.effects().is_pure()); + } + + #[test] + fn test_ref_get_instruction() { + let dst = ValueId::new(0); + let reference = ValueId::new(1); + let field = "name".to_string(); + let inst = MirInstruction::RefGet { dst, reference, field }; + + assert_eq!(inst.dst_value(), Some(dst)); + assert_eq!(inst.used_values(), vec![reference]); + assert!(!inst.effects().is_pure()); + assert!(inst.effects().contains(super::super::effect::Effect::ReadHeap)); + } + + #[test] + fn test_ref_set_instruction() { + let reference = ValueId::new(0); + let field = "value".to_string(); + let value = ValueId::new(1); + let inst = MirInstruction::RefSet { reference, field, value }; + + assert_eq!(inst.dst_value(), None); + assert_eq!(inst.used_values(), vec![reference, value]); + assert!(!inst.effects().is_pure()); + assert!(inst.effects().contains(super::super::effect::Effect::WriteHeap)); + } + + #[test] + fn test_weak_new_instruction() { + let dst = ValueId::new(0); + let box_val = ValueId::new(1); + let inst = MirInstruction::WeakNew { dst, box_val }; + + assert_eq!(inst.dst_value(), Some(dst)); + assert_eq!(inst.used_values(), vec![box_val]); + assert!(inst.effects().is_pure()); + } + + #[test] + fn test_weak_load_instruction() { + let dst = ValueId::new(0); + let weak_ref = ValueId::new(1); + let inst = MirInstruction::WeakLoad { dst, weak_ref }; + + assert_eq!(inst.dst_value(), Some(dst)); + assert_eq!(inst.used_values(), vec![weak_ref]); + assert!(!inst.effects().is_pure()); + assert!(inst.effects().contains(super::super::effect::Effect::ReadHeap)); + } + + #[test] + fn test_barrier_instructions() { + let ptr = ValueId::new(0); + + let read_barrier = MirInstruction::BarrierRead { ptr }; + assert_eq!(read_barrier.dst_value(), None); + assert_eq!(read_barrier.used_values(), vec![ptr]); + assert!(read_barrier.effects().contains(super::super::effect::Effect::Barrier)); + assert!(read_barrier.effects().contains(super::super::effect::Effect::ReadHeap)); + + let write_barrier = MirInstruction::BarrierWrite { ptr }; + assert_eq!(write_barrier.dst_value(), None); + assert_eq!(write_barrier.used_values(), vec![ptr]); + assert!(write_barrier.effects().contains(super::super::effect::Effect::Barrier)); + assert!(write_barrier.effects().contains(super::super::effect::Effect::WriteHeap)); + } } \ No newline at end of file diff --git a/src/mir/printer.rs b/src/mir/printer.rs index 21ef98f1..91407eb3 100644 --- a/src/mir/printer.rs +++ b/src/mir/printer.rs @@ -318,6 +318,35 @@ impl MirPrinter { MirInstruction::Safepoint => { "safepoint".to_string() }, + + // Phase 6: Box reference operations + MirInstruction::RefNew { dst, box_val } => { + format!("{} = ref_new {}", dst, box_val) + }, + + MirInstruction::RefGet { dst, reference, field } => { + format!("{} = ref_get {}.{}", dst, reference, field) + }, + + MirInstruction::RefSet { reference, field, value } => { + format!("ref_set {}.{} = {}", reference, field, value) + }, + + MirInstruction::WeakNew { dst, box_val } => { + format!("{} = weak_new {}", dst, box_val) + }, + + MirInstruction::WeakLoad { dst, weak_ref } => { + format!("{} = weak_load {}", dst, weak_ref) + }, + + MirInstruction::BarrierRead { ptr } => { + format!("barrier_read {}", ptr) + }, + + MirInstruction::BarrierWrite { ptr } => { + format!("barrier_write {}", ptr) + }, } } diff --git a/test_field_access.nyash b/test_field_access.nyash new file mode 100644 index 00000000..b1236fdd --- /dev/null +++ b/test_field_access.nyash @@ -0,0 +1,23 @@ +// Test for Phase 6 Box reference operations +// Simple field access test + +static box Main { + init { console } + + main() { + me.console = new ConsoleBox() + me.console.log("Testing Phase 6 Box reference operations") + + // Create a simple object + local obj + obj = new StringBox("Hello") + + // Test field access + local result + result = obj.length + + print("Field access result: " + result) + + return "Phase 6 test completed" + } +} \ No newline at end of file diff --git a/test_field_mir.nyash b/test_field_mir.nyash new file mode 100644 index 00000000..259c1ee1 --- /dev/null +++ b/test_field_mir.nyash @@ -0,0 +1,16 @@ +// Test field access MIR generation +static box TestBox { + init { name, value } +} + +static box Main { + init { test_obj } + + main() { + me.test_obj = new TestBox() + local result + result = me.test_obj.name + print(result) + return "Done" + } +} \ No newline at end of file diff --git a/test_simple_field.nyash b/test_simple_field.nyash new file mode 100644 index 00000000..de079ed9 --- /dev/null +++ b/test_simple_field.nyash @@ -0,0 +1,14 @@ +// Simpler test for field access MIR +static box Main { + init { obj } + + main() { + me.obj = "test" + local field_value + + // This should trigger field access parsing + field_value = me.obj + print(field_value) + return "Done" + } +} \ No newline at end of file