Merge tag 0.10.8 into master
Conflicts:
Cargo.toml
diff --git a/.travis.yml b/.travis.yml
index 4e9dea9..5378689 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,15 @@
- .git/modules
matrix:
+ include:
+ - rust: stable
+ env: ROLE=build
+ - rust: beta
+ env: ROLE=build
+ - rust: 1.12.1
+ env: ROLE=build
+ - rust: 1.13.0
+ env: ROLE=build
allow_failures:
- env: ROLE=clippy
@@ -27,21 +36,24 @@
build)
cargo build --no-default-features &&
cargo build &&
- cargo build --features 'full expand' &&
- cargo doc --features 'full expand'
+ cargo build --features full &&
+ cargo doc --features 'full visit'
;;
test)
git submodule update --init &&
- cargo test --features 'full aster expand pretty visit' --release
+ cargo test --features 'full aster visit' --release
;;
clippy)
- cargo build --features 'full aster expand pretty visit clippy'
+ cargo build --features 'full aster visit clippy'
+ ;;
+ *)
+ exit 1
;;
esac
after_success:
- |
- if [ "$ROLE" = build ]; then
+ if [ "$ROLE" = build ] && [ "$TRAVIS_RUST_VERSION" = nightly ]; then
travis-cargo doc-upload
fi
diff --git a/Cargo.toml b/Cargo.toml
index 13b273d..379316d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "syn"
-version = "0.10.8" # don't forget to update version in readme for breaking changes
+version = "0.11.4" # don't forget to update version in readme for breaking changes
authors = ["David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Nom parser for Rust source code"
@@ -11,22 +11,19 @@
[features]
default = ["parsing", "printing"]
aster = []
-expand = ["full", "parsing", "printing"]
full = []
parsing = ["unicode-xid"]
-pretty = ["syntex_syntax"]
printing = ["quote"]
visit = []
[dependencies]
clippy = { version = "0.*", optional = true }
quote = { version = "0.3.0", optional = true }
-syntex_syntax = { version = "0.50.0", optional = true }
unicode-xid = { version = "0.0.4", optional = true }
[dev-dependencies]
-syntex_pos = "0.50.0"
-syntex_syntax = "0.50.0"
+syntex_pos = "0.52.0"
+syntex_syntax = "0.52.0"
tempdir = "0.3.5"
time = "0.1.35"
walkdir = "1.0.1"
diff --git a/README.md b/README.md
index 4c4364d..8b30fb5 100644
--- a/README.md
+++ b/README.md
@@ -10,14 +10,17 @@
Designed for fast compile time.
-- Compile time for `syn` (from scratch including all dependencies): **4 seconds**
+- Compile time for `syn` (from scratch including all dependencies): **6 seconds**
- Compile time for the `syntex`/`quasi`/`aster` stack: **60+ seconds**
+If you get stuck with Macros 1.1 I am happy to provide help even if the issue is
+not related to syn. Please file a ticket in this repo.
+
## Usage with Macros 1.1
```toml
[dependencies]
-syn = "0.10"
+syn = "0.11"
quote = "0.3"
[lib]
@@ -25,8 +28,6 @@
```
```rust
-#![feature(proc_macro, proc_macro_lib)]
-
extern crate proc_macro;
use proc_macro::TokenStream;
@@ -39,8 +40,8 @@
pub fn my_macro(input: TokenStream) -> TokenStream {
let source = input.to_string();
- // Parse the string representation to an AST
- let ast = syn::parse_macro_input(&source).unwrap();
+ // Parse the string representation into a syntax tree
+ let ast = syn::parse_derive_input(&source).unwrap();
// Build the output, possibly using quasi-quotation
let expanded = quote! {
@@ -67,8 +68,6 @@
and [`quote`](https://github.com/dtolnay/quote) looks like this:
```rust
-#![feature(proc_macro, proc_macro_lib)]
-
extern crate proc_macro;
use proc_macro::TokenStream;
@@ -81,8 +80,8 @@
pub fn num_fields(input: TokenStream) -> TokenStream {
let source = input.to_string();
- // Parse the string representation to an AST
- let ast = syn::parse_macro_input(&source).unwrap();
+ // Parse the string representation into a syntax tree
+ let ast = syn::parse_derive_input(&source).unwrap();
// Build the output
let expanded = expand_num_fields(&ast);
@@ -91,7 +90,7 @@
expanded.parse().unwrap()
}
-fn expand_num_fields(ast: &syn::MacroInput) -> quote::Tokens {
+fn expand_num_fields(ast: &syn::DeriveInput) -> quote::Tokens {
let n = match ast.body {
syn::Body::Struct(ref data) => data.fields().len(),
syn::Body::Enum(_) => panic!("#[derive(NumFields)] can only be used with structs"),
@@ -114,6 +113,59 @@
}
```
+## Testing
+
+Macros 1.1 has a restriction that your proc-macro crate must export nothing but
+`proc_macro_derive` functions, and also `proc_macro_derive` procedural macros
+cannot be used from the same crate in which they are defined. These restrictions
+may be lifted in the future but for now they make writing tests a bit trickier
+than for other types of code.
+
+In particular, you will not be able to write test functions like `#[test] fn
+it_works() { ... }` in line with your code. Instead, either put tests in a
+[`tests` directory](https://doc.rust-lang.org/book/testing.html#the-tests-directory)
+or in a separate crate entirely.
+
+Additionally, if your procedural macro implements a particular trait, that trait
+must be defined in a separate crate from the procedural macro.
+
+As a concrete example, suppose your procedural macro crate is called `my_derive`
+and it implements a trait called `my_crate::MyTrait`. Your unit tests for the
+procedural macro can go in `my_derive/tests/test.rs` or into a separate crate
+`my_tests/tests/test.rs`. Either way the test would look something like this:
+
+```rust
+#[macro_use]
+extern crate my_derive;
+
+extern crate my_crate;
+use my_crate::MyTrait;
+
+#[test]
+fn it_works() {
+ #[derive(MyTrait)]
+ struct S { /* ... */ }
+
+ /* test the thing */
+}
+```
+
+## Debugging
+
+When developing a procedural macro it can be helpful to look at what the
+generated code looks like. Use `cargo rustc -- -Zunstable-options
+--pretty=expanded` or the
+[`cargo expand`](https://github.com/dtolnay/cargo-expand) subcommand.
+
+To show the expanded code for some crate that uses your procedural macro, run
+`cargo expand` from that crate. To show the expanded code for one of your own
+test cases, run `cargo expand --test the_test_case` where the last argument is
+the name of the test file without the `.rs` extension.
+
+This write-up by Brandon W Maister discusses debugging in more detail:
+[Debugging Rust's new Custom Derive
+system](https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/).
+
## Optional features
Syn puts a lot of functionality behind optional features in order to optimize
@@ -122,70 +174,14 @@
Features | Compile time | Functionality
--- | --- | ---
-*(none)* | 1 sec | The data structures representing the AST of Rust structs, enums, and types.
-parsing | 4 sec | Parsing Rust source code containing structs and enums into an AST.
-printing | 2 sec | Printing an AST of structs and enums as Rust source code.
-**parsing, printing** | **4 sec** | **This is the default.** Parsing and printing of Rust structs and enums. This is typically what you want for implementing Macros 1.1 custom derives.
-full | 2 sec | The data structures representing the full AST of all possible Rust code.
-full, parsing | 7 sec | Parsing any valid Rust source code to an AST.
-full, printing | 4 sec | Turning an AST into Rust source code.
-full, parsing, printing | 8 sec | Parsing and printing any Rust syntax.
-full, parsing, printing, expand | 9 sec | Expansion of custom derives in a file of Rust code. This is typically what you want for expanding custom derives on stable Rust using a build script.
-full, parsing, printing, expand, pretty | 60 sec | Expansion of custom derives with pretty-printed output. This is what you want when iterating on or debugging a custom derive, but the pretty printing should be disabled once you get everything working.
-
-## Custom derives on stable Rust
-
-Syn supports a way of expanding custom derives from a build script, similar to
-what [Serde is able to do with serde_codegen](https://serde.rs/codegen-stable.html).
-The advantage of using Syn for this purpose rather than Syntex is much faster
-compile time.
-
-Continuing with the `NumFields` example from above, it can be extended to
-support stable Rust like this. One or more custom derives are added to a
-[`Registry`](https://dtolnay.github.io/syn/syn/struct.Registry.html), which is
-then able to expand those derives in a source file at a particular path and
-write the expanded output to a different path. A custom derive is represented by
-the [`CustomDerive`](https://dtolnay.github.io/syn/syn/trait.CustomDerive.html)
-trait which takes a [`MacroInput`](https://dtolnay.github.io/syn/syn/struct.MacroInput.html)
-(either a struct or an enum) and [expands it](https://dtolnay.github.io/syn/syn/struct.Expanded.html)
-into zero or more new items and maybe a modified or unmodified instance of the
-original input.
-
-```rust
-pub fn expand_file<S, D>(src: S, dst: D) -> Result<(), String>
- where S: AsRef<Path>,
- D: AsRef<Path>
-{
- let mut registry = syn::Registry::new();
- registry.add_derive("NumFields", |input| {
- let tokens = expand_num_fields(&input);
- let items = syn::parse_items(&tokens.to_string()).unwrap();
- Ok(syn::Expanded {
- new_items: items,
- original: Some(input),
- })
- });
- registry.expand_file(src, dst)
-}
-```
-
-The codegen can be invoked from a build script as follows.
-
-```rust
-extern crate your_codegen;
-
-use std::env;
-use std::path::Path;
-
-fn main() {
- let out_dir = env::var_os("OUT_DIR").unwrap();
-
- let src = Path::new("src/codegen_types.in.rs");
- let dst = Path::new(&out_dir).join("codegen_types.rs");
-
- your_codegen::expand_file(&src, &dst).unwrap();
-}
-```
+*(none)* | 3 sec | The data structures representing the AST of Rust structs, enums, and types.
+parsing | 6 sec | Parsing Rust source code containing structs and enums into an AST.
+printing | 4 sec | Printing an AST of structs and enums as Rust source code.
+**parsing, printing** | **6 sec** | **This is the default.** Parsing and printing of Rust structs and enums. This is typically what you want for implementing Macros 1.1 custom derives.
+full | 4 sec | The data structures representing the full AST of all possible Rust code.
+full, parsing | 9 sec | Parsing any valid Rust source code to an AST.
+full, printing | 6 sec | Turning an AST into Rust source code.
+full, parsing, printing | 11 sec | Parsing and printing any Rust syntax.
## License
diff --git a/src/aster/ty.rs b/src/aster/ty.rs
index 96b6554..127b164 100644
--- a/src/aster/ty.rs
+++ b/src/aster/ty.rs
@@ -158,10 +158,6 @@
TyBuilder::with_callback(TyIteratorBuilder(self))
}
- pub fn object_sum(self) -> TyBuilder<TyObjectSumBuilder<F>> {
- TyBuilder::with_callback(TyObjectSumBuilder { builder: self })
- }
-
pub fn impl_trait(self) -> TyImplTraitTyBuilder<F> {
TyImplTraitTyBuilder {
builder: self,
@@ -389,90 +385,6 @@
// ////////////////////////////////////////////////////////////////////////////
-pub struct TyObjectSumBuilder<F> {
- builder: TyBuilder<F>,
-}
-
-impl<F> Invoke<Ty> for TyObjectSumBuilder<F>
- where F: Invoke<Ty>
-{
- type Result = TyObjectSumTyBuilder<F>;
-
- fn invoke(self, ty: Ty) -> Self::Result {
- TyObjectSumTyBuilder {
- builder: self.builder,
- ty: ty,
- bounds: Vec::new(),
- }
- }
-}
-
-pub struct TyObjectSumTyBuilder<F> {
- builder: TyBuilder<F>,
- ty: Ty,
- bounds: Vec<TyParamBound>,
-}
-
-impl<F> TyObjectSumTyBuilder<F>
- where F: Invoke<Ty>
-{
- pub fn with_bounds<I>(mut self, iter: I) -> Self
- where I: Iterator<Item = TyParamBound>
- {
- self.bounds.extend(iter);
- self
- }
-
- pub fn with_bound(mut self, bound: TyParamBound) -> Self {
- self.bounds.push(bound);
- self
- }
-
- pub fn bound(self) -> TyParamBoundBuilder<Self> {
- TyParamBoundBuilder::with_callback(self)
- }
-
- pub fn with_generics(self, generics: Generics) -> Self {
- self.with_lifetimes(generics.lifetimes
- .into_iter()
- .map(|def| def.lifetime))
- }
-
- pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
- where I: Iterator<Item = L>,
- L: IntoLifetime
- {
- for lifetime in lifetimes {
- self = self.lifetime(lifetime);
- }
-
- self
- }
-
- pub fn lifetime<L>(self, lifetime: L) -> Self
- where L: IntoLifetime
- {
- self.bound().lifetime(lifetime)
- }
-
- pub fn build(self) -> F::Result {
- let bounds = self.bounds;
- self.builder.build(Ty::ObjectSum(Box::new(self.ty), bounds))
- }
-}
-
-impl<F> Invoke<TyParamBound> for TyObjectSumTyBuilder<F>
- where F: Invoke<Ty>
-{
- type Result = Self;
-
- fn invoke(self, bound: TyParamBound) -> Self {
- self.with_bound(bound)
- }
-}
-
-// ////////////////////////////////////////////////////////////////////////////
-
pub struct TyImplTraitTyBuilder<F> {
builder: TyBuilder<F>,
bounds: Vec<TyParamBound>,
diff --git a/src/macro_input.rs b/src/derive.rs
similarity index 92%
rename from src/macro_input.rs
rename to src/derive.rs
index de99f27..20b710b 100644
--- a/src/macro_input.rs
+++ b/src/derive.rs
@@ -1,7 +1,7 @@
use super::*;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct MacroInput {
+pub struct DeriveInput {
pub ident: Ident,
pub vis: Visibility,
pub attrs: Vec<Attribute>,
@@ -24,14 +24,14 @@
use generics::parsing::generics;
use ident::parsing::ident;
- named!(pub macro_input -> MacroInput, do_parse!(
+ named!(pub derive_input -> DeriveInput, do_parse!(
attrs: many0!(outer_attr) >>
vis: visibility >>
which: alt!(keyword!("struct") | keyword!("enum")) >>
id: ident >>
generics: generics >>
item: switch!(value!(which),
- "struct" => map!(struct_body, move |(wh, body)| MacroInput {
+ "struct" => map!(struct_body, move |(wh, body)| DeriveInput {
ident: id,
vis: vis,
attrs: attrs,
@@ -42,7 +42,7 @@
body: Body::Struct(body),
})
|
- "enum" => map!(enum_body, move |(wh, body)| MacroInput {
+ "enum" => map!(enum_body, move |(wh, body)| DeriveInput {
ident: id,
vis: vis,
attrs: attrs,
@@ -64,7 +64,7 @@
use data::VariantData;
use quote::{Tokens, ToTokens};
- impl ToTokens for MacroInput {
+ impl ToTokens for DeriveInput {
fn to_tokens(&self, tokens: &mut Tokens) {
for attr in self.attrs.outer() {
attr.to_tokens(tokens);
diff --git a/src/expr.rs b/src/expr.rs
index c8b574d..7b6602a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -22,7 +22,7 @@
/// First expr is the place; second expr is the value.
InPlace(Box<Expr>, Box<Expr>),
/// An array (`[a, b, c, d]`)
- Vec(Vec<Expr>),
+ Array(Vec<Expr>),
/// A function call
///
/// The first field resolves to the function itself,
@@ -85,10 +85,10 @@
Loop(Block, Option<Ident>),
/// A `match` block.
Match(Box<Expr>, Vec<Arm>),
- /// A closure (for example, `move |a, b, c| {a + b + c}`)
- Closure(CaptureBy, Box<FnDecl>, Block),
+ /// A closure (for example, `move |a, b, c| a + b + c`)
+ Closure(CaptureBy, Box<FnDecl>, Box<Expr>),
/// A block (`{ ... }` or `unsafe { ... }`)
- Block(BlockCheckMode, Block),
+ Block(Unsafety, Block),
/// An assignment (`a = foo()`)
Assign(Box<Expr>, Box<Expr>),
@@ -116,8 +116,8 @@
/// A referencing operation (`&a` or `&mut a`)
AddrOf(Mutability, Box<Expr>),
- /// A `break`, with an optional label to break
- Break(Option<Ident>),
+ /// A `break`, with an optional label to break, and an optional expression
+ Break(Option<Ident>, Option<Box<Expr>>),
/// A `continue`, with an optional label
Continue(Option<Ident>),
/// A `return`, with an optional value to be returned
@@ -150,6 +150,7 @@
pub ident: Ident,
pub expr: Expr,
pub is_shorthand: bool,
+ pub attrs: Vec<Attribute>,
}
/// A Block (`{ .. }`).
@@ -161,12 +162,6 @@
pub stmts: Vec<Stmt>,
}
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum BlockCheckMode {
- Default,
- Unsafe,
-}
-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Stmt {
/// A local (let) binding.
@@ -300,6 +295,7 @@
/// The pattern the field is destructured to
pub pat: Box<Pat>,
pub is_shorthand: bool,
+ pub attrs: Vec<Attribute>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@@ -312,7 +308,7 @@
pub mod parsing {
use super::*;
use {BinOp, Delimited, DelimToken, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, Mac,
- TokenTree, Ty, UnOp};
+ TokenTree, Ty, UnOp, Unsafety};
use attr::parsing::outer_attr;
use generics::parsing::lifetime;
use ident::parsing::{ident, wordlike};
@@ -321,7 +317,7 @@
use mac::parsing::{mac, token_trees};
use nom::IResult::{self, Error};
use op::parsing::{assign_op, binop, unop};
- use ty::parsing::{mutability, path, qpath, ty};
+ use ty::parsing::{mutability, path, qpath, ty, unsafety};
// Struct literals are ambiguous in certain positions
// https://github.com/rust-lang/rfcs/pull/92
@@ -355,7 +351,7 @@
|
expr_mac // must be before expr_path
|
- expr_break // must be before expr_path
+ call!(expr_break, allow_struct) // must be before expr_path
|
expr_continue // must be before expr_path
|
@@ -365,7 +361,7 @@
|
expr_in_place
|
- expr_vec
+ expr_array
|
expr_tup
|
@@ -474,17 +470,17 @@
punct!("}") >>
(ExprKind::InPlace(
Box::new(place),
- Box::new(ExprKind::Block(BlockCheckMode::Default, Block {
+ Box::new(ExprKind::Block(Unsafety::Normal, Block {
stmts: value,
}).into()),
))
));
- named!(expr_vec -> ExprKind, do_parse!(
+ named!(expr_array -> ExprKind, do_parse!(
punct!("[") >>
elems: terminated_list!(punct!(","), expr) >>
punct!("]") >>
- (ExprKind::Vec(elems))
+ (ExprKind::Array(elems))
));
named!(and_call -> Vec<Expr>, do_parse!(
@@ -571,7 +567,7 @@
punct!("{") >>
else_block: within_block >>
punct!("}") >>
- (ExprKind::Block(BlockCheckMode::Default, Block {
+ (ExprKind::Block(Unsafety::Normal, Block {
stmts: else_block,
}).into())
)
@@ -632,7 +628,7 @@
));
fn arm_requires_comma(arm: &Arm) -> bool {
- if let ExprKind::Block(BlockCheckMode::Default, _) = arm.body.node {
+ if let ExprKind::Block(Unsafety::Normal, _) = arm.body.node {
false
} else {
true
@@ -645,7 +641,7 @@
guard: option!(preceded!(keyword!("if"), expr)) >>
punct!("=>") >>
body: alt!(
- map!(block, |blk| ExprKind::Block(BlockCheckMode::Default, blk).into())
+ map!(block, |blk| ExprKind::Block(Unsafety::Normal, blk).into())
|
expr
) >>
@@ -667,15 +663,10 @@
punct!("->") >>
ty: ty >>
body: block >>
- ((FunctionRetTy::Ty(ty), body))
+ (FunctionRetTy::Ty(ty), ExprKind::Block(Unsafety::Normal, body).into())
)
|
- map!(ambiguous_expr!(allow_struct), |e| (
- FunctionRetTy::Default,
- Block {
- stmts: vec![Stmt::Expr(Box::new(e))],
- },
- ))
+ map!(ambiguous_expr!(allow_struct), |e| (FunctionRetTy::Default, e))
) >>
(ExprKind::Closure(
capture,
@@ -684,7 +675,7 @@
output: ret_and_body.0,
variadic: false,
}),
- ret_and_body.1,
+ Box::new(ret_and_body.1),
))
));
@@ -720,10 +711,11 @@
(ExprKind::Continue(lbl))
));
- named!(expr_break -> ExprKind, do_parse!(
+ named_ambiguous_expr!(expr_break -> ExprKind, allow_struct, do_parse!(
keyword!("break") >>
lbl: option!(label) >>
- (ExprKind::Break(lbl))
+ val: option!(call!(ambiguous_expr, allow_struct, false)) >>
+ (ExprKind::Break(lbl, val.map(Box::new)))
));
named_ambiguous_expr!(expr_ret -> ExprKind, allow_struct, do_parse!(
@@ -756,6 +748,7 @@
ident: name,
expr: value,
is_shorthand: false,
+ attrs: Vec::new(),
})
)
|
@@ -763,6 +756,7 @@
ident: name.clone(),
expr: ExprKind::Path(None, name.into()).into(),
is_shorthand: true,
+ attrs: Vec::new(),
})
));
@@ -776,7 +770,7 @@
));
named!(expr_block -> ExprKind, do_parse!(
- rules: block_check_mode >>
+ rules: unsafety >>
b: block >>
(ExprKind::Block(rules, Block {
stmts: b.stmts,
@@ -834,12 +828,6 @@
})
));
- named!(block_check_mode -> BlockCheckMode, alt!(
- keyword!("unsafe") => { |_| BlockCheckMode::Unsafe }
- |
- epsilon!() => { |_| BlockCheckMode::Default }
- ));
-
named!(pub within_block -> Vec<Stmt>, do_parse!(
many0!(punct!(";")) >>
mut standalone: many0!(terminated!(standalone_stmt, many0!(punct!(";")))) >>
@@ -865,7 +853,7 @@
named!(stmt_mac -> Stmt, do_parse!(
attrs: many0!(outer_attr) >>
- name: ident >>
+ what: path >>
punct!("!") >>
// Only parse braces here; paren and bracket will get parsed as
// expression statements
@@ -875,7 +863,7 @@
semi: option!(punct!(";")) >>
(Stmt::Mac(Box::new((
Mac {
- path: name.into(),
+ path: what,
tts: vec![TokenTree::Delimited(Delimited {
delim: DelimToken::Brace,
tts: tts,
@@ -1024,6 +1012,7 @@
ident: ident,
pat: Box::new(pat),
is_shorthand: false,
+ attrs: Vec::new(),
})
)
|
@@ -1049,6 +1038,7 @@
ident: ident,
pat: Box::new(pat),
is_shorthand: true,
+ attrs: Vec::new(),
}
})
)
@@ -1159,7 +1149,7 @@
#[cfg(feature = "printing")]
mod printing {
use super::*;
- use {FnArg, FunctionRetTy, Mutability, Ty};
+ use {FnArg, FunctionRetTy, Mutability, Ty, Unsafety};
use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
@@ -1176,7 +1166,7 @@
place.to_tokens(tokens);
value.to_tokens(tokens);
}
- ExprKind::Vec(ref tys) => {
+ ExprKind::Array(ref tys) => {
tokens.append("[");
tokens.append_separated(tys, ",");
tokens.append("]");
@@ -1297,7 +1287,7 @@
tokens.append_all(arms);
tokens.append("}");
}
- ExprKind::Closure(capture, ref decl, ref body) => {
+ ExprKind::Closure(capture, ref decl, ref expr) => {
capture.to_tokens(tokens);
tokens.append("|");
for (i, input) in decl.inputs.iter().enumerate() {
@@ -1313,23 +1303,13 @@
}
tokens.append("|");
match decl.output {
- FunctionRetTy::Default => {
- if body.stmts.len() == 1 {
- if let Stmt::Expr(ref expr) = body.stmts[0] {
- expr.to_tokens(tokens);
- } else {
- body.to_tokens(tokens);
- }
- } else {
- body.to_tokens(tokens);
- }
- }
+ FunctionRetTy::Default => { /* nothing */ }
FunctionRetTy::Ty(ref ty) => {
tokens.append("->");
ty.to_tokens(tokens);
- body.to_tokens(tokens);
}
}
+ expr.to_tokens(tokens);
}
ExprKind::Block(rules, ref block) => {
rules.to_tokens(tokens);
@@ -1396,9 +1376,10 @@
mutability.to_tokens(tokens);
expr.to_tokens(tokens);
}
- ExprKind::Break(ref opt_label) => {
+ ExprKind::Break(ref opt_label, ref opt_val) => {
tokens.append("break");
opt_label.to_tokens(tokens);
+ opt_val.to_tokens(tokens);
}
ExprKind::Continue(ref opt_label) => {
tokens.append("continue");
@@ -1465,7 +1446,7 @@
tokens.append("=>");
self.body.to_tokens(tokens);
match self.body.node {
- ExprKind::Block(BlockCheckMode::Default, _) => {
+ ExprKind::Block(Unsafety::Normal, _) => {
// no comma
}
_ => tokens.append(","),
@@ -1646,17 +1627,6 @@
}
}
- impl ToTokens for BlockCheckMode {
- fn to_tokens(&self, tokens: &mut Tokens) {
- match *self {
- BlockCheckMode::Default => {
- // nothing
- }
- BlockCheckMode::Unsafe => tokens.append("unsafe"),
- }
- }
- }
-
impl ToTokens for Stmt {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
diff --git a/src/generics.rs b/src/generics.rs
index d76051f..46d7c43 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -19,8 +19,13 @@
#[derive(Debug)]
pub struct TyGenerics<'a>(&'a Generics);
+#[cfg(feature = "printing")]
+/// Returned by `TyGenerics::as_turbofish`.
+#[derive(Debug)]
+pub struct Turbofish<'a>(&'a Generics);
+
+#[cfg(feature = "printing")]
impl Generics {
- #[cfg(feature = "printing")]
/// Split a type's generics into the pieces required for impl'ing a trait
/// for that type.
///
@@ -45,6 +50,14 @@
}
}
+#[cfg(feature = "printing")]
+impl<'a> TyGenerics<'a> {
+ /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
+ pub fn as_turbofish(&self) -> Turbofish {
+ Turbofish(self.0)
+ }
+}
+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Lifetime {
pub ident: Ident,
@@ -125,6 +138,8 @@
BoundPredicate(WhereBoundPredicate),
/// A lifetime predicate, e.g. `'a: 'b+'c`
RegionPredicate(WhereRegionPredicate),
+ /// An equality predicate (unsupported)
+ EqPredicate(WhereEqPredicate),
}
/// A type bound.
@@ -149,6 +164,15 @@
pub bounds: Vec<Lifetime>,
}
+/// An equality predicate (unsupported).
+///
+/// E.g. `T=int`
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct WhereEqPredicate {
+ pub lhs_ty: Ty,
+ pub rhs_ty: Ty,
+}
+
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
@@ -349,6 +373,17 @@
}
}
+ impl<'a> ToTokens for Turbofish<'a> {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ let has_lifetimes = !self.0.lifetimes.is_empty();
+ let has_ty_params = !self.0.ty_params.is_empty();
+ if has_lifetimes || has_ty_params {
+ tokens.append("::");
+ TyGenerics(self.0).to_tokens(tokens);
+ }
+ }
+ }
+
impl ToTokens for Lifetime {
fn to_tokens(&self, tokens: &mut Tokens) {
self.ident.to_tokens(tokens);
@@ -414,6 +449,9 @@
WherePredicate::RegionPredicate(ref predicate) => {
predicate.to_tokens(tokens);
}
+ WherePredicate::EqPredicate(ref predicate) => {
+ predicate.to_tokens(tokens);
+ }
}
}
}
@@ -443,4 +481,12 @@
}
}
}
+
+ impl ToTokens for WhereEqPredicate {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ self.lhs_ty.to_tokens(tokens);
+ tokens.append("=");
+ self.rhs_ty.to_tokens(tokens);
+ }
+ }
}
diff --git a/src/item.rs b/src/item.rs
index 00d537a..dc4157e 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -80,8 +80,8 @@
Mac(Mac),
}
-impl From<MacroInput> for Item {
- fn from(input: MacroInput) -> Item {
+impl From<DeriveInput> for Item {
+ fn from(input: DeriveInput) -> Item {
Item {
ident: input.ident,
vis: input.vis,
@@ -242,8 +242,8 @@
use generics::parsing::{generics, lifetime, ty_param_bound, where_clause};
use ident::parsing::ident;
use mac::parsing::delimited;
- use macro_input::{Body, MacroInput};
- use macro_input::parsing::macro_input;
+ use derive::{Body, DeriveInput};
+ use derive::parsing::derive_input;
use ty::parsing::{abi, mutability, path, ty, unsafety};
named!(pub item -> Item, alt!(
@@ -280,7 +280,7 @@
named!(item_mac -> Item, do_parse!(
attrs: many0!(outer_attr) >>
- path: ident >>
+ what: path >>
punct!("!") >>
name: option!(ident) >>
body: delimited >>
@@ -293,7 +293,7 @@
vis: Visibility::Inherited,
attrs: attrs,
node: ItemKind::Mac(Mac {
- path: path.into(),
+ path: what,
tts: vec![TokenTree::Delimited(body)],
}),
})
@@ -639,8 +639,8 @@
));
named!(item_struct_or_enum -> Item, map!(
- macro_input,
- |def: MacroInput| Item {
+ derive_input,
+ |def: DeriveInput| Item {
ident: def.ident,
vis: def.vis,
attrs: def.attrs,
@@ -821,7 +821,7 @@
named!(trait_item_mac -> TraitItem, do_parse!(
attrs: many0!(outer_attr) >>
- id: ident >>
+ what: path >>
punct!("!") >>
body: delimited >>
cond!(match body.delim {
@@ -829,10 +829,10 @@
DelimToken::Brace => false,
}, punct!(";")) >>
(TraitItem {
- ident: id.clone(),
+ ident: Ident::new(""),
attrs: attrs,
node: TraitItemKind::Macro(Mac {
- path: id.into(),
+ path: what,
tts: vec![TokenTree::Delimited(body)],
}),
})
@@ -976,7 +976,7 @@
named!(impl_item_macro -> ImplItem, do_parse!(
attrs: many0!(outer_attr) >>
- id: ident >>
+ what: path >>
punct!("!") >>
body: delimited >>
cond!(match body.delim {
@@ -984,12 +984,12 @@
DelimToken::Brace => false,
}, punct!(";")) >>
(ImplItem {
- ident: id.clone(),
+ ident: Ident::new(""),
vis: Visibility::Inherited,
defaultness: Defaultness::Final,
attrs: attrs,
node: ImplItemKind::Macro(Mac {
- path: id.into(),
+ path: what,
tts: vec![TokenTree::Delimited(body)],
}),
})
diff --git a/src/lib.rs b/src/lib.rs
index 41b5ae0..fe80c6b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,12 +2,8 @@
#![cfg_attr(feature = "clippy", plugin(clippy))]
#[cfg(feature = "printing")]
-#[macro_use]
extern crate quote;
-#[cfg(feature = "pretty")]
-extern crate syntex_syntax as syntax;
-
#[cfg(feature = "parsing")]
extern crate unicode_xid;
@@ -37,14 +33,15 @@
#[cfg(feature = "full")]
mod expr;
#[cfg(feature = "full")]
-pub use expr::{Arm, BindingMode, Block, BlockCheckMode, CaptureBy, Expr, ExprKind, FieldPat,
- FieldValue, Local, MacStmtStyle, Pat, RangeLimits, Stmt};
+pub use expr::{Arm, BindingMode, Block, CaptureBy, Expr, ExprKind, FieldPat, FieldValue,
+ Local, MacStmtStyle, Pat, RangeLimits, Stmt};
mod generics;
pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
- WhereBoundPredicate, WhereClause, WherePredicate, WhereRegionPredicate};
+ WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
+ WhereRegionPredicate};
#[cfg(feature = "printing")]
-pub use generics::{ImplGenerics, TyGenerics};
+pub use generics::{ImplGenerics, Turbofish, TyGenerics};
mod ident;
pub use ident::Ident;
@@ -64,22 +61,18 @@
mod lit;
pub use lit::{FloatTy, IntTy, Lit, StrStyle};
-#[cfg(feature = "full")]
mod mac;
-#[cfg(feature = "full")]
pub use mac::{BinOpToken, DelimToken, Delimited, Mac, Token, TokenTree};
-mod macro_input;
-pub use macro_input::{Body, MacroInput};
+mod derive;
+pub use derive::{Body, DeriveInput};
+// Deprecated.
+#[doc(hidden)]
+pub type MacroInput = DeriveInput;
mod op;
pub use op::{BinOp, UnOp};
-#[cfg(feature = "expand")]
-mod registry;
-#[cfg(feature = "expand")]
-pub use registry::{CustomDerive, Expanded, Registry};
-
#[cfg(feature = "parsing")]
mod space;
@@ -97,14 +90,14 @@
#[cfg(feature = "parsing")]
mod parsing {
use super::*;
- use {generics, ident, macro_input, space, ty};
+ use {derive, generics, ident, mac, space, ty};
use nom::IResult;
#[cfg(feature = "full")]
- use {expr, item, krate, mac};
+ use {expr, item, krate};
- pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
- unwrap("macro input", macro_input::parsing::macro_input, input)
+ pub fn parse_derive_input(input: &str) -> Result<DeriveInput, String> {
+ unwrap("derive input", derive::parsing::derive_input, input)
}
#[cfg(feature = "full")]
@@ -139,7 +132,6 @@
unwrap("where clause", generics::parsing::where_clause, input)
}
- #[cfg(feature = "full")]
pub fn parse_token_trees(input: &str) -> Result<Vec<TokenTree>, String> {
unwrap("token trees", mac::parsing::token_trees, input)
}
@@ -148,6 +140,16 @@
unwrap("identifier", ident::parsing::ident, input)
}
+ pub fn parse_ty_param_bound(input: &str) -> Result<TyParamBound, String> {
+ unwrap("type parameter bound", generics::parsing::ty_param_bound, input)
+ }
+
+ // Deprecated.
+ #[doc(hidden)]
+ pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
+ parse_derive_input(input)
+ }
+
fn unwrap<T>(name: &'static str,
f: fn(&str) -> IResult<&str, T>,
input: &str)
diff --git a/src/mac.rs b/src/mac.rs
index 642f7bc..dd1447a 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -114,16 +114,17 @@
use super::*;
use Lifetime;
use generics::parsing::lifetime;
- use ident::parsing::{ident, word};
+ use ident::parsing::word;
use lit::parsing::lit;
use space::{block_comment, whitespace};
+ use ty::parsing::path;
named!(pub mac -> Mac, do_parse!(
- name: ident >>
+ what: path >>
punct!("!") >>
body: delimited >>
(Mac {
- path: name.into(),
+ path: what,
tts: vec![TokenTree::Delimited(body)],
})
));
diff --git a/src/nom.rs b/src/nom.rs
index 599a4bc..d987173 100644
--- a/src/nom.rs
+++ b/src/nom.rs
@@ -232,22 +232,12 @@
};
}
-pub fn str_chars(s: &str) -> Vec<char> {
- // Can't do `s.chars().collect()` because it triggers a compiler bug in 1.12.0
- // https://github.com/dtolnay/syn/issues/20
- let mut result = Vec::new();
- for ch in s.chars() {
- result.push(ch);
- }
- result
-}
-
macro_rules! take_until {
($input:expr, $substr:expr) => {{
if $substr.len() > $input.len() {
$crate::nom::IResult::Error
} else {
- let substr_vec: Vec<char> = $crate::nom::str_chars($substr);
+ let substr_vec: Vec<char> = $substr.chars().collect();
let mut window: Vec<char> = vec![];
let mut offset = $input.len();
let mut parsed = false;
diff --git a/src/registry.rs b/src/registry.rs
deleted file mode 100644
index 24e1c6b..0000000
--- a/src/registry.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-use super::{Attribute, AttrStyle, Body, Crate, Ident, Item, ItemKind, MacroInput, MetaItem,
- NestedMetaItem};
-use quote::Tokens;
-
-use std::collections::BTreeMap as Map;
-use std::fs::File;
-use std::io::{Read, Write};
-use std::path::Path;
-
-/// Implementation of a custom derive. Custom derives take a struct or enum and
-/// expand it into zero or more items, typically `impl` items.
-pub trait CustomDerive {
- /// Expand the given struct or enum. If this custom derive modifies the
- /// input item or preserves it unmodified, it must be returned back in the
- /// `original` field of Expanded. The custom derive may discard the input
- /// item by setting `original` to None.
- fn expand(&self, input: MacroInput) -> Result<Expanded, String>;
-}
-
-/// Produced by expanding a custom derive.
-pub struct Expanded {
- /// The items (typically `impl` items) constructed by the custom derive.
- pub new_items: Vec<Item>,
- /// The input to the custom derive, whether modified or unmodified. If the
- /// custom derive discards the input item it may do so by setting `original`
- /// to None.
- pub original: Option<MacroInput>,
-}
-
-/// Registry of custom derives. Callers add custom derives to a registry, then
-/// use the registry to expand those derives in a source file.
-#[derive(Default)]
-pub struct Registry<'a> {
- derives: Map<String, Box<CustomDerive + 'a>>,
-}
-
-impl<T> CustomDerive for T
- where T: Fn(MacroInput) -> Result<Expanded, String>
-{
- fn expand(&self, input: MacroInput) -> Result<Expanded, String> {
- self(input)
- }
-}
-
-impl<'a> Registry<'a> {
- pub fn new() -> Self {
- Default::default()
- }
-
- /// Register a custom derive. A `fn(MacroInput) -> Result<Expanded, String>`
- /// may be used as a custom derive.
- ///
- /// ```ignore
- /// registry.add_derive("Serialize", expand_serialize);
- /// ```
- pub fn add_derive<T>(&mut self, name: &str, derive: T)
- where T: CustomDerive + 'a
- {
- self.derives.insert(name.into(), Box::new(derive));
- }
-
- /// Read Rust source code from the `src` file, expand the custom derives
- /// that have been registered, and write the result to the `dst` file.
- pub fn expand_file<S, D>(&self, src: S, dst: D) -> Result<(), String>
- where S: AsRef<Path>,
- D: AsRef<Path>
- {
- // Open the src file
- let mut src = match File::open(src) {
- Ok(open) => open,
- Err(err) => return Err(err.to_string()),
- };
-
- // Read the contents of the src file to a String
- let mut content = String::new();
- if let Err(err) = src.read_to_string(&mut content) {
- return Err(err.to_string());
- }
-
- // Parse the contents
- let krate = try!(super::parse_crate(&content));
-
- // Expand
- let expanded = try!(expand_crate(self, krate));
-
- // Print the expanded code to a String
- let out = try!(pretty(quote!(#expanded)));
-
- // Create or truncate the dst file, opening in write-only mode
- let mut dst = match File::create(dst) {
- Ok(create) => create,
- Err(err) => return Err(err.to_string()),
- };
-
- // Write expanded code to the dst file
- if let Err(err) = dst.write_all(out.as_bytes()) {
- return Err(err.to_string());
- }
-
- Ok(())
- }
-}
-
-fn expand_crate(reg: &Registry, krate: Crate) -> Result<Crate, String> {
- let mut items = Vec::new();
- for item in krate.items {
- try!(expand_item(reg, item, Vec::new(), &mut items));
- }
- Ok(Crate { items: items, ..krate })
-}
-
-fn expand_item(reg: &Registry,
- mut item: Item,
- cfg: Vec<NestedMetaItem>,
- out: &mut Vec<Item>)
- -> Result<(), String> {
- let (body, generics) = match item.node {
- ItemKind::Enum(variants, generics) => (Body::Enum(variants), generics),
- ItemKind::Struct(variant_data, generics) => (Body::Struct(variant_data), generics),
- _ => {
- // Custom derives cannot apply to this item, preserve it unmodified
- item.attrs.extend(combine_cfgs(cfg));
- out.push(item);
- return Ok(());
- }
- };
- let macro_input = MacroInput {
- ident: item.ident,
- vis: item.vis,
- attrs: item.attrs,
- generics: generics,
- body: body,
- };
- expand_macro_input(reg, macro_input, cfg, out)
-}
-
-fn expand_macro_input(reg: &Registry,
- mut input: MacroInput,
- inherited_cfg: Vec<NestedMetaItem>,
- out: &mut Vec<Item>)
- -> Result<(), String> {
- let mut derives = Vec::new();
- let mut all_cfg = inherited_cfg;
-
- // Find custom derives on this item, removing them from the input
- input.attrs = input.attrs
- .into_iter()
- .flat_map(|attr| {
- let (new_derives, cfg, attr) = parse_attr(reg, attr);
- derives.extend(new_derives);
- all_cfg.extend(cfg);
- attr
- })
- .collect();
-
- // Expand each custom derive
- for derive in derives {
- let expanded = try!(reg.derives[derive.name.as_ref()].expand(input));
-
- for new_item in expanded.new_items {
- let mut extended_cfg = all_cfg.clone();
- extended_cfg.extend(derive.cfg.clone());
- try!(expand_item(reg, new_item, extended_cfg, out));
- }
-
- input = match expanded.original {
- Some(input) => input,
- None => return Ok(()),
- };
- }
-
- input.attrs.extend(combine_cfgs(all_cfg));
- out.push(input.into());
- Ok(())
-}
-
-struct Derive {
- name: Ident,
- /// If the custom derive was behind a cfg_attr
- cfg: Option<NestedMetaItem>,
-}
-
-/// Pull custom derives and cfgs out of the given Attribute.
-fn parse_attr(reg: &Registry,
- attr: Attribute)
- -> (Vec<Derive>, Vec<NestedMetaItem>, Option<Attribute>) {
- if attr.style != AttrStyle::Outer || attr.is_sugared_doc {
- return (Vec::new(), Vec::new(), Some(attr));
- }
-
- let (name, nested) = match attr.value {
- MetaItem::List(name, nested) => (name, nested),
- _ => return (Vec::new(), Vec::new(), Some(attr)),
- };
-
- match name.as_ref() {
- "derive" => {
- let (derives, attr) = parse_derive_attr(reg, nested);
- let derives = derives.into_iter()
- .map(|d| {
- Derive {
- name: d,
- cfg: None,
- }
- })
- .collect();
- (derives, Vec::new(), attr)
- }
- "cfg_attr" => {
- let (derives, attr) = parse_cfg_attr(reg, nested);
- (derives, Vec::new(), attr)
- }
- "cfg" => (Vec::new(), nested, None),
- _ => {
- // Rebuild the original attribute because it was destructured above
- let attr = Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List(name, nested),
- is_sugared_doc: false,
- };
- (Vec::new(), Vec::new(), Some(attr))
- }
- }
-}
-
-/// Assuming the given nested meta-items came from a #[derive(...)] attribute,
-/// pull out the ones that are custom derives.
-fn parse_derive_attr(reg: &Registry,
- nested: Vec<NestedMetaItem>)
- -> (Vec<Ident>, Option<Attribute>) {
- let mut derives = Vec::new();
-
- let remaining: Vec<_> = nested.into_iter()
- .flat_map(|meta| {
- let word = match meta {
- NestedMetaItem::MetaItem(MetaItem::Word(word)) => word,
- _ => return Some(meta),
- };
- if reg.derives.contains_key(word.as_ref()) {
- derives.push(word);
- None
- } else {
- Some(NestedMetaItem::MetaItem(MetaItem::Word(word)))
- }
- })
- .collect();
-
- let attr = if remaining.is_empty() {
- // Elide an empty #[derive()]
- None
- } else {
- Some(Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List("derive".into(), remaining),
- is_sugared_doc: false,
- })
- };
-
- (derives, attr)
-}
-
-/// Assuming the given nested meta-items came from a #[cfg_attr(...)] attribute,
-/// pull out any custom derives contained within.
-fn parse_cfg_attr(reg: &Registry, nested: Vec<NestedMetaItem>) -> (Vec<Derive>, Option<Attribute>) {
- if nested.len() != 2 {
- let attr = Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List("cfg_attr".into(), nested),
- is_sugared_doc: false,
- };
- return (Vec::new(), Some(attr));
- }
-
- let mut iter = nested.into_iter();
- let cfg = iter.next().unwrap();
- let arg = iter.next().unwrap();
-
- let (name, nested) = match arg {
- NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
- _ => {
- let attr = Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List("cfg_attr".into(), vec![cfg, arg]),
- is_sugared_doc: false,
- };
- return (Vec::new(), Some(attr));
- }
- };
-
- if name == "derive" {
- let (derives, attr) = parse_derive_attr(reg, nested);
- let derives = derives.into_iter()
- .map(|d| {
- Derive {
- name: d,
- cfg: Some(cfg.clone()),
- }
- })
- .collect();
- let attr = attr.map(|attr| {
- Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List("cfg_attr".into(),
- vec![cfg, NestedMetaItem::MetaItem(attr.value)]),
- is_sugared_doc: false,
- }
- });
- (derives, attr)
- } else {
- let attr = Attribute {
- style: AttrStyle::Outer,
- value:
- MetaItem::List("cfg_attr".into(),
- vec![cfg, NestedMetaItem::MetaItem(MetaItem::List(name, nested))]),
- is_sugared_doc: false,
- };
- (Vec::new(), Some(attr))
- }
-}
-
-/// Combine a list of cfg expressions into an attribute like `#[cfg(a)]` or
-/// `#[cfg(all(a, b, c))]`, or nothing if there are no cfg expressions.
-fn combine_cfgs(cfg: Vec<NestedMetaItem>) -> Option<Attribute> {
- // Flatten `all` cfgs so we don't nest `all` inside of `all`.
- let cfg: Vec<_> = cfg.into_iter()
- .flat_map(|cfg| {
- let (name, nested) = match cfg {
- NestedMetaItem::MetaItem(MetaItem::List(name, nested)) => (name, nested),
- _ => return vec![cfg],
- };
- if name == "all" {
- nested
- } else {
- vec![NestedMetaItem::MetaItem(MetaItem::List(name, nested))]
- }
- })
- .collect();
-
- let value = match cfg.len() {
- 0 => return None,
- 1 => cfg,
- _ => vec![NestedMetaItem::MetaItem(MetaItem::List("all".into(), cfg))],
- };
-
- Some(Attribute {
- style: AttrStyle::Outer,
- value: MetaItem::List("cfg".into(), value),
- is_sugared_doc: false,
- })
-}
-
-#[cfg(not(feature = "pretty"))]
-fn pretty(tokens: Tokens) -> Result<String, String> {
- Ok(tokens.to_string())
-}
-
-#[cfg(feature = "pretty")]
-fn pretty(tokens: Tokens) -> Result<String, String> {
- use syntax::parse::{self, ParseSess};
- use syntax::print::pprust;
-
- let name = "syn".to_string();
- let source = tokens.to_string();
- let sess = ParseSess::new();
- let krate = match parse::parse_crate_from_source_str(name, source, &sess) {
- Ok(krate) => krate,
- Err(mut err) => {
- err.emit();
- return Err("pretty printer failed to parse expanded code".into());
- }
- };
-
- if sess.span_diagnostic.has_errors() {
- return Err("pretty printer failed to parse expanded code".into());
- }
-
- let mut reader = &tokens.to_string().into_bytes()[..];
- let mut writer = Vec::new();
- let ann = pprust::NoAnn;
-
- try!(pprust::print_crate(
- sess.codemap(),
- &sess.span_diagnostic,
- &krate,
- "".to_string(),
- &mut reader,
- Box::new(&mut writer),
- &ann,
- false).map_err(|err| err.to_string()));
-
- String::from_utf8(writer).map_err(|err| err.to_string())
-}
diff --git a/src/ty.rs b/src/ty.rs
index e10901c..4031fc3 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -22,17 +22,19 @@
///
/// Type parameters are stored in the Path itself
Path(Option<QSelf>, Path),
- /// Something like `A+B`. Note that `B` must always be a path.
- ObjectSum(Box<Ty>, Vec<TyParamBound>),
- /// A type like `for<'a> Foo<&'a Bar>`
- PolyTraitRef(Vec<TyParamBound>),
- /// An `impl TraitA+TraitB` type.
+ /// A trait object type `Bound1 + Bound2 + Bound3`
+ /// where `Bound` is a trait or a lifetime.
+ TraitObject(Vec<TyParamBound>),
+ /// An `impl Bound1 + Bound2 + Bound3` type
+ /// where `Bound` is a trait or a lifetime.
ImplTrait(Vec<TyParamBound>),
/// No-op; kept solely so that we can pretty-print faithfully
Paren(Box<Ty>),
/// TyKind::Infer means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
Infer,
+ /// A macro in the type position.
+ Mac(Mac),
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
@@ -55,7 +57,10 @@
/// E.g. `std::cmp::PartialEq`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Path {
+ /// A `::foo` path, is relative to the crate root rather than current
+ /// module (like paths in an import).
pub global: bool,
+ /// The segments in the path: the things separated by `::`.
pub segments: Vec<PathSegment>,
}
@@ -75,7 +80,13 @@
/// E.g. `std`, `String` or `Box<T>`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PathSegment {
+ /// The identifier portion of this path segment.
pub ident: Ident,
+ /// Type/lifetime parameters attached to this path. They come in
+ /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
+ /// this is more than just simple syntactic sugar; the use of
+ /// parens affects the region binding rules, so we preserve the
+ /// distinction.
pub parameters: PathParameters,
}
@@ -220,6 +231,7 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
+ use {TyParamBound, TraitBoundModifier};
#[cfg(feature = "full")]
use ConstExpr;
use constant::parsing::const_expr;
@@ -228,11 +240,14 @@
use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
use ident::parsing::ident;
use lit::parsing::quoted_string;
+ use mac::parsing::mac;
use std::str;
named!(pub ty -> Ty, alt!(
ty_paren // must be before ty_tup
|
+ ty_mac // must be before ty_path
+ |
ty_path // must be before ty_poly_trait_ref
|
ty_vec
@@ -254,6 +269,8 @@
ty_impl_trait
));
+ named!(ty_mac -> Ty, map!(mac, Ty::Mac));
+
named!(ty_vec -> Ty, do_parse!(
punct!("[") >>
elem: ty >>
@@ -363,11 +380,18 @@
if let Some(Some(parenthesized)) = parenthesized {
path.segments.last_mut().unwrap().parameters = parenthesized;
}
- let path = Ty::Path(qself, path);
if bounds.is_empty() {
- path
+ Ty::Path(qself, path)
} else {
- Ty::ObjectSum(Box::new(path), bounds)
+ let path = TyParamBound::Trait(
+ PolyTraitRef {
+ bound_lifetimes: Vec::new(),
+ trait_ref: path,
+ },
+ TraitBoundModifier::None,
+ );
+ let bounds = Some(path).into_iter().chain(bounds).collect();
+ Ty::TraitObject(bounds)
}
})
));
@@ -423,7 +447,7 @@
named!(ty_poly_trait_ref -> Ty, map!(
separated_nonempty_list!(punct!("+"), ty_param_bound),
- Ty::PolyTraitRef
+ Ty::TraitObject
));
named!(ty_impl_trait -> Ty, do_parse!(
@@ -626,14 +650,7 @@
segment.to_tokens(tokens);
}
}
- Ty::ObjectSum(ref ty, ref bounds) => {
- ty.to_tokens(tokens);
- for bound in bounds {
- tokens.append("+");
- bound.to_tokens(tokens);
- }
- }
- Ty::PolyTraitRef(ref bounds) => {
+ Ty::TraitObject(ref bounds) => {
tokens.append_separated(bounds, "+");
}
Ty::ImplTrait(ref bounds) => {
@@ -648,6 +665,7 @@
Ty::Infer => {
tokens.append("_");
}
+ Ty::Mac(ref mac) => mac.to_tokens(tokens),
}
}
}
diff --git a/src/visit.rs b/src/visit.rs
index e23f3f0..a5d4f41 100644
--- a/src/visit.rs
+++ b/src/visit.rs
@@ -28,8 +28,8 @@
/// new default implementation gets introduced.)
pub trait Visitor: Sized {
fn visit_ident(&mut self, _ident: &Ident) {}
- fn visit_macro_input(&mut self, macro_input: &MacroInput) {
- walk_macro_input(self, macro_input)
+ fn visit_derive_input(&mut self, derive_input: &DeriveInput) {
+ walk_derive_input(self, derive_input)
}
fn visit_ty(&mut self, ty: &Ty) {
walk_ty(self, ty)
@@ -76,20 +76,67 @@
walk_const_expr(self, expr)
}
fn visit_lit(&mut self, _lit: &Lit) {}
+
+ fn visit_mac(&mut self, mac: &Mac) {
+ walk_mac(self, mac);
+ }
+
+ #[cfg(feature = "full")]
+ fn visit_crate(&mut self, _crate: &Crate) {
+ walk_crate(self, _crate);
+ }
+ #[cfg(feature = "full")]
+ fn visit_item(&mut self, item: &Item) {
+ walk_item(self, item);
+ }
+ #[cfg(feature = "full")]
+ fn visit_expr(&mut self, expr: &Expr) {
+ walk_expr(self, expr);
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
+ walk_foreign_item(self, foreign_item);
+ }
+ #[cfg(feature = "full")]
+ fn visit_pat(&mut self, pat: &Pat) {
+ walk_pat(self, pat);
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_decl(&mut self, fn_decl: &FnDecl) {
+ walk_fn_decl(self, fn_decl);
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item(&mut self, trait_item: &TraitItem) {
+ walk_trait_item(self, trait_item);
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item(&mut self, impl_item: &ImplItem) {
+ walk_impl_item(self, impl_item);
+ }
+ #[cfg(feature = "full")]
+ fn visit_method_sig(&mut self, method_sig: &MethodSig) {
+ walk_method_sig(self, method_sig);
+ }
+ #[cfg(feature = "full")]
+ fn visit_stmt(&mut self, stmt: &Stmt) {
+ walk_stmt(self, stmt);
+ }
+ #[cfg(feature = "full")]
+ fn visit_local(&mut self, local: &Local) {
+ walk_local(self, local);
+ }
+ #[cfg(feature = "full")]
+ fn visit_view_path(&mut self, view_path: &ViewPath) {
+ walk_view_path(self, view_path);
+ }
}
-#[macro_export]
macro_rules! walk_list {
- ($visitor: expr, $method: ident, $list: expr) => {
+ ($visitor:expr, $method:ident, $list:expr $(, $extra_args:expr)*) => {
for elem in $list {
- $visitor.$method(elem)
+ $visitor.$method(elem $(, $extra_args)*)
}
};
- ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
- for elem in $list {
- $visitor.$method(elem, $($extra_args,)*)
- }
- }
}
pub fn walk_opt_ident<V: Visitor>(visitor: &mut V, opt_ident: &Option<Ident>) {
@@ -110,18 +157,18 @@
visitor.visit_path(&trait_ref.trait_ref);
}
-pub fn walk_macro_input<V: Visitor>(visitor: &mut V, macro_input: &MacroInput) {
- visitor.visit_ident(¯o_input.ident);
- visitor.visit_generics(¯o_input.generics);
- match macro_input.body {
+pub fn walk_derive_input<V: Visitor>(visitor: &mut V, derive_input: &DeriveInput) {
+ visitor.visit_ident(&derive_input.ident);
+ visitor.visit_generics(&derive_input.generics);
+ match derive_input.body {
Body::Enum(ref variants) => {
- walk_list!(visitor, visit_variant, variants, ¯o_input.generics);
+ walk_list!(visitor, visit_variant, variants, &derive_input.generics);
}
Body::Struct(ref variant_data) => {
- visitor.visit_variant_data(variant_data, ¯o_input.ident, ¯o_input.generics);
+ visitor.visit_variant_data(variant_data, &derive_input.ident, &derive_input.generics);
}
}
- walk_list!(visitor, visit_attribute, ¯o_input.attrs);
+ walk_list!(visitor, visit_attribute, &derive_input.attrs);
}
pub fn walk_variant<V>(visitor: &mut V, variant: &Variant, generics: &Generics)
@@ -159,18 +206,17 @@
}
visitor.visit_path(path);
}
- Ty::ObjectSum(ref inner, ref bounds) => {
- visitor.visit_ty(inner);
- walk_list!(visitor, visit_ty_param_bound, bounds);
- }
Ty::Array(ref inner, ref len) => {
visitor.visit_ty(inner);
visitor.visit_const_expr(len);
}
- Ty::PolyTraitRef(ref bounds) |
+ Ty::TraitObject(ref bounds) |
Ty::ImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
+ Ty::Mac(ref mac) => {
+ visitor.visit_mac(mac);
+ }
}
}
@@ -240,6 +286,12 @@
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_lifetime, bounds);
}
+ WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty,
+ ref rhs_ty,
+ .. }) => {
+ visitor.visit_ty(lhs_ty);
+ visitor.visit_ty(rhs_ty);
+ }
}
}
}
@@ -290,6 +342,461 @@
ConstExpr::Paren(ref expr) => {
visitor.visit_const_expr(expr);
}
- ConstExpr::Other(_) => {}
+ ConstExpr::Other(ref other) => {
+ #[cfg(feature = "full")]
+ fn walk_other<V: Visitor>(visitor: &mut V, other: &Expr) {
+ visitor.visit_expr(other);
+ }
+ #[cfg(not(feature = "full"))]
+ fn walk_other<V: Visitor>(_: &mut V, _: &super::constant::Other) {}
+ walk_other(visitor, other);
+ }
+ }
+}
+
+pub fn walk_mac<V: Visitor>(visitor: &mut V, mac: &Mac) {
+ visitor.visit_path(&mac.path);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_crate<V: Visitor>(visitor: &mut V, _crate: &Crate) {
+ walk_list!(visitor, visit_attribute, &_crate.attrs);
+ walk_list!(visitor, visit_item, &_crate.items);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) {
+ visitor.visit_ident(&item.ident);
+ walk_list!(visitor, visit_attribute, &item.attrs);
+ match item.node {
+ ItemKind::ExternCrate(ref ident) => {
+ walk_opt_ident(visitor, ident);
+ }
+ ItemKind::Use(ref view_path) => {
+ visitor.visit_view_path(view_path);
+ }
+ ItemKind::Static(ref ty, _, ref expr) => {
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expr);
+ }
+ ItemKind::Const(ref ty, ref expr) => {
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expr);
+ }
+ ItemKind::Fn(ref decl, _, _, _, ref generics, ref body) => {
+ visitor.visit_fn_decl(decl);
+ visitor.visit_generics(generics);
+ walk_list!(visitor, visit_stmt, &body.stmts);
+ }
+ ItemKind::Mod(ref maybe_items) => {
+ if let Some(ref items) = *maybe_items {
+ walk_list!(visitor, visit_item, items);
+ }
+ }
+ ItemKind::ForeignMod(ref foreign_mod) => {
+ walk_list!(visitor, visit_foreign_item, &foreign_mod.items);
+ }
+ ItemKind::Ty(ref ty, ref generics) => {
+ visitor.visit_ty(ty);
+ visitor.visit_generics(generics);
+ }
+ ItemKind::Enum(ref variant, ref generics) => {
+ walk_list!(visitor, visit_variant, variant, generics);
+ }
+ ItemKind::Struct(ref variant_data, ref generics) => {
+ visitor.visit_variant_data(variant_data, &item.ident, generics);
+ }
+ ItemKind::Union(ref variant_data, ref generics) => {
+ visitor.visit_variant_data(variant_data, &item.ident, generics);
+ }
+ ItemKind::Trait(_, ref generics, ref bounds, ref trait_items) => {
+ visitor.visit_generics(generics);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_trait_item, trait_items);
+ }
+ ItemKind::DefaultImpl(_, ref path) => {
+ visitor.visit_path(path);
+ }
+ ItemKind::Impl(_, _, ref generics, ref maybe_path, ref ty, ref impl_items) => {
+ visitor.visit_generics(generics);
+ if let Some(ref path) = *maybe_path {
+ visitor.visit_path(path);
+ }
+ visitor.visit_ty(ty);
+ walk_list!(visitor, visit_impl_item, impl_items);
+ }
+ ItemKind::Mac(ref mac) => {
+ visitor.visit_mac(mac)
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) {
+ walk_list!(visitor, visit_attribute, &expr.attrs);
+ match expr.node {
+ ExprKind::Box(ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ ExprKind::InPlace(ref place, ref value) => {
+ visitor.visit_expr(place);
+ visitor.visit_expr(value);
+ }
+ ExprKind::Array(ref exprs) => {
+ walk_list!(visitor, visit_expr, exprs);
+ }
+ ExprKind::Call(ref callee, ref args) => {
+ visitor.visit_expr(callee);
+ walk_list!(visitor, visit_expr, args);
+ }
+ ExprKind::MethodCall(ref name, ref ty_args, ref args) => {
+ visitor.visit_ident(name);
+ walk_list!(visitor, visit_ty, ty_args);
+ walk_list!(visitor, visit_expr, args);
+ }
+ ExprKind::Tup(ref exprs) => {
+ walk_list!(visitor, visit_expr, exprs);
+ }
+ ExprKind::Binary(_, ref lhs, ref rhs) => {
+ visitor.visit_expr(lhs);
+ visitor.visit_expr(rhs);
+ }
+ ExprKind::Unary(_, ref operand) => {
+ visitor.visit_expr(operand);
+ }
+ ExprKind::Lit(ref lit) => {
+ visitor.visit_lit(lit);
+ }
+ ExprKind::Cast(ref expr, ref ty) => {
+ visitor.visit_expr(expr);
+ visitor.visit_ty(ty);
+ }
+ ExprKind::Type(ref expr, ref ty) => {
+ visitor.visit_expr(expr);
+ visitor.visit_ty(ty);
+ }
+ ExprKind::If(ref cond, ref cons, ref maybe_alt) => {
+ visitor.visit_expr(cond);
+ walk_list!(visitor, visit_stmt, &cons.stmts);
+ if let Some(ref alt) = *maybe_alt {
+ visitor.visit_expr(alt);
+ }
+ }
+ ExprKind::IfLet(ref pat, ref cond, ref cons, ref maybe_alt) => {
+ visitor.visit_pat(pat);
+ visitor.visit_expr(cond);
+ walk_list!(visitor, visit_stmt, &cons.stmts);
+ if let Some(ref alt) = *maybe_alt {
+ visitor.visit_expr(alt);
+ }
+ }
+ ExprKind::While(ref cond, ref body, ref label) => {
+ visitor.visit_expr(cond);
+ walk_list!(visitor, visit_stmt, &body.stmts);
+ walk_opt_ident(visitor, label);
+ }
+ ExprKind::WhileLet(ref pat, ref cond, ref body, ref label) => {
+ visitor.visit_pat(pat);
+ visitor.visit_expr(cond);
+ walk_list!(visitor, visit_stmt, &body.stmts);
+ walk_opt_ident(visitor, label);
+ }
+ ExprKind::ForLoop(ref pat, ref expr, ref body, ref label) => {
+ visitor.visit_pat(pat);
+ visitor.visit_expr(expr);
+ walk_list!(visitor, visit_stmt, &body.stmts);
+ walk_opt_ident(visitor, label);
+ }
+ ExprKind::Loop(ref body, ref label) => {
+ walk_list!(visitor, visit_stmt, &body.stmts);
+ walk_opt_ident(visitor, label);
+ }
+ ExprKind::Match(ref expr, ref arms) => {
+ visitor.visit_expr(expr);
+ for &Arm{ref attrs, ref pats, ref guard, ref body} in arms {
+ walk_list!(visitor, visit_attribute, attrs);
+ walk_list!(visitor, visit_pat, pats);
+ if let Some(ref guard) = *guard {
+ visitor.visit_expr(guard);
+ }
+ visitor.visit_expr(body);
+ }
+ }
+ ExprKind::Closure(_, ref decl, ref expr) => {
+ visitor.visit_fn_decl(decl);
+ visitor.visit_expr(expr);
+ }
+ ExprKind::Block(_, ref block) => {
+ walk_list!(visitor, visit_stmt, &block.stmts);
+ }
+ ExprKind::Assign(ref lhs, ref rhs) => {
+ visitor.visit_expr(lhs);
+ visitor.visit_expr(rhs);
+ }
+ ExprKind::AssignOp(_, ref lhs, ref rhs) => {
+ visitor.visit_expr(lhs);
+ visitor.visit_expr(rhs);
+ }
+ ExprKind::Field(ref obj, ref field) => {
+ visitor.visit_expr(obj);
+ visitor.visit_ident(field);
+ }
+ ExprKind::TupField(ref obj, _) => {
+ visitor.visit_expr(obj);
+ }
+ ExprKind::Index(ref obj, ref idx) => {
+ visitor.visit_expr(obj);
+ visitor.visit_expr(idx);
+ }
+ ExprKind::Range(ref maybe_start, ref maybe_end, _) => {
+ if let Some(ref start) = *maybe_start {
+ visitor.visit_expr(start);
+ }
+ if let Some(ref end) = *maybe_end {
+ visitor.visit_expr(end);
+ }
+ }
+ ExprKind::Path(ref maybe_qself, ref path) => {
+ if let Some(ref qself) = *maybe_qself {
+ visitor.visit_ty(&qself.ty);
+ }
+ visitor.visit_path(path);
+ }
+ ExprKind::AddrOf(_, ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ ExprKind::Break(ref maybe_label, ref maybe_expr) => {
+ walk_opt_ident(visitor, maybe_label);
+ if let Some(ref expr) = *maybe_expr {
+ visitor.visit_expr(expr);
+ }
+ }
+ ExprKind::Continue(ref maybe_label) => {
+ walk_opt_ident(visitor, maybe_label);
+ }
+ ExprKind::Ret(ref maybe_expr) => {
+ if let Some(ref expr) = *maybe_expr {
+ visitor.visit_expr(expr);
+ }
+ }
+ ExprKind::Mac(ref mac) => {
+ visitor.visit_mac(mac);
+ }
+ ExprKind::Struct(ref path, ref fields, ref maybe_base) => {
+ visitor.visit_path(path);
+ for &FieldValue{ref ident, ref expr, ..} in fields {
+ visitor.visit_ident(ident);
+ visitor.visit_expr(expr);
+ }
+ if let Some(ref base) = *maybe_base {
+ visitor.visit_expr(base);
+ }
+ }
+ ExprKind::Repeat(ref value, ref times) => {
+ visitor.visit_expr(value);
+ visitor.visit_expr(times);
+ }
+ ExprKind::Paren(ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ ExprKind::Try(ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_foreign_item<V: Visitor>(visitor: &mut V, foreign_item: &ForeignItem) {
+ visitor.visit_ident(&foreign_item.ident);
+ walk_list!(visitor, visit_attribute, &foreign_item.attrs);
+ match foreign_item.node {
+ ForeignItemKind::Fn(ref decl, ref generics) => {
+ visitor.visit_fn_decl(decl);
+ visitor.visit_generics(generics);
+ }
+ ForeignItemKind::Static(ref ty, _) => {
+ visitor.visit_ty(ty);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_pat<V: Visitor>(visitor: &mut V, pat: &Pat) {
+ match *pat {
+ Pat::Wild => {}
+ Pat::Ident(_, ref ident, ref maybe_pat) => {
+ visitor.visit_ident(ident);
+ if let Some(ref pat) = *maybe_pat {
+ visitor.visit_pat(pat);
+ }
+ }
+ Pat::Struct(ref path, ref field_pats, _) => {
+ visitor.visit_path(path);
+ for &FieldPat{ref ident, ref pat, ..} in field_pats {
+ visitor.visit_ident(ident);
+ visitor.visit_pat(pat);
+ }
+ }
+ Pat::TupleStruct(ref path, ref pats, _) => {
+ visitor.visit_path(path);
+ walk_list!(visitor, visit_pat, pats);
+ }
+ Pat::Path(ref maybe_qself, ref path) => {
+ if let Some(ref qself) = *maybe_qself {
+ visitor.visit_ty(&qself.ty);
+ }
+ visitor.visit_path(path);
+ }
+ Pat::Tuple(ref pats, _) => {
+ walk_list!(visitor, visit_pat, pats);
+ }
+ Pat::Box(ref pat) |
+ Pat::Ref(ref pat, _) => {
+ visitor.visit_pat(pat);
+ }
+ Pat::Lit(ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ Pat::Range(ref start, ref end) => {
+ visitor.visit_expr(start);
+ visitor.visit_expr(end);
+ }
+ Pat::Slice(ref start, ref maybe_mid, ref end) => {
+ walk_list!(visitor, visit_pat, start);
+ if let Some(ref mid) = *maybe_mid {
+ visitor.visit_pat(mid);
+ }
+ walk_list!(visitor, visit_pat, end);
+ }
+ Pat::Mac(ref mac) => {
+ visitor.visit_mac(mac);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, fn_decl: &FnDecl) {
+ for input in &fn_decl.inputs {
+ match *input {
+ FnArg::SelfRef(_, _) | FnArg::SelfValue(_) => {}
+ FnArg::Captured(ref pat, ref ty) => {
+ visitor.visit_pat(pat);
+ visitor.visit_ty(ty);
+ }
+ FnArg::Ignored(ref ty) => {
+ visitor.visit_ty(ty);
+ }
+ }
+ }
+ visitor.visit_fn_ret_ty(&fn_decl.output);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_trait_item<V: Visitor>(visitor: &mut V, trait_item: &TraitItem) {
+ visitor.visit_ident(&trait_item.ident);
+ walk_list!(visitor, visit_attribute, &trait_item.attrs);
+ match trait_item.node {
+ TraitItemKind::Const(ref ty, ref maybe_expr) => {
+ visitor.visit_ty(ty);
+ if let Some(ref expr) = *maybe_expr {
+ visitor.visit_expr(expr);
+ }
+ }
+ TraitItemKind::Method(ref method_sig, ref maybe_block) => {
+ visitor.visit_method_sig(method_sig);
+ if let Some(ref block) = *maybe_block {
+ walk_list!(visitor, visit_stmt, &block.stmts);
+ }
+ }
+ TraitItemKind::Type(ref bounds, ref maybe_ty) => {
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ if let Some(ref ty) = *maybe_ty {
+ visitor.visit_ty(ty);
+ }
+ }
+ TraitItemKind::Macro(ref mac) => {
+ visitor.visit_mac(mac);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_impl_item<V: Visitor>(visitor: &mut V, impl_item: &ImplItem) {
+ visitor.visit_ident(&impl_item.ident);
+ walk_list!(visitor, visit_attribute, &impl_item.attrs);
+ match impl_item.node {
+ ImplItemKind::Const(ref ty, ref expr) => {
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expr);
+ }
+ ImplItemKind::Method(ref method_sig, ref block) => {
+ visitor.visit_method_sig(method_sig);
+ walk_list!(visitor, visit_stmt, &block.stmts);
+ }
+ ImplItemKind::Type(ref ty) => {
+ visitor.visit_ty(ty);
+ }
+ ImplItemKind::Macro(ref mac) => {
+ visitor.visit_mac(mac);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_method_sig<V: Visitor>(visitor: &mut V, method_sig: &MethodSig) {
+ visitor.visit_fn_decl(&method_sig.decl);
+ visitor.visit_generics(&method_sig.generics);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_stmt<V: Visitor>(visitor: &mut V, stmt: &Stmt) {
+ match *stmt {
+ Stmt::Local(ref local) => {
+ visitor.visit_local(local);
+ }
+ Stmt::Item(ref item) => {
+ visitor.visit_item(item);
+ }
+ Stmt::Expr(ref expr) |
+ Stmt::Semi(ref expr) => {
+ visitor.visit_expr(expr);
+ }
+ Stmt::Mac(ref details) => {
+ let (ref mac, _, ref attrs) = **details;
+ visitor.visit_mac(mac);
+ walk_list!(visitor, visit_attribute, attrs);
+ }
+ }
+}
+
+#[cfg(feature = "full")]
+pub fn walk_local<V: Visitor>(visitor: &mut V, local: &Local) {
+ visitor.visit_pat(&local.pat);
+ if let Some(ref ty) = local.ty {
+ visitor.visit_ty(ty);
+ }
+ if let Some(ref init) = local.init {
+ visitor.visit_expr(init);
+ }
+ walk_list!(visitor, visit_attribute, &local.attrs);
+}
+
+#[cfg(feature = "full")]
+pub fn walk_view_path<V: Visitor>(visitor: &mut V, view_path: &ViewPath) {
+ match *view_path {
+ ViewPath::Simple(ref path, ref maybe_ident) => {
+ visitor.visit_path(path);
+ walk_opt_ident(visitor, maybe_ident);
+ }
+ ViewPath::Glob(ref path) => {
+ visitor.visit_path(path);
+ }
+ ViewPath::List(ref path, ref items) => {
+ visitor.visit_path(path);
+ for &PathListItem{ref name, ref rename} in items {
+ visitor.visit_ident(name);
+ walk_opt_ident(visitor, rename);
+ }
+ }
}
}
diff --git a/tests/rust b/tests/rust
index fc2373c..71c06a5 160000
--- a/tests/rust
+++ b/tests/rust
@@ -1 +1 @@
-Subproject commit fc2373c5a24646745dcbc14dc58889a9d8843f4e
+Subproject commit 71c06a56a120a0d5e3b224105ee3e6754f83e5fa
diff --git a/tests/test_expand.rs b/tests/test_expand.rs
deleted file mode 100644
index dc351ef..0000000
--- a/tests/test_expand.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-#![cfg(feature = "expand")]
-
-extern crate syn;
-use syn::*;
-
-#[macro_use]
-extern crate quote;
-use quote::Tokens;
-
-extern crate tempdir;
-use tempdir::TempDir;
-
-use std::fs::File;
-use std::io::{Read, Write};
-
-#[test]
-fn test_cfg() {
- let original = quote! {
- use super::*;
-
- #[derive(A)]
- struct P;
-
- #[cfg_attr(feature = "q", derive(A))]
- struct Q;
-
- #[derive(A)]
- #[cfg(feature = "r")]
- struct R;
-
- #[cfg(feature = "s1")]
- #[cfg(all(feature = "s2", feature = "s3"))]
- #[cfg_attr(feature = "s4", derive(A))]
- struct S;
- };
-
- let expected = quote! {
- // Unmodified from the input
- use super::*;
-
- type P = ();
-
- #[cfg(feature = "q")]
- type Q = ();
-
- #[cfg(feature = "r")]
- type R = ();
-
- #[cfg(all(feature = "s1", feature = "s2", feature = "s3", feature = "s4"))]
- type S = ();
- };
-
- test_expand(original, expected);
-}
-
-#[test]
-fn test_recursive() {
- let original = quote! {
- #[d]
- #[cfg_attr(feature = "f", derive(Copy, B, Clone))]
- #[e]
- #[cfg(feature = "e")]
- struct T;
- };
-
- let expected = quote! {
- // From #[derive(A)] on struct S produced by #[derive(B)]
- #[cfg(all(feature = "e", feature = "f", feature = "g"))]
- type S = ();
-
- // From #[derive(B)] on struct T
- #[cfg(all(feature = "e", feature = "f"))]
- impl B for T {}
-
- // From the input
- #[d]
- #[cfg_attr(feature = "f", derive(Copy, Clone))]
- #[e]
- #[cfg(feature = "e")]
- struct T;
- };
-
- test_expand(original, expected);
-}
-
-fn test_expand(original: Tokens, expected: Tokens) {
- let dir = TempDir::new("syn").expect("create temp dir");
- let src_path = dir.path().join("expand.in.rs");
- let dst_path = dir.path().join("expand.rs");
-
- // Write the src file
- let mut src_file = File::create(&src_path).expect("create temp file");
- src_file.write_all(original.to_string().as_bytes()).expect("write temp file");
-
- // Run expansion
- let mut registry = Registry::new();
- registry.add_derive("A", expand_a);
- registry.add_derive("B", expand_b);
- registry.expand_file(&src_path, &dst_path).unwrap();
-
- // Read the dst file
- let mut expanded = String::new();
- let mut dst_file = File::open(&dst_path).expect("open output file");
- dst_file.read_to_string(&mut expanded).expect("read output file");
- let krate = parse_crate(&expanded).expect("parse output file");
-
- assert_eq!(quote!(#krate), expected);
-}
-
-fn expand_a(input: MacroInput) -> Result<Expanded, String> {
- let name = &input.ident;
- let out = quote! {
- type #name = ();
- };
- Ok(Expanded {
- new_items: parse_items(&out.to_string()).unwrap(),
- original: None,
- })
-}
-
-fn expand_b(input: MacroInput) -> Result<Expanded, String> {
- assert_eq!(quote!(#input), quote! {
- #[d]
- #[cfg_attr(feature = "f", derive(Copy, Clone))]
- #[e]
- struct T;
- });
- let out = quote! {
- #[cfg_attr(feature = "g", derive(A))]
- struct S;
-
- impl B for T {}
- };
- Ok(Expanded {
- new_items: parse_items(&out.to_string()).unwrap(),
- original: Some(input),
- })
-}
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index c0e21fb..822d22d 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -58,14 +58,45 @@
};
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
-
let tokens = quote! {
impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
};
-
let expected = concat!("impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
"MyTrait for Test < 'a , 'b , T > ",
"where T : Debug { }");
-
assert_eq!(expected, tokens.to_string());
+
+ let turbofish = ty_generics.as_turbofish();
+ let tokens = quote! {
+ Test #turbofish
+ };
+ let expected = "Test :: < 'a , 'b , T >";
+ assert_eq!(expected, tokens.to_string());
+}
+
+#[test]
+fn test_ty_param_bound() {
+ let tokens = quote!('a);
+ let expected = TyParamBound::Region(Lifetime::new("'a"));
+ assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
+
+ let tokens = quote!(Debug);
+ let expected = TyParamBound::Trait(
+ PolyTraitRef {
+ bound_lifetimes: Vec::new(),
+ trait_ref: "Debug".into(),
+ },
+ TraitBoundModifier::None,
+ );
+ assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
+
+ let tokens = quote!(?Sized);
+ let expected = TyParamBound::Trait(
+ PolyTraitRef {
+ bound_lifetimes: Vec::new(),
+ trait_ref: "Sized".into(),
+ },
+ TraitBoundModifier::Maybe,
+ );
+ assert_eq!(expected, parse_ty_param_bound(tokens.as_str()).unwrap());
}
diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs
index 2d808b5..2b8528f 100644
--- a/tests/test_round_trip.rs
+++ b/tests/test_round_trip.rs
@@ -52,13 +52,7 @@
// TODO better support for attributes
"tests/rust/src/test/run-pass/item-attributes.rs" |
// TODO precedence issue with binop vs poly trait ref
- "tests/rust/src/test/run-pass/try-macro.rs" |
- // TODO type macros
- "tests/rust/src/test/run-pass/type-macros-hlist.rs" |
- // TODO type macros
- "tests/rust/src/test/run-pass/type-macros-simple.rs" |
- // TODO type macros
- "tests/rust/src/test/run-pass-fulldeps/proc_macro.rs" => false,
+ "tests/rust/src/test/run-pass/try-macro.rs" => false,
_ => true,
}
}
@@ -151,8 +145,9 @@
Visibility};
use syntex_syntax::codemap::{self, Spanned};
use syntex_syntax::fold::{self, Folder};
- use syntex_syntax::parse::token::{Lit, Token, intern};
+ use syntex_syntax::parse::token::{Lit, Token};
use syntex_syntax::ptr::P;
+ use syntex_syntax::symbol::Symbol;
use syntex_syntax::tokenstream::{Delimited, SequenceRepetition, TokenTree};
use syntex_syntax::util::move_map::MoveMap;
use syntex_syntax::util::small_vector::SmallVector;
@@ -169,12 +164,12 @@
// so many equivalent representations of the same literal; they are
// tested elsewhere
match l {
- Lit::Byte(_) => Lit::Byte(intern("")),
- Lit::Char(_) => Lit::Char(intern("")),
- Lit::Integer(_) => Lit::Integer(intern("")),
- Lit::Float(_) => Lit::Float(intern("")),
- Lit::Str_(_) => Lit::Str_(intern("")),
- Lit::ByteStr(_) => Lit::ByteStr(intern("")),
+ Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
+ Lit::Char(_) => Lit::Char(Symbol::intern("")),
+ Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
+ Lit::Float(_) => Lit::Float(Symbol::intern("")),
+ Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
+ Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
_ => l,
}
}
@@ -295,26 +290,26 @@
}
fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
- at.node.id.0 = 0;
+ at.id.0 = 0;
fold::noop_fold_attribute(at, self)
}
- fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> {
- meta_item.map(|Spanned { node, span }| {
- Spanned {
- node: match node {
- MetaItemKind::Word(id) => MetaItemKind::Word(id),
- MetaItemKind::List(id, mis) => {
- MetaItemKind::List(id, mis.move_map(|e| self.fold_meta_list_item(e)))
- }
- // default fold_meta_item does not fold the value span
- MetaItemKind::NameValue(id, lit) => {
- MetaItemKind::NameValue(id, self.fold_spanned(lit))
- }
- },
- span: self.new_span(span),
- }
- })
+ fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
+ let MetaItem { name, node, span } = meta_item;
+ MetaItem {
+ name: name,
+ node: match node {
+ MetaItemKind::Word => MetaItemKind::Word,
+ MetaItemKind::List(nested) => {
+ MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
+ }
+ // default fold_meta_item does not fold the value span
+ MetaItemKind::NameValue(lit) => {
+ MetaItemKind::NameValue(self.fold_spanned(lit))
+ }
+ },
+ span: self.new_span(span),
+ }
}
fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {