diff --git a/src/backend/vm.rs b/src/backend/vm.rs index 89d4c32c..2e52a860 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -178,8 +178,10 @@ impl VM { let mut should_return = None; // Execute instructions in this block + println!("Executing block {} with {} instructions", current_block, block.instructions.len()); for (index, instruction) in block.instructions.iter().enumerate() { self.pc = index; + println!(" Instruction {}: {:?}", index, instruction); match self.execute_instruction(instruction)? { ControlFlow::Continue => continue, @@ -194,6 +196,8 @@ impl VM { } } + println!("Block execution finished. should_return: {:?}, next_block: {:?}", should_return.is_some(), next_block.is_some()); + // Handle control flow if let Some(return_value) = should_return { return Ok(return_value); @@ -209,6 +213,7 @@ impl VM { /// Execute a single instruction fn execute_instruction(&mut self, instruction: &MirInstruction) -> Result { + println!("Executing instruction: {:?}", instruction); match instruction { MirInstruction::Const { dst, value } => { let vm_value = VMValue::from(value); @@ -247,8 +252,11 @@ impl VM { MirInstruction::Return { value } => { let return_value = if let Some(val_id) = value { - self.get_value(*val_id)? + let val = self.get_value(*val_id)?; + println!("Return: returning value from {:?} = {:?}", val_id, val); + val } else { + println!("Return: returning void (no value specified)"); VMValue::Void }; Ok(ControlFlow::Return(return_value)) @@ -463,10 +471,14 @@ impl VM { // Phase 7: Async/Future Operations MirInstruction::FutureNew { dst, value } => { let initial_value = self.get_value(*value)?; + println!("FutureNew: initial_value = {:?}", initial_value); let future = crate::boxes::future::FutureBox::new(); // Convert VMValue to NyashBox and set it in the future - future.set_result(initial_value.to_nyash_box()); + let nyash_box = initial_value.to_nyash_box(); + println!("FutureNew: converted to NyashBox type = {}", nyash_box.type_name()); + future.set_result(nyash_box); self.values.insert(*dst, VMValue::Future(future)); + println!("FutureNew: stored Future in dst = {:?}", dst); Ok(ControlFlow::Continue) }, @@ -484,12 +496,16 @@ impl VM { MirInstruction::Await { dst, future } => { let future_val = self.get_value(*future)?; + println!("Await: future_val = {:?}", future_val); if let VMValue::Future(ref future_box) = future_val { // This blocks until the future is ready let result = future_box.get(); + println!("Await: future.get() returned type = {}", result.type_name()); + println!("Await: future.get() string = {}", result.to_string_box().value); // Convert NyashBox back to VMValue let vm_value = VMValue::from_nyash_box(result); + println!("Await: converted back to VMValue = {:?}", vm_value); self.values.insert(*dst, vm_value); Ok(ControlFlow::Continue) } else { diff --git a/tests/mir_phase7_async_ops.rs b/tests/mir_phase7_async_ops.rs new file mode 100644 index 00000000..32e94f63 --- /dev/null +++ b/tests/mir_phase7_async_ops.rs @@ -0,0 +1,387 @@ +/*! + * Phase 7 MIR Builder & VM Test - Async Operations (nowait/await) + * + * Tests AST → MIR lowering and VM execution for Phase 7 async operations + */ + +use nyash_rust::mir::{MirBuilder, MirPrinter}; +use nyash_rust::backend::VM; +use nyash_rust::ast::{ASTNode, LiteralValue, Span}; +use std::collections::HashMap; + +#[test] +fn test_mir_phase7_basic_nowait_await() { + // Build AST equivalent to: + // static box Main { + // main() { + // nowait f1 = 42; + // local result = await f1; + // return result + // } + // } + + let mut main_methods = HashMap::new(); + + // Create main method body + let main_body = vec![ + // nowait f1 = 42 + ASTNode::Nowait { + variable: "f1".to_string(), + expression: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(42), + span: Span::unknown(), + }), + span: Span::unknown(), + }, + // local result = await f1 + ASTNode::Local { + variables: vec!["result".to_string()], + initial_values: vec![Some(Box::new(ASTNode::AwaitExpression { + expression: Box::new(ASTNode::Variable { + name: "f1".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + }))], + span: Span::unknown(), + }, + // return result + ASTNode::Return { + value: Some(Box::new(ASTNode::Variable { + name: "result".to_string(), + span: Span::unknown(), + })), + span: Span::unknown(), + }, + ]; + + // Create main method + let main_method = ASTNode::FunctionDeclaration { + name: "main".to_string(), + params: vec![], + body: main_body, + is_static: false, + is_override: false, + span: Span::unknown(), + }; + + main_methods.insert("main".to_string(), main_method); + + // Create static box Main + let ast = ASTNode::BoxDeclaration { + name: "Main".to_string(), + fields: vec![], + methods: main_methods, + constructors: HashMap::new(), + init_fields: vec![], + weak_fields: vec![], + is_interface: false, + extends: vec![], + implements: vec![], + type_parameters: vec![], + is_static: true, + static_init: None, + span: Span::unknown(), + }; + + // Build MIR + let mut builder = MirBuilder::new(); + let result = builder.build_module(ast); + + if let Err(e) = &result { + println!("MIR build error: {}", e); + } + assert!(result.is_ok(), "MIR build should succeed"); + + let module = result.unwrap(); + + // Print MIR for debugging + let printer = MirPrinter::new(); + let mir_output = printer.print_module(&module); + println!("Generated MIR:"); + println!("{}", mir_output); + + // Verify MIR contains expected instructions + let function = module.get_function("main").unwrap(); + let instructions: Vec<_> = function.blocks.values() + .flat_map(|block| &block.instructions) + .collect(); + + // Should contain FutureNew instruction + let has_future_new = instructions.iter().any(|inst| { + matches!(inst, nyash_rust::mir::MirInstruction::FutureNew { .. }) + }); + assert!(has_future_new, "MIR should contain FutureNew instruction"); + + // Should contain Await instruction + let has_await = instructions.iter().any(|inst| { + matches!(inst, nyash_rust::mir::MirInstruction::Await { .. }) + }); + assert!(has_await, "MIR should contain Await instruction"); + + // Test VM execution + let mut vm = VM::new(); + let execution_result = vm.execute_module(&module); + + if let Err(e) = &execution_result { + println!("VM execution error: {}", e); + } + assert!(execution_result.is_ok(), "VM execution should succeed"); + + let final_value = execution_result.unwrap(); + println!("VM execution result: {}", final_value.to_string_box().value); + + // Should return 42 + assert_eq!(final_value.to_string_box().value, "42"); +} + +#[test] +fn test_mir_phase7_multiple_nowait_await() { + // Build AST equivalent to: + // static box Main { + // main() { + // nowait f1 = 10; + // nowait f2 = 20; + // local result1 = await f1; + // local result2 = await f2; + // return result1 + result2 + // } + // } + + let mut main_methods = HashMap::new(); + + // Create main method body + let main_body = vec![ + // nowait f1 = 10 + ASTNode::Nowait { + variable: "f1".to_string(), + expression: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(10), + span: Span::unknown(), + }), + span: Span::unknown(), + }, + // nowait f2 = 20 + ASTNode::Nowait { + variable: "f2".to_string(), + expression: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(20), + span: Span::unknown(), + }), + span: Span::unknown(), + }, + // local result1 = await f1 + ASTNode::Local { + variables: vec!["result1".to_string()], + initial_values: vec![Some(Box::new(ASTNode::AwaitExpression { + expression: Box::new(ASTNode::Variable { + name: "f1".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + }))], + span: Span::unknown(), + }, + // local result2 = await f2 + ASTNode::Local { + variables: vec!["result2".to_string()], + initial_values: vec![Some(Box::new(ASTNode::AwaitExpression { + expression: Box::new(ASTNode::Variable { + name: "f2".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + }))], + span: Span::unknown(), + }, + // return result1 + result2 + ASTNode::Return { + value: Some(Box::new(ASTNode::BinaryOp { + left: Box::new(ASTNode::Variable { + name: "result1".to_string(), + span: Span::unknown(), + }), + operator: nyash_rust::ast::BinaryOperator::Add, + right: Box::new(ASTNode::Variable { + name: "result2".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + })), + span: Span::unknown(), + }, + ]; + + // Create main method + let main_method = ASTNode::FunctionDeclaration { + name: "main".to_string(), + params: vec![], + body: main_body, + is_static: false, + is_override: false, + span: Span::unknown(), + }; + + main_methods.insert("main".to_string(), main_method); + + // Create static box Main + let ast = ASTNode::BoxDeclaration { + name: "Main".to_string(), + fields: vec![], + methods: main_methods, + constructors: HashMap::new(), + init_fields: vec![], + weak_fields: vec![], + is_interface: false, + extends: vec![], + implements: vec![], + type_parameters: vec![], + is_static: true, + static_init: None, + span: Span::unknown(), + }; + + // Build MIR + let mut builder = MirBuilder::new(); + let result = builder.build_module(ast); + + assert!(result.is_ok(), "MIR build should succeed"); + let module = result.unwrap(); + + // Print MIR for debugging + let printer = MirPrinter::new(); + let mir_output = printer.print_module(&module); + println!("Generated MIR for multiple nowait/await:"); + println!("{}", mir_output); + + // Test VM execution + let mut vm = VM::new(); + let execution_result = vm.execute_module(&module); + + assert!(execution_result.is_ok(), "VM execution should succeed"); + let final_value = execution_result.unwrap(); + println!("VM execution result: {}", final_value.to_string_box().value); + + // Should return 30 (10 + 20) + assert_eq!(final_value.to_string_box().value, "30"); +} + +#[test] +fn test_mir_phase7_nested_await() { + // Build AST equivalent to: + // static box Main { + // main() { + // nowait outer = { + // nowait inner = 5; + // await inner * 2 + // }; + // return await outer + // } + // } + + let mut main_methods = HashMap::new(); + + // Create inner computation: nowait inner = 5; await inner * 2 + let inner_computation = ASTNode::Program { + statements: vec![ + ASTNode::Nowait { + variable: "inner".to_string(), + expression: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(5), + span: Span::unknown(), + }), + span: Span::unknown(), + }, + ASTNode::BinaryOp { + left: Box::new(ASTNode::AwaitExpression { + expression: Box::new(ASTNode::Variable { + name: "inner".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + }), + operator: nyash_rust::ast::BinaryOperator::Multiply, + right: Box::new(ASTNode::Literal { + value: LiteralValue::Integer(2), + span: Span::unknown(), + }), + span: Span::unknown(), + }, + ], + span: Span::unknown(), + }; + + // Create main method body + let main_body = vec![ + // nowait outer = { ... } + ASTNode::Nowait { + variable: "outer".to_string(), + expression: Box::new(inner_computation), + span: Span::unknown(), + }, + // return await outer + ASTNode::Return { + value: Some(Box::new(ASTNode::AwaitExpression { + expression: Box::new(ASTNode::Variable { + name: "outer".to_string(), + span: Span::unknown(), + }), + span: Span::unknown(), + })), + span: Span::unknown(), + }, + ]; + + // Create main method + let main_method = ASTNode::FunctionDeclaration { + name: "main".to_string(), + params: vec![], + body: main_body, + is_static: false, + is_override: false, + span: Span::unknown(), + }; + + main_methods.insert("main".to_string(), main_method); + + // Create static box Main + let ast = ASTNode::BoxDeclaration { + name: "Main".to_string(), + fields: vec![], + methods: main_methods, + constructors: HashMap::new(), + init_fields: vec![], + weak_fields: vec![], + is_interface: false, + extends: vec![], + implements: vec![], + type_parameters: vec![], + is_static: true, + static_init: None, + span: Span::unknown(), + }; + + // Build MIR + let mut builder = MirBuilder::new(); + let result = builder.build_module(ast); + + assert!(result.is_ok(), "MIR build should succeed"); + let module = result.unwrap(); + + // Print MIR for debugging + let printer = MirPrinter::new(); + let mir_output = printer.print_module(&module); + println!("Generated MIR for nested await:"); + println!("{}", mir_output); + + // Test VM execution + let mut vm = VM::new(); + let execution_result = vm.execute_module(&module); + + assert!(execution_result.is_ok(), "VM execution should succeed"); + let final_value = execution_result.unwrap(); + println!("VM execution result: {}", final_value.to_string_box().value); + + // Should return 10 (5 * 2) + assert_eq!(final_value.to_string_box().value, "10"); +} \ No newline at end of file