Make deserialization fast (#314)

swc_ecma_ast:
  - add deserialization benchmark

ast_node:
 - #[ast_node] on enum now implements faster deserialization
This commit is contained in:
강동윤 2019-03-05 23:16:45 +09:00 committed by GitHub
parent b4a391b3a7
commit ed100700f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2581 additions and 24 deletions

View File

@ -20,7 +20,7 @@ pub use self::{
pos::*,
source_map::{FileLines, FileLoader, FileName, FilePathMapping, SourceMap, SpanSnippetError},
};
pub use ast_node::{ast_node, Fold, FromVariant, Spanned};
pub use ast_node::{ast_node, DeserializeEnum, Fold, FromVariant, Spanned};
use serde::Serialize;
use std::fmt::Debug;

View File

@ -7,3 +7,9 @@ pub struct Node<T> {
#[serde(flatten)]
pub node: T,
}
#[derive(Deserialize)]
pub struct Type {
#[serde(rename = "type")]
pub ty: String,
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,539 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 23,
"ctxt": 0
},
"body": [
{
"type": "FunctionDeclaration",
"identifier": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "asyncGeneratorStep",
"optional": false
},
"declare": false,
"params": [
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "gen",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "resolve",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "reject",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "_next",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "_throw",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "key",
"optional": false
},
{
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "arg",
"optional": false
}
],
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"body": {
"type": "BlockStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"stmts": [
{
"type": "TryStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"block": {
"type": "BlockStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"stmts": [
{
"type": "VariableDeclaration",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"kind": "var",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "info",
"optional": false
},
"init": {
"type": "CallExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "gen",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "key",
"optional": false
},
"computed": true
},
"arguments": [
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "arg",
"optional": false
}
}
],
"typeArguments": null
},
"definite": false
}
]
},
{
"type": "VariableDeclaration",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"kind": "var",
"declare": false,
"declarations": [
{
"type": "VariableDeclarator",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"id": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "value",
"optional": false
},
"init": {
"type": "MemberExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "info",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "value",
"optional": false
},
"computed": false
},
"definite": false
}
]
}
]
},
"handler": {
"type": "CatchClause",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"param": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "error",
"optional": false
},
"body": {
"type": "BlockStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"stmts": [
{
"type": "CallExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "reject",
"optional": false
},
"arguments": [
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "error",
"optional": false
}
}
],
"typeArguments": null
},
{
"type": "ReturnStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
}
}
]
}
}
},
{
"type": "IfStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"test": {
"type": "MemberExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "info",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "done",
"optional": false
},
"computed": false
},
"consequent": {
"type": "BlockStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"stmts": [
{
"type": "CallExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"callee": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "resolve",
"optional": false
},
"arguments": [
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "value",
"optional": false
}
}
],
"typeArguments": null
}
]
},
"alternate": {
"type": "BlockStatement",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"stmts": [
{
"type": "CallExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"object": {
"type": "CallExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "Promise",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "resolve",
"optional": false
},
"computed": false
},
"arguments": [
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "value",
"optional": false
}
}
],
"typeArguments": null
},
"property": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "then",
"optional": false
},
"computed": false
},
"arguments": [
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "_next",
"optional": false
}
},
{
"expr": {
"type": "Identifier",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"value": "_throw",
"optional": false
}
}
],
"typeArguments": null
}
]
}
}
]
},
"generator": false,
"async": false
}
]
}

View File

@ -0,0 +1,25 @@
#![feature(test)]
extern crate serde_json;
extern crate swc_ecma_ast;
extern crate test;
use swc_ecma_ast::Module;
use test::Bencher;
#[bench]
fn module_1(b: &mut Bencher) {
const SRC: &str = include_str!("module-1.json");
b.bytes = SRC.len() as _;
b.iter(|| test::black_box(serde_json::from_str::<Module>(SRC).unwrap()))
}
#[bench]
fn module_2(b: &mut Bencher) {
const SRC: &str = include_str!("module-2.json");
b.bytes = SRC.len() as _;
b.iter(|| test::black_box(serde_json::from_str::<Module>(SRC).unwrap()))
}

View File

