Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(ast, regular_expression)!: converge oxc_ast::RegExpFlags and oxc_regular_expression::ast::Flags. #5592

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions crates/oxc_ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ oxc_ast_macros = { workspace = true }
oxc_span = { workspace = true }
oxc_syntax = { workspace = true }
oxc_regular_expression = { workspace = true }

bitflags = { workspace = true }
num-bigint = { workspace = true }
num-bigint = { workspace = true }

serde = { workspace = true, features = ["derive"], optional = true }
serde_json = { workspace = true, optional = true }
Expand Down
72 changes: 2 additions & 70 deletions crates/oxc_ast/src/ast/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
#![allow(non_snake_case)]

use std::hash::Hash;

use bitflags::bitflags;
use oxc_allocator::{Box, CloneIn};
use oxc_ast_macros::ast;
use oxc_regular_expression::ast::Pattern;
use oxc_regular_expression::ast::{Pattern, RegularExpressionFlags};
use oxc_span::{cmp::ContentEq, hash::ContentHash, Atom, GetSpan, GetSpanMut, Span};
use oxc_syntax::number::{BigintBase, NumberBase};
#[cfg(feature = "serialize")]
Expand Down Expand Up @@ -111,7 +108,7 @@ pub struct RegExp<'a> {
/// The regex pattern between the slashes
pub pattern: RegExpPattern<'a>,
/// Regex flags after the closing slash
pub flags: RegExpFlags,
pub flags: RegularExpressionFlags,
}

/// A regular expression pattern
Expand Down Expand Up @@ -152,68 +149,3 @@ pub struct StringLiteral<'a> {
pub span: Span,
pub value: Atom<'a>,
}

bitflags! {
/// Regular expression flags.
///
/// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#advanced_searching_with_flags>
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RegExpFlags: u8 {
/// Global flag
///
/// Causes the pattern to match multiple times.
const G = 1 << 0;
/// Ignore case flag
///
/// Causes the pattern to ignore case.
const I = 1 << 1;
/// Multiline flag
///
/// Causes `^` and `$` to match the start/end of each line.
const M = 1 << 2;
/// DotAll flag
///
/// Causes `.` to also match newlines.
const S = 1 << 3;
/// Unicode flag
///
/// Causes the pattern to treat the input as a sequence of Unicode code points.
const U = 1 << 4;
/// Sticky flag
///
/// Perform a "sticky" search that matches starting at the current position in the target string.
const Y = 1 << 5;
/// Indices flag
///
/// Causes the regular expression to generate indices for substring matches.
const D = 1 << 6;
/// Unicode sets flag
///
/// Similar to the `u` flag, but also enables the `\\p{}` and `\\P{}` syntax.
/// Added by the [`v` flag proposal](https://github.com/tc39/proposal-regexp-set-notation).
const V = 1 << 7;
}
}

#[cfg(feature = "serialize")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = r#"
export type RegExpFlags = {
/** Global flag */
G: 1,
/** Ignore case flag */
I: 2,
/** Multiline flag */
M: 4,
/** DotAll flag */
S: 8,
/** Unicode flag */
U: 16,
/** Sticky flag */
Y: 32,
/** Indices flag */
D: 64,
/** Unicode sets flag */
V: 128
};
"#;
89 changes: 1 addition & 88 deletions crates/oxc_ast/src/ast_impl/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ use std::{
hash::{Hash, Hasher},
};

use oxc_allocator::CloneIn;
use oxc_regular_expression::ast::Pattern;
use oxc_span::{cmp::ContentEq, hash::ContentHash, Atom, Span};
use oxc_span::{hash::ContentHash, Atom, Span};
use oxc_syntax::number::NumberBase;

use crate::ast::*;
Expand Down Expand Up @@ -173,92 +172,6 @@ impl<'a> fmt::Display for RegExpPattern<'a> {
}
}

impl ContentEq for RegExpFlags {
fn content_eq(&self, other: &Self) -> bool {
self == other
}
}

impl ContentHash for RegExpFlags {
fn content_hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(self, state);
}
}

impl<'alloc> CloneIn<'alloc> for RegExpFlags {
type Cloned = Self;

fn clone_in(&self, _: &'alloc oxc_allocator::Allocator) -> Self::Cloned {
*self
}
}

