refactor(transformer): RegExp transform do not take ownership of Pattern then reallocate it (#5492)

Previously `try_parse_pattern` took ownership of an existing pattern and then reallocated it back into arena, even if it wasn't changed.

Rust's borrow-checker makes it quite hard to avoid this. Only way I could find is to move some of the logic out of `try_parse_pattern`.
This commit is contained in:
overlookmotel 2024-09-05 16:04:41 +00:00
parent 64db1b4c40
commit dd198231dc

View file

@ -43,10 +43,8 @@
mod options; mod options;
use std::borrow::Cow; use std::borrow::Cow;
use std::mem;
pub use options::RegExpOptions; pub use options::RegExpOptions;
use oxc_allocator::Box;
use oxc_allocator::Vec; use oxc_allocator::Vec;
use oxc_ast::ast::*; use oxc_ast::ast::*;
use oxc_regular_expression::ast::{ use oxc_regular_expression::ast::{
@ -119,7 +117,8 @@ impl<'a> Traverse<'a> for RegExp<'a> {
return; return;
}; };
let has_unsupported_flags = regexp.regex.flags.intersects(self.unsupported_flags); let flags = regexp.regex.flags;
let has_unsupported_flags = flags.intersects(self.unsupported_flags);
if !has_unsupported_flags { if !has_unsupported_flags {
if !self.some_unsupported_patterns { if !self.some_unsupported_patterns {
// This RegExp has no unsupported flags, and there are no patterns which may need transforming, // This RegExp has no unsupported flags, and there are no patterns which may need transforming,
@ -127,18 +126,26 @@ impl<'a> Traverse<'a> for RegExp<'a> {
return; return;
} }
match try_parse_pattern(regexp, ctx) { let span = regexp.span;
Ok(pattern) => { let pattern = match &mut regexp.regex.pattern {
let is_unsupported = self.has_unsupported_regular_expression_pattern(&pattern); RegExpPattern::Raw(raw) => {
regexp.regex.pattern = RegExpPattern::Pattern(pattern); if let Some(pattern) = try_parse_pattern(raw, span, flags, ctx) {
if !is_unsupported { regexp.regex.pattern = RegExpPattern::Pattern(ctx.alloc(pattern));
let RegExpPattern::Pattern(pattern) = &regexp.regex.pattern else {
unreachable!()
};
pattern
} else {
regexp.regex.pattern = RegExpPattern::Invalid(raw);
return; return;
} }
} }
Err(err) => { RegExpPattern::Invalid(_) => return,
regexp.regex.pattern = RegExpPattern::Invalid(err); RegExpPattern::Pattern(pattern) => &**pattern,
return; };
}
if !self.has_unsupported_regular_expression_pattern(pattern) {
return;
} }
} }
@ -220,26 +227,22 @@ fn has_unicode_property_escape_character_class(character_class: &CharacterClass)
} }
fn try_parse_pattern<'a>( fn try_parse_pattern<'a>(
literal: &mut RegExpLiteral<'a>, raw: &'a str,
span: Span,
flags: RegExpFlags,
ctx: &mut TraverseCtx<'a>, ctx: &mut TraverseCtx<'a>,
) -> Result<Box<'a, Pattern<'a>>, &'a str> { ) -> Option<Pattern<'a>> {
// Take the ownership of the pattern use oxc_regular_expression::{ParserOptions, PatternParser};
let regexp_pattern = mem::replace(&mut literal.regex.pattern, RegExpPattern::Raw(""));
match regexp_pattern { let options = ParserOptions {
RegExpPattern::Raw(raw) => { span_offset: span.start + 1, // exclude `/`
use oxc_regular_expression::{ParserOptions, PatternParser}; unicode_mode: flags.contains(RegExpFlags::U) || flags.contains(RegExpFlags::V),
let options = ParserOptions { unicode_sets_mode: flags.contains(RegExpFlags::V),
span_offset: literal.span.start + 1, // exclude `/` };
unicode_mode: literal.regex.flags.contains(RegExpFlags::U)
|| literal.regex.flags.contains(RegExpFlags::V), let ret = PatternParser::new(ctx.ast.allocator, raw, options).parse();
unicode_sets_mode: literal.regex.flags.contains(RegExpFlags::V), match ret {
}; Ok(pattern) => Some(pattern),
PatternParser::new(ctx.ast.allocator, raw, options) Err(_) => None,
.parse()
.map_or_else(|_| Err(raw), |p| Ok(ctx.alloc(p)))
}
RegExpPattern::Pattern(pattern) => Ok(pattern),
RegExpPattern::Invalid(raw) => Err(raw),
} }
} }