1#![cfg_attr(docsrs, feature(doc_cfg))]
117#![cfg_attr(test, feature(test))]
118#![deny(clippy::all)]
119#![deny(unused)]
120#![allow(clippy::nonminimal_bool)]
121#![allow(clippy::too_many_arguments)]
122#![allow(clippy::unnecessary_unwrap)]
123#![allow(clippy::vec_box)]
124#![allow(clippy::wrong_self_convention)]
125#![allow(clippy::match_like_matches_macro)]
126
127use error::Error;
128use lexer::Lexer;
129use serde::{Deserialize, Serialize};
130pub use swc_common::input::{Input, StringInput};
131use swc_common::{comments::Comments, input::SourceFileInput, SourceFile};
132use swc_ecma_ast::*;
133
134pub use self::parser::*;
135
136#[macro_use]
137mod macros;
138#[macro_use]
139pub mod token;
140pub mod error;
141pub mod lexer;
142mod parser;
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
145#[serde(deny_unknown_fields, tag = "syntax")]
146pub enum Syntax {
147 #[serde(rename = "ecmascript")]
149 Es(EsSyntax),
150 #[cfg(feature = "typescript")]
152 #[cfg_attr(docsrs, doc(cfg(feature = "typescript")))]
153 #[serde(rename = "typescript")]
154 Typescript(TsSyntax),
155}
156
157impl Default for Syntax {
158 fn default() -> Self {
159 Syntax::Es(Default::default())
160 }
161}
162
163impl Syntax {
164 fn auto_accessors(self) -> bool {
165 match self {
166 Syntax::Es(EsSyntax {
167 auto_accessors: true,
168 ..
169 }) => true,
170 #[cfg(feature = "typescript")]
171 Syntax::Typescript(_) => true,
172 _ => false,
173 }
174 }
175
176 pub fn import_attributes(self) -> bool {
177 match self {
178 Syntax::Es(EsSyntax {
179 import_attributes, ..
180 }) => import_attributes,
181 #[cfg(feature = "typescript")]
182 Syntax::Typescript(_) => true,
183 }
184 }
185
186 pub fn jsx(self) -> bool {
188 match self {
189 Syntax::Es(EsSyntax { jsx: true, .. }) => true,
190 #[cfg(feature = "typescript")]
191 Syntax::Typescript(TsSyntax { tsx: true, .. }) => true,
192 _ => false,
193 }
194 }
195
196 pub fn fn_bind(self) -> bool {
197 matches!(self, Syntax::Es(EsSyntax { fn_bind: true, .. }))
198 }
199
200 pub fn decorators(self) -> bool {
201 match self {
202 Syntax::Es(EsSyntax {
203 decorators: true, ..
204 }) => true,
205 #[cfg(feature = "typescript")]
206 Syntax::Typescript(TsSyntax {
207 decorators: true, ..
208 }) => true,
209 _ => false,
210 }
211 }
212
213 pub fn decorators_before_export(self) -> bool {
214 match self {
215 Syntax::Es(EsSyntax {
216 decorators_before_export: true,
217 ..
218 }) => true,
219 #[cfg(feature = "typescript")]
220 Syntax::Typescript(..) => true,
221 _ => false,
222 }
223 }
224
225 #[cfg(not(feature = "typescript"))]
227 pub const fn typescript(self) -> bool {
228 false
229 }
230
231 #[cfg(feature = "typescript")]
233 pub const fn typescript(self) -> bool {
234 matches!(self, Syntax::Typescript(..))
235 }
236
237 pub fn export_default_from(self) -> bool {
238 matches!(
239 self,
240 Syntax::Es(EsSyntax {
241 export_default_from: true,
242 ..
243 })
244 )
245 }
246
247 pub fn dts(self) -> bool {
248 match self {
249 #[cfg(feature = "typescript")]
250 Syntax::Typescript(t) => t.dts,
251 _ => false,
252 }
253 }
254
255 pub(crate) fn allow_super_outside_method(self) -> bool {
256 match self {
257 Syntax::Es(EsSyntax {
258 allow_super_outside_method,
259 ..
260 }) => allow_super_outside_method,
261 #[cfg(feature = "typescript")]
262 Syntax::Typescript(_) => true,
263 }
264 }
265
266 pub(crate) fn allow_return_outside_function(self) -> bool {
267 match self {
268 Syntax::Es(EsSyntax {
269 allow_return_outside_function,
270 ..
271 }) => allow_return_outside_function,
272 #[cfg(feature = "typescript")]
273 Syntax::Typescript(_) => false,
274 }
275 }
276
277 pub(crate) fn early_errors(self) -> bool {
278 match self {
279 #[cfg(feature = "typescript")]
280 Syntax::Typescript(t) => !t.no_early_errors,
281 Syntax::Es(..) => true,
282 }
283 }
284
285 fn disallow_ambiguous_jsx_like(self) -> bool {
286 match self {
287 #[cfg(feature = "typescript")]
288 Syntax::Typescript(t) => t.disallow_ambiguous_jsx_like,
289 _ => false,
290 }
291 }
292
293 pub fn explicit_resource_management(&self) -> bool {
294 match self {
295 Syntax::Es(EsSyntax {
296 explicit_resource_management: using_decl,
297 ..
298 }) => *using_decl,
299 #[cfg(feature = "typescript")]
300 Syntax::Typescript(_) => true,
301 }
302 }
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
306#[serde(rename_all = "camelCase")]
307pub struct TsSyntax {
308 #[serde(default)]
309 pub tsx: bool,
310
311 #[serde(default)]
312 pub decorators: bool,
313
314 #[serde(skip, default)]
316 pub dts: bool,
317
318 #[serde(skip, default)]
319 pub no_early_errors: bool,
320
321 #[serde(skip, default)]
327 pub disallow_ambiguous_jsx_like: bool,
328}
329
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
331#[serde(rename_all = "camelCase")]
332pub struct EsSyntax {
333 #[serde(default)]
334 pub jsx: bool,
335
336 #[serde(rename = "functionBind")]
338 #[serde(default)]
339 pub fn_bind: bool,
340
341 #[serde(default)]
343 pub decorators: bool,
344
345 #[serde(rename = "decoratorsBeforeExport")]
349 #[serde(default)]
350 pub decorators_before_export: bool,
351
352 #[serde(default)]
353 pub export_default_from: bool,
354
355 #[serde(default, alias = "importAssertions")]
357 pub import_attributes: bool,
358
359 #[serde(default, rename = "allowSuperOutsideMethod")]
360 pub allow_super_outside_method: bool,
361
362 #[serde(default, rename = "allowReturnOutsideFunction")]
363 pub allow_return_outside_function: bool,
364
365 #[serde(default)]
366 pub auto_accessors: bool,
367
368 #[serde(default)]
369 pub explicit_resource_management: bool,
370}
371
372#[derive(Debug, Clone, Copy, Default)]
374pub struct Context {
375 ignore_error: bool,
377
378 module: bool,
380 can_be_module: bool,
381 strict: bool,
382
383 expr_ctx: ExpressionContext,
384
385 include_in_expr: bool,
386 in_async: bool,
389 in_generator: bool,
392
393 in_static_block: bool,
395
396 is_continue_allowed: bool,
397 is_break_allowed: bool,
398
399 in_type: bool,
400 should_not_lex_lt_or_gt_as_type: bool,
402 in_declare: bool,
404
405 in_cond_expr: bool,
407 will_expect_colon_for_cond: bool,
408
409 in_class: bool,
410
411 in_class_field: bool,
412
413 in_function: bool,
414
415 inside_non_arrow_function_scope: bool,
418
419 in_parameters: bool,
420
421 has_super_class: bool,
422
423 in_property_name: bool,
424
425 in_forced_jsx_context: bool,
426
427 allow_direct_super: bool,
429
430 ignore_else_clause: bool,
431
432 disallow_conditional_types: bool,
433
434 allow_using_decl: bool,
435}
436
437#[derive(Debug, Clone, Copy, Default)]
438struct ExpressionContext {
439 for_loop_init: bool,
442 for_await_loop_init: bool,
443}
444
445#[cfg(test)]
446fn with_test_sess<F, Ret>(src: &str, f: F) -> Result<Ret, ::testing::StdErr>
447where
448 F: FnOnce(&swc_common::errors::Handler, StringInput<'_>) -> Result<Ret, ()>,
449{
450 use swc_common::FileName;
451
452 ::testing::run_test(false, |cm, handler| {
453 let fm = cm.new_source_file(FileName::Real("testing".into()).into(), src.into());
454
455 f(handler, (&*fm).into())
456 })
457}
458
459pub fn with_file_parser<T>(
460 fm: &SourceFile,
461 syntax: Syntax,
462 target: EsVersion,
463 comments: Option<&dyn Comments>,
464 recovered_errors: &mut Vec<Error>,
465 op: impl for<'aa> FnOnce(&mut Parser<Lexer>) -> PResult<T>,
466) -> PResult<T> {
467 let lexer = Lexer::new(syntax, target, SourceFileInput::from(fm), comments);
468 let mut p = Parser::new_from(lexer);
469 let ret = op(&mut p);
470
471 recovered_errors.append(&mut p.take_errors());
472
473 ret
474}
475
476macro_rules! expose {
477 (
478 $name:ident,
479 $T:ty,
480 $($t:tt)*
481 ) => {
482 pub fn $name(
487 fm: &SourceFile,
488 syntax: Syntax,
489 target: EsVersion,
490 comments: Option<&dyn Comments>,
491 recovered_errors: &mut Vec<Error>,
492 ) -> PResult<$T> {
493 with_file_parser(fm, syntax, target, comments, recovered_errors, $($t)*)
494 }
495 };
496}
497
498expose!(parse_file_as_expr, Box<Expr>, |p| {
499 p.input().ctx.can_be_module = true;
501 p.parse_expr()
502});
503expose!(parse_file_as_module, Module, |p| { p.parse_module() });
504expose!(parse_file_as_script, Script, |p| { p.parse_script() });
505expose!(parse_file_as_program, Program, |p| { p.parse_program() });
506
507#[inline(always)]
508#[cfg(any(
509 target_arch = "wasm32",
510 target_arch = "arm",
511 not(feature = "stacker"),
512 miri
514))]
515fn maybe_grow<R, F: FnOnce() -> R>(_red_zone: usize, _stack_size: usize, callback: F) -> R {
516 callback()
517}
518
519#[inline(always)]
520#[cfg(all(
521 not(any(target_arch = "wasm32", target_arch = "arm", miri)),
522 feature = "stacker"
523))]
524fn maybe_grow<R, F: FnOnce() -> R>(red_zone: usize, stack_size: usize, callback: F) -> R {
525 stacker::maybe_grow(red_zone, stack_size, callback)
526}