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
42pub type PResult<T> = Result<T, Error>;
44
45#[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 potential_arrow_start: Option<BytePos>,
57
58 found_module_item: bool,
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 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 let ctx = Context {
125 module: true,
126 strict: false,
127 ..self.ctx()
128 };
129 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 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 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 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}