feat: async/await 语法支持(AWAIT 帧快照挂起/恢复 + 微任务驱动 + AsyncFunction intrinsics)
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
//! async/await 运行时测试:异步函数调用返回 promise、await 恢复、reject 进 catch、
|
||||
//! 多 await 顺序、嵌套 async、微任务执行序。
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_parser::Allocator;
|
||||
use oxide_vm::promise::promise_settled_value;
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
/// 执行源码并格式化顶层结果;Promise 结果取其 drain 后的 settled 值。
|
||||
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();
|
||||
match vm.run(&module) {
|
||||
Ok(result) => format_value(&vm, result),
|
||||
Err(e) => format!("vm error: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_value(vm: &Vm, val: oxide_vm::JsValue) -> String {
|
||||
if val.is_string() {
|
||||
format!("\"{}\"", vm.lookup_str(val).unwrap_or_default())
|
||||
} else if val.is_object() {
|
||||
let obj = unsafe { &*val.as_js_object_ptr() };
|
||||
if obj.is_promise_obj() {
|
||||
match promise_settled_value(obj) {
|
||||
Some((true, v)) => format_value(vm, v),
|
||||
Some((false, v)) => format!("<rejected {}>", format_value(vm, v)),
|
||||
None => "<pending>".to_string(),
|
||||
}
|
||||
} else if obj.is_array() {
|
||||
format!("[array]")
|
||||
} else {
|
||||
"[object]".to_string()
|
||||
}
|
||||
} else {
|
||||
format!("{val}")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_returns_immediate_value() {
|
||||
assert_eq!(eval("async function f(){ return 42 } f()"), "42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_await_primitive() {
|
||||
assert_eq!(eval("async function f(){ var v = await 10; return v*2 } f()"), "20");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_await_resolved_promise() {
|
||||
assert_eq!(eval("async function f(){ var v = await Promise.resolve(5); return v+1 } f()"), "6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_await_reject_into_catch() {
|
||||
assert_eq!(
|
||||
eval("async function f(){ try { await Promise.reject('e') } catch(e) { return 'caught:'+e } } f()"),
|
||||
"\"caught:e\""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_multiple_awaits_in_order() {
|
||||
assert_eq!(eval("async function f(){ var x = await 1; x += await 2; return x } f()"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_await_return_promise() {
|
||||
assert_eq!(eval("async function f(){ return await Promise.resolve(7) } f()"), "7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_nested_calls() {
|
||||
assert_eq!(eval("async function g(){ return 2 } async function f(){ return await g() + 3 } f()"), "5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_arrow_in_then() {
|
||||
assert_eq!(eval("Promise.resolve().then(async ()=>{ return 9 }).then(v=>v)"), "9");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_execution_order_suspends_immediately() {
|
||||
// await 挂起 body;当前同步代码先跑完,body 恢复在微任务 drain 阶段。
|
||||
assert_eq!(
|
||||
eval("var order=[]; async function f(){ order.push(1); await 0; order.push(2) } f(); order.push(0); Promise.resolve().then(function(){ return order.join(',') })"),
|
||||
"\"1,0,2\""
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_throw_rejects_promise() {
|
||||
assert_eq!(eval("async function f(){ throw 'boom' } f()"), "<rejected \"boom\">");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_is_not_constructor() {
|
||||
assert!(eval("new (async function(){})").starts_with("vm error") || eval("new (async function(){})").contains("not a constructor"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_constructor_name() {
|
||||
assert_eq!(eval("async function f(){}; f.constructor.name"), "\"AsyncFunction\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn async_class_method() {
|
||||
assert_eq!(eval("class A { async m(){ return await 7 } } new A().m()"), "7");
|
||||
}
|
||||
Reference in New Issue
Block a user