diff --git a/Cargo.lock b/Cargo.lock index fa5439c5d310e..0fa92f1035171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1588,6 +1588,7 @@ dependencies = [ "cow-utils", "oxc_allocator", "oxc_ast_macros", + "oxc_data_structures", "oxc_estree", "oxc_regular_expression", "oxc_span", diff --git a/crates/oxc_ast/Cargo.toml b/crates/oxc_ast/Cargo.toml index afa3d82241a7d..5bdae2175d3bd 100644 --- a/crates/oxc_ast/Cargo.toml +++ b/crates/oxc_ast/Cargo.toml @@ -21,6 +21,7 @@ doctest = false [dependencies] oxc_allocator = { workspace = true } oxc_ast_macros = { workspace = true } +oxc_data_structures = { workspace = true } oxc_estree = { workspace = true } oxc_regular_expression = { workspace = true } oxc_span = { workspace = true } diff --git a/crates/oxc_ast/src/ast_impl/literal.rs b/crates/oxc_ast/src/ast_impl/literal.rs index 4477b8954dfdd..2753f35d2900b 100644 --- a/crates/oxc_ast/src/ast_impl/literal.rs +++ b/crates/oxc_ast/src/ast_impl/literal.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, fmt}; use oxc_allocator::CloneIn; +use oxc_data_structures::inline_string::InlineString; use oxc_regular_expression::ast::Pattern; use oxc_span::ContentEq; @@ -255,31 +256,47 @@ impl TryFrom for RegExpFlags { impl fmt::Display for RegExpFlags { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // In alphabetical order - if self.contains(Self::D) { - write!(f, "d")?; - } - if self.contains(Self::G) { - write!(f, "g")?; - } - if self.contains(Self::I) { - write!(f, "i")?; - } - if self.contains(Self::M) { - write!(f, "m")?; - } - if self.contains(Self::S) { - write!(f, "s")?; - } - if self.contains(Self::U) { - write!(f, "u")?; - } - if self.contains(Self::V) { - write!(f, "v")?; - } - if self.contains(Self::Y) { - write!(f, "y")?; + f.write_str(self.to_inline_string().as_str()) + } +} + +impl RegExpFlags { + /// Convert [`RegExpFlags`] to an [`InlineString`]. + /// + /// This performs the same role as `RegExpFlags::to_string`, but does not allocate. + pub fn to_inline_string(&self) -> InlineString<8, usize> { + let mut str = InlineString::new(); + + // In alphabetical order. + // SAFETY: Capacity of the `InlineString` is 8, and we push a maximum of 8 bytes. + // All bytes pushed are ASCII. + unsafe { + if self.contains(Self::D) { + str.push_unchecked(b'd'); + } + if self.contains(Self::G) { + str.push_unchecked(b'g'); + } + if self.contains(Self::I) { + str.push_unchecked(b'i'); + } + if self.contains(Self::M) { + str.push_unchecked(b'm'); + } + if self.contains(Self::S) { + str.push_unchecked(b's'); + } + if self.contains(Self::U) { + str.push_unchecked(b'u'); + } + if self.contains(Self::V) { + str.push_unchecked(b'v'); + } + if self.contains(Self::Y) { + str.push_unchecked(b'y'); + } } - Ok(()) + + str } } diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index 277084fc2c00e..9292dc7509fe6 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -279,7 +279,7 @@ pub struct RegExpFlagsConverter<'b>(pub &'b RegExpFlags); impl ESTree for RegExpFlagsConverter<'_> { fn serialize(&self, serializer: S) { - JsonSafeString(self.0.to_string().as_str()).serialize(serializer); + JsonSafeString(self.0.to_inline_string().as_str()).serialize(serializer); } } diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 634ef00babe58..5c840d3cccec9 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1355,7 +1355,7 @@ impl Gen for RegExpLiteral<'_> { p.print_ascii_byte(b'/'); p.print_str(pattern_text.as_ref()); p.print_ascii_byte(b'/'); - p.print_str(self.regex.flags.to_string().as_str()); + p.print_str(self.regex.flags.to_inline_string().as_str()); p.prev_reg_exp_end = p.code().len(); } } diff --git a/crates/oxc_transformer/src/regexp/mod.rs b/crates/oxc_transformer/src/regexp/mod.rs index 62dad5e1b1604..f8842c614cc6f 100644 --- a/crates/oxc_transformer/src/regexp/mod.rs +++ b/crates/oxc_transformer/src/regexp/mod.rs @@ -185,7 +185,11 @@ impl<'a> Traverse<'a> for RegExp<'a, '_> { let arguments = ctx.ast.vec_from_array([ Argument::from(ctx.ast.expression_string_literal(SPAN, pattern_source, None)), - Argument::from(ctx.ast.expression_string_literal(SPAN, flags.to_string(), None)), + Argument::from(ctx.ast.expression_string_literal( + SPAN, + flags.to_inline_string().as_str(), + None, + )), ]); *expr = ctx.ast.expression_new(regexp.span, callee, arguments, NONE); diff --git a/tasks/coverage/src/driver.rs b/tasks/coverage/src/driver.rs index 54fcb5154f365..545d02fb6e980 100644 --- a/tasks/coverage/src/driver.rs +++ b/tasks/coverage/src/driver.rs @@ -167,7 +167,7 @@ impl Driver { continue; }; let printed1 = pattern.to_string(); - let flags = literal.regex.flags.to_string(); + let flags = literal.regex.flags.to_inline_string(); match LiteralParser::new(&allocator, &printed1, Some(&flags), Options::default()) .parse() {