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