Typescript & parser for decorators

swc_atoms:
 - add some atoms

swc_ecma_ast:
 - ast nodes for typescript
 - `ClassMethod` -> `Method`, `ClassMethodKind` -> `MethodKind`
 - private class method / class property
 - use separate type for tagged template literals
 - add `declare` field to `Decl`s
 - make function body optional

swc_ecma_parser:
 - rename Type to TokenContext
 - support decorators
 Note: error reporting for invalid decorator is not implemented yet
 - merge `Config` into `Syntax`
 - Use DiagnosticBuilder for error type
This is to make backtracking cheaper.

swc_ecma_transforms:
 - add `strip` pass
This commit is contained in:
강동윤 2019-01-07 19:43:47 +09:00 committed by GitHub
parent 2e22397f42
commit ea610c6ded
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
516 changed files with 39207 additions and 2488 deletions

View File

@ -63,7 +63,7 @@ notifications:
env:
global:
- CASHER_TIME_OUT=600
- RUST_MIN_STACK=4194304
- RUST_MIN_STACK=16777216
- CARGO_INCREMENTAL=0
- RUSTFLAGS="--cfg procmacro2_semver_exempt"
- secure: Z4RSNlpg/12Qx2fIjS+7TToYxPJQgK70X7u9A5lJiCIa0JfzWCxr1ZEKXfAVLG9o4nQok+nWOZa+vxR1IgyUVnf6oSanjjWl1pSRbvccxMS799NvHmGzIAiqSKAlxiSJuxf7MQbs1XBuI3XahsWLfXGPo7vPT6sKe4AAf9gT6igJr61D5hpHkVIXK7P6rnrWQALQYplyaox0NlU9UlqSXXBjdJfp3138rl7FIeYRsMMow44unBNPvs+mhVP8PWpeFWeop0jxbNbTHwnJUbCm4ZWrvqnJ/m70IMlBMN1AskLmz4KeXOhPx+XR9VtdWBX4q8lJ7s9J0hMBxrEnxgiYVBPMlLoEX+wW3zwZ5F+DQs7uLpRHYRUpxpi/7ZuQjp+uT3mN9PMMSvbHwHLH2r/CC9olKYWySXIsGsGVyyMnZeUwvgzwxiYLoeCWe4zZY99zc7jvGKbSmk0RtPu6hApPwL5A6novXbXL2QsXzqqeWpgMLmZyb7KYhM5IGIAB1oPQIqI++Re9Z+/ea/DRSUJOsA96yRQ+vVbiuClrVgDhaAaJOGYCtR1XZ5N2zRb9+Spu/ECtfisLOb9Xs1584DyRbqG69nRdjuscjYOTFZUlOoOeFvuADY65Jt0kF6u7g8NIDkJ1ROb3heKQtY/bAQUrBNUJydOQnn5tBwn8Z618+Ac=

View File

@ -3,7 +3,10 @@ extern crate string_cache_codegen;
use std::{env, path::Path};
fn main() {
let strs = include_str!("words.txt").lines().map(|l| l.trim()).collect::<Vec<_>>();
let strs = include_str!("words.txt")
.lines()
.map(|l| l.trim())
.collect::<Vec<_>>();
gen("js_word", "JsWord", &strs);
}

View File

@ -7,10 +7,13 @@ RegExp
_extends
_toConsumableArray
abstract
any
apply
as
async
await
bigint
boolean
break
call
case
@ -23,6 +26,7 @@ continue
createClass
createReactClass
debugger
declare
default
delete
do
@ -37,17 +41,26 @@ for
from
function
get
global
if
implements
import
in
infer
instanceof
interface
is
key
keyof
length
let
module
namespace
never
new
null
number
object
of
package
private
@ -55,18 +68,24 @@ process
protected
public
readonly
require
return
set
static
string
super
switch
symbol
target
this
throw
true
try
type
typeof
undefined
unique
unknown
var
void
while

View File

