swc_ecma_parser/parser/
mod.rs

1#![allow(clippy::let_unit_value)]
2#![deny(non_snake_case)]
3
4use std::ops::{Deref, DerefMut};
5
6use rustc_hash::FxHashMap;
7use swc_atoms::Atom;
8use swc_common::{comments::Comments, input::StringInput, BytePos, Span};
9use swc_ecma_ast::*;
10pub use swc_ecma_lexer::input::{Capturing, Tokens, TokensInput};
11use swc_ecma_lexer::{
12    error::SyntaxError,
13    input::Buffer,
14    token::{Token, Word},
15    Lexer, *,
16};
17
18use self::util::ParseObject;
19use crate::{Context, EsVersion, Syntax, TsSyntax};
20#[cfg(test)]
21extern crate test;
22#[cfg(test)]
23use test::Bencher;
24
25use crate::error::Error;
26
27#[macro_use]
28mod macros;
29mod class_and_fn;
30mod expr;
31mod ident;
32pub mod input;
33mod jsx;
34mod object;
35mod pat;
36mod stmt;
37#[cfg(test)]
38mod tests;
39#[cfg(feature = "typescript")]
40mod typescript;
41mod util;
42
43/// When error occurs, error is emitted and parser returns Err(()).
44pub type PResult<T> = Result<T, Error>;
45
46/// EcmaScript parser.
47#[derive(Clone)]
48pub struct Parser<I: Tokens> {
49    state: State,
50    input: Buffer<I>,
51    found_module_item: bool,
52}
53
54#[derive(Clone, Default)]
55struct State {
56    labels: Vec<Atom>,
57    /// Start position of an assignment expression.
58    potential_arrow_start: Option<BytePos>,
59    /// Start position of an AST node and the span of its trailing comma.
60    trailing_commas: FxHashMap<BytePos, Span>,
61}
62
63impl<'a> Parser<Lexer<'a>> {
64    pub fn new(syntax: Syntax, input: StringInput<'a>, comments: Option<&'a dyn Comments>) -> Self {
65        Self::new_from(Lexer::new(syntax, Default::default(), input, comments))
66    }
67}
68
69impl<I: Tokens> Parser<I> {
70    pub fn new_from(mut input: I) -> Self {
71        #[cfg(feature = "typescript")]
72        let in_declare = matches!(
73            input.syntax(),
74            Syntax::Typescript(TsSyntax { dts: true, .. })
75        );
76        #[cfg(not(feature = "typescript"))]
77        let in_declare = false;
78        let mut ctx = input.ctx() | Context::TopLevel;
79        ctx.set(Context::InDeclare, in_declare);
80        input.set_ctx(ctx);
81
82        Parser {
83            state: Default::default(),
84            input: Buffer::new(input),
85            found_module_item: false,
86        }
87    }
88
89    pub fn take_errors(&mut self) -> Vec<Error> {
90        self.input().take_errors()
91    }
92
93    pub fn take_script_module_errors(&mut self) -> Vec<Error> {
94        self.input().take_script_module_errors()
95    }
96
97    pub fn parse_script(&mut self) -> PResult<Script> {
98        trace_cur!(self, parse_script);
99
100        let ctx = (self.ctx() & !Context::Module) | Context::TopLevel;
101        self.set_ctx(ctx);
102
103        let start = cur_pos!(self);
104
105        let shebang = self.parse_shebang()?;
106
107        self.parse_block_body(true, None).map(|body| Script {
108            span: span!(self, start),
109            body,
110            shebang,
111        })
112    }
113
114    pub fn parse_typescript_module(&mut self) -> PResult<Module> {
115        trace_cur!(self, parse_typescript_module);
116
117        debug_assert!(self.syntax().typescript());
118
119        //TODO: parse() -> PResult<Program>
120        let ctx = (self.ctx() | Context::Module | Context::TopLevel) & !Context::Strict;
121        // Module code is always in strict mode
122        self.set_ctx(ctx);
123
124        let start = cur_pos!(self);
125        let shebang = self.parse_shebang()?;
126
127        self.parse_block_body(true, None).map(|body| Module {
128            span: span!(self, start),
129            body,
130            shebang,
131        })
132    }
133
134    /// Returns [Module] if it's a module and returns [Script] if it's not a
135    /// module.
136    ///
137    /// Note: This is not perfect yet. It means, some strict mode violations may
138    /// not be reported even if the method returns [Module].
139    pub fn parse_program(&mut self) -> PResult<Program> {
140        let start = cur_pos!(self);
141        let shebang = self.parse_shebang()?;
142        let ctx = self.ctx() | Context::CanBeModule | Context::TopLevel;
143
144        let body: Vec<ModuleItem> = self.with_ctx(ctx).parse_block_body(true, None)?;
145        let has_module_item = self.found_module_item
146            || body
147                .iter()
148                .any(|item| matches!(item, ModuleItem::ModuleDecl(..)));
149        if has_module_item && !self.ctx().contains(Context::Module) {
150            let ctx = self.ctx()
151                | Context::Module
152                | Context::CanBeModule
153                | Context::TopLevel
154                | Context::Strict;
155            // Emit buffered strict mode / module code violations
156            self.input.set_ctx(ctx);
157        }
158
159        Ok(if has_module_item {
160            Program::Module(Module {
161                span: span!(self, start),
162                body,
163                shebang,
164            })
165        } else {
166            let body = body
167                .into_iter()
168                .map(|item| match item {
169                    ModuleItem::ModuleDecl(_) => unreachable!("Module is handled above"),
170                    ModuleItem::Stmt(stmt) => stmt,
171                })
172                .collect();
173            Program::Script(Script {
174                span: span!(self, start),
175                body,
176                shebang,
177            })
178        })
179    }
180
181    pub fn parse_module(&mut self) -> PResult<Module> {
182        let ctx = self.ctx()
183            | Context::Module
184            | Context::CanBeModule
185            | Context::TopLevel
186            | Context::Strict;
187        // Module code is always in strict mode
188        self.set_ctx(ctx);
189
190        let start = cur_pos!(self);
191        let shebang = self.parse_shebang()?;
192
193        self.parse_block_body(true, None).map(|body| Module {
194            span: span!(self, start),
195            body,
196            shebang,
197        })
198    }
199
200    fn parse_shebang(&mut self) -> PResult<Option<Atom>> {
201        match cur!(self, false) {
202            Ok(&Token::Shebang(..)) => match bump!(self) {
203                Token::Shebang(v) => Ok(Some(v)),
204                _ => unreachable!(),
205            },
206            _ => Ok(None),
207        }
208    }
209
210    fn ctx(&self) -> Context {
211        self.input.get_ctx()
212    }
213
214    #[cold]
215    fn emit_err(&mut self, span: Span, error: SyntaxError) {
216        if self.ctx().contains(Context::IgnoreError) || !self.syntax().early_errors() {
217            return;
218        }
219
220        self.emit_error(Error::new(span, error))
221    }
222
223    #[cold]
224    fn emit_error(&mut self, error: Error) {
225        if self.ctx().contains(Context::IgnoreError) || !self.syntax().early_errors() {
226            return;
227        }
228
229        if matches!(self.input.cur(), Some(Token::Error(..))) {
230            let err = self.input.bump();
231            match err {
232                Token::Error(err) => {
233                    self.input_ref().add_error(err);
234                }
235                _ => unreachable!(),
236            }
237        }
238
239        self.input_ref().add_error(error);
240    }
241
242    #[cold]
243    fn emit_strict_mode_err(&self, span: Span, error: SyntaxError) {
244        if self.ctx().contains(Context::IgnoreError) {
245            return;
246        }
247        let error = Error::new(span, error);
248        self.input_ref().add_module_mode_error(error);
249    }
250}
251
252#[cfg(test)]
253pub fn test_parser<F, Ret>(s: &'static str, syntax: Syntax, f: F) -> Ret
254where
255    F: FnOnce(&mut Parser<Lexer>) -> Result<Ret, Error>,
256{
257    crate::with_test_sess(s, |handler, input| {
258        let lexer = Lexer::new(syntax, EsVersion::Es2019, input, None);
259        let mut p = Parser::new_from(lexer);
260        let ret = f(&mut p);
261        let mut error = false;
262
263        for err in p.take_errors() {
264            error = true;
265            err.into_diagnostic(handler).emit();
266        }
267
268        let res = ret.map_err(|err| err.into_diagnostic(handler).emit())?;
269
270        if error {
271            return Err(());
272        }
273
274        Ok(res)
275    })
276    .unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{s}\n{output}"))
277}
278
279#[cfg(test)]
280pub fn test_parser_comment<F, Ret>(c: &dyn Comments, s: &'static str, syntax: Syntax, f: F) -> Ret
281where
282    F: FnOnce(&mut Parser<Lexer>) -> Result<Ret, Error>,
283{
284    crate::with_test_sess(s, |handler, input| {
285        let lexer = Lexer::new(syntax, EsVersion::Es2019, input, Some(&c));
286        let mut p = Parser::new_from(lexer);
287        let ret = f(&mut p);
288
289        for err in p.take_errors() {
290            err.into_diagnostic(handler).emit();
291        }
292
293        ret.map_err(|err| err.into_diagnostic(handler).emit())
294    })
295    .unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{s}\n{output}"))
296}
297
298#[cfg(test)]
299pub fn bench_parser<F>(b: &mut Bencher, s: &'static str, syntax: Syntax, mut f: F)
300where
301    F: for<'a> FnMut(&'a mut Parser<Lexer<'a>>) -> PResult<()>,
302{
303    b.bytes = s.len() as u64;
304
305    let _ = crate::with_test_sess(s, |handler, input| {
306        b.iter(|| {
307            let lexer = Lexer::new(syntax, Default::default(), input.clone(), None);
308            let _ =
309                f(&mut Parser::new_from(lexer)).map_err(|err| err.into_diagnostic(handler).emit());
310        });
311
312        Ok(())
313    });
314}