swc_ecma_lexer/parser/
mod.rs

1#![allow(clippy::let_unit_value)]
2#![deny(non_snake_case)]
3
4use swc_ecma_ast::*;
5
6use crate::{
7    common::{
8        input::Tokens,
9        parser::{
10            buffer::Buffer as BufferTrait,
11            expr::{parse_lhs_expr, parse_primary_expr, parse_tagged_tpl, parse_unary_expr},
12            jsx::parse_jsx_element,
13            module_item::parse_module_item_block_body,
14            parse_shebang,
15            stmt::parse_stmt_block_body,
16            typescript::ts_in_no_context,
17            Parser as ParserTrait,
18        },
19    },
20    error::Error,
21    input::Buffer,
22    token::{Token, TokenAndSpan},
23    Context, *,
24};
25
26#[macro_use]
27mod macros;
28#[cfg(feature = "typescript")]
29mod typescript;
30
31/// EcmaScript parser.
32#[derive(Clone)]
33pub struct Parser<I: Tokens<TokenAndSpan>> {
34    state: crate::common::parser::state::State,
35    input: Buffer<I>,
36    found_module_item: bool,
37}
38
39impl<'a, I: Tokens<TokenAndSpan>> crate::common::parser::Parser<'a> for Parser<I> {
40    type Buffer = Buffer<I>;
41    type Checkpoint = Self;
42    type I = I;
43    type Next = TokenAndSpan;
44    type Token = Token;
45    type TokenAndSpan = TokenAndSpan;
46
47    #[inline(always)]
48    fn input(&self) -> &Self::Buffer {
49        &self.input
50    }
51
52    #[inline(always)]
53    fn input_mut(&mut self) -> &mut Self::Buffer {
54        &mut self.input
55    }
56
57    #[inline(always)]
58    fn state(&self) -> &common::parser::state::State {
59        &self.state
60    }
61
62    #[inline(always)]
63    fn state_mut(&mut self) -> &mut common::parser::state::State {
64        &mut self.state
65    }
66
67    fn checkpoint_save(&self) -> Self::Checkpoint {
68        self.clone()
69    }
70
71    fn checkpoint_load(&mut self, checkpoint: Self::Checkpoint) {
72        *self = checkpoint;
73    }
74
75    #[inline(always)]
76    fn mark_found_module_item(&mut self) {
77        self.found_module_item = true;
78    }
79
80    #[inline(always)]
81    fn parse_unary_expr(&mut self) -> PResult<Box<Expr>> {
82        parse_unary_expr(self)
83    }
84
85    #[inline(always)]
86    fn parse_jsx_element(
87        &mut self,
88        _in_expr_context: bool,
89    ) -> PResult<either::Either<JSXFragment, JSXElement>> {
90        parse_jsx_element(self)
91    }
92
93    #[inline(always)]
94    fn parse_primary_expr(&mut self) -> PResult<Box<Expr>> {
95        parse_primary_expr(self)
96    }
97
98    #[inline(always)]
99    fn ts_in_no_context<T>(&mut self, op: impl FnOnce(&mut Self) -> PResult<T>) -> PResult<T> {
100        ts_in_no_context(self, op)
101    }
102
103    fn parse_tagged_tpl(
104        &mut self,
105        tag: Box<Expr>,
106        type_params: Option<Box<TsTypeParamInstantiation>>,
107    ) -> PResult<TaggedTpl> {
108        parse_tagged_tpl(self, tag, type_params)
109    }
110
111    fn parse_tagged_tpl_ty(&mut self) -> PResult<TsLitType> {
112        unreachable!("use `common::parser::expr::parse_ts_tpl_lit_type` directly");
113    }
114
115    fn parse_lhs_expr(&mut self) -> PResult<Box<Expr>> {
116        parse_lhs_expr::<Self, true>(self)
117    }
118}
119
120impl<I: Tokens<TokenAndSpan>> Parser<I> {
121    pub fn new_from(mut input: I) -> Self {
122        let in_declare = input.syntax().dts();
123        let mut ctx = input.ctx() | Context::TopLevel;
124        ctx.set(Context::InDeclare, in_declare);
125        input.set_ctx(ctx);
126
127        let mut p = Parser {
128            state: Default::default(),
129            input: Buffer::new(input),
130            found_module_item: false,
131        };
132        p.input.bump(); // consume EOF
133        p
134    }
135
136    pub fn take_errors(&mut self) -> Vec<Error> {
137        self.input.iter.take_errors()
138    }
139
140    pub fn take_script_module_errors(&mut self) -> Vec<Error> {
141        self.input.iter.take_script_module_errors()
142    }
143
144    pub fn parse_script(&mut self) -> PResult<Script> {
145        trace_cur!(self, parse_script);
146
147        let ctx = (self.ctx() & !Context::Module) | Context::TopLevel;
148        self.set_ctx(ctx);
149
150        let start = self.cur_pos();
151
152        let shebang = parse_shebang(self)?;
153
154        let ret = parse_stmt_block_body(self, true, None).map(|body| Script {
155            span: self.span(start),
156            body,
157            shebang,
158        })?;
159
160        Ok(ret)
161    }
162
163    pub fn parse_commonjs(&mut self) -> PResult<Script> {
164        trace_cur!(self, parse_commonjs);
165
166        // CommonJS module is acctually in a function scope
167        let ctx = (self.ctx() & !Context::Module)
168            | Context::InFunction
169            | Context::InsideNonArrowFunctionScope;
170        self.set_ctx(ctx);
171
172        let start = self.cur_pos();
173        let shebang = parse_shebang(self)?;
174
175        let ret = parse_stmt_block_body(self, true, None).map(|body| Script {
176            span: self.span(start),
177            body,
178            shebang,
179        })?;
180
181        debug_assert!(self.input().cur() == &Token::Eof);
182        self.input_mut().bump();
183
184        Ok(ret)
185    }
186
187    #[cfg(test)]
188    pub fn parse_typescript_module(&mut self) -> PResult<Module> {
189        trace_cur!(self, parse_typescript_module);
190
191        debug_assert!(self.syntax().typescript());
192
193        //TODO: parse() -> PResult<Program>
194        let ctx = (self.ctx() | Context::Module | Context::TopLevel) & !Context::Strict; // Module code is always in strict mode
195        self.set_ctx(ctx);
196
197        let start = self.cur_pos();
198        let shebang = parse_shebang(self)?;
199
200        let ret = parse_module_item_block_body(self, true, None).map(|body| Module {
201            span: self.span(start),
202            body,
203            shebang,
204        })?;
205
206        debug_assert!(self.input().cur() == &Token::Eof);
207        self.input_mut().bump();
208
209        Ok(ret)
210    }
211
212    /// Returns [Module] if it's a module and returns [Script] if it's not a
213    /// module.
214    ///
215    /// Note: This is not perfect yet. It means, some strict mode violations may
216    /// not be reported even if the method returns [Module].
217    pub fn parse_program(&mut self) -> PResult<Program> {
218        let start = self.cur_pos();
219        let shebang = parse_shebang(self)?;
220
221        let body: Vec<ModuleItem> = self
222            .do_inside_of_context(Context::CanBeModule.union(Context::TopLevel), |p| {
223                parse_module_item_block_body(p, true, None)
224            })?;
225        let has_module_item = self.found_module_item
226            || body
227                .iter()
228                .any(|item| matches!(item, ModuleItem::ModuleDecl(..)));
229        if has_module_item && !self.ctx().contains(Context::Module) {
230            let ctx = self.ctx()
231                | Context::Module
232                | Context::CanBeModule
233                | Context::TopLevel
234                | Context::Strict;
235            // Emit buffered strict mode / module code violations
236            self.input.set_ctx(ctx);
237        }
238
239        let ret = if has_module_item {
240            Program::Module(Module {
241                span: self.span(start),
242                body,
243                shebang,
244            })
245        } else {
246            let body = body
247                .into_iter()
248                .map(|item| match item {
249                    ModuleItem::ModuleDecl(_) => unreachable!(
250                        "Module is handled
251    above"
252                    ),
253                    ModuleItem::Stmt(stmt) => stmt,
254                })
255                .collect();
256            Program::Script(Script {
257                span: self.span(start),
258                body,
259                shebang,
260            })
261        };
262
263        debug_assert!(self.input().cur() == &Token::Eof);
264        self.input_mut().bump();
265
266        Ok(ret)
267    }
268
269    pub fn parse_module(&mut self) -> PResult<Module> {
270        let ctx = self.ctx()
271            | Context::Module
272            | Context::CanBeModule
273            | Context::TopLevel
274            | Context::Strict;
275        // Module code is always in strict mode
276        self.set_ctx(ctx);
277
278        let start = self.cur_pos();
279        let shebang = parse_shebang(self)?;
280
281        let ret = parse_module_item_block_body(self, true, None).map(|body| Module {
282            span: self.span(start),
283            body,
284            shebang,
285        })?;
286
287        debug_assert!(self.input().cur() == &Token::Eof);
288        self.input_mut().bump();
289
290        Ok(ret)
291    }
292}