diff --git a/crates/oxide_parser/src/lib.rs b/crates/oxide_parser/src/lib.rs index b0ccf835..852724ef 100644 --- a/crates/oxide_parser/src/lib.rs +++ b/crates/oxide_parser/src/lib.rs @@ -17,11 +17,11 @@ pub use oxc_span::Span; /// 使用 oxc 默认 `SourceType`(严格模式由语法自身决定)。返回 `Ok(program)` /// 或 `Err`(收集全部解析错误,按源码顺序排列);若 oxc 内部 panic(不可恢复 /// 语法错误)则返回单个通用错误。 -pub fn parse<'a>(allocator: &'a Allocator, source: &'a str) -> Result, Vec> { +fn parse_with_source_type<'a>( + allocator: &'a Allocator, source: &'a str, source_type: oxc_span::SourceType, +) -> Result, Vec> { use oxc_parser::Parser; - use oxc_span::SourceType; - let source_type = SourceType::unambiguous(); let ret = Parser::new(allocator, source, source_type).parse(); if ret.panicked { @@ -46,3 +46,20 @@ pub fn parse<'a>(allocator: &'a Allocator, source: &'a str) -> Result(allocator: &'a Allocator, source: &'a str) -> Result, Vec> { + parse_with_source_type(allocator, source, oxc_span::SourceType::unambiguous()) +} + +/// 将 `source` 强制按 ES module 解析为 AST 根节点 `Program`。 +/// +/// 与 [`parse`] 的唯一区别是 SourceType 固定为模块(`SourceType::mjs`): +/// 即使源码没有 import/export 也会按模块文法解析(如 `await` 保留字、 +/// module-only early errors 等),用于 test262 `flags: [module]` 用例。 +pub fn parse_module<'a>(allocator: &'a Allocator, source: &'a str) -> Result, Vec> { + parse_with_source_type(allocator, source, oxc_span::SourceType::mjs()) +} diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index 56832a7e..e1d1be55 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -387,12 +387,10 @@ impl RunConfig { /// 按测试元数据的 flags/features 判断是否应跳过,返回跳过原因(None 表示不跳过)。 fn is_skipped(meta: &TestMeta) -> Option { for flag in &meta.flags { - match flag.as_str() { - "module" => return Some("module tests excluded".into()), - "raw" => return Some("raw tests excluded".into()), - // noStrict 测试放行——很多在严格模式下仍可通过;运行时跳过逻辑会捕获失败。 - _ => {} + if flag.as_str() == "raw" { + return Some("raw tests excluded".into()); } + // noStrict 测试放行——很多在严格模式下仍可通过;运行时跳过逻辑会捕获失败。 } // 保持大范围已实现 feature tag 可运行;只排除真正未实现的子特性。 @@ -401,7 +399,6 @@ fn is_skipped(meta: &TestMeta) -> Option { let excluded_features = [ "Proxy", "Intl", - "module", "Atomics", "SharedArrayBuffer", "cross-realm", @@ -449,6 +446,7 @@ fn run_test_inner( let start = std::time::Instant::now(); let is_async = meta.flags.iter().any(|f| f == "async"); + let is_module = meta.flags.iter().any(|f| f == "module"); let code = match get_harness_prefix(meta, harness, harness_cache) { Ok(prefix) => { @@ -480,7 +478,11 @@ fn run_test_inner( }; let alloc = oxide_parser::Allocator::default(); - let program = match oxide_parser::parse(&alloc, &code) { + let program = match if is_module { + oxide_parser::parse_module(&alloc, &code) + } else { + oxide_parser::parse(&alloc, &code) + } { Ok(p) => p, Err(errs) => { let dur = start.elapsed().as_millis() as u64; @@ -572,13 +574,13 @@ fn judge_async_result( } if output.contains("Test262:AsyncTestComplete") { - if meta.negative.is_some() { + if let Some(neg) = meta.negative.as_ref() { return TestResult::fail( path.to_path_buf(), dur, format!( "expected runtime error ({}), got: async complete", - meta.negative.as_ref().unwrap().error_type + neg.error_type ), ); }