impl TryFrom<char> for RegExpFlags {
type Error = char;

fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'g' => Ok(Self::G),
'i' => Ok(Self::I),
'm' => Ok(Self::M),
's' => Ok(Self::S),
'u' => Ok(Self::U),
'y' => Ok(Self::Y),
'd' => Ok(Self::D),
'v' => Ok(Self::V),
_ => Err(value),
}
}
}

impl TryFrom<u8> for RegExpFlags {
type Error = u8;

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
b'g' => Ok(Self::G),
b'i' => Ok(Self::I),
b'm' => Ok(Self::M),
b's' => Ok(Self::S),
b'u' => Ok(Self::U),
b'y' => Ok(Self::Y),
b'd' => Ok(Self::D),
b'v' => Ok(Self::V),
_ => Err(value),
}
}
}

impl fmt::Display for RegExpFlags {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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::Y) {
write!(f, "y")?;
}
if self.contains(Self::D) {
write!(f, "d")?;
}
if self.contains(Self::V) {
write!(f, "v")?;
}
Ok(())
}
}

impl<'a> StringLiteral<'a> {
pub fn new(span: Span, value: Atom<'a>) -> Self {
Self { span, value }
Expand Down
28 changes: 2 additions & 26 deletions crates/oxc_ast/src/generated/assert_layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1412,24 +1412,12 @@ const _: () = {
assert!(size_of::<LanguageVariant>() == 1usize);
assert!(align_of::<LanguageVariant>() == 1usize);

assert!(size_of::<RegularExpression>() == 72usize);
assert!(size_of::<RegularExpression>() == 64usize);
assert!(align_of::<RegularExpression>() == 8usize);
assert!(offset_of!(RegularExpression, span) == 0usize);
assert!(offset_of!(RegularExpression, pattern) == 8usize);
assert!(offset_of!(RegularExpression, flags) == 56usize);

assert!(size_of::<Flags>() == 16usize);
assert!(align_of::<Flags>() == 4usize);
assert!(offset_of!(Flags, span) == 0usize);
assert!(offset_of!(Flags, global) == 8usize);
assert!(offset_of!(Flags, ignore_case) == 9usize);
assert!(offset_of!(Flags, multiline) == 10usize);
assert!(offset_of!(Flags, unicode) == 11usize);
assert!(offset_of!(Flags, sticky) == 12usize);
assert!(offset_of!(Flags, dot_all) == 13usize);
assert!(offset_of!(Flags, has_indices) == 14usize);
assert!(offset_of!(Flags, unicode_sets) == 15usize);

assert!(size_of::<Pattern>() == 48usize);
assert!(align_of::<Pattern>() == 8usize);
assert!(offset_of!(Pattern, span) == 0usize);
Expand Down Expand Up @@ -2966,24 +2954,12 @@ const _: () = {
assert!(size_of::<LanguageVariant>() == 1usize);
assert!(align_of::<LanguageVariant>() == 1usize);

assert!(size_of::<RegularExpression>() == 56usize);
assert!(size_of::<RegularExpression>() == 44usize);
assert!(align_of::<RegularExpression>() == 4usize);
assert!(offset_of!(RegularExpression, span) == 0usize);
assert!(offset_of!(RegularExpression, pattern) == 8usize);
assert!(offset_of!(RegularExpression, flags) == 40usize);

assert!(size_of::<Flags>() == 16usize);
assert!(align_of::<Flags>() == 4usize);
assert!(offset_of!(Flags, span) == 0usize);
assert!(offset_of!(Flags, global) == 8usize);
assert!(offset_of!(Flags, ignore_case) == 9usize);
assert!(offset_of!(Flags, multiline) == 10usize);
assert!(offset_of!(Flags, unicode) == 11usize);
assert!(offset_of!(Flags, sticky) == 12usize);
assert!(offset_of!(Flags, dot_all) == 13usize);
assert!(offset_of!(Flags, has_indices) == 14usize);
assert!(offset_of!(Flags, unicode_sets) == 15usize);

assert!(size_of::<Pattern>() == 32usize);
assert!(align_of::<Pattern>() == 4usize);
assert!(offset_of!(Pattern, span) == 0usize);
Expand Down
13 changes: 2 additions & 11 deletions crates/oxc_ast/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::ast::{
ArrayAssignmentTarget, ArrayPattern, AssignmentTargetMaybeDefault, AssignmentTargetProperty,
AssignmentTargetRest, BindingPattern, BindingPatternKind, BindingProperty, BindingRestElement,
Directive, Elision, FormalParameter, FormalParameterKind, FormalParameters,
ObjectAssignmentTarget, ObjectPattern, Program, RegExpFlags, Statement, StringLiteral,
TSModuleBlock, TSTypeAnnotation,
ObjectAssignmentTarget, ObjectPattern, Program, Statement, StringLiteral, TSModuleBlock,
TSTypeAnnotation,
};

pub struct EcmaFormatter;
Expand Down Expand Up @@ -42,15 +42,6 @@ impl<'a> Program<'a> {
}
}

impl Serialize for RegExpFlags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

/// Serialize `ArrayExpressionElement::Elision` variant as `null` in JSON
impl Serialize for Elision {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
7 changes: 4 additions & 3 deletions crates/oxc_linter/src/ast_util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::hash::Hasher;

use oxc_ast::{ast::BindingIdentifier, AstKind};
use oxc_regular_expression::ast::RegularExpressionFlags;
use oxc_semantic::{AstNode, AstNodeId, SymbolId};
use oxc_span::{hash::ContentHash, GetSpan, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator};
Expand Down Expand Up @@ -290,16 +291,16 @@ pub fn get_symbol_id_of_variable(

pub fn extract_regex_flags<'a>(
args: &'a oxc_allocator::Vec<'a, Argument<'a>>,
) -> Option<RegExpFlags> {
) -> Option<RegularExpressionFlags> {
if args.len() <= 1 {
return None;
}
let Argument::StringLiteral(flag_arg) = &args[1] else {
return None;
};
let mut flags = RegExpFlags::empty();
let mut flags = RegularExpressionFlags::empty();
for ch in flag_arg.value.chars() {
let flag = RegExpFlags::try_from(ch).ok()?;
let flag = RegularExpressionFlags::try_from(ch).ok()?;
flags |= flag;
}
Some(flags)
Expand Down
9 changes: 5 additions & 4 deletions crates/oxc_linter/src/rules/eslint/no_control_regex.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use lazy_static::lazy_static;
use oxc_ast::{
ast::{Argument, RegExpFlags, RegExpPattern},
ast::{Argument, RegExpPattern},
AstKind,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_regular_expression::ast::RegularExpressionFlags;
use oxc_span::{GetSpan, Span};
use regex::{Matches, Regex};

Expand Down Expand Up @@ -101,7 +102,7 @@ impl Rule for NoControlRegex {
// extract numeric part from \u{00}
if numeric_part.starts_with('{') {
let has_unicode_flag = match flags {
Some(flags) if flags.contains(RegExpFlags::U) => true,
Some(flags) if flags.contains(RegularExpressionFlags::U) => true,
_ => {
continue;
}
Expand Down Expand Up @@ -161,7 +162,7 @@ struct RegexPatternData<'a> {
///
/// Note that flags are represented by a `u8` and therefore safely clonable
/// with low performance overhead.
flags: Option<RegExpFlags>,
flags: Option<RegularExpressionFlags>,
/// The pattern's span. For [`oxc_ast::ast::Expression::NewExpression`]s
/// and [`oxc_ast::ast::Expression::CallExpression`]s,
/// this will match the entire new/call expression.
Expand All @@ -176,7 +177,7 @@ struct RegexPatternData<'a> {
/// * /foo/ -> "foo"
/// * new RegExp("foo") -> foo
///
/// note: [`RegExpFlags`] and [`Span`]s are both tiny and cloneable.
/// note: [`RegularExpressionFlags`] and [`Span`]s are both tiny and cloneable.
fn regex_pattern<'a>(node: &AstNode<'a>) -> Option<RegexPatternData<'a>> {
let kind = node.kind();
match kind {
Expand Down
Loading