swc_ecma_regexp/parser/reader/
reader_impl.rs

1use swc_atoms::Atom;
2
3use crate::{
4    diagnostics::Result,
5    parser::reader::string_literal_parser::{
6        ast as StringLiteralAst, parse_regexp_literal, Options as StringLiteralParserOptions,
7        Parser as StringLiteralParser,
8    },
9};
10
11pub struct Reader<'a> {
12    source_text: &'a str,
13    units: Vec<StringLiteralAst::CodePoint>,
14    index: usize,
15    offset: u32,
16}
17
18impl<'a> Reader<'a> {
19    pub fn initialize(
20        source_text: &'a str,
21        unicode_mode: bool,
22        parse_string_literal: bool,
23    ) -> Result<Self> {
24        // NOTE: This must be `0`.
25        // Since `source_text` here may be a slice of the original source text,
26        // using `Span` for `span.source_text(source_text)` will be out of range in some
27        // cases.
28        let span_offset = 0;
29
30        let units = if parse_string_literal {
31            let StringLiteralAst::StringLiteral { body, .. } = StringLiteralParser::new(
32                source_text,
33                StringLiteralParserOptions {
34                    strict_mode: false,
35                    span_offset,
36                    combine_surrogate_pair: unicode_mode,
37                },
38            )
39            .parse()?;
40            body
41        } else {
42            parse_regexp_literal(source_text, span_offset, unicode_mode)
43        };
44
45        Ok(Self {
46            source_text,
47            units,
48            index: 0,
49            // If `parse_string_literal` is `true`, the first character is the opening quote.
50            // We need to +1 to skip it.
51            offset: u32::from(parse_string_literal),
52        })
53    }
54
55    pub fn offset(&self) -> u32 {
56        self.offset
57    }
58
59    pub fn checkpoint(&self) -> (usize, u32) {
60        (self.index, self.offset)
61    }
62
63    pub fn rewind(&mut self, checkpoint: (usize, u32)) {
64        self.index = checkpoint.0;
65        self.offset = checkpoint.1;
66    }
67
68    pub fn advance(&mut self) {
69        if let Some(unit) = self.units.get(self.index) {
70            self.offset = unit.span.hi.0;
71            self.index += 1;
72        }
73    }
74
75    fn peek_nth(&self, n: usize) -> Option<u32> {
76        let nth = self.index + n;
77        self.units.get(nth).map(|cp| cp.value)
78    }
79
80    pub fn peek(&self) -> Option<u32> {
81        self.peek_nth(0)
82    }
83
84    pub fn peek2(&self) -> Option<u32> {
85        self.peek_nth(1)
86    }
87
88    pub fn eat(&mut self, ch: char) -> bool {
89        if self.peek_nth(0) == Some(ch as u32) {
90            self.advance();
91            return true;
92        }
93        false
94    }
95
96    pub fn eat2(&mut self, ch: char, ch2: char) -> bool {
97        if self.peek_nth(0) == Some(ch as u32) && self.peek_nth(1) == Some(ch2 as u32) {
98            self.advance();
99            self.advance();
100            return true;
101        }
102        false
103    }
104
105    pub fn eat3(&mut self, ch: char, ch2: char, ch3: char) -> bool {
106        if self.peek_nth(0) == Some(ch as u32)
107            && self.peek_nth(1) == Some(ch2 as u32)
108            && self.peek_nth(2) == Some(ch3 as u32)
109        {
110            self.advance();
111            self.advance();
112            self.advance();
113            return true;
114        }
115        false
116    }
117
118    pub fn eat4(&mut self, ch: char, ch2: char, ch3: char, ch4: char) -> bool {
119        if self.peek_nth(0) == Some(ch as u32)
120            && self.peek_nth(1) == Some(ch2 as u32)
121            && self.peek_nth(2) == Some(ch3 as u32)
122            && self.peek_nth(3) == Some(ch4 as u32)
123        {
124            self.advance();
125            self.advance();
126            self.advance();
127            self.advance();
128            return true;
129        }
130        false
131    }
132
133    pub fn atom(&self, start: u32, end: u32) -> Atom {
134        Atom::from(&self.source_text[start as usize..end as usize])
135    }
136}