use prometeu_compiler::frontends::pbs::parser::Parser; use prometeu_compiler::frontends::pbs::collector::SymbolCollector; use prometeu_compiler::frontends::pbs::symbols::ModuleSymbols; use prometeu_compiler::frontends::pbs::lowering::Lowerer; use prometeu_compiler::ir_core; #[test] fn test_host_contract_call_lowering() { let code = " declare contract Gfx host {} declare contract Log host {} fn main() { Gfx.clear(0); Log.write(\"Hello\"); } "; let mut parser = Parser::new(code, 0); let ast = parser.parse_file().expect("Failed to parse"); let mut collector = SymbolCollector::new(); let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols"); let module_symbols = ModuleSymbols { type_symbols, value_symbols }; let lowerer = Lowerer::new(&module_symbols); let program = lowerer.lower_file(&ast, "test"); let func = &program.modules[0].functions[0]; let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Gfx.clear -> 0x1001 assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::Syscall(0x1001)))); // Log.write -> 0x5001 assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::Syscall(0x5001)))); } #[test] fn test_contract_call_without_host_lowering() { let code = " declare contract Gfx {} fn main() { Gfx.clear(0); } "; let mut parser = Parser::new(code, 0); let ast = parser.parse_file().expect("Failed to parse"); let mut collector = SymbolCollector::new(); let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols"); let module_symbols = ModuleSymbols { type_symbols, value_symbols }; let lowerer = Lowerer::new(&module_symbols); let program = lowerer.lower_file(&ast, "test"); let func = &program.modules[0].functions[0]; let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Should NOT be a syscall if not declared as host assert!(!instrs.iter().any(|i| matches!(i, ir_core::Instr::Syscall(_)))); } #[test] fn test_shadowed_contract_call_lowering() { let code = " declare contract Gfx host {} fn main() { let Gfx = 10; Gfx.clear(0); } "; let mut parser = Parser::new(code, 0); let ast = parser.parse_file().expect("Failed to parse"); let mut collector = SymbolCollector::new(); let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols"); let module_symbols = ModuleSymbols { type_symbols, value_symbols }; let lowerer = Lowerer::new(&module_symbols); let program = lowerer.lower_file(&ast, "test"); let func = &program.modules[0].functions[0]; let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Should NOT be a syscall because Gfx is shadowed by a local assert!(!instrs.iter().any(|i| matches!(i, ir_core::Instr::Syscall(_)))); } #[test] fn test_invalid_contract_call_lowering() { let code = " declare contract Gfx host {} fn main() { Gfx.invalidMethod(0); } "; let mut parser = Parser::new(code, 0); let ast = parser.parse_file().expect("Failed to parse"); let mut collector = SymbolCollector::new(); let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols"); let module_symbols = ModuleSymbols { type_symbols, value_symbols }; let lowerer = Lowerer::new(&module_symbols); let program = lowerer.lower_file(&ast, "test"); let func = &program.modules[0].functions[0]; let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect(); // Should NOT be a syscall if invalid assert!(!instrs.iter().any(|i| matches!(i, ir_core::Instr::Syscall(_)))); // Should be a regular call (which might fail later or be a dummy) assert!(instrs.iter().any(|i| matches!(i, ir_core::Instr::Call(_, _)))); }