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
43pub type PResult<T> = Result<T, Error>;
45
46#[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 potential_arrow_start: Option<BytePos>,
59 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 let ctx = (self.ctx() | Context::Module | Context::TopLevel) & !Context::Strict;
121 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 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 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 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}