Merge branch 'main' of github.com-moecharm:moe-charm/nyash
This commit is contained in:
@ -41,6 +41,7 @@ pub enum VMValue {
|
|||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(String),
|
String(String),
|
||||||
|
Future(crate::boxes::future::FutureBox),
|
||||||
Void,
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +53,7 @@ impl VMValue {
|
|||||||
VMValue::Float(f) => Box::new(StringBox::new(&f.to_string())), // Simplified for now
|
VMValue::Float(f) => Box::new(StringBox::new(&f.to_string())), // Simplified for now
|
||||||
VMValue::Bool(b) => Box::new(BoolBox::new(*b)),
|
VMValue::Bool(b) => Box::new(BoolBox::new(*b)),
|
||||||
VMValue::String(s) => Box::new(StringBox::new(s)),
|
VMValue::String(s) => Box::new(StringBox::new(s)),
|
||||||
|
VMValue::Future(f) => Box::new(f.clone()),
|
||||||
VMValue::Void => Box::new(VoidBox::new()),
|
VMValue::Void => Box::new(VoidBox::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,6 +65,7 @@ impl VMValue {
|
|||||||
VMValue::Float(f) => f.to_string(),
|
VMValue::Float(f) => f.to_string(),
|
||||||
VMValue::Bool(b) => b.to_string(),
|
VMValue::Bool(b) => b.to_string(),
|
||||||
VMValue::String(s) => s.clone(),
|
VMValue::String(s) => s.clone(),
|
||||||
|
VMValue::Future(f) => f.to_string_box().value,
|
||||||
VMValue::Void => "void".to_string(),
|
VMValue::Void => "void".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,6 +86,23 @@ impl VMValue {
|
|||||||
_ => Err(VMError::TypeError(format!("Expected bool, got {:?}", self))),
|
_ => Err(VMError::TypeError(format!("Expected bool, got {:?}", self))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert from NyashBox to VMValue
|
||||||
|
pub fn from_nyash_box(nyash_box: Box<dyn crate::box_trait::NyashBox>) -> VMValue {
|
||||||
|
// Try to downcast to known types
|
||||||
|
if let Some(int_box) = nyash_box.as_any().downcast_ref::<IntegerBox>() {
|
||||||
|
VMValue::Integer(int_box.value)
|
||||||
|
} else if let Some(bool_box) = nyash_box.as_any().downcast_ref::<BoolBox>() {
|
||||||
|
VMValue::Bool(bool_box.value)
|
||||||
|
} else if let Some(string_box) = nyash_box.as_any().downcast_ref::<StringBox>() {
|
||||||
|
VMValue::String(string_box.value.clone())
|
||||||
|
} else if let Some(future_box) = nyash_box.as_any().downcast_ref::<crate::boxes::future::FutureBox>() {
|
||||||
|
VMValue::Future(future_box.clone())
|
||||||
|
} else {
|
||||||
|
// For any other type, convert to string representation
|
||||||
|
VMValue::String(nyash_box.to_string_box().value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ConstValue> for VMValue {
|
impl From<&ConstValue> for VMValue {
|
||||||
@ -158,8 +178,10 @@ impl VM {
|
|||||||
let mut should_return = None;
|
let mut should_return = None;
|
||||||
|
|
||||||
// Execute instructions in this block
|
// Execute instructions in this block
|
||||||
|
println!("Executing block {} with {} instructions", current_block, block.instructions.len());
|
||||||
for (index, instruction) in block.instructions.iter().enumerate() {
|
for (index, instruction) in block.instructions.iter().enumerate() {
|
||||||
self.pc = index;
|
self.pc = index;
|
||||||
|
println!(" Instruction {}: {:?}", index, instruction);
|
||||||
|
|
||||||
match self.execute_instruction(instruction)? {
|
match self.execute_instruction(instruction)? {
|
||||||
ControlFlow::Continue => continue,
|
ControlFlow::Continue => continue,
|
||||||
@ -174,6 +196,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("Block execution finished. should_return: {:?}, next_block: {:?}", should_return.is_some(), next_block.is_some());
|
||||||
|
|
||||||
// Handle control flow
|
// Handle control flow
|
||||||
if let Some(return_value) = should_return {
|
if let Some(return_value) = should_return {
|
||||||
return Ok(return_value);
|
return Ok(return_value);
|
||||||
@ -189,6 +213,7 @@ impl VM {
|
|||||||
|
|
||||||
/// Execute a single instruction
|
/// Execute a single instruction
|
||||||
fn execute_instruction(&mut self, instruction: &MirInstruction) -> Result<ControlFlow, VMError> {
|
fn execute_instruction(&mut self, instruction: &MirInstruction) -> Result<ControlFlow, VMError> {
|
||||||
|
println!("Executing instruction: {:?}", instruction);
|
||||||
match instruction {
|
match instruction {
|
||||||
MirInstruction::Const { dst, value } => {
|
MirInstruction::Const { dst, value } => {
|
||||||
let vm_value = VMValue::from(value);
|
let vm_value = VMValue::from(value);
|
||||||
@ -227,8 +252,11 @@ impl VM {
|
|||||||
|
|
||||||
MirInstruction::Return { value } => {
|
MirInstruction::Return { value } => {
|
||||||
let return_value = if let Some(val_id) = 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 {
|
} else {
|
||||||
|
println!("Return: returning void (no value specified)");
|
||||||
VMValue::Void
|
VMValue::Void
|
||||||
};
|
};
|
||||||
Ok(ControlFlow::Return(return_value))
|
Ok(ControlFlow::Return(return_value))
|
||||||
@ -439,6 +467,51 @@ impl VM {
|
|||||||
// In a real implementation, this would ensure memory ordering
|
// In a real implementation, this would ensure memory ordering
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
|
||||||
|
MirInstruction::FutureSet { future, value } => {
|
||||||
|
let future_val = self.get_value(*future)?;
|
||||||
|
let new_value = self.get_value(*value)?;
|
||||||
|
|
||||||
|
if let VMValue::Future(ref future_box) = future_val {
|
||||||
|
future_box.set_result(new_value.to_nyash_box());
|
||||||
|
Ok(ControlFlow::Continue)
|
||||||
|
} else {
|
||||||
|
Err(VMError::TypeError(format!("Expected Future, got {:?}", future_val)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Err(VMError::TypeError(format!("Expected Future, got {:?}", future_val)))
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -203,6 +203,15 @@ impl MirBuilder {
|
|||||||
self.build_new_expression(class.clone(), arguments.clone())
|
self.build_new_expression(class.clone(), arguments.clone())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Phase 7: Async operations
|
||||||
|
ASTNode::Nowait { variable, expression, .. } => {
|
||||||
|
self.build_nowait_statement(variable.clone(), *expression.clone())
|
||||||
|
},
|
||||||
|
|
||||||
|
ASTNode::AwaitExpression { expression, .. } => {
|
||||||
|
self.build_await_expression(*expression.clone())
|
||||||
|
},
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
Err(format!("Unsupported AST node type: {:?}", ast))
|
Err(format!("Unsupported AST node type: {:?}", ast))
|
||||||
}
|
}
|
||||||
@ -771,6 +780,41 @@ impl MirBuilder {
|
|||||||
_ => Err(format!("Unsupported unary operator: {}", op)),
|
_ => Err(format!("Unsupported unary operator: {}", op)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build nowait statement: nowait variable = expression
|
||||||
|
fn build_nowait_statement(&mut self, variable: String, expression: ASTNode) -> Result<ValueId, String> {
|
||||||
|
// Evaluate the expression
|
||||||
|
let expression_value = self.build_expression(expression)?;
|
||||||
|
|
||||||
|
// Create a new Future with the evaluated expression as the initial value
|
||||||
|
let future_id = self.value_gen.next();
|
||||||
|
self.emit_instruction(MirInstruction::FutureNew {
|
||||||
|
dst: future_id,
|
||||||
|
value: expression_value,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Store the future in the variable
|
||||||
|
self.variable_map.insert(variable.clone(), future_id);
|
||||||
|
|
||||||
|
Ok(future_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build await expression: await expression
|
||||||
|
fn build_await_expression(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
||||||
|
// Evaluate the expression (should be a Future)
|
||||||
|
let future_value = self.build_expression(expression)?;
|
||||||
|
|
||||||
|
// Create destination for await result
|
||||||
|
let result_id = self.value_gen.next();
|
||||||
|
|
||||||
|
// Emit await instruction
|
||||||
|
self.emit_instruction(MirInstruction::Await {
|
||||||
|
dst: result_id,
|
||||||
|
future: future_value,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper enum for binary operator classification
|
/// Helper enum for binary operator classification
|
||||||
|
|||||||
@ -250,6 +250,29 @@ pub enum MirInstruction {
|
|||||||
BarrierWrite {
|
BarrierWrite {
|
||||||
ptr: ValueId,
|
ptr: ValueId,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// === Phase 7: Async/Future Operations ===
|
||||||
|
|
||||||
|
/// Create a new Future with initial value
|
||||||
|
/// `%dst = future_new %value`
|
||||||
|
FutureNew {
|
||||||
|
dst: ValueId,
|
||||||
|
value: ValueId,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Set Future value and mark as ready
|
||||||
|
/// `future_set %future = %value`
|
||||||
|
FutureSet {
|
||||||
|
future: ValueId,
|
||||||
|
value: ValueId,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Wait for Future completion and get value
|
||||||
|
/// `%dst = await %future`
|
||||||
|
Await {
|
||||||
|
dst: ValueId,
|
||||||
|
future: ValueId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constant values in MIR
|
/// Constant values in MIR
|
||||||
@ -304,6 +327,7 @@ pub enum MirType {
|
|||||||
String,
|
String,
|
||||||
Box(String), // Box type with name
|
Box(String), // Box type with name
|
||||||
Array(Box<MirType>),
|
Array(Box<MirType>),
|
||||||
|
Future(Box<MirType>), // Future containing a type
|
||||||
Void,
|
Void,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
@ -360,6 +384,11 @@ impl MirInstruction {
|
|||||||
MirInstruction::WeakLoad { .. } => EffectMask::READ, // Loading weak ref has read effects
|
MirInstruction::WeakLoad { .. } => EffectMask::READ, // Loading weak ref has read effects
|
||||||
MirInstruction::BarrierRead { .. } => EffectMask::READ.add(Effect::Barrier), // Memory barrier with read
|
MirInstruction::BarrierRead { .. } => EffectMask::READ.add(Effect::Barrier), // Memory barrier with read
|
||||||
MirInstruction::BarrierWrite { .. } => EffectMask::WRITE.add(Effect::Barrier), // Memory barrier with write
|
MirInstruction::BarrierWrite { .. } => EffectMask::WRITE.add(Effect::Barrier), // Memory barrier with write
|
||||||
|
|
||||||
|
// Phase 7: Async/Future Operations
|
||||||
|
MirInstruction::FutureNew { .. } => EffectMask::PURE.add(Effect::Alloc), // Creating future may allocate
|
||||||
|
MirInstruction::FutureSet { .. } => EffectMask::WRITE, // Setting future has write effects
|
||||||
|
MirInstruction::Await { .. } => EffectMask::READ.add(Effect::Async), // Await blocks and reads
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +409,9 @@ impl MirInstruction {
|
|||||||
MirInstruction::RefNew { dst, .. } |
|
MirInstruction::RefNew { dst, .. } |
|
||||||
MirInstruction::RefGet { dst, .. } |
|
MirInstruction::RefGet { dst, .. } |
|
||||||
MirInstruction::WeakNew { dst, .. } |
|
MirInstruction::WeakNew { dst, .. } |
|
||||||
MirInstruction::WeakLoad { dst, .. } => Some(*dst),
|
MirInstruction::WeakLoad { dst, .. } |
|
||||||
|
MirInstruction::FutureNew { dst, .. } |
|
||||||
|
MirInstruction::Await { dst, .. } => Some(*dst),
|
||||||
|
|
||||||
MirInstruction::Call { dst, .. } |
|
MirInstruction::Call { dst, .. } |
|
||||||
MirInstruction::BoxCall { dst, .. } => *dst,
|
MirInstruction::BoxCall { dst, .. } => *dst,
|
||||||
@ -396,6 +427,7 @@ impl MirInstruction {
|
|||||||
MirInstruction::RefSet { .. } |
|
MirInstruction::RefSet { .. } |
|
||||||
MirInstruction::BarrierRead { .. } |
|
MirInstruction::BarrierRead { .. } |
|
||||||
MirInstruction::BarrierWrite { .. } |
|
MirInstruction::BarrierWrite { .. } |
|
||||||
|
MirInstruction::FutureSet { .. } |
|
||||||
MirInstruction::Safepoint |
|
MirInstruction::Safepoint |
|
||||||
MirInstruction::Nop => None,
|
MirInstruction::Nop => None,
|
||||||
|
|
||||||
@ -463,6 +495,11 @@ impl MirInstruction {
|
|||||||
MirInstruction::WeakLoad { weak_ref, .. } => vec![*weak_ref],
|
MirInstruction::WeakLoad { weak_ref, .. } => vec![*weak_ref],
|
||||||
MirInstruction::BarrierRead { ptr } => vec![*ptr],
|
MirInstruction::BarrierRead { ptr } => vec![*ptr],
|
||||||
MirInstruction::BarrierWrite { ptr } => vec![*ptr],
|
MirInstruction::BarrierWrite { ptr } => vec![*ptr],
|
||||||
|
|
||||||
|
// Phase 7: Async/Future Operations
|
||||||
|
MirInstruction::FutureNew { value, .. } => vec![*value],
|
||||||
|
MirInstruction::FutureSet { future, value } => vec![*future, *value],
|
||||||
|
MirInstruction::Await { future, .. } => vec![*future],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -347,6 +347,19 @@ impl MirPrinter {
|
|||||||
MirInstruction::BarrierWrite { ptr } => {
|
MirInstruction::BarrierWrite { ptr } => {
|
||||||
format!("barrier_write {}", ptr)
|
format!("barrier_write {}", ptr)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Phase 7: Async/Future Operations
|
||||||
|
MirInstruction::FutureNew { dst, value } => {
|
||||||
|
format!("{} = future_new {}", dst, value)
|
||||||
|
},
|
||||||
|
|
||||||
|
MirInstruction::FutureSet { future, value } => {
|
||||||
|
format!("future_set {} = {}", future, value)
|
||||||
|
},
|
||||||
|
|
||||||
|
MirInstruction::Await { dst, future } => {
|
||||||
|
format!("{} = await {}", dst, future)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +372,7 @@ impl MirPrinter {
|
|||||||
super::MirType::String => "str".to_string(),
|
super::MirType::String => "str".to_string(),
|
||||||
super::MirType::Box(name) => format!("box<{}>", name),
|
super::MirType::Box(name) => format!("box<{}>", name),
|
||||||
super::MirType::Array(elem_type) => format!("[{}]", self.format_type(elem_type)),
|
super::MirType::Array(elem_type) => format!("[{}]", self.format_type(elem_type)),
|
||||||
|
super::MirType::Future(inner_type) => format!("future<{}>", self.format_type(inner_type)),
|
||||||
super::MirType::Void => "void".to_string(),
|
super::MirType::Void => "void".to_string(),
|
||||||
super::MirType::Unknown => "?".to_string(),
|
super::MirType::Unknown => "?".to_string(),
|
||||||
}
|
}
|
||||||
|
|||||||
387
tests/mir_phase7_async_ops.rs
Normal file
387
tests/mir_phase7_async_ops.rs
Normal file
@ -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");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user