1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(test, feature(test))]
3#![deny(clippy::all)]
4#![deny(unused)]
5#![allow(clippy::nonminimal_bool)]
6#![allow(clippy::too_many_arguments)]
7#![allow(clippy::unnecessary_unwrap)]
8#![allow(clippy::vec_box)]
9#![allow(clippy::wrong_self_convention)]
10#![allow(clippy::match_like_matches_macro)]
11
12use serde::{Deserialize, Serialize};
13
14pub mod lexer;
15
16use input::Tokens;
17pub use lexer::*;
18
19#[macro_use]
20pub mod token;
21pub mod error;
22pub mod input;
23mod utils;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
26#[serde(deny_unknown_fields, tag = "syntax")]
27pub enum Syntax {
28 #[serde(rename = "ecmascript")]
30 Es(EsSyntax),
31 #[cfg(feature = "typescript")]
33 #[cfg_attr(docsrs, doc(cfg(feature = "typescript")))]
34 #[serde(rename = "typescript")]
35 Typescript(TsSyntax),
36}
37
38impl Default for Syntax {
39 fn default() -> Self {
40 Syntax::Es(Default::default())
41 }
42}
43
44impl Syntax {
45 pub fn auto_accessors(self) -> bool {
46 match self {
47 Syntax::Es(EsSyntax {
48 auto_accessors: true,
49 ..
50 }) => true,
51 #[cfg(feature = "typescript")]
52 Syntax::Typescript(_) => true,
53 _ => false,
54 }
55 }
56
57 pub fn import_attributes(self) -> bool {
58 match self {
59 Syntax::Es(EsSyntax {
60 import_attributes, ..
61 }) => import_attributes,
62 #[cfg(feature = "typescript")]
63 Syntax::Typescript(_) => true,
64 }
65 }
66
67 pub fn jsx(self) -> bool {
69 match self {
70 Syntax::Es(EsSyntax { jsx: true, .. }) => true,
71 #[cfg(feature = "typescript")]
72 Syntax::Typescript(TsSyntax { tsx: true, .. }) => true,
73 _ => false,
74 }
75 }
76
77 pub fn fn_bind(self) -> bool {
78 matches!(self, Syntax::Es(EsSyntax { fn_bind: true, .. }))
79 }
80
81 pub fn decorators(self) -> bool {
82 match self {
83 Syntax::Es(EsSyntax {
84 decorators: true, ..
85 }) => true,
86 #[cfg(feature = "typescript")]
87 Syntax::Typescript(TsSyntax {
88 decorators: true, ..
89 }) => true,
90 _ => false,
91 }
92 }
93
94 pub fn decorators_before_export(self) -> bool {
95 match self {
96 Syntax::Es(EsSyntax {
97 decorators_before_export: true,
98 ..
99 }) => true,
100 #[cfg(feature = "typescript")]
101 Syntax::Typescript(..) => true,
102 _ => false,
103 }
104 }
105
106 #[cfg(not(feature = "typescript"))]
108 pub const fn typescript(self) -> bool {
109 false
110 }
111
112 #[cfg(feature = "typescript")]
114 pub const fn typescript(self) -> bool {
115 matches!(self, Syntax::Typescript(..))
116 }
117
118 pub fn export_default_from(self) -> bool {
119 matches!(
120 self,
121 Syntax::Es(EsSyntax {
122 export_default_from: true,
123 ..
124 })
125 )
126 }
127
128 pub fn dts(self) -> bool {
129 match self {
130 #[cfg(feature = "typescript")]
131 Syntax::Typescript(t) => t.dts,
132 _ => false,
133 }
134 }
135
136 pub fn allow_super_outside_method(self) -> bool {
137 match self {
138 Syntax::Es(EsSyntax {
139 allow_super_outside_method,
140 ..
141 }) => allow_super_outside_method,
142 #[cfg(feature = "typescript")]
143 Syntax::Typescript(_) => true,
144 }
145 }
146
147 pub fn allow_return_outside_function(self) -> bool {
148 match self {
149 Syntax::Es(EsSyntax {
150 allow_return_outside_function,
151 ..
152 }) => allow_return_outside_function,
153 #[cfg(feature = "typescript")]
154 Syntax::Typescript(_) => false,
155 }
156 }
157
158 pub fn early_errors(self) -> bool {
159 match self {
160 #[cfg(feature = "typescript")]
161 Syntax::Typescript(t) => !t.no_early_errors,
162 Syntax::Es(..) => true,
163 }
164 }
165
166 pub fn disallow_ambiguous_jsx_like(self) -> bool {
167 match self {
168 #[cfg(feature = "typescript")]
169 Syntax::Typescript(t) => t.disallow_ambiguous_jsx_like,
170 _ => false,
171 }
172 }
173
174 pub fn explicit_resource_management(&self) -> bool {
175 match self {
176 Syntax::Es(EsSyntax {
177 explicit_resource_management: using_decl,
178 ..
179 }) => *using_decl,
180 #[cfg(feature = "typescript")]
181 Syntax::Typescript(_) => true,
182 }
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
187#[serde(rename_all = "camelCase")]
188pub struct TsSyntax {
189 #[serde(default)]
190 pub tsx: bool,
191
192 #[serde(default)]
193 pub decorators: bool,
194
195 #[serde(skip, default)]
197 pub dts: bool,
198
199 #[serde(skip, default)]
200 pub no_early_errors: bool,
201
202 #[serde(skip, default)]
208 pub disallow_ambiguous_jsx_like: bool,
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
212#[serde(rename_all = "camelCase")]
213pub struct EsSyntax {
214 #[serde(default)]
215 pub jsx: bool,
216
217 #[serde(rename = "functionBind")]
219 #[serde(default)]
220 pub fn_bind: bool,
221
222 #[serde(default)]
224 pub decorators: bool,
225
226 #[serde(rename = "decoratorsBeforeExport")]
230 #[serde(default)]
231 pub decorators_before_export: bool,
232
233 #[serde(default)]
234 pub export_default_from: bool,
235
236 #[serde(default, alias = "importAssertions")]
238 pub import_attributes: bool,
239
240 #[serde(default, rename = "allowSuperOutsideMethod")]
241 pub allow_super_outside_method: bool,
242
243 #[serde(default, rename = "allowReturnOutsideFunction")]
244 pub allow_return_outside_function: bool,
245
246 #[serde(default)]
247 pub auto_accessors: bool,
248
249 #[serde(default)]
250 pub explicit_resource_management: bool,
251}
252
253bitflags::bitflags! {
254 #[derive(Debug, Clone, Copy, Default)]
255 pub struct Context: u32 {
256
257 const IgnoreError = 1 << 0;
259
260 const Module = 1 << 1;
262 const CanBeModule = 1 << 2;
263 const Strict = 1 << 3;
264
265 const ForLoopInit = 1 << 4;
266 const ForAwaitLoopInit = 1 << 5;
267
268 const IncludeInExpr = 1 << 6;
269 const InAsync = 1 << 7;
272 const InGenerator = 1 << 8;
275
276 const InStaticBlock = 1 << 9;
278
279 const IsContinueAllowed = 1 << 10;
280 const IsBreakAllowed = 1 << 11;
281
282 const InType = 1 << 12;
283 const ShouldNotLexLtOrGtAsType = 1 << 13;
285 const InDeclare = 1 << 14;
287
288 const InCondExpr = 1 << 15;
290 const WillExpectColonForCond = 1 << 16;
291
292 const InClass = 1 << 17;
293
294 const InClassField = 1 << 18;
295
296 const InFunction = 1 << 19;
297
298 const InsideNonArrowFunctionScope = 1 << 20;
301
302 const InParameters = 1 << 21;
303
304 const HasSuperClass = 1 << 22;
305
306 const InPropertyName = 1 << 23;
307
308 const InForcedJsxContext = 1 << 24;
309
310 const AllowDirectSuper = 1 << 25;
312
313 const IgnoreElseClause = 1 << 26;
314
315 const DisallowConditionalTypes = 1 << 27;
316
317 const AllowUsingDecl = 1 << 28;
318
319 const TopLevel = 1 << 29;
320 }
321}
322
323#[cfg(test)]
324fn with_test_sess<F, Ret>(src: &str, f: F) -> Result<Ret, ::testing::StdErr>
325where
326 F: FnOnce(&swc_common::errors::Handler, swc_common::input::StringInput<'_>) -> Result<Ret, ()>,
327{
328 use swc_common::FileName;
329
330 ::testing::run_test(false, |cm, handler| {
331 let fm = cm.new_source_file(FileName::Real("testing".into()).into(), src.into());
332
333 f(handler, (&*fm).into())
334 })
335}
336
337#[macro_export]
338macro_rules! tok {
339 ('`') => {
340 $crate::token::Token::BackQuote
341 };
342 ('@') => {
344 $crate::token::Token::At
345 };
346 ('#') => {
347 $crate::token::Token::Hash
348 };
349
350 ('&') => {
351 $crate::token::Token::BinOp($crate::token::BinOpToken::BitAnd)
352 };
353 ('|') => {
354 $crate::token::Token::BinOp($crate::token::BinOpToken::BitOr)
355 };
356 ('^') => {
357 $crate::token::Token::BinOp($crate::token::BinOpToken::BitXor)
358 };
359 ('+') => {
360 $crate::token::Token::BinOp($crate::token::BinOpToken::Add)
361 };
362 ('-') => {
363 $crate::token::Token::BinOp($crate::token::BinOpToken::Sub)
364 };
365 ("??") => {
366 $crate::token::Token::BinOp($crate::token::BinOpToken::NullishCoalescing)
367 };
368 ('~') => {
369 $crate::token::Token::Tilde
370 };
371 ('!') => {
372 $crate::token::Token::Bang
373 };
374 ("&&") => {
375 $crate::token::Token::BinOp($crate::token::BinOpToken::LogicalAnd)
376 };
377 ("||") => {
378 $crate::token::Token::BinOp($crate::token::BinOpToken::LogicalOr)
379 };
380 ("&&=") => {
381 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::AndAssign)
382 };
383 ("||=") => {
384 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::OrAssign)
385 };
386 ("??=") => {
387 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::NullishAssign)
388 };
389
390 ("==") => {
391 $crate::token::Token::BinOp($crate::token::BinOpToken::EqEq)
392 };
393 ("===") => {
394 $crate::token::Token::BinOp($crate::token::BinOpToken::EqEqEq)
395 };
396 ("!=") => {
397 $crate::token::Token::BinOp($crate::token::BinOpToken::NotEq)
398 };
399 ("!==") => {
400 $crate::token::Token::BinOp($crate::token::BinOpToken::NotEqEq)
401 };
402
403 (',') => {
404 $crate::token::Token::Comma
405 };
406 ('?') => {
407 $crate::token::Token::QuestionMark
408 };
409 (':') => {
410 $crate::token::Token::Colon
411 };
412 ('.') => {
413 $crate::token::Token::Dot
414 };
415 ("=>") => {
416 $crate::token::Token::Arrow
417 };
418 ("...") => {
419 $crate::token::Token::DotDotDot
420 };
421 ("${") => {
422 $crate::token::Token::DollarLBrace
423 };
424
425 ('+') => {
426 $crate::token::Token::BinOp($crate::token::BinOpToken::Add)
427 };
428 ('-') => {
429 $crate::token::Token::BinOp($crate::token::BinOpToken::Sub)
430 };
431 ('*') => {
432 $crate::token::Token::BinOp($crate::token::BinOpToken::Mul)
433 };
434 ('/') => {
435 $crate::token::Token::BinOp($crate::token::BinOpToken::Div)
436 };
437 ("/=") => {
438 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::DivAssign)
439 };
440 ('%') => {
441 $crate::token::Token::BinOp($crate::token::BinOpToken::Mod)
442 };
443 ('~') => {
444 $crate::token::Token::Tilde
445 };
446 ('<') => {
447 $crate::token::Token::BinOp($crate::token::BinOpToken::Lt)
448 };
449 ("<<") => {
450 $crate::token::Token::BinOp($crate::token::BinOpToken::LShift)
451 };
452 ("<=") => {
453 $crate::token::Token::BinOp($crate::token::BinOpToken::LtEq)
454 };
455 ("<<=") => {
456 $crate::token::Token::AssignOp($crate::token::AssignOp::LShiftAssign)
457 };
458 ('>') => {
459 $crate::token::Token::BinOp($crate::token::BinOpToken::Gt)
460 };
461 (">>") => {
462 $crate::token::Token::BinOp($crate::token::BinOpToken::RShift)
463 };
464 (">>>") => {
465 $crate::token::Token::BinOp($crate::token::BinOpToken::ZeroFillRShift)
466 };
467 (">=") => {
468 $crate::token::Token::BinOp($crate::token::BinOpToken::GtEq)
469 };
470 (">>=") => {
471 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::RShiftAssign)
472 };
473 (">>>=") => {
474 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::ZeroFillRShiftAssign)
475 };
476
477 ("++") => {
478 $crate::token::Token::PlusPlus
479 };
480 ("--") => {
481 $crate::token::Token::MinusMinus
482 };
483
484 ('=') => {
485 $crate::token::Token::AssignOp(swc_ecma_ast::AssignOp::Assign)
486 };
487
488 ('(') => {
489 $crate::token::Token::LParen
490 };
491 (')') => {
492 $crate::token::Token::RParen
493 };
494 ('{') => {
495 $crate::token::Token::LBrace
496 };
497 ('}') => {
498 $crate::token::Token::RBrace
499 };
500 ('[') => {
501 $crate::token::Token::LBracket
502 };
503 (']') => {
504 $crate::token::Token::RBracket
505 };
506
507 ("await") => {
508 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Await))
509 };
510 ("break") => {
511 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Break))
512 };
513 ("case") => {
514 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Case))
515 };
516 ("catch") => {
517 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Catch))
518 };
519 ("class") => {
520 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Class))
521 };
522 ("const") => {
523 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Const))
524 };
525 ("continue") => {
526 $crate::token::Token::Word($crate::token::Word::Keyword(
527 $crate::token::Keyword::Continue,
528 ))
529 };
530 ("debugger") => {
531 $crate::token::Token::Word($crate::token::Word::Keyword(
532 $crate::token::Keyword::Debugger,
533 ))
534 };
535 ("default") => {
536 $crate::token::Token::Word($crate::token::Word::Keyword(
537 $crate::token::Keyword::Default_,
538 ))
539 };
540 ("delete") => {
541 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Delete))
542 };
543 ("do") => {
544 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Do))
545 };
546 ("else") => {
547 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Else))
548 };
549 ("export") => {
550 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Export))
551 };
552 ("extends") => {
553 $crate::token::Token::Word($crate::token::Word::Keyword(
554 $crate::token::Keyword::Extends,
555 ))
556 };
557 ("false") => {
558 $crate::token::Token::Word($crate::token::Word::False)
559 };
560 ("finally") => {
561 $crate::token::Token::Word($crate::token::Word::Keyword(
562 $crate::token::Keyword::Finally,
563 ))
564 };
565 ("for") => {
566 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::For))
567 };
568 ("function") => {
569 $crate::token::Token::Word($crate::token::Word::Keyword(
570 $crate::token::Keyword::Function,
571 ))
572 };
573 ("if") => {
574 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::If))
575 };
576 ("in") => {
577 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::In))
578 };
579 ("instanceof") => {
580 $crate::token::Token::Word($crate::token::Word::Keyword(
581 $crate::token::Keyword::InstanceOf,
582 ))
583 };
584 ("import") => {
585 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Import))
586 };
587 ("let") => {
588 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Let))
589 };
590 ("new") => {
591 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::New))
592 };
593 ("null") => {
594 $crate::token::Token::Word($crate::token::Word::Null)
595 };
596
597 ("return") => {
598 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Return))
599 };
600 ("super") => {
601 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Super))
602 };
603 ("switch") => {
604 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Switch))
605 };
606 ("this") => {
607 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::This))
608 };
609 ("throw") => {
610 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Throw))
611 };
612 ("true") => {
613 $crate::token::Token::Word($crate::token::Word::True)
614 };
615 ("try") => {
616 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Try))
617 };
618 ("typeof") => {
619 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::TypeOf))
620 };
621 ("var") => {
622 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Var))
623 };
624 ("void") => {
625 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Void))
626 };
627 ("while") => {
628 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::While))
629 };
630 ("with") => {
631 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::With))
632 };
633 ("yield") => {
634 $crate::token::Token::Word($crate::token::Word::Keyword($crate::token::Keyword::Yield))
635 };
636
637 (JSXTagStart) => {
641 $crate::token::Token::JSXTagStart
642 };
643
644 (JSXTagEnd) => {
645 $crate::token::Token::JSXTagEnd
646 };
647
648 ($tt:tt) => {
649 $crate::token::Token::Word($crate::token::Word::Ident($crate::token::IdentLike::Known(
650 known_ident!($tt),
651 )))
652 };
653}