swc_ecma_regexp/parser/
parser_impl.rs

1use super::{
2    flags_parser::FlagsParser, pattern_parser::PatternParser, reader::Reader,
3    span_factory::SpanFactory,
4};
5use crate::{
6    ast,
7    diagnostics::{self, Result},
8    options::Options,
9};
10
11/// Regular expression parser for `/literal/` usage.
12/// - `pattern_text`: the text between `/` and `/`
13/// - `flags_text`: the text after the second `/`
14pub struct LiteralParser<'a> {
15    pattern_text: &'a str,
16    flags_text: Option<&'a str>,
17    options: Options,
18}
19
20impl<'a> LiteralParser<'a> {
21    pub fn new(pattern_text: &'a str, flags_text: Option<&'a str>, options: Options) -> Self {
22        Self {
23            pattern_text,
24            flags_text,
25            options,
26        }
27    }
28
29    pub fn parse(self) -> Result<ast::Pattern> {
30        let parse_string_literal = false;
31        let Options {
32            pattern_span_offset,
33            flags_span_offset,
34        } = self.options;
35
36        let (unicode_mode, unicode_sets_mode) = if let Some(flags_text) = self.flags_text {
37            let reader = Reader::initialize(flags_text, true, parse_string_literal)?; // For literal, never expect to throw
38
39            FlagsParser::new(reader, flags_span_offset).parse()?
40        } else {
41            (false, false)
42        };
43
44        let pattern_text = if self.pattern_text.is_empty() {
45            "(?:)"
46        } else {
47            self.pattern_text
48        };
49        let reader = Reader::initialize(pattern_text, unicode_mode, parse_string_literal)?; // For literal, never expect to throw
50
51        PatternParser::new(
52            reader,
53            (unicode_mode, unicode_sets_mode),
54            pattern_span_offset,
55        )
56        .parse()
57    }
58}
59
60/// Regular expression parser for `new RegExp("constrocutor")` usage.
61/// - `pattern_text`: the string literal text as 1st argument of `RegExp`
62///   constructor
63/// - `flags_text`: the string literal text as 2nd argument of `RegExp`
64///   constructor
65///
66/// String literal text should be in the form of `'...'` or `"..."` and may
67/// contain escape sequences.
68pub struct ConstructorParser<'a> {
69    pattern_text: &'a str,
70    flags_text: Option<&'a str>,
71    options: Options,
72}
73
74impl<'a> ConstructorParser<'a> {
75    pub fn new(pattern_text: &'a str, flags_text: Option<&'a str>, options: Options) -> Self {
76        Self {
77            pattern_text,
78            flags_text,
79            options,
80        }
81    }
82
83    pub fn parse(self) -> Result<ast::Pattern> {
84        let parse_string_literal = true;
85        let Options {
86            pattern_span_offset,
87            flags_span_offset,
88        } = self.options;
89
90        let (unicode_mode, unicode_sets_mode) = if let Some(flags_text) = self.flags_text {
91            let reader =
92                Reader::initialize(flags_text, true, parse_string_literal).map_err(|_| {
93                    let span_start = flags_span_offset;
94                    #[expect(clippy::cast_possible_truncation)]
95                    let span_end = flags_span_offset + flags_text.len() as u32;
96                    diagnostics::invalid_input(SpanFactory::span_from_u32(span_start, span_end))
97                })?;
98
99            FlagsParser::new(reader, self.options.flags_span_offset).parse()?
100        } else {
101            (false, false)
102        };
103
104        let pattern_text = if matches!(self.pattern_text, r#""""# | "''") {
105            r#""(?:)""#
106        } else {
107            self.pattern_text
108        };
109        let reader =
110            Reader::initialize(pattern_text, unicode_mode, parse_string_literal).map_err(|_| {
111                let span_start = pattern_span_offset;
112                #[expect(clippy::cast_possible_truncation)]
113                let span_end = pattern_span_offset + pattern_text.len() as u32;
114                diagnostics::invalid_input(SpanFactory::span_from_u32(span_start, span_end))
115            })?;
116
117        PatternParser::new(
118            reader,
119            (unicode_mode, unicode_sets_mode),
120            pattern_span_offset,
121        )
122        .parse()
123    }
124}