use std::sync::Arc; use oxide_compiler::compiler::Compiler; use oxide_compiler::DefaultCompilerService; use oxide_parser::Allocator; use oxide_vm::vm::Vm; fn eval(source: &str) -> String { let allocator = Allocator::default(); let program = match oxide_parser::parse(&allocator, source) { Ok(p) => p, Err(e) => return format!("parse error: {}", e[0].message), }; let module = match Compiler::new().compile(&program) { Ok(m) => m, Err(e) => return format!("compile error: {e}"), }; let mut vm = Vm::new(); vm.set_compiler_service(Arc::new(DefaultCompilerService)); match vm.run(&Arc::new(module)) { Ok(result) => format!("{result}"), Err(e) => format!("vm error: {e}"), } } // 非简单 `??`(带副作用操作数)后跟带标签的构造不得把下游 label id 移位 // (否则 emit 期报 `Label ... not found`)。 #[test] fn coalesce_nonsimple_then_if() { assert_eq!( eval("function a(){return null;} function b(){return 2;} var v=a()??b(); if(v>0){v=v+10;} v"), "12" ); } #[test] fn coalesce_nonsimple_then_while() { assert_eq!( eval("function a(){return null;} function b(){return 3;} var v=a()??b(); var c=0; while(c0){} v"), "2"); } #[test] fn compound_member_value_regression() { assert_eq!(eval("var o={x:10}; o.x-=3; o.x"), "7"); }