feat(coverage): add regular expression idempotency test (#5676)

closes #5634
This commit is contained in:
Boshen 2024-09-11 02:07:42 +00:00
parent b9bf54494f
commit 2016bae98c
6 changed files with 63 additions and 6 deletions

1
Cargo.lock generated
View file

@ -1409,6 +1409,7 @@ dependencies = [
"oxc_mangler",
"oxc_minifier",
"oxc_parser",
"oxc_regular_expression",
"oxc_semantic",
"oxc_sourcemap",
"oxc_span",

View file

@ -28,6 +28,9 @@ required-features = ["full"]
[dependencies]
oxc_allocator = { workspace = true }
oxc_ast = { workspace = true }
oxc_parser = { workspace = true }
oxc_regular_expression = { workspace = true }
oxc_cfg = { workspace = true, optional = true }
oxc_codegen = { workspace = true, optional = true }
oxc_diagnostics = { workspace = true }
@ -35,7 +38,6 @@ oxc_index = { workspace = true }
oxc_isolated_declarations = { workspace = true, optional = true }
oxc_mangler = { workspace = true, optional = true }
oxc_minifier = { workspace = true, optional = true }
oxc_parser = { workspace = true }
oxc_semantic = { workspace = true, optional = true }
oxc_sourcemap = { workspace = true, optional = true }
oxc_span = { workspace = true }

View file

@ -33,6 +33,11 @@ pub mod parser {
pub use oxc_parser::*;
}
pub mod regular_expression {
#[doc(inline)]
pub use oxc_regular_expression::*;
}
pub mod span {
#[doc(inline)]
pub use oxc_span::*;

View file

@ -2,8 +2,11 @@ commit: d62fa93c
parser_test262 Summary:
AST Parsed : 43765/43765 (100.00%)
Positive Passed: 43765/43765 (100.00%)
Positive Passed: 43764/43765 (100.00%)
Negative Passed: 4237/4237 (100.00%)
Expect to Parse: tasks/coverage/test262/test/annexB/language/literals/regexp/legacy-octal-escape.js
× Regular Expression mismatch: \03 \3
× '0'-prefixed octal literals and octal escape sequences are deprecated
╭─[test262/test/annexB/language/expressions/template-literal/legacy-octal-escape-sequence-strict.js:19:4]

View file

@ -2,7 +2,7 @@ commit: d62fa93c
semantic_test262 Summary:
AST Parsed : 43765/43765 (100.00%)
Positive Passed: 43565/43765 (99.54%)
Positive Passed: 43564/43765 (99.54%)
tasks/coverage/test262/test/annexB/language/function-code/if-decl-else-decl-a-func-block-scoping.js
semantic error: Symbol scope ID mismatch:
after transform: SymbolId(3): ScopeId(4294967294)
@ -1119,6 +1119,9 @@ semantic error: Symbol scope ID mismatch:
after transform: SymbolId(0): ScopeId(4294967294)
rebuilt : SymbolId(0): ScopeId(4294967294)
tasks/coverage/test262/test/annexB/language/literals/regexp/legacy-octal-escape.js
semantic error: Regular Expression mismatch: \03 \3
tasks/coverage/test262/test/language/module-code/eval-rqstd-once.js
semantic error: Bindings mismatch:
after transform: ScopeId(0): ["dflt1", "dflt2", "dflt3", "global", "ns1", "ns3"]

View file

@ -1,14 +1,19 @@
use std::{collections::HashSet, ops::ControlFlow, path::PathBuf};
use oxc::{
ast::{ast::Program, Trivias},
allocator::Allocator,
ast::{
ast::{Program, RegExpFlags},
Trivias,
},
codegen::CodegenOptions,
diagnostics::OxcDiagnostic,
minifier::CompressOptions,
parser::{ParseOptions, ParserReturn},
regular_expression::{ParserOptions, PatternParser},
semantic::{
post_transform_checker::{check_semantic_after_transform, check_semantic_ids},
SemanticBuilderReturn,
Semantic, SemanticBuilderReturn,
},
span::{SourceType, Span},
transformer::{TransformOptions, TransformerReturn},
@ -78,7 +83,7 @@ impl CompilerInterface for Driver {
fn after_semantic(
&mut self,
program: &mut Program<'_>,
_semantic_return: &mut SemanticBuilderReturn,
ret: &mut SemanticBuilderReturn,
) -> ControlFlow<()> {
if self.check_semantic {
if let Some(errors) = check_semantic_ids(program) {
@ -86,6 +91,7 @@ impl CompilerInterface for Driver {
return ControlFlow::Break(());
}
};
self.check_regular_expressions(&ret.semantic);
ControlFlow::Continue(())
}
@ -150,4 +156,41 @@ impl Driver {
}
false
}
/// Idempotency test for printing regular expressions.
fn check_regular_expressions(&mut self, semantic: &Semantic<'_>) {
let allocator = Allocator::default();
for literal in semantic.nodes().iter().filter_map(|node| node.kind().as_reg_exp_literal()) {
let Some(pattern) = literal.regex.pattern.as_pattern() else {
continue;
};
let printed1 = pattern.to_string();
let flags = literal.regex.flags;
let printed2 = match PatternParser::new(
&allocator,
&printed1,
ParserOptions {
span_offset: 0,
unicode_mode: flags.contains(RegExpFlags::U) || flags.contains(RegExpFlags::V),
unicode_sets_mode: flags.contains(RegExpFlags::V),
},
)
.parse()
{
Ok(pattern) => pattern.to_string(),
Err(error) => {
self.errors.push(OxcDiagnostic::error(format!(
"Failed to re-parse `{}`, printed as `/{printed1}/{flags}`, {error}",
literal.span.source_text(semantic.source_text()),
)));
continue;
}
};
if printed1 != printed2 {
self.errors.push(OxcDiagnostic::error(format!(
"Regular Expression mismatch: {printed1} {printed2}"
)));
}
}
}
}