/*! * Nyash MIR (Mid-level Intermediate Representation) - Stage 1 Implementation * * ChatGPT5-designed MIR infrastructure for native compilation support * Based on SSA form with effect tracking and Box-aware optimizations */ pub mod instruction; pub mod instruction_v2; // New 25-instruction specification pub mod basic_block; pub mod function; pub mod builder; pub mod loop_builder; // SSA loop construction with phi nodes pub mod verification; pub mod ownership_verifier_simple; // Simple ownership forest verification for current MIR pub mod printer; pub mod value_id; pub mod effect; pub mod optimizer; // Re-export main types for easy access pub use instruction::{MirInstruction, BinaryOp, CompareOp, UnaryOp, ConstValue, MirType, TypeOpKind, WeakRefOp, BarrierOp}; pub use instruction_v2::{MirInstructionV2, AtomicOrdering}; // New 25-instruction set pub use basic_block::{BasicBlock, BasicBlockId, BasicBlockIdGenerator}; pub use function::{MirFunction, MirModule, FunctionSignature}; pub use builder::MirBuilder; pub use verification::{MirVerifier, VerificationError}; pub use ownership_verifier_simple::{OwnershipVerifier, OwnershipError, OwnershipStats}; // Simple ownership forest verification pub use printer::MirPrinter; pub use value_id::{ValueId, LocalId, ValueIdGenerator}; pub use effect::{EffectMask, Effect}; pub use optimizer::MirOptimizer; /// MIR compilation result #[derive(Debug, Clone)] pub struct MirCompileResult { pub module: MirModule, pub verification_result: Result<(), Vec>, } /// MIR compiler - converts AST to MIR/SSA form pub struct MirCompiler { builder: MirBuilder, verifier: MirVerifier, optimize: bool, } impl MirCompiler { /// Create a new MIR compiler pub fn new() -> Self { Self { builder: MirBuilder::new(), verifier: MirVerifier::new(), optimize: true, } } /// Create with options pub fn with_options(optimize: bool) -> Self { Self { builder: MirBuilder::new(), verifier: MirVerifier::new(), optimize, } } /// Compile AST to MIR module with verification pub fn compile(&mut self, ast: crate::ast::ASTNode) -> Result { // Convert AST to MIR using builder let mut module = self.builder.build_module(ast)?; if self.optimize { let mut optimizer = MirOptimizer::new(); let stats = optimizer.optimize_module(&mut module); if std::env::var("NYASH_OPT_DIAG_FAIL").is_ok() && stats.diagnostics_reported > 0 { return Err(format!("Diagnostic failure: {} unlowered type-op calls detected", stats.diagnostics_reported)); } } // Verify the generated MIR let verification_result = self.verifier.verify_module(&module); Ok(MirCompileResult { module, verification_result, }) } /// Dump MIR to string for debugging pub fn dump_mir(&self, module: &MirModule) -> String { MirPrinter::new().print_module(module) } } impl Default for MirCompiler { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; use crate::ast::{ASTNode, LiteralValue}; #[test] fn test_basic_mir_compilation() { let mut compiler = MirCompiler::new(); // Create a simple literal AST node let ast = ASTNode::Literal { value: LiteralValue::Integer(42), span: crate::ast::Span::unknown() }; // Compile to MIR let result = compiler.compile(ast); assert!(result.is_ok(), "Basic MIR compilation should succeed"); let compile_result = result.unwrap(); assert!(!compile_result.module.functions.is_empty(), "Module should contain at least one function"); } #[test] fn test_mir_dump() { let mut compiler = MirCompiler::new(); let ast = ASTNode::Literal { value: LiteralValue::Integer(42), span: crate::ast::Span::unknown() }; let result = compiler.compile(ast).unwrap(); let mir_dump = compiler.dump_mir(&result.module); assert!(!mir_dump.is_empty(), "MIR dump should not be empty"); assert!(mir_dump.contains("define"), "MIR dump should contain function definition"); } #[test] fn test_lowering_is_type_function_call_in_print() { // Build AST: print(isType(42, "Integer")) let ast = ASTNode::Print { expression: Box::new(ASTNode::FunctionCall { name: "isType".to_string(), arguments: vec![ ASTNode::Literal { value: LiteralValue::Integer(42), span: crate::ast::Span::unknown() }, ASTNode::Literal { value: LiteralValue::String("Integer".to_string()), span: crate::ast::Span::unknown() }, ], span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), }; let mut compiler = MirCompiler::new(); let result = compiler.compile(ast).expect("compile should succeed"); // Ensure TypeOp exists in the resulting MIR let has_typeop = result.module.functions.values().any(|f| { f.blocks.values().any(|b| b.all_instructions().any(|i| matches!(i, MirInstruction::TypeOp { .. }))) }); assert!(has_typeop, "Expected TypeOp lowering for print(isType(...))"); } #[test] fn test_lowering_is_method_call_in_print() { // Build AST: print( (42).is("Integer") ) let ast = ASTNode::Print { expression: Box::new(ASTNode::MethodCall { object: Box::new(ASTNode::Literal { value: LiteralValue::Integer(42), span: crate::ast::Span::unknown() }), method: "is".to_string(), arguments: vec![ ASTNode::Literal { value: LiteralValue::String("Integer".to_string()), span: crate::ast::Span::unknown() }, ], span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), }; let mut compiler = MirCompiler::new(); let result = compiler.compile(ast).expect("compile should succeed"); // Ensure TypeOp exists in the resulting MIR let has_typeop = result.module.functions.values().any(|f| { f.blocks.values().any(|b| b.all_instructions().any(|i| matches!(i, MirInstruction::TypeOp { .. }))) }); assert!(has_typeop, "Expected TypeOp lowering for print(obj.is(...))"); } #[test] fn test_throw_compilation() { let mut compiler = MirCompiler::new(); let throw_ast = ASTNode::Throw { expression: Box::new(ASTNode::Literal { value: LiteralValue::String("Test exception".to_string()), span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), }; let result = compiler.compile(throw_ast); assert!(result.is_ok(), "Throw compilation should succeed"); let compile_result = result.unwrap(); let mir_dump = compiler.dump_mir(&compile_result.module); assert!(mir_dump.contains("throw"), "MIR should contain throw instruction"); assert!(mir_dump.contains("safepoint"), "MIR should contain safepoint instruction"); } #[test] fn test_loop_compilation() { let mut compiler = MirCompiler::new(); let loop_ast = ASTNode::Loop { condition: Box::new(ASTNode::Literal { value: LiteralValue::Bool(true), span: crate::ast::Span::unknown(), }), body: vec![ ASTNode::Print { expression: Box::new(ASTNode::Literal { value: LiteralValue::String("Loop body".to_string()), span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), } ], span: crate::ast::Span::unknown(), }; let result = compiler.compile(loop_ast); assert!(result.is_ok(), "Loop compilation should succeed"); let compile_result = result.unwrap(); let mir_dump = compiler.dump_mir(&compile_result.module); assert!(mir_dump.contains("br"), "MIR should contain branch instructions"); assert!(mir_dump.contains("safepoint"), "MIR should contain safepoint instructions"); } #[test] fn test_try_catch_compilation() { let mut compiler = MirCompiler::new(); let try_catch_ast = ASTNode::TryCatch { try_body: vec![ ASTNode::Print { expression: Box::new(ASTNode::Literal { value: LiteralValue::String("Try block".to_string()), span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), } ], catch_clauses: vec![ crate::ast::CatchClause { exception_type: Some("Exception".to_string()), variable_name: Some("e".to_string()), body: vec![ ASTNode::Print { expression: Box::new(ASTNode::Literal { value: LiteralValue::String("Catch block".to_string()), span: crate::ast::Span::unknown(), }), span: crate::ast::Span::unknown(), } ], span: crate::ast::Span::unknown(), } ], finally_body: None, span: crate::ast::Span::unknown(), }; let result = compiler.compile(try_catch_ast); assert!(result.is_ok(), "TryCatch compilation should succeed"); let compile_result = result.unwrap(); let mir_dump = compiler.dump_mir(&compile_result.module); assert!(mir_dump.contains("catch"), "MIR should contain catch instruction"); } }