Skip to content

Commit

Permalink
refactor(ast, regular_expression): converge oxc_ast::RegExpFlags an…
Browse files Browse the repository at this point in the history
…d `oxc_regular_expression::ast::Flags`.
  • Loading branch information
rzvxa committed Sep 7, 2024
1 parent 8c9179d commit 4d8d090
Show file tree
Hide file tree
Showing 38 changed files with 514 additions and 632 deletions.
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

0 comments on commit 4d8d090

Please sign in to comment.