implement #[span]

This commit is contained in:
강동윤 2018-03-04 15:17:52 +09:00
parent 3321ca590d
commit 077e0c551f
16 changed files with 215 additions and 76 deletions

View File

@ -29,4 +29,8 @@ features = [ "suggestions", "color" ]
[profile.bench] [profile.bench]
debug = true debug = true
[patch.crates-io]
darling = { git = "https://github.com/kdy1/darling", branch = "proc-macro2-nightly" }

View File

@ -12,13 +12,14 @@ pub enum Decl {
#[ast_node] #[ast_node]
pub struct FnDecl { pub struct FnDecl {
pub ident: Ident, pub ident: Ident,
#[span]
pub function: Function, pub function: Function,
} }
#[ast_node] #[ast_node]
pub struct ClassDecl { pub struct ClassDecl {
pub ident: Ident, pub ident: Ident,
#[span]
pub class: Class, pub class: Class,
} }

View File

@ -1,6 +1,6 @@
use super::{AssignOp, BinaryOp, BlockStmt, Class, Function, Ident, Lit, Pat, Prop, UnaryOp, use super::{AssignOp, BinaryOp, BlockStmt, Class, Function, Ident, Lit, Pat, Prop, UnaryOp,
UpdateOp}; UpdateOp};
use swc_common::Span; use swc_common::{Span, Spanned};
use swc_macros::ast_node; use swc_macros::ast_node;
#[ast_node] #[ast_node]
@ -114,7 +114,7 @@ pub struct BinExpr {
#[ast_node] #[ast_node]
pub struct FnExpr { pub struct FnExpr {
pub ident: Option<Ident>, pub ident: Option<Ident>,
#[span]
pub function: Function, pub function: Function,
} }
@ -122,7 +122,7 @@ pub struct FnExpr {
#[ast_node] #[ast_node]
pub struct ClassExpr { pub struct ClassExpr {
pub ident: Option<Ident>, pub ident: Option<Ident>,
#[span]
pub class: Class, pub class: Class,
} }
@ -136,34 +136,42 @@ pub struct AssignExpr {
#[ast_node] #[ast_node]
pub struct MemberExpr { pub struct MemberExpr {
pub span: Span,
pub obj: ExprOrSuper, pub obj: ExprOrSuper,
pub prop: Box<Expr>, pub prop: Box<Expr>,
pub computed: bool, pub computed: bool,
} }
#[ast_node] #[ast_node]
pub struct CondExpr { pub struct CondExpr {
#[span(lo)]
pub test: Box<Expr>, pub test: Box<Expr>,
pub cons: Box<Expr>, pub cons: Box<Expr>,
#[span(hi)]
pub alt: Box<Expr>, pub alt: Box<Expr>,
} }
#[ast_node] #[ast_node]
pub struct CallExpr { pub struct CallExpr {
pub span: Span,
pub callee: ExprOrSuper, pub callee: ExprOrSuper,
pub args: Vec<ExprOrSpread>, pub args: Vec<ExprOrSpread>,
} }
#[ast_node] #[ast_node]
pub struct NewExpr { pub struct NewExpr {
pub span: Span,
pub callee: Box<Expr>, pub callee: Box<Expr>,
// #[code = "$( $( $args ),* )?"]
pub args: Option<(Vec<ExprOrSpread>)>, pub args: Option<(Vec<ExprOrSpread>)>,
} }
#[ast_node] #[ast_node]
pub struct SeqExpr { pub struct SeqExpr {
/// TODO: Calculate
pub span: Span,
pub exprs: Vec<(Box<Expr>)>, pub exprs: Vec<(Box<Expr>)>,
} }
#[ast_node] #[ast_node]
pub struct ArrowExpr { pub struct ArrowExpr {
pub span: Span,
pub params: Vec<Pat>, pub params: Vec<Pat>,
pub body: BlockStmtOrExpr, pub body: BlockStmtOrExpr,
@ -173,21 +181,26 @@ pub struct ArrowExpr {
#[ast_node] #[ast_node]
pub struct YieldExpr { pub struct YieldExpr {
pub span: Span,
pub arg: Option<(Box<Expr>)>, pub arg: Option<(Box<Expr>)>,
pub delegate: bool, pub delegate: bool,
} }
#[ast_node] #[ast_node]
pub struct MetaPropExpr { pub struct MetaPropExpr {
#[span(lo)]
pub meta: Ident, pub meta: Ident,
#[span(hi)]
pub prop: Ident, pub prop: Ident,
} }
#[ast_node] #[ast_node]
pub struct AwaitExpr { pub struct AwaitExpr {
pub span: Span,
pub arg: Box<Expr>, pub arg: Box<Expr>,
} }
#[ast_node] #[ast_node]
pub struct TplLit { pub struct TplLit {
pub span: Span,
pub tag: Option<(Box<Expr>)>, pub tag: Option<(Box<Expr>)>,
pub exprs: Vec<(Box<Expr>)>, pub exprs: Vec<(Box<Expr>)>,
@ -197,6 +210,7 @@ pub struct TplLit {
#[ast_node] #[ast_node]
pub struct TplElement { pub struct TplElement {
pub span: Span,
pub tail: bool, pub tail: bool,
pub cooked: bool, pub cooked: bool,
pub raw: String, pub raw: String,
@ -214,11 +228,20 @@ pub enum ExprOrSuper {
Expr(Box<Expr>), Expr(Box<Expr>),
} }
#[ast_node] #[derive(Fold, Clone, Debug, PartialEq)]
pub struct ExprOrSpread { pub struct ExprOrSpread {
pub spread: Option<Span>, pub spread: Option<Span>,
pub expr: Box<Expr>, pub expr: Box<Expr>,
} }
impl Spanned for ExprOrSpread {
fn span(&self) -> Span {
let expr = self.expr.span();
match self.spread {
Some(spread) => expr.with_lo(spread.lo()),
None => expr,
}
}
}
#[ast_node] #[ast_node]
pub enum BlockStmtOrExpr { pub enum BlockStmtOrExpr {

View File

@ -12,15 +12,18 @@ pub use self::class::{Class, ClassMethod, ClassMethodKind};
pub use self::decl::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator}; pub use self::decl::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator};
pub use self::expr::{ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr, pub use self::expr::{ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr,
CallExpr, ClassExpr, CondExpr, Expr, ExprOrSpread, ExprOrSuper, FnExpr, CallExpr, ClassExpr, CondExpr, Expr, ExprOrSpread, ExprOrSuper, FnExpr,
MemberExpr, MetaPropExpr, NewExpr, ObjectLit, PatOrExpr, SeqExpr, TplElement, MemberExpr, MetaPropExpr, NewExpr, ObjectLit, ParenExpr, PatOrExpr, SeqExpr,
TplLit, UnaryExpr, UpdateExpr, YieldExpr}; ThisExpr, TplElement, TplLit, UnaryExpr, UpdateExpr, YieldExpr};
pub use self::function::Function; pub use self::function::Function;
pub use self::lit::{Bool, Lit, Null, Number, Regex, RegexFlags, Str}; pub use self::lit::{Bool, Lit, Null, Number, Regex, RegexFlags, Str};
pub use self::module::{Module, ModuleItem}; pub use self::module::{Module, ModuleItem};
pub use self::module_decl::{ExportDefaultDecl, ExportSpecifier, ImportSpecifier, ModuleDecl}; pub use self::module_decl::{ExportAll, ExportDefaultDecl, ExportSpecifier, ImportDecl,
ImportDefault, ImportSpecific, ImportSpecifier, ImportStarAs,
ModuleDecl, NamedExport};
pub use self::operators::{AssignOp, BinaryOp, UnaryOp, UpdateOp}; pub use self::operators::{AssignOp, BinaryOp, UnaryOp, UpdateOp};
pub use self::pat::{ObjectPatProp, Pat}; pub use self::pat::{ArrayPat, AssignPat, AssignPatProp, KeyValuePatProp, ObjectPat, ObjectPatProp,
pub use self::prop::{Prop, PropName}; Pat};
pub use self::prop::{AssignProp, GetterProp, KeyValueProp, MethodProp, Prop, PropName, SetterProp};
pub use self::stmt::{BlockStmt, BreakStmt, CatchClause, ContinueStmt, DebuggerStmt, DoWhileStmt, pub use self::stmt::{BlockStmt, BreakStmt, CatchClause, ContinueStmt, DebuggerStmt, DoWhileStmt,
EmptyStmt, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt, EmptyStmt, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt,
Stmt, SwitchCase, SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr, Stmt, SwitchCase, SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr,

View File

@ -78,6 +78,7 @@ pub struct ImportSpecific {
#[ast_node] #[ast_node]
pub struct ExportSpecifier { pub struct ExportSpecifier {
pub span: Span,
/// `foo` in `export { foo as bar }` /// `foo` in `export { foo as bar }`
pub orig: Ident, pub orig: Ident,
/// `Some(bar)` in `export { foo as bar }` /// `Some(bar)` in `export { foo as bar }`

View File

@ -10,7 +10,7 @@ pub enum Pat {
Rest(Box<Pat>), Rest(Box<Pat>),
Object(Vec<ObjectPatProp>), Object(ObjectPat),
Assign(AssignPat), Assign(AssignPat),
@ -24,6 +24,12 @@ pub struct ArrayPat {
pub elems: Vec<(Option<Pat>)>, pub elems: Vec<(Option<Pat>)>,
} }
#[ast_node]
pub struct ObjectPat {
pub span: Span,
pub props: Vec<ObjectPatProp>,
}
#[ast_node] #[ast_node]
pub struct AssignPat { pub struct AssignPat {
pub span: Span, pub span: Span,
@ -40,12 +46,15 @@ pub enum ObjectPatProp {
/// `{key: value}` /// `{key: value}`
#[ast_node] #[ast_node]
pub struct KeyValuePatProp { pub struct KeyValuePatProp {
#[span(lo)]
pub key: PropName, pub key: PropName,
#[span(hi)]
pub value: Box<Pat>, pub value: Box<Pat>,
} }
/// `{key}` or `{key = value}` /// `{key}` or `{key = value}`
#[ast_node] #[ast_node]
pub struct AssignPatProp { pub struct AssignPatProp {
pub span: Span,
pub key: Ident, pub key: Ident,
pub value: Option<(Box<Expr>)>, pub value: Option<(Box<Expr>)>,

View File

@ -18,18 +18,18 @@ pub enum Prop {
#[ast_node] #[ast_node]
pub struct KeyValueProp { pub struct KeyValueProp {
// #[span(lo)] #[span(lo)]
pub key: PropName, pub key: PropName,
// #[span(hi)] #[span(hi)]
pub value: Box<Expr>, pub value: Box<Expr>,
} }
#[ast_node] #[ast_node]
pub struct AssignProp { pub struct AssignProp {
// #[span(lo)] #[span(lo)]
key: Ident, key: Ident,
// #[span(hi)] #[span(hi)]
value: Box<Expr>, value: Box<Expr>,
} }
#[ast_node] #[ast_node]
@ -47,9 +47,9 @@ pub struct SetterProp {
} }
#[ast_node] #[ast_node]
pub struct MethodProp { pub struct MethodProp {
// #[span(lo)] #[span(lo)]
key: PropName, key: PropName,
// #[span(hi)] #[span(hi)]
function: Function, function: Function,
} }

View File

@ -11,6 +11,7 @@ swc_macros_common = { path = "../common" }
pmutil = "0.1" pmutil = "0.1"
proc-macro2 = { version = "0.2", features = ["nightly"] } proc-macro2 = { version = "0.2", features = ["nightly"] }
quote = "0.4" quote = "0.4"
darling = "0.3"
[dependencies.syn] [dependencies.syn]
version = "0.12" version = "0.12"

View File

@ -1,5 +1,7 @@
#![feature(box_syntax, proc_macro)] #![feature(box_syntax, proc_macro)]
#[macro_use]
extern crate darling;
#[macro_use] #[macro_use]
extern crate pmutil; extern crate pmutil;
extern crate proc_macro; extern crate proc_macro;

View File

@ -1,5 +1,22 @@
use darling::FromField;
use swc_macros_common::prelude::*; use swc_macros_common::prelude::*;
#[derive(Debug, FromField)]
#[darling(attributes(span))]
struct MyField {
/// Name of the field.
pub ident: Option<Ident>,
/// Type of the field.
pub ty: Type,
/// `#[span(lo)]`
#[darling(default)]
pub lo: bool,
/// `#[span(hi)]`
#[darling(default)]
pub hi: bool,
}
pub fn derive(input: DeriveInput) -> ItemImpl { pub fn derive(input: DeriveInput) -> ItemImpl {
let arms = Binder::new_from(&input) let arms = Binder::new_from(&input)
.variants() .variants()
@ -53,6 +70,15 @@ pub fn derive(input: DeriveInput) -> ItemImpl {
} }
fn make_body_for_variant(v: &VariantBinder, bindings: Vec<BindedField>) -> Box<Expr> { fn make_body_for_variant(v: &VariantBinder, bindings: Vec<BindedField>) -> Box<Expr> {
/// `swc_common::Spanned::span(#field)`
fn simple_field(field: &ToTokens) -> Box<Expr> {
box Quote::new(Span::def_site())
.quote_with(smart_quote!(Vars { field }, {
swc_common::Spanned::span(field)
}))
.parse()
}
if bindings.len() == 0 { if bindings.len() == 0 {
panic!("#[derive(Spanned)] requires a field to get span from") panic!("#[derive(Spanned)] requires a field to get span from")
} }
@ -61,35 +87,75 @@ fn make_body_for_variant(v: &VariantBinder, bindings: Vec<BindedField>) -> Box<E
match *v.data() { match *v.data() {
Fields::Unnamed(..) => { Fields::Unnamed(..) => {
// Call self.0.span() // Call self.0.span()
return box Quote::new(Span::def_site()) return simple_field(&bindings[0]);
.quote_with(smart_quote!(
Vars {
field: &bindings[0],
},
{ swc_common::Spanned::span(field) }
))
.parse();
} }
_ => {} _ => {}
} }
} }
// TODO: Handle #[span] attribute. // Handle #[span] attribute.
if let Some(f) = bindings
let span_field = bindings
.iter() .iter()
.find(|b| { .find(|b| has_empty_span_attr(&b.field().attrs))
let s = b.field().ident.as_ref().map(|ident| ident.as_ref()); {
Some("span") == s //TODO: Verify that there's no more #[span]
}) return simple_field(f);
.unwrap_or_else(|| { }
panic!(
"#[derive(Spanned)]: cannot determine span field to use for {}",
v.qual_path().dump()
)
});
box Quote::new(Span::def_site()) // If all fields do not have `#[span(..)]`, check for field named `span`.
.quote_with(smart_quote!(Vars { span_field }, { span_field })) let has_any_span_attr = bindings
.parse() .iter()
.map(|b| {
b.field()
.attrs
.iter()
.any(|attr| is_attr_name(attr, "span"))
})
.any(|b| b);
if !has_any_span_attr {
let span_field = bindings
.iter()
.find(|b| Some("span") == b.field().ident.as_ref().map(|ident| ident.as_ref()))
.unwrap_or_else(|| {
panic!(
"#[derive(Spanned)]: cannot determine span field to use for {}",
v.qual_path().dump()
)
});
return simple_field(span_field);
}
let fields: Vec<_> = bindings
.iter()
.map(|b| (b, MyField::from_field(b.field()).unwrap()))
.collect();
// TODO: Only one field should be `#[span(lo)]`.
let lo = fields.iter().find(|&&(_, ref f)| f.lo);
let hi = fields.iter().find(|&&(_, ref f)| f.hi);
match (lo, hi) {
(Some(&(ref lo_field, _)), Some(&(ref hi_field, _))) => {
// Create a new span from lo_field.lo(), hi_field.hi()
box Quote::new(Span::def_site())
.quote_with(smart_quote!(Vars { lo_field, hi_field }, {
swc_common::Spanned::span(lo_field)
.with_hi(swc_common::Spanned::span(hi_field).hi())
}))
.parse()
}
_ => panic!("#[derive(Spanned)]: #[span(lo)] and #[span(hi)] is required"),
}
}
/// Search for `#[span]`
fn has_empty_span_attr(attrs: &[Attribute]) -> bool {
attrs.iter().any(|attr| {
if !is_attr_name(attr, "span") {
return false;
}
attr.tts.is_empty()
})
} }

View File

@ -0,0 +1,24 @@
//! Test that `#[span]` and `#[fold]` can be used at same time.
#![feature(proc_macro)]
extern crate swc_common;
extern crate swc_macros;
use swc_common::{Fold, Span, Spanned};
use swc_macros::ast_node;
#[ast_node]
// See https://github.com/rust-lang/rust/issues/44925
pub struct Class {
#[span]
pub has_span: HasSpan,
#[fold(ignore)]
pub s: String,
}
#[ast_node]
pub struct Tuple(#[span] HasSpan, #[fold(ignore)] usize, usize);
#[derive(Debug, Clone, PartialEq, Fold, Spanned)]
pub struct HasSpan {
pub span: Span,
}

View File

@ -1,15 +0,0 @@
#![feature(specialization, proc_macro)]
extern crate swc_common;
extern crate swc_macros;
use swc_macros::ast_node;
#[ast_node]
// See https://github.com/rust-lang/rust/issues/44925
pub struct Class {
#[fold(ignore)]
pub s: String,
}
#[ast_node]
pub struct Tuple(usize, usize);

View File

@ -1,12 +1,12 @@
#![feature(specialization, proc_macro)] #![feature(proc_macro)]
extern crate ast_node;
extern crate swc_common; extern crate swc_common;
extern crate swc_macros; use ast_node::*;
use swc_macros::ast_node;
#[ast_node] #[derive(Debug, Fold)]
pub struct Struct {} pub struct Struct {}
#[ast_node] #[derive(Debug, FromVariant, Fold)]
pub enum Enum { pub enum Enum {
} }

View File

@ -1,30 +1,29 @@
//! Ensures that #[derive(AstNode)] works with generic types. //! Ensures that #[derive(Fold)] works with generic types.
#![feature(specialization, proc_macro)] #![feature(specialization, proc_macro)]
extern crate swc_common; extern crate swc_common;
extern crate swc_macros; extern crate swc_macros;
use std::fmt::Debug; use std::fmt::Debug;
use swc_common::AstNode; use swc_common::{AstNode, Fold};
use swc_macros::ast_node;
pub trait Ast: Copy + Eq + Debug { pub trait Ast: Copy + Eq + Debug {
type CustomExpr: AstNode; type CustomExpr: AstNode;
} }
#[ast_node] #[derive(Fold)]
pub struct Stmt<A: Ast> { pub struct Stmt<A: Ast> {
#[fold(bound)] #[fold(bound)]
pub expr: Expr<A>, pub expr: Expr<A>,
} }
#[ast_node] #[derive(Fold)]
pub struct Expr<A: Ast> { pub struct Expr<A: Ast> {
#[fold(bound)] #[fold(bound)]
pub node: ExprKind<A>, pub node: ExprKind<A>,
} }
#[ast_node] #[derive(Fold)]
pub enum ExprKind<A: Ast> { pub enum ExprKind<A: Ast> {
Custom(#[fold(bound)] A::CustomExpr), Custom(#[fold(bound)] A::CustomExpr),
/// Recursive /// Recursive

View File

@ -2,15 +2,14 @@
extern crate swc_common; extern crate swc_common;
extern crate swc_macros; extern crate swc_macros;
use swc_common::{FoldWith, Folder}; use swc_common::{Fold, FoldWith};
use swc_macros::ast_node;
pub trait AssertFolder<T>: Folder<T> {} pub trait AssertFolder<T>: Fold<T> {}
// check for trait bound // check for trait bound
pub struct LitFolder; pub struct LitFolder;
impl Folder<Lit> for LitFolder { impl Fold<Lit> for LitFolder {
fn fold(&mut self, _: Lit) -> Lit { fn fold(&mut self, _: Lit) -> Lit {
Lit::A Lit::A
} }
@ -18,7 +17,7 @@ impl Folder<Lit> for LitFolder {
impl AssertFolder<Expr> for LitFolder {} impl AssertFolder<Expr> for LitFolder {}
impl AssertFolder<ExprKind> for LitFolder {} impl AssertFolder<ExprKind> for LitFolder {}
#[ast_node] #[derive(Debug, Fold, PartialEq, Eq)]
pub struct Expr { pub struct Expr {
pub node: ExprKind, pub node: ExprKind,
/// This field should be skipped. /// This field should be skipped.
@ -40,7 +39,7 @@ impl<F> FoldWith<F> for PanicOnFold {
} }
} }
#[ast_node] #[derive(Debug, Fold, PartialEq, Eq)]
pub enum ExprKind { pub enum ExprKind {
RecursiveBoud(Box<Expr>), RecursiveBoud(Box<Expr>),
Rec2(Vec<Option<Box<Expr>>>), Rec2(Vec<Option<Box<Expr>>>),
@ -48,7 +47,7 @@ pub enum ExprKind {
Lit(Lit), Lit(Lit),
} }
#[ast_node] #[derive(Debug, Fold, PartialEq, Eq)]
pub enum Lit { pub enum Lit {
A, A,
B, B,

View File

@ -0,0 +1,22 @@
#![feature(proc_macro)]
extern crate swc_common;
use swc_common::{BytePos, Span, Spanned};
#[test]
fn lo_hi() {
#[derive(Spanned)]
struct LoHi {
#[span(lo)]
pub lo: BytePos,
#[span(hi)]
pub hi: BytePos,
}
let lo = BytePos(0);
let hi = BytePos(5);
assert_eq!(
LoHi { lo, hi }.span(),
Span::new(lo, hi, Default::default())
);
}