@ -1,30 +1,114 @@
use super::{Expr, Function, PropName};
use crate::{
expr::Expr,
function::{Function, PatOrTsParamProp},
ident::PrivateName,
prop::PropName,
stmt::BlockStmt,
typescript::{
Accessibility, TsExprWithTypeArgs, TsIndexSignature, TsTypeAnn, TsTypeParamDecl,
TsTypeParamInstantiation,
},
};
use swc_common::{ast_node, Fold, Span};
#[ast_node]
pub struct Class {
pub span: Span,
pub body: Vec<ClassMethod>,
pub decorators: Vec<Decorator>,
pub body: Vec<ClassMember>,
pub super_class: Option<Box<Expr>>,
pub is_abstract: bool,
pub type_params: Option<TsTypeParamDecl>,
pub super_type_params: Option<TsTypeParamInstantiation>,
/// Typescript extension.
pub implements: Vec<TsExprWithTypeArgs>,
}
#[ast_node]
pub struct ClassMethod {
pub enum ClassMember {
Constructor(Constructor),
/// `es2015`
Method(Method),
PrivateMethod(PrivateMethod),
/// stage 0 / Typescript
ClassProp(ClassProp),
PrivateProp(PrivateProp),
TsIndexSignature(TsIndexSignature),
}
pub type ClassProp = ClassProperty<Box<Expr>>;
pub type PrivateProp = ClassProperty<PrivateName>;
#[ast_node]
pub struct ClassProperty<K> {
pub span: Span,
#[fold(bound)]
pub key: K,
pub value: Option<Box<Expr>>,
pub type_ann: Option<TsTypeAnn>,
pub is_static: bool,
pub decorators: Vec<Decorator>,
/// Typescript extension.
pub accessibility: Option<Accessibility>,
/// Typescript extension.
pub is_abstract: bool,
pub is_optional: bool,
pub readonly: bool,
pub definite: bool,
}
pub type Method = ClassMethod<PropName>;
pub type PrivateMethod = ClassMethod<PrivateName>;
#[ast_node]
pub struct Constructor {
pub span: Span,
pub key: PropName,
pub params: Vec<PatOrTsParamProp>,
pub body: Option<BlockStmt>,
pub accessibility: Option<Accessibility>,
pub is_optional: bool,
}
#[ast_node]
pub struct ClassMethod<K> {
pub span: Span,
#[fold(bound)]
pub key: K,
pub function: Function,
#[fold(ignore)]
pub kind: ClassMethodKind,
pub kind: MethodKind,
pub is_static: bool,
/// Typescript extension.
pub accessibility: Option<Accessibility>,
/// Typescript extension.
pub is_abstract: bool,
pub is_optional: bool,
}
#[ast_node]
pub struct Decorator {
pub span: Span,
pub expr: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Fold)]
pub enum ClassMethodKind {
Constructor,
pub enum MethodKind {
Method,
Getter,
Setter,

View File

@ -1,4 +1,11 @@
use super::{Class, Expr, Function, Ident, Pat};
use crate::{
class::Class,
expr::Expr,
function::Function,
ident::Ident,
pat::Pat,
typescript::{TsEnumDecl, TsInterfaceDecl, TsModuleDecl, TsTypeAliasDecl},
};
use swc_common::{ast_node, Fold, Span};
#[ast_node]
@ -6,11 +13,16 @@ pub enum Decl {
Class(ClassDecl),
Fn(FnDecl),
Var(VarDecl),
TsInterface(TsInterfaceDecl),
TsTypeAlias(TsTypeAliasDecl),
TsEnum(TsEnumDecl),
TsModule(TsModuleDecl),
}
#[ast_node]
pub struct FnDecl {
pub ident: Ident,
pub declare: bool,
#[span]
pub function: Function,
}
@ -18,6 +30,7 @@ pub struct FnDecl {
#[ast_node]
pub struct ClassDecl {
pub ident: Ident,
pub declare: bool,
#[span]
pub class: Class,
}
@ -26,7 +39,7 @@ pub struct ClassDecl {
pub struct VarDecl {
pub span: Span,
pub kind: VarDeclKind,
pub declare: bool,
pub decls: Vec<VarDeclarator>,
}
@ -47,4 +60,7 @@ pub struct VarDeclarator {
pub name: Pat,
/// Initialization expresion.
pub init: Option<(Box<Expr>)>,
/// Typescript onpy
pub definite: bool,
}

View File

@ -1,6 +1,17 @@
use super::{
AssignOp, BinaryOp, BlockStmt, Class, Function, Ident, JSXElement, JSXEmptyExpr, JSXFragment,
JSXMemberExpr, JSXNamespacedName, Lit, Pat, Prop, Str, UnaryOp, UpdateOp,
use crate::{
class::Class,
function::Function,
ident::Ident,
jsx::{JSXElement, JSXEmptyExpr, JSXFragment, JSXMemberExpr, JSXNamespacedName},
lit::{Lit, Str},
operators::{AssignOp, BinaryOp, UnaryOp, UpdateOp},
pat::Pat,
prop::Prop,
stmt::BlockStmt,
typescript::{
TsAsExpr, TsNonNullExpr, TsTypeAnn, TsTypeAssertion, TsTypeCastExpr, TsTypeParamDecl,
TsTypeParamInstantiation,
},
};
use swc_common::{ast_node, Fold, Span, Spanned};
@ -50,7 +61,9 @@ pub enum Expr {
Lit(Lit),
Tpl(TplLit),
Tpl(Tpl),
TaggedTpl(TaggedTpl),
Arrow(ArrowExpr),
@ -69,6 +82,11 @@ pub enum Expr {
JSXEmpty(JSXEmptyExpr),
JSXElement(JSXElement),
JSXFragment(JSXFragment),
TsTypeAssertion(TsTypeAssertion),
TsNonNull(TsNonNullExpr),
TsTypeCast(TsTypeCastExpr),
TsAs(TsAsExpr),
}
#[ast_node]
@ -178,6 +196,8 @@ pub struct CallExpr {
pub span: Span,
pub callee: ExprOrSuper,
pub args: Vec<ExprOrSpread>,
pub type_args: Option<TsTypeParamInstantiation>,
// pub type_params: Option<TsTypeParamInstantiation>,
}
#[ast_node]
@ -185,6 +205,8 @@ pub struct NewExpr {
pub span: Span,
pub callee: Box<Expr>,
pub args: Option<(Vec<ExprOrSpread>)>,
pub type_args: Option<TsTypeParamInstantiation>,
// pub type_params: Option<TsTypeParamInstantiation>,
}
#[ast_node]
@ -201,6 +223,8 @@ pub struct ArrowExpr {
pub body: BlockStmtOrExpr,
pub is_async: bool,
pub is_generator: bool,
pub type_params: Option<TsTypeParamDecl>,
pub return_type: Option<TsTypeAnn>,
}
#[ast_node]
@ -223,13 +247,21 @@ pub struct AwaitExpr {
}
#[ast_node]
pub struct TplLit {
pub struct Tpl {
pub span: Span,
pub tag: Option<(Box<Expr>)>,
pub exprs: Vec<(Box<Expr>)>,
pub quasis: Vec<TplElement>,
}
#[ast_node]
pub struct TaggedTpl {
pub span: Span,
pub tag: Box<Expr>,
pub exprs: Vec<(Box<Expr>)>,
pub quasis: Vec<TplElement>,
pub type_params: Option<TsTypeParamInstantiation>,
}
#[ast_node]
pub struct TplElement {
pub span: Span,

View File

@ -1,17 +1,32 @@
use super::{BlockStmt, Pat};
use crate::{
class::Decorator,
pat::Pat,
stmt::BlockStmt,
typescript::{TsParamProp, TsTypeAnn, TsTypeParamDecl},
};
use swc_common::{ast_node, Span};
/// Common parts of function and method.
#[ast_node]
pub struct Function {
pub params: Vec<Pat>,
pub decorators: Vec<Decorator>,
pub span: Span,
pub body: BlockStmt,
pub body: Option<BlockStmt>,
/// if it's a generator.
pub is_generator: bool,
/// if it's an async function.
pub is_async: bool,
pub type_params: Option<TsTypeParamDecl>,
pub return_type: Option<TsTypeAnn>,
}
#[ast_node]
pub enum PatOrTsParamProp {
Pat(Pat),
TsParamProp(TsParamProp),
}

View File

@ -1,5 +1,59 @@
use crate::Ident;
use crate::typescript::TsTypeAnn;
use std::fmt::{self, Debug, Display, Formatter};
use swc_atoms::JsWord;
use swc_common::{ast_node, Fold, Span, Spanned};
/// Ident with span.
#[derive(Spanned, Fold, Clone, PartialEq)]
pub struct Ident {
pub span: Span,
#[fold(ignore)]
pub sym: JsWord,
pub type_ann: Option<TsTypeAnn>,
/// TypeScript only. Used in case of an optional parameter.
pub optional: bool,
}
impl Debug for Ident {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Ident")
.field("sym", &DebugUsingDisplay(&self.sym))
.field("span", &self.span)
.field("type_ann", &self.type_ann)
.field("optional", &self.optional)
.finish()
}
}
#[ast_node]
pub struct PrivateName {
pub span: Span,
pub id: Ident,
}
impl AsRef<str> for Ident {
fn as_ref(&self) -> &str {
&self.sym
}
}
struct DebugUsingDisplay<T: Display>(T);
impl<T: Display> Debug for DebugUsingDisplay<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Ident {
pub const fn new(sym: JsWord, span: Span) -> Self {
Ident {
span,
sym,
type_ann: None,
optional: false,
}
}
}
pub trait IdentExt: AsRef<str> {
fn is_reserved_for_es3(&self) -> bool {

View File

@ -1,9 +1,15 @@
use super::{Expr, Ident, Lit, SpreadElement};
use crate::{
expr::{Expr, SpreadElement},
ident::Ident,
lit::Lit,
typescript::TsTypeParamInstantiation,
};
use swc_atoms::JsWord;
use swc_common::{ast_node, Span};
/// Used for `obj` property of `JSXMemberExpr`.
#[ast_node]
#[allow(variant_size_differences)]
pub enum JSXObject {
JSXMemberExpr(Box<JSXMemberExpr>),
Ident(Ident),
@ -65,6 +71,7 @@ pub struct JSXOpeningElement {
pub span: Span,
pub attrs: Vec<JSXAttrOrSpread>,
pub self_closing: bool,
pub type_args: Option<TsTypeParamInstantiation>,
}
#[ast_node]

View File

@ -15,22 +15,25 @@ extern crate swc_atoms;
extern crate swc_common;
pub use self::{
class::{Class, ClassMethod, ClassMethodKind},
class::{
Class, ClassMember, ClassMethod, ClassProp, ClassProperty, Constructor, Decorator, Method,
MethodKind, PrivateMethod, PrivateProp,
},
decl::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator},
expr::{
ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr, CallExpr, ClassExpr,
CondExpr, Expr, ExprOrSpread, ExprOrSuper, FnExpr, MemberExpr, MetaPropExpr, NewExpr,
ObjectLit, ParenExpr, PatOrExpr, PropOrSpread, SeqExpr, SpreadElement, ThisExpr,
TplElement, TplLit, UnaryExpr, UpdateExpr, YieldExpr,
ObjectLit, ParenExpr, PatOrExpr, PropOrSpread, SeqExpr, SpreadElement, TaggedTpl, ThisExpr,
Tpl, TplElement, UnaryExpr, UpdateExpr, YieldExpr,
},
function::Function,
function::{Function, PatOrTsParamProp},
ident::{Ident, IdentExt, PrivateName},
jsx::{
JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXClosingElement, JSXClosingFragment,
JSXElement, JSXElementChild, JSXElementName, JSXEmptyExpr, JSXExpr, JSXExprContainer,
JSXFragment, JSXMemberExpr, JSXNamespacedName, JSXObject, JSXOpeningElement,
JSXOpeningFragment, JSXSpreadChild, JSXText,
},
keywords::IdentExt,
lit::{Bool, Lit, Null, Number, Regex, RegexFlags, Str},
module::{Module, ModuleItem},
module_decl::{
@ -47,17 +50,29 @@ pub use self::{
ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, Stmt, SwitchCase,
SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, VarDeclOrPat, WhileStmt, WithStmt,
},
typescript::{
Accessibility, TruePlusMinus, TsArrayType, TsAsExpr, TsCallSignatureDecl,
TsConditionalType, TsConstructSignatureDecl, TsConstructorType, TsEntityName, TsEnumDecl,
TsEnumMember, TsEnumMemberId, TsExportAssignment, TsExprWithTypeArgs, TsExternalModuleRef,
TsFnOrConstructorType, TsFnParam, TsFnType, TsImportEqualsDecl, TsIndexSignature,
TsIndexedAccessType, TsInferType, TsInterfaceBody, TsInterfaceDecl, TsIntersectionType,
TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType, TsMappedType, TsMethodSignature,
TsModuleBlock, TsModuleDecl, TsModuleName, TsModuleRef, TsNamespaceBody, TsNamespaceDecl,
TsNamespaceExportDecl, TsNonNullExpr, TsOptionalType, TsParamProp, TsParamPropParam,
TsParenthesizedType, TsPropertySignature, TsQualifiedName, TsRestType, TsSignatureDecl,
TsThisType, TsThisTypeOrIdent, TsTupleType, TsType, TsTypeAliasDecl, TsTypeAnn,
TsTypeAssertion, TsTypeCastExpr, TsTypeElement, TsTypeLit, TsTypeOperator,
TsTypeOperatorOp, TsTypeParam, TsTypeParamDecl, TsTypeParamInstantiation, TsTypePredicate,
TsTypeQuery, TsTypeRef, TsUnionOrIntersectionType, TsUnionType,
},
};
use std::fmt::{self, Debug, Display, Formatter};
use swc_atoms::JsWord;
use swc_common::{Fold, Span, Spanned};
mod class;
mod decl;
mod expr;
mod function;
mod ident;
mod jsx;
mod keywords;
mod lit;
mod macros;
mod module;
@ -66,39 +81,4 @@ mod operators;
mod pat;
mod prop;
mod stmt;
/// Ident with span.
#[derive(Spanned, Fold, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ident {
pub span: Span,
#[fold(ignore)]
pub sym: JsWord,
}
impl Debug for Ident {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_tuple("Ident")
.field(&DebugUsingDisplay(&self.sym))
.field(&self.span)
.finish()
}
}
impl AsRef<str> for Ident {
fn as_ref(&self) -> &str {
&self.sym
}
}
struct DebugUsingDisplay<T: Display>(T);
impl<T: Display> Debug for DebugUsingDisplay<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Ident {
pub fn new(sym: JsWord, span: Span) -> Self {
Ident { span, sym }
}
}
mod typescript;

View File

@ -1,4 +1,4 @@
use super::JSXText;
use crate::jsx::JSXText;
use std::fmt::{self, Display, Formatter};
use swc_atoms::JsWord;
use swc_common::{ast_node, Span};

View File

@ -1,4 +1,4 @@
use super::{ModuleDecl, Stmt};
use crate::{module_decl::ModuleDecl, stmt::Stmt};
use swc_common::{ast_node, Span};
#[ast_node]

View File

@ -1,4 +1,10 @@
use super::{ClassExpr, Decl, Expr, FnExpr, Ident, Str, VarDecl};
use crate::{
decl::{Decl, VarDecl},
expr::{ClassExpr, Expr, FnExpr},
ident::Ident,
lit::Str,
typescript::{TsExportAssignment, TsImportEqualsDecl, TsInterfaceDecl, TsNamespaceExportDecl},
};
use swc_common::{ast_node, Span};
#[ast_node]
@ -11,6 +17,9 @@ pub enum ModuleDecl {
ExportDefaultExpr(Box<Expr>),
ExportAll(ExportAll),
TsImportEqualsDecl(TsImportEqualsDecl),
TsExportAssignment(TsExportAssignment),
TsNamespaceExportDecl(TsNamespaceExportDecl),
}
#[ast_node]
@ -45,6 +54,8 @@ pub enum ExportDefaultDecl {
Fn(FnExpr),
Var(VarDecl),
TsInterfaceDecl(TsInterfaceDecl),
}
#[ast_node]

View File

@ -1,4 +1,4 @@
use super::{Expr, Ident, PropName};
use crate::{expr::Expr, ident::Ident, prop::PropName, typescript::TsTypeAnn};
use swc_common::{ast_node, Span};
#[ast_node]
@ -21,12 +21,14 @@ pub enum Pat {
pub struct ArrayPat {
pub span: Span,
pub elems: Vec<(Option<Pat>)>,
pub type_ann: Option<TsTypeAnn>,
}
#[ast_node]
pub struct ObjectPat {
pub span: Span,
pub props: Vec<ObjectPatProp>,
pub type_ann: Option<TsTypeAnn>,
}
#[ast_node]
@ -34,6 +36,7 @@ pub struct AssignPat {
pub span: Span,
pub left: Box<Pat>,
pub right: Box<Expr>,
pub type_ann: Option<TsTypeAnn>,
}
/// EsTree `RestElement`
@ -43,6 +46,7 @@ pub struct RestPat {
pub dot3_token: Span,
#[span(hi)]
pub arg: Box<Pat>,
pub type_ann: Option<TsTypeAnn>,
}
#[ast_node]

View File

@ -1,4 +1,11 @@
use super::{BlockStmt, Expr, Function, Ident, Number, Pat, Str};
use crate::{
expr::Expr,
function::Function,
ident::Ident,
lit::{Number, Str},
pat::Pat,
stmt::BlockStmt,
};
use swc_common::{ast_node, Span};
#[ast_node]
@ -35,14 +42,14 @@ pub struct AssignProp {
pub struct GetterProp {
pub span: Span,
pub key: PropName,
pub body: BlockStmt,
pub body: Option<BlockStmt>,
}
#[ast_node]
pub struct SetterProp {
pub span: Span,
pub key: PropName,
pub param: Pat,
pub body: BlockStmt,
pub body: Option<BlockStmt>,
}
#[ast_node]
pub struct MethodProp {

View File

@ -1,4 +1,9 @@
use super::{Decl, Expr, Ident, Pat, VarDecl};
use crate::{
decl::{Decl, VarDecl},
expr::Expr,
ident::Ident,
pat::Pat,
};
use swc_common::{ast_node, Span};
/// Use when only block statements are allowed.

View File

@ -0,0 +1,566 @@
#![allow(missing_copy_implementations)]
use crate::{
class::Decorator,
expr::Expr,
ident::Ident,
lit::{Bool, Number, Str},
module::ModuleItem,
pat::{AssignPat, ObjectPat, RestPat},
};
use swc_common::{ast_node, Fold, Span};
#[ast_node]
pub struct TsTypeAnn {
pub span: Span,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsTypeParamDecl {
pub span: Span,
pub params: Vec<TsTypeParam>,
}
#[ast_node]
pub struct TsTypeParam {
pub span: Span,
pub name: Ident,
pub constraint: Option<Box<TsType>>,
pub default: Option<Box<TsType>>,
}
#[ast_node]
pub struct TsTypeParamInstantiation {
pub span: Span,
pub params: Vec<Box<TsType>>,
}
#[ast_node]
pub struct TsTypeCastExpr {
pub span: Span,
pub expr: Box<Expr>,
pub type_ann: TsTypeAnn,
}
#[ast_node]
pub struct TsParamProp {
pub span: Span,
pub decorators: Vec<Decorator>,
/// At least one of `accessibility` or `readonly` must be set.
pub accessibility: Option<Accessibility>,
pub readonly: bool,
pub param: TsParamPropParam,
}
#[ast_node]
pub enum TsParamPropParam {
Ident(Ident),
Assign(AssignPat),
}
#[ast_node]
pub struct TsQualifiedName {
#[span(lo)]
pub left: TsEntityName,
#[span(hi)]
pub right: Ident,
}
#[ast_node]
#[allow(variant_size_differences)]
pub enum TsEntityName {
TsQualifiedName(Box<TsQualifiedName>),
Ident(Ident),
}
#[ast_node]
pub enum TsSignatureDecl {
TsCallSignatureDecl(TsCallSignatureDecl),
TsConstructSignatureDecl(TsConstructSignatureDecl),
TsMethodSignature(TsMethodSignature),
TsFnType(TsFnType),
TsConstructorType(TsConstructorType),
}
// ================
// TypeScript type members (for type literal / interface / class)
// ================
#[ast_node]
pub enum TsTypeElement {
TsCallSignatureDecl(TsCallSignatureDecl),
TsConstructSignatureDecl(TsConstructSignatureDecl),
TsPropertySignature(TsPropertySignature),
TsMethodSignature(TsMethodSignature),
TsIndexSignature(TsIndexSignature),
}
#[ast_node]
pub struct TsCallSignatureDecl {
pub span: Span,
pub params: Vec<TsFnParam>,
pub type_ann: Option<TsTypeAnn>,
pub type_params: Option<TsTypeParamDecl>,
}
#[ast_node]
pub struct TsConstructSignatureDecl {
pub span: Span,
pub params: Vec<TsFnParam>,
pub type_ann: Option<TsTypeAnn>,
pub type_params: Option<TsTypeParamDecl>,
}
#[ast_node]
pub struct TsPropertySignature {
pub span: Span,
pub readonly: bool,
pub key: Box<Expr>,
pub computed: bool,
pub optional: bool,
pub init: Option<Box<Expr>>,
pub params: Vec<TsFnParam>,
pub type_ann: Option<TsTypeAnn>,
pub type_params: Option<TsTypeParamDecl>,
}
#[ast_node]
pub struct TsMethodSignature {
pub span: Span,
pub readonly: bool,
pub key: Box<Expr>,
pub computed: bool,
pub optional: bool,
pub params: Vec<TsFnParam>,
pub type_ann: Option<TsTypeAnn>,
pub type_params: Option<TsTypeParamDecl>,
}
#[ast_node]
pub struct TsIndexSignature {
pub params: Vec<TsFnParam>,
pub type_ann: Option<TsTypeAnn>,
pub readonly: bool,
pub span: Span,
}
// ================
// TypeScript types
// ================
#[ast_node]
pub enum TsType {
TsKeywordType(TsKeywordType),
TsThisType(TsThisType),
TsFnOrConstructorType(TsFnOrConstructorType),
TsTypeRef(TsTypeRef),
TsTypeQuery(TsTypeQuery),
TsTypeLit(TsTypeLit),
TsArrayType(TsArrayType),
TsTupleType(TsTupleType),
TsOptionalType(TsOptionalType),
TsRestType(TsRestType),
TsUnionOrIntersectionType(TsUnionOrIntersectionType),
TsConditionalType(TsConditionalType),
TsInferType(TsInferType),
TsParenthesizedType(TsParenthesizedType),
TsTypeOperator(TsTypeOperator),
TsIndexedAccessType(TsIndexedAccessType),
TsMappedType(TsMappedType),
TsLitType(TsLitType),
TsTypePredicate(TsTypePredicate),
}
#[ast_node]
pub enum TsFnOrConstructorType {
TsFnType(TsFnType),
TsConstructorType(TsConstructorType),
}
impl From<TsFnType> for TsType {
fn from(t: TsFnType) -> Self {
TsFnOrConstructorType::TsFnType(t).into()
}
}
impl From<TsConstructorType> for TsType {
fn from(t: TsConstructorType) -> Self {
TsFnOrConstructorType::TsConstructorType(t).into()
}
}
impl From<TsUnionType> for TsType {
fn from(t: TsUnionType) -> Self {
TsUnionOrIntersectionType::TsUnionType(t).into()
}
}
impl From<TsIntersectionType> for TsType {
fn from(t: TsIntersectionType) -> Self {
TsUnionOrIntersectionType::TsIntersectionType(t).into()
}
}
#[ast_node]
pub struct TsKeywordType {
pub span: Span,
pub kind: TsKeywordTypeKind,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Fold)]
pub enum TsKeywordTypeKind {
TsAnyKeyword,
TsUnknownKeyword,
TsNumberKeyword,
TsObjectKeyword,
TsBooleanKeyword,
TsBigIntKeyword,
TsStringKeyword,
TsSymbolKeyword,
TsVoidKeyword,
TsUndefinedKeyword,
TsNullKeyword,
TsNeverKeyword,
}
#[ast_node]
pub struct TsThisType {
pub span: Span,
}
#[ast_node]
pub enum TsFnParam {
Ident(Ident),
Rest(RestPat),
Object(ObjectPat),
}
#[ast_node]
pub struct TsFnType {
pub span: Span,
pub params: Vec<TsFnParam>,
pub type_params: Option<TsTypeParamDecl>,
pub type_ann: TsTypeAnn,
}
#[ast_node]
pub struct TsConstructorType {
pub span: Span,
pub params: Vec<TsFnParam>,
pub type_params: Option<TsTypeParamDecl>,
pub type_ann: TsTypeAnn,
}
#[ast_node]
pub struct TsTypeRef {
pub span: Span,
pub type_name: TsEntityName,
pub type_params: Option<TsTypeParamInstantiation>,
}
#[ast_node]
pub struct TsTypePredicate {
pub span: Span,
pub param_name: TsThisTypeOrIdent,
pub type_ann: TsTypeAnn,
}
#[ast_node]
#[allow(variant_size_differences)]
pub enum TsThisTypeOrIdent {
TsThisType(TsThisType),
Ident(Ident),
}
/// `typeof` operator
#[ast_node]
pub struct TsTypeQuery {
pub span: Span,
pub expr_name: TsEntityName,
}
#[ast_node]
pub struct TsTypeLit {
pub span: Span,
pub members: Vec<TsTypeElement>,
}
#[ast_node]
pub struct TsArrayType {
pub span: Span,
pub elem_type: Box<TsType>,
}
#[ast_node]
pub struct TsTupleType {
pub span: Span,
pub elem_types: Vec<Box<TsType>>,
}
#[ast_node]
pub struct TsOptionalType {
pub span: Span,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsRestType {
pub span: Span,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub enum TsUnionOrIntersectionType {
TsUnionType(TsUnionType),
TsIntersectionType(TsIntersectionType),
}
#[ast_node]
pub struct TsUnionType {
pub span: Span,
pub types: Vec<Box<TsType>>,
}
#[ast_node]
pub struct TsIntersectionType {
pub span: Span,
pub types: Vec<Box<TsType>>,
}
#[ast_node]
pub struct TsConditionalType {
pub span: Span,
pub check_type: Box<TsType>,
pub extends_type: Box<TsType>,
pub true_type: Box<TsType>,
pub false_type: Box<TsType>,
}
#[ast_node]
pub struct TsInferType {
pub span: Span,
pub type_param: TsTypeParam,
}
#[ast_node]
pub struct TsParenthesizedType {
pub span: Span,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsTypeOperator {
pub span: Span,
pub op: TsTypeOperatorOp,
pub type_ann: Box<TsType>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Fold)]
pub enum TsTypeOperatorOp {
KeyOf,
Unique,
}
#[ast_node]
pub struct TsIndexedAccessType {
pub span: Span,
pub obj_type: Box<TsType>,
pub index_type: Box<TsType>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Fold)]
pub enum TruePlusMinus {
True,
Plus,
Minus,
}
#[ast_node]
pub struct TsMappedType {
pub span: Span,
pub readonly: Option<TruePlusMinus>,
pub type_param: TsTypeParam,
pub optional: Option<TruePlusMinus>,
pub type_ann: Option<Box<TsType>>,
}
#[ast_node]
pub struct TsLitType {
pub span: Span,
pub lit: TsLit,
}
#[ast_node]
pub enum TsLit {
Number(Number),
Str(Str),
Bool(Bool),
}
// // ================
// // TypeScript declarations
// // ================
#[ast_node]
pub struct TsInterfaceDecl {
pub span: Span,
pub id: Ident,
pub declare: bool,
pub type_params: Option<TsTypeParamDecl>,
pub extends: Vec<TsExprWithTypeArgs>,
pub body: TsInterfaceBody,
}
#[ast_node]
pub struct TsInterfaceBody {
pub span: Span,
pub body: Vec<TsTypeElement>,
}
#[ast_node]
pub struct TsExprWithTypeArgs {
pub span: Span,
pub expr: TsEntityName,
pub type_params: Option<TsTypeParamInstantiation>,
}
#[ast_node]
pub struct TsTypeAliasDecl {
pub span: Span,
pub declare: bool,
pub id: Ident,
pub type_params: Option<TsTypeParamDecl>,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsEnumDecl {
pub span: Span,
pub declare: bool,
pub is_const: bool,
pub id: Ident,
pub members: Vec<TsEnumMember>,
}
#[ast_node]
pub struct TsEnumMember {
pub span: Span,
pub id: TsEnumMemberId,
pub init: Option<Box<Expr>>,
}
#[ast_node]
pub enum TsEnumMemberId {
Ident(Ident),
Str(Str),
}
#[ast_node]
pub struct TsModuleDecl {
pub span: Span,
pub declare: bool,
/// In TypeScript, this is only available through`node.flags`.
pub global: bool,
pub id: TsModuleName,
pub body: Option<TsNamespaceBody>,
}
/// `namespace A.B { }` is a namespace named `A` with another TsNamespaceDecl as
/// its body.
#[ast_node]
pub enum TsNamespaceBody {
TsModuleBlock(TsModuleBlock),
TsNamespaceDecl(TsNamespaceDecl),
}
#[ast_node]
pub struct TsModuleBlock {
pub span: Span,
pub body: Vec<ModuleItem>,
}
#[ast_node]
pub struct TsNamespaceDecl {
pub span: Span,
pub declare: bool,
/// In TypeScript, this is only available through`node.flags`.
pub global: bool,
pub id: Ident,
pub body: Box<TsNamespaceBody>,
}
#[ast_node]
pub enum TsModuleName {
Ident(Ident),
Str(Str),
}
#[ast_node]
pub struct TsImportEqualsDecl {
pub span: Span,
pub declare: bool,
pub is_export: bool,
pub id: Ident,
pub module_ref: TsModuleRef,
}
#[ast_node]
pub enum TsModuleRef {
TsEntityName(TsEntityName),
TsExternalModuleRef(TsExternalModuleRef),
}
#[ast_node]
pub struct TsExternalModuleRef {
pub span: Span,
pub expr: Str,
}
/// TypeScript's own parser uses ExportAssignment for both `export default` and
/// `export =`. But for @babel/parser, `export default` is an ExportDefaultDecl,
/// so a TsExportAssignment is always `export =`.
#[ast_node]
pub struct TsExportAssignment {
pub span: Span,
pub expr: Box<Expr>,
}
#[ast_node]
pub struct TsNamespaceExportDecl {
pub span: Span,
pub id: Ident,
}
// // ================
// // TypeScript exprs
// // ================
#[ast_node]
pub struct TsAsExpr {
pub span: Span,
pub expr: Box<Expr>,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsTypeAssertion {
pub span: Span,
pub expr: Box<Expr>,
pub type_ann: Box<TsType>,
}
#[ast_node]
pub struct TsNonNullExpr {
pub span: Span,
pub expr: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Fold)]
pub enum Accessibility {
Public,
Protected,
Private,
}

View File

@ -90,14 +90,17 @@ module.exports = {
fn emit_colors(b: &mut Bencher) {
b.bytes = SOURCE.len() as _;
let _ = ::testing::run_test(|cm, handler| {
let session = Session {
handler: &handler,
cfg: Default::default(),
};
let _ = ::testing::run_test(true, |cm, handler| {
let session = Session { handler: &handler };
let fm = cm.new_source_file(FileName::Anon(0), SOURCE.into());
let mut parser = Parser::new(session, Syntax::Es2019, SourceFileInput::from(&*fm));
let module = parser.parse_module().unwrap();
let mut parser = Parser::new(session, Syntax::Es, SourceFileInput::from(&*fm));
let module = parser
.parse_module()
.map_err(|e| {
e.emit();
()
})
.unwrap();
b.iter(|| {
let buf = vec![];

View File

@ -14,6 +14,10 @@ impl<'a> Emitter<'a> {
emit!(n);
semi!(); // VarDecl is also used for for-loops
}
Decl::TsEnum(ref n) => emit!(n),
Decl::TsInterface(ref n) => emit!(n),
Decl::TsModule(ref n) => emit!(n),
Decl::TsTypeAlias(ref n) => emit!(n),
}
}

View File

@ -37,6 +37,7 @@ pub mod list;
#[cfg(test)]
mod tests;
pub mod text_writer;
mod typescript;
pub mod util;
pub type Result = io::Result<()>;
@ -121,6 +122,9 @@ impl<'a> Emitter<'a> {
semi!();
}
ModuleDecl::ExportAll(ref d) => emit!(d),
ModuleDecl::TsExportAssignment(ref n) => emit!(n),
ModuleDecl::TsImportEqualsDecl(ref n) => emit!(n),
ModuleDecl::TsNamespaceExportDecl(ref n) => emit!(n),
}
self.wr.write_line()?;
}
@ -132,9 +136,10 @@ impl<'a> Emitter<'a> {
keyword!("default");
space!();
match *node {
ExportDefaultDecl::Class(ref class) => emit!(class),
ExportDefaultDecl::Fn(ref f) => emit!(f),
ExportDefaultDecl::Var(ref decl) => emit!(decl),
ExportDefaultDecl::Class(ref n) => emit!(n),
ExportDefaultDecl::Fn(ref n) => emit!(n),
ExportDefaultDecl::Var(ref n) => emit!(n),
ExportDefaultDecl::TsInterfaceDecl(ref n) => emit!(n),
}
semi!();
}
@ -369,6 +374,7 @@ impl<'a> Emitter<'a> {
Expr::Object(ref n) => emit!(n),
Expr::Paren(ref n) => emit!(n),
Expr::Seq(ref n) => emit!(n),
Expr::TaggedTpl(ref n) => emit!(n),
Expr::This(ref n) => emit!(n),
Expr::Tpl(ref n) => emit!(n),
Expr::Unary(ref n) => emit!(n),
@ -380,6 +386,11 @@ impl<'a> Emitter<'a> {
Expr::JSXEmpty(ref n) => emit!(n),
Expr::JSXElement(ref n) => emit!(n),
Expr::JSXFragment(ref n) => emit!(n),
Expr::TsAs(ref n) => emit!(n),
Expr::TsNonNull(ref n) => emit!(n),
Expr::TsTypeAssertion(ref n) => emit!(n),
Expr::TsTypeCast(ref n) => emit!(n),
}
}
@ -520,16 +531,50 @@ impl<'a> Emitter<'a> {
}
#[emitter]
pub fn emit_class_method(&mut self, node: &ClassMethod) -> Result {
pub fn emit_class_memeber(&mut self, node: &ClassMember) -> Result {
match *node {
ClassMember::Constructor(ref n) => emit!(n),
ClassMember::ClassProp(ref n) => emit!(n),
ClassMember::Method(ref n) => emit!(n),
ClassMember::PrivateMethod(ref n) => emit!(n),
ClassMember::PrivateProp(ref n) => emit!(n),
ClassMember::TsIndexSignature(ref n) => emit!(n),
}
}
#[emitter]
pub fn emit_private_method(&mut self, n: &PrivateMethod) -> Result {
unimplemented!("emit_private_method")
}
#[emitter]
pub fn emit_private_prop(&mut self, n: &PrivateProp) -> Result {
unimplemented!("emit_private_prop")
}
#[emitter]
pub fn emit_class_prop(&mut self, node: &ClassProp) -> Result {
unimplemented!("emit_class_prop")
}
#[emitter]
pub fn emit_class_constructor(&mut self, n: &Constructor) -> Result {
keyword!("constructor");
punct!("(");
self.emit_list(n.span(), Some(&n.params), ListFormat::Parameters)?;
punct!(")");
emit!(n.body);
}
#[emitter]
pub fn emit_class_method(&mut self, node: &Method) -> Result {
if node.is_static {
keyword!("static");
space!();
}
match node.kind {
ClassMethodKind::Constructor => {
keyword!("constructor");
}
ClassMethodKind::Method => {
MethodKind::Method => {
if node.function.is_async {
keyword!("async");
}
@ -540,13 +585,13 @@ impl<'a> Emitter<'a> {
emit!(node.key);
}
ClassMethodKind::Getter => {
MethodKind::Getter => {
keyword!("get");
space!();
emit!(node.key);
}
ClassMethodKind::Setter => {
MethodKind::Setter => {
keyword!("set");
space!();
@ -602,8 +647,8 @@ impl<'a> Emitter<'a> {
self.emit_fn_trailing(&node.function)?;
}
#[emitter]
/// prints `(b){}` from `function a(b){}`
#[emitter]
pub fn emit_fn_trailing(&mut self, node: &Function) -> Result {
punct!("(");
self.emit_list(node.span, Some(&node.params), ListFormat::CommaListElements)?;
@ -631,22 +676,39 @@ impl<'a> Emitter<'a> {
}
#[emitter]
pub fn emit_tpl_lit(&mut self, node: &TplLit) -> Result {
pub fn emit_tpl_lit(&mut self, node: &Tpl) -> Result {
debug_assert!(node.quasis.len() == node.exprs.len() + 1);
if let Some(ref tag) = node.tag {
emit!(tag);
}
punct!("`");
let i = 0;
println!("{:?}", node.exprs.len() + node.quasis.len());
for i in 0..(node.quasis.len() + node.exprs.len()) {
if i % 2 == 0 {
emit!(node.quasis[i / 2]);
} else {
punct!("$");
punct!("{");
punct!("${");
emit!(node.exprs[i / 2]);
punct!("}");
}
}
punct!("`");
}
#[emitter]
pub fn emit_tagged_tpl_lit(&mut self, node: &TaggedTpl) -> Result {
debug_assert!(node.quasis.len() == node.exprs.len() + 1);
emit!(node.tag);
emit!(node.type_params);
punct!("`");
let i = 0;
for i in 0..(node.quasis.len() + node.exprs.len()) {
if i % 2 == 0 {
emit!(node.quasis[i / 2]);
} else {
punct!("${");
emit!(node.exprs[i / 2]);
punct!("}");
}

View File

@ -71,7 +71,7 @@ fn test_from_to(from: &str, to: &str) {
where
F: for<'a> FnOnce(&mut Parser<'a, SourceFileInput>) -> PResult<'a, Ret>,
{
self::testing::run_test(|cm, handler| {
self::testing::run_test(true, |cm, handler| {
let src = cm.new_source_file(FileName::Real(file_name.into()), s.to_string());
println!(
"Source: \n{}\nPos: {:?} ~ {:?}",
@ -79,13 +79,14 @@ fn test_from_to(from: &str, to: &str) {
);
let res = f(&mut Parser::new(
Session {
handler: &handler,
cfg: Default::default(),
},
Syntax::Es2019,
Session { handler: &handler },
Syntax::Es,
(&*src).into(),
));
))
.map_err(|e| {
e.emit();
()
});
res
})

View File

@ -0,0 +1,330 @@
use super::{Emitter, Result};
use crate::list::ListFormat;
use swc_common::Spanned;
use swc_ecma_ast::*;
use swc_ecma_codegen_macros::emitter;
impl<'a> Emitter<'a> {
#[emitter]
pub fn emit_pat_or_ts_param_prop(&mut self, n: &PatOrTsParamProp) -> Result {
match *n {
PatOrTsParamProp::Pat(ref n) => emit!(n),
PatOrTsParamProp::TsParamProp(ref n) => emit!(n),
}
}
#[emitter]
pub fn emit_ts_array_type(&mut self, n: &TsArrayType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_as_expr(&mut self, n: &TsAsExpr) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_call_signature_decl(&mut self, n: &TsCallSignatureDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_cond_type(&mut self, n: &TsConditionalType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_constructor_signature_decl(&mut self, n: &TsConstructSignatureDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_constructor_type(&mut self, n: &TsConstructorType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_entity_name(&mut self, n: &TsEntityName) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_enum_decl(&mut self, n: &TsEnumDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_enum_member(&mut self, n: &TsEnumMember) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_enum_member_id(&mut self, n: &TsEnumMemberId) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_export_assignment(&mut self, n: &TsExportAssignment) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_expr_with_type_args(&mut self, n: &TsExprWithTypeArgs) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_external_module_ref(&mut self, n: &TsExternalModuleRef) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_fn_or_constructor_type(&mut self, n: &TsFnOrConstructorType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_fn_param(&mut self, n: &TsFnParam) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_fn_type(&mut self, n: &TsFnType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_import_equals_decl(&mut self, n: &TsImportEqualsDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_index_signature(&mut self, n: &TsIndexSignature) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_index_accessed_type(&mut self, n: &TsIndexedAccessType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_infer_type(&mut self, n: &TsInferType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_interface_body(&mut self, n: &TsInterfaceBody) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_interface_decl(&mut self, n: &TsInterfaceDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_intersection_type(&mut self, n: &TsIntersectionType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_keyword_type(&mut self, n: &TsKeywordType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_lit(&mut self, n: &TsLit) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_lit_type(&mut self, n: &TsLitType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_mapped_type(&mut self, n: &TsMappedType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_method_signature(&mut self, n: &TsMethodSignature) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_module_block(&mut self, n: &TsModuleBlock) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_module_decl(&mut self, n: &TsModuleDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_module_name(&mut self, n: &TsModuleName) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_module_ref(&mut self, n: &TsModuleRef) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_ns_body(&mut self, n: &TsNamespaceBody) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_ns_decl(&mut self, n: &TsNamespaceDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_ns_export_decl(&mut self, n: &TsNamespaceExportDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_non_null_expr(&mut self, n: &TsNonNullExpr) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_optional_type(&mut self, n: &TsOptionalType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_param_prop(&mut self, n: &TsParamProp) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_param_prop_param(&mut self, n: &TsParamPropParam) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_paren_type(&mut self, n: &TsParenthesizedType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_property_signature(&mut self, n: &TsPropertySignature) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_qualified_name(&mut self, n: &TsQualifiedName) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_rest_type(&mut self, n: &TsRestType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_signature_decl(&mut self, n: &TsSignatureDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_this_type(&mut self, n: &TsThisType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_this_type_or_ident(&mut self, n: &TsThisTypeOrIdent) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_tuple_type(&mut self, n: &TsTupleType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type(&mut self, n: &TsType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_alias_decl(&mut self, n: &TsTypeAliasDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_ann(&mut self, n: &TsTypeAnn) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_assertion(&mut self, n: &TsTypeAssertion) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_cast_expr(&mut self, n: &TsTypeCastExpr) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_element(&mut self, n: &TsTypeElement) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_lit(&mut self, n: &TsTypeLit) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_operator(&mut self, n: &TsTypeOperator) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_param(&mut self, n: &TsTypeParam) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_param_decl(&mut self, n: &TsTypeParamDecl) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_param_instantiation(&mut self, n: &TsTypeParamInstantiation) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_predicate(&mut self, n: &TsTypePredicate) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_query(&mut self, n: &TsTypeQuery) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_type_ref(&mut self, n: &TsTypeRef) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_union_or_intersection_type(&mut self, n: &TsUnionOrIntersectionType) -> Result {
unimplemented!()
}
#[emitter]
pub fn emit_ts_union_type(&mut self, n: &TsUnionType) -> Result {
unimplemented!()
}
}

View File

@ -190,12 +190,21 @@ impl StartsWithAlphaNum for Expr {
false
}
Expr::TaggedTpl(TaggedTpl { ref tag, .. }) => tag.starts_with_alpha_num(),
// it's empty
Expr::JSXEmpty(..) => false,
// start with `<`
Expr::JSXFragment(..) | Expr::JSXElement(..) => false,
Expr::JSXNamespacedName(..) => true,
Expr::JSXMebmer(..) => true,
Expr::TsTypeAssertion(..) => false,
Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
| Expr::TsAs(TsAsExpr { ref expr, .. }) => expr.starts_with_alpha_num(),
// TODO
Expr::TsTypeCast(..) => true,
}
}
}

View File

@ -1,4 +1,4 @@
class a{
constructor() {
constructor(){
}
}

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
()=>{
super();
};

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
super();
}
}

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
()=>super();
}
}

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
super.c;
}
}

View File

@ -1,5 +1,5 @@
class a{
constructor() {
constructor(){
}
['constructor']() {
}

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
({
c: super()
});

View File

@ -1,4 +1,4 @@
class a{
constructor() {
constructor(){
}
}

View File

@ -1,12 +1,12 @@
class a{
constructor() {
constructor(){
}
b() {
}
}
;
class c{
constructor(...d) {
constructor(...d){
}
b() {
}

View File

@ -1,5 +1,5 @@
class a extends b{
constructor() {
constructor(){
super();
}
}

View File

@ -1,5 +1,5 @@
(class{
constructor() {
constructor(){
super.a;
}
});

View File

@ -1,6 +1,6 @@
class a{
static constructor() {
constructor(){
}
static constructor() {
constructor(){
}
}

View File

@ -1,4 +1,4 @@
class a extends b{
constructor(c = super()) {
constructor(c = super()){
}
}

View File

@ -1,4 +1,4 @@
(class{
static constructor() {
constructor(){
}
});

View File

@ -1,5 +1,5 @@
(class extends a{
constructor() {
constructor(){
super();
}
});

View File

@ -16,8 +16,7 @@ use std::{
path::Path,
sync::{Arc, RwLock},
};
use swc_common::{sync::Lrc, Fold, FoldWith, Span};
use swc_ecma_ast::*;
use swc_common::sync::Lrc;
use swc_ecma_codegen::Emitter;
use swc_ecma_parser::{Parser, Session, SourceFileInput, Syntax};
use test::{test_main, Options, ShouldPanic::No, TestDesc, TestDescAndFn, TestFn, TestName};
@ -27,6 +26,7 @@ const IGNORED_PASS_TESTS: &[&str] = &[
// Temporalily ignored
"431ecef8c85d4d24.js",
"8386fbff927a9e0e.js",
"5654d4106d7025c2.js",
// Wrong tests (variable name or value is different)
"0339fa95c78c11bd.js",
"0426f15dac46e92d.js",
@ -136,7 +136,7 @@ fn error_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
);
let mut wr = Buf(Arc::new(RwLock::new(vec![])));
::testing::run_test(|cm, handler| {
::testing::run_test(false, |cm, handler| {
let src = cm.load_file(&entry.path()).expect("failed to load file");
eprintln!(
"{}\nPos: {:?} ~ {:?} (L{})",
@ -147,14 +147,8 @@ fn error_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
);
let handlers = box MyHandlers;
let mut parser: Parser<SourceFileInput> = Parser::new(
Session {
handler: &handler,
cfg: Default::default(),
},
Syntax::Es2019,
(&*src).into(),
);
let mut parser: Parser<SourceFileInput> =
Parser::new(Session { handler: &handler }, Syntax::Es, (&*src).into());
let s: Lrc<String> = src.src.as_ref().map(|s| s.clone()).unwrap();
let mut src_map_builder = SourceMapBuilder::new(Some(&s));
@ -174,9 +168,19 @@ fn error_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
// Parse source
if module {
emitter.emit_module(&parser.parse_module()?).unwrap();
emitter
.emit_module(&parser.parse_module().map_err(|e| {
e.emit();
()
})?)
.unwrap();
} else {
emitter.emit_script(&parser.parse_script()?).unwrap();
emitter
.emit_script(&parser.parse_script().map_err(|e| {
e.emit();
()
})?)
.unwrap();
}
}
let ref_file = format!("{}", ref_dir.join(&file_name).display());
@ -202,87 +206,6 @@ fn identity() {
test_main(&args, tests, Options::new());
}
pub fn normalize<T>(t: T) -> T
where
Normalizer: Fold<T>,
{
let mut n = Normalizer;
n.fold(t)
}
pub struct Normalizer;
impl Fold<Span> for Normalizer {
fn fold(&mut self, _: Span) -> Span {
Span::default()
}
}
impl Fold<Str> for Normalizer {
fn fold(&mut self, s: Str) -> Str {
Str {
span: Default::default(),
has_escape: false,
..s
}
}
}
impl Fold<Expr> for Normalizer {
fn fold(&mut self, e: Expr) -> Expr {
let e = e.fold_children(self);
match e {
Expr::Paren(ParenExpr { expr, .. }) => *expr,
Expr::New(NewExpr {
callee,
args: None,
span,
}) => Expr::New(NewExpr {
span,
callee,
args: Some(vec![]),
}),
// Flatten comma expressions.
Expr::Seq(SeqExpr { mut exprs, span }) => {
let need_work = exprs.iter().any(|n| match **n {
Expr::Seq(..) => true,
_ => false,
});
if need_work {
exprs = exprs.into_iter().fold(vec![], |mut v, e| {
match *e {
Expr::Seq(SeqExpr { exprs, .. }) => v.extend(exprs),
_ => v.push(e),
}
v
});
}
Expr::Seq(SeqExpr { exprs, span })
}
_ => e,
}
}
}
impl Fold<PropName> for Normalizer {
fn fold(&mut self, n: PropName) -> PropName {
let n = n.fold_children(self);
match n {
PropName::Ident(Ident { sym, .. }) => PropName::Str(Str {
span: Default::default(),
value: sym,
has_escape: false,
}),
PropName::Num(num) => PropName::Str(Str {
span: Default::default(),
value: num.to_string().into(),
has_escape: false,
}),
_ => n,
}
}
}
#[derive(Debug, Clone)]
struct Buf(Arc<RwLock<Vec<u8>>>);
impl Write for Buf {

View File

@ -87,16 +87,17 @@ fn add_golden_tests(tests: &mut Vec<TestDescAndFn>) -> Result<(), io::Error> {
file_name, input
);
let stderr = ::testing::run_test(|cm, handler| {
let stderr = ::testing::run_test(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Real(path.clone()), input);
let module = {
let session = parser::Session {
cfg: Default::default(),
handler: &handler,
};
parser::Parser::new(session, Syntax::Es2019, SourceFileInput::from(&*fm))
.parse_module()?
let session = parser::Session { handler: &handler };
parser::Parser::new(session, Syntax::Es, SourceFileInput::from(&*fm))
.parse_module()
.map_err(|e| {
e.emit();
()
})?
};
lints::lint_all(&handler, &module);

View File

@ -53,16 +53,13 @@ fn yui(b: &mut Bencher) {
fn bench_module(b: &mut Bencher, src: &'static str) {
b.bytes = src.len() as _;
let _ = ::testing::run_test(|cm, handler| {
let session = Session {
handler: &handler,
cfg: Default::default(),
};
let _ = ::testing::run_test(false, |cm, handler| {
let session = Session { handler: &handler };
let fm = cm.new_source_file(FileName::Anon(0), src.into());
b.iter(|| {
test::black_box({
let mut parser = Parser::new(session, Syntax::Es2019, SourceFileInput::from(&*fm));
let mut parser = Parser::new(session, Syntax::Es, SourceFileInput::from(&*fm));
let _ = parser.parse_module();
})
});

View File

@ -60,7 +60,11 @@ impl Fold for InjectSelf {
}
}
if i.method == "parse_with" || i.method == "spanned" {
if i.method == "parse_with"
|| i.method == "spanned"
|| i.method == "try_parse_ts"
|| i.method == "ts_in_no_context"
{
//TODO
let parser = get_parser_arg(&i);
return fold::fold_expr_method_call(
@ -107,7 +111,7 @@ impl Fold for InjectSelf {
let span = get_joinned_span(&i.path);
match &*name {
"vec" | "unreachable" | "tok" | "op" | "js_word" => return i,
"smallvec" | "vec" | "unreachable" | "tok" | "op" | "js_word" => return i,
"println" | "print" | "format" | "assert" | "assert_eq" | "assert_ne"
| "debug_assert" | "debug_assert_eq" | "debug_assert_ne" => {
let mut args: Punctuated<Expr, token::Comma> = parse_args(i.tts.into());

View File

@ -83,6 +83,7 @@ pub(crate) enum SyntaxError {
left: String,
left_span: Span,
},
Hash,
LineBreakInThrow,
LineBreakBeforeArrow,
@ -110,6 +111,7 @@ pub(crate) enum SyntaxError {
/// `()`
EmptyParenExpr,
InvalidPat,
InvalidExpr,
NotSimpleAssign,
ExpectedIdent,
ExpctedSemi,
@ -134,6 +136,20 @@ pub(crate) enum SyntaxError {
JSXExpectedClosingTag {
tag: JsWord,
},
InvalidLeadingDecorator,
DecoratorOnExport,
TsNonLastRest,
TsRequiredAfterOptional,
TsInvalidParamPropPat,
SpaceBetweenHashAndIdent,
AsyncConstructor,
PropertyNamedConstructor,
ClassProperty,
ReadOnlyMethod,
TsBindingPatCannotBeOptional,
}
impl<'a> From<ErrorToDiag<'a>> for Error {
@ -190,6 +206,7 @@ impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
identifier in string mode"
.into(),
UnaryInExp { .. } => "** cannot be applied to unary expression".into(),
Hash => "Unexpected token '#'".into(),
LineBreakInThrow => "LineBreak cannot follow 'throw'".into(),
LineBreakBeforeArrow => "Unexpected line break between arrow head and arrow".into(),
Unexpected { ref got } => format!("Unexpected token {}", got).into(),
@ -213,6 +230,7 @@ impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
SpreadInParenExpr => "Parenthesized expression cannot contain spread operator".into(),
EmptyParenExpr => "Parenthized expression cannot be empty".into(),
InvalidPat => "Not a pattern".into(),
InvalidExpr => "Not an expression".into(),
// TODO
NotSimpleAssign => "Cannot assign to this".into(),
ExpectedIdent => "Expected ident".into(),
@ -242,6 +260,29 @@ impl<'a> From<ErrorToDiag<'a>> for DiagnosticBuilder<'a> {
JSXExpectedClosingTag { ref tag } => {
format!("Expected corresponding JSX closing tag for <{}>", tag).into()
}
InvalidLeadingDecorator => {
"Leading decorators must be attached to a class declaration".into()
}
DecoratorOnExport => "Using the export keyword between a decorator and a class is not \
allowed. Please use `export @dec class` instead."
.into(),
TsNonLastRest => "A rest element must be last in a tuple type.".into(),
TsRequiredAfterOptional => {
"A required element cannot follow an optional element.".into()
}
TsInvalidParamPropPat => {
"Typescript parameter property must be identifer or assignment pattern".into()
}
SpaceBetweenHashAndIdent => "Unexpected space between # and identifier".into(),
AsyncConstructor => "Constructor can't be an async function".into(),
PropertyNamedConstructor => {
"Classes may not have a non-static field named 'constructor'".into()
}
ClassProperty => "Class property requires `esnext.classProperty` to be true".into(),
ReadOnlyMethod => "A method cannot be readonly".into(),
TsBindingPatCannotBeOptional => "A binding pattern parameter cannot be optional in an \
implementation signature."
.into(),
};
let d = e.handler.error(&msg).span(e.span);

View File

@ -108,14 +108,20 @@ impl<'a> Input for SourceFileInput<'a> {
self.start_pos = to;
self.last_pos = to;
}
fn is_at_start(&self) -> bool {
self.fm.start_pos == self.last_pos
}
}
pub trait Input {
pub trait Input: Clone {
fn cur(&mut self) -> Option<char>;
fn peek(&mut self) -> Option<char>;
fn peek_ahead(&mut self) -> Option<char>;
fn bump(&mut self);
fn is_at_start(&self) -> bool;
fn cur_pos(&mut self) -> BytePos;
fn last_pos(&self) -> BytePos;

View File

@ -5,6 +5,7 @@
#![allow(unused_mut)]
#![allow(unused_variables)]
pub use self::input::Input;
pub(crate) use self::state::{TokenContext, TokenContexts};
use self::{state::State, util::*};
use crate::{
error::{Error, SyntaxError},
@ -26,6 +27,7 @@ pub mod util;
pub(crate) type LexResult<T> = Result<T, Error>;
#[derive(Clone)]
pub(crate) struct Lexer<'a, I: Input> {
session: Session<'a>,
pub ctx: Context,
@ -54,6 +56,7 @@ impl<'a, I: Input> Lexer<'a, I> {
let start = self.cur_pos();
let token = match c {
'#' => return self.read_token_number_sign(),
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
c if c == '\\' || c.is_ident_start() => return self.read_ident_or_keyword().map(Some),
@ -110,7 +113,7 @@ impl<'a, I: Input> Lexer<'a, I> {
':' => {
self.input.bump();
if self.session.cfg.fn_bind && self.input.cur() == Some(':') {
if self.syntax.fn_bind() && self.input.cur() == Some(':') {
self.input.bump();
return Ok(Some(tok!("::")));
}
@ -278,6 +281,47 @@ impl<'a, I: Input> Lexer<'a, I> {
Ok(Some(token))
}
/// `#`
fn read_token_number_sign(&mut self) -> LexResult<Option<Token>> {
assert!(self.cur().is_some());
let start = self.input.cur_pos();
if self.input.is_at_start() && self.read_token_interpreter()? {
return Ok(None);
}
if self.syntax.class_private_props() || self.syntax.class_private_methods() {
self.input.bump(); // '#'
return Ok(Some(Token::Hash));
}
self.error(start, SyntaxError::Hash)?
}
fn read_token_interpreter(&mut self) -> LexResult<bool> {
if !self.input.is_at_start() {
return Ok(false);
}
let start = self.input.cur_pos();
self.input.bump();
let c = self.input.cur();
if c == Some('!') {
loop {
while let Some(c) = self.input.cur() {
if c != '\n' && c != '\r' && c != '\u{8232}' && c != '\u{8233}' {
self.input.bump();
continue;
}
}
}
} else {
self.input.reset_to(start);
return Ok(false);
}
}
/// Read an escaped charater for string literal.
///
/// In template literal, we should preserve raw string.
@ -766,6 +810,10 @@ impl<'a, I: Input> Lexer<'a, I> {
pub fn had_line_break_before_last(&self) -> bool {
self.state.had_line_break
}
pub fn set_expr_allowed(&mut self, allow: bool) {
self.state.is_expr_allowed = allow;
}
}
fn pos_span(p: BytePos) -> Span {

View File

@ -226,7 +226,7 @@ impl<'a, I: Input> Lexer<'a, I> {
let mut total: Ret = Default::default();
while let Some(c) = self.cur() {
if self.session.cfg.num_sep {
if self.syntax.num_sep() {
// let prev: char = unimplemented!("prev");
// let next = self.input.peek();
@ -288,7 +288,7 @@ mod tests {
F: FnOnce(&mut Lexer<SourceFileInput>) -> Ret,
{
crate::with_test_sess(s, |sess, fm| {
let mut l = Lexer::new(sess, Syntax::Es2019, fm.into());
let mut l = Lexer::new(sess, Syntax::Es, fm.into());
Ok(f(&mut l))
})
.unwrap()
@ -376,7 +376,7 @@ mod tests {
let vec = panic::catch_unwind(|| {
crate::with_test_sess(case, |mut sess, input| {
let mut l = Lexer::new(sess, Syntax::Es2019, input);
let mut l = Lexer::new(sess, Syntax::Es, input);
l.ctx.strict = strict;
Ok(l.map(|ts| ts.token).collect::<Vec<_>>())
})

View File

@ -7,7 +7,7 @@ use swc_common::BytePos;
/// State of lexer.
///
/// Ported from babylon.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub(super) struct State {
pub is_expr_allowed: bool,
pub octal_pos: Option<BytePos>,
@ -19,7 +19,7 @@ pub(super) struct State {
pub cur_line: usize,
pub line_start: BytePos,
context: Context,
context: TokenContexts,
syntax: Syntax,
token_type: Option<TokenType>,
@ -74,7 +74,7 @@ impl<'a> From<&'a Token> for TokenType {
Token::JSXName { .. } => TokenType::JSXName,
Token::BinOp(op) => TokenType::BinOp(op),
Token::Word(Keyword(k)) => TokenType::Keyword(k),
Token::Word(Word::Keyword(k)) => TokenType::Keyword(k),
_ => TokenType::Other {
before_expr: t.before_expr(),
},
@ -82,6 +82,18 @@ impl<'a> From<&'a Token> for TokenType {
}
}
impl<'a, I: Input> Lexer<'a, I> {
pub const fn token_context(&self) -> &TokenContexts {
&self.state.context
}
pub fn token_context_mut(&mut self) -> &mut TokenContexts {
&mut self.state.context
}
pub fn set_token_context(&mut self, c: TokenContexts) {
self.state.context = c;
}
}
impl<'a, I: Input> Iterator for Lexer<'a, I> {
type Item = TokenAndSpan;
fn next(&mut self) -> Option<Self::Item> {
@ -107,8 +119,8 @@ impl<'a, I: Input> Iterator for Lexer<'a, I> {
}
};
match self.input.cur() {
Some(..) => {}
let c = match self.input.cur() {
Some(c) => c,
None => return None,
};
@ -122,9 +134,19 @@ impl<'a, I: Input> Iterator for Lexer<'a, I> {
self.state.start = start;
let res = (|| -> Result<Option<_>, _> {
if self.syntax.jsx() {
if self.syntax.typescript() && self.ctx.in_type {
if c == '<' {
self.input.bump();
return Ok(Some(tok!('<')));
} else if c == '>' {
self.input.bump();
return Ok(Some(tok!('>')));
}
}
if self.syntax.jsx() && !self.ctx.in_property_name {
//jsx
if self.state.context.current() == Some(Type::JSXExpr) {
if self.state.context.current() == Some(TokenContext::JSXExpr) {
let start = self.cur_pos();
return self.read_jsx_token();
@ -132,8 +154,8 @@ impl<'a, I: Input> Iterator for Lexer<'a, I> {
let c = self.cur();
if let Some(c) = c {
if self.state.context.current() == Some(Type::JSXOpeningTag)
|| self.state.context.current() == Some(Type::JSXClosingTag)
if self.state.context.current() == Some(TokenContext::JSXOpeningTag)
|| self.state.context.current() == Some(TokenContext::JSXClosingTag)
{
if c.is_ident_start() {
return self.read_jsx_word().map(Some);
@ -145,7 +167,7 @@ impl<'a, I: Input> Iterator for Lexer<'a, I> {
}
if (c == '\'' || c == '"')
&& self.state.context.current() == Some(Type::JSXOpeningTag)
&& self.state.context.current() == Some(TokenContext::JSXOpeningTag)
{
return self.read_jsx_str(c).map(Some);
}
@ -158,7 +180,7 @@ impl<'a, I: Input> Iterator for Lexer<'a, I> {
}
}
if let Some(Type::Tpl {
if let Some(TokenContext::Tpl {
start: start_pos_of_tpl,
}) = self.state.context.current()
{
@ -195,7 +217,7 @@ impl State {
octal_pos: None,
is_first: true,
had_line_break: false,
context: Context(smallvec![Type::BraceStmt]),
context: TokenContexts(smallvec![TokenContext::BraceStmt]),
token_type: None,
start: BytePos(0),
line_start: BytePos(0),
@ -244,7 +266,7 @@ impl State {
/// `is_expr_allowed`: previous value.
/// `start`: start of newly produced token.
fn is_expr_allowed_on_next(
context: &mut Context,
context: &mut TokenContexts,
syntax: Syntax,
prev: Option<TokenType>,
start: BytePos,
@ -253,7 +275,7 @@ impl State {
is_expr_allowed: bool,
) -> bool {
let is_next_keyword = match next {
&Word(Keyword(..)) => true,
&Word(Word::Keyword(..)) => true,
_ => false,
};
@ -271,13 +293,15 @@ impl State {
let out = context.pop().unwrap();
// let a = function(){}
if out == Type::BraceStmt && context.current() == Some(Type::FnExpr) {
if out == TokenContext::BraceStmt
&& context.current() == Some(TokenContext::FnExpr)
{
context.pop();
return false;
}
// ${} in template
if out == Type::TplQuasi {
if out == TokenContext::TplQuasi {
return true;
}
@ -291,20 +315,22 @@ impl State {
if is_expr_allowed
&& !context.is_brace_block(prev, had_line_break, is_expr_allowed)
{
context.push(Type::FnExpr);
context.push(TokenContext::FnExpr);
}
return false;
}
// for (a of b) {}
tok!("of") if Some(Type::ParenStmt { is_for_loop: true }) == context.current() => {
tok!("of")
if Some(TokenContext::ParenStmt { is_for_loop: true }) == context.current() =>
{
// e.g. for (a of _) => true
!prev
.expect("context.current() if ParenStmt, so prev token cannot be None")
.before_expr()
}
Word(Ident(ref ident)) => {
Word(Word::Ident(ref ident)) => {
// variable declaration
return match prev {
Some(prev) => match prev {
@ -324,16 +350,16 @@ impl State {
tok!('{') => {
let cur = context.current();
if syntax.jsx() && cur == Some(Type::JSXOpeningTag) {
context.push(Type::BraceExpr)
} else if syntax.jsx() && cur == Some(Type::JSXExpr) {
context.push(Type::TplQuasi);
if syntax.jsx() && cur == Some(TokenContext::JSXOpeningTag) {
context.push(TokenContext::BraceExpr)
} else if syntax.jsx() && cur == Some(TokenContext::JSXExpr) {
context.push(TokenContext::TplQuasi);
} else {
let next_ctxt =
if context.is_brace_block(prev, had_line_break, is_expr_allowed) {
Type::BraceStmt
TokenContext::BraceStmt
} else {
Type::BraceExpr
TokenContext::BraceExpr
};
context.push(next_ctxt);
}
@ -343,12 +369,12 @@ impl State {
tok!('/') if syntax.jsx() && prev == Some(TokenType::JSXTagStart) => {
context.pop();
context.pop(); // do not consider JSX expr -> JSX open tag -> ... anymore
context.push(Type::JSXClosingTag); // reconsider as closing tag context
context.push(TokenContext::JSXClosingTag); // reconsider as closing tag context
false
}
tok!("${") => {
context.push(Type::TplQuasi);
context.push(TokenContext::TplQuasi);
return true;
}
@ -357,11 +383,11 @@ impl State {
context.push(match prev {
Some(TokenType::Keyword(k)) => match k {
If | With | While => Type::ParenStmt { is_for_loop: false },
For => Type::ParenStmt { is_for_loop: true },
_ => Type::ParenExpr,
If | With | While => TokenContext::ParenStmt { is_for_loop: false },
For => TokenContext::ParenStmt { is_for_loop: true },
_ => TokenContext::ParenExpr,
},
_ => Type::ParenExpr,
_ => TokenContext::ParenExpr,
});
return true;
}
@ -371,30 +397,30 @@ impl State {
tok!('`') => {
// If we are in template, ` terminates template.
if let Some(Type::Tpl { .. }) = context.current() {
if let Some(TokenContext::Tpl { .. }) = context.current() {
context.pop();
} else {
context.push(Type::Tpl { start });
context.push(TokenContext::Tpl { start });
}
return false;
}
// tt.jsxTagStart.updateContext
Token::JSXTagStart => {
context.push(Type::JSXExpr); // treat as beginning of JSX expression
context.push(Type::JSXOpeningTag); // start opening tag context
context.push(TokenContext::JSXExpr); // treat as beginning of JSX expression
context.push(TokenContext::JSXOpeningTag); // start opening tag context
return false;
}
// tt.jsxTagEnd.updateContext
Token::JSXTagEnd => {
let out = context.pop();
if (out == Some(Type::JSXOpeningTag)
if (out == Some(TokenContext::JSXOpeningTag)
&& prev == Some(TokenType::BinOp(BinOpToken::Div)))
|| out == Some(Type::JSXClosingTag)
|| out == Some(TokenContext::JSXClosingTag)
{
context.pop();
return context.current() == Some(Type::JSXExpr);
return context.current() == Some(TokenContext::JSXExpr);
} else {
return true;
}
@ -408,9 +434,9 @@ impl State {
}
}
#[derive(Debug, Default)]
struct Context(SmallVec<[Type; 32]>);
impl Context {
#[derive(Debug, Clone, Default)]
pub(crate) struct TokenContexts(pub SmallVec<[TokenContext; 32]>);
impl TokenContexts {
/// Returns true if following `LBrace` token is `block statement` according
/// to `ctx`, `prev`, `is_expr_allowed`.
fn is_brace_block(
@ -421,10 +447,10 @@ impl Context {
) -> bool {
match prev {
Some(TokenType::Colon) => match self.current() {
Some(Type::BraceStmt) => return true,
Some(TokenContext::BraceStmt) => return true,
// `{ a: {} }`
// ^ ^
Some(Type::BraceExpr) => return false,
Some(TokenContext::BraceExpr) => return false,
_ => {}
},
_ => {}
@ -452,7 +478,7 @@ impl Context {
}
// If previous token was `{`
Some(TokenType::LBrace) => return self.current() == Some(Type::BraceStmt),
Some(TokenType::LBrace) => return self.current() == Some(TokenContext::BraceStmt),
// `class C<T> { ... }`
Some(TokenType::BinOp(Lt)) | Some(TokenType::BinOp(Gt)) => return true,
@ -462,18 +488,18 @@ impl Context {
return !is_expr_allowed;
}
fn len(&self) -> usize {
pub fn len(&self) -> usize {
self.0.len()
}
fn pop(&mut self) -> Option<Type> {
pub fn pop(&mut self) -> Option<TokenContext> {
let opt = self.0.pop();
trace!("context.pop({:?})", opt);
opt
}
fn current(&self) -> Option<Type> {
pub fn current(&self) -> Option<TokenContext> {
self.0.last().cloned()
}
fn push(&mut self, t: Type) {
fn push(&mut self, t: TokenContext) {
trace!("context.push({:?})", t);
self.0.push(t);
}
@ -484,7 +510,7 @@ impl Context {
/// See https://github.com/mozilla/sweet.js/wiki/design
#[derive(Debug, Clone, Copy, PartialEq, Eq, Kind)]
#[kind(fucntion(is_expr = "bool", preserve_space = "bool"))]
enum Type {
pub(crate) enum TokenContext {
BraceStmt,
#[kind(is_expr)]
BraceExpr,
@ -522,7 +548,7 @@ where
let mut l = Lexer::new(sess, syntax, fm);
let res = f(&mut l);
let c: SmallVec<[Type; 32]> = smallvec![Type::BraceStmt];
let c: SmallVec<[TokenContext; 32]> = smallvec![TokenContext::BraceStmt];
assert_eq!(l.state.context.0, c);
res

View File

@ -76,12 +76,12 @@ impl WithSpan for f64 {
}
impl<'a> WithSpan for &'a str {
fn into_token(self) -> Token {
Word(Ident(self.into()))
Word(Word::Ident(self.into()))
}
}
impl WithSpan for Keyword {
fn into_token(self) -> Token {
Word(Keyword(self))
Word(Word::Keyword(self))
}
}
impl WithSpan for Word {
@ -103,7 +103,7 @@ impl WithSpan for AssignOpToken {
#[test]
fn module_legacy_octal() {
assert_eq!(
lex_module(Syntax::Es2019, "01"),
lex_module(Syntax::Es, "01"),
vec![Token::Error(Error {
span: sp(0..2),
error: SyntaxError::LegacyOctal,
@ -115,7 +115,7 @@ fn module_legacy_octal() {
#[test]
fn module_legacy_decimal() {
assert_eq!(
lex_module(Syntax::Es2019, "08"),
lex_module(Syntax::Es, "08"),
vec![Token::Error(Error {
span: sp(0..2),
error: SyntaxError::LegacyDecimal,
@ -128,7 +128,7 @@ fn module_legacy_decimal() {
#[test]
fn module_legacy_comment_1() {
assert_eq!(
lex_module(Syntax::Es2019, "<!-- foo oo"),
lex_module(Syntax::Es, "<!-- foo oo"),
vec![Token::Error(Error {
span: sp(0..11),
error: SyntaxError::LegacyCommentInModule,
@ -141,7 +141,7 @@ fn module_legacy_comment_1() {
#[test]
fn module_legacy_comment_2() {
assert_eq!(
lex_module(Syntax::Es2019, "-->"),
lex_module(Syntax::Es, "-->"),
vec![Token::Error(Error {
span: sp(0..3),
error: SyntaxError::LegacyCommentInModule,
@ -162,7 +162,7 @@ fn test262_lexer_error_0001() {
1.span(7..8),
RParen.span(8..9),
],
lex(Syntax::Es2019, "123..a(1)")
lex(Syntax::Es, "123..a(1)")
)
}
@ -178,41 +178,35 @@ fn test262_lexer_error_0002() {
.lb(),
Semi.span(15..16),
],
lex(Syntax::Es2019, r#"'use\x20strict';"#)
lex(Syntax::Es, r#"'use\x20strict';"#)
);
}
#[test]
fn test262_lexer_error_0003() {
assert_eq!(vec!["a".span(0..6).lb()], lex(Syntax::Es2019, r#"\u0061"#));
assert_eq!(vec!["a".span(0..6).lb()], lex(Syntax::Es, r#"\u0061"#));
}
#[test]
fn test262_lexer_error_0004() {
assert_eq!(
vec![tok!('+'), tok!('{'), tok!('}'), tok!('/'), 1.into_token()],
lex_tokens(Syntax::Es2019, "+{} / 1")
lex_tokens(Syntax::Es, "+{} / 1")
);
}
#[test]
fn ident_escape_unicode() {
assert_eq!(
vec!["aa".span(0..7).lb()],
lex(Syntax::Es2019, r#"a\u0061"#)
);
assert_eq!(vec!["aa".span(0..7).lb()], lex(Syntax::Es, r#"a\u0061"#));
}
#[test]
fn ident_escape_unicode_2() {
assert_eq!(
vec!["℘℘".span(0..6).lb()],
lex(Syntax::Es2019, "℘℘")
);
assert_eq!(vec!["℘℘".span(0..6).lb()], lex(Syntax::Es, "℘℘"));
assert_eq!(
vec!["℘℘".span(0..9).lb()],
lex(Syntax::Es2019, r#"℘\u2118"#)
lex(Syntax::Es, r#"℘\u2118"#)
);
}
@ -220,7 +214,7 @@ fn ident_escape_unicode_2() {
fn tpl_multiline() {
assert_eq!(
lex_tokens(
Syntax::Es2019,
Syntax::Es,
"`this
is
multiline`"
@ -240,7 +234,7 @@ multiline`"
#[test]
fn tpl_raw_unicode_escape() {
assert_eq!(
lex_tokens(Syntax::Es2019, r"`\u{0010}`"),
lex_tokens(Syntax::Es, r"`\u{0010}`"),
vec![
tok!('`'),
Token::Template {
@ -256,7 +250,7 @@ fn tpl_raw_unicode_escape() {
#[test]
fn str_escape() {
assert_eq!(
lex_tokens(Syntax::Es2019, r#"'\n'"#),
lex_tokens(Syntax::Es, r#"'\n'"#),
vec![Token::Str {
value: "\n".into(),
has_escape: true
@ -267,7 +261,7 @@ fn str_escape() {
#[test]
fn str_escape_2() {
assert_eq!(
lex_tokens(Syntax::Es2019, r#"'\\n'"#),
lex_tokens(Syntax::Es, r#"'\\n'"#),
vec![Token::Str {
value: "\\n".into(),
has_escape: true
@ -278,7 +272,7 @@ fn str_escape_2() {
#[test]
fn str_escape_hex() {
assert_eq!(
lex(Syntax::Es2019, r#"'\x61'"#),
lex(Syntax::Es, r#"'\x61'"#),
vec![Token::Str {
value: "a".into(),
has_escape: true,
@ -291,7 +285,7 @@ fn str_escape_hex() {
#[test]
fn str_escape_octal() {
assert_eq!(
lex(Syntax::Es2019, r#"'Hello\012World'"#),
lex(Syntax::Es, r#"'Hello\012World'"#),
vec![Token::Str {
value: "Hello\nWorld".into(),
has_escape: true,
@ -304,7 +298,7 @@ fn str_escape_octal() {
#[test]
fn str_escape_unicode_long() {
assert_eq!(
lex(Syntax::Es2019, r#"'\u{00000000034}'"#),
lex(Syntax::Es, r#"'\u{00000000034}'"#),
vec![Token::Str {
value: "4".into(),
has_escape: true,
@ -317,7 +311,7 @@ fn str_escape_unicode_long() {
#[test]
fn regexp_unary_void() {
assert_eq!(
lex(Syntax::Es2019, "void /test/"),
lex(Syntax::Es, "void /test/"),
vec![
Void.span(0..4).lb(),
Regex(
@ -332,7 +326,7 @@ fn regexp_unary_void() {
]
);
assert_eq!(
lex(Syntax::Es2019, "void (/test/)"),
lex(Syntax::Es, "void (/test/)"),
vec![
Void.span(0..4).lb(),
LParen.span(5..6),
@ -353,7 +347,7 @@ fn regexp_unary_void() {
#[test]
fn non_regexp_unary_plus() {
assert_eq!(
lex(Syntax::Es2019, "+{} / 1"),
lex(Syntax::Es, "+{} / 1"),
vec![
tok!('+').span(0..1).lb(),
tok!('{').span(1..2),
@ -370,7 +364,7 @@ fn non_regexp_unary_plus() {
fn paren_semi() {
assert_eq!(
vec![LParen.span(0).lb(), RParen.span(1), Semi.span(2)],
lex(Syntax::Es2019, "();")
lex(Syntax::Es, "();")
);
}
@ -384,7 +378,7 @@ fn ident_paren() {
RParen.span(4),
Semi.span(5),
],
lex(Syntax::Es2019, "a(bc);")
lex(Syntax::Es, "a(bc);")
);
}
@ -392,14 +386,14 @@ fn ident_paren() {
fn read_word() {
assert_eq!(
vec!["a".span(0).lb(), "b".span(2), "c".span(4)],
lex(Syntax::Es2019, "a b c"),
lex(Syntax::Es, "a b c"),
)
}
#[test]
fn simple_regex() {
assert_eq!(
lex(Syntax::Es2019, "x = /42/i"),
lex(Syntax::Es, "x = /42/i"),
vec![
"x".span(0).lb(),
Assign.span(2),
@ -420,7 +414,7 @@ fn simple_regex() {
);
assert_eq!(
lex(Syntax::Es2019, "/42/"),
lex(Syntax::Es, "/42/"),
vec![Regex(
Str {
span: sp(1..3),
@ -438,12 +432,12 @@ fn simple_regex() {
fn complex_regex() {
assert_eq_ignore_span!(
vec![
Word(Ident("f".into())),
Word(Word::Ident("f".into())),
LParen,
RParen,
Semi,
Word(Keyword(Function)),
Word(Ident("foo".into())),
Word(Word::Keyword(Function)),
Word(Word::Ident("foo".into())),
LParen,
RParen,
LBrace,
@ -461,7 +455,7 @@ fn complex_regex() {
}),
),
],
lex_tokens(Syntax::Es2019, "f(); function foo() {} /42/i")
lex_tokens(Syntax::Es, "f(); function foo() {} /42/i")
)
}
@ -469,7 +463,7 @@ fn complex_regex() {
fn simple_div() {
assert_eq!(
vec!["a".span(0).lb(), Div.span(2), "b".span(4)],
lex(Syntax::Es2019, "a / b")
lex(Syntax::Es, "a / b")
);
}
@ -477,20 +471,20 @@ fn simple_div() {
fn complex_divide() {
assert_eq!(
vec![
Word(Ident("x".into())),
Word(Word::Ident("x".into())),
AssignOp(Assign),
Word(Keyword(Function)),
Word(Ident("foo".into())),
Word(Word::Keyword(Function)),
Word(Word::Ident("foo".into())),
LParen,
RParen,
LBrace,
RBrace,
BinOp(Div),
Word(Ident("a".into())),
Word(Word::Ident("a".into())),
BinOp(Div),
Word(Ident("i".into())),
Word(Word::Ident("i".into())),
],
lex_tokens(Syntax::Es2019, "x = function foo() {} /a/i"),
lex_tokens(Syntax::Es, "x = function foo() {} /a/i"),
"/ should be parsed as div operator"
)
}
@ -500,22 +494,22 @@ fn complex_divide() {
#[test]
fn spec_001() {
let expected = vec![
Word(Ident("a".into())),
Word(Word::Ident("a".into())),
AssignOp(Assign),
Word(Ident("b".into())),
Word(Word::Ident("b".into())),
BinOp(Div),
Word(Ident("hi".into())),
Word(Word::Ident("hi".into())),
BinOp(Div),
Word(Ident("g".into())),
Word(Word::Ident("g".into())),
Dot,
Word(Ident("exec".into())),
Word(Word::Ident("exec".into())),
LParen,
Word(Ident("c".into())),
Word(Word::Ident("c".into())),
RParen,
Dot,
Word(Ident("map".into())),
Word(Word::Ident("map".into())),
LParen,
Word(Ident("d".into())),
Word(Word::Ident("d".into())),
RParen,
Semi,
];
@ -523,14 +517,14 @@ fn spec_001() {
assert_eq!(
expected,
lex_tokens(
Syntax::Es2019,
Syntax::Es,
"a = b
/hi/g.exec(c).map(d);"
)
);
assert_eq!(
expected,
lex_tokens(Syntax::Es2019, "a = b / hi / g.exec(c).map(d);")
lex_tokens(Syntax::Es, "a = b / hi / g.exec(c).map(d);")
);
}
@ -539,7 +533,7 @@ fn spec_001() {
#[test]
fn after_if() {
assert_eq!(
lex(Syntax::Es2019, "if(x){} /y/.test(z)"),
lex(Syntax::Es, "if(x){} /y/.test(z)"),
vec![
Keyword::If.span(0..2).lb(),
LParen.span(2),
@ -567,7 +561,7 @@ fn after_if() {
#[test]
fn empty() {
assert_eq!(lex(Syntax::Es2019, ""), vec![]);
assert_eq!(lex(Syntax::Es, ""), vec![]);
}
#[test]
@ -584,7 +578,7 @@ fn invalid_number_failure() {
// BlockComment(" hello world ".into()).span(0..17),
// Regex("42".into(), "".into()).span(17..21),
// ],
// lex(Syntax::Es2019, "/* hello world */ /42/")
// lex(Syntax::Es, "/* hello world */ /42/")
// )
// }
@ -599,7 +593,7 @@ fn invalid_number_failure() {
// 42.span(13..15),
// LineComment(" the Ultimate".into()).span(17..32),
// ],
// lex(Syntax::Es2019, "var answer = 42 // the Ultimate"),
// lex(Syntax::Es, "var answer = 42 // the Ultimate"),
// )
// }
@ -620,7 +614,7 @@ fn migrated_0002() {
.span(9..13),
RParen.span(13),
],
lex(Syntax::Es2019, "tokenize(/42/)")
lex(Syntax::Es, "tokenize(/42/)")
)
}
@ -635,7 +629,7 @@ fn migrated_0003() {
42.span(9..11),
Div.span(11),
],
lex(Syntax::Es2019, "(false) /42/"),
lex(Syntax::Es, "(false) /42/"),
)
}
@ -659,7 +653,7 @@ fn migrated_0004() {
)
.span(15..19),
],
lex(Syntax::Es2019, "function f(){} /42/")
lex(Syntax::Es, "function f(){} /42/")
);
}
@ -677,7 +671,7 @@ fn migrated_0004() {
// Div.span(13),
// 42.span(14..16),
// ],
// lex(Syntax::Es2019, "function (){} /42")
// lex(Syntax::Es, "function (){} /42")
// );
// }
@ -686,7 +680,7 @@ fn migrated_0006() {
// This test seems wrong.
// assert_eq!(
// vec![LBrace.span(0).lb(), RBrace.span(1), Div.span(3), 42.span(4..6)],
// lex(Syntax::Es2019, "{} /42")
// lex(Syntax::Es, "{} /42")
// )
assert_eq!(
@ -703,7 +697,7 @@ fn migrated_0006() {
)
.span(3..7),
],
lex(Syntax::Es2019, "{} /42/")
lex(Syntax::Es, "{} /42/")
)
}
@ -714,21 +708,21 @@ fn str_lit() {
value: "abcde".into(),
has_escape: false,
}],
lex_tokens(Syntax::Es2019, "'abcde'")
lex_tokens(Syntax::Es, "'abcde'")
);
assert_eq_ignore_span!(
vec![Token::Str {
value: "abc".into(),
has_escape: true,
}],
lex_tokens(Syntax::Es2019, "'\\\nabc'")
lex_tokens(Syntax::Es, "'\\\nabc'")
);
}
#[test]
fn tpl_empty() {
assert_eq!(
lex_tokens(Syntax::Es2019, r#"``"#),
lex_tokens(Syntax::Es, r#"``"#),
vec![
tok!('`'),
Template {
@ -744,7 +738,7 @@ fn tpl_empty() {
#[test]
fn tpl() {
assert_eq!(
lex_tokens(Syntax::Es2019, r#"`${a}`"#),
lex_tokens(Syntax::Es, r#"`${a}`"#),
vec![
tok!('`'),
Template {
@ -753,7 +747,7 @@ fn tpl() {
has_escape: false
},
tok!("${"),
Word(Ident("a".into())),
Word(Word::Ident("a".into())),
tok!('}'),
Template {
raw: "".into(),
@ -769,12 +763,12 @@ fn tpl() {
fn comment() {
assert_eq!(
lex(
Syntax::Es2019,
Syntax::Es,
"// foo
a"
),
vec![TokenAndSpan {
token: Word(Ident("a".into())),
token: Word(Word::Ident("a".into())),
span: sp(7..8),
// first line
had_line_break: true
@ -786,13 +780,13 @@ a"
fn comment_2() {
assert_eq!(
lex(
Syntax::Es2019,
Syntax::Es,
"// foo
// bar
a"
),
vec![TokenAndSpan {
token: Word(Ident("a".into())),
token: Word(Word::Ident("a".into())),
span: sp(14..15),
// first line
had_line_break: true
@ -875,7 +869,7 @@ fn lex_colors_js(b: &mut Bencher) {
b.bytes = include_str!("../../colors.js").len() as _;
b.iter(|| {
let _ = with_lexer(Syntax::Es2019, include_str!("../../colors.js"), |lexer| {
let _ = with_lexer(Syntax::Es, include_str!("../../colors.js"), |lexer| {
for _ in lexer {}
Ok(())
});

View File

@ -35,10 +35,7 @@
//! let handler =
//! Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone()));
//!
//! let session = Session {
//! handler: &handler,
//! cfg: Default::default(),
//! };
//! let session = Session { handler: &handler };
//!
//! // Real usage
//! // let fm = cm
@ -50,9 +47,15 @@
//! "function foo() {}".into(),
//! );
//!
//! let mut parser = Parser::new(session, Syntax::Es2019, SourceFileInput::from(&*fm));
//! let mut parser = Parser::new(session, Syntax::Es, SourceFileInput::from(&*fm));
//!
//! let _module = parser.parse_module().expect("failed to parser module");
//! let _module = parser
//! .parse_module()
//! .map_err(|e| {
//! e.emit();
//! ()
//! })
//! .expect("failed to parser module");
//! });
//! }
//! ```
@ -109,16 +112,24 @@ mod parser;
mod token;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(tag = "syntax")]
pub enum Syntax {
Es2019,
#[serde = "esnext"]
EsNext(EsNextConfig),
/// Standard
#[serde = "es"]
Es,
#[serde = "jsx"]
Jsx,
#[serde = "typescript"]
Typescript,
#[serde = "tsx"]
Tsx,
}
impl Default for Syntax{
fn default()->Self{
Syntax::Es2019
impl Default for Syntax {
fn default() -> Self {
Syntax::Es
}
}
@ -130,20 +141,107 @@ impl Syntax {
_ => false,
}
}
pub fn fn_bind(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig { fn_bind: true, .. }) => true,
_ => false,
}
}
pub fn num_sep(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig { num_sep: true, .. }) => true,
_ => false,
}
}
pub fn decorators(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig {
decorators: true, ..
})
| Syntax::Typescript
| Syntax::Tsx => true,
_ => false,
}
}
pub fn class_private_methods(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig {
class_private_methods: true,
..
}) => true,
_ => false,
}
}
pub fn class_private_props(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig {
class_private_props: true,
..
}) => true,
_ => false,
}
}
pub fn class_props(self) -> bool {
if self.typescript() {
return true;
}
match self {
Syntax::EsNext(EsNextConfig {
class_props: true, ..
}) => true,
_ => false,
}
}
pub fn decorators_before_export(self) -> bool {
match self {
Syntax::EsNext(EsNextConfig {
decorators_before_export: true,
..
}) => true,
_ => false,
}
}
/// Should we pare typescript?
pub fn typescript(self) -> bool {
match self {
Syntax::Typescript | Syntax::Tsx => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Config {
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct EsNextConfig {
/// Support numeric separator.
pub num_sep: bool,
pub class_private_props: bool,
pub class_private_methods: bool,
pub class_props: bool,
/// Support function bind expression.
pub fn_bind: bool,
/// Enable decorators.
pub decorators: bool,
/// babel: `decorators.decoratorsBeforeExport`
///
/// Effective only if `decorator` is true.
pub decorators_before_export: bool,
}
/// Syntatic context.
#[derive(Debug, Clone, Copy, Default)]
struct Context {
pub(crate) struct Context {
/// Is in module code?
module: bool,
strict: bool,
@ -155,16 +253,24 @@ struct Context {
/// keyword.
in_generator: bool,
in_type: bool,
/// Typescript extension.
in_declare: bool,
in_function: bool,
in_parameters: bool,
in_method: bool,
in_class_prop: bool,
in_property_name: bool,
in_forced_jsx_context: bool,
}
#[derive(Clone, Copy)]
pub struct Session<'a> {
pub cfg: Config,
pub handler: &'a Handler,
}
@ -175,15 +281,9 @@ where
{
use swc_common::FileName;
::testing::run_test(|cm, handler| {
::testing::run_test(true, |cm, handler| {
let fm = cm.new_source_file(FileName::Real("testing".into()), src.into());
f(
Session {
handler: &handler,
cfg: Default::default(),
},
(&*fm).into(),
)
f(Session { handler: &handler }, (&*fm).into())
})
}

View File

@ -1,226 +1,336 @@
macro_rules! tok {
('`') => {
Token::BackQuote
crate::token::Token::BackQuote
};
// (';') => { Token::Semi };
('@') => {
crate::token::Token::At
};
('#') => {
crate::token::Token::Hash
};
('&') => {
crate::token::Token::BinOp(crate::token::BinOpToken::BitAnd)
};
('+') => {
crate::token::Token::BinOp(crate::token::BinOpToken::Add)
};
('-') => {
crate::token::Token::BinOp(crate::token::BinOpToken::Sub)
};
('~') => {
crate::token::Token::Tilde
};
('!') => {
crate::token::Token::Bang
};
('|') => {
crate::token::Token::BinOp(crate::token::BinOpToken::BitOr)
};
(',') => {
Token::Comma
crate::token::Token::Comma
};
('?') => {
Token::QuestionMark
crate::token::Token::QuestionMark
};
(':') => {
Token::Colon
crate::token::Token::Colon
};
("::") => {
Token::ColonColon
crate::token::Token::ColonColon
};
('.') => {
Token::Dot
crate::token::Token::Dot
};
("=>") => {
Token::Arrow
crate::token::Token::Arrow
};
("...") => {
Token::DotDotDot
crate::token::Token::DotDotDot
};
("${") => {
Token::DollarLBrace
crate::token::Token::DollarLBrace
};
('+') => {
Token::BinOp(Add)
crate::token::Token::BinOp(crate::token::BinOpToken::Add)
};
('-') => {
Token::BinOp(Sub)
crate::token::Token::BinOp(crate::token::BinOpToken::Sub)
};
('*') => {
Token::BinOp(Mul)
crate::token::Token::BinOp(crate::token::BinOpToken::Mul)
};
('/') => {
Token::BinOp(Div)
crate::token::Token::BinOp(crate::token::BinOpToken::Div)
};
("/=") => {
Token::AssignOp(DivAssign)
crate::token::Token::AssignOp(DivAssign)
};
('%') => {
Token::BinOp(Mod)
};
('!') => {
Token::Bang
crate::token::Token::BinOp(Mod)
};
('~') => {
Token::Tilde
crate::token::Token::Tilde
};
('<') => {
Token::BinOp(Lt)
crate::token::Token::BinOp(crate::token::BinOpToken::Lt)
};
('>') => {
Token::BinOp(Gt)
crate::token::Token::BinOp(crate::token::BinOpToken::Gt)
};
("++") => {
Token::PlusPlus
crate::token::Token::PlusPlus
};
("--") => {
Token::MinusMinus
crate::token::Token::MinusMinus
};
('=') => {
Token::AssignOp(Assign)
crate::token::Token::AssignOp(crate::token::AssignOpToken::Assign)
};
('(') => {
Token::LParen
crate::token::Token::LParen
};
(')') => {
Token::RParen
crate::token::Token::RParen
};
('{') => {
Token::LBrace
crate::token::Token::LBrace
};
('}') => {
Token::RBrace
crate::token::Token::RBrace
};
('[') => {
Token::LBracket
crate::token::Token::LBracket
};
(']') => {
Token::RBracket
crate::token::Token::RBracket
};
("async") => {
Token::Word(Word::Ident(js_word!("async")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("async")))
};
("as") => {
Token::Word(Word::Ident(js_word!("as")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("as")))
};
("await") => {
Token::Word(Keyword(Await))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Await))
};
("break") => {
Token::Word(Keyword(Break))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Break))
};
("case") => {
Token::Word(Keyword(Case))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Case))
};
("catch") => {
Token::Word(Keyword(Catch))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Catch))
};
("class") => {
Token::Word(Keyword(Class))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Class))
};
("const") => {
Token::Word(Keyword(Const))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Const))
};
("continue") => {
Token::Word(Keyword(Continue))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Continue))
};
("debugger") => {
Token::Word(Keyword(Debugger))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Debugger))
};
("default") => {
Token::Word(Keyword(Default_))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Default_))
};
("delete") => {
Token::Word(Keyword(Delete))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Delete))
};
("do") => {
Token::Word(Keyword(Do))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Do))
};
("else") => {
Token::Word(Keyword(Else))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Else))
};
("export") => {
Token::Word(Keyword(Export))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Export))
};
("extends") => {
Token::Word(Keyword(Extends))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Extends))
};
("false") => {
Token::Word(False)
crate::token::Token::Word(crate::token::Word::False)
};
("finally") => {
Token::Word(Keyword(Finally))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Finally))
};
("for") => {
Token::Word(Keyword(For))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::For))
};
("from") => {
Token::Word(Word::Ident(js_word!("from")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("from")))
};
("function") => {
Token::Word(Keyword(Function))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Function))
};
("if") => {
Token::Word(Keyword(If))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::If))
};
("in") => {
Token::Word(Keyword(In))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::In))
};
("import") => {
Token::Word(Keyword(Import))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Import))
};
("let") => {
Token::Word(Keyword(Let))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Let))
};
("new") => {
Token::Word(Keyword(New))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::New))
};
("null") => {
Token::Word(Null)
crate::token::Token::Word(crate::token::Word::Null)
};
("of") => {
Token::Word(Ident(js_word!("of")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("of")))
};
("return") => {
Token::Word(Keyword(Return))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Return))
};
("super") => {
Token::Word(Keyword(Super))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Super))
};
("static") => {
Token::Word(Word::Ident(js_word!("static")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("static")))
};
("switch") => {
Token::Word(Keyword(Switch))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Switch))
};
("target") => {
Token::Word(Word::Ident(js_word!("target")))
crate::token::Token::Word(crate::token::Word::Ident(js_word!("target")))
};
("this") => {
Token::Word(Keyword(This))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::This))
};
("throw") => {
Token::Word(Keyword(Throw))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Throw))
};
("true") => {
Token::Word(True)
crate::token::Token::Word(crate::token::Word::True)
};
("try") => {
Token::Word(Keyword(Try))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Try))
};
("typeof") => {
Token::Word(Keyword(TypeOf))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::TypeOf))
};
("var") => {
Token::Word(Keyword(Var))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Var))
};
("void") => {
Token::Word(Keyword(Void))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Void))
};
("while") => {
Token::Word(Keyword(While))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::While))
};
("with") => {
Token::Word(Keyword(With))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::With))
};
("yield") => {
Token::Word(Keyword(Yield))
crate::token::Token::Word(crate::token::Word::Keyword(crate::token::Keyword::Yield))
};
// ----------
// JSX
// ----------
(JSXTagStart) => {
crate::token::Token::JSXTagStart
};
(JSXTagEnd) => {
Token::JSXTagEnd
crate::token::Token::JSXTagEnd
};
// ----------
// Typescript
// ----------
("implements") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("implements")))
};
("is") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("is")))
};
("new") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("new")))
};
("keyof") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("keyof")))
};
("unique") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("unique")))
};
("object") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("object")))
};
("global") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("global")))
};
("require") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("require")))
};
("enum") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("enum")))
};
("readonly") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("readonly")))
};
("as") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("as")))
};
("namespace") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("namespace")))
};
("abstract") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("abstract")))
};
("infer") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("infer")))
};
("any") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("any")))
};
("boolean") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("boolean")))
};
("bigint") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("bigint")))
};
("never") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("never")))
};
("number") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("number")))
};
("string") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("string")))
};
("symbol") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("symbol")))
};
("unknown") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("unknown")))
};
("require") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("require")))
};
("interface") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("interface")))
};
("declare") => {
crate::token::Token::Word(crate::token::Word::Ident(js_word!("declare")))
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
use super::{pat::PatType, util::ExprExt, *};
use crate::{lexer::TokenContext, token::AssignOpToken};
use either::Either;
use swc_common::Spanned;
use swc_common::{ast_node, Spanned};
mod ops;
#[cfg(test)]
@ -28,16 +29,71 @@ impl<'a, I: Input> Parser<'a, I> {
Ok(expr)
}
///`parseMaybeAssign` (overrided)
pub(super) fn parse_assignment_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
if self.input.syntax().typescript() {
// Note: When the JSX plugin is on, type assertions (`<T> x`) aren't valid
// syntax.
if is!(JSXTagStart) {
let cur_context = self.input.token_context().current();
assert_eq!(cur_context, Some(TokenContext::JSXOpeningTag));
// Only time j_oTag is pushed is right after j_expr.
assert_eq!(
self.input.token_context().0[self.input.token_context().len() - 2],
TokenContext::JSXExpr
);
let res = self.try_parse_ts(|p| p.parse_assignment_expr_base().map(Some));
if let Some(res) = res {
return Ok(res);
} else {
assert_eq!(
self.input.token_context().current(),
Some(TokenContext::JSXOpeningTag)
);
self.input.token_context_mut().pop();
assert_eq!(
self.input.token_context().current(),
Some(TokenContext::JSXExpr)
);
self.input.token_context_mut().pop();
}
}
}
let res = self.try_parse_ts(|p| {
let type_parameters = p.parse_ts_type_params()?;
let mut arrow = p.parse_assignment_expr_base()?;
match *arrow {
Expr::Arrow(ArrowExpr {
ref mut type_params,
..
}) => {
*type_params = Some(type_parameters);
}
_ => unexpected!(),
}
Ok(Some(arrow))
});
if let Some(res) = res {
return Ok(res);
}
self.parse_assignment_expr_base()
}
/// Parse an assignment expression. This includes applications of
/// operators like `+=`.
pub(super) fn parse_assignment_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
///
/// `parseMaybeAssign`
fn parse_assignment_expr_base(&mut self) -> PResult<'a, (Box<Expr>)> {
if self.ctx().in_generator && is!("yield") {
return self.parse_yield_expr();
}
// TODO: Check if cur!(true) correct.
self.state.potential_arrow_start = match *cur!(true)? {
Word(Ident(..)) | tok!('(') | tok!("yield") => Some(cur_pos!()),
Word(Word::Ident(..)) | tok!('(') | tok!("yield") => Some(cur_pos!()),
_ => None,
};
@ -56,8 +112,8 @@ impl<'a, I: Input> Parser<'a, I> {
}
match cur!(false) {
Ok(&AssignOp(op)) => {
let left = if op == Assign {
Ok(&Token::AssignOp(op)) => {
let left = if op == AssignOpToken::Assign {
self.reparse_expr_as_pat(PatType::AssignPat, cond)
.map(Box::new)
.map(PatOrExpr::Pat)?
@ -117,23 +173,33 @@ impl<'a, I: Input> Parser<'a, I> {
let can_be_arrow = self
.state
.potential_arrow_start
.map(|s| s == cur_pos!())
.map(|s| s == start)
.unwrap_or(false);
if eat!("this") {
return Ok(box Expr::This(ThisExpr { span: span!(start) }));
}
// Handle async function expression
if is!("async") {
if peeked_is!("function") && !self.input.has_linebreak_between_cur_and_peeked() {
// handle `async function` expression
return self.parse_async_fn_expr();
}
if can_be_arrow && self.input.syntax().typescript() && peeked_is!('<') {
// try parsing `async<T>() => {}`
if let Some(res) = self.try_parse_ts(|p| {
let start = cur_pos!();
assert_and_bump!("async");
p.try_parse_ts_generic_async_arrow_fn(start)
}) {
return Ok(box Expr::Arrow(res));
}
}
if can_be_arrow && peeked_is!('(') {
let start = cur_pos!();
expect!("async");
let async_span = span!(start);
let async_span = self.input.prev_span();
return self.parse_paren_expr_or_arrow_fn(can_be_arrow, Some(async_span));
}
}
@ -157,7 +223,11 @@ impl<'a, I: Input> Parser<'a, I> {
// Literals
if {
match *cur!(false)? {
tok!("null") | tok!("true") | tok!("false") | Num(..) | Token::Str { .. } => true,
tok!("null")
| tok!("true")
| tok!("false")
| Token::Num(..)
| Token::Str { .. } => true,
_ => false,
}
} {
@ -167,12 +237,12 @@ impl<'a, I: Input> Parser<'a, I> {
// Regexp
if {
match *cur!(false)? {
Regex(..) => true,
Token::Regex(..) => true,
_ => false,
}
} {
match bump!() {
Regex(exp, flags) => {
Token::Regex(exp, flags) => {
return Ok(box Expr::Lit(Lit::Regex(Regex {
span: span!(start),
exp,
@ -185,17 +255,16 @@ impl<'a, I: Input> Parser<'a, I> {
if is!('`') {
// parse template literal
return Ok(box Expr::Tpl(self.parse_tpl_lit(None)?));
return Ok(box Expr::Tpl(self.parse_tpl()?));
}
if is!('(') {
return self.parse_paren_expr_or_arrow_fn(can_be_arrow, None);
}
if is!("let") || is!(IdentRef) {
if is!("let") || (self.input.syntax().typescript() && is!(IdentName)) || is!(IdentRef) {
// TODO: Handle [Yield, Await]
let id = self.parse_ident_ref()?;
let id = self.parse_ident_name()?;
if can_be_arrow && id.sym == js_word!("async") && is!(BindingIdent) {
// async a => body
let arg = self.parse_binding_ident().map(Pat::from)?;
@ -208,6 +277,8 @@ impl<'a, I: Input> Parser<'a, I> {
params,
is_async: true,
is_generator: false,
return_type: None,
type_params: None,
}));
} else if can_be_arrow && !self.input.had_line_break_before_cur() && eat!("=>") {
let params = vec![id.into()];
@ -219,6 +290,10 @@ impl<'a, I: Input> Parser<'a, I> {
params,
is_async: false,
is_generator: false,
// TODO
return_type: None,
// TODO
type_params: None,
}));
} else {
return Ok(box Expr::Ident(id));
@ -269,14 +344,8 @@ impl<'a, I: Input> Parser<'a, I> {
let start_of_target = cur_pos!();
if eat!("target") {
return Ok(box Expr::MetaProp(MetaPropExpr {
meta: Ident {
span: span_of_new,
sym: js_word!("new"),
},
prop: Ident {
span: span!(start_of_target),
sym: js_word!("target"),
},
meta: Ident::new(js_word!("new"), span_of_new),
prop: Ident::new(js_word!("target"), span!(start_of_target)),
}));
}
@ -287,6 +356,18 @@ impl<'a, I: Input> Parser<'a, I> {
let callee = self.parse_member_expr_or_new_expr(is_new_expr)?;
return_if_arrow!(callee);
let type_args = if self.input.syntax().typescript() && is!('<') {
self.try_parse_ts(|p| {
let args = p.parse_ts_type_args()?;
if !is!('(') {
unexpected!()
}
Ok(Some(args))
})
} else {
None
};
if !is_new_expr || is!('(') {
// Parsed with 'MemberExpression' production.
let args = self.parse_args().map(Some)?;
@ -295,6 +376,7 @@ impl<'a, I: Input> Parser<'a, I> {
span: span!(start),
callee,
args,
type_args,
}));
// We should parse subscripts for MemberExpression.
@ -308,6 +390,7 @@ impl<'a, I: Input> Parser<'a, I> {
span: span!(start),
callee,
args: None,
type_args,
}));
}
@ -323,7 +406,7 @@ impl<'a, I: Input> Parser<'a, I> {
/// Parse `NewExpresion`.
/// This includes `MemberExpression`.
fn parse_new_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
pub(super) fn parse_new_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
self.parse_member_expr_or_new_expr(true)
}
@ -381,19 +464,33 @@ impl<'a, I: Input> Parser<'a, I> {
// But as all patterns of javascript is subset of
// expressions, we can parse both as expression.
let expr_or_spreads = self.include_in_expr(true).parse_args_or_pats()?;
let paren_items = self.include_in_expr(true).parse_args_or_pats()?;
let has_pattern = paren_items.iter().any(|item| match item {
PatOrExprOrSpread::Pat(..) => true,
_ => false,
});
let return_type = if self.input.syntax().typescript() && is!(':') {
let start = cur_pos!();
Some(self.parse_ts_type_or_type_predicate_ann(&tok!(':'))?)
} else {
None
};
// we parse arrow function at here, to handle it efficiently.
if is!("=>") {
if has_pattern || return_type.is_some() || is!("=>") {
if self.input.had_line_break_before_cur() {
syntax_error!(span!(start), SyntaxError::LineBreakBeforeArrow);
}
if !can_be_arrow {
unexpected!();
unexpected!()
}
assert_and_bump!("=>");
expect!("=>");
let params = self.parse_exprs_as_params(expr_or_spreads)?;
let params = self
.parse_paren_items_as_params(paren_items)?
.into_iter()
.collect();
let body: BlockStmtOrExpr = self.parse_fn_body(async_span.is_some(), false)?;
return Ok(box Expr::Arrow(ArrowExpr {
@ -402,14 +499,27 @@ impl<'a, I: Input> Parser<'a, I> {
is_generator: false,
params,
body,
return_type,
type_params: None,
}));
}
let expr_or_spreads = paren_items
.into_iter()
.map(|item| -> PResult<'a, _> {
match item {
PatOrExprOrSpread::ExprOrSpread(e) => Ok(e),
_ => syntax_error!(item.span(), SyntaxError::InvalidExpr),
}
})
.collect::<Result<Vec<_>, _>>()?;
if let Some(async_span) = async_span {
// It's a call expression
return Ok(box Expr::Call(CallExpr {
span: span!(start).with_lo(async_span.lo()),
span: span!(async_span.lo()),
callee: ExprOrSuper::Expr(box Expr::Ident(Ident::new("async".into(), async_span))),
args: expr_or_spreads,
type_args: None,
}));
}
@ -468,13 +578,10 @@ impl<'a, I: Input> Parser<'a, I> {
}
}
fn parse_tpl_lit(&mut self, tag: Option<(Box<Expr>)>) -> PResult<'a, TplLit> {
let start = cur_pos!();
assert_and_bump!('`');
let is_tagged = tag.is_some();
fn parse_tpl_elements(
&mut self,
is_tagged: bool,
) -> PResult<'a, (Vec<Box<Expr>>, Vec<TplElement>)> {
let mut exprs = vec![];
let cur_elem = self.parse_tpl_element(is_tagged)?;
@ -490,13 +597,45 @@ impl<'a, I: Input> Parser<'a, I> {
quasis.push(elem);
}
Ok((exprs, quasis))
}
fn parse_tagged_tpl(
&mut self,
tag: Box<Expr>,
type_params: Option<TsTypeParamInstantiation>,
) -> PResult<'a, TaggedTpl> {
let start = cur_pos!();
assert_and_bump!('`');
let (exprs, quasis) = self.parse_tpl_elements(false)?;
expect!('`');
let span = span!(start);
Ok(TplLit {
Ok(TaggedTpl {
span,
tag,
exprs,
type_params,
quasis,
})
}
fn parse_tpl(&mut self) -> PResult<'a, Tpl> {
let start = cur_pos!();
assert_and_bump!('`');
let (exprs, quasis) = self.parse_tpl_elements(false)?;
expect!('`');
let span = span!(start);
Ok(Tpl {
span,
exprs,
quasis,
})
}
@ -505,8 +644,8 @@ impl<'a, I: Input> Parser<'a, I> {
let start = cur_pos!();
let (raw, cooked) = match *cur!(true)? {
Template { .. } => match bump!() {
Template {
Token::Template { .. } => match bump!() {
Token::Template {
raw,
cooked,
has_escape,
@ -556,8 +695,92 @@ impl<'a, I: Input> Parser<'a, I> {
no_call: bool,
) -> PResult<'a, (Box<Expr>, bool)> {
let _ = cur!(false);
let start = cur_pos!();
if self.input.syntax().typescript() {
if !self.input.had_line_break_before_cur() && is!('!') {
self.input.set_expr_allowed(false);
assert_and_bump!('!');
let expr = match obj {
ExprOrSuper::Super(..) => unimplemented!("super!"),
ExprOrSuper::Expr(expr) => expr,
};
return Ok((
box Expr::TsNonNull(TsNonNullExpr {
span: span!(start),
expr,
}),
true,
));
}
// TODO(kdy1): Remove this.
let obj = obj.clone();
if {
match obj {
ExprOrSuper::Expr(..) => true,
// super() cannot be generic
_ => false,
}
} && is!('<')
{
// tsTryParseAndCatch is expensive, so avoid if not necessary.
// There are number of things we are going to "maybe" parse, like type arguments
// on tagged template expressions. If any of them fail, walk it back and
// continue.
let result = self.try_parse_ts(|p| {
if !no_call
&& p.at_possible_async(match obj {
ExprOrSuper::Expr(ref expr) => &*expr,
_ => unreachable!(),
})?
{
// Almost certainly this is a generic async function `async <T>() => ...
// But it might be a call with a type argument `async<T>();`
let async_arrow_fn = p.try_parse_ts_generic_async_arrow_fn(start)?;
if let Some(async_arrow_fn) = async_arrow_fn {
return Ok(Some((box Expr::Arrow(async_arrow_fn), true)));
}
}
let type_args = p.parse_ts_type_args()?;
if !no_call && is!('(') {
// possibleAsync always false here, because we would have handled it
// above. (won't be any undefined arguments)
let args = p.parse_args()?;
return Ok(Some((
box Expr::Call(CallExpr {
span: span!(start),
callee: obj,
type_args: Some(type_args),
args,
}),
true,
)));
} else if is!('`') {
return p
.parse_tagged_tpl(
match obj {
ExprOrSuper::Expr(obj) => obj,
_ => unreachable!(),
},
Some(type_args),
)
.map(|expr| (box Expr::TaggedTpl(expr), true))
.map(Some);
} else {
unexpected!()
}
});
if let Some(result) = result {
return Ok(result);
}
}
}
// member expression
// $obj.name
if eat!('.') {
@ -596,6 +819,7 @@ impl<'a, I: Input> Parser<'a, I> {
span: span!(start),
callee: obj,
args,
type_args: None,
}),
true,
));
@ -605,8 +829,8 @@ impl<'a, I: Input> Parser<'a, I> {
ExprOrSuper::Expr(expr) => {
// MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged]
if is!('`') {
let tpl = self.parse_tpl_lit(Some(expr))?;
return Ok((box Expr::Tpl(tpl), true));
let tpl = self.parse_tagged_tpl(expr, None)?;
return Ok((box Expr::TaggedTpl(tpl), true));
}
Ok((expr, false))
@ -650,7 +874,7 @@ impl<'a, I: Input> Parser<'a, I> {
// jsx as the lt sign is not allowed in places that expect an expression
// FIXME:
// this.finishToken(tt.jsxTagStart);
// self.finishToken(tt.jsxTagStart);
return self.parse_jsx_element().map(into_expr);
}
@ -665,16 +889,33 @@ impl<'a, I: Input> Parser<'a, I> {
let callee = self.parse_new_expr()?;
return_if_arrow!(callee);
let type_args = if self.input.syntax().typescript() && is!('<') {
self.try_parse_ts(|p| {
let type_args = p.parse_ts_type_args()?;
if is!('(') {
Ok(Some(type_args))
} else {
Ok(None)
}
})
} else {
None
};
match *callee {
// If this is parsed using 'NewExpression' rule, just return it.
// Because it's not left-recursive.
Expr::New(NewExpr { args: None, .. }) => {
Expr::New(ne @ NewExpr { args: None, .. }) => {
if type_args.is_some() {
// This fails with `expected (`
expect!('(');
}
assert_ne!(
cur!(false).ok(),
Some(&LParen),
Some(&tok!('(')),
"parse_new_expr() should eat paren if it exists"
);
return Ok(callee);
return Ok(box Expr::New(NewExpr { type_args, ..ne }));
}
_ => {}
}
@ -685,15 +926,21 @@ impl<'a, I: Input> Parser<'a, I> {
// This is parsed using production MemberExpression,
// which is left-recursive.
let args = self.parse_args()?;
let call_expr = box Expr::Call(CallExpr {
span: span!(start),
callee: ExprOrSuper::Expr(callee),
args,
type_args,
});
return self.parse_subscripts(ExprOrSuper::Expr(call_expr), false);
}
if type_args.is_some() {
// This fails
expect!('(');
}
// This is parsed using production 'NewExpression', which contains
// 'MemberExpression'
@ -703,11 +950,140 @@ impl<'a, I: Input> Parser<'a, I> {
pub(super) fn parse_expr_or_pat(&mut self) -> PResult<'a, (Box<Expr>)> {
self.parse_expr()
}
pub(super) fn parse_args_or_pats(&mut self) -> PResult<'a, (Vec<ExprOrSpread>)> {
self.parse_args()
pub(super) fn parse_args_or_pats(&mut self) -> PResult<'a, Vec<PatOrExprOrSpread>> {
expect!('(');
let mut first = true;
let mut items = vec![];
let mut rest_span = None;
// TODO(kdy1): optimize (once we parsed a pattern, we can parse everything else
// as a pattern instead of reparsing)
while !eof!() && !is!(')') {
if first {
first = false;
} else {
expect!(',');
// Handle trailing comma.
if is!(')') {
break;
}
}
let arg = {
if self.input.syntax().typescript()
&& (is!(IdentRef) || (is!("...") && peeked_is!(IdentRef)))
{
let spread = if eat!("...") {
Some(self.input.prev_span())
} else {
None
};
// At here, we use parse_bin_expr() instead of parse_assignment_expr()
// because `x?: number` should not be parsed as a conditional expression
let expr = if spread.is_some() {
self.include_in_expr(true).parse_bin_expr()?
} else {
self.parse_bin_expr()?
};
ExprOrSpread { spread, expr }
} else {
self.include_in_expr(true).parse_expr_or_spread()?
}
};
let optional = if self.input.syntax().typescript() {
if eat!('?') {
match arg {
ExprOrSpread {
expr: box Expr::Ident(..),
..
} => {}
_ => syntax_error!(arg.span(), SyntaxError::TsBindingPatCannotBeOptional),
}
true
} else {
false
}
} else {
false
};
if optional || (self.input.syntax().typescript() && is!(':')) {
let start = cur_pos!();
let mut pat = self.reparse_expr_as_pat(PatType::BindingPat, arg.expr)?;
if optional {
match pat {
Pat::Ident(ref mut i) => i.optional = true,
_ => unreachable!(),
}
}
if let Some(span) = arg.spread {
if let Some(rest_span) = rest_span {
// Rest pattern must be last one.
syntax_error!(rest_span, SyntaxError::NonLastRestParam);
}
rest_span = Some(span);
pat = Pat::Rest(RestPat {
dot3_token: span,
arg: box pat,
type_ann: None,
});
}
match pat {
Pat::Ident(Ident {
ref mut type_ann, ..
})
| Pat::Array(ArrayPat {
ref mut type_ann, ..
})
| Pat::Assign(AssignPat {
ref mut type_ann, ..
})
| Pat::Object(ObjectPat {
ref mut type_ann, ..
})
| Pat::Rest(RestPat {
ref mut type_ann, ..
}) => {
*type_ann = self
.parse_ts_type_ann(/* eat_colon */ true, start)
.map(Some)?
}
Pat::Expr(ref expr) => unreachable!("invalid pattern: Expr({:?})", expr),
}
if eat!('=') {
//TODO: is parse_expr correct?
let right = self.parse_expr()?;
pat = Pat::Assign(AssignPat {
span: span!(start),
left: box pat,
right,
type_ann: None,
});
}
items.push(PatOrExprOrSpread::Pat(pat))
} else {
items.push(PatOrExprOrSpread::ExprOrSpread(arg));
}
}
expect!(')');
Ok(items)
}
}
#[ast_node]
pub(in crate::parser) enum PatOrExprOrSpread {
Pat(Pat),
ExprOrSpread(ExprOrSpread),
}
/// simple leaf methods.
#[parser]
impl<'a, I: Input> Parser<'a, I> {
@ -743,17 +1119,30 @@ impl<'a, I: Input> Parser<'a, I> {
}
}
fn at_possible_async(&mut self, expr: &Expr) -> PResult<'a, bool> {
// TODO(kdy1): !this.state.containsEsc &&
Ok(self.state.potential_arrow_start == Some(expr.span().lo())
&& match *expr {
Expr::Ident(Ident {
sym: js_word!("async"),
..
}) => true,
_ => false,
})
}
/// 12.2.5 Array Initializer
fn parse_lit(&mut self) -> PResult<'a, Lit> {
pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
let start = cur_pos!();
let v = match *cur!(true)? {
Word(Null) => {
Word(Word::Null) => {
bump!();
let span = span!(start);
Lit::Null(Null { span })
}
Word(True) | Word(False) => {
Word(Word::True) | Word(Word::False) => {
let value = is!("true");
bump!();
let span = span!(start);
@ -768,8 +1157,8 @@ impl<'a, I: Input> Parser<'a, I> {
}),
_ => unreachable!(),
},
Num(..) => match bump!() {
Num(value) => Lit::Num(Number {
Token::Num(..) => match bump!() {
Token::Num(value) => Lit::Num(Number {
span: span!(start),
value,
}),

View File

@ -1,5 +1,6 @@
//! Parser for unary operations and binary operations.
use super::{util::ExprExt, *};
use crate::token::Keyword;
use swc_common::Spanned;
#[parser]
@ -17,11 +18,29 @@ impl<'a, I: Input> Parser<'a, I> {
/// `minPrec` provides context that allows the function to stop and
/// defer further parser to one of its callers when it encounters an
/// operator that has a lower precedence than the set it is parsing.
///
/// `parseExprOp`
fn parse_bin_op_recursively(
&mut self,
left: Box<Expr>,
min_prec: u8,
) -> PResult<'a, (Box<Expr>)> {
) -> PResult<'a, Box<Expr>> {
const PREC_OF_IN: u8 = 7;
if self.input.syntax().typescript() {
if PREC_OF_IN > min_prec && !self.input.had_line_break_before_cur() && is!("as") {
let span = span!(left.span().lo());
let expr = left;
let type_ann = self.next_then_parse_ts_type()?;
let node = box Expr::TsAs(TsAsExpr {
span,
expr,
type_ann,
});
return self.parse_bin_op_recursively(node, min_prec);
}
}
let op = match {
// Return left on eof
match cur!(false) {
@ -29,9 +48,9 @@ impl<'a, I: Input> Parser<'a, I> {
Err(..) => return Ok(left),
}
} {
&Word(Keyword(In)) if self.ctx().include_in_expr => op!("in"),
&Word(Keyword(InstanceOf)) => op!("instanceof"),
&BinOp(op) => op.into(),
&Word(Word::Keyword(Keyword::In)) if self.ctx().include_in_expr => op!("in"),
&Word(Word::Keyword(Keyword::InstanceOf)) => op!("instanceof"),
&Token::BinOp(op) => op.into(),
_ => {
return Ok(left);
}
@ -99,12 +118,16 @@ impl<'a, I: Input> Parser<'a, I> {
/// Parse unary expression and update expression.
///
/// spec: 'UnaryExpression'
fn parse_unary_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
pub(in crate::parser) fn parse_unary_expr(&mut self) -> PResult<'a, (Box<Expr>)> {
let start = cur_pos!();
if !self.input.syntax().jsx() && eat!('<') {
return self.parse_ts_type_assertion().map(Expr::from).map(Box::new);
}
// Parse update expression
if is!("++") || is!("--") {
let op = if bump!() == PlusPlus {
let op = if bump!() == tok!("++") {
op!("++")
} else {
op!("--")
@ -126,13 +149,13 @@ impl<'a, I: Input> Parser<'a, I> {
// Parse unary expression
if is_one_of!("delete", "void", "typeof", '+', '-', '~', '!') {
let op = match bump!() {
Word(Keyword(Delete)) => op!("delete"),
Word(Keyword(Void)) => op!("void"),
Word(Keyword(TypeOf)) => op!("typeof"),
BinOp(Add) => op!(unary, "+"),
BinOp(Sub) => op!(unary, "-"),
Tilde => op!("~"),
Bang => op!("!"),
tok!("delete") => op!("delete"),
tok!("void") => op!("void"),
tok!("typeof") => op!("typeof"),
tok!('+') => op!(unary, "+"),
tok!('-') => op!(unary, "-"),
tok!('~') => op!("~"),
tok!('!') => op!("!"),
_ => unreachable!(),
};
let arg = self.parse_unary_expr()?;
@ -163,7 +186,7 @@ impl<'a, I: Input> Parser<'a, I> {
}
let start = cur_pos!();
let op = if bump!() == PlusPlus {
let op = if bump!() == tok!("++") {
op!("++")
} else {
op!("--")
@ -200,15 +223,17 @@ impl<'a, I: Input> Parser<'a, I> {
#[cfg(test)]
mod tests {
use super::*;
use swc_common::DUMMY_SP;
use swc_common::DUMMY_SP as span;
fn bin(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| p.parse_bin_expr())
test_parser(s, Syntax::Es, |p| {
p.parse_bin_expr().map_err(|e| {
e.emit();
()
})
})
}
#[allow(non_upper_case_globals)]
const span: Span = DUMMY_SP;
#[test]
fn simple() {
assert_eq_ignore_span!(

View File

@ -2,23 +2,43 @@ use super::*;
use swc_common::DUMMY_SP as span;
fn lhs(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| p.parse_lhs_expr())
test_parser(s, Syntax::Es, |p| {
p.parse_lhs_expr().map_err(|e| {
e.emit();
()
})
})
}
fn new_expr(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| p.parse_new_expr())
test_parser(s, Syntax::Es, |p| {
p.parse_new_expr().map_err(|e| {
e.emit();
()
})
})
}
fn member_expr(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| p.parse_member_expr())
test_parser(s, Syntax::Es, |p| {
p.parse_member_expr().map_err(|e| {
e.emit();
()
})
})
}
fn expr(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| {
p.parse_stmt(true).map(|stmt| match stmt {
Stmt::Expr(expr) => expr,
_ => unreachable!(),
})
test_parser(s, Syntax::Es, |p| {
p.parse_stmt(true)
.map(|stmt| match stmt {
Stmt::Expr(expr) => expr,
_ => unreachable!(),
})
.map_err(|e| {
e.emit();
()
})
})
}
@ -28,13 +48,7 @@ fn arrow_assign() {
expr("a = b => false"),
box Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Pat(
box Ident {
span,
sym: "a".into(),
}
.into()
),
left: PatOrExpr::Pat(box Ident::new("a".into(), span).into()),
op: op!("="),
right: expr("b => false"),
})
@ -49,6 +63,7 @@ fn async_call() {
span,
callee: ExprOrSuper::Expr(expr("async")),
args: vec![],
type_args: None,
})
);
}
@ -63,6 +78,8 @@ fn async_arrow() {
is_generator: false,
params: vec![],
body: BlockStmtOrExpr::Expr(expr("foo")),
return_type: None,
type_params: None,
})
);
}
@ -79,14 +96,18 @@ fn object_rest_pat() {
span,
props: vec![ObjectPatProp::Rest(RestPat {
dot3_token: span,
arg: box Pat::Ident(Ident::new("a34".into(), span))
})]
arg: box Pat::Ident(Ident::new("a34".into(), span)),
type_ann: None,
})],
type_ann: None
})
.into()],
body: BlockStmtOrExpr::BlockStmt(BlockStmt {
span,
stmts: vec![]
})
}),
return_type: None,
type_params: None,
})
);
}
@ -97,38 +118,17 @@ fn object_spread() {
expr("foo = {a, ...bar, b}"),
box Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Pat(box Pat::Ident(
Ident {
span,
sym: "foo".into()
}
.into()
)),
left: PatOrExpr::Pat(box Pat::Ident(Ident::new("foo".into(), span))),
op: op!("="),
right: box Expr::Object(ObjectLit {
span,
props: vec![
PropOrSpread::Prop(
box Ident {
span,
sym: "a".into()
}
.into()
),
PropOrSpread::Prop(box Ident::new("a".into(), span).into()),
PropOrSpread::Spread(SpreadElement {
dot3_token: span,
expr: box Expr::Ident(Ident {
span,
sym: "bar".into(),
})
expr: box Expr::Ident(Ident::new("bar".into(), span))
}),
PropOrSpread::Prop(
box Ident {
span,
sym: "b".into()
}
.into()
),
PropOrSpread::Prop(box Ident::new("b".into(), span).into()),
]
})
})
@ -142,11 +142,7 @@ fn new_expr_should_not_eat_too_much() {
box Expr::Member(MemberExpr {
span,
obj: ExprOrSuper::Expr(member_expr("new Date()")),
prop: box Ident {
sym: "toString".into(),
span,
}
.into(),
prop: box Ident::new("toString".into(), span).into(),
computed: false,
})
);
@ -159,6 +155,7 @@ fn lhs_expr_as_new_expr_prod() {
span,
callee: lhs("Date.toString"),
args: Some(vec![]),
type_args: None,
})
);
}
@ -171,6 +168,7 @@ fn lhs_expr_as_call() {
span,
callee: ExprOrSuper::Expr(lhs("new Date.toString()")),
args: vec![],
type_args: None,
})
)
}
@ -185,6 +183,8 @@ fn arrow_fn_no_args() {
is_generator: false,
params: vec![],
body: BlockStmtOrExpr::Expr(expr("1")),
return_type: None,
type_params: None,
})
);
}
@ -196,11 +196,10 @@ fn arrow_fn() {
span,
is_async: false,
is_generator: false,
params: vec![Pat::Ident(Ident {
span,
sym: "a".into(),
})],
params: vec![Pat::Ident(Ident::new("a".into(), span)).into()],
body: BlockStmtOrExpr::Expr(expr("1")),
return_type: None,
type_params: None,
})
);
}
@ -214,12 +213,13 @@ fn arrow_fn_rest() {
is_generator: false,
params: vec![Pat::Rest(RestPat {
dot3_token: span,
arg: box Pat::Ident(Ident {
span,
sym: "a".into(),
}),
})],
arg: box Pat::Ident(Ident::new("a".into(), span)),
type_ann: None
})
.into()],
body: BlockStmtOrExpr::Expr(expr("1")),
return_type: None,
type_params: None,
})
);
}
@ -231,11 +231,10 @@ fn arrow_fn_no_paren() {
span,
is_async: false,
is_generator: false,
params: vec![Pat::Ident(Ident {
span,
sym: "a".into(),
})],
params: vec![Pat::Ident(Ident::new("a".into(), span)).into()],
body: BlockStmtOrExpr::Expr(expr("1")),
type_params: None,
return_type: None,
})
);
}
@ -248,6 +247,7 @@ fn new_no_paren() {
span,
callee: expr("a"),
args: None,
type_args: None,
})
);
}
@ -260,6 +260,7 @@ fn new_new_no_paren() {
span,
callee: expr("new a"),
args: None,
type_args: None,
})
);
}

View File

@ -1,9 +1,37 @@
//! 12.1 Identifiers
use super::*;
use crate::token::Keyword;
use either::Either;
#[parser]
impl<'a, I: Input> Parser<'a, I> {
pub(super) fn parse_maybe_private_name(&mut self) -> PResult<'a, Either<PrivateName, Ident>> {
let start = cur_pos!();
let is_private = is!('#');
if is_private {
self.parse_private_name().map(Either::Left)
} else {
self.parse_ident_name().map(Either::Right)
}
}
pub(super) fn parse_private_name(&mut self) -> PResult<'a, PrivateName> {
let start = cur_pos!();
assert_and_bump!('#');
let hash_end = self.input.prev_span().hi();
if self.input.cur_pos() - hash_end != BytePos(0) {
syntax_error!(span!(start), SyntaxError::SpaceBetweenHashAndIdent);
}
let id = self.parse_ident(true, true)?;
Ok(PrivateName {
span: span!(start),
id,
})
}
/// IdentifierReference
pub(super) fn parse_ident_ref(&mut self) -> PResult<'a, Ident> {
let ctx = self.ctx();
@ -55,18 +83,18 @@ impl<'a, I: Input> Parser<'a, I> {
// StringValue of IdentifierName is: "implements", "interface", "let",
// "package", "private", "protected", "public", "static", or "yield".
match w {
Ident(js_word!("enum")) => {
Word::Ident(js_word!("enum")) => {
syntax_error!(p.input.prev_span(), SyntaxError::InvalidIdentInStrict)
}
Keyword(Yield)
| Ident(js_word!("static"))
| Ident(js_word!("implements"))
| Ident(js_word!("interface"))
| Ident(js_word!("let"))
| Ident(js_word!("package"))
| Ident(js_word!("private"))
| Ident(js_word!("protected"))
| Ident(js_word!("public"))
Word::Keyword(Keyword::Yield)
| Word::Ident(js_word!("static"))
| Word::Ident(js_word!("implements"))
| Word::Ident(js_word!("interface"))
| Word::Ident(js_word!("let"))
| Word::Ident(js_word!("package"))
| Word::Ident(js_word!("private"))
| Word::Ident(js_word!("protected"))
| Word::Ident(js_word!("public"))
if strict =>
{
syntax_error!(p.input.prev_span(), SyntaxError::InvalidIdentInStrict)
@ -82,14 +110,17 @@ impl<'a, I: Input> Parser<'a, I> {
match w {
// It is a Syntax Error if the goal symbol of the syntactic grammar is Module
// and the StringValue of IdentifierName is "await".
Keyword(Await) if p.ctx().module => {
Word::Keyword(Keyword::Await) if p.ctx().module => {
syntax_error!(p.input.prev_span(), SyntaxError::ExpectedIdent)
}
Keyword(Let) => Ok(w.into()),
Ident(ident) => Ok(ident),
Keyword(Yield) if incl_yield => Ok(js_word!("yield")),
Keyword(Await) if incl_await => Ok(js_word!("await")),
Keyword(..) | Null | True | False => {
Word::Keyword(Keyword::This) if p.input.syntax().typescript() => {
Ok(js_word!("this"))
}
Word::Keyword(Keyword::Let) => Ok(js_word!("let")),
Word::Ident(ident) => Ok(ident),
Word::Keyword(Keyword::Yield) if incl_yield => Ok(js_word!("yield")),
Word::Keyword(Keyword::Await) if incl_await => Ok(js_word!("await")),
Word::Keyword(..) | Word::Null | Word::True | Word::False => {
syntax_error!(p.input.prev_span(), SyntaxError::ExpectedIdent)
}
}

View File

@ -1,11 +1,12 @@
use crate::{
lexer::{Input, Lexer},
lexer::{self, Input, Lexer},
token::*,
Context, Syntax,
};
use swc_common::{BytePos, Span, DUMMY_SP};
/// This struct is responsible for managing current token and peeked token.
#[derive(Clone)]
pub(super) struct ParserInput<'a, I: Input> {
iter: Lexer<'a, I>,
/// Span of the previous token.
@ -127,7 +128,7 @@ impl<'a, I: Input> ParserInput<'a, I> {
}
pub fn eat_keyword(&mut self, kwd: Keyword) -> bool {
self.eat(&Word(Keyword(kwd)))
self.eat(&Word(Word::Keyword(kwd)))
}
/// Returns start of current token.
@ -170,4 +171,18 @@ impl<'a, I: Input> ParserInput<'a, I> {
pub const fn syntax(&self) -> Syntax {
self.iter.syntax
}
pub fn set_expr_allowed(&mut self, allow: bool) {
self.iter.set_expr_allowed(allow)
}
pub(crate) const fn token_context(&self) -> &lexer::TokenContexts {
self.iter.token_context()
}
pub fn token_context_mut(&mut self) -> &mut lexer::TokenContexts {
self.iter.token_context_mut()
}
pub(crate) fn set_token_context(&mut self, c: lexer::TokenContexts) {
self.iter.set_token_context(c)
}
}

View File

@ -175,14 +175,20 @@ impl<'a, I: Input> Parser<'a, I> {
.map(Either::Right)
}
/// `jsxParseOpeningElementAfterName`
pub(super) fn parse_jsx_opening_element_after_name(
&mut self,
name: JSXElementName,
) -> PResult<'a, JSXOpeningElement> {
debug_assert!(self.input.syntax().jsx());
let start = name.span().lo();
let type_args = if self.input.syntax().typescript() {
self.try_parse_ts(|p| p.parse_ts_type_args().map(Some))
} else {
None
};
let mut attrs = vec![];
while let Ok(..) = cur!(false) {
if is!('/') || is!(JSXTagEnd) {
@ -201,6 +207,7 @@ impl<'a, I: Input> Parser<'a, I> {
name,
attrs,
self_closing,
type_args,
})
}

View File

@ -3,7 +3,12 @@ use crate::parser::test_parser;
use swc_common::DUMMY_SP as span;
fn jsx(src: &'static str) -> Box<Expr> {
test_parser(src, Syntax::Jsx, |p| p.parse_expr())
test_parser(src, Syntax::Jsx, |p| {
p.parse_expr().map_err(|e| {
e.emit();
()
})
})
}
#[test]
@ -16,7 +21,8 @@ fn self_closing_01() {
span,
name: JSXElementName::Ident(Ident::new("a".into(), span)),
self_closing: true,
attrs: vec![]
attrs: vec![],
type_args: None,
},
children: vec![],
closing: None,
@ -34,7 +40,8 @@ fn normal_01() {
span,
name: JSXElementName::Ident(Ident::new("a".into(), span)),
self_closing: false,
attrs: vec![]
attrs: vec![],
type_args: None,
},
children: vec![JSXElementChild::JSXText(JSXText {
span,
@ -68,6 +75,7 @@ fn escape_in_attr() {
})],
name: JSXElementName::Ident(Ident::new("div".into(), span)),
self_closing: true,
type_args: None,
},
children: vec![],
closing: None

View File

@ -9,7 +9,7 @@ macro_rules! unexpected {
///
/// Returns bool.
macro_rules! is {
($p:expr,BindingIdent) => {{
($p:expr, BindingIdent) => {{
let ctx = $p.ctx();
match cur!($p, false) {
Ok(&Word(ref w)) => !ctx.is_reserved_word(&w.clone().into()),
@ -17,7 +17,7 @@ macro_rules! is {
}
}};
($p:expr,IdentRef) => {{
($p:expr, IdentRef) => {{
let ctx = $p.ctx();
match cur!($p, false) {
Ok(&Word(ref w)) => !ctx.is_reserved_word(&w.clone().into()),
@ -44,6 +44,39 @@ macro_rules! is {
};
}
macro_rules! peeked_is {
($p:expr, BindingIdent) => {{
let ctx = $p.ctx();
match peek!($p) {
Ok(&Word(ref w)) => !ctx.is_reserved_word(&w.clone().into()),
_ => false,
}
}};
($p:expr, IdentRef) => {{
let ctx = $p.ctx();
match peek!($p) {
Ok(&Word(ref w)) => !ctx.is_reserved_word(&w.clone().into()),
_ => false,
}
}};
($p:expr,IdentName) => {{
match peek!($p) {
Ok(&Word(..)) => true,
_ => false,
}
}};
($p:expr, ';') => {{
compile_error!("peeked_is!(';') is invalid");
}};
($p:expr, $t:tt) => {
$p.input.peeked_is(&tok!($t))
};
}
/// Returns true on eof.
macro_rules! eof {
($p:expr) => {
@ -51,12 +84,6 @@ macro_rules! eof {
};
}
macro_rules! peeked_is {
($p:expr, $t:tt) => {
$p.input.peeked_is(&tok!($t))
};
}
macro_rules! is_one_of {
($p:expr, $($t:tt),+) => {{
false
@ -86,7 +113,7 @@ macro_rules! assert_and_bump {
/// Returns bool if token is static, and Option<Token>
/// if token has data like string.
macro_rules! eat {
($p:expr,';') => {{
($p:expr, ';') => {{
trace!("eat(';'): cur={:?}", cur!($p, true));
$p.input.eat(&Token::Semi)
|| eof!($p)
@ -95,7 +122,6 @@ macro_rules! eat {
}};
($p:expr, $t:tt) => {{
const TOKEN: &Token = &tok!($t);
if is!($p, $t) {
bump!($p);
true
@ -150,13 +176,13 @@ macro_rules! cur {
if is_err_token {
match $p.input.bump() {
$crate::token::Token::Error(e) => {
::swc_common::errors::DiagnosticBuilder::from($crate::error::ErrorToDiag {
handler: &$p.session.handler,
span: e.span,
error: e.error,
})
.emit();
let err: Result<!, _> = Err(());
let err =
::swc_common::errors::DiagnosticBuilder::from($crate::error::ErrorToDiag {
handler: &$p.session.handler,
span: e.span,
error: e.error,
});
let err: Result<!, _> = Err(err);
err?
}
_ => unreachable!(),
@ -167,13 +193,17 @@ macro_rules! cur {
Some(c) => Ok(c),
None => {
if $required {
::swc_common::errors::DiagnosticBuilder::from($crate::error::Eof {
let err = ::swc_common::errors::DiagnosticBuilder::from($crate::error::Eof {
last,
handler: &$p.session.handler,
})
.emit();
});
let err: Result<!, _> = Err(err);
err?
}
Err(())
Err($crate::error::Eof {
last,
handler: &$p.session.handler,
})
}
}
}};
@ -193,13 +223,12 @@ Current token is {:?}",
match $p.input.peek() {
Some(c) => Ok(c),
None => {
::swc_common::errors::DiagnosticBuilder::from($crate::error::Eof {
let err = ::swc_common::errors::DiagnosticBuilder::from($crate::error::Eof {
//TODO: Use whole span
last,
handler: &$p.session.handler,
})
.emit();
Err(())
});
Err(err)
}
}
}};
@ -269,13 +298,12 @@ macro_rules! syntax_error {
};
($p:expr, $span:expr, $err:expr) => {{
::swc_common::errors::DiagnosticBuilder::from($crate::error::ErrorToDiag {
let err = ::swc_common::errors::DiagnosticBuilder::from($crate::error::ErrorToDiag {
handler: $p.session.handler,
span: $span,
error: $err,
})
.emit();
let res: Result<!, _> = Err(());
res?
});
let err: Result<!, _> = Err(err);
err?
}};
}

View File

@ -5,13 +5,13 @@ use crate::{
error::SyntaxError,
lexer::{Input, Lexer},
parser_macros::parser,
token::*,
token::{Token, Word},
Context, Session, Syntax,
};
use ast::*;
use std::ops::{Deref, DerefMut};
use swc_atoms::JsWord;
use swc_common::{BytePos, Span};
use swc_common::{errors::DiagnosticBuilder, BytePos, Span};
#[macro_use]
mod macros;
@ -23,19 +23,21 @@ mod jsx;
mod object;
mod pat;
mod stmt;
mod typescript;
mod util;
/// When error ocurred, error is emiited and parser returnes Err(()).
pub type PResult<'a, T> = Result<T, ()>;
pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
/// EcmaScript parser.
#[derive(Clone)]
pub struct Parser<'a, I: Input> {
session: Session<'a>,
state: State,
input: ParserInput<'a, I>,
}
#[derive(Debug, Default)]
#[derive(Debug, Clone, Default)]
struct State {
labels: Vec<JsWord>,
/// Start position of an assignment expression.
@ -92,14 +94,3 @@ where
crate::with_test_sess(s, |sess, input| f(&mut Parser::new(sess, syntax, input)))
.unwrap_or_else(|output| panic!("test_parser(): failed to parse \n{}\n{}", s, output))
}
#[test]
fn module_legacy() {
test_parser("<!--", Syntax::Es2019, |f| {
let res = f.parse_module();
assert!(f.ctx().module);
assert!(f.ctx().strict);
let _ = res.expect_err("!");
Ok(())
});
}

View File

@ -35,44 +35,48 @@ impl<'a, I: Input> Parser<'a, I> {
/// spec: 'PropertyName'
pub(super) fn parse_prop_name(&mut self) -> PResult<'a, PropName> {
let start = cur_pos!();
let ctx = self.ctx();
self.with_ctx(Context {
in_property_name: true,
..ctx
})
.parse_with(|p| {
let start = cur_pos!();
let v = match *cur!(true)? {
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => PropName::Str(Str {
span: span!(start),
value,
has_escape,
}),
_ => unreachable!(),
},
Num(_) => match bump!() {
Num(value) => PropName::Num(Number {
span: span!(start),
value,
}),
_ => unreachable!(),
},
Word(..) => match bump!() {
Word(w) => PropName::Ident(Ident {
span: span!(start),
sym: w.into(),
}),
_ => unreachable!(),
},
LBracket => {
bump!();
let expr = self
.include_in_expr(true)
.parse_assignment_expr()
.map(PropName::Computed)?;
expect!(']');
expr
}
_ => unexpected!(),
};
let v = match *cur!(true)? {
Token::Str { .. } => match bump!() {
Token::Str { value, has_escape } => PropName::Str(Str {
span: span!(start),
value,
has_escape,
}),
_ => unreachable!(),
},
Token::Num(_) => match bump!() {
Token::Num(value) => PropName::Num(Number {
span: span!(start),
value,
}),
_ => unreachable!(),
},
Word(..) => match bump!() {
Word(w) => PropName::Ident(Ident::new(w.into(), span!(start))),
_ => unreachable!(),
},
tok!('[') => {
bump!();
let expr = p
.include_in_expr(true)
.parse_assignment_expr()
.map(PropName::Computed)?;
expect!(']');
expr
}
_ => unexpected!(),
};
Ok(v)
Ok(v)
})
}
}
@ -103,7 +107,14 @@ impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
let name = self.parse_prop_name()?;
return self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, false, true)
.parse_fn_args_body(
// no decorator in an object literal
vec![],
start,
Parser::parse_unique_formal_params,
false,
true,
)
.map(|function| {
PropOrSpread::Prop(box Prop::Method(MethodProp {
key: name,
@ -127,9 +138,16 @@ impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
}
// Handle `a(){}` (and async(){} / get(){} / set(){})
if is!('(') {
if (self.input.syntax().typescript() && is!('<')) || is!('(') {
return self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, false, false)
.parse_fn_args_body(
// no decorator in an object literal
vec![],
start,
Parser::parse_unique_formal_params,
false,
false,
)
.map(|function| box Prop::Method(MethodProp { key, function }))
.map(PropOrSpread::Prop);
}
@ -167,7 +185,14 @@ impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
return match ident.sym {
js_word!("get") => self
.parse_fn_args_body(start, |_| Ok(vec![]), false, false)
.parse_fn_args_body(
// no decorator in an object literal
vec![],
start,
|_| Ok(vec![]),
false,
false,
)
.map(|Function { body, .. }| {
PropOrSpread::Prop(box Prop::Getter(GetterProp {
span: span!(start),
@ -177,6 +202,8 @@ impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
}),
js_word!("set") => self
.parse_fn_args_body(
// no decorator in an object literal
vec![],
start,
|p| p.parse_formal_param().map(|pat| vec![pat]),
false,
@ -192,7 +219,14 @@ impl<'a, I: Input> ParseObject<'a, (Box<Expr>)> for Parser<'a, I> {
}))
}),
js_word!("async") => self
.parse_fn_args_body(start, Parser::parse_unique_formal_params, true, false)
.parse_fn_args_body(
// no decorator in an object literal
vec![],
start,
Parser::parse_unique_formal_params,
true,
false,
)
.map(|function| {
PropOrSpread::Prop(box Prop::Method(MethodProp { key, function }))
}),
@ -209,7 +243,11 @@ impl<'a, I: Input> ParseObject<'a, Pat> for Parser<'a, I> {
type Prop = ObjectPatProp;
fn make_object(span: Span, props: Vec<Self::Prop>) -> Pat {
Pat::Object(ObjectPat { span, props })
Pat::Object(ObjectPat {
span,
props,
type_ann: None,
})
}
/// Production 'BindingProperty'
@ -222,7 +260,11 @@ impl<'a, I: Input> ParseObject<'a, Pat> for Parser<'a, I> {
let arg = box self.parse_binding_pat_or_ident()?;
return Ok(ObjectPatProp::Rest(RestPat { dot3_token, arg }));
return Ok(ObjectPatProp::Rest(RestPat {
dot3_token,
arg,
type_ann: None,
}));
}
let key = self.parse_prop_name()?;

View File

@ -1,12 +1,13 @@
//! 13.3.3 Destructuring Binding Patterns
use super::{util::ExprExt, *};
use crate::{parser::expr::PatOrExprOrSpread, token::AssignOpToken};
use std::iter;
use swc_common::Spanned;
#[parser]
impl<'a, I: Input> Parser<'a, I> {
pub(super) fn parse_opt_binding_ident(&mut self) -> PResult<'a, (Option<Ident>)> {
if is!(BindingIdent) {
if is!(BindingIdent) || (self.input.syntax().typescript() && is!("this")) {
self.parse_binding_ident().map(Some)
} else {
Ok(None)
@ -60,6 +61,7 @@ impl<'a, I: Input> Parser<'a, I> {
span: span!(start),
left: box left,
right,
type_ann: None,
}));
}
@ -94,6 +96,7 @@ impl<'a, I: Input> Parser<'a, I> {
let pat = Pat::Rest(RestPat {
dot3_token,
arg: box pat,
type_ann: None,
});
elems.push(Some(pat));
// Trailing comma isn't allowed
@ -108,17 +111,67 @@ impl<'a, I: Input> Parser<'a, I> {
Ok(Pat::Array(ArrayPat {
span: span!(start),
elems,
type_ann: None,
}))
}
/// spec: 'FormalParameter'
///
/// babel: `parseAssignableListItem`
pub(super) fn parse_formal_param(&mut self) -> PResult<'a, Pat> {
self.parse_binding_element()
let start = cur_pos!();
let mut pat = self.parse_binding_element()?;
if self.input.syntax().typescript() {
if eat!('?') {
match pat {
Pat::Ident(Ident {
ref mut optional, ..
}) => {
*optional = true;
}
_ => syntax_error!(
self.input.prev_span(),
SyntaxError::TsBindingPatCannotBeOptional
),
}
}
match pat {
Pat::Array(ArrayPat {
ref mut type_ann, ..
})
| Pat::Assign(AssignPat {
ref mut type_ann, ..
})
| Pat::Ident(Ident {
ref mut type_ann, ..
})
| Pat::Object(ObjectPat {
ref mut type_ann, ..
})
| Pat::Rest(RestPat {
ref mut type_ann, ..
}) => {
*type_ann = self.try_parse_ts_type_ann()?;
}
Pat::Expr(expr) => unreachable!("invalid syntax: Pat(expr): {:?}", expr),
}
}
if eat!('=') {
let right = self.parse_expr()?;
Ok(Pat::Assign(AssignPat {
span: span!(start),
left: box pat,
type_ann: None,
right,
}))
} else {
Ok(pat)
}
}
///
/// spec: 'FormalParameterList'
pub(super) fn parse_formal_params(&mut self) -> PResult<'a, (Vec<Pat>)> {
pub(super) fn parse_constructor_params(&mut self) -> PResult<'a, Vec<PatOrTsParamProp>> {
let mut first = true;
let mut params = vec![];
@ -139,22 +192,101 @@ impl<'a, I: Input> Parser<'a, I> {
let dot3_token = span!(start);
let pat = self.parse_binding_pat_or_ident()?;
let type_ann = if self.input.syntax().typescript() && is!(':') {
let cur_pos = cur_pos!();
Some(self.parse_ts_type_ann(/* eat_colon */ true, cur_pos)?)
} else {
None
};
let pat = Pat::Rest(RestPat {
dot3_token,
arg: box pat,
type_ann,
});
params.push(pat);
params.push(PatOrTsParamProp::Pat(pat));
break;
} else {
params.push(self.parse_binding_element()?);
params.push(self.parse_constructor_param()?);
}
}
Ok(params)
}
pub(super) fn parse_unique_formal_params(&mut self) -> PResult<'a, (Vec<Pat>)> {
// FIXME: This is wrong.
fn parse_constructor_param(&mut self) -> PResult<'a, PatOrTsParamProp> {
let start = cur_pos!();
let (accessibility, readonly) = if self.input.syntax().typescript() {
let accessibility = self.parse_access_modifier()?;
(
accessibility,
self.parse_ts_modifier(&["readonly"])?.is_some(),
)
} else {
(None, false)
};
if accessibility == None && readonly == false {
self.parse_formal_param().map(PatOrTsParamProp::from)
} else {
Ok(PatOrTsParamProp::TsParamProp(TsParamProp {
span: span!(start),
accessibility,
readonly,
decorators: vec![],
param: match self.parse_formal_param()? {
Pat::Ident(i) => TsParamPropParam::Ident(i),
Pat::Assign(a) => TsParamPropParam::Assign(a),
node => syntax_error!(node.span(), SyntaxError::TsInvalidParamPropPat),
},
}))
}
}
pub(super) fn parse_formal_params(&mut self) -> PResult<'a, Vec<Pat>> {
let mut first = true;
let mut params = vec![];
while !eof!() && !is!(')') {
if first {
first = false;
} else {
expect!(',');
// Handle trailing comma.
if is!(')') {
break;
}
}
let start = cur_pos!();
if eat!("...") {
let dot3_token = span!(start);
let pat = self.parse_binding_pat_or_ident()?;
let type_ann = if self.input.syntax().typescript() && is!(':') {
let cur_pos = cur_pos!();
Some(self.parse_ts_type_ann(/* eat_colon */ true, cur_pos)?)
} else {
None
};
let pat = Pat::Rest(RestPat {
dot3_token,
arg: box pat,
type_ann,
});
params.push(pat);
break;
} else {
params.push(self.parse_formal_param()?);
}
}
Ok(params)
}
pub(super) fn parse_unique_formal_params(&mut self) -> PResult<'a, Vec<Pat>> {
// FIXME: This is wrong
self.parse_formal_params()
}
}
@ -258,7 +390,12 @@ impl<'a, I: Input> Parser<'a, I> {
match *expr {
Expr::Paren(inner) => syntax_error!(span, SyntaxError::InvalidPat),
Expr::Assign(assign_expr @ AssignExpr { op: Assign, .. }) => {
Expr::Assign(
assign_expr @ AssignExpr {
op: AssignOpToken::Assign,
..
},
) => {
let AssignExpr {
span, left, right, ..
} = assign_expr;
@ -269,6 +406,7 @@ impl<'a, I: Input> Parser<'a, I> {
PatOrExpr::Pat(left) => left,
},
right,
type_ann: None,
}));
}
Expr::Object(ObjectLit { span, props }) => {
@ -307,6 +445,7 @@ impl<'a, I: Input> Parser<'a, I> {
// FIXME: is BindingPat correct?
arg: box self
.reparse_expr_as_pat(PatType::BindingPat, expr)?,
type_ann: None,
}))
}
@ -314,6 +453,7 @@ impl<'a, I: Input> Parser<'a, I> {
}
})
.collect::<(PResult<'a, _>)>()?,
type_ann: None,
}));
}
Expr::Ident(ident) => return Ok(ident.into()),
@ -324,6 +464,7 @@ impl<'a, I: Input> Parser<'a, I> {
return Ok(Pat::Array(ArrayPat {
span,
elems: vec![],
type_ann: None,
}));
}
@ -370,6 +511,7 @@ impl<'a, I: Input> Parser<'a, I> {
Pat::Rest(RestPat {
dot3_token,
arg: box pat,
type_ann: None,
})
})
.map(Some)?
@ -386,6 +528,7 @@ impl<'a, I: Input> Parser<'a, I> {
return Ok(Pat::Array(ArrayPat {
span,
elems: params,
type_ann: None,
}));
}
@ -411,10 +554,10 @@ impl<'a, I: Input> Parser<'a, I> {
}
}
pub(super) fn parse_exprs_as_params(
pub(super) fn parse_paren_items_as_params(
&mut self,
mut exprs: Vec<ExprOrSpread>,
) -> PResult<'a, (Vec<Pat>)> {
mut exprs: Vec<PatOrExprOrSpread>,
) -> PResult<'a, Vec<Pat>> {
let pat_ty = PatType::BindingPat;
let len = exprs.len();
@ -426,10 +569,16 @@ impl<'a, I: Input> Parser<'a, I> {
for expr in exprs.drain(..len - 1) {
match expr {
ExprOrSpread {
PatOrExprOrSpread::ExprOrSpread(ExprOrSpread {
spread: Some(..), ..
} => syntax_error!(expr.span(), SyntaxError::NonLastRestParam),
ExprOrSpread { expr, .. } => params.push(self.reparse_expr_as_pat(pat_ty, expr)?),
})
| PatOrExprOrSpread::Pat(Pat::Rest(..)) => {
syntax_error!(expr.span(), SyntaxError::NonLastRestParam)
}
PatOrExprOrSpread::ExprOrSpread(ExprOrSpread {
spread: None, expr, ..
}) => params.push(self.reparse_expr_as_pat(pat_ty, expr)?),
PatOrExprOrSpread::Pat(pat) => params.push(pat),
}
}
@ -437,16 +586,20 @@ impl<'a, I: Input> Parser<'a, I> {
let expr = exprs.into_iter().next().unwrap();
let last = match expr {
// Rest
ExprOrSpread {
PatOrExprOrSpread::ExprOrSpread(ExprOrSpread {
spread: Some(dot3_token),
expr,
} => self.reparse_expr_as_pat(pat_ty, expr).map(|pat| {
}) => self.reparse_expr_as_pat(pat_ty, expr).map(|pat| {
Pat::Rest(RestPat {
dot3_token,
arg: box pat,
type_ann: None,
})
})?,
ExprOrSpread { expr, .. } => self.reparse_expr_as_pat(pat_ty, expr)?,
PatOrExprOrSpread::ExprOrSpread(ExprOrSpread { expr, .. }) => {
self.reparse_expr_as_pat(pat_ty, expr)?
}
PatOrExprOrSpread::Pat(pat) => pat,
};
params.push(last);
@ -460,14 +613,16 @@ mod tests {
use swc_common::DUMMY_SP as span;
fn array_pat(s: &'static str) -> Pat {
test_parser(s, Syntax::Es2019, |p| p.parse_array_binding_pat())
test_parser(s, Syntax::Es, |p| {
p.parse_array_binding_pat().map_err(|e| {
e.emit();
()
})
})
}
fn ident(s: &str) -> Ident {
Ident {
sym: s.into(),
span,
}
Ident::new(s.into(), span)
}
#[test]
@ -480,13 +635,16 @@ mod tests {
Some(Pat::Ident(ident("a"))),
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("b")))]
elems: vec![Some(Pat::Ident(ident("b")))],
type_ann: None
})),
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("c")))]
elems: vec![Some(Pat::Ident(ident("c")))],
type_ann: None
}))
]
],
type_ann: None
})
);
}
@ -502,13 +660,16 @@ mod tests {
Some(Pat::Ident(ident("a"))),
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("b")))]
elems: vec![Some(Pat::Ident(ident("b")))],
type_ann: None
})),
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("c")))]
elems: vec![Some(Pat::Ident(ident("c")))],
type_ann: None
}))
]
],
type_ann: None
})
);
}
@ -524,13 +685,16 @@ mod tests {
None,
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("b")))]
elems: vec![Some(Pat::Ident(ident("b")))],
type_ann: None
})),
Some(Pat::Array(ArrayPat {
span,
elems: vec![Some(Pat::Ident(ident("c")))]
elems: vec![Some(Pat::Ident(ident("c")))],
type_ann: None
}))
]
],
type_ann: None
})
);
}

View File

@ -55,11 +55,11 @@ impl<'a, I: Input> Parser<'a, I> {
}
pub fn parse_stmt(&mut self, top_level: bool) -> PResult<'a, Stmt> {
self.parse_stmt_internal(false, top_level)
self.parse_stmt_like(false, top_level)
}
fn parse_stmt_list_item(&mut self, top_level: bool) -> PResult<'a, Stmt> {
self.parse_stmt_internal(true, top_level)
self.parse_stmt_like(true, top_level)
}
/// Parse a statement, declaration or module item.
@ -68,16 +68,34 @@ impl<'a, I: Input> Parser<'a, I> {
Self: StmtLikeParser<'a, Type>,
Type: IsDirective + From<Stmt>,
{
let decorators = self.parse_decorators(true)?;
if is_one_of!("import", "export") {
return self.handle_import_export(top_level);
return self.handle_import_export(top_level, decorators);
}
self.parse_stmt_internal(include_decl, top_level)
self.parse_stmt_internal(include_decl, top_level, decorators)
.map(From::from)
}
fn parse_stmt_internal(&mut self, include_decl: bool, top_level: bool) -> PResult<'a, Stmt> {
/// `parseStatementContent`
fn parse_stmt_internal(
&mut self,
include_decl: bool,
top_level: bool,
decorators: Vec<Decorator>,
) -> PResult<'a, Stmt> {
let start = cur_pos!();
if self.input.syntax().typescript() && is!("const") && peeked_is!("enum") {
assert_and_bump!("const");
assert_and_bump!("enum");
return self
.parse_ts_enum_decl(start, /* is_const */ true)
.map(Decl::from)
.map(Stmt::from);
}
if is_one_of!("break", "continue") {
let is_break = is!("break");
bump!();
@ -117,14 +135,14 @@ impl<'a, I: Input> Parser<'a, I> {
unexpected!()
}
return self.parse_fn_decl().map(Stmt::from);
return self.parse_fn_decl(decorators).map(Stmt::from);
}
if is!("class") {
if !include_decl {
unexpected!()
}
return self.parse_class_decl().map(Stmt::from);
return self.parse_class_decl(decorators).map(Stmt::from);
}
if is!("if") {
@ -187,7 +205,7 @@ impl<'a, I: Input> Parser<'a, I> {
&& peeked_is!("function")
&& !self.input.has_linebreak_between_cur_and_peeked()
{
return self.parse_async_fn_decl().map(From::from);
return self.parse_async_fn_decl(decorators).map(From::from);
}
// If the statement does not start with a statement keyword or a
@ -196,6 +214,7 @@ impl<'a, I: Input> Parser<'a, I> {
// next token is a colon and the expression was a simple
// Identifier node, we switch to interpreting it as a label.
let expr = self.include_in_expr(true).parse_expr()?;
let expr = match expr {
box Expr::Ident(ident) => {
if eat!(':') {
@ -209,6 +228,16 @@ impl<'a, I: Input> Parser<'a, I> {
expr
}
};
match *expr {
Expr::Ident(ref ident) => {
if self.input.syntax().typescript() {
if let Some(decl) = self.parse_ts_expr_stmt(decorators, ident.clone())? {
return Ok(Stmt::Decl(decl));
}
}
}
_ => {}
}
if eat!(';') {
Ok(Stmt::Expr(expr))
@ -400,7 +429,7 @@ impl<'a, I: Input> Parser<'a, I> {
}
}
fn parse_var_stmt(&mut self, for_loop: bool) -> PResult<'a, VarDecl> {
pub(super) fn parse_var_stmt(&mut self, for_loop: bool) -> PResult<'a, VarDecl> {
let start = cur_pos!();
let kind = match bump!() {
tok!("const") => VarDeclKind::Const,
@ -422,6 +451,7 @@ impl<'a, I: Input> Parser<'a, I> {
Ok(VarDecl {
span: span!(start),
declare: self.ctx().in_declare,
kind,
decls,
})
@ -429,17 +459,57 @@ impl<'a, I: Input> Parser<'a, I> {
fn parse_var_declarator(&mut self, for_loop: bool) -> PResult<'a, VarDeclarator> {
let start = cur_pos!();
let name = self.parse_binding_pat_or_ident()?;
let mut name = self.parse_binding_pat_or_ident()?;
let definite = if self.input.syntax().typescript() {
match name {
Pat::Ident(..) => eat!('!'),
_ => false,
}
} else {
false
};
// Typescript extension
if self.input.syntax().typescript() && is!(':') {
let type_annotation = self.try_parse_ts_type_ann()?;
match name {
Pat::Array(ArrayPat {
ref mut type_ann, ..
})
| Pat::Assign(AssignPat {
ref mut type_ann, ..
})
| Pat::Ident(Ident {
ref mut type_ann, ..
})
| Pat::Object(ObjectPat {
ref mut type_ann, ..
})
| Pat::Rest(RestPat {
ref mut type_ann, ..
}) => {
*type_ann = type_annotation;
}
Pat::Expr(expr) => unreachable!("invalid syntax: Pat(expr): {:?}", expr),
}
}
//FIXME: This is wrong. Should check in/of only on first loop.
let init = if !for_loop || !is_one_of!("in", "of") {
if eat!('=') {
Some(self.parse_assignment_expr()?)
} else {
// Destructuring bindings require initializers.
match name {
Pat::Ident(..) => None,
_ => syntax_error!(span!(start), SyntaxError::PatVarWithoutInit),
// Destructuring bindings require initializers, but
// typescript allows `declare` vars not to have initializers.
if self.ctx().in_declare {
None
} else {
match name {
Pat::Ident(..) => None,
_ => syntax_error!(span!(start), SyntaxError::PatVarWithoutInit),
}
}
}
} else {
@ -451,6 +521,7 @@ impl<'a, I: Input> Parser<'a, I> {
span: span!(start),
name,
init,
definite,
});
}
@ -510,7 +581,7 @@ impl<'a, I: Input> Parser<'a, I> {
expect!('{');
let stmts = self.parse_block_body(allow_directives, false, Some(&RBrace))?;
let stmts = self.parse_block_body(allow_directives, false, Some(&tok!('}')))?;
let span = span!(start);
Ok(BlockStmt { span, stmts })
@ -525,7 +596,7 @@ impl<'a, I: Input> Parser<'a, I> {
}
}
let body = box if is!("function") {
let f = self.parse_fn_decl()?;
let f = self.parse_fn_decl(vec![])?;
match f {
Decl::Fn(FnDecl {
function:
@ -710,12 +781,16 @@ impl IsDirective for Stmt {
}
pub(super) trait StmtLikeParser<'a, Type: IsDirective> {
fn handle_import_export(&mut self, top_level: bool) -> PResult<'a, Type>;
fn handle_import_export(
&mut self,
top_level: bool,
decorators: Vec<Decorator>,
) -> PResult<'a, Type>;
}
#[parser]
impl<'a, I: Input> StmtLikeParser<'a, Stmt> for Parser<'a, I> {
fn handle_import_export(&mut self, top_level: bool) -> PResult<'a, Stmt> {
fn handle_import_export(&mut self, top_level: bool, _: Vec<Decorator>) -> PResult<'a, Stmt> {
syntax_error!(SyntaxError::ImportExportInScript);
}
}
@ -723,13 +798,24 @@ impl<'a, I: Input> StmtLikeParser<'a, Stmt> for Parser<'a, I> {
#[cfg(test)]
mod tests {
use super::*;
use crate::EsNextConfig;
use swc_common::DUMMY_SP as span;
fn stmt(s: &'static str) -> Stmt {
test_parser(s, Syntax::Es2019, |p| p.parse_stmt(true))
test_parser(s, Syntax::Es, |p| {
p.parse_stmt(true).map_err(|e| {
e.emit();
()
})
})
}
fn expr(s: &'static str) -> Box<Expr> {
test_parser(s, Syntax::Es2019, |p| p.parse_expr())
test_parser(s, Syntax::Es, |p| {
p.parse_expr().map_err(|e| {
e.emit();
()
})
})
}
#[test]
@ -753,8 +839,10 @@ mod tests {
span,
props: vec![ObjectPatProp::Rest(RestPat {
dot3_token: span,
arg: box Pat::Ident(Ident::new("a34".into(), span))
})]
arg: box Pat::Ident(Ident::new("a34".into(), span)),
type_ann: None
})],
type_ann: None,
})
.into(),
body: BlockStmt {
@ -791,16 +879,12 @@ mod tests {
decls: vec![VarDeclarator {
span,
init: None,
name: Pat::Ident(Ident {
span,
sym: "a".into()
})
name: Pat::Ident(Ident::new("a".into(), span)),
definite: false,
}],
declare: false,
}),
right: box Expr::Ident(Ident {
span,
sym: "b".into()
}),
right: box Expr::Ident(Ident::new("b".into(), span)),
body: box Stmt::Empty(EmptyStmt { span })
})
@ -839,4 +923,48 @@ mod tests {
})
);
}
#[test]
fn class_decorator() {
assert_eq_ignore_span!(
test_parser(
"
@decorator
@dec2
class Foo {}
",
Syntax::EsNext(EsNextConfig {
decorators: true,
..Default::default()
}),
|p| p.parse_stmt_list_item(true).map_err(|e| {
e.emit();
()
}),
),
Stmt::Decl(Decl::Class(ClassDecl {
ident: Ident::new("Foo".into(), span),
class: Class {
span,
decorators: vec![
Decorator {
span,
expr: expr("decorator")
},
Decorator {
span,
expr: expr("dec2")
}
],
super_class: None,
implements: vec![],
body: vec![],
is_abstract: false,
super_type_params: None,
type_params: None,
},
declare: false,
}))
);
}
}

View File

@ -6,6 +6,14 @@ impl<'a, I: Input> Parser<'a, I> {
let start = cur_pos!();
assert_and_bump!("import");
if self.input.syntax().typescript() {
if is!(IdentRef) && peeked_is!('=') {
return self
.parse_ts_import_equals_decl(start, false)
.map(From::from);
}
}
// Handle import 'mod.js'
let str_start = cur_pos!();
match *cur!(false)? {
@ -126,10 +134,64 @@ impl<'a, I: Input> Parser<'a, I> {
self.with_ctx(ctx).parse_binding_ident()
}
fn parse_export(&mut self) -> PResult<'a, ModuleDecl> {
fn parse_export(&mut self, decorators: Vec<Decorator>) -> PResult<'a, ModuleDecl> {
let start = cur_pos!();
assert_and_bump!("export");
// "export declare" is equivalent to just "export".
let declare = self.input.syntax().typescript() && eat!("declare");
if declare {
// TODO: Remove
if let Some(decl) = self.try_parse_ts_declare(start, decorators.clone())? {
return Ok(ModuleDecl::ExportDecl(decl));
}
}
if self.input.syntax().typescript() && is!(IdentName) {
let sym = match *cur!(true)? {
Token::Word(ref w) => w.clone().into(),
_ => unreachable!(),
};
// TODO: remove clone
if let Some(decl) = self.try_parse_ts_export_decl(decorators.clone(), sym)? {
return Ok(ModuleDecl::ExportDecl(decl));
}
}
if self.input.syntax().typescript() {
if eat!("import") {
// export import A = B
return self
.parse_ts_import_equals_decl(start, /* is_export */ true)
.map(From::from);
}
if eat!('=') {
// `export = x;`
let expr = self.parse_expr()?;
expect!(';');
return Ok(TsExportAssignment {
span: span!(start),
expr,
}
.into());
}
if eat!("as") {
// `export as namespace A;`
// See `parseNamespaceExportDeclaration` in TypeScript's own parser
expect!("namespace");
let id = self.parse_ident(false, false)?;
expect!(';');
return Ok(TsNamespaceExportDecl {
span: span!(start),
id,
}
.into());
}
}
if eat!('*') {
let src = self.parse_from_clause_and_semi()?;
return Ok(ModuleDecl::ExportAll(ExportAll {
@ -139,15 +201,35 @@ impl<'a, I: Input> Parser<'a, I> {
}
if eat!("default") {
if self.input.syntax().typescript() {
if is!("abstract") && peeked_is!("class") {
let start = cur_pos!();
assert_and_bump!("abstract");
let mut class = self.parse_default_class(decorators)?;
match class {
ExportDefaultDecl::Class(ClassExpr { ref mut class, .. }) => {
class.is_abstract = true
}
_ => unreachable!(),
}
return Ok(class.into());
}
if eat!("interface") {
let decl = self.parse_ts_interface_decl().map(Decl::from)?;
return Ok(decl.into());
}
}
let decl = if is!("class") {
self.parse_default_class()?
self.parse_default_class(decorators)?
} else if is!("async")
&& peeked_is!("function")
&& !self.input.has_linebreak_between_cur_and_peeked()
{
self.parse_default_async_fn()?
self.parse_default_async_fn(decorators)?
} else if is!("function") {
self.parse_default_fn()?
self.parse_default_fn(decorators)?
} else {
let expr = self.include_in_expr(true).parse_assignment_expr()?;
expect!(';');
@ -158,14 +240,22 @@ impl<'a, I: Input> Parser<'a, I> {
}
let decl = if is!("class") {
self.parse_class_decl()?
self.parse_class_decl(decorators)?
} else if is!("async")
&& peeked_is!("function")
&& !self.input.has_linebreak_between_cur_and_peeked()
{
self.parse_async_fn_decl()?
self.parse_async_fn_decl(decorators)?
} else if is!("function") {
self.parse_fn_decl()?
self.parse_fn_decl(decorators)?
} else if self.input.syntax().typescript() && is!("const") && peeked_is!("enum") {
let start = cur_pos!();
assert_and_bump!("const");
assert_and_bump!("enum");
return self
.parse_ts_enum_decl(start, /* is_const */ true)
.map(Decl::from)
.map(ModuleDecl::from);
} else if is!("var")
|| is!("const")
|| (is!("let")
@ -265,7 +355,11 @@ impl IsDirective for ModuleItem {
#[parser]
impl<'a, I: Input> StmtLikeParser<'a, ModuleItem> for Parser<'a, I> {
fn handle_import_export(&mut self, top_level: bool) -> PResult<'a, ModuleItem> {
fn handle_import_export(
&mut self,
top_level: bool,
decorators: Vec<Decorator>,
) -> PResult<'a, ModuleItem> {
if !top_level {
syntax_error!(SyntaxError::NonTopLevelImportExport);
}
@ -274,7 +368,7 @@ impl<'a, I: Input> StmtLikeParser<'a, ModuleItem> for Parser<'a, I> {
let decl = if is!("import") {
self.parse_import()?
} else if is!("export") {
self.parse_export()?
self.parse_export(decorators)?
} else {
unreachable!(
"handle_import_export should not be called if current token isn't import nor \

File diff suppressed because it is too large Load Diff

View File

@ -85,6 +85,15 @@ impl<'a, I: Input> Parser<'a, I> {
self.with_ctx(ctx)
}
/// Original context is restored when returned guard is dropped.
pub(super) fn in_type<'w>(&'w mut self) -> WithCtx<'w, 'a, I> {
let ctx = Context {
in_type: true,
..self.ctx()
};
self.with_ctx(ctx)
}
/// Original context is restored when returned guard is dropped.
pub(super) fn include_in_expr<'w>(&'w mut self, include_in_expr: bool) -> WithCtx<'w, 'a, I> {
let ctx = Context {
@ -170,7 +179,8 @@ pub(super) trait ExprExt {
| Expr::Object(..)
| Expr::Fn(..)
| Expr::Class(..)
| Expr::Tpl(..) => false,
| Expr::Tpl(..)
| Expr::TaggedTpl(..) => false,
Expr::Paren(ParenExpr { ref expr, .. }) => {
expr.is_valid_simple_assignment_target(strict)
}
@ -199,6 +209,14 @@ pub(super) trait ExprExt {
| Expr::JSXEmpty(..)
| Expr::JSXElement(..)
| Expr::JSXFragment(..) => false,
// typescript
Expr::TsNonNull(TsNonNullExpr { ref expr, .. })
| Expr::TsTypeAssertion(TsTypeAssertion { ref expr, .. })
| Expr::TsTypeCast(TsTypeCastExpr { ref expr, .. })
| Expr::TsAs(TsAsExpr { ref expr, .. }) => {
expr.is_valid_simple_assignment_target(strict)
}
}
}
}

View File

@ -1,7 +1,7 @@
//! Ported from [babel/bablyon][]
//!
//! [babel/bablyon]:https://github.com/babel/babel/blob/2d378d076eb0c5fe63234a8b509886005c01d7ee/packages/babylon/src/tokenizer/types.js
pub(crate) use self::{AssignOpToken::*, BinOpToken::*, Keyword::*, Token::*, Word::*};
pub(crate) use self::{AssignOpToken::*, BinOpToken::*, Keyword::*, Token::*};
use crate::error::Error;
pub(crate) use ast::AssignOp as AssignOpToken;
use ast::{BinaryOp, Str};
@ -23,6 +23,9 @@ pub(crate) enum Token {
#[kind(before_expr)]
Arrow,
/// '#'
Hash,
/// '@'
At,
/// '.'
@ -223,9 +226,9 @@ pub enum Word {
impl From<JsWord> for Word {
fn from(i: JsWord) -> Self {
match i {
js_word!("null") => Null,
js_word!("true") => True,
js_word!("false") => False,
js_word!("null") => Word::Null,
js_word!("true") => Word::True,
js_word!("false") => Word::False,
js_word!("await") => Await.into(),
js_word!("break") => Break.into(),
js_word!("case") => Case.into(),
@ -261,20 +264,20 @@ impl From<JsWord> for Word {
js_word!("typeof") => TypeOf.into(),
js_word!("void") => Void.into(),
js_word!("delete") => Delete.into(),
_ => Ident(i),
_ => Word::Ident(i),
}
}
}
impl From<Keyword> for Word {
fn from(kwd: Keyword) -> Self {
Keyword(kwd)
Word::Keyword(kwd)
}
}
impl From<Word> for JsWord {
fn from(w: Word) -> Self {
match w {
Keyword(k) => match k {
Word::Keyword(k) => match k {
Await => js_word!("await"),
Break => js_word!("break"),
Case => js_word!("case"),
@ -328,11 +331,11 @@ impl From<Word> for JsWord {
Delete => js_word!("delete"),
},
Null => js_word!("null"),
True => js_word!("true"),
False => js_word!("false"),
Word::Null => js_word!("null"),
Word::True => js_word!("true"),
Word::False => js_word!("false"),
Ident(w) => w,
Word::Ident(w) => w,
}
}
}
@ -534,7 +537,7 @@ impl Token {
// This is required to recognize `let let` in strict mode.
tok!("let") => true,
tok!('{') | tok!('[') | Word(Ident(..)) | tok!("yield") | tok!("await") => true,
tok!('{') | tok!('[') | Word(Word::Ident(..)) | tok!("yield") | tok!("await") => true,
_ => false,
}

View File

@ -15,7 +15,6 @@ use std::{
io::{self, Read},
path::Path,
};
use swc_common::{Fold, FoldWith, Span};
use swc_ecma_ast::*;
use swc_ecma_parser::{PResult, Parser, Session, SourceFileInput, Syntax};
use test::{test_main, Options, ShouldPanic::No, TestDesc, TestDescAndFn, TestFn, TestName};
@ -163,19 +162,20 @@ fn with_parser<F, Ret>(file_name: &Path, f: F) -> Result<Ret, StdErr>
where
F: for<'a> FnOnce(&mut Parser<'a, SourceFileInput>) -> PResult<'a, Ret>,
{
let output = ::testing::run_test(|cm, handler| {
let output = ::testing::run_test(false, |cm, handler| {
let fm = cm
.load_file(file_name)
.unwrap_or_else(|e| panic!("failed to load {}: {}", file_name.display(), e));
let res = f(&mut Parser::new(
Session {
handler: &handler,
cfg: Default::default(),
},
Session { handler: &handler },
Syntax::Jsx,
(&*fm).into(),
));
))
.map_err(|e| {
e.emit();
()
});
res
});
@ -198,84 +198,3 @@ fn error() {
error_tests(&mut tests).unwrap();
test_main(&args, tests, Options::new());
}
pub fn normalize<T>(t: T) -> T
where
Normalizer: Fold<T>,
{
let mut n = Normalizer;
n.fold(t)
}
pub struct Normalizer;
impl Fold<Span> for Normalizer {
fn fold(&mut self, _: Span) -> Span {
Span::default()
}
}
impl Fold<Str> for Normalizer {
fn fold(&mut self, s: Str) -> Str {
Str {
span: Default::default(),
has_escape: false,
..s
}
}
}
impl Fold<Expr> for Normalizer {
fn fold(&mut self, e: Expr) -> Expr {
let e = e.fold_children(self);
match e {
Expr::Paren(ParenExpr { expr, .. }) => *expr,
Expr::New(NewExpr {
callee,
args: None,
span,
}) => Expr::New(NewExpr {
span,
callee,
args: Some(vec![]),
}),
// Flatten comma expressions.
Expr::Seq(SeqExpr { mut exprs, span }) => {
let need_work = exprs.iter().any(|n| match **n {
Expr::Seq(..) => true,
_ => false,
});
if need_work {
exprs = exprs.into_iter().fold(vec![], |mut v, e| {
match *e {
Expr::Seq(SeqExpr { exprs, .. }) => v.extend(exprs),
_ => v.push(e),
}
v
});
}
Expr::Seq(SeqExpr { exprs, span })
}
_ => e,
}
}
}
impl Fold<PropName> for Normalizer {
fn fold(&mut self, n: PropName) -> PropName {
let n = n.fold_children(self);
match n {
PropName::Ident(Ident { sym, .. }) => PropName::Str(Str {
span: Default::default(),
value: sym,
has_escape: false,
}),
PropName::Num(num) => PropName::Str(Str {
span: Default::default(),
value: num.to_string().into(),
has_escape: false,
}),
_ => n,
}
}
}

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXExprContainer(
@ -80,9 +83,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
30
),
@ -90,8 +93,10 @@ Module {
31
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -78,9 +81,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
20
),
@ -88,8 +91,10 @@ Module {
23
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXElement(
@ -63,9 +66,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
br,
Span {
Ident {
sym: br,
span: Span {
lo: BytePos(
6
),
@ -73,8 +76,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -86,7 +91,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -120,9 +126,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
37
),
@ -130,8 +136,10 @@ Module {
40
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
LeftRight,
Span {
Ident {
sym: LeftRight,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
left,
Span {
Ident {
sym: left,
span: Span {
lo: BytePos(
11
),
@ -69,8 +71,10 @@ Module {
15
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
JSXElement(
@ -86,9 +90,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
17
),
@ -96,8 +100,10 @@ Module {
18
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -109,7 +115,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -130,9 +137,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
right,
Span {
Ident {
sym: right,
span: Span {
lo: BytePos(
22
),
@ -140,8 +147,10 @@ Module {
27
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
JSXElement(
@ -157,9 +166,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
29
),
@ -167,8 +176,10 @@ Module {
30
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -180,7 +191,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -211,9 +223,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
52
),
@ -221,8 +233,10 @@ Module {
53
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -232,7 +246,8 @@ Module {
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -26,9 +26,9 @@ Module {
name: JSXMemberExpr(
JSXMemberExpr {
obj: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -36,12 +36,14 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
prop: Ident(
b,
Span {
prop: Ident {
sym: b,
span: Span {
lo: BytePos(
3
),
@ -49,8 +51,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
span: Span {
@ -63,7 +67,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -80,9 +85,9 @@ Module {
name: JSXMemberExpr(
JSXMemberExpr {
obj: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
7
),
@ -90,12 +95,14 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
prop: Ident(
b,
Span {
prop: Ident {
sym: b,
span: Span {
lo: BytePos(
9
),
@ -103,8 +110,10 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
)
}

View File

@ -28,9 +28,9 @@ Module {
obj: JSXMemberExpr(
JSXMemberExpr {
obj: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -38,12 +38,14 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
prop: Ident(
b,
Span {
prop: Ident {
sym: b,
span: Span {
lo: BytePos(
3
),
@ -51,13 +53,15 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
prop: Ident(
c,
Span {
prop: Ident {
sym: c,
span: Span {
lo: BytePos(
5
),
@ -65,8 +69,10 @@ Module {
6
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
span: Span {
@ -79,7 +85,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -98,9 +105,9 @@ Module {
obj: JSXMemberExpr(
JSXMemberExpr {
obj: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
9
),
@ -108,12 +115,14 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
prop: Ident(
b,
Span {
prop: Ident {
sym: b,
span: Span {
lo: BytePos(
11
),
@ -121,13 +130,15 @@ Module {
12
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
prop: Ident(
c,
Span {
prop: Ident {
sym: c,
span: Span {
lo: BytePos(
13
),
@ -135,8 +146,10 @@ Module {
14
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
)
}

View File

@ -47,9 +47,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
2
),
@ -57,8 +57,10 @@ Module {
5
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -70,7 +72,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -79,9 +82,9 @@ Module {
}
),
right: Ident(
Ident(
x,
Span {
Ident {
sym: x,
span: Span {
lo: BytePos(
12
),
@ -89,8 +92,10 @@ Module {
13
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
expr: Ident(
Ident(
props,
Span {
Ident {
sym: props,
span: Span {
lo: BytePos(
9
),
@ -69,13 +71,16 @@ Module {
14
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
expr: Ident(
Ident(
props,
Span {
Ident {
sym: props,
span: Span {
lo: BytePos(
9
),
@ -69,8 +71,10 @@ Module {
14
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
),
@ -86,9 +90,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
post,
Span {
Ident {
sym: post,
span: Span {
lo: BytePos(
16
),
@ -96,8 +100,10 @@ Module {
20
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -121,7 +127,8 @@ Module {
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
pre,
Span {
Ident {
sym: pre,
span: Span {
lo: BytePos(
5
),
@ -69,8 +71,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -105,9 +109,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
pre2,
Span {
Ident {
sym: pre2,
span: Span {
lo: BytePos(
19
),
@ -115,8 +119,10 @@ Module {
23
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -151,9 +157,9 @@ Module {
ctxt: #0
},
expr: Ident(
Ident(
props,
Span {
Ident {
sym: props,
span: Span {
lo: BytePos(
40
),
@ -161,13 +167,16 @@ Module {
45
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -182,9 +191,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
49
),
@ -192,8 +201,10 @@ Module {
52
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -25,9 +25,9 @@ Module {
opening: JSXOpeningElement {
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
n,
Span {
ns: Ident {
sym: n,
span: Span {
lo: BytePos(
1
),
@ -35,11 +35,13 @@ Module {
2
),
ctxt: #0
}
),
name: Ident(
a,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: a,
span: Span {
lo: BytePos(
3
),
@ -47,8 +49,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
span: Span {
@ -74,9 +78,9 @@ Module {
},
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
n,
Span {
ns: Ident {
sym: n,
span: Span {
lo: BytePos(
5
),
@ -84,11 +88,13 @@ Module {
6
),
ctxt: #0
}
),
name: Ident(
v,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: v,
span: Span {
lo: BytePos(
7
),
@ -96,15 +102,18 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
value: None
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
aa,
Span {
Ident {
sym: aa,
span: Span {
lo: BytePos(
3
),
@ -69,8 +71,10 @@ Module {
5
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Member(
@ -98,9 +102,9 @@ Module {
},
obj: Expr(
Ident(
Ident(
aa,
Span {
Ident {
sym: aa,
span: Span {
lo: BytePos(
7
),
@ -108,14 +112,16 @@ Module {
9
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
),
prop: Ident(
Ident(
bb,
Span {
Ident {
sym: bb,
span: Span {
lo: BytePos(
10
),
@ -123,17 +129,19 @@ Module {
12
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
computed: false
}
)
),
prop: Ident(
Ident(
cc,
Span {
Ident {
sym: cc,
span: Span {
lo: BytePos(
13
),
@ -141,8 +149,10 @@ Module {
15
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
computed: false
}
@ -162,9 +172,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
bb,
Span {
Ident {
sym: bb,
span: Span {
lo: BytePos(
17
),
@ -172,8 +182,10 @@ Module {
19
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Member(
@ -201,9 +213,9 @@ Module {
},
obj: Expr(
Ident(
Ident(
bb,
Span {
Ident {
sym: bb,
span: Span {
lo: BytePos(
21
),
@ -211,14 +223,16 @@ Module {
23
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
),
prop: Ident(
Ident(
cc,
Span {
Ident {
sym: cc,
span: Span {
lo: BytePos(
24
),
@ -226,17 +240,19 @@ Module {
26
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
computed: false
}
)
),
prop: Ident(
Ident(
dd,
Span {
Ident {
sym: dd,
span: Span {
lo: BytePos(
27
),
@ -244,8 +260,10 @@ Module {
29
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
computed: false
}
@ -254,7 +272,8 @@ Module {
}
)
],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXElement(
@ -270,9 +289,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
32
),
@ -280,8 +299,10 @@ Module {
35
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -293,7 +314,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXExprContainer(
@ -312,9 +334,9 @@ Module {
},
obj: Expr(
Ident(
Ident(
aa,
Span {
Ident {
sym: aa,
span: Span {
lo: BytePos(
37
),
@ -322,14 +344,16 @@ Module {
39
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
),
prop: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
40
),
@ -337,8 +361,10 @@ Module {
41
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
computed: false
}
@ -359,9 +385,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
44
),
@ -369,8 +395,10 @@ Module {
47
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -389,9 +417,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
50
),
@ -399,8 +427,10 @@ Module {
51
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
expr: Ident(
Ident(
c,
Span {
Ident {
sym: c,
span: Span {
lo: BytePos(
9
),
@ -69,13 +71,16 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -96,9 +101,9 @@ Module {
JSXSpreadChild(
JSXSpreadChild {
expr: Ident(
Ident(
children,
Span {
Ident {
sym: children,
span: Span {
lo: BytePos(
17
),
@ -106,8 +111,10 @@ Module {
25
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
),
@ -115,9 +122,9 @@ Module {
JSXExprContainer {
expr: Expr(
Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
27
),
@ -125,8 +132,10 @@ Module {
28
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
)
}
@ -134,9 +143,9 @@ Module {
JSXSpreadChild(
JSXSpreadChild {
expr: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
33
),
@ -144,8 +153,10 @@ Module {
34
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -162,9 +173,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
37
),
@ -172,8 +183,10 @@ Module {
40
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -60,9 +62,9 @@ Module {
},
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
n,
Span {
ns: Ident {
sym: n,
span: Span {
lo: BytePos(
3
),
@ -70,11 +72,13 @@ Module {
4
),
ctxt: #0
}
),
name: Ident(
foo,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: foo,
span: Span {
lo: BytePos(
5
),
@ -82,8 +86,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
value: Some(
@ -108,7 +114,8 @@ Module {
}
)
],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -130,9 +137,9 @@ Module {
JSXExprContainer {
expr: Expr(
Ident(
Ident(
value,
Span {
Ident {
sym: value,
span: Span {
lo: BytePos(
17
),
@ -140,8 +147,10 @@ Module {
22
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
)
}
@ -174,9 +183,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
25
),
@ -184,8 +193,10 @@ Module {
26
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -197,7 +208,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXElement(
@ -213,9 +225,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
c,
Span {
Ident {
sym: c,
span: Span {
lo: BytePos(
28
),
@ -223,8 +235,10 @@ Module {
29
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -236,7 +250,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -255,9 +270,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
34
),
@ -265,8 +280,10 @@ Module {
35
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -285,9 +302,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
38
),
@ -295,8 +312,10 @@ Module {
39
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
3
),
@ -69,8 +71,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -105,9 +109,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
c,
Span {
Ident {
sym: c,
span: Span {
lo: BytePos(
11
),
@ -115,8 +119,10 @@ Module {
12
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -151,9 +157,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
d,
Span {
Ident {
sym: d,
span: Span {
lo: BytePos(
17
),
@ -161,8 +167,10 @@ Module {
18
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -197,9 +205,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
e,
Span {
Ident {
sym: e,
span: Span {
lo: BytePos(
27
),
@ -207,8 +215,10 @@ Module {
28
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -232,7 +242,8 @@ Module {
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
日本語,
Span {
Ident {
sym: 日本語,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -62,9 +65,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
日本語,
Span {
Ident {
sym: 日本語,
span: Span {
lo: BytePos(
13
),
@ -72,8 +75,10 @@ Module {
22
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
AbC-def,
Span {
Ident {
sym: AbC-def,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
test,
Span {
Ident {
sym: test,
span: Span {
lo: BytePos(
11
),
@ -69,8 +71,10 @@ Module {
15
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Lit(
@ -94,7 +98,8 @@ Module {
}
)
],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -137,9 +142,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
AbC-def,
Span {
Ident {
sym: AbC-def,
span: Span {
lo: BytePos(
43
),
@ -147,8 +152,10 @@ Module {
50
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -59,9 +61,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
b,
Span {
Ident {
sym: b,
span: Span {
lo: BytePos(
3
),
@ -69,8 +71,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
value: Some(
Cond(
@ -85,9 +89,9 @@ Module {
ctxt: #0
},
test: Ident(
Ident(
x,
Span {
Ident {
sym: x,
span: Span {
lo: BytePos(
6
),
@ -95,8 +99,10 @@ Module {
7
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
cons: JSXElement(
JSXElement {
@ -111,9 +117,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
c,
Span {
Ident {
sym: c,
span: Span {
lo: BytePos(
11
),
@ -121,8 +127,10 @@ Module {
12
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -134,7 +142,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -153,9 +162,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
d,
Span {
Ident {
sym: d,
span: Span {
lo: BytePos(
19
),
@ -163,8 +172,10 @@ Module {
20
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -176,7 +187,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -188,7 +200,8 @@ Module {
}
)
],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None

View File

@ -13,9 +13,9 @@ Module {
Decl(
Fn(
FnDecl {
ident: Ident(
x,
Span {
ident: Ident {
sym: x,
span: Span {
lo: BytePos(
9
),
@ -23,10 +23,14 @@ Module {
10
),
ctxt: #0
}
),
},
type_ann: None,
optional: false
},
declare: false,
function: Function {
params: [],
decorators: [],
span: Span {
lo: BytePos(
0
@ -36,109 +40,120 @@ Module {
),
ctxt: #0
},
body: BlockStmt {
span: Span {
lo: BytePos(
13
),
hi: BytePos(
34
),
ctxt: #0
},
stmts: [
Decl(
Var(
VarDecl {
span: Span {
lo: BytePos(
17
),
hi: BytePos(
22
),
ctxt: #0
},
kind: "let",
decls: [
VarDeclarator {
span: Span {
lo: BytePos(
21
),
hi: BytePos(
22
),
ctxt: #0
},
name: Ident(
Ident(
x,
Span {
lo: BytePos(
21
),
hi: BytePos(
22
),
ctxt: #0
}
)
),
init: None
}
]
}
)
),
Expr(
JSXElement(
JSXElement {
span: Span {
lo: BytePos(
25
),
hi: BytePos(
32
),
ctxt: #0
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
lo: BytePos(
26
),
hi: BytePos(
29
),
ctxt: #0
}
)
),
body: Some(
BlockStmt {
span: Span {
lo: BytePos(
13
),
hi: BytePos(
34
),
ctxt: #0
},
stmts: [
Decl(
Var(
VarDecl {
span: Span {
lo: BytePos(
26
17
),
hi: BytePos(
22
),
ctxt: #0
},
kind: "let",
declare: false,
decls: [
VarDeclarator {
span: Span {
lo: BytePos(
21
),
hi: BytePos(
22
),
ctxt: #0
},
name: Ident(
Ident {
sym: x,
span: Span {
lo: BytePos(
21
),
hi: BytePos(
22
),
ctxt: #0
},
type_ann: None,
optional: false
}
),
init: None,
definite: false
}
]
}
)
),
Expr(
JSXElement(
JSXElement {
span: Span {
lo: BytePos(
25
),
hi: BytePos(
32
),
ctxt: #0
},
attrs: [],
self_closing: true
},
children: [],
closing: None
}
opening: JSXOpeningElement {
name: Ident(
Ident {
sym: div,
span: Span {
lo: BytePos(
26
),
hi: BytePos(
29
),
ctxt: #0
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
26
),
hi: BytePos(
32
),
ctxt: #0
},
attrs: [],
self_closing: true,
type_args: None
},
children: [],
closing: None
}
)
)
)
]
},
]
}
),
is_generator: false,
is_async: false
is_async: false,
type_params: None,
return_type: None
}
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXExprContainer(
@ -80,9 +83,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
a,
Span {
Ident {
sym: a,
span: Span {
lo: BytePos(
7
),
@ -90,8 +93,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -78,9 +81,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
14
),
@ -88,8 +91,10 @@ Module {
15
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -66,9 +66,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
span,
Span {
Ident {
sym: span,
span: Span {
lo: BytePos(
7
),
@ -76,8 +76,10 @@ Module {
11
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -89,7 +91,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -128,9 +131,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
span,
Span {
Ident {
sym: span,
span: Span {
lo: BytePos(
24
),
@ -138,8 +141,10 @@ Module {
28
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -177,9 +182,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
33
),
@ -187,8 +192,10 @@ Module {
36
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -200,7 +207,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -231,9 +239,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
42
),
@ -241,8 +249,10 @@ Module {
45
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -66,9 +66,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
34
),
@ -76,8 +76,10 @@ Module {
37
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -89,7 +91,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -104,9 +107,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
40
),
@ -114,8 +117,10 @@ Module {
43
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)
@ -153,9 +158,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
48
),
@ -163,8 +168,10 @@ Module {
51
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -176,7 +183,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -191,9 +199,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
54
),
@ -201,8 +209,10 @@ Module {
57
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -47,9 +47,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
3
),
@ -57,8 +57,10 @@ Module {
6
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -70,7 +72,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -101,9 +104,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
div,
Span {
Ident {
sym: div,
span: Span {
lo: BytePos(
19
),
@ -111,8 +114,10 @@ Module {
22
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
var,
Span {
Ident {
sym: var,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
4
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -62,9 +65,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
var,
Span {
Ident {
sym: var,
span: Span {
lo: BytePos(
7
),
@ -72,8 +75,10 @@ Module {
10
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -25,9 +25,9 @@ Module {
opening: JSXOpeningElement {
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
Foo,
Span {
ns: Ident {
sym: Foo,
span: Span {
lo: BytePos(
1
),
@ -35,11 +35,13 @@ Module {
4
),
ctxt: #0
}
),
name: Ident(
Bar,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: Bar,
span: Span {
lo: BytePos(
5
),
@ -47,8 +49,10 @@ Module {
8
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
span: Span {
@ -61,7 +65,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: true
self_closing: true,
type_args: None
},
children: [],
closing: None
@ -85,9 +90,9 @@ Module {
opening: JSXOpeningElement {
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
Foo,
Span {
ns: Ident {
sym: Foo,
span: Span {
lo: BytePos(
14
),
@ -95,11 +100,13 @@ Module {
17
),
ctxt: #0
}
),
name: Ident(
Bar,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: Bar,
span: Span {
lo: BytePos(
18
),
@ -107,8 +114,10 @@ Module {
21
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
),
span: Span {
@ -121,7 +130,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [],
closing: Some(
@ -137,9 +147,9 @@ Module {
},
name: JSXNamespacedName(
JSXNamespacedName {
ns: Ident(
Foo,
Span {
ns: Ident {
sym: Foo,
span: Span {
lo: BytePos(
24
),
@ -147,11 +157,13 @@ Module {
27
),
ctxt: #0
}
),
name: Ident(
Bar,
Span {
},
type_ann: None,
optional: false
},
name: Ident {
sym: Bar,
span: Span {
lo: BytePos(
28
),
@ -159,8 +171,10 @@ Module {
31
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
}
)
}

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -78,9 +81,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
13
),
@ -88,8 +91,10 @@ Module {
14
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -24,9 +24,9 @@ Module {
},
opening: JSXOpeningElement {
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
1
),
@ -34,8 +34,10 @@ Module {
2
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
@ -47,7 +49,8 @@ Module {
ctxt: #0
},
attrs: [],
self_closing: false
self_closing: false,
type_args: None
},
children: [
JSXText(
@ -78,9 +81,9 @@ Module {
ctxt: #0
},
name: Ident(
Ident(
A,
Span {
Ident {
sym: A,
span: Span {
lo: BytePos(
14
),
@ -88,8 +91,10 @@ Module {
15
),
ctxt: #0
}
)
},
type_ann: None,
optional: false
}
)
}
)

View File

@ -13,9 +13,9 @@ Module {
Decl(
Fn(
FnDecl {
ident: Ident(
it,
Span {
ident: Ident {
sym: it,
span: Span {
lo: BytePos(
9
),
@ -23,10 +23,14 @@ Module {
11
),
ctxt: #0
}
),
},
type_ann: None,
optional: false
},
declare: false,
function: Function {
params: [],
decorators: [],
span: Span {
lo: BytePos(
0
@ -36,107 +40,116 @@ Module {
),
ctxt: #0
},
body: BlockStmt {
span: Span {
lo: BytePos(
13
),
hi: BytePos(
35
),
ctxt: #0
},
stmts: [
Expr(
Yield(
YieldExpr {
span: Span {
lo: BytePos(
19
),
hi: BytePos(
32
),
ctxt: #0
},
arg: Some(
JSXElement(
JSXElement {
span: Span {
lo: BytePos(
25
),
hi: BytePos(
32
),
ctxt: #0
},
opening: JSXOpeningElement {
name: Ident(
Ident(
a,
Span {
lo: BytePos(
26
),
hi: BytePos(
27
),
ctxt: #0
}
)
),
body: Some(
BlockStmt {
span: Span {
lo: BytePos(
13
),
hi: BytePos(
35
),
ctxt: #0
},
stmts: [
Expr(
Yield(
YieldExpr {
span: Span {
lo: BytePos(
19
),
hi: BytePos(
32
),
ctxt: #0
},
arg: Some(
JSXElement(
JSXElement {
span: Span {
lo: BytePos(
26
25
),
hi: BytePos(
28
32
),
ctxt: #0
},
attrs: [],
self_closing: false
},
children: [],
closing: Some(
JSXClosingElement {
opening: JSXOpeningElement {
name: Ident(
Ident {
sym: a,
span: Span {
lo: BytePos(
26
),
hi: BytePos(
27
),
ctxt: #0
},
type_ann: None,
optional: false
}
),
span: Span {
lo: BytePos(
30
26
),
hi: BytePos(
32
28
),
ctxt: #0
},
name: Ident(
Ident(
a,
Span {
lo: BytePos(
30
),
hi: BytePos(
31
),
ctxt: #0
attrs: [],
self_closing: false,
type_args: None
},
children: [],
closing: Some(
JSXClosingElement {
span: Span {
lo: BytePos(
30
),
hi: BytePos(
32
),
ctxt: #0
},
name: Ident(
Ident {
sym: a,
span: Span {
lo: BytePos(
30
),
hi: BytePos(
31
),
ctxt: #0
},
type_ann: None,
optional: false
}
)
)
}
)
}
)
),
delegate: false
}
}
)
}
)
),
delegate: false
}
)
)
)
]
},
]
}
),
is_generator: true,
is_async: false
is_async: false,
type_params: None,
return_type: None
}
}
)

View File

@ -4,9 +4,3 @@ error: Unexpected eof
1 | class
| ^
error: Expected ident
--> $DIR/tests/test262-parser/fail/0889113e04d3203f.js:1:1
|
1 | class
| ^^^^^

Some files were not shown because too many files have changed in this diff Show More