@ -45,13 +45,19 @@ pub struct Class {
#[ast_node]
pub enum ClassMember {
#[tag("Constructor")]
Constructor(Constructor),
/// `es2015`
#[tag("ClassMethod")]
Method(ClassMethod),
#[tag("PrivateMethod")]
PrivateMethod(PrivateMethod),
/// stage 0 / Typescript
#[tag("ClassProperty")]
ClassProp(ClassProp),
#[tag("PrivateProperty")]
PrivateProp(PrivateProp),
#[tag("TsIndexSignature")]
TsIndexSignature(TsIndexSignature),
}

View File

@ -12,12 +12,19 @@ use swc_common::{ast_node, Span};
#[ast_node]
pub enum Decl {
#[tag("ClassDeclaration")]
Class(ClassDecl),
#[tag("FunctionDeclaration")]
Fn(FnDecl),
#[tag("VariableDeclaration")]
Var(VarDecl),
#[tag("TsInterfaceDeclaration")]
TsInterface(TsInterfaceDecl),
#[tag("TsTypeAliasDeclaration")]
TsTypeAlias(TsTypeAliasDecl),
#[tag("TsEnumDeclaration")]
TsEnum(TsEnumDecl),
#[tag("TsModuleDeclaration")]
TsModule(TsModuleDecl),
}

View File

@ -20,21 +20,29 @@ use swc_common::{ast_node, Span, Spanned, DUMMY_SP};
#[ast_node]
pub enum Expr {
#[tag("ThisExpression")]
This(ThisExpr),
#[tag("ArrayExpression")]
Array(ArrayLit),
#[tag("ObjectExpression")]
Object(ObjectLit),
#[tag("FunctionExpression")]
Fn(FnExpr),
#[tag("UnaryExpression")]
Unary(UnaryExpr),
/// `++v`, `--v`, `v++`, `v--`
#[tag("UpdateExpression")]
Update(UpdateExpr),
#[tag("BinaryExpression")]
Bin(BinExpr),
#[tag("AssignmentExpression")]
Assign(AssignExpr),
//
@ -48,56 +56,86 @@ pub enum Expr {
/// computed (a[b]) member expression and property is an Expression. If
/// computed is false, the node corresponds to a static (a.b) member
/// expression and property is an Identifier.
#[tag("MemberExpression")]
Member(MemberExpr),
/// true ? 'a' : 'b'
#[tag("ConditionalExpression")]
Cond(CondExpr),
#[tag("CallExpression")]
Call(CallExpr),
/// `new Cat()`
#[tag("NewExpression")]
New(NewExpr),
#[tag("SequenceExpression")]
Seq(SeqExpr),
#[tag("Identifier")]
Ident(Ident),
#[tag("StringLiteral")]
#[tag("BooleanLiteral")]
#[tag("NullLiteral")]
#[tag("NumericLiteral")]
#[tag("RegExpLiteral")]
#[tag("JSXText")]
Lit(Lit),
#[tag("TemplateLiteral")]
Tpl(Tpl),
#[tag("TaggedTemplateExpression")]
TaggedTpl(TaggedTpl),
#[tag("ArrowFunctionExpression")]
Arrow(ArrowExpr),
#[tag("ClassExpression")]
Class(ClassExpr),
#[tag("YieldExpression")]
Yield(YieldExpr),
#[tag("MetaProperty")]
MetaProp(MetaPropExpr),
#[tag("AwaitExpression")]
Await(AwaitExpr),
#[tag("ParenthesisExpression")]
Paren(ParenExpr),
#[tag("JSXMemberExpression")]
JSXMebmer(JSXMemberExpr),
#[tag("JSXNamespacedName")]
JSXNamespacedName(JSXNamespacedName),
#[tag("JSXEmptyExpression")]
JSXEmpty(JSXEmptyExpr),
#[tag("JSXElement")]
JSXElement(JSXElement),
#[tag("JSXFragment")]
JSXFragment(JSXFragment),
#[tag("TsTypeAssertion")]
TsTypeAssertion(TsTypeAssertion),
#[tag("TsNonNullExpression")]
TsNonNull(TsNonNullExpr),
#[tag("TsTypeCastExpression")]
TsTypeCast(TsTypeCastExpr),
#[tag("TsAsExpression")]
TsAs(TsAsExpr),
#[tag("PrivateName")]
PrivateName(PrivateName),
}
@ -130,9 +168,12 @@ pub struct ObjectLit {
#[ast_node]
pub enum PropOrSpread {
Prop(Box<Prop>),
/// Spread properties, e.g., `{a: 1, ...obj, b: 2}`.
#[tag("SpreadElement")]
Spread(SpreadElement),
#[tag("*")]
Prop(Box<Prop>),
}
#[ast_node("SpreadElement")]
@ -403,8 +444,18 @@ pub struct ParenExpr {
#[ast_node]
#[allow(variant_size_differences)]
pub enum ExprOrSuper {
#[tag("Super")]
Super(Super),
#[tag("*")]
Expr(Box<Expr>),
Super(Span),
}
#[ast_node("Super")]
#[derive(Copy)]
pub struct Super {
#[serde(default)]
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -429,14 +480,53 @@ impl Spanned for ExprOrSpread {
#[ast_node]
#[allow(variant_size_differences)]
pub enum BlockStmtOrExpr {
#[tag("BlockStatement")]
BlockStmt(BlockStmt),
#[tag("*")]
Expr(Box<Expr>),
}
#[ast_node]
pub enum PatOrExpr {
// order is important for proper deserialization.
#[tag("ThisExpression")]
#[tag("ArrayExpression")]
#[tag("ObjectExpression")]
#[tag("FunctionExpression")]
#[tag("UnaryExpression")]
#[tag("UpdateExpression")]
#[tag("BinaryExpression")]
#[tag("AssignmentExpression")]
#[tag("MemberExpression")]
#[tag("ConditionalExpression")]
#[tag("CallExpression")]
#[tag("NewExpression")]
#[tag("SequenceExpression")]
#[tag("StringLiteral")]
#[tag("BooleanLiteral")]
#[tag("NullLiteral")]
#[tag("NumericLiteral")]
#[tag("RegExpLiteral")]
#[tag("JSXText")]
#[tag("TemplateLiteral")]
#[tag("TaggedTemplateLiteral")]
#[tag("ArrowFunctionExpression")]
#[tag("ClassExpression")]
#[tag("YieldExpression")]
#[tag("MetaProperty")]
#[tag("AwaitExpression")]
#[tag("ParenthesisExpression")]
#[tag("JSXMemberExpression")]
#[tag("JSXNamespacedName")]
#[tag("JSXEmptyExpression")]
#[tag("JSXElement")]
#[tag("JSXFragment")]
#[tag("TsTypeAssertion")]
#[tag("TsNonNullExpression")]
#[tag("TsTypeCastExpression")]
#[tag("TsAsExpression")]
#[tag("PrivateName")]
Expr(Box<Expr>),
#[tag("*")]
Pat(Box<Pat>),
}

View File

@ -43,6 +43,8 @@ pub struct Function {
#[ast_node]
pub enum PatOrTsParamProp {
Pat(Pat),
#[tag("TsParameterProperty")]
TsParamProp(TsParamProp),
#[tag("*")]
Pat(Pat),
}

View File

@ -11,7 +11,9 @@ use swc_common::{ast_node, Span};
#[ast_node]
#[allow(variant_size_differences)]
pub enum JSXObject {
#[tag("JSXMemberExpression")]
JSXMemberExpr(Box<JSXMemberExpr>),
#[tag("Identifier")]
Ident(Ident),
}
@ -53,7 +55,9 @@ pub struct JSXExprContainer {
#[ast_node]
#[allow(variant_size_differences)]
pub enum JSXExpr {
#[tag("JSXEmptyExpression")]
JSXEmptyExpr(JSXEmptyExpr),
#[tag("*")]
Expr(Box<Expr>),
}
@ -66,8 +70,11 @@ pub struct JSXSpreadChild {
#[ast_node]
pub enum JSXElementName {
#[tag("Identifier")]
Ident(Ident),
#[tag("JSXMemberExpression")]
JSXMemberExpr(JSXMemberExpr),
#[tag("JSXNamespacedName")]
JSXNamespacedName(JSXNamespacedName),
}
@ -97,7 +104,9 @@ pub struct JSXOpeningElement {
#[ast_node]
#[allow(variant_size_differences)]
pub enum JSXAttrOrSpread {
#[tag("JSXAttribute")]
JSXAttr(JSXAttr),
#[tag("SpreadElement")]
SpreadElement(SpreadElement),
}
@ -120,15 +129,29 @@ pub struct JSXAttr {
#[ast_node]
pub enum JSXAttrName {
#[tag("Identifier")]
Ident(Ident),
#[tag("JSXNamespacedName")]
JSXNamespacedName(JSXNamespacedName),
}
#[ast_node]
pub enum JSXAttrValue {
#[tag("StringLiteral")]
#[tag("BooleanLiteral")]
#[tag("NullLiteral")]
#[tag("NumericLiteral")]
#[tag("RegExpLiteral")]
#[tag("JSXText")]
Lit(Lit),
#[tag("JSXExpressionContainer")]
JSXExprContainer(JSXExprContainer),
#[tag("JSXElement")]
JSXElement(Box<JSXElement>),
#[tag("JSXFragment")]
JSXFragment(JSXFragment),
}
@ -151,10 +174,19 @@ pub struct JSXElement {
#[ast_node]
pub enum JSXElementChild {
#[tag("JSXText")]
JSXText(JSXText),
#[tag("JSXExpressionContainer")]
JSXExprContainer(JSXExprContainer),
#[tag("JSXSpreadChild")]
JSXSpreadChild(JSXSpreadChild),
#[tag("JSXElement")]
JSXElement(Box<JSXElement>),
#[tag("JSXFragment")]
JSXFragment(JSXFragment),
}

View File

@ -24,8 +24,8 @@ pub use self::{
expr::{
ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr, CallExpr, ClassExpr,
CondExpr, Expr, ExprOrSpread, ExprOrSuper, FnExpr, MemberExpr, MetaPropExpr, NewExpr,
ObjectLit, ParenExpr, PatOrExpr, PropOrSpread, SeqExpr, SpreadElement, TaggedTpl, ThisExpr,
Tpl, TplElement, UnaryExpr, UpdateExpr, YieldExpr,
ObjectLit, ParenExpr, PatOrExpr, PropOrSpread, SeqExpr, SpreadElement, Super, TaggedTpl,
ThisExpr, Tpl, TplElement, UnaryExpr, UpdateExpr, YieldExpr,
},
function::{Function, PatOrTsParamProp},
ident::{Ident, IdentExt, PrivateName},

View File

@ -5,16 +5,22 @@ use swc_common::{ast_node, Span};
#[ast_node]
pub enum Lit {
#[tag("StringLiteral")]
Str(Str),
#[tag("BooleanLiteral")]
Bool(Bool),
#[tag("NullLiteral")]
Null(Null),
#[tag("NumericLiteral")]
Num(Number),
#[tag("RegExpLiteral")]
Regex(Regex),
#[tag("JSXText")]
JSXText(JSXText),
}

View File

@ -34,8 +34,18 @@ pub struct Script {
#[ast_node]
pub enum ModuleItem {
Stmt(Stmt),
#[tag("ImportDeclaration")]
#[tag("ExportDeclaration")]
#[tag("ExportNamedDeclaration")]
#[tag("ExportDefaultDeclaration")]
#[tag("ExportDefaultExpression")]
#[tag("ExportAllDeclaration")]
#[tag("TsImportEqualsDeclaration")]
#[tag("TsExportAssignment")]
#[tag("TsNamespaceExportDeclaration")]
ModuleDecl(ModuleDecl),
#[tag("*")]
Stmt(Stmt),
}
// This test ensures that FnDecl can be deserialized if type field is present

View File

@ -9,16 +9,31 @@ use swc_common::{ast_node, Span};
#[ast_node]
pub enum ModuleDecl {
#[tag("ImportDeclaration")]
Import(ImportDecl),
#[tag("ExportDeclaration")]
ExportDecl(ExportDecl),
#[tag("ExportNamedDeclaration")]
ExportNamed(NamedExport),
#[tag("ExportDefaultDeclaration")]
ExportDefaultDecl(ExportDefaultDecl),
#[tag("ExportDefaultExpression")]
ExportDefaultExpr(ExportDefaultExpr),
#[tag("ExportAllDeclaration")]
ExportAll(ExportAll),
#[tag("TsImportEqualsDeclaration")]
TsImportEquals(TsImportEqualsDecl),
#[tag("TsExportAssignment")]
TsExportAssignment(TsExportAssignment),
#[tag("TsNamespaceExportDeclaration")]
TsNamespaceExport(TsNamespaceExportDecl),
}
@ -85,17 +100,23 @@ pub struct ExportDefaultDecl {
#[ast_node]
pub enum DefaultDecl {
#[tag("ClassExpression")]
Class(ClassExpr),
#[tag("FunctionExpression")]
Fn(FnExpr),
#[tag("TsInterfaceDeclaration")]
TsInterfaceDecl(TsInterfaceDecl),
}
#[ast_node]
pub enum ImportSpecifier {
#[tag("ImportSpecifier")]
Specific(ImportSpecific),
#[tag("ImportDefaultSpecifier")]
Default(ImportDefault),
#[tag("ImportNamespaceSpecifier")]
Namespace(ImportStarAs),
}
@ -131,10 +152,13 @@ pub struct ImportSpecific {
#[ast_node]
pub enum ExportSpecifier {
#[tag("ExportNamespaceSpecifer")]
Namespace(NamespaceExportSpecifier),
#[tag("ExportDefaultSpecifier")]
Default(DefaultExportSpecifier),
#[tag("ExportSpecifier")]
Named(NamedExportSpecifier),
}

View File

@ -3,17 +3,23 @@ use swc_common::{ast_node, Span};
#[ast_node]
pub enum Pat {
#[tag("Identifier")]
Ident(Ident),
#[tag("ArrayPattern")]
Array(ArrayPat),
#[tag("RestElement")]
Rest(RestPat),
#[tag("ObjectPattern")]
Object(ObjectPat),
#[tag("AssignmentPattern")]
Assign(AssignPat),
/// Only for for-in / for-of loops. This is *syntatically* valid.
#[tag("*")]
Expr(Box<Expr>),
}
@ -87,8 +93,13 @@ pub struct RestPat {
#[ast_node]
pub enum ObjectPatProp {
#[tag("KeyValuePatternProperty")]
KeyValue(KeyValuePatProp),
#[tag("AssignmentPatternProperty")]
Assign(AssignPatProp),
#[tag("RestElement")]
Rest(RestPat),
}

View File

@ -11,14 +11,24 @@ use swc_common::{ast_node, Span};
#[ast_node]
pub enum Prop {
/// `a` in `{ a, }`
#[tag("Identifier")]
Shorthand(Ident),
/// `key: value` in `{ key: value, }`
#[tag("KeyValueProperty")]
KeyValue(KeyValueProp),
/// This is **invalid** for object literal.
#[tag("AssignmentProperty")]
Assign(AssignProp),
#[tag("GetterProperty")]
Getter(GetterProp),
#[tag("SetterProperty")]
Setter(SetterProp),
#[tag("MethodProperty")]
Method(MethodProp),
}
@ -67,10 +77,14 @@ pub struct MethodProp {
#[ast_node]
pub enum PropName {
#[tag("Identifier")]
Ident(Ident),
/// String literal.
#[tag("StringLiteral")]
Str(Str),
/// Numeric literal.
#[tag("NumericLiteral")]
Num(Number),
#[tag("*")]
Computed(Box<Expr>),
}

View File

@ -18,44 +18,69 @@ pub struct BlockStmt {
#[ast_node]
pub enum Stmt {
Expr(Box<Expr>),
#[tag("BlockStatement")]
Block(BlockStmt),
#[tag("EmptyStatement")]
Empty(EmptyStmt),
#[tag("DebuggerStatement")]
Debugger(DebuggerStmt),
#[tag("WithStatement")]
With(WithStmt),
#[tag("ReturnStatement")]
Return(ReturnStmt),
#[tag("LabeledStatement")]
Labeled(LabeledStmt),
#[tag("BreakStatement")]
Break(BreakStmt),
#[tag("ContinueStatement")]
Continue(ContinueStmt),
#[tag("IfStatement")]
If(IfStmt),
#[tag("SwitchStatement")]
Switch(SwitchStmt),
#[tag("ThrowStatement")]
Throw(ThrowStmt),
/// A try statement. If handler is null then finalizer must be a BlockStmt.
#[tag("TryStatement")]
Try(TryStmt),
#[tag("WhileStatement")]
While(WhileStmt),
#[tag("DoWhileStatement")]
DoWhile(DoWhileStmt),
#[tag("ForStatement")]
For(ForStmt),
#[tag("ForInStatement")]
ForIn(ForInStmt),
#[tag("ForOfStatement")]
ForOf(ForOfStmt),
#[tag("ClassDeclaration")]
#[tag("FunctionDeclaration")]
#[tag("VariableDeclaration")]
#[tag("TsInterfaceDeclaration")]
#[tag("TsTypeAliasDeclaration")]
#[tag("TsEnumDeclaration")]
#[tag("TsModuleDeclaration")]
Decl(Decl),
#[tag("*")]
Expr(Box<Expr>),
}
#[ast_node("EmptyStatement")]
@ -244,13 +269,19 @@ pub struct CatchClause {
#[ast_node]
pub enum VarDeclOrPat {
#[tag("VariableDeclaration")]
VarDecl(VarDecl),
#[tag("*")]
Pat(Pat),
}
#[ast_node]
#[allow(variant_size_differences)]
pub enum VarDeclOrExpr {
#[tag("VariableDeclaration")]
VarDecl(VarDecl),
#[tag("*")]
Expr(Box<Expr>),
}

View File

@ -77,7 +77,10 @@ pub struct TsParamProp {
#[ast_node]
pub enum TsParamPropParam {
#[tag("Identifier")]
Ident(Ident),
#[tag("AssignmentPattern")]
Assign(AssignPat),
}
@ -92,16 +95,28 @@ pub struct TsQualifiedName {
#[ast_node]
#[allow(variant_size_differences)]
pub enum TsEntityName {
#[tag("TsQualifiedName")]
TsQualifiedName(Box<TsQualifiedName>),
#[tag("Identifier")]
Ident(Ident),
}
#[ast_node]
pub enum TsSignatureDecl {
#[tag("TsCallSignatureDeclaration")]
TsCallSignatureDecl(TsCallSignatureDecl),
#[tag("TsConstructSignatureDeclaration")]
TsConstructSignatureDecl(TsConstructSignatureDecl),
#[tag("TsMethodSignature")]
TsMethodSignature(TsMethodSignature),
#[tag("TsFunctionType")]
TsFnType(TsFnType),
#[tag("TsConstructorType")]
TsConstructorType(TsConstructorType),
}
@ -111,10 +126,19 @@ pub enum TsSignatureDecl {
#[ast_node]
pub enum TsTypeElement {
#[tag("TsCallSignatureDeclaration")]
TsCallSignatureDecl(TsCallSignatureDecl),
#[tag("TsConstructSignatureDeclaration")]
TsConstructSignatureDecl(TsConstructSignatureDecl),
#[tag("TsPropertySignature")]
TsPropertySignature(TsPropertySignature),
#[tag("TsMethodSignature")]
TsMethodSignature(TsMethodSignature),
#[tag("TsIndexSignature")]
TsIndexSignature(TsIndexSignature),
}
@ -205,30 +229,71 @@ pub struct TsIndexSignature {
#[ast_node]
pub enum TsType {
#[tag("TsKeywordType")]
TsKeywordType(TsKeywordType),
#[tag("TsThisType")]
TsThisType(TsThisType),
#[tag("TsFunctionType")]
#[tag("TsConstructorType")]
TsFnOrConstructorType(TsFnOrConstructorType),
#[tag("TsTypeReference")]
TsTypeRef(TsTypeRef),
#[tag("TsTypeQuery")]
TsTypeQuery(TsTypeQuery),
#[tag("TsTypeLiteral")]
TsTypeLit(TsTypeLit),
#[tag("TsArrayType")]
TsArrayType(TsArrayType),
#[tag("TsTupleType")]
TsTupleType(TsTupleType),
#[tag("TsOptionalType")]
TsOptionalType(TsOptionalType),
#[tag("TsRestType")]
TsRestType(TsRestType),
#[tag("TsUnionType")]
#[tag("TsIntersectionType")]
TsUnionOrIntersectionType(TsUnionOrIntersectionType),
#[tag("TsConditionalType")]
TsConditionalType(TsConditionalType),
#[tag("TsInferType")]
TsInferType(TsInferType),
#[tag("TsParenthesizedType")]
TsParenthesizedType(TsParenthesizedType),
#[tag("TsTypeOperator")]
TsTypeOperator(TsTypeOperator),
#[tag("TsIndexedAccessType")]
TsIndexedAccessType(TsIndexedAccessType),
#[tag("TsMappedType")]
TsMappedType(TsMappedType),
#[tag("TsLiteralType")]
TsLitType(TsLitType),
#[tag("TsTypePredicate")]
TsTypePredicate(TsTypePredicate),
}
#[ast_node]
pub enum TsFnOrConstructorType {
#[tag("TsFunctionType")]
TsFnType(TsFnType),
#[tag("TsConstructorType")]
TsConstructorType(TsConstructorType),
}
@ -311,8 +376,13 @@ pub struct TsThisType {
#[ast_node]
pub enum TsFnParam {
#[tag("Identifier")]
Ident(Ident),
#[tag("RestElement")]
Rest(RestPat),
#[tag("ObjectPattern")]
Object(ObjectPat),
}
@ -360,7 +430,10 @@ pub struct TsTypePredicate {
#[ast_node]
#[allow(variant_size_differences)]
pub enum TsThisTypeOrIdent {
#[tag("TsThisType")]
TsThisType(TsThisType),
#[tag("Identifier")]
Ident(Ident),
}
@ -411,7 +484,10 @@ pub struct TsRestType {
#[ast_node]
pub enum TsUnionOrIntersectionType {
#[tag("TsUnionType")]
TsUnionType(TsUnionType),
#[tag("TsIntersectionType")]
TsIntersectionType(TsIntersectionType),
}
@ -570,8 +646,13 @@ pub struct TsLitType {
#[ast_node]
pub enum TsLit {
#[tag("NumericLiteral")]
Number(Number),
#[tag("StringLiteral")]
Str(Str),
#[tag("BooleanLiteral")]
Bool(Bool),
}
@ -641,7 +722,10 @@ pub struct TsEnumMember {
#[ast_node]
pub enum TsEnumMemberId {
#[tag("Identifier")]
Ident(Ident),
#[tag("StringLiteral")]
Str(Str),
}
@ -661,7 +745,10 @@ pub struct TsModuleDecl {
/// its body.
#[ast_node]
pub enum TsNamespaceBody {
#[tag("TsModuleBlock")]
TsModuleBlock(TsModuleBlock),
#[tag("TsNamespaceDeclaration")]
TsNamespaceDecl(TsNamespaceDecl),
}
@ -685,7 +772,10 @@ pub struct TsNamespaceDecl {
#[ast_node]
pub enum TsModuleName {
#[tag("Identifier")]
Ident(Ident),
#[tag("StringLiteral")]
Str(Str),
}
@ -701,7 +791,11 @@ pub struct TsImportEqualsDecl {
#[ast_node]
pub enum TsModuleRef {
#[tag("TsQualifiedName")]
#[tag("Identifier")]
TsEntityName(TsEntityName),
#[tag("TsExternalModuleReference")]
TsExternalModuleRef(TsExternalModuleRef),
}

View File

@ -422,9 +422,13 @@ impl<'a> Emitter<'a> {
pub fn emit_expr_or_super(&mut self, node: &ExprOrSuper) -> Result {
match *node {
ExprOrSuper::Expr(ref e) => emit!(e),
ExprOrSuper::Super(span) => keyword!(span, "super"),
ExprOrSuper::Super(ref n) => emit!(n),
}
}
#[emitter]
pub fn emit_super(&mut self, node: &Super) -> Result {
keyword!(node.span, "super");
}
#[emitter]
pub fn emit_expr(&mut self, node: &Expr) -> Result {

View File

@ -423,7 +423,7 @@ impl<'a, I: Input> Parser<'a, I> {
}
if eat!("super") {
let base = ExprOrSuper::Super(span!(start));
let base = ExprOrSuper::Super(Super { span: span!(start) });
return self.parse_subscripts(base, true);
}
let obj = self.parse_primary_expr()?;
@ -925,7 +925,7 @@ impl<'a, I: Input> Parser<'a, I> {
// `super()` can't be handled from parse_new_expr()
if eat!("super") {
let obj = ExprOrSuper::Super(span!(start));
let obj = ExprOrSuper::Super(Super { span: span!(start) });
return self.parse_subscripts(obj, false);
}
@ -1161,7 +1161,9 @@ impl<'a, I: Input> Parser<'a, I> {
#[ast_node]
pub(in crate::parser) enum PatOrExprOrSpread {
#[tag("*")]
Pat(Pat),
#[tag("*")]
ExprOrSpread(ExprOrSpread),
}

View File

@ -103,7 +103,10 @@ impl<'a> Fold<Expr> for SuperCalleeFolder<'a> {
prefix,
}) => match *arg {
Expr::Member(MemberExpr {
obj: ExprOrSuper::Super(super_token),
obj:
ExprOrSuper::Super(Super {
span: super_token, ..
}),
prop,
..
}) => {
@ -139,12 +142,18 @@ impl<'a> Fold<Expr> for SuperCalleeFolder<'a> {
right,
}) => match left {
PatOrExpr::Expr(box Expr::Member(MemberExpr {
obj: ExprOrSuper::Super(super_token),
obj:
ExprOrSuper::Super(Super {
span: super_token, ..
}),
prop,
..
}))
| PatOrExpr::Pat(box Pat::Expr(box Expr::Member(MemberExpr {
obj: ExprOrSuper::Super(super_token),
obj:
ExprOrSuper::Super(Super {
span: super_token, ..
}),
prop,
..
}))) => self.super_to_set_call(super_token, false, prop, op, right),
@ -160,7 +169,10 @@ impl<'a> Fold<Expr> for SuperCalleeFolder<'a> {
match n {
Expr::Member(MemberExpr {
obj: ExprOrSuper::Super(super_token),
obj:
ExprOrSuper::Super(Super {
span: super_token, ..
}),
prop,
computed,
..

View File

@ -85,7 +85,7 @@ impl Fold<Expr> for ActualFolder {
}
let (this, callee) = match *callee {
Expr::Member(MemberExpr {
obj: ExprOrSuper::Super(span),
obj: ExprOrSuper::Super(Super { span, .. }),
..
}) => (box Expr::This(ThisExpr { span }), callee),

View File

@ -258,7 +258,7 @@ impl Decorators {
vec![
Stmt::Expr(box Expr::Call(CallExpr {
span: DUMMY_SP,
callee: ExprOrSuper::Super(DUMMY_SP),
callee: ExprOrSuper::Super(Super { span: DUMMY_SP }),
args: vec![ExprOrSpread {
spread: Some(DUMMY_SP),
expr: box Expr::Ident(quote_ident!("args")),

View File

@ -841,7 +841,7 @@ pub fn default_constructor(has_super: bool) -> Constructor {
stmts: if has_super {
vec![Stmt::Expr(box Expr::Call(CallExpr {
span: DUMMY_SP,
callee: ExprOrSuper::Super(DUMMY_SP),
callee: ExprOrSuper::Super(Super { span: DUMMY_SP }),
args: vec![ExprOrSpread {
spread: Some(DUMMY_SP),
expr: box Expr::Ident(quote_ident!(span, "args")),

View File

@ -28,5 +28,5 @@ features = ["derive", "fold", "parsing", "printing"]
[dev-dependencies]
swc_common = { version = "0.3", path = "../../common" }
swc_common = { version = "0.3", path = "../../common", features = ["fold"] }
serde = { version = "1", features = ["derive"] }

View File

@ -17,7 +17,181 @@ impl Parse for Args {
}
}
pub fn expand(args: Args, i: DeriveInput) -> Vec<ItemImpl> {
struct VariantAttr {
_paren_token: token::Paren,
tags: Punctuated<Lit, Token![,]>,
}
impl Parse for VariantAttr {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
Ok(VariantAttr {
_paren_token: parenthesized!(content in input),
tags: content.parse_terminated(Lit::parse)?,
})
}
}
pub fn expand_enum(
DeriveInput {
generics,
ident,
data,
..
}: DeriveInput,
) -> Vec<ItemImpl> {
let data = match data {
Data::Enum(data) => data,
_ => unreachable!("expand_enum is called with none-enum item"),
};
let deserialize = {
let mut all_tags: Punctuated<_, token::Comma> = Default::default();
let mut match_type = data
.variants
.iter()
.map(|variant| {
let field_type = match variant.fields {
Fields::Unnamed(ref fields) => {
assert!(
fields.unnamed.len() == 1,
"#[ast_node] enum cannot contain variant with multiple fields"
);
fields.unnamed.last().unwrap().into_value().ty.clone()
}
_ => {
unreachable!("#[ast_node] enum cannot contain named fields or unit variant")
}
};
let tags = variant
.attrs
.iter()
.filter_map(|attr| -> Option<VariantAttr> {
if !is_attr_name(attr, "tag") {
return None;
}
let tags =
parse2(attr.tts.clone()).expect("failed to parse #[tag] attribute");
Some(tags)
})
.flat_map(|v| v.tags)
.collect::<Punctuated<_, token::Comma>>();
assert!(
tags.len() >= 1,
"All #[ast_node] enum variants have one or more tag"
);
if tags.len() == 1
&& match tags.first().map(Pair::into_value) {
Some(Lit::Str(s)) => &*s.value() == "*",
_ => false,
}
{
Quote::new_call_site()
.quote_with(smart_quote!(
Vars {
Enum: &ident,
Variant: &variant.ident,
VariantFieldType: &field_type,
},
{
if let Ok(v) = std::result::Result::map(
<VariantFieldType as serde::Deserialize>::deserialize(
serde::private::de::ContentRefDeserializer::<D::Error>::new(
&content,
),
),
Enum::Variant,
) {
return Ok(v);
}
}
))
.parse()
} else {
for tag in tags.iter() {
all_tags.push(tag.clone());
}
Quote::new_call_site()
.quote_with(smart_quote!(
Vars {
Enum: &ident,
Variant: &variant.ident,
VariantFieldType: &field_type,
tags,
},
{
{
const TAGS: &[&str] = &[tags];
if TAGS.contains(&&*ty.ty) {
if let Ok(v) = std::result::Result::map(
<VariantFieldType as serde::Deserialize>::deserialize(
serde::private::de::ContentRefDeserializer::<
D::Error,
>::new(
&content
),
),
Enum::Variant,
) {
return Ok(v);
}
}
}
}
))
.parse()
}
})
.collect::<Vec<Expr>>();
let mut match_type_expr = Quote::new_call_site();
for expr in match_type {
match_type_expr = match_type_expr.quote_with(smart_quote!(Vars { expr }, { expr }));
}
match_type_expr = match_type_expr.quote_with(smart_quote!(Vars { all_tags }, {
return Err(serde::de::Error::unknown_variant(&ty.ty, &[all_tags]));
}));
Quote::new_call_site()
.quote_with(smart_quote!(
Vars {
match_type_expr,
Enum: &ident
},
{
impl<'de> serde::Deserialize<'de> for Enum {
fn deserialize<D>(Deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let content =
<serde::private::de::Content as serde::Deserialize>::deserialize(
Deserializer,
)?;
let ty = swc_common::serializer::Type::deserialize(
serde::private::de::ContentRefDeserializer::<D::Error>::new(
&content,
),
)?;
match_type_expr
}
}
}
))
.parse::<ItemImpl>()
.with_generics(generics.clone())
};
vec![deserialize]
}
pub fn expand_struct(args: Args, i: DeriveInput) -> Vec<ItemImpl> {
let mut items = vec![];
let generics = i.generics.clone();
let item_ident = Ident::new("Item", i.ident.span());

View File

@ -82,6 +82,21 @@ pub fn derive_from_variant(input: proc_macro::TokenStream) -> proc_macro::TokenS
print("derive(FromVariant)", item.dump())
}
#[proc_macro_derive(DeserializeEnum, attributes(tag))]
pub fn derive_deserialize_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
let item =
ast_node_macro::expand_enum(input)
.into_iter()
.fold(TokenStream::new(), |mut t, item| {
item.to_tokens(&mut t);
t
});
print("derive(DeserializeEnum)", item.dump())
}
/// Alias for
/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq)]` for a struct and
/// `#[derive(Spanned, Fold, Clone, Debug, PartialEq, FromVariant)]` for an
@ -100,9 +115,10 @@ pub fn ast_node(
if !args.is_empty() {
panic!("#[ast_node] on enum does not accept any argument")
}
item.quote_with(smart_quote!(Vars { input }, {
#[derive(::swc_common::FromVariant, ::swc_common::Spanned, Clone, Debug, PartialEq)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
#[derive(::serde::Serialize, ::swc_common::DeserializeEnum)]
#[serde(untagged)]
#[cfg_attr(feature = "fold", derive(::swc_common::Fold))]
input
@ -138,7 +154,7 @@ pub fn ast_node(
});
let ast_node_impl = match args {
Some(ref args) => Some(ast_node_macro::expand(args.clone(), input.clone())),
Some(ref args) => Some(ast_node_macro::expand_struct(args.clone(), input.clone())),
None => None,
};

View File

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use swc_common::{ast_node, Fold, Span, Spanned};
#[ast_node]
#[derive(Deserialize)]
// See https://github.com/rust-lang/rust/issues/44925
pub struct Class {
#[span]
@ -14,9 +15,18 @@ pub struct Class {
}
#[ast_node]
#[derive(Deserialize)]
pub struct Tuple(#[span] HasSpan, #[fold(ignore)] usize, usize);
#[derive(Debug, Clone, PartialEq, Fold, Spanned, Serialize, Deserialize)]
pub struct HasSpan {
pub span: Span,
}
#[ast_node]
pub enum Node {
#[tag("Class")]
Class(Class),
#[tag("Tuple")]
Tuple(Tuple),
}