mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
implement #[span]
This commit is contained in:
parent
3321ca590d
commit
077e0c551f
@ -30,3 +30,7 @@ features = [ "suggestions", "color" ]
|
||||
|
||||
[profile.bench]
|
||||
debug = true
|
||||
|
||||
|
||||
[patch.crates-io]
|
||||
darling = { git = "https://github.com/kdy1/darling", branch = "proc-macro2-nightly" }
|
@ -12,13 +12,14 @@ pub enum Decl {
|
||||
#[ast_node]
|
||||
pub struct FnDecl {
|
||||
pub ident: Ident,
|
||||
#[span]
|
||||
pub function: Function,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct ClassDecl {
|
||||
pub ident: Ident,
|
||||
|
||||
#[span]
|
||||
pub class: Class,
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{AssignOp, BinaryOp, BlockStmt, Class, Function, Ident, Lit, Pat, Prop, UnaryOp,
|
||||
UpdateOp};
|
||||
use swc_common::Span;
|
||||
use swc_common::{Span, Spanned};
|
||||
use swc_macros::ast_node;
|
||||
|
||||
#[ast_node]
|
||||
@ -114,7 +114,7 @@ pub struct BinExpr {
|
||||
#[ast_node]
|
||||
pub struct FnExpr {
|
||||
pub ident: Option<Ident>,
|
||||
|
||||
#[span]
|
||||
pub function: Function,
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ pub struct FnExpr {
|
||||
#[ast_node]
|
||||
pub struct ClassExpr {
|
||||
pub ident: Option<Ident>,
|
||||
|
||||
#[span]
|
||||
pub class: Class,
|
||||
}
|
||||
|
||||
@ -136,34 +136,42 @@ pub struct AssignExpr {
|
||||
|
||||
#[ast_node]
|
||||
pub struct MemberExpr {
|
||||
pub span: Span,
|
||||
pub obj: ExprOrSuper,
|
||||
pub prop: Box<Expr>,
|
||||
pub computed: bool,
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct CondExpr {
|
||||
#[span(lo)]
|
||||
pub test: Box<Expr>,
|
||||
pub cons: Box<Expr>,
|
||||
#[span(hi)]
|
||||
pub alt: Box<Expr>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct CallExpr {
|
||||
pub span: Span,
|
||||
pub callee: ExprOrSuper,
|
||||
pub args: Vec<ExprOrSpread>,
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct NewExpr {
|
||||
pub span: Span,
|
||||
pub callee: Box<Expr>,
|
||||
// #[code = "$( $( $args ),* )?"]
|
||||
pub args: Option<(Vec<ExprOrSpread>)>,
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct SeqExpr {
|
||||
/// TODO: Calculate
|
||||
pub span: Span,
|
||||
pub exprs: Vec<(Box<Expr>)>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct ArrowExpr {
|
||||
pub span: Span,
|
||||
pub params: Vec<Pat>,
|
||||
|
||||
pub body: BlockStmtOrExpr,
|
||||
@ -173,21 +181,26 @@ pub struct ArrowExpr {
|
||||
|
||||
#[ast_node]
|
||||
pub struct YieldExpr {
|
||||
pub span: Span,
|
||||
pub arg: Option<(Box<Expr>)>,
|
||||
pub delegate: bool,
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct MetaPropExpr {
|
||||
#[span(lo)]
|
||||
pub meta: Ident,
|
||||
#[span(hi)]
|
||||
pub prop: Ident,
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct AwaitExpr {
|
||||
pub span: Span,
|
||||
pub arg: Box<Expr>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct TplLit {
|
||||
pub span: Span,
|
||||
pub tag: Option<(Box<Expr>)>,
|
||||
|
||||
pub exprs: Vec<(Box<Expr>)>,
|
||||
@ -197,6 +210,7 @@ pub struct TplLit {
|
||||
|
||||
#[ast_node]
|
||||
pub struct TplElement {
|
||||
pub span: Span,
|
||||
pub tail: bool,
|
||||
pub cooked: bool,
|
||||
pub raw: String,
|
||||
@ -214,11 +228,20 @@ pub enum ExprOrSuper {
|
||||
Expr(Box<Expr>),
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Fold, Clone, Debug, PartialEq)]
|
||||
pub struct ExprOrSpread {
|
||||
pub spread: Option<Span>,
|
||||
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]
|
||||
pub enum BlockStmtOrExpr {
|
||||
|
@ -12,15 +12,18 @@ pub use self::class::{Class, ClassMethod, ClassMethodKind};
|
||||
pub use self::decl::{ClassDecl, Decl, FnDecl, VarDecl, VarDeclKind, VarDeclarator};
|
||||
pub use self::expr::{ArrayLit, ArrowExpr, AssignExpr, AwaitExpr, BinExpr, BlockStmtOrExpr,
|
||||
CallExpr, ClassExpr, CondExpr, Expr, ExprOrSpread, ExprOrSuper, FnExpr,
|
||||
MemberExpr, MetaPropExpr, NewExpr, ObjectLit, PatOrExpr, SeqExpr, TplElement,
|
||||
TplLit, UnaryExpr, UpdateExpr, YieldExpr};
|
||||
MemberExpr, MetaPropExpr, NewExpr, ObjectLit, ParenExpr, PatOrExpr, SeqExpr,
|
||||
ThisExpr, TplElement, TplLit, UnaryExpr, UpdateExpr, YieldExpr};
|
||||
pub use self::function::Function;
|
||||
pub use self::lit::{Bool, Lit, Null, Number, Regex, RegexFlags, Str};
|
||||
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::pat::{ObjectPatProp, Pat};
|
||||
pub use self::prop::{Prop, PropName};
|
||||
pub use self::pat::{ArrayPat, AssignPat, AssignPatProp, KeyValuePatProp, ObjectPat, ObjectPatProp,
|
||||
Pat};
|
||||
pub use self::prop::{AssignProp, GetterProp, KeyValueProp, MethodProp, Prop, PropName, SetterProp};
|
||||
pub use self::stmt::{BlockStmt, BreakStmt, CatchClause, ContinueStmt, DebuggerStmt, DoWhileStmt,
|
||||
EmptyStmt, ForInStmt, ForOfStmt, ForStmt, IfStmt, LabeledStmt, ReturnStmt,
|
||||
Stmt, SwitchCase, SwitchStmt, ThrowStmt, TryStmt, VarDeclOrExpr,
|
||||
|
@ -78,6 +78,7 @@ pub struct ImportSpecific {
|
||||
|
||||
#[ast_node]
|
||||
pub struct ExportSpecifier {
|
||||
pub span: Span,
|
||||
/// `foo` in `export { foo as bar }`
|
||||
pub orig: Ident,
|
||||
/// `Some(bar)` in `export { foo as bar }`
|
||||
|
@ -10,7 +10,7 @@ pub enum Pat {
|
||||
|
||||
Rest(Box<Pat>),
|
||||
|
||||
Object(Vec<ObjectPatProp>),
|
||||
Object(ObjectPat),
|
||||
|
||||
Assign(AssignPat),
|
||||
|
||||
@ -24,6 +24,12 @@ pub struct ArrayPat {
|
||||
pub elems: Vec<(Option<Pat>)>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct ObjectPat {
|
||||
pub span: Span,
|
||||
pub props: Vec<ObjectPatProp>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct AssignPat {
|
||||
pub span: Span,
|
||||
@ -40,12 +46,15 @@ pub enum ObjectPatProp {
|
||||
/// `{key: value}`
|
||||
#[ast_node]
|
||||
pub struct KeyValuePatProp {
|
||||
#[span(lo)]
|
||||
pub key: PropName,
|
||||
#[span(hi)]
|
||||
pub value: Box<Pat>,
|
||||
}
|
||||
/// `{key}` or `{key = value}`
|
||||
#[ast_node]
|
||||
pub struct AssignPatProp {
|
||||
pub span: Span,
|
||||
pub key: Ident,
|
||||
|
||||
pub value: Option<(Box<Expr>)>,
|
||||
|
@ -18,18 +18,18 @@ pub enum Prop {
|
||||
|
||||
#[ast_node]
|
||||
pub struct KeyValueProp {
|
||||
// #[span(lo)]
|
||||
#[span(lo)]
|
||||
pub key: PropName,
|
||||
|
||||
// #[span(hi)]
|
||||
#[span(hi)]
|
||||
pub value: Box<Expr>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub struct AssignProp {
|
||||
// #[span(lo)]
|
||||
#[span(lo)]
|
||||
key: Ident,
|
||||
// #[span(hi)]
|
||||
#[span(hi)]
|
||||
value: Box<Expr>,
|
||||
}
|
||||
#[ast_node]
|
||||
@ -47,9 +47,9 @@ pub struct SetterProp {
|
||||
}
|
||||
#[ast_node]
|
||||
pub struct MethodProp {
|
||||
// #[span(lo)]
|
||||
#[span(lo)]
|
||||
key: PropName,
|
||||
// #[span(hi)]
|
||||
#[span(hi)]
|
||||
function: Function,
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ swc_macros_common = { path = "../common" }
|
||||
pmutil = "0.1"
|
||||
proc-macro2 = { version = "0.2", features = ["nightly"] }
|
||||
quote = "0.4"
|
||||
darling = "0.3"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "0.12"
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![feature(box_syntax, proc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate darling;
|
||||
#[macro_use]
|
||||
extern crate pmutil;
|
||||
extern crate proc_macro;
|
||||
|
@ -1,5 +1,22 @@
|
||||
use darling::FromField;
|
||||
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 {
|
||||
let arms = Binder::new_from(&input)
|
||||
.variants()
|
||||
@ -53,6 +70,15 @@ pub fn derive(input: DeriveInput) -> ItemImpl {
|
||||
}
|
||||
|
||||
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 {
|
||||
panic!("#[derive(Spanned)] requires a field to get span from")
|
||||
}
|
||||
@ -61,27 +87,35 @@ fn make_body_for_variant(v: &VariantBinder, bindings: Vec<BindedField>) -> Box<E
|
||||
match *v.data() {
|
||||
Fields::Unnamed(..) => {
|
||||
// Call self.0.span()
|
||||
return box Quote::new(Span::def_site())
|
||||
.quote_with(smart_quote!(
|
||||
Vars {
|
||||
field: &bindings[0],
|
||||
},
|
||||
{ swc_common::Spanned::span(field) }
|
||||
))
|
||||
.parse();
|
||||
return simple_field(&bindings[0]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle #[span] attribute.
|
||||
// Handle #[span] attribute.
|
||||
if let Some(f) = bindings
|
||||
.iter()
|
||||
.find(|b| has_empty_span_attr(&b.field().attrs))
|
||||
{
|
||||
//TODO: Verify that there's no more #[span]
|
||||
return simple_field(f);
|
||||
}
|
||||
|
||||
// If all fields do not have `#[span(..)]`, check for field named `span`.
|
||||
let has_any_span_attr = bindings
|
||||
.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| {
|
||||
let s = b.field().ident.as_ref().map(|ident| ident.as_ref());
|
||||
Some("span") == s
|
||||
})
|
||||
.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 {}",
|
||||
@ -89,7 +123,39 @@ fn make_body_for_variant(v: &VariantBinder, bindings: Vec<BindedField>) -> Box<E
|
||||
)
|
||||
});
|
||||
|
||||
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 { span_field }, { span_field }))
|
||||
.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()
|
||||
})
|
||||
}
|
||||
|
24
macros/ast_node/tests/attr_interop.rs
Normal file
24
macros/ast_node/tests/attr_interop.rs
Normal 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,
|
||||
}
|
@ -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);
|
@ -1,12 +1,12 @@
|
||||
#![feature(specialization, proc_macro)]
|
||||
#![feature(proc_macro)]
|
||||
|
||||
extern crate ast_node;
|
||||
extern crate swc_common;
|
||||
extern crate swc_macros;
|
||||
use swc_macros::ast_node;
|
||||
use ast_node::*;
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Debug, Fold)]
|
||||
pub struct Struct {}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Debug, FromVariant, Fold)]
|
||||
pub enum Enum {
|
||||
}
|
||||
|
@ -1,30 +1,29 @@
|
||||
//! Ensures that #[derive(AstNode)] works with generic types.
|
||||
//! Ensures that #[derive(Fold)] works with generic types.
|
||||
|
||||
#![feature(specialization, proc_macro)]
|
||||
|
||||
extern crate swc_common;
|
||||
extern crate swc_macros;
|
||||
use std::fmt::Debug;
|
||||
use swc_common::AstNode;
|
||||
use swc_macros::ast_node;
|
||||
use swc_common::{AstNode, Fold};
|
||||
|
||||
pub trait Ast: Copy + Eq + Debug {
|
||||
type CustomExpr: AstNode;
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Fold)]
|
||||
pub struct Stmt<A: Ast> {
|
||||
#[fold(bound)]
|
||||
pub expr: Expr<A>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Fold)]
|
||||
pub struct Expr<A: Ast> {
|
||||
#[fold(bound)]
|
||||
pub node: ExprKind<A>,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Fold)]
|
||||
pub enum ExprKind<A: Ast> {
|
||||
Custom(#[fold(bound)] A::CustomExpr),
|
||||
/// Recursive
|
@ -2,15 +2,14 @@
|
||||
|
||||
extern crate swc_common;
|
||||
extern crate swc_macros;
|
||||
use swc_common::{FoldWith, Folder};
|
||||
use swc_macros::ast_node;
|
||||
use swc_common::{Fold, FoldWith};
|
||||
|
||||
pub trait AssertFolder<T>: Folder<T> {}
|
||||
pub trait AssertFolder<T>: Fold<T> {}
|
||||
|
||||
// check for trait bound
|
||||
|
||||
pub struct LitFolder;
|
||||
impl Folder<Lit> for LitFolder {
|
||||
impl Fold<Lit> for LitFolder {
|
||||
fn fold(&mut self, _: Lit) -> Lit {
|
||||
Lit::A
|
||||
}
|
||||
@ -18,7 +17,7 @@ impl Folder<Lit> for LitFolder {
|
||||
impl AssertFolder<Expr> for LitFolder {}
|
||||
impl AssertFolder<ExprKind> for LitFolder {}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Debug, Fold, PartialEq, Eq)]
|
||||
pub struct Expr {
|
||||
pub node: ExprKind,
|
||||
/// 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 {
|
||||
RecursiveBoud(Box<Expr>),
|
||||
Rec2(Vec<Option<Box<Expr>>>),
|
||||
@ -48,7 +47,7 @@ pub enum ExprKind {
|
||||
Lit(Lit),
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
#[derive(Debug, Fold, PartialEq, Eq)]
|
||||
pub enum Lit {
|
||||
A,
|
||||
B,
|
22
macros/ast_node/tests/spanned_attr.rs
Normal file
22
macros/ast_node/tests/spanned_attr.rs
Normal 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())
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user