2021-06-12 08:17:09 +03:00
//! EcmaScript/TypeScript parser for the rust programming language.
2018-11-18 08:00:07 +03:00
//!
//! # Features
//!
//! ## Heavily tested
//!
//! Passes almost all tests from [tc39/test262][].
//!
//! ## Error reporting
//!
//! ```sh
//! error: 'implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', or 'yield' cannot be used as an identifier in strict mode
//! --> invalid.js:3:10
//! |
//! 3 | function yield() {
//! | ^^^^^
//! ```
//!
2019-11-17 12:36:47 +03:00
//! ## Error recovery
//!
2021-02-20 09:18:09 +03:00
//! The parser can recover from some parsing errors. For example, parser returns
2019-11-17 12:36:47 +03:00
//! `Ok(Module)` for the code below, while emitting error to handler.
//!
//! ```ts
//! const CONST = 9000 % 2;
//! const enum D {
2021-02-20 09:18:09 +03:00
//! // Comma is required, but parser can recover because of the newline.
2019-11-17 12:36:47 +03:00
//! d = 10
//! g = CONST
//! }
//! ```
//!
2019-11-06 07:14:44 +03:00
//! # Example (lexer)
//!
//! See `lexer.rs` in examples directory.
//!
//! # Example (parser)
2018-11-18 08:00:07 +03:00
//!
//! ```
//! #[macro_use]
//! extern crate swc_common;
//! extern crate swc_ecma_parser;
2020-08-12 16:18:47 +03:00
//! use swc_common::sync::Lrc;
2018-11-18 08:00:07 +03:00
//! use swc_common::{
//! errors::{ColorConfig, Handler},
//! FileName, FilePathMapping, SourceMap,
//! };
2020-07-31 12:49:07 +03:00
//! use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
2018-11-18 08:00:07 +03:00
//!
//! fn main() {
2020-08-12 16:18:47 +03:00
//! let cm: Lrc<SourceMap> = Default::default();
//! let handler =
//! Handler::with_tty_emitter(ColorConfig::Auto, true, false,
//! Some(cm.clone()));
//!
//! // Real usage
//! // let fm = cm
//! // .load_file(Path::new("test.js"))
//! // .expect("failed to load test.js");
//! let fm = cm.new_source_file(
//! FileName::Custom("test.js".into()),
//! "function foo() {}".into(),
//! );
//! let lexer = Lexer::new(
//! // We want to parse ecmascript
//! Syntax::Es(Default::default()),
//! // JscTarget defaults to es5
//! Default::default(),
//! StringInput::from(&*fm),
//! None,
//! );
//!
//! let mut parser = Parser::new_from(lexer);
//!
//! for e in parser.take_errors() {
//! e.into_diagnostic(&handler).emit();
//! }
//!
//! let _module = parser
//! .parse_module()
//! .map_err(|mut e| {
//! // Unrecoverable fatal error occurred
//! e.into_diagnostic(&handler).emit()
//! })
//! .expect("failed to parser module");
2018-11-18 08:00:07 +03:00
//! }
//! ```
//!
2021-06-12 08:17:09 +03:00
//! ## Known issues
//!
//! ### Null character after `\`
//!
//! Becuase [String] of rust should only contain valid utf-8 characters while
//! javascript allows non-utf8 chraceters, the parser stores invalid utf8
//! chracters in escpaed form.
//!
//! As a result, swc needs a way to distinguish invalid-utf8 code points and
//! input specified by the user. The parser stores a null chracter right after
//! `\\` for non-utf8 code points. Note that other parts of swc is aware of this
//! fact.
//!
//! Note that this can be changed at anytime with a breaking change.
2018-11-18 08:00:07 +03:00
//!
//! [tc39/test262]:https://github.com/tc39/test262
2021-08-15 13:01:08 +03:00
#![ cfg_attr(test, feature(bench_black_box)) ]
2018-12-21 10:54:36 +03:00
#![ cfg_attr(test, feature(test)) ]
2020-07-31 12:49:07 +03:00
#![ deny(unused) ]
2018-01-12 10:53:06 +03:00
2018-09-16 14:25:41 +03:00
pub use self ::{
2020-07-31 12:49:07 +03:00
lexer ::input ::{ Input , StringInput } ,
2018-09-16 14:25:41 +03:00
parser ::* ,
} ;
2018-12-30 07:06:13 +03:00
use serde ::{ Deserialize , Serialize } ;
2021-01-20 13:43:56 +03:00
pub use swc_ecma_ast ::EsVersion as JscTarget ;
2018-01-12 10:53:06 +03:00
#[ macro_use ]
mod macros ;
2020-07-25 14:26:04 +03:00
pub mod error ;
2019-11-06 07:14:44 +03:00
pub mod lexer ;
2018-01-21 11:47:37 +03:00
mod parser ;
2019-12-15 02:08:13 +03:00
pub mod token ;
2018-01-21 11:47:37 +03:00
2019-11-26 04:08:48 +03:00
#[ derive(Debug, Clone, Copy, Deserialize, Serialize) ]
2020-03-28 05:59:45 +03:00
#[ serde(deny_unknown_fields, tag = " syntax " ) ]
2018-12-30 05:57:27 +03:00
pub enum Syntax {
2019-01-07 13:43:47 +03:00
/// Standard
2019-01-08 10:34:35 +03:00
#[ serde(rename = " ecmascript " ) ]
Es ( EsConfig ) ,
2021-07-25 12:37:59 +03:00
/// This variant requires the cargo feature `typescript` to be enabled.
#[ cfg(feature = " typescript " ) ]
2019-01-08 10:34:35 +03:00
#[ serde(rename = " typescript " ) ]
Typescript ( TsConfig ) ,
2018-12-30 05:57:27 +03:00
}
2018-12-30 07:06:13 +03:00
2019-01-07 13:43:47 +03:00
impl Default for Syntax {
fn default ( ) -> Self {
2019-01-08 10:34:35 +03:00
Syntax ::Es ( Default ::default ( ) )
2018-12-30 07:06:13 +03:00
}
}
2018-12-30 05:57:27 +03:00
impl Syntax {
2020-09-23 08:27:27 +03:00
pub fn import_assertions ( self ) -> bool {
match self {
Syntax ::Es ( EsConfig {
import_assertions , ..
} )
| Syntax ::Typescript ( TsConfig {
import_assertions , ..
} ) = > import_assertions ,
}
}
2021-08-29 18:03:14 +03:00
pub fn static_blocks ( self ) -> bool {
match self {
Syntax ::Es ( EsConfig {
static_blocks : true ,
..
} )
| Syntax ::Typescript ( .. ) = > true ,
_ = > false ,
}
}
2020-02-09 21:22:51 +03:00
/// Should we parse jsx?
2018-12-30 05:57:27 +03:00
pub fn jsx ( self ) -> bool {
match self {
2019-01-08 10:34:35 +03:00
Syntax ::Es ( EsConfig { jsx : true , .. } )
| Syntax ::Typescript ( TsConfig { tsx : true , .. } ) = > true ,
2018-12-30 05:57:27 +03:00
_ = > false ,
}
}
2019-01-07 13:43:47 +03:00
2021-08-09 19:13:41 +03:00
pub const fn optional_chaining ( self ) -> bool {
2020-06-20 09:09:57 +03:00
true
2020-01-31 18:59:47 +03:00
}
2021-08-09 19:13:41 +03:00
pub const fn dynamic_import ( self ) -> bool {
2021-08-08 16:53:41 +03:00
true
2019-02-10 06:07:40 +03:00
}
2019-01-07 13:43:47 +03:00
pub fn fn_bind ( self ) -> bool {
match self {
2019-01-08 10:34:35 +03:00
Syntax ::Es ( EsConfig { fn_bind : true , .. } ) = > true ,
2019-01-07 13:43:47 +03:00
_ = > false ,
}
}
2021-08-09 19:13:41 +03:00
pub const fn num_sep ( self ) -> bool {
2020-06-20 09:09:57 +03:00
true
2019-01-07 13:43:47 +03:00
}
pub fn decorators ( self ) -> bool {
match self {
2019-01-08 10:34:35 +03:00
Syntax ::Es ( EsConfig {
2019-01-07 13:43:47 +03:00
decorators : true , ..
} )
2019-01-08 10:34:35 +03:00
| Syntax ::Typescript ( TsConfig {
decorators : true , ..
} ) = > true ,
2019-01-07 13:43:47 +03:00
_ = > false ,
}
}
2021-08-09 19:13:41 +03:00
pub const fn class_private_methods ( self ) -> bool {
2020-06-20 09:09:57 +03:00
true
2019-01-07 13:43:47 +03:00
}
2021-08-09 19:13:41 +03:00
pub const fn class_private_props ( self ) -> bool {
2021-08-08 16:53:41 +03:00
true
2019-01-07 13:43:47 +03:00
}
2021-08-09 19:13:41 +03:00
pub const fn class_props ( self ) -> bool {
2020-06-20 09:09:57 +03:00
true
2019-01-07 13:43:47 +03:00
}
pub fn decorators_before_export ( self ) -> bool {
match self {
2019-01-08 10:34:35 +03:00
Syntax ::Es ( EsConfig {
2019-01-07 13:43:47 +03:00
decorators_before_export : true ,
..
2019-03-09 03:07:15 +03:00
} )
| Syntax ::Typescript ( .. ) = > true ,
2019-01-07 13:43:47 +03:00
_ = > false ,
}
}
/// Should we pare typescript?
2021-07-25 12:37:59 +03:00
#[ cfg(not(feature = " typescript " )) ]
pub const fn typescript ( self ) -> bool {
false
}
/// Should we pare typescript?
#[ cfg(feature = " typescript " ) ]
pub const fn typescript ( self ) -> bool {
2019-01-07 13:43:47 +03:00
match self {
2019-01-08 10:34:35 +03:00
Syntax ::Typescript ( .. ) = > true ,
2019-01-07 13:43:47 +03:00
_ = > false ,
}
}
2019-02-12 09:30:11 +03:00
pub fn export_default_from ( self ) -> bool {
match self {
Syntax ::Es ( EsConfig {
export_default_from : true ,
..
} ) = > true ,
_ = > false ,
}
}
2019-02-18 08:01:56 +03:00
2020-10-06 14:48:29 +03:00
/// `true`
2021-08-09 19:13:41 +03:00
pub const fn export_namespace_from ( self ) -> bool {
2020-10-06 14:48:29 +03:00
true
2019-02-18 08:01:56 +03:00
}
2019-12-24 11:01:32 +03:00
2020-10-06 14:48:29 +03:00
/// `true`
2021-08-09 19:13:41 +03:00
pub const fn nullish_coalescing ( self ) -> bool {
2020-06-20 09:09:57 +03:00
true
2019-12-24 11:01:32 +03:00
}
2020-01-01 00:57:34 +03:00
2021-08-09 19:13:41 +03:00
pub const fn import_meta ( self ) -> bool {
2021-08-08 16:53:41 +03:00
true
2020-01-01 00:57:34 +03:00
}
2020-02-05 04:05:23 +03:00
2021-08-09 19:13:41 +03:00
pub const fn top_level_await ( self ) -> bool {
2021-08-08 16:53:41 +03:00
true
2020-02-05 04:05:23 +03:00
}
2020-03-09 15:18:41 +03:00
pub fn dts ( self ) -> bool {
match self {
Syntax ::Typescript ( t ) = > t . dts ,
_ = > false ,
}
}
2020-06-02 13:22:41 +03:00
2021-09-27 11:03:48 +03:00
pub fn private_in_object ( self ) -> bool {
match self {
Syntax ::Es ( EsConfig {
private_in_object , ..
} ) = > private_in_object ,
_ = > false ,
}
}
2020-06-02 13:22:41 +03:00
pub ( crate ) fn early_errors ( self ) -> bool {
match self {
Syntax ::Typescript ( t ) = > ! t . no_early_errors ,
Syntax ::Es ( .. ) = > true ,
}
}
2018-12-30 05:57:27 +03:00
}
2019-11-26 04:08:48 +03:00
#[ derive(Debug, Clone, Copy, Default, Serialize, Deserialize) ]
2019-02-10 06:07:40 +03:00
#[ serde(deny_unknown_fields, rename_all = " camelCase " ) ]
2019-01-08 10:34:35 +03:00
pub struct TsConfig {
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-08 10:34:35 +03:00
pub tsx : bool ,
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-08 10:34:35 +03:00
pub decorators : bool ,
2019-02-10 06:07:40 +03:00
#[ serde(default) ]
pub dynamic_import : bool ,
2020-03-09 15:18:41 +03:00
/// `.d.ts`
#[ serde(skip, default) ]
pub dts : bool ,
2020-06-02 13:22:41 +03:00
#[ serde(skip, default) ]
pub no_early_errors : bool ,
2020-09-23 08:27:27 +03:00
/// Stage 3.
#[ serde(default) ]
pub import_assertions : bool ,
2019-01-08 10:34:35 +03:00
}
2019-11-26 04:08:48 +03:00
#[ derive(Debug, Clone, Copy, Default, Serialize, Deserialize) ]
2019-02-10 06:07:40 +03:00
#[ serde(deny_unknown_fields, rename_all = " camelCase " ) ]
2019-01-08 10:34:35 +03:00
pub struct EsConfig {
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-08 10:34:35 +03:00
pub jsx : bool ,
2018-01-21 11:47:37 +03:00
/// Support numeric separator.
2019-12-24 11:01:32 +03:00
/// Stage 3.
2019-01-08 10:34:35 +03:00
#[ serde(rename = " numericSeparator " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2018-01-21 11:47:37 +03:00
pub num_sep : bool ,
2019-01-08 10:34:35 +03:00
#[ serde(rename = " classPrivateProperty " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-07 13:43:47 +03:00
pub class_private_props : bool ,
2019-01-08 10:34:35 +03:00
#[ serde(rename = " privateMethod " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-07 13:43:47 +03:00
pub class_private_methods : bool ,
2019-01-08 10:34:35 +03:00
#[ serde(rename = " classProperty " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-07 13:43:47 +03:00
pub class_props : bool ,
2018-01-21 11:47:37 +03:00
/// Support function bind expression.
2019-01-08 10:34:35 +03:00
#[ serde(rename = " functionBind " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2018-01-21 11:47:37 +03:00
pub fn_bind : bool ,
2019-01-07 13:43:47 +03:00
/// Enable decorators.
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-07 13:43:47 +03:00
pub decorators : bool ,
/// babel: `decorators.decoratorsBeforeExport`
///
/// Effective only if `decorator` is true.
2019-01-08 10:34:35 +03:00
#[ serde(rename = " decoratorsBeforeExport " ) ]
2019-01-08 12:27:38 +03:00
#[ serde(default) ]
2019-01-07 13:43:47 +03:00
pub decorators_before_export : bool ,
2019-02-10 06:07:40 +03:00
2019-02-12 09:30:11 +03:00
#[ serde(default) ]
pub export_default_from : bool ,
2019-02-18 08:01:56 +03:00
#[ serde(default) ]
pub export_namespace_from : bool ,
2019-02-10 06:07:40 +03:00
#[ serde(default) ]
pub dynamic_import : bool ,
2019-12-24 11:01:32 +03:00
/// Stage 3.
#[ serde(default) ]
pub nullish_coalescing : bool ,
2020-01-01 00:57:34 +03:00
2020-01-31 18:59:47 +03:00
#[ serde(default) ]
pub optional_chaining : bool ,
2020-01-01 00:57:34 +03:00
/// Stage 3.
#[ serde(default) ]
pub import_meta : bool ,
2020-02-05 04:05:23 +03:00
/// Stage 3.
#[ serde(default) ]
pub top_level_await : bool ,
2020-09-23 08:27:27 +03:00
/// Stage 3.
#[ serde(default) ]
pub import_assertions : bool ,
2021-08-29 18:03:14 +03:00
2021-09-27 11:03:48 +03:00
#[ serde(default, rename = " staticBlocks " ) ]
2021-08-29 18:03:14 +03:00
pub static_blocks : bool ,
2021-09-27 11:03:48 +03:00
#[ serde(default, rename = " privateInObject " ) ]
pub private_in_object : bool ,
2018-01-26 15:53:30 +03:00
}
2018-01-21 11:47:37 +03:00
2019-11-06 07:14:44 +03:00
/// Syntactic context.
2019-02-12 09:30:11 +03:00
#[ derive(Debug, Clone, Copy, Default) ]
2019-11-06 07:14:44 +03:00
pub struct Context {
2018-01-21 11:47:37 +03:00
/// Is in module code?
2018-01-26 15:53:30 +03:00
module : bool ,
2021-08-09 19:13:41 +03:00
can_be_module : bool ,
2018-01-26 15:53:30 +03:00
strict : bool ,
include_in_expr : bool ,
/// If true, await expression is parsed, and "await" is treated as a
/// keyword.
in_async : bool ,
/// If true, yield expression is parsed, and "yield" is treated as a
/// keyword.
in_generator : bool ,
2019-11-17 12:36:47 +03:00
is_continue_allowed : bool ,
is_break_allowed : bool ,
2019-01-07 13:43:47 +03:00
in_type : bool ,
/// Typescript extension.
in_declare : bool ,
2019-02-12 16:05:46 +03:00
/// If true, `:` should not be treated as a type annotation.
in_cond_expr : bool ,
2021-08-29 23:40:52 +03:00
is_direct_child_of_cond : bool ,
2019-02-12 16:05:46 +03:00
2018-01-26 15:53:30 +03:00
in_function : bool ,
in_parameters : bool ,
2018-12-30 05:57:27 +03:00
2021-04-07 18:38:24 +03:00
has_super_class : bool ,
2019-01-07 13:43:47 +03:00
in_property_name : bool ,
2018-12-30 05:57:27 +03:00
in_forced_jsx_context : bool ,
2020-06-03 06:19:05 +03:00
/// If true, `:` should not be treated as a type annotation.
2021-09-09 14:45:20 +03:00
dont_parse_colon_as_type_ann : bool ,
2018-01-21 11:47:37 +03:00
}
2018-01-22 04:45:08 +03:00
#[ cfg(test) ]
2019-11-23 17:03:19 +03:00
fn with_test_sess < F , Ret > ( src : & str , f : F ) -> Result < Ret , ::testing ::StdErr >
2018-01-22 04:45:08 +03:00
where
2020-07-31 12:49:07 +03:00
F : FnOnce ( & swc_common ::errors ::Handler , StringInput < '_ > ) -> Result < Ret , ( ) > ,
2018-01-22 04:45:08 +03:00
{
2018-11-17 06:30:49 +03:00
use swc_common ::FileName ;
2018-01-23 15:38:48 +03:00
2019-01-20 05:08:26 +03:00
::testing ::run_test ( false , | cm , handler | {
2018-11-17 06:30:49 +03:00
let fm = cm . new_source_file ( FileName ::Real ( " testing " . into ( ) ) , src . into ( ) ) ;
2018-01-23 15:38:48 +03:00
2020-07-25 14:26:04 +03:00
f ( handler , ( & * fm ) . into ( ) )
2018-11-17 06:30:49 +03:00
} )
2018-01-21 11:47:37 +03:00
}