Merge syn-error-experiment
diff --git a/.gitignore b/.gitignore
index b1c7301..aba0fb5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-/Cargo.lock
-/target
-**/*.rs.bk
+target
+Cargo.lock
+tests/rust/*
+!tests/rust/clone.sh
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bd79341
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,64 @@
+sudo: false
+language: rust
+
+cache:
+ cargo: true
+ directories:
+ - tests/rust
+
+rust:
+ - nightly
+ - stable
+ - beta
+ - 1.15.1
+
+before_script:
+ - set -o errexit
+
+script:
+ - cargo build --no-default-features
+ - cargo build
+ - cargo build --features full
+ - cargo build --features 'fold visit visit-mut'
+ - cargo build --features 'full fold visit visit-mut'
+ - cargo build --no-default-features --features derive
+ - cargo build --no-default-features --features 'derive parsing'
+ - cargo build --no-default-features --features 'derive printing'
+ - cargo build --no-default-features --features full
+ - cargo build --no-default-features --features 'full parsing'
+ - cargo build --no-default-features --features 'full printing'
+ - cargo build --no-default-features --features 'full parsing printing'
+ - cargo build --no-default-features --features 'fold visit visit-mut parsing printing'
+ - cargo build --no-default-features --features 'full fold visit visit-mut parsing printing'
+
+matrix:
+ include:
+ - rust: nightly
+ env: ROLE=test
+ script:
+ - cargo test --all-features --release
+ - rust: nightly
+ env: ROLE=codegen
+ script:
+ - (cd codegen && cargo run)
+ - git diff --exit-code
+ - rust: nightly
+ env: ROLE=minimal
+ script:
+ - cargo update -Z minimal-versions
+ - cargo build --all-features
+ - rust: nightly
+ env: ROLE=clippy
+ script:
+ - rustup component add clippy-preview
+ - cargo clippy --all-features -- -Dclippy
+ allow_failures:
+ - rust: nightly
+ env: ROLE=clippy
+ fast_finish: true
+
+env:
+ matrix:
+ - ROLE=build
+ global:
+ - RUST_MIN_STACK=20000000
diff --git a/Cargo.toml b/Cargo.toml
index 6dd6f14..5faba2b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,21 +1,48 @@
[package]
-name = "syn-error-experiment"
-version = "0.0.0"
+name = "syn"
+version = "0.14.9" # don't forget to update html_root_url
authors = ["David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0"
-description = "Syn error experiment"
-repository = "https://github.com/dtolnay/syn/issues/47"
-documentation = "https://docs.rs/syn-error-experiment"
+description = "Nom parser for Rust source code"
+repository = "https://github.com/dtolnay/syn"
+documentation = "https://docs.rs/syn"
categories = ["development-tools::procedural-macro-helpers"]
+readme = "README.md"
+include = ["/Cargo.toml", "/src/**/*.rs", "/README.md", "/LICENSE-APACHE", "/LICENSE-MIT"]
+
+[[example]]
+name = "dump-syntax"
+path = "examples/dump-syntax/main.rs"
+required-features = ["full", "parsing", "extra-traits"]
[features]
-default = ["proc-macro"]
-proc-macro = ["proc-macro2/proc-macro", "syn/proc-macro"]
+default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"]
+derive = []
+full = []
+parsing = []
+printing = ["quote"]
+visit = []
+visit-mut = []
+fold = []
+clone-impls = []
+extra-traits = []
+proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]
[dependencies]
-proc-macro2 = { version = "0.4", default-features = false }
+proc-macro2 = { version = "0.4.4", default-features = false }
+quote = { version = "0.6", optional = true, default-features = false }
+unicode-xid = "0.1"
-[dependencies.syn]
-version = "0.14"
-default-features = false
-features = ["parsing"]
+[dev-dependencies]
+rayon = "1.0"
+regex = "1.0"
+walkdir = "2.1"
+
+[package.metadata.docs.rs]
+all-features = true
+
+[package.metadata.playground]
+all-features = true
+
+[badges]
+travis-ci = { repository = "dtolnay/syn" }
diff --git a/LICENSE-MIT b/LICENSE-MIT
index 31aa793..5767dea 100644
--- a/LICENSE-MIT
+++ b/LICENSE-MIT
@@ -1,3 +1,5 @@
+Copyright (c) 2018 Syn Developers
+
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e7a51ab
--- /dev/null
+++ b/README.md
@@ -0,0 +1,282 @@
+Nom parser for Rust source code
+===============================
+
+[](https://travis-ci.org/dtolnay/syn)
+[](https://crates.io/crates/syn)
+[](https://docs.rs/syn/0.14/syn/)
+[](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html)
+
+Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree
+of Rust source code.
+
+Currently this library is geared toward the [custom derive] use case but
+contains some APIs that may be useful for Rust procedural macros more generally.
+
+[custom derive]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
+
+- **Data structures** — Syn provides a complete syntax tree that can represent
+ any valid Rust source code. The syntax tree is rooted at [`syn::File`] which
+ represents a full source file, but there are other entry points that may be
+ useful to procedural macros including [`syn::Item`], [`syn::Expr`] and
+ [`syn::Type`].
+
+- **Custom derives** — Of particular interest to custom derives is
+ [`syn::DeriveInput`] which is any of the three legal input items to a derive
+ macro. An example below shows using this type in a library that can derive
+ implementations of a trait of your own.
+
+- **Parser combinators** — Parsing in Syn is built on a suite of public parser
+ combinator macros that you can use for parsing any token-based syntax you
+ dream up within a `functionlike!(...)` procedural macro. Every syntax tree
+ node defined by Syn is individually parsable and may be used as a building
+ block for custom syntaxes, or you may do it all yourself working from the most
+ primitive tokens.
+
+- **Location information** — Every token parsed by Syn is associated with a
+ `Span` that tracks line and column information back to the source of that
+ token. These spans allow a procedural macro to display detailed error messages
+ pointing to all the right places in the user's code. There is an example of
+ this below.
+
+- **Feature flags** — Functionality is aggressively feature gated so your
+ procedural macros enable only what they need, and do not pay in compile time
+ for all the rest.
+
+[`syn::File`]: https://docs.rs/syn/0.14/syn/struct.File.html
+[`syn::Item`]: https://docs.rs/syn/0.14/syn/enum.Item.html
+[`syn::Expr`]: https://docs.rs/syn/0.14/syn/enum.Expr.html
+[`syn::Type`]: https://docs.rs/syn/0.14/syn/enum.Type.html
+[`syn::DeriveInput`]: https://docs.rs/syn/0.14/syn/struct.DeriveInput.html
+
+If you get stuck with anything involving procedural macros in Rust I am happy to
+provide help even if the issue is not related to Syn. Please file a ticket in
+this repo.
+
+*Version requirement: Syn supports any compiler version back to Rust's very
+first support for procedural macros in Rust 1.15.0. Some features especially
+around error reporting are only available in newer compilers or on the nightly
+channel.*
+
+[*Release notes*](https://github.com/dtolnay/syn/releases)
+
+## Example of a custom derive
+
+The canonical custom derive using Syn looks like this. We write an ordinary Rust
+function tagged with a `proc_macro_derive` attribute and the name of the trait
+we are deriving. Any time that derive appears in the user's code, the Rust
+compiler passes their data structure as tokens into our macro. We get to execute
+arbitrary Rust code to figure out what to do with those tokens, then hand some
+tokens back to the compiler to compile into the user's crate.
+
+[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
+
+```toml
+[dependencies]
+syn = "0.14"
+quote = "0.6"
+
+[lib]
+proc-macro = true
+```
+
+```rust
+extern crate proc_macro;
+extern crate syn;
+
+#[macro_use]
+extern crate quote;
+
+use proc_macro::TokenStream;
+use syn::DeriveInput;
+
+#[proc_macro_derive(MyMacro)]
+pub fn my_macro(input: TokenStream) -> TokenStream {
+ // Parse the input tokens into a syntax tree
+ let input: DeriveInput = syn::parse(input).unwrap();
+
+ // Build the output, possibly using quasi-quotation
+ let expanded = quote! {
+ // ...
+ };
+
+ // Hand the output tokens back to the compiler
+ expanded.into()
+}
+```
+
+The [`heapsize`] example directory shows a complete working Macros 1.1
+implementation of a custom derive. It works on any Rust compiler \>=1.15.0. The
+example derives a `HeapSize` trait which computes an estimate of the amount of
+heap memory owned by a value.
+
+[`heapsize`]: examples/heapsize
+
+```rust
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+```
+
+The custom derive allows users to write `#[derive(HeapSize)]` on data structures
+in their program.
+
+```rust
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+```
+
+## Spans and error reporting
+
+The [`heapsize2`] example directory is an extension of the `heapsize` example
+that demonstrates some of the hygiene and error reporting properties of Macros
+2.0. This example currently requires a nightly Rust compiler \>=1.24.0-nightly
+but we are working to stabilize all of the APIs involved.
+
+[`heapsize2`]: examples/heapsize2
+
+The token-based procedural macro API provides great control over where the
+compiler's error messages are displayed in user code. Consider the error the
+user sees if one of their field types does not implement `HeapSize`.
+
+```rust
+#[derive(HeapSize)]
+struct Broken {
+ ok: String,
+ bad: std::thread::Thread,
+}
+```
+
+In the Macros 1.1 string-based procedural macro world, the resulting error would
+point unhelpfully to the invocation of the derive macro and not to the actual
+problematic field.
+
+```
+error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope
+ --> src/main.rs:4:10
+ |
+4 | #[derive(HeapSize)]
+ | ^^^^^^^^
+```
+
+By tracking span information all the way through the expansion of a procedural
+macro as shown in the `heapsize2` example, token-based macros in Syn are able to
+trigger errors that directly pinpoint the source of the problem.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
+
+## Parsing a custom syntax using combinators
+
+The [`lazy-static`] example directory shows the implementation of a
+`functionlike!(...)` procedural macro in which the input tokens are parsed using
+[`nom`]-style parser combinators.
+
+[`lazy-static`]: examples/lazy-static
+[`nom`]: https://github.com/Geal/nom
+
+The example reimplements the popular `lazy_static` crate from crates.io as a
+procedural macro.
+
+```
+lazy_static! {
+ static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+}
+```
+
+The implementation shows how to trigger custom warnings and error messages on
+the macro input.
+
+```
+warning: come on, pick a more creative name
+ --> src/main.rs:10:16
+ |
+10 | static ref FOO: String = "lazy_static".to_owned();
+ | ^^^
+```
+
+## 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`] subcommand.
+
+[`cargo expand`]: https://github.com/dtolnay/cargo-expand
+
+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][debugging].
+
+[debugging]: 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
+compile time for the most common use cases. The following features are
+available.
+
+- **`derive`** *(enabled by default)* — Data structures for representing the
+ possible input to a custom derive, including structs and enums and types.
+- **`full`** — Data structures for representing the syntax tree of all valid
+ Rust source code, including items and expressions.
+- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a
+ syntax tree node of a chosen type.
+- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as
+ tokens of Rust source code.
+- **`visit`** — Trait for traversing a syntax tree.
+- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree.
+- **`fold`** — Trait for transforming an owned syntax tree.
+- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
+ types.
+- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
+ types.
+- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic
+ library libproc_macro from rustc toolchain.
+
+## Nightly features
+
+By default Syn uses the [`proc-macro2`] crate to emulate the nightly compiler's
+procedural macro API in a stable way that works all the way back to Rust 1.15.0.
+This shim makes it possible to write code without regard for whether the current
+compiler version supports the features we use.
+
+[`proc-macro2`]: https://github.com/alexcrichton/proc-macro2
+
+On a nightly compiler, to eliminate the stable shim and use the compiler's
+`proc-macro` directly, add `proc-macro2` to your Cargo.toml and set its
+`"nightly"` feature which bypasses the stable shim.
+
+```toml
+[dependencies]
+syn = "0.14"
+proc-macro2 = { version = "0.4", features = ["nightly"] }
+```
+
+## License
+
+Licensed under either of
+
+ * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..020c8ac
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,16 @@
+environment:
+ matrix:
+ - TARGET: x86_64-pc-windows-msvc
+
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
+ - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;C:\MinGW\bin
+ - rustc -V
+ - cargo -V
+
+build: false
+
+test_script:
+ - cargo build --all-features
diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml
new file mode 100644
index 0000000..3d3c391
--- /dev/null
+++ b/codegen/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "syn_codegen"
+version = "0.1.0"
+authors = ["Nika Layzell <nika@thelayzells.com>"]
+
+publish = false # this is an internal crate which should never be published
+
+[dependencies]
+syn = { path = "..", features = ["full", "extra-traits"] }
+quote = "0.6"
+failure = "0.1"
+inflections = "1.1"
+proc-macro2 = "0.4"
+rustfmt-nightly = "0.99"
diff --git a/codegen/README.md b/codegen/README.md
new file mode 100644
index 0000000..df46bd2
--- /dev/null
+++ b/codegen/README.md
@@ -0,0 +1,12 @@
+# syn_codegen
+
+This is an internal (not published on crates.io) crate which is used to generate
+the files in the `gen/` directory of `syn`. It is used to ensure that the
+implementations for `Fold`, `Visit`, and `VisitMut` remain in sync with the
+actual AST.
+
+To run this program, run `cargo run` in this directory, and the `gen/` folder
+will be re-generated.
+
+This program is slow, and is therefore not run when building `syn` as part of
+the build script to save on compile time.
diff --git a/codegen/src/main.rs b/codegen/src/main.rs
new file mode 100644
index 0000000..0cf873e
--- /dev/null
+++ b/codegen/src/main.rs
@@ -0,0 +1,1173 @@
+//! This crate automatically generates the definition of the `Visit`,
+//! `VisitMut`, and `Fold` traits in `syn` based on the `syn` source. It
+//! discovers structs and enums declared with the `ast_*` macros and generates
+//! the functions for those types.
+//!
+//! It makes a few assumptions about the target crate:
+//! 1. All structs which are discovered must be re-exported in the root of the
+//! crate, even if they were declared in a submodule.
+//! 2. This code cannot discover submodules which are located in subdirectories
+//! - only submodules located in the same directory.
+//! 3. The path to `syn` is hardcoded.
+
+#![recursion_limit = "128"]
+#![cfg_attr(
+ feature = "cargo-clippy",
+ allow(
+ needless_pass_by_value,
+ redundant_closure,
+ write_with_newline,
+ )
+)]
+
+#[macro_use]
+extern crate failure;
+extern crate inflections;
+extern crate proc_macro2;
+#[macro_use]
+extern crate quote;
+#[macro_use]
+extern crate syn;
+extern crate rustfmt_nightly as rustfmt;
+
+use failure::{err_msg, Error};
+use proc_macro2::{Span, TokenStream};
+use quote::ToTokens;
+use syn::{Attribute, Data, DataStruct, DeriveInput, Ident, Item};
+
+use std::collections::BTreeMap;
+use std::fmt::{self, Debug};
+use std::fs::File;
+use std::io::{Read, Write};
+use std::path::Path;
+
+const SYN_CRATE_ROOT: &str = "../src/lib.rs";
+
+const FOLD_SRC: &str = "../src/gen/fold.rs";
+const VISIT_SRC: &str = "../src/gen/visit.rs";
+const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
+
+const IGNORED_MODS: &[&str] = &["fold", "visit", "visit_mut"];
+
+const EXTRA_TYPES: &[&str] = &["Lifetime"];
+
+const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
+
+fn path_eq(a: &syn::Path, b: &str) -> bool {
+ if a.global() {
+ return false;
+ }
+ if a.segments.len() != 1 {
+ return false;
+ }
+ a.segments[0].ident == b
+}
+
+fn get_features(attrs: &[Attribute], mut features: TokenStream) -> TokenStream {
+ for attr in attrs {
+ if path_eq(&attr.path, "cfg") {
+ attr.to_tokens(&mut features);
+ }
+ }
+ features
+}
+
+#[derive(Clone)]
+pub struct AstItem {
+ ast: DeriveInput,
+ features: TokenStream,
+ // True if this is an ast_enum_of_structs! item with a #full annotation.
+ eos_full: bool,
+}
+
+impl Debug for AstItem {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("AstItem")
+ .field("ast", &self.ast)
+ .field("features", &self.features.to_string())
+ .finish()
+ }
+}
+
+// NOTE: BTreeMap is used here instead of HashMap to have deterministic output.
+type Lookup = BTreeMap<Ident, AstItem>;
+
+fn load_file<P: AsRef<Path>>(
+ name: P,
+ features: &TokenStream,
+ lookup: &mut Lookup,
+) -> Result<(), Error> {
+ let name = name.as_ref();
+ let parent = name.parent().ok_or_else(|| err_msg("no parent path"))?;
+
+ let mut f = File::open(name)?;
+ let mut src = String::new();
+ f.read_to_string(&mut src)?;
+
+ // Parse the file
+ let file =
+ syn::parse_file(&src).map_err(|_| format_err!("failed to parse {}", name.display()))?;
+
+ // Collect all of the interesting AstItems declared in this file or submodules.
+ 'items: for item in file.items {
+ match item {
+ Item::Mod(item) => {
+ // Don't inspect inline modules.
+ if item.content.is_some() {
+ continue;
+ }
+
+ // We don't want to try to load the generated rust files and
+ // parse them, so we ignore them here.
+ for name in IGNORED_MODS {
+ if item.ident == name {
+ continue 'items;
+ }
+ }
+
+ // Lookup any #[cfg()] attributes on the module and add them to
+ // the feature set.
+ //
+ // The derive module is weird because it is built with either
+ // `full` or `derive` but exported only under `derive`.
+ let features = if item.ident == "derive" {
+ quote!(#[cfg(feature = "derive")])
+ } else {
+ get_features(&item.attrs, features.clone())
+ };
+
+ // Look up the submodule file, and recursively parse it.
+ // XXX: Only handles same-directory .rs file submodules.
+ let path = parent.join(&format!("{}.rs", item.ident));
+ load_file(path, &features, lookup)?;
+ }
+ Item::Macro(item) => {
+ // Lookip any #[cfg()] attributes directly on the macro
+ // invocation, and add them to the feature set.
+ let features = get_features(&item.attrs, features.clone());
+
+ // Try to parse the AstItem declaration out of the item.
+ let tts = &item.mac.tts;
+ let found = if path_eq(&item.mac.path, "ast_struct") {
+ syn::parse_str::<parsing::AstStruct>("e!(#tts).to_string())
+ .map_err(|_| err_msg("failed to parse ast_struct"))?
+ .0
+ } else if path_eq(&item.mac.path, "ast_enum") {
+ syn::parse_str::<parsing::AstEnum>("e!(#tts).to_string())
+ .map_err(|_| err_msg("failed to parse ast_enum"))?
+ .0
+ } else if path_eq(&item.mac.path, "ast_enum_of_structs") {
+ syn::parse_str::<parsing::AstEnumOfStructs>("e!(#tts).to_string())
+ .map_err(|_| err_msg("failed to parse ast_enum_of_structs"))?
+ .0
+ } else {
+ continue;
+ };
+
+ // Record our features on the parsed AstItems.
+ for mut item in found {
+ features.to_tokens(&mut item.features);
+ lookup.insert(item.ast.ident.clone(), item);
+ }
+ }
+ Item::Struct(item) => {
+ let ident = item.ident;
+ if EXTRA_TYPES.contains(&&ident.to_string()[..]) {
+ lookup.insert(
+ ident.clone(),
+ AstItem {
+ ast: DeriveInput {
+ ident,
+ vis: item.vis,
+ attrs: item.attrs,
+ generics: item.generics,
+ data: Data::Struct(DataStruct {
+ fields: item.fields,
+ struct_token: item.struct_token,
+ semi_token: item.semi_token,
+ }),
+ },
+ features: features.clone(),
+ eos_full: false,
+ },
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+ Ok(())
+}
+
+mod parsing {
+ use super::AstItem;
+
+ use proc_macro2::TokenStream;
+ use syn;
+ use syn::synom::*;
+ use syn::*;
+
+ // Parses #full - returns #[cfg(feature = "full")] if it is present, and
+ // nothing otherwise.
+ named!(full -> (TokenStream, bool), map!(option!(do_parse!(
+ punct!(#) >>
+ id: syn!(Ident) >>
+ cond_reduce!(id == "full") >>
+ ()
+ )), |s| if s.is_some() {
+ (quote!(#[cfg(feature = "full")]), true)
+ } else {
+ (quote!(), false)
+ }));
+
+ named!(manual_extra_traits -> (), do_parse!(
+ punct!(#) >>
+ id: syn!(Ident) >>
+ cond_reduce!(id == "manual_extra_traits") >>
+ ()
+ ));
+
+ // Parses a simple AstStruct without the `pub struct` prefix.
+ named!(ast_struct_inner -> AstItem, do_parse!(
+ id: syn!(Ident) >>
+ features: full >>
+ option!(manual_extra_traits) >>
+ rest: syn!(TokenStream) >>
+ (AstItem {
+ ast: syn::parse_str("e! {
+ pub struct #id #rest
+ }.to_string())?,
+ features: features.0,
+ eos_full: features.1,
+ })
+ ));
+
+ // ast_struct! parsing
+ pub struct AstStruct(pub Vec<AstItem>);
+ impl Synom for AstStruct {
+ named!(parse -> Self, do_parse!(
+ many0!(Attribute::parse_outer) >>
+ keyword!(pub) >>
+ keyword!(struct) >>
+ res: call!(ast_struct_inner) >>
+ (AstStruct(vec![res]))
+ ));
+ }
+
+ named!(no_visit -> (), do_parse!(
+ punct!(#) >>
+ id: syn!(Ident) >>
+ cond_reduce!(id == "no_visit") >>
+ ()
+ ));
+
+ // ast_enum! parsing
+ pub struct AstEnum(pub Vec<AstItem>);
+ impl Synom for AstEnum {
+ named!(parse -> Self, do_parse!(
+ many0!(Attribute::parse_outer) >>
+ keyword!(pub) >>
+ keyword!(enum) >>
+ id: syn!(Ident) >>
+ no_visit: option!(no_visit) >>
+ rest: syn!(TokenStream) >>
+ (AstEnum(if no_visit.is_some() {
+ vec![]
+ } else {
+ vec![AstItem {
+ ast: syn::parse_str("e! {
+ pub enum #id #rest
+ }.to_string())?,
+ features: quote!(),
+ eos_full: false,
+ }]
+ }))
+ ));
+ }
+
+ // A single variant of an ast_enum_of_structs!
+ struct EosVariant {
+ name: Ident,
+ member: Option<Path>,
+ inner: Option<AstItem>,
+ }
+ named!(eos_variant -> EosVariant, do_parse!(
+ many0!(Attribute::parse_outer) >>
+ keyword!(pub) >>
+ variant: syn!(Ident) >>
+ member: option!(map!(parens!(alt!(
+ call!(ast_struct_inner) => { |x: AstItem| (Path::from(x.ast.ident.clone()), Some(x)) }
+ |
+ syn!(Path) => { |x| (x, None) }
+ )), |x| x.1)) >>
+ punct!(,) >>
+ (EosVariant {
+ name: variant,
+ member: member.clone().map(|x| x.0),
+ inner: member.map(|x| x.1).unwrap_or_default(),
+ })
+ ));
+
+ // ast_enum_of_structs! parsing
+ pub struct AstEnumOfStructs(pub Vec<AstItem>);
+ impl Synom for AstEnumOfStructs {
+ named!(parse -> Self, do_parse!(
+ many0!(Attribute::parse_outer) >>
+ keyword!(pub) >>
+ keyword!(enum) >>
+ id: syn!(Ident) >>
+ variants: braces!(many0!(eos_variant)) >>
+ option!(syn!(Ident)) >> // do_not_generate_to_tokens
+ ({
+ let enum_item = {
+ let variants = variants.1.iter().map(|v| {
+ let name = v.name.clone();
+ match v.member {
+ Some(ref member) => quote!(#name(#member)),
+ None => quote!(#name),
+ }
+ });
+ parse_quote! {
+ pub enum #id {
+ #(#variants),*
+ }
+ }
+ };
+ let mut items = vec![AstItem {
+ ast: enum_item,
+ features: quote!(),
+ eos_full: false,
+ }];
+ items.extend(variants.1.into_iter().filter_map(|v| v.inner));
+ AstEnumOfStructs(items)
+ })
+ ));
+ }
+}
+
+mod codegen {
+ use super::{AstItem, Lookup};
+ use inflections::Inflect;
+ use proc_macro2::{Span, TokenStream};
+ use quote::{ToTokens, TokenStreamExt};
+ use syn::punctuated::Punctuated;
+ use syn::synom::ext::IdentExt;
+ use syn::synom::Parser;
+ use syn::*;
+
+ #[derive(Default)]
+ pub struct State {
+ pub visit_trait: TokenStream,
+ pub visit_impl: TokenStream,
+ pub visit_mut_trait: TokenStream,
+ pub visit_mut_impl: TokenStream,
+ pub fold_trait: TokenStream,
+ pub fold_impl: TokenStream,
+ }
+
+ fn under_name(name: Ident) -> Ident {
+ Ident::new(&name.to_string().to_snake_case(), Span::call_site())
+ }
+
+ enum RelevantType<'a> {
+ Box(&'a Type),
+ Vec(&'a Type),
+ Punctuated(&'a Type),
+ Option(&'a Type),
+ Tuple(&'a Punctuated<Type, Token![,]>),
+ Simple(&'a AstItem),
+ TokenPunct(TokenStream),
+ TokenKeyword(TokenStream),
+ TokenGroup(Ident),
+ Pass,
+ }
+
+ fn classify<'a>(ty: &'a Type, lookup: &'a Lookup) -> RelevantType<'a> {
+ match *ty {
+ Type::Path(TypePath {
+ qself: None,
+ ref path,
+ }) => {
+ let last = path.segments.last().unwrap().into_value();
+ match &last.ident.to_string()[..] {
+ "Box" => RelevantType::Box(first_arg(&last.arguments)),
+ "Vec" => RelevantType::Vec(first_arg(&last.arguments)),
+ "Punctuated" => RelevantType::Punctuated(first_arg(&last.arguments)),
+ "Option" => RelevantType::Option(first_arg(&last.arguments)),
+ "Brace" | "Bracket" | "Paren" | "Group" => {
+ RelevantType::TokenGroup(last.ident.clone())
+ }
+ _ => {
+ if let Some(item) = lookup.get(&last.ident) {
+ RelevantType::Simple(item)
+ } else {
+ RelevantType::Pass
+ }
+ }
+ }
+ }
+ Type::Tuple(TypeTuple { ref elems, .. }) => RelevantType::Tuple(elems),
+ Type::Macro(TypeMacro { ref mac })
+ if mac.path.segments.last().unwrap().into_value().ident == "Token" =>
+ {
+ let is_ident = Ident::parse_any.parse2(mac.tts.clone()).is_ok() ;
+ let is_underscore = parse2::<Token![_]>(mac.tts.clone()).is_ok();
+ if is_ident && !is_underscore {
+ RelevantType::TokenKeyword(mac.into_token_stream())
+ } else {
+ RelevantType::TokenPunct(mac.into_token_stream())
+ }
+ }
+ _ => RelevantType::Pass,
+ }
+ }
+
+ #[derive(Debug, Eq, PartialEq, Copy, Clone)]
+ enum Kind {
+ Visit,
+ VisitMut,
+ Fold,
+ }
+
+ enum Operand {
+ Borrowed(TokenStream),
+ Owned(TokenStream),
+ }
+
+ use self::Kind::*;
+ use self::Operand::*;
+
+ impl Operand {
+ fn tokens(&self) -> &TokenStream {
+ match *self {
+ Borrowed(ref n) | Owned(ref n) => n,
+ }
+ }
+
+ fn ref_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => n.clone(),
+ Owned(ref n) => quote!(&#n),
+ }
+ }
+
+ fn ref_mut_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => n.clone(),
+ Owned(ref n) => quote!(&mut #n),
+ }
+ }
+
+ fn owned_tokens(&self) -> TokenStream {
+ match *self {
+ Borrowed(ref n) => quote!(*#n),
+ Owned(ref n) => n.clone(),
+ }
+ }
+ }
+
+ fn first_arg(params: &PathArguments) -> &Type {
+ let data = match *params {
+ PathArguments::AngleBracketed(ref data) => data,
+ _ => panic!("Expected at least 1 type argument here"),
+ };
+
+ match **data
+ .args
+ .first()
+ .expect("Expected at least 1 type argument here")
+ .value()
+ {
+ GenericArgument::Type(ref ty) => ty,
+ _ => panic!("Expected at least 1 type argument here"),
+ }
+ }
+
+ fn simple_visit(item: &AstItem, kind: Kind, name: &Operand) -> TokenStream {
+ let ident = under_name(item.ast.ident.clone());
+
+ match kind {
+ Visit => {
+ let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
+ let name = name.ref_tokens();
+ quote! {
+ _visitor.#method(#name)
+ }
+ }
+ VisitMut => {
+ let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
+ let name = name.ref_mut_tokens();
+ quote! {
+ _visitor.#method(#name)
+ }
+ }
+ Fold => {
+ let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
+ let name = name.owned_tokens();
+ quote! {
+ _visitor.#method(#name)
+ }
+ }
+ }
+ }
+
+ fn box_visit(elem: &Type, lookup: &Lookup, kind: Kind, name: &Operand) -> Option<TokenStream> {
+ let name = name.owned_tokens();
+ let res = visit(elem, lookup, kind, &Owned(quote!(*#name)))?;
+ Some(match kind {
+ Fold => quote! {
+ Box::new(#res)
+ },
+ Visit | VisitMut => res,
+ })
+ }
+
+ fn vec_visit(elem: &Type, lookup: &Lookup, kind: Kind, name: &Operand) -> Option<TokenStream> {
+ let operand = match kind {
+ Visit | VisitMut => Borrowed(quote!(it)),
+ Fold => Owned(quote!(it)),
+ };
+ let val = visit(elem, lookup, kind, &operand)?;
+ Some(match kind {
+ Visit => {
+ let name = name.ref_tokens();
+ quote! {
+ for it in #name {
+ #val
+ }
+ }
+ }
+ VisitMut => {
+ let name = name.ref_mut_tokens();
+ quote! {
+ for it in #name {
+ #val
+ }
+ }
+ }
+ Fold => {
+ let name = name.owned_tokens();
+ quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ }
+ }
+ })
+ }
+
+ fn punctuated_visit(
+ elem: &Type,
+ lookup: &Lookup,
+ kind: Kind,
+ name: &Operand,
+ ) -> Option<TokenStream> {
+ let operand = match kind {
+ Visit | VisitMut => Borrowed(quote!(it)),
+ Fold => Owned(quote!(it)),
+ };
+ let val = visit(elem, lookup, kind, &operand)?;
+ Some(match kind {
+ Visit => {
+ let name = name.ref_tokens();
+ quote! {
+ for el in Punctuated::pairs(#name) {
+ let it = el.value();
+ #val
+ }
+ }
+ }
+ VisitMut => {
+ let name = name.ref_mut_tokens();
+ quote! {
+ for mut el in Punctuated::pairs_mut(#name) {
+ let it = el.value_mut();
+ #val
+ }
+ }
+ }
+ Fold => {
+ let name = name.owned_tokens();
+ quote! {
+ FoldHelper::lift(#name, |it| { #val })
+ }
+ }
+ })
+ }
+
+ fn option_visit(
+ elem: &Type,
+ lookup: &Lookup,
+ kind: Kind,
+ name: &Operand,
+ ) -> Option<TokenStream> {
+ let it = match kind {
+ Visit | VisitMut => Borrowed(quote!(it)),
+ Fold => Owned(quote!(it)),
+ };
+ let val = visit(elem, lookup, kind, &it)?;
+ let name = name.owned_tokens();
+ Some(match kind {
+ Visit => quote! {
+ if let Some(ref it) = #name {
+ #val
+ }
+ },
+ VisitMut => quote! {
+ if let Some(ref mut it) = #name {
+ #val
+ }
+ },
+ Fold => quote! {
+ (#name).map(|it| { #val })
+ },
+ })
+ }
+
+ fn tuple_visit(
+ elems: &Punctuated<Type, Token![,]>,
+ lookup: &Lookup,
+ kind: Kind,
+ name: &Operand,
+ ) -> Option<TokenStream> {
+ if elems.is_empty() {
+ return None;
+ }
+
+ let mut code = TokenStream::new();
+ for (i, elem) in elems.iter().enumerate() {
+ let name = name.tokens();
+ let i = Index::from(i);
+ let it = Owned(quote!((#name).#i));
+ let val = visit(elem, lookup, kind, &it).unwrap_or_else(|| noop_visit(kind, &it));
+ code.append_all(val);
+ match kind {
+ Fold => code.append_all(quote!(,)),
+ Visit | VisitMut => code.append_all(quote!(;)),
+ }
+ }
+ Some(match kind {
+ Fold => quote! {
+ (#code)
+ },
+ Visit | VisitMut => code,
+ })
+ }
+
+ fn token_punct_visit(ty: TokenStream, kind: Kind, name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ match kind {
+ Fold => quote! {
+ #ty(tokens_helper(_visitor, &#name.spans))
+ },
+ Visit => quote! {
+ tokens_helper(_visitor, &#name.spans)
+ },
+ VisitMut => quote! {
+ tokens_helper(_visitor, &mut #name.spans)
+ },
+ }
+ }
+
+ fn token_keyword_visit(ty: TokenStream, kind: Kind, name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ match kind {
+ Fold => quote! {
+ #ty(tokens_helper(_visitor, &#name.span))
+ },
+ Visit => quote! {
+ tokens_helper(_visitor, &#name.span)
+ },
+ VisitMut => quote! {
+ tokens_helper(_visitor, &mut #name.span)
+ },
+ }
+ }
+
+ fn token_group_visit(ty: Ident, kind: Kind, name: &Operand) -> TokenStream {
+ let name = name.tokens();
+ match kind {
+ Fold => quote! {
+ #ty(tokens_helper(_visitor, &#name.span))
+ },
+ Visit => quote! {
+ tokens_helper(_visitor, &#name.span)
+ },
+ VisitMut => quote! {
+ tokens_helper(_visitor, &mut #name.span)
+ },
+ }
+ }
+
+ fn noop_visit(kind: Kind, name: &Operand) -> TokenStream {
+ match kind {
+ Fold => name.owned_tokens(),
+ Visit | VisitMut => {
+ let name = name.tokens();
+ quote! {
+ skip!(#name)
+ }
+ }
+ }
+ }
+
+ fn visit(ty: &Type, lookup: &Lookup, kind: Kind, name: &Operand) -> Option<TokenStream> {
+ match classify(ty, lookup) {
+ RelevantType::Box(elem) => box_visit(elem, lookup, kind, name),
+ RelevantType::Vec(elem) => vec_visit(elem, lookup, kind, name),
+ RelevantType::Punctuated(elem) => punctuated_visit(elem, lookup, kind, name),
+ RelevantType::Option(elem) => option_visit(elem, lookup, kind, name),
+ RelevantType::Tuple(elems) => tuple_visit(elems, lookup, kind, name),
+ RelevantType::Simple(item) => {
+ let mut res = simple_visit(item, kind, name);
+ Some(if item.eos_full {
+ quote! {
+ full!(#res)
+ }
+ } else {
+ res
+ })
+ }
+ RelevantType::TokenPunct(ty) => Some(token_punct_visit(ty, kind, name)),
+ RelevantType::TokenKeyword(ty) => Some(token_keyword_visit(ty, kind, name)),
+ RelevantType::TokenGroup(ty) => Some(token_group_visit(ty, kind, name)),
+ RelevantType::Pass => None,
+ }
+ }
+
+ pub fn generate(state: &mut State, lookup: &Lookup, s: &AstItem) {
+ let features = &s.features;
+ let under_name = under_name(s.ast.ident.clone());
+ let ty = &s.ast.ident;
+ let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
+ let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
+ let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
+
+ let mut visit_impl = TokenStream::new();
+ let mut visit_mut_impl = TokenStream::new();
+ let mut fold_impl = TokenStream::new();
+
+ match s.ast.data {
+ Data::Enum(ref e) => {
+ let mut visit_variants = TokenStream::new();
+ let mut visit_mut_variants = TokenStream::new();
+ let mut fold_variants = TokenStream::new();
+
+ for variant in &e.variants {
+ let variant_ident = &variant.ident;
+
+ match variant.fields {
+ Fields::Named(..) => panic!("Doesn't support enum struct variants"),
+ Fields::Unnamed(ref fields) => {
+ let mut bind_visit_fields = TokenStream::new();
+ let mut bind_visit_mut_fields = TokenStream::new();
+ let mut bind_fold_fields = TokenStream::new();
+
+ let mut visit_fields = TokenStream::new();
+ let mut visit_mut_fields = TokenStream::new();
+ let mut fold_fields = TokenStream::new();
+
+ for (idx, field) in fields.unnamed.iter().enumerate() {
+ let name = format!("_binding_{}", idx);
+ let binding = Ident::new(&name, Span::call_site());
+
+ bind_visit_fields.append_all(quote! {
+ ref #binding,
+ });
+ bind_visit_mut_fields.append_all(quote! {
+ ref mut #binding,
+ });
+ bind_fold_fields.append_all(quote! {
+ #binding,
+ });
+
+ let borrowed_binding = Borrowed(quote!(#binding));
+ let owned_binding = Owned(quote!(#binding));
+
+ visit_fields.append_all(
+ visit(&field.ty, lookup, Visit, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(Visit, &borrowed_binding)),
+ );
+ visit_mut_fields.append_all(
+ visit(&field.ty, lookup, VisitMut, &borrowed_binding)
+ .unwrap_or_else(|| noop_visit(VisitMut, &borrowed_binding)),
+ );
+ fold_fields.append_all(
+ visit(&field.ty, lookup, Fold, &owned_binding)
+ .unwrap_or_else(|| noop_visit(Fold, &owned_binding)),
+ );
+
+ visit_fields.append_all(quote!(;));
+ visit_mut_fields.append_all(quote!(;));
+ fold_fields.append_all(quote!(,));
+ }
+
+ visit_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_visit_fields) => {
+ #visit_fields
+ }
+ });
+
+ visit_mut_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_visit_mut_fields) => {
+ #visit_mut_fields
+ }
+ });
+
+ fold_variants.append_all(quote! {
+ #ty::#variant_ident(#bind_fold_fields) => {
+ #ty::#variant_ident(
+ #fold_fields
+ )
+ }
+ });
+ }
+ Fields::Unit => {
+ visit_variants.append_all(quote! {
+ #ty::#variant_ident => {}
+ });
+ visit_mut_variants.append_all(quote! {
+ #ty::#variant_ident => {}
+ });
+ fold_variants.append_all(quote! {
+ #ty::#variant_ident => {
+ #ty::#variant_ident
+ }
+ });
+ }
+ }
+ }
+
+ visit_impl.append_all(quote! {
+ match *_i {
+ #visit_variants
+ }
+ });
+
+ visit_mut_impl.append_all(quote! {
+ match *_i {
+ #visit_mut_variants
+ }
+ });
+
+ fold_impl.append_all(quote! {
+ match _i {
+ #fold_variants
+ }
+ });
+ }
+ Data::Struct(ref v) => {
+ let mut fold_fields = TokenStream::new();
+
+ for (idx, field) in v.fields.iter().enumerate() {
+ let id = match field.ident {
+ Some(ref ident) => Member::Named(ident.clone()),
+ None => Member::Unnamed(Index::from(idx)),
+ };
+ let ref_toks = Owned(quote!(_i.#id));
+ let visit_field = visit(&field.ty, lookup, Visit, &ref_toks)
+ .unwrap_or_else(|| noop_visit(Visit, &ref_toks));
+ visit_impl.append_all(quote! {
+ #visit_field;
+ });
+ let visit_mut_field = visit(&field.ty, lookup, VisitMut, &ref_toks)
+ .unwrap_or_else(|| noop_visit(VisitMut, &ref_toks));
+ visit_mut_impl.append_all(quote! {
+ #visit_mut_field;
+ });
+ let fold = visit(&field.ty, lookup, Fold, &ref_toks)
+ .unwrap_or_else(|| noop_visit(Fold, &ref_toks));
+ if let Some(ref name) = field.ident {
+ fold_fields.append_all(quote! {
+ #name: #fold,
+ });
+ } else {
+ fold_fields.append_all(quote! {
+ #fold,
+ });
+ }
+ }
+
+ match v.fields {
+ Fields::Named(..) | Fields::Unnamed(..) => fold_impl.append_all(quote! {
+ #ty {
+ #fold_fields
+ }
+ }),
+ Fields::Unit => {
+ if ty == "Ident" {
+ fold_impl.append_all(quote! {
+ let mut _i = _i;
+ let span = _visitor.fold_span(_i.span());
+ _i.set_span(span);
+ });
+ }
+ fold_impl.append_all(quote! {
+ _i
+ });
+ }
+ };
+ }
+ Data::Union(..) => panic!("Union not supported"),
+ }
+
+ let mut include_fold_impl = true;
+ if let Data::Struct(ref data) = s.ast.data {
+ if let Fields::Named(ref fields) = data.fields {
+ if fields
+ .named
+ .iter()
+ .any(|field| field.vis == Visibility::Inherited)
+ {
+ // Discard the generated impl if there are private fields.
+ // These have to be handwritten.
+ include_fold_impl = false;
+ }
+ }
+ }
+
+ state.visit_trait.append_all(quote! {
+ #features
+ fn #visit_fn(&mut self, i: &'ast #ty) {
+ #visit_fn(self, i)
+ }
+ });
+
+ state.visit_impl.append_all(quote! {
+ #features
+ pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V, _i: &'ast #ty
+ ) {
+ #visit_impl
+ }
+ });
+
+ state.visit_mut_trait.append_all(quote! {
+ #features
+ fn #visit_mut_fn(&mut self, i: &mut #ty) {
+ #visit_mut_fn(self, i)
+ }
+ });
+
+ state.visit_mut_impl.append_all(quote! {
+ #features
+ pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
+ _visitor: &mut V, _i: &mut #ty
+ ) {
+ #visit_mut_impl
+ }
+ });
+
+ state.fold_trait.append_all(quote! {
+ #features
+ fn #fold_fn(&mut self, i: #ty) -> #ty {
+ #fold_fn(self, i)
+ }
+ });
+
+ if include_fold_impl {
+ state.fold_impl.append_all(quote! {
+ #features
+ pub fn #fold_fn<V: Fold + ?Sized>(
+ _visitor: &mut V, _i: #ty
+ ) -> #ty {
+ #fold_impl
+ }
+ });
+ }
+ }
+}
+
+fn write_file(path: &str, content: TokenStream) {
+ let mut file = File::create(path).unwrap();
+ write!(
+ file,
+ "// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT\n\n"
+ ).unwrap();
+ let mut config = rustfmt::Config::default();
+ config.set().emit_mode(rustfmt::EmitMode::Stdout);
+ config.set().verbose(rustfmt::Verbosity::Quiet);
+ config.set().format_macro_matchers(true);
+ let mut session = rustfmt::Session::new(config, Some(&mut file));
+ session
+ .format(rustfmt::Input::Text(content.to_string()))
+ .unwrap();
+}
+
+fn main() {
+ let mut lookup = BTreeMap::new();
+ load_file(SYN_CRATE_ROOT, "e!(), &mut lookup).unwrap();
+
+ // Load in any terminal types
+ for &tt in TERMINAL_TYPES {
+ use syn::*;
+ lookup.insert(
+ Ident::new(&tt, Span::call_site()),
+ AstItem {
+ ast: DeriveInput {
+ ident: Ident::new(tt, Span::call_site()),
+ vis: Visibility::Public(VisPublic {
+ pub_token: <Token![pub]>::default(),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ fields: Fields::Unit,
+ struct_token: <Token![struct]>::default(),
+ semi_token: None,
+ }),
+ },
+ features: TokenStream::new(),
+ eos_full: false,
+ },
+ );
+ }
+
+ let mut state = codegen::State::default();
+ for s in lookup.values() {
+ codegen::generate(&mut state, &lookup, s);
+ }
+
+ let full_macro = quote! {
+ #[cfg(feature = "full")]
+ macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+ }
+
+ #[cfg(all(feature = "derive", not(feature = "full")))]
+ macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+ }
+ };
+
+ let skip_macro = quote! {
+ #[cfg(any(feature = "full", feature = "derive"))]
+ macro_rules! skip {
+ ($($tt:tt)*) => {};
+ }
+ };
+
+ let fold_trait = state.fold_trait;
+ let fold_impl = state.fold_impl;
+ write_file(
+ FOLD_SRC,
+ quote! {
+ // Unreachable code is generated sometimes without the full feature.
+ #![allow(unreachable_code)]
+ #![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
+
+ use *;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use token::{Brace, Bracket, Paren, Group};
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use gen::helper::fold::*;
+
+ #full_macro
+
+ /// Syntax tree traversal to transform the nodes of an owned syntax tree.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: index.html
+ ///
+ /// *This trait is available if Syn is built with the `"fold"` feature.*
+ pub trait Fold {
+ #fold_trait
+ }
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ macro_rules! fold_span_only {
+ ($f:ident : $t:ident) => {
+ pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t {
+ let span = _visitor.fold_span(_i.span());
+ _i.set_span(span);
+ _i
+ }
+ }
+ }
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_byte: LitByte);
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_byte_str: LitByteStr);
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_char: LitChar);
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_float: LitFloat);
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_int: LitInt);
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fold_span_only!(fold_lit_str: LitStr);
+
+ #fold_impl
+ },
+ );
+
+ let visit_trait = state.visit_trait;
+ let visit_impl = state.visit_impl;
+ write_file(
+ VISIT_SRC,
+ quote! {
+ #![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
+
+ use *;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use punctuated::Punctuated;
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use gen::helper::visit::*;
+
+ #full_macro
+ #skip_macro
+
+ /// Syntax tree traversal to walk a shared borrow of a syntax tree.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: index.html
+ ///
+ /// *This trait is available if Syn is built with the `"visit"` feature.*
+ pub trait Visit<'ast> {
+ #visit_trait
+ }
+
+ #visit_impl
+ },
+ );
+
+ let visit_mut_trait = state.visit_mut_trait;
+ let visit_mut_impl = state.visit_mut_impl;
+ write_file(
+ VISIT_MUT_SRC,
+ quote! {
+ #![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
+
+ use *;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use punctuated::Punctuated;
+ use proc_macro2::Span;
+ #[cfg(any(feature = "full", feature = "derive"))]
+ use gen::helper::visit_mut::*;
+
+ #full_macro
+ #skip_macro
+
+ /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
+ /// place.
+ ///
+ /// See the [module documentation] for details.
+ ///
+ /// [module documentation]: index.html
+ ///
+ /// *This trait is available if Syn is built with the `"visit-mut"` feature.*
+ pub trait VisitMut {
+ #visit_mut_trait
+ }
+
+ #visit_mut_impl
+ },
+ );
+}
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..75bc450
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,28 @@
+### [`dump-syntax`](dump-syntax)
+
+Little utility to parse a Rust source file into a `syn::File` and print out a
+debug representation of the syntax tree.
+
+### [`heapsize`](heapsize)
+
+A complete working Macros 1.1 implementation of a custom derive. Works on any
+Rust compiler >=1.15.0.
+
+### [`heapsize2`](heapsize2)
+
+The equivalent of the previous example but using fancy new APIs from the nightly
+compiler. It illustrates some neat features of the hygiene system of Macros 2.0
+and shows how to leverage those to provide amazing error messages to users.
+Currently requires a nightly Rust compiler >=1.24.0-nightly but we are working
+to stabilize all of the APIs involved.
+
+### [`lazy-static`](lazy-static)
+
+An example of parsing a custom syntax within a `functionlike!(...)` procedural
+macro. Demonstrates how to trigger custom warnings and error messages on
+individual tokens of the input.
+
+### [`trace-var`](trace-var)
+
+An attribute procedural macro that uses a syntax tree traversal to transform
+certain syntax tree nodes in a function body.
diff --git a/examples/dump-syntax/Cargo.toml b/examples/dump-syntax/Cargo.toml
new file mode 100644
index 0000000..aee56ff
--- /dev/null
+++ b/examples/dump-syntax/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "dump-syntax"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies.syn]
+path = "../.."
+default-features = false
+features = ["parsing", "full", "extra-traits"]
+
+[[bin]]
+name = "dump-syntax"
+path = "main.rs"
diff --git a/examples/dump-syntax/README.md b/examples/dump-syntax/README.md
new file mode 100644
index 0000000..3b23736
--- /dev/null
+++ b/examples/dump-syntax/README.md
@@ -0,0 +1,28 @@
+Parse a Rust source file into a `syn::File` and print out a debug representation
+of the syntax tree.
+
+Use the following command from this directory to test this program by running it
+on its own source code:
+
+```
+cargo run -- main.rs
+```
+
+The output will begin with:
+
+```
+File {
+ shebang: None,
+ attrs: [
+ Attribute {
+ pound_token: Pound,
+ style: Inner(
+ Bang
+ ),
+ bracket_token: Bracket,
+ path: Path {
+ leading_colon: None,
+ segments: [
+ ...
+}
+```
diff --git a/examples/dump-syntax/main.rs b/examples/dump-syntax/main.rs
new file mode 100644
index 0000000..584fe3c
--- /dev/null
+++ b/examples/dump-syntax/main.rs
@@ -0,0 +1,46 @@
+//! Parse a Rust source file into a `syn::File` and print out a debug
+//! representation of the syntax tree.
+//!
+//! Use the following command from this directory to test this program by
+//! running it on its own source code:
+//!
+//! cargo run -- main.rs
+//!
+//! The output will begin with:
+//!
+//! File {
+//! shebang: None,
+//! attrs: [
+//! Attribute {
+//! pound_token: Pound,
+//! style: Inner(
+//! ...
+//! }
+
+extern crate syn;
+
+use std::env;
+use std::fs::File;
+use std::io::Read;
+use std::process;
+
+fn main() {
+ let mut args = env::args();
+ let _ = args.next(); // executable name
+
+ let filename = match (args.next(), args.next()) {
+ (Some(filename), None) => filename,
+ _ => {
+ eprintln!("Usage: dump-syntax path/to/filename.rs");
+ process::exit(1);
+ }
+ };
+
+ let mut file = File::open(&filename).expect("Unable to open file");
+
+ let mut src = String::new();
+ file.read_to_string(&mut src).expect("Unable to read file");
+
+ let syntax = syn::parse_file(&src).expect("Unable to parse file");
+ println!("{:#?}", syntax);
+}
diff --git a/examples/heapsize/README.md b/examples/heapsize/README.md
new file mode 100644
index 0000000..b3deb8d
--- /dev/null
+++ b/examples/heapsize/README.md
@@ -0,0 +1,42 @@
+A complete working Macros 1.1 implementation of a custom derive. Works on any
+Rust compiler >=1.15.0.
+
+- [`heapsize/src/lib.rs`](heapsize/src/lib.rs)
+- [`heapsize_derive/src/lib.rs`](heapsize_derive/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+We are deriving the `HeapSize` trait which computes an estimate of the amount of
+heap memory owned by a value.
+
+```rust
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+```
+
+The custom derive allows users to write `#[derive(HeapSize)]` on data structures
+in their program.
+
+```rust
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+```
+
+The trait impl generated by the custom derive here would look like:
+
+```rust
+impl<'a, T: ?Sized + ::heapsize::HeapSize> ::heapsize::HeapSize for Demo<'a, T> {
+ fn heap_size_of_children(&self) -> usize {
+ 0 + ::heapsize::HeapSize::heap_size_of_children(&self.a)
+ + ::heapsize::HeapSize::heap_size_of_children(&self.b)
+ + ::heapsize::HeapSize::heap_size_of_children(&self.c)
+ + ::heapsize::HeapSize::heap_size_of_children(&self.d)
+ }
+}
+```
diff --git a/examples/heapsize/example/Cargo.toml b/examples/heapsize/example/Cargo.toml
new file mode 100644
index 0000000..0384d16
--- /dev/null
+++ b/examples/heapsize/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "heapsize_example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
+heapsize = { path = "../heapsize" }
+heapsize_derive = { path = "../heapsize_derive" }
diff --git a/examples/heapsize/example/src/main.rs b/examples/heapsize/example/src/main.rs
new file mode 100644
index 0000000..9c9d88a
--- /dev/null
+++ b/examples/heapsize/example/src/main.rs
@@ -0,0 +1,30 @@
+#[macro_use]
+extern crate heapsize_derive;
+
+extern crate heapsize;
+use heapsize::HeapSize;
+
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: String,
+}
+
+fn main() {
+ let demo = Demo {
+ a: b"bytestring".to_vec().into_boxed_slice(),
+ b: 255,
+ c: "&'static str",
+ d: "String".to_owned(),
+ };
+
+ // 10 + 0 + 0 + 6 = 16
+ println!("heap size = {} + {} + {} + {} = {}",
+ demo.a.heap_size_of_children(),
+ demo.b.heap_size_of_children(),
+ demo.c.heap_size_of_children(),
+ demo.d.heap_size_of_children(),
+ demo.heap_size_of_children());
+}
diff --git a/examples/heapsize/heapsize/Cargo.toml b/examples/heapsize/heapsize/Cargo.toml
new file mode 100644
index 0000000..7f321b5
--- /dev/null
+++ b/examples/heapsize/heapsize/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "heapsize"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
diff --git a/examples/heapsize/heapsize/src/lib.rs b/examples/heapsize/heapsize/src/lib.rs
new file mode 100644
index 0000000..8b4ce03
--- /dev/null
+++ b/examples/heapsize/heapsize/src/lib.rs
@@ -0,0 +1,62 @@
+use std::mem;
+
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ ///
+ /// Does not include the size of `self` itself, which may or may not be on
+ /// the heap. Includes only children of `self`, meaning things pointed to by
+ /// `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+
+//
+// In a real version of this library there would be lots more impls here, but
+// here are some interesting ones.
+//
+
+impl HeapSize for u8 {
+ /// A `u8` does not own any heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
+
+impl HeapSize for String {
+ /// A `String` owns enough heap memory to hold its reserved capacity.
+ fn heap_size_of_children(&self) -> usize {
+ self.capacity()
+ }
+}
+
+impl<T> HeapSize for Box<T>
+where
+ T: ?Sized + HeapSize,
+{
+ /// A `Box` owns however much heap memory was allocated to hold the value of
+ /// type `T` that we placed on the heap, plus transitively however much `T`
+ /// itself owns.
+ fn heap_size_of_children(&self) -> usize {
+ mem::size_of_val(&**self) + (**self).heap_size_of_children()
+ }
+}
+
+impl<T> HeapSize for [T]
+where
+ T: HeapSize,
+{
+ /// Sum of heap memory owned by each element of a dynamically sized slice of
+ /// `T`.
+ fn heap_size_of_children(&self) -> usize {
+ self.iter().map(HeapSize::heap_size_of_children).sum()
+ }
+}
+
+impl<'a, T> HeapSize for &'a T
+where
+ T: ?Sized,
+{
+ /// A shared reference does not own heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
diff --git a/examples/heapsize/heapsize_derive/Cargo.toml b/examples/heapsize/heapsize_derive/Cargo.toml
new file mode 100644
index 0000000..a71ab0a
--- /dev/null
+++ b/examples/heapsize/heapsize_derive/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "heapsize_derive"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "0.4"
+quote = "0.6"
+syn = { path = "../../.." }
diff --git a/examples/heapsize/heapsize_derive/src/lib.rs b/examples/heapsize/heapsize_derive/src/lib.rs
new file mode 100644
index 0000000..68055e5
--- /dev/null
+++ b/examples/heapsize/heapsize_derive/src/lib.rs
@@ -0,0 +1,88 @@
+extern crate proc_macro;
+extern crate proc_macro2;
+
+#[macro_use]
+extern crate syn;
+
+#[macro_use]
+extern crate quote;
+
+use proc_macro2::TokenStream;
+use syn::{DeriveInput, Data, Fields, Generics, GenericParam};
+
+#[proc_macro_derive(HeapSize)]
+pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ // Parse the input tokens into a syntax tree.
+ let input: DeriveInput = syn::parse(input).unwrap();
+
+ // Used in the quasi-quotation below as `#name`.
+ let name = input.ident;
+
+ // Add a bound `T: HeapSize` to every type parameter T.
+ let generics = add_trait_bounds(input.generics);
+ let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+
+ // Generate an expression to sum up the heap size of each field.
+ let sum = heap_size_sum(&input.data);
+
+ let expanded = quote! {
+ // The generated impl.
+ impl #impl_generics ::heapsize::HeapSize for #name #ty_generics #where_clause {
+ fn heap_size_of_children(&self) -> usize {
+ #sum
+ }
+ }
+ };
+
+ // Hand the output tokens back to the compiler.
+ expanded.into()
+}
+
+// Add a bound `T: HeapSize` to every type parameter T.
+fn add_trait_bounds(mut generics: Generics) -> Generics {
+ for param in &mut generics.params {
+ if let GenericParam::Type(ref mut type_param) = *param {
+ type_param.bounds.push(parse_quote!(::heapsize::HeapSize));
+ }
+ }
+ generics
+}
+
+// Generate an expression to sum up the heap size of each field.
+fn heap_size_sum(data: &Data) -> TokenStream {
+ match *data {
+ Data::Struct(ref data) => {
+ match data.fields {
+ Fields::Named(ref fields) => {
+ // Expands to an expression like
+ //
+ // 0 + self.x.heap_size() + self.y.heap_size() + self.z.heap_size()
+ //
+ // but using fully qualified function call syntax.
+ let fnames = fields.named.iter().map(|f| &f.ident);
+ quote! {
+ 0 #(
+ + ::heapsize::HeapSize::heap_size_of_children(&self.#fnames)
+ )*
+ }
+ }
+ Fields::Unnamed(ref fields) => {
+ // Expands to an expression like
+ //
+ // 0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
+ let indices = 0..fields.unnamed.len();
+ quote! {
+ 0 #(
+ + ::heapsize::HeapSize::heap_size_of_children(&self.#indices)
+ )*
+ }
+ }
+ Fields::Unit => {
+ // Unit structs cannot own more than 0 bytes of heap memory.
+ quote!(0)
+ }
+ }
+ }
+ Data::Enum(_) | Data::Union(_) => unimplemented!(),
+ }
+}
diff --git a/examples/heapsize2/README.md b/examples/heapsize2/README.md
new file mode 100644
index 0000000..3d232e7
--- /dev/null
+++ b/examples/heapsize2/README.md
@@ -0,0 +1,61 @@
+A complete working custom derive that illustrates the hygiene properties of
+Macros 2.0. Currently requires a nightly Rust compiler >=1.24.0-nightly but we
+are working to stabilize all of the APIs used here.
+
+This is the same example as the unhygienic stable [`heapsize`](../heapsize)
+example. Please read that other example first before diving into this one, as
+the comments here assume an understanding of how the other one works.
+
+- [`heapsize/src/lib.rs`](heapsize/src/lib.rs) (unchanged)
+- [`heapsize_derive/src/lib.rs`](heapsize_derive/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+A major advantage of spans and the token-based procedural macro API is that we
+get great control over where the compiler's error messages are displayed.
+Consider the error the user sees if one of their field types does not implement
+`HeapSize`.
+
+```rust
+#[derive(HeapSize)]
+struct Broken {
+ ok: String,
+ bad: std::thread::Thread,
+}
+```
+
+The Macros 1.1 string-based procedural macro and a naively implemented
+token-based procedural macro result in the following error.
+
+```
+error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope
+ --> src/main.rs:4:10
+ |
+4 | #[derive(HeapSize)]
+ | ^^^^^^^^
+```
+
+With just a bit of work, as shown in the `heapsize_derive` implementation here,
+we can improve this error to point out exactly which field is not right.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
+
+Some unstable APIs in the `proc-macro2` crate let us improve this further by
+joining together the span of the field name and the field type. There is no
+difference in our code -- everything is as shown in this directory -- but
+building the example crate with `cargo build` shows errors like the one above
+and building with `RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build` is
+able to show errors like the following.
+
+```
+error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+ --> src/main.rs:7:5
+ |
+7 | bad: std::thread::Thread,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread`
+```
diff --git a/examples/heapsize2/example/Cargo.toml b/examples/heapsize2/example/Cargo.toml
new file mode 100644
index 0000000..0384d16
--- /dev/null
+++ b/examples/heapsize2/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "heapsize_example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
+heapsize = { path = "../heapsize" }
+heapsize_derive = { path = "../heapsize_derive" }
diff --git a/examples/heapsize2/example/src/main.rs b/examples/heapsize2/example/src/main.rs
new file mode 100644
index 0000000..1c66692
--- /dev/null
+++ b/examples/heapsize2/example/src/main.rs
@@ -0,0 +1,29 @@
+#[macro_use]
+extern crate heapsize_derive;
+
+extern crate heapsize;
+
+#[derive(HeapSize)]
+struct Demo<'a, T: ?Sized> {
+ a: Box<T>,
+ b: u8,
+ c: &'a str,
+ d: HeapSize,
+}
+
+#[derive(HeapSize)]
+struct HeapSize {
+ e: String,
+}
+
+fn main() {
+ let demo = Demo {
+ a: b"bytestring".to_vec().into_boxed_slice(),
+ b: 255,
+ c: "&'static str",
+ d: HeapSize {
+ e: "String".to_owned(),
+ },
+ };
+ println!("heap size = {}", heapsize::HeapSize::heap_size_of_children(&demo));
+}
diff --git a/examples/heapsize2/heapsize/Cargo.toml b/examples/heapsize2/heapsize/Cargo.toml
new file mode 100644
index 0000000..7f321b5
--- /dev/null
+++ b/examples/heapsize2/heapsize/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "heapsize"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
diff --git a/examples/heapsize2/heapsize/src/lib.rs b/examples/heapsize2/heapsize/src/lib.rs
new file mode 100644
index 0000000..8b4ce03
--- /dev/null
+++ b/examples/heapsize2/heapsize/src/lib.rs
@@ -0,0 +1,62 @@
+use std::mem;
+
+pub trait HeapSize {
+ /// Total number of bytes of heap memory owned by `self`.
+ ///
+ /// Does not include the size of `self` itself, which may or may not be on
+ /// the heap. Includes only children of `self`, meaning things pointed to by
+ /// `self`.
+ fn heap_size_of_children(&self) -> usize;
+}
+
+//
+// In a real version of this library there would be lots more impls here, but
+// here are some interesting ones.
+//
+
+impl HeapSize for u8 {
+ /// A `u8` does not own any heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
+
+impl HeapSize for String {
+ /// A `String` owns enough heap memory to hold its reserved capacity.
+ fn heap_size_of_children(&self) -> usize {
+ self.capacity()
+ }
+}
+
+impl<T> HeapSize for Box<T>
+where
+ T: ?Sized + HeapSize,
+{
+ /// A `Box` owns however much heap memory was allocated to hold the value of
+ /// type `T` that we placed on the heap, plus transitively however much `T`
+ /// itself owns.
+ fn heap_size_of_children(&self) -> usize {
+ mem::size_of_val(&**self) + (**self).heap_size_of_children()
+ }
+}
+
+impl<T> HeapSize for [T]
+where
+ T: HeapSize,
+{
+ /// Sum of heap memory owned by each element of a dynamically sized slice of
+ /// `T`.
+ fn heap_size_of_children(&self) -> usize {
+ self.iter().map(HeapSize::heap_size_of_children).sum()
+ }
+}
+
+impl<'a, T> HeapSize for &'a T
+where
+ T: ?Sized,
+{
+ /// A shared reference does not own heap memory.
+ fn heap_size_of_children(&self) -> usize {
+ 0
+ }
+}
diff --git a/examples/heapsize2/heapsize_derive/Cargo.toml b/examples/heapsize2/heapsize_derive/Cargo.toml
new file mode 100644
index 0000000..9dd7af7
--- /dev/null
+++ b/examples/heapsize2/heapsize_derive/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "heapsize_derive"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = { path = "../../.." }
+quote = "0.6"
+proc-macro2 = { version = "0.4", features = ["nightly"] }
diff --git a/examples/heapsize2/heapsize_derive/src/lib.rs b/examples/heapsize2/heapsize_derive/src/lib.rs
new file mode 100644
index 0000000..87bb60e
--- /dev/null
+++ b/examples/heapsize2/heapsize_derive/src/lib.rs
@@ -0,0 +1,105 @@
+extern crate proc_macro;
+extern crate proc_macro2;
+
+#[macro_use]
+extern crate syn;
+
+#[macro_use]
+extern crate quote;
+
+use proc_macro2::{Span, TokenStream};
+use syn::{DeriveInput, Data, Fields, Generics, GenericParam, Index};
+use syn::spanned::Spanned;
+
+#[proc_macro_derive(HeapSize)]
+pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ // Parse the input tokens into a syntax tree.
+ let input: DeriveInput = syn::parse(input).unwrap();
+
+ // Used in the quasi-quotation below as `#name`.
+ let name = input.ident;
+
+ // Add a bound `T: HeapSize` to every type parameter T.
+ let generics = add_trait_bounds(input.generics);
+ let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+
+ // Generate an expression to sum up the heap size of each field.
+ let var = quote!(self);
+ let sum = heap_size_sum(&input.data, &var);
+
+ let expanded = quote! {
+ // The generated impl.
+ impl #impl_generics ::heapsize::HeapSize for #name #ty_generics #where_clause {
+ fn heap_size_of_children(&#var) -> usize {
+ #sum
+ }
+ }
+ };
+
+ // Hand the output tokens back to the compiler.
+ expanded.into()
+}
+
+// Add a bound `T: HeapSize` to every type parameter T.
+fn add_trait_bounds(mut generics: Generics) -> Generics {
+ for param in &mut generics.params {
+ if let GenericParam::Type(ref mut type_param) = *param {
+ type_param.bounds.push(parse_quote!(::heapsize::HeapSize));
+ }
+ }
+ generics
+}
+
+// Generate an expression to sum up the heap size of each field.
+fn heap_size_sum(data: &Data, var: &TokenStream) -> TokenStream {
+ let call_site = Span::call_site();
+
+ match *data {
+ Data::Struct(ref data) => {
+ match data.fields {
+ Fields::Named(ref fields) => {
+ // Expands to an expression like
+ //
+ // 0 + HeapSize::heap_size(&self.x) + HeapSize::heap_size(&self.y)
+ //
+ // We take some care to use the span of each `syn::Field` as
+ // the span of the corresponding `heap_size_of_children`
+ // call. This way if one of the field types does not
+ // implement `HeapSize` then the compiler's error message
+ // underlines which field it is. An example is shown in the
+ // readme of the parent directory.
+ let recurse = fields.named.iter().map(|f| {
+ let name = &f.ident;
+ let access = quote_spanned!(call_site=> #var.#name);
+ quote_spanned! {f.span()=>
+ ::heapsize::HeapSize::heap_size_of_children(&#access)
+ }
+ });
+ quote! {
+ 0 #(+ #recurse)*
+ }
+ }
+ Fields::Unnamed(ref fields) => {
+ // This expands to an expression like
+ //
+ // 0 + HeapSize::heap_size(&self.0) + HeapSize::heap_size(&self.1)
+ let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
+ let index = Index { index: i as u32, span: call_site };
+ let access = quote_spanned!(call_site=> #var.#index);
+ quote_spanned! {f.span()=>
+ ::heapsize::HeapSize::heap_size_of_children(&#access)
+ }
+ });
+ quote! {
+ 0 #(+ #recurse)*
+ }
+ }
+ Fields::Unit => {
+ // Unit structs cannot own more than 0 bytes of heap memory.
+ quote!(0)
+ }
+ }
+ }
+ Data::Enum(_) | Data::Union(_) => unimplemented!(),
+ }
+}
diff --git a/examples/lazy-static/README.md b/examples/lazy-static/README.md
new file mode 100644
index 0000000..bc64585
--- /dev/null
+++ b/examples/lazy-static/README.md
@@ -0,0 +1,42 @@
+An example of parsing a custom syntax within a `functionlike!(...)` procedural
+macro. Demonstrates how to trigger custom warnings and error messages on
+individual tokens of the input.
+
+- [`lazy-static/src/lib.rs`](lazy-static/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+The library implements a `lazy_static!` macro similar to the one from the real
+[`lazy_static`](https://docs.rs/lazy_static/1.0.0/lazy_static/) crate on
+crates.io.
+
+```rust
+lazy_static! {
+ static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+}
+```
+
+Compile and run the example by doing `cargo run` in the directory of the
+`example` crate.
+
+The implementation shows how to trigger custom warnings and error messages on
+the macro input. For example if you try adding an uncreatively named `FOO` lazy
+static, the macro will scold you with the following warning.
+
+```
+warning: come on, pick a more creative name
+ --> src/main.rs:10:16
+ |
+10 | static ref FOO: String = "lazy_static".to_owned();
+ | ^^^
+```
+
+And if you try to lazily initialize `() = ()`, the macro will outright refuse to
+compile it for you.
+
+```
+error: I can't think of a legitimate use for lazily initializing the value `()`
+ --> src/main.rs:10:27
+ |
+10 | static ref UNIT: () = ();
+ | ^^
+```
diff --git a/examples/lazy-static/example/Cargo.toml b/examples/lazy-static/example/Cargo.toml
new file mode 100644
index 0000000..d5d40c5
--- /dev/null
+++ b/examples/lazy-static/example/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
+lazy_static = { path = "../lazy-static" }
+regex = "0.2"
diff --git a/examples/lazy-static/example/src/main.rs b/examples/lazy-static/example/src/main.rs
new file mode 100644
index 0000000..16cfb36
--- /dev/null
+++ b/examples/lazy-static/example/src/main.rs
@@ -0,0 +1,25 @@
+#![feature(proc_macro)]
+
+extern crate lazy_static;
+extern crate regex;
+
+use lazy_static::lazy_static;
+use regex::Regex;
+
+lazy_static! {
+ static ref USERNAME: Regex = {
+ println!("Compiling username regex...");
+ Regex::new("^[a-z0-9_-]{3,16}$").unwrap()
+ };
+}
+
+fn main() {
+ println!("Let's validate some usernames.");
+ validate("fergie");
+ validate("will.i.am");
+}
+
+fn validate(name: &str) {
+ // The USERNAME regex is compiled lazily the first time its value is accessed.
+ println!("is_match({:?}): {}", name, USERNAME.is_match(name));
+}
diff --git a/examples/lazy-static/lazy-static/Cargo.toml b/examples/lazy-static/lazy-static/Cargo.toml
new file mode 100644
index 0000000..d5c8e3c
--- /dev/null
+++ b/examples/lazy-static/lazy-static/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "lazy_static"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = { path = "../../../", features = ["full"] }
+quote = "0.6"
+proc-macro2 = { version = "0.4", features = ["nightly"] }
diff --git a/examples/lazy-static/lazy-static/src/lib.rs b/examples/lazy-static/lazy-static/src/lib.rs
new file mode 100644
index 0000000..4d4131f
--- /dev/null
+++ b/examples/lazy-static/lazy-static/src/lib.rs
@@ -0,0 +1,134 @@
+#![recursion_limit = "128"]
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate syn;
+#[macro_use]
+extern crate quote;
+extern crate proc_macro;
+
+use syn::{Visibility, Ident, Type, Expr};
+use syn::synom::Synom;
+use syn::spanned::Spanned;
+use proc_macro::TokenStream;
+
+/// Parses the following syntax, which aligns with the input of the real
+/// `lazy_static` crate.
+///
+/// lazy_static! {
+/// $VISIBILITY static ref $NAME: $TYPE = $EXPR;
+/// }
+///
+/// For example:
+///
+/// lazy_static! {
+/// static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+/// }
+struct LazyStatic {
+ visibility: Visibility,
+ name: Ident,
+ ty: Type,
+ init: Expr,
+}
+
+impl Synom for LazyStatic {
+ named!(parse -> Self, do_parse!(
+ visibility: syn!(Visibility) >>
+ keyword!(static) >>
+ keyword!(ref) >>
+ name: syn!(Ident) >>
+ punct!(:) >>
+ ty: syn!(Type) >>
+ punct!(=) >>
+ init: syn!(Expr) >>
+ punct!(;) >>
+ (LazyStatic { visibility, name, ty, init })
+ ));
+}
+
+#[proc_macro]
+pub fn lazy_static(input: TokenStream) -> TokenStream {
+ let LazyStatic { visibility, name, ty, init } = syn::parse(input).unwrap();
+
+ // The warning looks like this.
+ //
+ // warning: come on, pick a more creative name
+ // --> src/main.rs:10:16
+ // |
+ // 10 | static ref FOO: String = "lazy_static".to_owned();
+ // | ^^^
+ if name == "FOO" {
+ name.span().unstable()
+ .warning("come on, pick a more creative name")
+ .emit();
+ }
+
+ // The error looks like this.
+ //
+ // error: I can't think of a legitimate use for lazily initializing the value `()`
+ // --> src/main.rs:10:27
+ // |
+ // 10 | static ref UNIT: () = ();
+ // | ^^
+ if let Expr::Tuple(ref init) = init {
+ if init.elems.is_empty() {
+ init.span().unstable()
+ .error("I can't think of a legitimate use for lazily initializing the value `()`")
+ .emit();
+ return TokenStream::new();
+ }
+ }
+
+ // Assert that the static type implements Sync. If not, user sees an error
+ // message like the following. We span this assertion with the field type's
+ // line/column so that the error message appears in the correct place.
+ //
+ // error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
+ // --> src/main.rs:10:21
+ // |
+ // 10 | static ref PTR: *const () = &();
+ // | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
+ let assert_sync = quote_spanned! {ty.span()=>
+ struct _AssertSync where #ty: ::std::marker::Sync;
+ };
+
+ // Check for Sized. Not vital to check here, but the error message is less
+ // confusing this way than if they get a Sized error in one of our
+ // implementation details where it assumes Sized.
+ //
+ // error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ // --> src/main.rs:10:19
+ // |
+ // 10 | static ref A: str = "";
+ // | ^^^ `str` does not have a constant size known at compile-time
+ let assert_sized = quote_spanned! {ty.span()=>
+ struct _AssertSized where #ty: ::std::marker::Sized;
+ };
+
+ let init_ptr = quote_spanned! {init.span()=>
+ Box::into_raw(Box::new(#init))
+ };
+
+ let expanded = quote! {
+ #visibility struct #name;
+
+ impl ::std::ops::Deref for #name {
+ type Target = #ty;
+
+ fn deref(&self) -> &#ty {
+ #assert_sync
+ #assert_sized
+
+ static ONCE: ::std::sync::Once = ::std::sync::ONCE_INIT;
+ static mut VALUE: *mut #ty = 0 as *mut #ty;
+
+ unsafe {
+ ONCE.call_once(|| VALUE = #init_ptr);
+ &*VALUE
+ }
+ }
+ }
+ };
+
+ expanded.into()
+}
diff --git a/examples/trace-var/README.md b/examples/trace-var/README.md
new file mode 100644
index 0000000..45eace7
--- /dev/null
+++ b/examples/trace-var/README.md
@@ -0,0 +1,61 @@
+An example of an attribute procedural macro. The `#[trace_var(...)]` attribute
+prints the value of the given variables each time they are reassigned.
+
+- [`trace-var/src/lib.rs`](trace-var/src/lib.rs)
+- [`example/src/main.rs`](example/src/main.rs)
+
+Consider the following factorial implementation.
+
+```rust
+#[trace_var(p, n)]
+fn factorial(mut n: u64) -> u64 {
+ let mut p = 1;
+ while n > 1 {
+ p *= n;
+ n -= 1;
+ }
+ p
+}
+```
+
+Invoking this with `factorial(8)` prints all the values of `p` and `n` during
+the execution of the function.
+
+```
+p = 1
+p = 8
+n = 7
+p = 56
+n = 6
+p = 336
+n = 5
+p = 1680
+n = 4
+p = 6720
+n = 3
+p = 20160
+n = 2
+p = 40320
+n = 1
+```
+
+The procedural macro uses a syntax tree [`Fold`] to rewrite every `let`
+statement and assignment expression in the following way:
+
+[`Fold`]: https://docs.rs/syn/0.14/syn/fold/trait.Fold.html
+
+```rust
+// Before
+let VAR = INIT;
+
+// After
+let VAR = { let VAR = INIT; println!("VAR = {:?}", VAR); VAR };
+```
+
+```rust
+// Before
+VAR = INIT
+
+// After
+{ VAR = INIT; println!("VAR = {:?}", VAR); }
+```
diff --git a/examples/trace-var/example/Cargo.toml b/examples/trace-var/example/Cargo.toml
new file mode 100644
index 0000000..8c2d99d
--- /dev/null
+++ b/examples/trace-var/example/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "example"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[dependencies]
+trace-var = { path = "../trace-var" }
diff --git a/examples/trace-var/example/src/main.rs b/examples/trace-var/example/src/main.rs
new file mode 100644
index 0000000..c9371f3
--- /dev/null
+++ b/examples/trace-var/example/src/main.rs
@@ -0,0 +1,18 @@
+#![feature(proc_macro)]
+
+extern crate trace_var;
+use trace_var::trace_var;
+
+fn main() {
+ println!("{}", factorial(8));
+}
+
+#[trace_var(p, n)]
+fn factorial(mut n: u64) -> u64 {
+ let mut p = 1;
+ while n > 1 {
+ p *= n;
+ n -= 1;
+ }
+ p
+}
diff --git a/examples/trace-var/trace-var/Cargo.toml b/examples/trace-var/trace-var/Cargo.toml
new file mode 100644
index 0000000..4a14bd1
--- /dev/null
+++ b/examples/trace-var/trace-var/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "trace-var"
+version = "0.0.0"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = { path = "../../../", features = ["full", "fold"] }
+quote = "0.6"
+proc-macro2 = { version = "0.4", features = ["nightly"] }
diff --git a/examples/trace-var/trace-var/src/lib.rs b/examples/trace-var/trace-var/src/lib.rs
new file mode 100644
index 0000000..5fb6ccf
--- /dev/null
+++ b/examples/trace-var/trace-var/src/lib.rs
@@ -0,0 +1,198 @@
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+#[macro_use]
+extern crate syn;
+
+#[macro_use]
+extern crate quote;
+
+use proc_macro::TokenStream;
+use quote::ToTokens;
+use std::collections::HashSet as Set;
+use syn::fold::{self, Fold};
+use syn::punctuated::Punctuated;
+use syn::synom::Synom;
+use syn::{Expr, Ident, ItemFn, Local, Pat, Stmt};
+
+/// Parses a parenthesized nonempty list of variable names separated by commas.
+///
+/// (a, b, c)
+///
+/// This is how the compiler passes in arguments to our attribute -- it is
+/// everything that comes after the attribute name.
+///
+/// #[trace_var(a, b, c)]
+/// ^^^^^^^^^
+struct Args {
+ vars: Set<Ident>,
+}
+
+impl Synom for Args {
+ named!(parse -> Self, map!(
+ call!(Punctuated::<Ident, Token![,]>::parse_terminated_nonempty),
+ |vars| Args {
+ vars: vars.into_iter().collect(),
+ }
+ ));
+}
+
+impl Args {
+ /// Determines whether the given `Expr` is a path referring to one of the
+ /// variables we intend to print. Expressions are used as the left-hand side
+ /// of the assignment operator.
+ fn should_print_expr(&self, e: &Expr) -> bool {
+ match *e {
+ Expr::Path(ref e) => {
+ if e.path.leading_colon.is_some() {
+ false
+ } else if e.path.segments.len() != 1 {
+ false
+ } else {
+ let first = e.path.segments.first().unwrap();
+ let segment = first.value();
+ self.vars.contains(&segment.ident) && segment.arguments.is_empty()
+ }
+ }
+ _ => false,
+ }
+ }
+
+ /// Determines whether the given `Pat` is an identifier equal to one of the
+ /// variables we intend to print. Patterns are used as the left-hand side of
+ /// a `let` binding.
+ fn should_print_pat(&self, p: &Punctuated<Pat, Token![|]>) -> bool {
+ if p.len() != 1 {
+ return false;
+ }
+ match p[0] {
+ Pat::Ident(ref p) => self.vars.contains(&p.ident),
+ _ => false,
+ }
+ }
+
+ /// Produces an expression that assigns the right-hand side to the left-hand
+ /// side and then prints the value.
+ ///
+ /// // Before
+ /// VAR = INIT
+ ///
+ /// // After
+ /// { VAR = INIT; println!("VAR = {:?}", VAR); }
+ fn assign_and_print(&mut self, left: Expr, op: &ToTokens, right: Expr) -> Expr {
+ let right = fold::fold_expr(self, right);
+ parse_quote!({
+ #left #op #right;
+ println!(concat!(stringify!(#left), " = {:?}"), #left);
+ })
+ }
+
+ /// Produces a let-binding that assigns the right-hand side to the left-hand
+ /// side and then prints the value.
+ ///
+ /// // Before
+ /// let VAR = INIT;
+ ///
+ /// // After
+ /// let VAR = { let VAR = INIT; println!("VAR = {:?}", VAR); VAR };
+ fn let_and_print(&mut self, local: Local) -> Stmt {
+ let Local { pats, ty, init, .. } = local;
+ let pat = &pats[0];
+ let ty = ty.map(|(colon_token, ty)| quote!(#colon_token #ty));
+ let init = self.fold_expr(*init.unwrap().1);
+ let ident = match *pat {
+ Pat::Ident(ref p) => &p.ident,
+ _ => unreachable!(),
+ };
+ parse_quote! {
+ let #pat #ty = {
+ let #pat = #init;
+ println!(concat!(stringify!(#ident), " = {:?}"), #ident);
+ #ident
+ };
+ }
+ }
+}
+
+/// The `Fold` trait is a way to traverse an owned syntax tree and replace some
+/// of its nodes.
+///
+/// Syn provides two other syntax tree traversal traits: `Visit` which walks a
+/// shared borrow of a syntax tree, and `VisitMut` which walks an exclusive
+/// borrow of a syntax tree and can mutate it in place.
+///
+/// All three traits have a method corresponding to each type of node in Syn's
+/// syntax tree. All of these methods have default no-op implementations that
+/// simply recurse on any child nodes. We can override only those methods for
+/// which we want non-default behavior. In this case the traversal needs to
+/// transform `Expr` and `Stmt` nodes.
+impl Fold for Args {
+ fn fold_expr(&mut self, e: Expr) -> Expr {
+ match e {
+ Expr::Assign(e) => {
+ if self.should_print_expr(&e.left) {
+ self.assign_and_print(*e.left, &e.eq_token, *e.right)
+ } else {
+ Expr::Assign(fold::fold_expr_assign(self, e))
+ }
+ }
+ Expr::AssignOp(e) => {
+ if self.should_print_expr(&e.left) {
+ self.assign_and_print(*e.left, &e.op, *e.right)
+ } else {
+ Expr::AssignOp(fold::fold_expr_assign_op(self, e))
+ }
+ }
+ _ => fold::fold_expr(self, e),
+ }
+ }
+
+ fn fold_stmt(&mut self, s: Stmt) -> Stmt {
+ match s {
+ Stmt::Local(s) => {
+ if s.init.is_some() && self.should_print_pat(&s.pats) {
+ self.let_and_print(s)
+ } else {
+ Stmt::Local(fold::fold_local(self, s))
+ }
+ }
+ _ => fold::fold_stmt(self, s),
+ }
+ }
+}
+
+/// Attribute to print the value of the given variables each time they are
+/// reassigned.
+///
+/// # Example
+///
+/// ```
+/// #[trace_var(p, n)]
+/// fn factorial(mut n: u64) -> u64 {
+/// let mut p = 1;
+/// while n > 1 {
+/// p *= n;
+/// n -= 1;
+/// }
+/// p
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn trace_var(args: TokenStream, input: TokenStream) -> TokenStream {
+ // Return the input unchanged if it failed to parse. The compiler will show
+ // the right diagnostics.
+ let input: ItemFn = match syn::parse(input.clone()) {
+ Ok(input) => input,
+ Err(_) => return input,
+ };
+
+ // Parse the list of variables the user wanted to print.
+ let mut args: Args = syn::parse(args).unwrap();
+
+ // Use a syntax tree traversal to transform the function body.
+ let output = args.fold_item_fn(input);
+
+ // Hand the resulting function body back to the compiler.
+ quote!(#output).into()
+}
diff --git a/src/attr.rs b/src/attr.rs
new file mode 100644
index 0000000..83ad8d7
--- /dev/null
+++ b/src/attr.rs
@@ -0,0 +1,547 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use punctuated::Punctuated;
+
+use std::iter;
+
+use proc_macro2::{Delimiter, Spacing, TokenStream, TokenTree};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "extra-traits")]
+use tt::TokenStreamHelper;
+
+ast_struct! {
+ /// An attribute like `#[repr(transparent)]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax
+ ///
+ /// Rust has six types of attributes.
+ ///
+ /// - Outer attributes like `#[repr(transparent)]`. These appear outside or
+ /// in front of the item they describe.
+ /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside
+ /// of the item they describe, usually a module.
+ /// - Outer doc comments like `/// # Example`.
+ /// - Inner doc comments like `//! Please file an issue`.
+ /// - Outer block comments `/** # Example */`.
+ /// - Inner block comments `/*! Please file an issue */`.
+ ///
+ /// The `style` field of type `AttrStyle` distinguishes whether an attribute
+ /// is outer or inner. Doc comments and block comments are promoted to
+ /// attributes, as this is how they are processed by the compiler and by
+ /// `macro_rules!` macros.
+ ///
+ /// The `path` field gives the possibly colon-delimited path against which
+ /// the attribute is resolved. It is equal to `"doc"` for desugared doc
+ /// comments. The `tts` field contains the rest of the attribute body as
+ /// tokens.
+ ///
+ /// ```text
+ /// #[derive(Copy)] #[crate::precondition x < 5]
+ /// ^^^^^^~~~~~~ ^^^^^^^^^^^^^^^^^^^ ~~~~~
+ /// path tts path tts
+ /// ```
+ ///
+ /// Use the [`interpret_meta`] method to try parsing the tokens of an
+ /// attribute into the structured representation that is used by convention
+ /// across most Rust libraries.
+ ///
+ /// [`interpret_meta`]: #method.interpret_meta
+ pub struct Attribute #manual_extra_traits {
+ pub pound_token: Token![#],
+ pub style: AttrStyle,
+ pub bracket_token: token::Bracket,
+ pub path: Path,
+ pub tts: TokenStream,
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Attribute {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Attribute {
+ fn eq(&self, other: &Self) -> bool {
+ self.style == other.style
+ && self.pound_token == other.pound_token
+ && self.bracket_token == other.bracket_token
+ && self.path == other.path
+ && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Attribute {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.style.hash(state);
+ self.pound_token.hash(state);
+ self.bracket_token.hash(state);
+ self.path.hash(state);
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+impl Attribute {
+ /// Parses the tokens after the path as a [`Meta`](enum.Meta.html) if
+ /// possible.
+ pub fn interpret_meta(&self) -> Option<Meta> {
+ let name = if self.path.segments.len() == 1 {
+ &self.path.segments.first().unwrap().value().ident
+ } else {
+ return None;
+ };
+
+ if self.tts.is_empty() {
+ return Some(Meta::Word(name.clone()));
+ }
+
+ let tts = self.tts.clone().into_iter().collect::<Vec<_>>();
+
+ if tts.len() == 1 {
+ if let Some(meta) = Attribute::extract_meta_list(name.clone(), &tts[0]) {
+ return Some(meta);
+ }
+ }
+
+ if tts.len() == 2 {
+ if let Some(meta) = Attribute::extract_name_value(name.clone(), &tts[0], &tts[1]) {
+ return Some(meta);
+ }
+ }
+
+ None
+ }
+
+ fn extract_meta_list(ident: Ident, tt: &TokenTree) -> Option<Meta> {
+ let g = match *tt {
+ TokenTree::Group(ref g) => g,
+ _ => return None,
+ };
+ if g.delimiter() != Delimiter::Parenthesis {
+ return None;
+ }
+ let tokens = g.stream().clone().into_iter().collect::<Vec<_>>();
+ let nested = match list_of_nested_meta_items_from_tokens(&tokens) {
+ Some(n) => n,
+ None => return None,
+ };
+ Some(Meta::List(MetaList {
+ paren_token: token::Paren(g.span()),
+ ident: ident,
+ nested: nested,
+ }))
+ }
+
+ fn extract_name_value(ident: Ident, a: &TokenTree, b: &TokenTree) -> Option<Meta> {
+ let a = match *a {
+ TokenTree::Punct(ref o) => o,
+ _ => return None,
+ };
+ if a.spacing() != Spacing::Alone {
+ return None;
+ }
+ if a.as_char() != '=' {
+ return None;
+ }
+
+ match *b {
+ TokenTree::Literal(ref l) if !l.to_string().starts_with('/') => {
+ Some(Meta::NameValue(MetaNameValue {
+ ident: ident,
+ eq_token: Token]),
+ lit: Lit::new(l.clone()),
+ }))
+ }
+ TokenTree::Ident(ref v) => match &v.to_string()[..] {
+ v @ "true" | v @ "false" => Some(Meta::NameValue(MetaNameValue {
+ ident: ident,
+ eq_token: Token]),
+ lit: Lit::Bool(LitBool {
+ value: v == "true",
+ span: b.span(),
+ }),
+ })),
+ _ => None,
+ },
+ _ => None,
+ }
+ }
+}
+
+fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMeta, &[TokenTree])> {
+ assert!(!tts.is_empty());
+
+ match tts[0] {
+ TokenTree::Literal(ref lit) => {
+ if lit.to_string().starts_with('/') {
+ None
+ } else {
+ let lit = Lit::new(lit.clone());
+ Some((NestedMeta::Literal(lit), &tts[1..]))
+ }
+ }
+
+ TokenTree::Ident(ref ident) => {
+ if tts.len() >= 3 {
+ if let Some(meta) = Attribute::extract_name_value(ident.clone(), &tts[1], &tts[2]) {
+ return Some((NestedMeta::Meta(meta), &tts[3..]));
+ }
+ }
+
+ if tts.len() >= 2 {
+ if let Some(meta) = Attribute::extract_meta_list(ident.clone(), &tts[1]) {
+ return Some((NestedMeta::Meta(meta), &tts[2..]));
+ }
+ }
+
+ Some((Meta::Word(ident.clone()).into(), &tts[1..]))
+ }
+
+ _ => None,
+ }
+}
+
+fn list_of_nested_meta_items_from_tokens(
+ mut tts: &[TokenTree],
+) -> Option<Punctuated<NestedMeta, Token![,]>> {
+ let mut nested_meta_items = Punctuated::new();
+ let mut first = true;
+
+ while !tts.is_empty() {
+ let prev_comma = if first {
+ first = false;
+ None
+ } else if let TokenTree::Punct(ref op) = tts[0] {
+ if op.spacing() != Spacing::Alone {
+ return None;
+ }
+ if op.as_char() != ',' {
+ return None;
+ }
+ let tok = Token]);
+ tts = &tts[1..];
+ if tts.is_empty() {
+ break;
+ }
+ Some(tok)
+ } else {
+ return None;
+ };
+ let (nested, rest) = match nested_meta_item_from_tokens(tts) {
+ Some(pair) => pair,
+ None => return None,
+ };
+ if let Some(comma) = prev_comma {
+ nested_meta_items.push_punct(comma);
+ }
+ nested_meta_items.push_value(nested);
+ tts = rest;
+ }
+
+ Some(nested_meta_items)
+}
+
+ast_enum! {
+ /// Distinguishes between attributes that decorate an item and attributes
+ /// that are contained within an item.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Outer attributes
+ ///
+ /// - `#[repr(transparent)]`
+ /// - `/// # Example`
+ /// - `/** Please file an issue */`
+ ///
+ /// # Inner attributes
+ ///
+ /// - `#![feature(proc_macro)]`
+ /// - `//! # Example`
+ /// - `/*! Please file an issue */`
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum AttrStyle {
+ Outer,
+ Inner(Token![!]),
+ }
+}
+
+ast_enum_of_structs! {
+ /// Content of a compile-time structured attribute.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// ## Word
+ ///
+ /// A meta word is like the `test` in `#[test]`.
+ ///
+ /// ## List
+ ///
+ /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`.
+ ///
+ /// ## NameValue
+ ///
+ /// A name-value meta is like the `path = "..."` in `#[path =
+ /// "sys/windows.rs"]`.
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Meta {
+ pub Word(Ident),
+ /// A structured list within an attribute, like `derive(Copy, Clone)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub List(MetaList {
+ pub ident: Ident,
+ pub paren_token: token::Paren,
+ pub nested: Punctuated<NestedMeta, Token![,]>,
+ }),
+ /// A name-value pair within an attribute, like `feature = "nightly"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub NameValue(MetaNameValue {
+ pub ident: Ident,
+ pub eq_token: Token![=],
+ pub lit: Lit,
+ }),
+ }
+}
+
+impl Meta {
+ /// Returns the identifier that begins this structured meta item.
+ ///
+ /// For example this would return the `test` in `#[test]`, the `derive` in
+ /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
+ pub fn name(&self) -> Ident {
+ match *self {
+ Meta::Word(ref meta) => meta.clone(),
+ Meta::List(ref meta) => meta.ident.clone(),
+ Meta::NameValue(ref meta) => meta.ident.clone(),
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// Element of a compile-time attribute list.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum NestedMeta {
+ /// A structured meta item, like the `Copy` in `#[derive(Copy)]` which
+ /// would be a nested `Meta::Word`.
+ pub Meta(Meta),
+
+ /// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`.
+ pub Literal(Lit),
+ }
+}
+
+pub trait FilterAttrs<'a> {
+ type Ret: Iterator<Item = &'a Attribute>;
+
+ fn outer(self) -> Self::Ret;
+ fn inner(self) -> Self::Ret;
+}
+
+impl<'a, T> FilterAttrs<'a> for T
+where
+ T: IntoIterator<Item = &'a Attribute>,
+{
+ type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
+
+ fn outer(self) -> Self::Ret {
+ fn is_outer(attr: &&Attribute) -> bool {
+ match attr.style {
+ AttrStyle::Outer => true,
+ _ => false,
+ }
+ }
+ self.into_iter().filter(is_outer)
+ }
+
+ fn inner(self) -> Self::Ret {
+ fn is_inner(attr: &&Attribute) -> bool {
+ match attr.style {
+ AttrStyle::Inner(_) => true,
+ _ => false,
+ }
+ }
+ self.into_iter().filter(is_inner)
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use buffer::Cursor;
+ use parse_error;
+ use proc_macro2::{Literal, Punct, Spacing, Span, TokenTree};
+ use synom::PResult;
+
+ fn eq(span: Span) -> TokenTree {
+ let mut op = Punct::new('=', Spacing::Alone);
+ op.set_span(span);
+ op.into()
+ }
+
+ impl Attribute {
+ named!(pub parse_inner -> Self, alt!(
+ do_parse!(
+ pound: punct!(#) >>
+ bang: punct!(!) >>
+ path_and_tts: brackets!(tuple!(
+ call!(Path::parse_mod_style),
+ syn!(TokenStream),
+ )) >>
+ ({
+ let (bracket, (path, tts)) = path_and_tts;
+
+ Attribute {
+ style: AttrStyle::Inner(bang),
+ path: path,
+ tts: tts,
+ pound_token: pound,
+ bracket_token: bracket,
+ }
+ })
+ )
+ |
+ map!(
+ call!(lit_doc_comment, Comment::Inner),
+ |lit| {
+ let span = lit.span();
+ Attribute {
+ style: AttrStyle::Inner(Token),
+ path: Ident::new("doc", span).into(),
+ tts: vec![
+ eq(span),
+ lit,
+ ].into_iter().collect(),
+ pound_token: Token,
+ bracket_token: token::Bracket(span),
+ }
+ }
+ )
+ ));
+
+ named!(pub parse_outer -> Self, alt!(
+ do_parse!(
+ pound: punct!(#) >>
+ path_and_tts: brackets!(tuple!(
+ call!(Path::parse_mod_style),
+ syn!(TokenStream),
+ )) >>
+ ({
+ let (bracket, (path, tts)) = path_and_tts;
+
+ Attribute {
+ style: AttrStyle::Outer,
+ path: path,
+ tts: tts,
+ pound_token: pound,
+ bracket_token: bracket,
+ }
+ })
+ )
+ |
+ map!(
+ call!(lit_doc_comment, Comment::Outer),
+ |lit| {
+ let span = lit.span();
+ Attribute {
+ style: AttrStyle::Outer,
+ path: Ident::new("doc", span).into(),
+ tts: vec![
+ eq(span),
+ lit,
+ ].into_iter().collect(),
+ pound_token: Token,
+ bracket_token: token::Bracket(span),
+ }
+ }
+ )
+ ));
+ }
+
+ enum Comment {
+ Inner,
+ Outer,
+ }
+
+ fn lit_doc_comment(input: Cursor, style: Comment) -> PResult<TokenTree> {
+ match input.literal() {
+ Some((lit, rest)) => {
+ let string = lit.to_string();
+ let ok = match style {
+ Comment::Inner => string.starts_with("//!") || string.starts_with("/*!"),
+ Comment::Outer => string.starts_with("///") || string.starts_with("/**"),
+ };
+ if ok {
+ let mut new = Literal::string(&string);
+ new.set_span(lit.span());
+ Ok((new.into(), rest))
+ } else {
+ parse_error()
+ }
+ }
+ _ => parse_error(),
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Attribute {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pound_token.to_tokens(tokens);
+ if let AttrStyle::Inner(ref b) = self.style {
+ b.to_tokens(tokens);
+ }
+ self.bracket_token.surround(tokens, |tokens| {
+ self.path.to_tokens(tokens);
+ self.tts.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for MetaList {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.nested.to_tokens(tokens);
+ })
+ }
+ }
+
+ impl ToTokens for MetaNameValue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.lit.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/buffer.rs b/src/buffer.rs
new file mode 100644
index 0000000..499c4f1
--- /dev/null
+++ b/src/buffer.rs
@@ -0,0 +1,469 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A stably addressed token buffer supporting efficient traversal based on a
+//! cheaply copyable cursor.
+//!
+//! The [`Synom`] trait is implemented for syntax tree types that can be parsed
+//! from one of these token cursors.
+//!
+//! [`Synom`]: ../synom/trait.Synom.html
+//!
+//! *This module is available if Syn is built with the `"parsing"` feature.*
+//!
+//! # Example
+//!
+//! This example shows a basic token parser for parsing a token stream without
+//! using Syn's parser combinator macros.
+//!
+//! ```
+//! #![feature(proc_macro_diagnostic)]
+//!
+//! extern crate syn;
+//! extern crate proc_macro;
+//!
+//! #[macro_use]
+//! extern crate quote;
+//!
+//! use syn::{token, ExprTuple};
+//! use syn::buffer::{Cursor, TokenBuffer};
+//! use syn::spanned::Spanned;
+//! use syn::synom::Synom;
+//! use proc_macro::{Diagnostic, Span, TokenStream};
+//!
+//! /// A basic token parser for parsing a token stream without using Syn's
+//! /// parser combinator macros.
+//! pub struct Parser<'a> {
+//! cursor: Cursor<'a>,
+//! }
+//!
+//! impl<'a> Parser<'a> {
+//! pub fn new(cursor: Cursor<'a>) -> Self {
+//! Parser { cursor }
+//! }
+//!
+//! pub fn current_span(&self) -> Span {
+//! self.cursor.span().unstable()
+//! }
+//!
+//! pub fn parse<T: Synom>(&mut self) -> Result<T, Diagnostic> {
+//! let (val, rest) = T::parse(self.cursor)
+//! .map_err(|e| match T::description() {
+//! Some(desc) => {
+//! self.current_span().error(format!("{}: expected {}", e, desc))
+//! }
+//! None => {
+//! self.current_span().error(e.to_string())
+//! }
+//! })?;
+//!
+//! self.cursor = rest;
+//! Ok(val)
+//! }
+//!
+//! pub fn expect_eof(&mut self) -> Result<(), Diagnostic> {
+//! if !self.cursor.eof() {
+//! return Err(self.current_span().error("trailing characters; expected eof"));
+//! }
+//!
+//! Ok(())
+//! }
+//! }
+//!
+//! fn eval(input: TokenStream) -> Result<TokenStream, Diagnostic> {
+//! let buffer = TokenBuffer::new(input);
+//! let mut parser = Parser::new(buffer.begin());
+//!
+//! // Parse some syntax tree types out of the input tokens. In this case we
+//! // expect something like:
+//! //
+//! // (a, b, c) = (1, 2, 3)
+//! let a = parser.parse::<ExprTuple>()?;
+//! parser.parse::<token::Eq>()?;
+//! let b = parser.parse::<ExprTuple>()?;
+//! parser.expect_eof()?;
+//!
+//! // Perform some validation and report errors.
+//! let (a_len, b_len) = (a.elems.len(), b.elems.len());
+//! if a_len != b_len {
+//! let diag = b.span().unstable()
+//! .error(format!("expected {} element(s), got {}", a_len, b_len))
+//! .span_note(a.span().unstable(), "because of this");
+//!
+//! return Err(diag);
+//! }
+//!
+//! // Build the output tokens.
+//! let out = quote! {
+//! println!("All good! Received two tuples of size {}", #a_len);
+//! };
+//!
+//! Ok(out.into())
+//! }
+//! #
+//! # extern crate proc_macro2;
+//! #
+//! # // This method exists on proc_macro2::Span but is behind the "nightly"
+//! # // feature.
+//! # trait ToUnstableSpan {
+//! # fn unstable(&self) -> Span;
+//! # }
+//! #
+//! # impl ToUnstableSpan for proc_macro2::Span {
+//! # fn unstable(&self) -> Span {
+//! # unimplemented!()
+//! # }
+//! # }
+//! #
+//! # fn main() {}
+//! ```
+
+// This module is heavily commented as it contains the only unsafe code in Syn,
+// and caution should be used when editing it. The public-facing interface is
+// 100% safe but the implementation is fragile internally.
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+))]
+use proc_macro as pm;
+use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream};
+use proc_macro2::{Group, Punct, TokenTree};
+
+use std::marker::PhantomData;
+use std::ptr;
+
+#[cfg(synom_verbose_trace)]
+use std::fmt::{self, Debug};
+
+/// Internal type which is used instead of `TokenTree` to represent a token tree
+/// within a `TokenBuffer`.
+enum Entry {
+ // Mimicking types from proc-macro.
+ Group(Span, Delimiter, TokenBuffer),
+ Ident(Ident),
+ Punct(Punct),
+ Literal(Literal),
+ // End entries contain a raw pointer to the entry from the containing
+ // token tree, or null if this is the outermost level.
+ End(*const Entry),
+}
+
+/// A buffer that can be efficiently traversed multiple times, unlike
+/// `TokenStream` which requires a deep copy in order to traverse more than
+/// once.
+///
+/// See the [module documentation] for an example of `TokenBuffer` in action.
+///
+/// [module documentation]: index.html
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+pub struct TokenBuffer {
+ // NOTE: Do not derive clone on this - there are raw pointers inside which
+ // will be messed up. Moving the `TokenBuffer` itself is safe as the actual
+ // backing slices won't be moved.
+ data: Box<[Entry]>,
+}
+
+impl TokenBuffer {
+ // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT
+ // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE.
+ fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer {
+ // Build up the entries list, recording the locations of any Groups
+ // in the list to be processed later.
+ let mut entries = Vec::new();
+ let mut seqs = Vec::new();
+ for tt in stream {
+ match tt {
+ TokenTree::Ident(sym) => {
+ entries.push(Entry::Ident(sym));
+ }
+ TokenTree::Punct(op) => {
+ entries.push(Entry::Punct(op));
+ }
+ TokenTree::Literal(l) => {
+ entries.push(Entry::Literal(l));
+ }
+ TokenTree::Group(g) => {
+ // Record the index of the interesting entry, and store an
+ // `End(null)` there temporarially.
+ seqs.push((entries.len(), g.span(), g.delimiter(), g.stream().clone()));
+ entries.push(Entry::End(ptr::null()));
+ }
+ }
+ }
+ // Add an `End` entry to the end with a reference to the enclosing token
+ // stream which was passed in.
+ entries.push(Entry::End(up));
+
+ // NOTE: This is done to ensure that we don't accidentally modify the
+ // length of the backing buffer. The backing buffer must remain at a
+ // constant address after this point, as we are going to store a raw
+ // pointer into it.
+ let mut entries = entries.into_boxed_slice();
+ for (idx, span, delim, seq_stream) in seqs {
+ // We know that this index refers to one of the temporary
+ // `End(null)` entries, and we know that the last entry is
+ // `End(up)`, so the next index is also valid.
+ let seq_up = &entries[idx + 1] as *const Entry;
+
+ // The end entry stored at the end of this Entry::Group should
+ // point to the Entry which follows the Group in the list.
+ let inner = Self::inner_new(seq_stream, seq_up);
+ entries[idx] = Entry::Group(span, delim, inner);
+ }
+
+ TokenBuffer { data: entries }
+ }
+
+ /// Creates a `TokenBuffer` containing all the tokens from the input
+ /// `TokenStream`.
+ ///
+ /// *This method is available if Syn is built with both the `"parsing"` and
+ /// `"proc-macro"` features.*
+ #[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+ ))]
+ pub fn new(stream: pm::TokenStream) -> TokenBuffer {
+ Self::new2(stream.into())
+ }
+
+ /// Creates a `TokenBuffer` containing all the tokens from the input
+ /// `TokenStream`.
+ pub fn new2(stream: TokenStream) -> TokenBuffer {
+ Self::inner_new(stream, ptr::null())
+ }
+
+ /// Creates a cursor referencing the first token in the buffer and able to
+ /// traverse until the end of the buffer.
+ pub fn begin(&self) -> Cursor {
+ unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) }
+ }
+}
+
+/// A cheaply copyable cursor into a `TokenBuffer`.
+///
+/// This cursor holds a shared reference into the immutable data which is used
+/// internally to represent a `TokenStream`, and can be efficiently manipulated
+/// and copied around.
+///
+/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer`
+/// object and get a cursor to its first token with `begin()`.
+///
+/// Two cursors are equal if they have the same location in the same input
+/// stream, and have the same scope.
+///
+/// See the [module documentation] for an example of a `Cursor` in action.
+///
+/// [module documentation]: index.html
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct Cursor<'a> {
+ /// The current entry which the `Cursor` is pointing at.
+ ptr: *const Entry,
+ /// This is the only `Entry::End(..)` object which this cursor is allowed to
+ /// point at. All other `End` objects are skipped over in `Cursor::create`.
+ scope: *const Entry,
+ /// This uses the &'a reference which guarantees that these pointers are
+ /// still valid.
+ marker: PhantomData<&'a Entry>,
+}
+
+impl<'a> Cursor<'a> {
+ /// Creates a cursor referencing a static empty TokenStream.
+ pub fn empty() -> Self {
+ // It's safe in this situation for us to put an `Entry` object in global
+ // storage, despite it not actually being safe to send across threads
+ // (`Ident` is a reference into a thread-local table). This is because
+ // this entry never includes a `Ident` object.
+ //
+ // This wrapper struct allows us to break the rules and put a `Sync`
+ // object in global storage.
+ struct UnsafeSyncEntry(Entry);
+ unsafe impl Sync for UnsafeSyncEntry {}
+ static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry));
+
+ Cursor {
+ ptr: &EMPTY_ENTRY.0,
+ scope: &EMPTY_ENTRY.0,
+ marker: PhantomData,
+ }
+ }
+
+ /// This create method intelligently exits non-explicitly-entered
+ /// `None`-delimited scopes when the cursor reaches the end of them,
+ /// allowing for them to be treated transparently.
+ unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self {
+ // NOTE: If we're looking at a `End(..)`, we want to advance the cursor
+ // past it, unless `ptr == scope`, which means that we're at the edge of
+ // our cursor's scope. We should only have `ptr != scope` at the exit
+ // from None-delimited groups entered with `ignore_none`.
+ while let Entry::End(exit) = *ptr {
+ if ptr == scope {
+ break;
+ }
+ ptr = exit;
+ }
+
+ Cursor {
+ ptr: ptr,
+ scope: scope,
+ marker: PhantomData,
+ }
+ }
+
+ /// Get the current entry.
+ fn entry(self) -> &'a Entry {
+ unsafe { &*self.ptr }
+ }
+
+ /// Bump the cursor to point at the next token after the current one. This
+ /// is undefined behavior if the cursor is currently looking at an
+ /// `Entry::End`.
+ unsafe fn bump(self) -> Cursor<'a> {
+ Cursor::create(self.ptr.offset(1), self.scope)
+ }
+
+ /// If the cursor is looking at a `None`-delimited group, move it to look at
+ /// the first token inside instead. If the group is empty, this will move
+ /// the cursor past the `None`-delimited group.
+ ///
+ /// WARNING: This mutates its argument.
+ fn ignore_none(&mut self) {
+ if let Entry::Group(_, Delimiter::None, ref buf) = *self.entry() {
+ // NOTE: We call `Cursor::create` here to make sure that situations
+ // where we should immediately exit the span after entering it are
+ // handled correctly.
+ unsafe {
+ *self = Cursor::create(&buf.data[0], self.scope);
+ }
+ }
+ }
+
+ /// Checks whether the cursor is currently pointing at the end of its valid
+ /// scope.
+ #[inline]
+ pub fn eof(self) -> bool {
+ // We're at eof if we're at the end of our scope.
+ self.ptr == self.scope
+ }
+
+ /// If the cursor is pointing at a `Group` with the given delimiter, returns
+ /// a cursor into that group and one pointing to the next `TokenTree`.
+ pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> {
+ // If we're not trying to enter a none-delimited group, we want to
+ // ignore them. We have to make sure to _not_ ignore them when we want
+ // to enter them, of course. For obvious reasons.
+ if delim != Delimiter::None {
+ self.ignore_none();
+ }
+
+ if let Entry::Group(span, group_delim, ref buf) = *self.entry() {
+ if group_delim == delim {
+ return Some((buf.begin(), span, unsafe { self.bump() }));
+ }
+ }
+
+ None
+ }
+
+ /// If the cursor is pointing at a `Ident`, returns it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Ident(ref ident) => Some((ident.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// If the cursor is pointing at an `Punct`, returns it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Punct(ref op) => Some((op.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// If the cursor is pointing at a `Literal`, return it along with a cursor
+ /// pointing at the next `TokenTree`.
+ pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> {
+ self.ignore_none();
+ match *self.entry() {
+ Entry::Literal(ref lit) => Some((lit.clone(), unsafe { self.bump() })),
+ _ => None,
+ }
+ }
+
+ /// Copies all remaining tokens visible from this cursor into a
+ /// `TokenStream`.
+ pub fn token_stream(self) -> TokenStream {
+ let mut tts = Vec::new();
+ let mut cursor = self;
+ while let Some((tt, rest)) = cursor.token_tree() {
+ tts.push(tt);
+ cursor = rest;
+ }
+ tts.into_iter().collect()
+ }
+
+ /// If the cursor is pointing at a `TokenTree`, returns it along with a
+ /// cursor pointing at the next `TokenTree`.
+ ///
+ /// Returns `None` if the cursor has reached the end of its stream.
+ ///
+ /// This method does not treat `None`-delimited groups as transparent, and
+ /// will return a `Group(None, ..)` if the cursor is looking at one.
+ pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> {
+ let tree = match *self.entry() {
+ Entry::Group(span, delim, ref buf) => {
+ let stream = buf.begin().token_stream();
+ let mut g = Group::new(delim, stream);
+ g.set_span(span);
+ TokenTree::from(g)
+ }
+ Entry::Literal(ref lit) => lit.clone().into(),
+ Entry::Ident(ref ident) => ident.clone().into(),
+ Entry::Punct(ref op) => op.clone().into(),
+ Entry::End(..) => {
+ return None;
+ }
+ };
+
+ Some((tree, unsafe { self.bump() }))
+ }
+
+ /// Returns the `Span` of the current token, or `Span::call_site()` if this
+ /// cursor points to eof.
+ pub fn span(self) -> Span {
+ match *self.entry() {
+ Entry::Group(span, ..) => span,
+ Entry::Literal(ref l) => l.span(),
+ Entry::Ident(ref t) => t.span(),
+ Entry::Punct(ref o) => o.span(),
+ Entry::End(..) => Span::call_site(),
+ }
+ }
+}
+
+// We do a custom implementation for `Debug` as the default implementation is
+// pretty useless.
+#[cfg(synom_verbose_trace)]
+impl<'a> Debug for Cursor<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Print what the cursor is currently looking at.
+ // This will look like Cursor("some remaining tokens here")
+ f.debug_tuple("Cursor")
+ .field(&self.token_stream().to_string())
+ .finish()
+ }
+}
diff --git a/src/data.rs b/src/data.rs
new file mode 100644
index 0000000..8ffc8a4
--- /dev/null
+++ b/src/data.rs
@@ -0,0 +1,415 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use punctuated::Punctuated;
+
+ast_struct! {
+ /// An enum variant.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Variant {
+ /// Attributes tagged on the variant.
+ pub attrs: Vec<Attribute>,
+
+ /// Name of the variant.
+ pub ident: Ident,
+
+ /// Content stored in the variant.
+ pub fields: Fields,
+
+ /// Explicit discriminant: `Variant = 1`
+ pub discriminant: Option<(Token![=], Expr)>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// Data stored within an enum variant or struct.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Fields {
+ /// Named fields of a struct or struct variant such as `Point { x: f64,
+ /// y: f64 }`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Named(FieldsNamed {
+ pub brace_token: token::Brace,
+ pub named: Punctuated<Field, Token![,]>,
+ }),
+
+ /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Unnamed(FieldsUnnamed {
+ pub paren_token: token::Paren,
+ pub unnamed: Punctuated<Field, Token![,]>,
+ }),
+
+ /// Unit struct or unit variant such as `None`.
+ pub Unit,
+ }
+}
+
+impl Fields {
+ /// Get an iterator over the borrowed [`Field`] items in this object. This
+ /// iterator can be used to iterate over a named or unnamed struct or
+ /// variant's fields uniformly.
+ ///
+ /// [`Field`]: struct.Field.html
+ pub fn iter(&self) -> punctuated::Iter<Field> {
+ match *self {
+ Fields::Unit => punctuated::Iter::private_empty(),
+ Fields::Named(ref f) => f.named.iter(),
+ Fields::Unnamed(ref f) => f.unnamed.iter(),
+ }
+ }
+
+ /// Get an iterator over the mutably borrowed [`Field`] items in this
+ /// object. This iterator can be used to iterate over a named or unnamed
+ /// struct or variant's fields uniformly.
+ ///
+ /// [`Field`]: struct.Field.html
+ pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
+ match *self {
+ Fields::Unit => punctuated::IterMut::private_empty(),
+ Fields::Named(ref mut f) => f.named.iter_mut(),
+ Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(),
+ }
+ }
+}
+
+impl<'a> IntoIterator for &'a Fields {
+ type Item = &'a Field;
+ type IntoIter = punctuated::Iter<'a, Field>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a> IntoIterator for &'a mut Fields {
+ type Item = &'a mut Field;
+ type IntoIter = punctuated::IterMut<'a, Field>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter_mut()
+ }
+}
+
+ast_struct! {
+ /// A field of a struct or enum variant.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Field {
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Visibility of the field.
+ pub vis: Visibility,
+
+ /// Name of the field, if any.
+ ///
+ /// Fields of tuple structs have no names.
+ pub ident: Option<Ident>,
+
+ pub colon_token: Option<Token![:]>,
+
+ /// Type of the field.
+ pub ty: Type,
+ }
+}
+
+ast_enum_of_structs! {
+ /// The visibility level of an item: inherited or `pub` or
+ /// `pub(restricted)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Visibility {
+ /// A public visibility level: `pub`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Public(VisPublic {
+ pub pub_token: Token![pub],
+ }),
+
+ /// A crate-level visibility: `crate`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Crate(VisCrate {
+ pub crate_token: Token![crate],
+ }),
+
+ /// A visibility level restricted to some path: `pub(self)` or
+ /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Restricted(VisRestricted {
+ pub pub_token: Token![pub],
+ pub paren_token: token::Paren,
+ pub in_token: Option<Token![in]>,
+ pub path: Box<Path>,
+ }),
+
+ /// An inherited visibility, which usually means private.
+ pub Inherited,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use synom::Synom;
+
+ impl Synom for Variant {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ id: syn!(Ident) >>
+ fields: alt!(
+ syn!(FieldsNamed) => { Fields::Named }
+ |
+ syn!(FieldsUnnamed) => { Fields::Unnamed }
+ |
+ epsilon!() => { |_| Fields::Unit }
+ ) >>
+ disr: option!(tuple!(punct!(=), syn!(Expr))) >>
+ (Variant {
+ ident: id,
+ attrs: attrs,
+ fields: fields,
+ discriminant: disr,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("enum variant")
+ }
+ }
+
+ impl Synom for FieldsNamed {
+ named!(parse -> Self, map!(
+ braces!(call!(Punctuated::parse_terminated_with, Field::parse_named)),
+ |(brace, fields)| FieldsNamed {
+ brace_token: brace,
+ named: fields,
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("named fields in a struct or struct variant")
+ }
+ }
+
+ impl Synom for FieldsUnnamed {
+ named!(parse -> Self, map!(
+ parens!(call!(Punctuated::parse_terminated_with, Field::parse_unnamed)),
+ |(paren, fields)| FieldsUnnamed {
+ paren_token: paren,
+ unnamed: fields,
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("unnamed fields in a tuple struct or tuple variant")
+ }
+ }
+
+ impl Field {
+ named!(pub parse_named -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ id: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ (Field {
+ ident: Some(id),
+ vis: vis,
+ attrs: attrs,
+ ty: ty,
+ colon_token: Some(colon),
+ })
+ ));
+
+ named!(pub parse_unnamed -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ ty: syn!(Type) >>
+ (Field {
+ ident: None,
+ colon_token: None,
+ vis: vis,
+ attrs: attrs,
+ ty: ty,
+ })
+ ));
+ }
+
+ impl Synom for Visibility {
+ named!(parse -> Self, alt!(
+ do_parse!(
+ pub_token: keyword!(pub) >>
+ other: parens!(keyword!(crate)) >>
+ (Visibility::Restricted(VisRestricted {
+ pub_token: pub_token,
+ paren_token: other.0,
+ in_token: None,
+ path: Box::new(other.1.into()),
+ }))
+ )
+ |
+ do_parse!(
+ crate_token: keyword!(crate) >>
+ not!(punct!(::)) >>
+ (Visibility::Crate(VisCrate {
+ crate_token: crate_token,
+ }))
+ )
+ |
+ do_parse!(
+ pub_token: keyword!(pub) >>
+ other: parens!(keyword!(self)) >>
+ (Visibility::Restricted(VisRestricted {
+ pub_token: pub_token,
+ paren_token: other.0,
+ in_token: None,
+ path: Box::new(other.1.into()),
+ }))
+ )
+ |
+ do_parse!(
+ pub_token: keyword!(pub) >>
+ other: parens!(keyword!(super)) >>
+ (Visibility::Restricted(VisRestricted {
+ pub_token: pub_token,
+ paren_token: other.0,
+ in_token: None,
+ path: Box::new(other.1.into()),
+ }))
+ )
+ |
+ do_parse!(
+ pub_token: keyword!(pub) >>
+ other: parens!(do_parse!(
+ in_tok: keyword!(in) >>
+ restricted: call!(Path::parse_mod_style) >>
+ (in_tok, restricted)
+ )) >>
+ (Visibility::Restricted(VisRestricted {
+ pub_token: pub_token,
+ paren_token: other.0,
+ in_token: Some((other.1).0),
+ path: Box::new((other.1).1),
+ }))
+ )
+ |
+ keyword!(pub) => { |tok| {
+ Visibility::Public(VisPublic {
+ pub_token: tok,
+ })
+ } }
+ |
+ epsilon!() => { |_| Visibility::Inherited }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("visibility qualifier such as `pub`")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for Variant {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.ident.to_tokens(tokens);
+ self.fields.to_tokens(tokens);
+ if let Some((ref eq_token, ref disc)) = self.discriminant {
+ eq_token.to_tokens(tokens);
+ disc.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for FieldsNamed {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ self.named.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for FieldsUnnamed {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.unnamed.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for Field {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.vis.to_tokens(tokens);
+ if let Some(ref ident) = self.ident {
+ ident.to_tokens(tokens);
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ }
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for VisPublic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pub_token.to_tokens(tokens)
+ }
+ }
+
+ impl ToTokens for VisCrate {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.crate_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for VisRestricted {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pub_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ // XXX: If we have a path which is not "self" or "super" or
+ // "crate", automatically add the "in" token.
+ self.in_token.to_tokens(tokens);
+ self.path.to_tokens(tokens);
+ });
+ }
+ }
+}
diff --git a/src/derive.rs b/src/derive.rs
new file mode 100644
index 0000000..ecef776
--- /dev/null
+++ b/src/derive.rs
@@ -0,0 +1,242 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use punctuated::Punctuated;
+
+ast_struct! {
+ /// Data structure sent to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` feature.*
+ pub struct DeriveInput {
+ /// Attributes tagged on the whole struct or enum.
+ pub attrs: Vec<Attribute>,
+
+ /// Visibility of the struct or enum.
+ pub vis: Visibility,
+
+ /// Name of the struct or enum.
+ pub ident: Ident,
+
+ /// Generics required to complete the definition.
+ pub generics: Generics,
+
+ /// Data within the struct or enum.
+ pub data: Data,
+ }
+}
+
+ast_enum_of_structs! {
+ /// The storage of a struct, enum or union data structure.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Data {
+ /// A struct input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub Struct(DataStruct {
+ pub struct_token: Token![struct],
+ pub fields: Fields,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// An enum input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub Enum(DataEnum {
+ pub enum_token: Token![enum],
+ pub brace_token: token::Brace,
+ pub variants: Punctuated<Variant, Token![,]>,
+ }),
+
+ /// A tagged union input to a `proc_macro_derive` macro.
+ ///
+ /// *This type is available if Syn is built with the `"derive"`
+ /// feature.*
+ pub Union(DataUnion {
+ pub union_token: Token![union],
+ pub fields: FieldsNamed,
+ }),
+ }
+
+ do_not_generate_to_tokens
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use synom::Synom;
+
+ enum DeriveInputKind {
+ Struct(Token![struct]),
+ Enum(Token![enum]),
+ Union(Token![union]),
+ }
+
+ impl Synom for DeriveInputKind {
+ named!(parse -> Self, alt!(
+ keyword!(struct) => { DeriveInputKind::Struct }
+ |
+ keyword!(enum) => { DeriveInputKind::Enum }
+ |
+ keyword!(union) => { DeriveInputKind::Union }
+ ));
+ }
+
+ impl Synom for DeriveInput {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ which: syn!(DeriveInputKind) >>
+ id: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ item: switch!(value!(which),
+ DeriveInputKind::Struct(s) => map!(data_struct, move |(wh, fields, semi)| DeriveInput {
+ ident: id,
+ vis: vis,
+ attrs: attrs,
+ generics: Generics {
+ where_clause: wh,
+ ..generics
+ },
+ data: Data::Struct(DataStruct {
+ struct_token: s,
+ fields: fields,
+ semi_token: semi,
+ }),
+ })
+ |
+ DeriveInputKind::Enum(e) => map!(data_enum, move |(wh, brace, variants)| DeriveInput {
+ ident: id,
+ vis: vis,
+ attrs: attrs,
+ generics: Generics {
+ where_clause: wh,
+ ..generics
+ },
+ data: Data::Enum(DataEnum {
+ variants: variants,
+ brace_token: brace,
+ enum_token: e,
+ }),
+ })
+ |
+ DeriveInputKind::Union(u) => map!(data_union, move |(wh, fields)| DeriveInput {
+ ident: id,
+ vis: vis,
+ attrs: attrs,
+ generics: Generics {
+ where_clause: wh,
+ ..generics
+ },
+ data: Data::Union(DataUnion {
+ union_token: u,
+ fields: fields,
+ }),
+ })
+ ) >>
+ (item)
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("derive input")
+ }
+ }
+
+ named!(data_struct -> (Option<WhereClause>, Fields, Option<Token![;]>), alt!(
+ do_parse!(
+ wh: option!(syn!(WhereClause)) >>
+ fields: syn!(FieldsNamed) >>
+ (wh, Fields::Named(fields), None)
+ )
+ |
+ do_parse!(
+ fields: syn!(FieldsUnnamed) >>
+ wh: option!(syn!(WhereClause)) >>
+ semi: punct!(;) >>
+ (wh, Fields::Unnamed(fields), Some(semi))
+ )
+ |
+ do_parse!(
+ wh: option!(syn!(WhereClause)) >>
+ semi: punct!(;) >>
+ (wh, Fields::Unit, Some(semi))
+ )
+ ));
+
+ named!(data_enum -> (Option<WhereClause>, token::Brace, Punctuated<Variant, Token![,]>), do_parse!(
+ wh: option!(syn!(WhereClause)) >>
+ data: braces!(Punctuated::parse_terminated) >>
+ (wh, data.0, data.1)
+ ));
+
+ named!(data_union -> (Option<WhereClause>, FieldsNamed), tuple!(
+ option!(syn!(WhereClause)),
+ syn!(FieldsNamed),
+ ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for DeriveInput {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ for attr in self.attrs.outer() {
+ attr.to_tokens(tokens);
+ }
+ self.vis.to_tokens(tokens);
+ match self.data {
+ Data::Struct(ref d) => d.struct_token.to_tokens(tokens),
+ Data::Enum(ref d) => d.enum_token.to_tokens(tokens),
+ Data::Union(ref d) => d.union_token.to_tokens(tokens),
+ }
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ match self.data {
+ Data::Struct(ref data) => match data.fields {
+ Fields::Named(ref fields) => {
+ self.generics.where_clause.to_tokens(tokens);
+ fields.to_tokens(tokens);
+ }
+ Fields::Unnamed(ref fields) => {
+ fields.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&data.semi_token).to_tokens(tokens);
+ }
+ Fields::Unit => {
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&data.semi_token).to_tokens(tokens);
+ }
+ },
+ Data::Enum(ref data) => {
+ self.generics.where_clause.to_tokens(tokens);
+ data.brace_token.surround(tokens, |tokens| {
+ data.variants.to_tokens(tokens);
+ });
+ }
+ Data::Union(ref data) => {
+ self.generics.where_clause.to_tokens(tokens);
+ data.fields.to_tokens(tokens);
+ }
+ }
+ }
+ }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..6673aa3
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,60 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use buffer::Cursor;
+use std::error::Error;
+use std::fmt::{self, Display};
+
+/// The result of a `Synom` parser.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: index.html
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+pub type PResult<'a, O> = Result<(O, Cursor<'a>), ParseError>;
+
+/// An error with a default error message.
+///
+/// NOTE: We should provide better error messages in the future.
+pub fn parse_error<'a, O>() -> PResult<'a, O> {
+ Err(ParseError(None))
+}
+
+/// Error returned when a `Synom` parser cannot parse the input tokens.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: index.html
+///
+/// *This type is available if Syn is built with the `"parsing"` feature.*
+#[derive(Debug)]
+pub struct ParseError(Option<String>);
+
+impl Error for ParseError {
+ fn description(&self) -> &str {
+ match self.0 {
+ Some(ref desc) => desc,
+ None => "failed to parse",
+ }
+ }
+}
+
+impl Display for ParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(self.description(), f)
+ }
+}
+
+impl ParseError {
+ // For syn use only. Not public API.
+ #[doc(hidden)]
+ pub fn new<T: Into<String>>(msg: T) -> Self {
+ ParseError(Some(msg.into()))
+ }
+}
diff --git a/src/expr.rs b/src/expr.rs
new file mode 100644
index 0000000..60caae2
--- /dev/null
+++ b/src/expr.rs
@@ -0,0 +1,3905 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use proc_macro2::{Span, TokenStream};
+use punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "full")]
+use std::mem;
+#[cfg(feature = "extra-traits")]
+use tt::TokenStreamHelper;
+
+ast_enum_of_structs! {
+ /// A Rust expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enums
+ ///
+ /// This type is a syntax tree enum. In Syn this and other syntax tree enums
+ /// are designed to be traversed using the following rebinding idiom.
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # const IGNORE: &str = stringify! {
+ /// let expr: Expr = /* ... */;
+ /// # };
+ /// match expr {
+ /// Expr::MethodCall(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::Cast(expr) => {
+ /// /* ... */
+ /// }
+ /// Expr::IfLet(expr) => {
+ /// /* ... */
+ /// }
+ /// /* ... */
+ /// # _ => {}
+ /// }
+ /// # }
+ /// ```
+ ///
+ /// We begin with a variable `expr` of type `Expr` that has no fields
+ /// (because it is an enum), and by matching on it and rebinding a variable
+ /// with the same name `expr` we effectively imbue our variable with all of
+ /// the data fields provided by the variant that it turned out to be. So for
+ /// example above if we ended up in the `MethodCall` case then we get to use
+ /// `expr.receiver`, `expr.args` etc; if we ended up in the `IfLet` case we
+ /// get to use `expr.pat`, `expr.then_branch`, `expr.else_branch`.
+ ///
+ /// The pattern is similar if the input expression is borrowed:
+ ///
+ /// ```
+ /// # use syn::Expr;
+ /// #
+ /// # fn example(expr: &Expr) {
+ /// match *expr {
+ /// Expr::MethodCall(ref expr) => {
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// This approach avoids repeating the variant names twice on every line.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprMethodCall};
+ /// #
+ /// # fn example(expr: Expr) {
+ /// # match expr {
+ /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { // repetitive
+ /// # }
+ /// # _ => {}
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// In general, the name to which a syntax tree enum variant is bound should
+ /// be a suitable name for the complete syntax tree enum type.
+ ///
+ /// ```
+ /// # use syn::{Expr, ExprField};
+ /// #
+ /// # fn example(discriminant: &ExprField) {
+ /// // Binding is called `base` which is the name I would use if I were
+ /// // assigning `*discriminant.base` without an `if let`.
+ /// if let Expr::Tuple(ref base) = *discriminant.base {
+ /// # }
+ /// # }
+ /// ```
+ ///
+ /// A sign that you may not be choosing the right variable names is if you
+ /// see names getting repeated in your code, like accessing
+ /// `receiver.receiver` or `pat.pat` or `cond.cond`.
+ pub enum Expr {
+ /// A box expression: `box f`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Box(ExprBox #full {
+ pub attrs: Vec<Attribute>,
+ pub box_token: Token![box],
+ pub expr: Box<Expr>,
+ }),
+
+ /// A placement expression: `place <- value`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub InPlace(ExprInPlace #full {
+ pub attrs: Vec<Attribute>,
+ pub place: Box<Expr>,
+ pub arrow_token: Token![<-],
+ pub value: Box<Expr>,
+ }),
+
+ /// A slice literal expression: `[a, b, c, d]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Array(ExprArray #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }),
+
+ /// A function call expression: `invoke(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Call(ExprCall {
+ pub attrs: Vec<Attribute>,
+ pub func: Box<Expr>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }),
+
+ /// A method call expression: `x.foo::<T>(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub MethodCall(ExprMethodCall #full {
+ pub attrs: Vec<Attribute>,
+ pub receiver: Box<Expr>,
+ pub dot_token: Token![.],
+ pub method: Ident,
+ pub turbofish: Option<MethodTurbofish>,
+ pub paren_token: token::Paren,
+ pub args: Punctuated<Expr, Token![,]>,
+ }),
+
+ /// A tuple expression: `(a, b, c, d)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Tuple(ExprTuple #full {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Expr, Token![,]>,
+ }),
+
+ /// A binary operation: `a + b`, `a * b`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Binary(ExprBinary {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }),
+
+ /// A unary operation: `!x`, `*x`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Unary(ExprUnary {
+ pub attrs: Vec<Attribute>,
+ pub op: UnOp,
+ pub expr: Box<Expr>,
+ }),
+
+ /// A literal in place of an expression: `1`, `"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Lit(ExprLit {
+ pub attrs: Vec<Attribute>,
+ pub lit: Lit,
+ }),
+
+ /// A cast expression: `foo as f64`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Cast(ExprCast {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub as_token: Token![as],
+ pub ty: Box<Type>,
+ }),
+
+ /// A type ascription expression: `foo: f64`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Type(ExprType #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ }),
+
+ /// An `if` expression with an optional `else` block: `if expr { ... }
+ /// else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If`, `IfLet`, or
+ /// `Block` expression, not any of the other types of expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub If(ExprIf #full {
+ pub attrs: Vec<Attribute>,
+ pub if_token: Token![if],
+ pub cond: Box<Expr>,
+ pub then_branch: Block,
+ pub else_branch: Option<(Token![else], Box<Expr>)>,
+ }),
+
+ /// An `if let` expression with an optional `else` block: `if let pat =
+ /// expr { ... } else { ... }`.
+ ///
+ /// The `else` branch expression may only be an `If`, `IfLet`, or
+ /// `Block` expression, not any of the other types of expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub IfLet(ExprIfLet #full {
+ pub attrs: Vec<Attribute>,
+ pub if_token: Token![if],
+ pub let_token: Token![let],
+ pub pats: Punctuated<Pat, Token![|]>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub then_branch: Block,
+ pub else_branch: Option<(Token![else], Box<Expr>)>,
+ }),
+
+ /// A while loop: `while expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub While(ExprWhile #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub while_token: Token![while],
+ pub cond: Box<Expr>,
+ pub body: Block,
+ }),
+
+ /// A while-let loop: `while let pat = expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub WhileLet(ExprWhileLet #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub while_token: Token![while],
+ pub let_token: Token![let],
+ pub pats: Punctuated<Pat, Token![|]>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub body: Block,
+ }),
+
+ /// A for loop: `for pat in expr { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub ForLoop(ExprForLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub for_token: Token![for],
+ pub pat: Box<Pat>,
+ pub in_token: Token![in],
+ pub expr: Box<Expr>,
+ pub body: Block,
+ }),
+
+ /// Conditionless loop: `loop { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Loop(ExprLoop #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub loop_token: Token![loop],
+ pub body: Block,
+ }),
+
+ /// A `match` expression: `match n { Some(n) => {}, None => {} }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Match(ExprMatch #full {
+ pub attrs: Vec<Attribute>,
+ pub match_token: Token![match],
+ pub expr: Box<Expr>,
+ pub brace_token: token::Brace,
+ pub arms: Vec<Arm>,
+ }),
+
+ /// A closure expression: `|a, b| a + b`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Closure(ExprClosure #full {
+ pub attrs: Vec<Attribute>,
+ pub asyncness: Option<Token![async]>,
+ pub movability: Option<Token![static]>,
+ pub capture: Option<Token![move]>,
+ pub or1_token: Token![|],
+ pub inputs: Punctuated<FnArg, Token![,]>,
+ pub or2_token: Token![|],
+ pub output: ReturnType,
+ pub body: Box<Expr>,
+ }),
+
+ /// An unsafe block: `unsafe { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Unsafe(ExprUnsafe #full {
+ pub attrs: Vec<Attribute>,
+ pub unsafe_token: Token![unsafe],
+ pub block: Block,
+ }),
+
+ /// A blocked scope: `{ ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Block(ExprBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub label: Option<Label>,
+ pub block: Block,
+ }),
+
+ /// An assignment expression: `a = compute()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Assign(ExprAssign #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub eq_token: Token![=],
+ pub right: Box<Expr>,
+ }),
+
+ /// A compound assignment expression: `counter += 1`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub AssignOp(ExprAssignOp #full {
+ pub attrs: Vec<Attribute>,
+ pub left: Box<Expr>,
+ pub op: BinOp,
+ pub right: Box<Expr>,
+ }),
+
+ /// Access of a named struct field (`obj.k`) or unnamed tuple struct
+ /// field (`obj.0`).
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Field(ExprField {
+ pub attrs: Vec<Attribute>,
+ pub base: Box<Expr>,
+ pub dot_token: Token![.],
+ pub member: Member,
+ }),
+
+ /// A square bracketed indexing expression: `vector[2]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Index(ExprIndex {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub bracket_token: token::Bracket,
+ pub index: Box<Expr>,
+ }),
+
+ /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Range(ExprRange #full {
+ pub attrs: Vec<Attribute>,
+ pub from: Option<Box<Expr>>,
+ pub limits: RangeLimits,
+ pub to: Option<Box<Expr>>,
+ }),
+
+ /// A path like `std::mem::replace` possibly containing generic
+ /// parameters and a qualified self-type.
+ ///
+ /// A plain identifier like `x` is a path of length 1.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Path(ExprPath {
+ pub attrs: Vec<Attribute>,
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }),
+
+ /// A referencing operation: `&a` or `&mut a`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Reference(ExprReference #full {
+ pub attrs: Vec<Attribute>,
+ pub and_token: Token![&],
+ pub mutability: Option<Token![mut]>,
+ pub expr: Box<Expr>,
+ }),
+
+ /// A `break`, with an optional label to break and an optional
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Break(ExprBreak #full {
+ pub attrs: Vec<Attribute>,
+ pub break_token: Token![break],
+ pub label: Option<Lifetime>,
+ pub expr: Option<Box<Expr>>,
+ }),
+
+ /// A `continue`, with an optional label.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Continue(ExprContinue #full {
+ pub attrs: Vec<Attribute>,
+ pub continue_token: Token![continue],
+ pub label: Option<Lifetime>,
+ }),
+
+ /// A `return`, with an optional value to be returned.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Return(ExprReturn #full {
+ pub attrs: Vec<Attribute>,
+ pub return_token: Token![return],
+ pub expr: Option<Box<Expr>>,
+ }),
+
+ /// A macro invocation expression: `format!("{}", q)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(ExprMacro #full {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ }),
+
+ /// A struct literal expression: `Point { x: 1, y: 1 }`.
+ ///
+ /// The `rest` provides the value of the remaining fields as in `S { a:
+ /// 1, b: 1, ..rest }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Struct(ExprStruct #full {
+ pub attrs: Vec<Attribute>,
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldValue, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ pub rest: Option<Box<Expr>>,
+ }),
+
+ /// An array literal constructed from one repeated element: `[0u8; N]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Repeat(ExprRepeat #full {
+ pub attrs: Vec<Attribute>,
+ pub bracket_token: token::Bracket,
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ pub len: Box<Expr>,
+ }),
+
+ /// A parenthesized expression: `(a + b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Paren(ExprParen {
+ pub attrs: Vec<Attribute>,
+ pub paren_token: token::Paren,
+ pub expr: Box<Expr>,
+ }),
+
+ /// An expression contained within invisible delimiters.
+ ///
+ /// This variant is important for faithfully representing the precedence
+ /// of expressions and is related to `None`-delimited spans in a
+ /// `TokenStream`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Group(ExprGroup #full {
+ pub attrs: Vec<Attribute>,
+ pub group_token: token::Group,
+ pub expr: Box<Expr>,
+ }),
+
+ /// A try-expression: `expr?`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Try(ExprTry #full {
+ pub attrs: Vec<Attribute>,
+ pub expr: Box<Expr>,
+ pub question_token: Token![?],
+ }),
+
+ /// An async block: `async { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Async(ExprAsync #full {
+ pub attrs: Vec<Attribute>,
+ pub async_token: Token![async],
+ pub capture: Option<Token![move]>,
+ pub block: Block,
+ }),
+
+ /// A try block: `try { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub TryBlock(ExprTryBlock #full {
+ pub attrs: Vec<Attribute>,
+ pub try_token: Token![try],
+ pub block: Block,
+ }),
+
+ /// A yield expression: `yield expr`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Yield(ExprYield #full {
+ pub attrs: Vec<Attribute>,
+ pub yield_token: Token![yield],
+ pub expr: Option<Box<Expr>>,
+ }),
+
+ /// Tokens in expression position not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Verbatim(ExprVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ExprVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ExprVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ExprVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+impl Expr {
+ // Not public API.
+ #[doc(hidden)]
+ #[cfg(feature = "full")]
+ pub fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
+ match *self {
+ Expr::Box(ExprBox { ref mut attrs, .. })
+ | Expr::InPlace(ExprInPlace { ref mut attrs, .. })
+ | Expr::Array(ExprArray { ref mut attrs, .. })
+ | Expr::Call(ExprCall { ref mut attrs, .. })
+ | Expr::MethodCall(ExprMethodCall { ref mut attrs, .. })
+ | Expr::Tuple(ExprTuple { ref mut attrs, .. })
+ | Expr::Binary(ExprBinary { ref mut attrs, .. })
+ | Expr::Unary(ExprUnary { ref mut attrs, .. })
+ | Expr::Lit(ExprLit { ref mut attrs, .. })
+ | Expr::Cast(ExprCast { ref mut attrs, .. })
+ | Expr::Type(ExprType { ref mut attrs, .. })
+ | Expr::If(ExprIf { ref mut attrs, .. })
+ | Expr::IfLet(ExprIfLet { ref mut attrs, .. })
+ | Expr::While(ExprWhile { ref mut attrs, .. })
+ | Expr::WhileLet(ExprWhileLet { ref mut attrs, .. })
+ | Expr::ForLoop(ExprForLoop { ref mut attrs, .. })
+ | Expr::Loop(ExprLoop { ref mut attrs, .. })
+ | Expr::Match(ExprMatch { ref mut attrs, .. })
+ | Expr::Closure(ExprClosure { ref mut attrs, .. })
+ | Expr::Unsafe(ExprUnsafe { ref mut attrs, .. })
+ | Expr::Block(ExprBlock { ref mut attrs, .. })
+ | Expr::Assign(ExprAssign { ref mut attrs, .. })
+ | Expr::AssignOp(ExprAssignOp { ref mut attrs, .. })
+ | Expr::Field(ExprField { ref mut attrs, .. })
+ | Expr::Index(ExprIndex { ref mut attrs, .. })
+ | Expr::Range(ExprRange { ref mut attrs, .. })
+ | Expr::Path(ExprPath { ref mut attrs, .. })
+ | Expr::Reference(ExprReference { ref mut attrs, .. })
+ | Expr::Break(ExprBreak { ref mut attrs, .. })
+ | Expr::Continue(ExprContinue { ref mut attrs, .. })
+ | Expr::Return(ExprReturn { ref mut attrs, .. })
+ | Expr::Macro(ExprMacro { ref mut attrs, .. })
+ | Expr::Struct(ExprStruct { ref mut attrs, .. })
+ | Expr::Repeat(ExprRepeat { ref mut attrs, .. })
+ | Expr::Paren(ExprParen { ref mut attrs, .. })
+ | Expr::Group(ExprGroup { ref mut attrs, .. })
+ | Expr::Try(ExprTry { ref mut attrs, .. })
+ | Expr::Async(ExprAsync { ref mut attrs, .. })
+ | Expr::TryBlock(ExprTryBlock { ref mut attrs, .. })
+ | Expr::Yield(ExprYield { ref mut attrs, .. }) => mem::replace(attrs, new),
+ Expr::Verbatim(_) => {
+ // TODO
+ Vec::new()
+ }
+ }
+ }
+}
+
+ast_enum! {
+ /// A struct or tuple struct field accessed in a struct literal or field
+ /// expression.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum Member {
+ /// A named field like `self.x`.
+ Named(Ident),
+ /// An unnamed field like `self.0`.
+ Unnamed(Index),
+ }
+}
+
+ast_struct! {
+ /// The index of an unnamed tuple struct field.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Index #manual_extra_traits {
+ pub index: u32,
+ pub span: Span,
+ }
+}
+
+impl From<usize> for Index {
+ fn from(index: usize) -> Index {
+ assert!(index < u32::max_value() as usize);
+ Index {
+ index: index as u32,
+ span: Span::call_site(),
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Index {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Index {
+ fn eq(&self, other: &Self) -> bool {
+ self.index == other.index
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Index {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.index.hash(state);
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// The `::<>` explicit type parameters passed to a method call:
+ /// `parse::<u64>()`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct MethodTurbofish {
+ pub colon2_token: Token![::],
+ pub lt_token: Token![<],
+ pub args: Punctuated<GenericMethodArgument, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// An individual generic argument to a method, like `T`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum GenericMethodArgument {
+ /// A type argument.
+ Type(Type),
+ /// A const expression. Must be inside of a block.
+ ///
+ /// NOTE: Identity expressions are represented as Type arguments, as
+ /// they are indistinguishable syntactically.
+ Const(Expr),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A field-value pair in a struct literal.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FieldValue {
+ /// Attributes tagged on the field.
+ pub attrs: Vec<Attribute>,
+
+ /// Name or index of the field.
+ pub member: Member,
+
+ /// The colon in `Struct { x: x }`. If written in shorthand like
+ /// `Struct { x }`, there is no colon.
+ pub colon_token: Option<Token![:]>,
+
+ /// Value of the field.
+ pub expr: Expr,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A lifetime labeling a `for`, `while`, or `loop`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Label {
+ pub name: Lifetime,
+ pub colon_token: Token![:],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A braced block containing Rust statements.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Block {
+ pub brace_token: token::Brace,
+ /// Statements in a block
+ pub stmts: Vec<Stmt>,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// A statement, usually ending in a semicolon.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub enum Stmt {
+ /// A local (let) binding.
+ Local(Local),
+
+ /// An item definition.
+ Item(Item),
+
+ /// Expr without trailing semicolon.
+ Expr(Expr),
+
+ /// Expression with trailing semicolon.
+ Semi(Expr, Token![;]),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A local `let` binding: `let x: u64 = s.parse()?`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Local {
+ pub attrs: Vec<Attribute>,
+ pub let_token: Token![let],
+ pub pats: Punctuated<Pat, Token![|]>,
+ pub ty: Option<(Token![:], Box<Type>)>,
+ pub init: Option<(Token![=], Box<Expr>)>,
+ pub semi_token: Token![;],
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum_of_structs! {
+ /// A pattern in a local binding, function signature, match expression, or
+ /// various other places.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ // Clippy false positive
+ // https://github.com/Manishearth/rust-clippy/issues/1241
+ #[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
+ pub enum Pat {
+ /// A pattern that matches any value: `_`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Wild(PatWild {
+ pub underscore_token: Token![_],
+ }),
+
+ /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Ident(PatIdent {
+ pub by_ref: Option<Token![ref]>,
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub subpat: Option<(Token![@], Box<Pat>)>,
+ }),
+
+ /// A struct or struct variant pattern: `Variant { x, y, .. }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Struct(PatStruct {
+ pub path: Path,
+ pub brace_token: token::Brace,
+ pub fields: Punctuated<FieldPat, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ }),
+
+ /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub TupleStruct(PatTupleStruct {
+ pub path: Path,
+ pub pat: PatTuple,
+ }),
+
+ /// A path pattern like `Color::Red`, optionally qualified with a
+ /// self-type.
+ ///
+ /// Unquailfied path patterns can legally refer to variants, structs,
+ /// constants or associated constants. Quailfied path patterns like
+ /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to
+ /// associated constants.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Path(PatPath {
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }),
+
+ /// A tuple pattern: `(a, b)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Tuple(PatTuple {
+ pub paren_token: token::Paren,
+ pub front: Punctuated<Pat, Token![,]>,
+ pub dot2_token: Option<Token![..]>,
+ pub comma_token: Option<Token![,]>,
+ pub back: Punctuated<Pat, Token![,]>,
+ }),
+
+ /// A box pattern: `box v`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Box(PatBox {
+ pub box_token: Token![box],
+ pub pat: Box<Pat>,
+ }),
+
+ /// A reference pattern: `&mut (first, second)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Ref(PatRef {
+ pub and_token: Token![&],
+ pub mutability: Option<Token![mut]>,
+ pub pat: Box<Pat>,
+ }),
+
+ /// A literal pattern: `0`.
+ ///
+ /// This holds an `Expr` rather than a `Lit` because negative numbers
+ /// are represented as an `Expr::Unary`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Lit(PatLit {
+ pub expr: Box<Expr>,
+ }),
+
+ /// A range pattern: `1..=2`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Range(PatRange {
+ pub lo: Box<Expr>,
+ pub limits: RangeLimits,
+ pub hi: Box<Expr>,
+ }),
+
+ /// A dynamically sized slice pattern: `[a, b, i.., y, z]`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Slice(PatSlice {
+ pub bracket_token: token::Bracket,
+ pub front: Punctuated<Pat, Token![,]>,
+ pub middle: Option<Box<Pat>>,
+ pub dot2_token: Option<Token![..]>,
+ pub comma_token: Option<Token![,]>,
+ pub back: Punctuated<Pat, Token![,]>,
+ }),
+
+ /// A macro in expression position.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(PatMacro {
+ pub mac: Macro,
+ }),
+
+ /// Tokens in pattern position not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Verbatim(PatVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(all(feature = "full", feature = "extra-traits"))]
+impl Eq for PatVerbatim {}
+
+#[cfg(all(feature = "full", feature = "extra-traits"))]
+impl PartialEq for PatVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(all(feature = "full", feature = "extra-traits"))]
+impl Hash for PatVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// One arm of a `match` expression: `0...10 => { return true; }`.
+ ///
+ /// As in:
+ ///
+ /// ```rust
+ /// # fn f() -> bool {
+ /// # let n = 0;
+ /// match n {
+ /// 0...10 => {
+ /// return true;
+ /// }
+ /// // ...
+ /// # _ => {}
+ /// }
+ /// # false
+ /// # }
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct Arm {
+ pub attrs: Vec<Attribute>,
+ pub leading_vert: Option<Token![|]>,
+ pub pats: Punctuated<Pat, Token![|]>,
+ pub guard: Option<(Token![if], Box<Expr>)>,
+ pub fat_arrow_token: Token![=>],
+ pub body: Box<Expr>,
+ pub comma: Option<Token![,]>,
+ }
+}
+
+#[cfg(feature = "full")]
+ast_enum! {
+ /// Limit types of a range, inclusive or exclusive.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum RangeLimits {
+ /// Inclusive at the beginning, exclusive at the end.
+ HalfOpen(Token![..]),
+ /// Inclusive at the beginning and end.
+ Closed(Token![..=]),
+ }
+}
+
+#[cfg(feature = "full")]
+ast_struct! {
+ /// A single field in a struct pattern.
+ ///
+ /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
+ /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FieldPat {
+ pub attrs: Vec<Attribute>,
+ pub member: Member,
+ pub colon_token: Option<Token![:]>,
+ pub pat: Box<Pat>,
+ }
+}
+
+#[cfg(any(feature = "parsing", feature = "printing"))]
+#[cfg(feature = "full")]
+fn arm_expr_requires_comma(expr: &Expr) -> bool {
+ // see https://github.com/rust-lang/rust/blob/eb8f2586e
+ // /src/libsyntax/parse/classify.rs#L17-L37
+ match *expr {
+ Expr::Unsafe(..)
+ | Expr::Block(..)
+ | Expr::If(..)
+ | Expr::IfLet(..)
+ | Expr::Match(..)
+ | Expr::While(..)
+ | Expr::WhileLet(..)
+ | Expr::Loop(..)
+ | Expr::ForLoop(..)
+ | Expr::Async(..)
+ | Expr::TryBlock(..) => false,
+ _ => true,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use path::parsing::mod_style_path_segment;
+ #[cfg(feature = "full")]
+ use path::parsing::ty_no_eq_after;
+
+ use buffer::Cursor;
+ #[cfg(feature = "full")]
+ use parse_error;
+ #[cfg(feature = "full")]
+ use proc_macro2::TokenStream;
+ use synom::PResult;
+ use synom::Synom;
+
+ // When we're parsing expressions which occur before blocks, like in an if
+ // statement's condition, we cannot parse a struct literal.
+ //
+ // Struct literals are ambiguous in certain positions
+ // https://github.com/rust-lang/rfcs/pull/92
+ macro_rules! ambiguous_expr {
+ ($i:expr, $allow_struct:ident) => {
+ ambiguous_expr($i, $allow_struct, true)
+ };
+ }
+
+ // When we are parsing an optional suffix expression, we cannot allow blocks
+ // if structs are not allowed.
+ //
+ // Example:
+ //
+ // if break {} {}
+ //
+ // is ambiguous between:
+ //
+ // if (break {}) {}
+ // if (break) {} {}
+ #[cfg(feature = "full")]
+ macro_rules! opt_ambiguous_expr {
+ ($i:expr, $allow_struct:ident) => {
+ option!($i, call!(ambiguous_expr, $allow_struct, $allow_struct))
+ };
+ }
+
+ impl Synom for Expr {
+ named!(parse -> Self, ambiguous_expr!(true));
+
+ fn description() -> Option<&'static str> {
+ Some("expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(expr_no_struct -> Expr, ambiguous_expr!(false));
+
+ // Parse an arbitrary expression.
+ #[cfg(feature = "full")]
+ fn ambiguous_expr(i: Cursor, allow_struct: bool, allow_block: bool) -> PResult<Expr> {
+ call!(i, assign_expr, allow_struct, allow_block)
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn ambiguous_expr(i: Cursor, allow_struct: bool, allow_block: bool) -> PResult<Expr> {
+ // NOTE: We intentionally skip assign_expr, placement_expr, and
+ // range_expr, as they are not parsed in non-full mode.
+ call!(i, or_expr, allow_struct, allow_block)
+ }
+
+ // Parse a left-associative binary operator.
+ macro_rules! binop {
+ (
+ $name: ident,
+ $next: ident,
+ $submac: ident!( $($args:tt)* )
+ ) => {
+ named!($name(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!($next, allow_struct, allow_block) >>
+ many0!(do_parse!(
+ op: $submac!($($args)*) >>
+ rhs: call!($next, allow_struct, true) >>
+ ({
+ e = ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(e.into()),
+ op: op,
+ right: Box::new(rhs.into()),
+ }.into();
+ })
+ )) >>
+ (e)
+ ));
+ }
+ }
+
+ // <placement> = <placement> ..
+ // <placement> += <placement> ..
+ // <placement> -= <placement> ..
+ // <placement> *= <placement> ..
+ // <placement> /= <placement> ..
+ // <placement> %= <placement> ..
+ // <placement> ^= <placement> ..
+ // <placement> &= <placement> ..
+ // <placement> |= <placement> ..
+ // <placement> <<= <placement> ..
+ // <placement> >>= <placement> ..
+ //
+ // NOTE: This operator is right-associative.
+ #[cfg(feature = "full")]
+ named!(assign_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(placement_expr, allow_struct, allow_block) >>
+ alt!(
+ do_parse!(
+ eq: punct!(=) >>
+ // Recurse into self to parse right-associative operator.
+ rhs: call!(assign_expr, allow_struct, true) >>
+ ({
+ e = ExprAssign {
+ attrs: Vec::new(),
+ left: Box::new(e),
+ eq_token: eq,
+ right: Box::new(rhs),
+ }.into();
+ })
+ )
+ |
+ do_parse!(
+ op: call!(BinOp::parse_assign_op) >>
+ // Recurse into self to parse right-associative operator.
+ rhs: call!(assign_expr, allow_struct, true) >>
+ ({
+ e = ExprAssignOp {
+ attrs: Vec::new(),
+ left: Box::new(e),
+ op: op,
+ right: Box::new(rhs),
+ }.into();
+ })
+ )
+ |
+ epsilon!()
+ ) >>
+ (e)
+ ));
+
+ // <range> <- <range> ..
+ //
+ // NOTE: The `in place { expr }` version of this syntax is parsed in
+ // `atom_expr`, not here.
+ //
+ // NOTE: This operator is right-associative.
+ #[cfg(feature = "full")]
+ named!(placement_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(range_expr, allow_struct, allow_block) >>
+ alt!(
+ do_parse!(
+ arrow: punct!(<-) >>
+ // Recurse into self to parse right-associative operator.
+ rhs: call!(placement_expr, allow_struct, true) >>
+ ({
+ e = ExprInPlace {
+ attrs: Vec::new(),
+ // op: BinOp::Place(larrow),
+ place: Box::new(e),
+ arrow_token: arrow,
+ value: Box::new(rhs),
+ }.into();
+ })
+ )
+ |
+ epsilon!()
+ ) >>
+ (e)
+ ));
+
+ // <or> ... <or> ..
+ // <or> .. <or> ..
+ // <or> ..
+ //
+ // NOTE: This is currently parsed oddly - I'm not sure of what the exact
+ // rules are for parsing these expressions are, but this is not correct.
+ // For example, `a .. b .. c` is not a legal expression. It should not
+ // be parsed as either `(a .. b) .. c` or `a .. (b .. c)` apparently.
+ //
+ // NOTE: The form of ranges which don't include a preceding expression are
+ // parsed by `atom_expr`, rather than by this function.
+ #[cfg(feature = "full")]
+ named!(range_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(or_expr, allow_struct, allow_block) >>
+ many0!(do_parse!(
+ limits: syn!(RangeLimits) >>
+ // We don't want to allow blocks here if we don't allow structs. See
+ // the reasoning for `opt_ambiguous_expr!` above.
+ hi: option!(call!(or_expr, allow_struct, allow_struct)) >>
+ ({
+ e = ExprRange {
+ attrs: Vec::new(),
+ from: Some(Box::new(e)),
+ limits: limits,
+ to: hi.map(|e| Box::new(e)),
+ }.into();
+ })
+ )) >>
+ (e)
+ ));
+
+ // <and> || <and> ...
+ binop!(or_expr, and_expr, map!(punct!(||), BinOp::Or));
+
+ // <compare> && <compare> ...
+ binop!(and_expr, compare_expr, map!(punct!(&&), BinOp::And));
+
+ // <bitor> == <bitor> ...
+ // <bitor> != <bitor> ...
+ // <bitor> >= <bitor> ...
+ // <bitor> <= <bitor> ...
+ // <bitor> > <bitor> ...
+ // <bitor> < <bitor> ...
+ //
+ // NOTE: This operator appears to be parsed as left-associative, but errors
+ // if it is used in a non-associative manner.
+ binop!(
+ compare_expr,
+ bitor_expr,
+ alt!(
+ punct!(==) => { BinOp::Eq }
+ |
+ punct!(!=) => { BinOp::Ne }
+ |
+ // must be above Lt
+ punct!(<=) => { BinOp::Le }
+ |
+ // must be above Gt
+ punct!(>=) => { BinOp::Ge }
+ |
+ do_parse!(
+ // Make sure that we don't eat the < part of a <- operator
+ not!(punct!(<-)) >>
+ t: punct!(<) >>
+ (BinOp::Lt(t))
+ )
+ |
+ punct!(>) => { BinOp::Gt }
+ )
+ );
+
+ // <bitxor> | <bitxor> ...
+ binop!(
+ bitor_expr,
+ bitxor_expr,
+ do_parse!(not!(punct!(||)) >> not!(punct!(|=)) >> t: punct!(|) >> (BinOp::BitOr(t)))
+ );
+
+ // <bitand> ^ <bitand> ...
+ binop!(
+ bitxor_expr,
+ bitand_expr,
+ do_parse!(
+ // NOTE: Make sure we aren't looking at ^=.
+ not!(punct!(^=)) >> t: punct!(^) >> (BinOp::BitXor(t))
+ )
+ );
+
+ // <shift> & <shift> ...
+ binop!(
+ bitand_expr,
+ shift_expr,
+ do_parse!(
+ // NOTE: Make sure we aren't looking at && or &=.
+ not!(punct!(&&)) >> not!(punct!(&=)) >> t: punct!(&) >> (BinOp::BitAnd(t))
+ )
+ );
+
+ // <arith> << <arith> ...
+ // <arith> >> <arith> ...
+ binop!(
+ shift_expr,
+ arith_expr,
+ alt!(
+ punct!(<<) => { BinOp::Shl }
+ |
+ punct!(>>) => { BinOp::Shr }
+ )
+ );
+
+ // <term> + <term> ...
+ // <term> - <term> ...
+ binop!(
+ arith_expr,
+ term_expr,
+ alt!(
+ punct!(+) => { BinOp::Add }
+ |
+ punct!(-) => { BinOp::Sub }
+ )
+ );
+
+ // <cast> * <cast> ...
+ // <cast> / <cast> ...
+ // <cast> % <cast> ...
+ binop!(
+ term_expr,
+ cast_expr,
+ alt!(
+ punct!(*) => { BinOp::Mul }
+ |
+ punct!(/) => { BinOp::Div }
+ |
+ punct!(%) => { BinOp::Rem }
+ )
+ );
+
+ // <unary> as <ty>
+ // <unary> : <ty>
+ #[cfg(feature = "full")]
+ named!(cast_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(unary_expr, allow_struct, allow_block) >>
+ many0!(alt!(
+ do_parse!(
+ as_: keyword!(as) >>
+ // We can't accept `A + B` in cast expressions, as it's
+ // ambiguous with the + expression.
+ ty: call!(Type::without_plus) >>
+ ({
+ e = ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ as_token: as_,
+ ty: Box::new(ty),
+ }.into();
+ })
+ )
+ |
+ do_parse!(
+ colon: punct!(:) >>
+ // We can't accept `A + B` in cast expressions, as it's
+ // ambiguous with the + expression.
+ ty: call!(Type::without_plus) >>
+ ({
+ e = ExprType {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ colon_token: colon,
+ ty: Box::new(ty),
+ }.into();
+ })
+ )
+ )) >>
+ (e)
+ ));
+
+ // <unary> as <ty>
+ #[cfg(not(feature = "full"))]
+ named!(cast_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(unary_expr, allow_struct, allow_block) >>
+ many0!(do_parse!(
+ as_: keyword!(as) >>
+ // We can't accept `A + B` in cast expressions, as it's
+ // ambiguous with the + expression.
+ ty: call!(Type::without_plus) >>
+ ({
+ e = ExprCast {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ as_token: as_,
+ ty: Box::new(ty),
+ }.into();
+ })
+ )) >>
+ (e)
+ ));
+
+ // <UnOp> <trailer>
+ // & <trailer>
+ // &mut <trailer>
+ // box <trailer>
+ #[cfg(feature = "full")]
+ named!(unary_expr(allow_struct: bool, allow_block: bool) -> Expr, alt!(
+ do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ op: syn!(UnOp) >>
+ expr: call!(unary_expr, allow_struct, true) >>
+ (ExprUnary {
+ attrs: attrs,
+ op: op,
+ expr: Box::new(expr),
+ }.into())
+ )
+ |
+ do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ and: punct!(&) >>
+ mutability: option!(keyword!(mut)) >>
+ expr: call!(unary_expr, allow_struct, true) >>
+ (ExprReference {
+ attrs: attrs,
+ and_token: and,
+ mutability: mutability,
+ expr: Box::new(expr),
+ }.into())
+ )
+ |
+ do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ box_: keyword!(box) >>
+ expr: call!(unary_expr, allow_struct, true) >>
+ (ExprBox {
+ attrs: attrs,
+ box_token: box_,
+ expr: Box::new(expr),
+ }.into())
+ )
+ |
+ call!(trailer_expr, allow_struct, allow_block)
+ ));
+
+ // XXX: This duplication is ugly
+ #[cfg(not(feature = "full"))]
+ named!(unary_expr(allow_struct: bool, allow_block: bool) -> Expr, alt!(
+ do_parse!(
+ op: syn!(UnOp) >>
+ expr: call!(unary_expr, allow_struct, true) >>
+ (ExprUnary {
+ attrs: Vec::new(),
+ op: op,
+ expr: Box::new(expr),
+ }.into())
+ )
+ |
+ call!(trailer_expr, allow_struct, allow_block)
+ ));
+
+ #[cfg(feature = "full")]
+ fn take_outer(attrs: &mut Vec<Attribute>) -> Vec<Attribute> {
+ let mut outer = Vec::new();
+ let mut inner = Vec::new();
+ for attr in mem::replace(attrs, Vec::new()) {
+ match attr.style {
+ AttrStyle::Outer => outer.push(attr),
+ AttrStyle::Inner(_) => inner.push(attr),
+ }
+ }
+ *attrs = inner;
+ outer
+ }
+
+ // <atom> (..<args>) ...
+ // <atom> . <ident> (..<args>) ...
+ // <atom> . <ident> ...
+ // <atom> . <lit> ...
+ // <atom> [ <expr> ] ...
+ // <atom> ? ...
+ #[cfg(feature = "full")]
+ named!(trailer_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(atom_expr, allow_struct, allow_block) >>
+ outer_attrs: value!({
+ let mut attrs = e.replace_attrs(Vec::new());
+ let outer_attrs = take_outer(&mut attrs);
+ e.replace_attrs(attrs);
+ outer_attrs
+ }) >>
+ many0!(alt!(
+ tap!(args: and_call => {
+ let (paren, args) = args;
+ e = ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ args: args,
+ paren_token: paren,
+ }.into();
+ })
+ |
+ tap!(more: and_method_call => {
+ let mut call = more;
+ call.receiver = Box::new(e);
+ e = call.into();
+ })
+ |
+ tap!(field: and_field => {
+ let (token, member) = field;
+ e = ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token: token,
+ member: member,
+ }.into();
+ })
+ |
+ tap!(i: and_index => {
+ let (bracket, i) = i;
+ e = ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: bracket,
+ index: Box::new(i),
+ }.into();
+ })
+ |
+ tap!(question: punct!(?) => {
+ e = ExprTry {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ question_token: question,
+ }.into();
+ })
+ )) >>
+ ({
+ let mut attrs = outer_attrs;
+ attrs.extend(e.replace_attrs(Vec::new()));
+ e.replace_attrs(attrs);
+ e
+ })
+ ));
+
+ // XXX: Duplication == ugly
+ #[cfg(not(feature = "full"))]
+ named!(trailer_expr(allow_struct: bool, allow_block: bool) -> Expr, do_parse!(
+ mut e: call!(atom_expr, allow_struct, allow_block) >>
+ many0!(alt!(
+ tap!(args: and_call => {
+ e = ExprCall {
+ attrs: Vec::new(),
+ func: Box::new(e),
+ paren_token: args.0,
+ args: args.1,
+ }.into();
+ })
+ |
+ tap!(field: and_field => {
+ let (token, member) = field;
+ e = ExprField {
+ attrs: Vec::new(),
+ base: Box::new(e),
+ dot_token: token,
+ member: member,
+ }.into();
+ })
+ |
+ tap!(i: and_index => {
+ e = ExprIndex {
+ attrs: Vec::new(),
+ expr: Box::new(e),
+ bracket_token: i.0,
+ index: Box::new(i.1),
+ }.into();
+ })
+ )) >>
+ (e)
+ ));
+
+ // Parse all atomic expressions which don't have to worry about precedence
+ // interactions, as they are fully contained.
+ #[cfg(feature = "full")]
+ named!(atom_expr(allow_struct: bool, allow_block: bool) -> Expr, alt!(
+ syn!(ExprGroup) => { Expr::Group } // must be placed first
+ |
+ syn!(ExprLit) => { Expr::Lit } // must be before expr_struct
+ |
+ // must be before ExprStruct
+ syn!(ExprAsync) => { Expr::Async }
+ |
+ // must be before ExprStruct
+ syn!(ExprTryBlock) => { Expr::TryBlock }
+ |
+ // must be before expr_path
+ cond_reduce!(allow_struct, syn!(ExprStruct)) => { Expr::Struct }
+ |
+ syn!(ExprParen) => { Expr::Paren } // must be before expr_tup
+ |
+ syn!(ExprMacro) => { Expr::Macro } // must be before expr_path
+ |
+ call!(expr_break, allow_struct) // must be before expr_path
+ |
+ syn!(ExprContinue) => { Expr::Continue } // must be before expr_path
+ |
+ call!(expr_ret, allow_struct) // must be before expr_path
+ |
+ syn!(ExprArray) => { Expr::Array }
+ |
+ syn!(ExprTuple) => { Expr::Tuple }
+ |
+ syn!(ExprIf) => { Expr::If }
+ |
+ syn!(ExprIfLet) => { Expr::IfLet }
+ |
+ syn!(ExprWhile) => { Expr::While }
+ |
+ syn!(ExprWhileLet) => { Expr::WhileLet }
+ |
+ syn!(ExprForLoop) => { Expr::ForLoop }
+ |
+ syn!(ExprLoop) => { Expr::Loop }
+ |
+ syn!(ExprMatch) => { Expr::Match }
+ |
+ syn!(ExprYield) => { Expr::Yield }
+ |
+ syn!(ExprUnsafe) => { Expr::Unsafe }
+ |
+ call!(expr_closure, allow_struct)
+ |
+ cond_reduce!(allow_block, syn!(ExprBlock)) => { Expr::Block }
+ |
+ // NOTE: This is the prefix-form of range
+ call!(expr_range, allow_struct)
+ |
+ syn!(ExprPath) => { Expr::Path }
+ |
+ syn!(ExprRepeat) => { Expr::Repeat }
+ ));
+
+ #[cfg(not(feature = "full"))]
+ named!(atom_expr(_allow_struct: bool, _allow_block: bool) -> Expr, alt!(
+ syn!(ExprLit) => { Expr::Lit }
+ |
+ syn!(ExprParen) => { Expr::Paren }
+ |
+ syn!(ExprPath) => { Expr::Path }
+ ));
+
+ #[cfg(feature = "full")]
+ named!(expr_nosemi -> Expr, do_parse!(
+ nosemi: alt!(
+ syn!(ExprIf) => { Expr::If }
+ |
+ syn!(ExprIfLet) => { Expr::IfLet }
+ |
+ syn!(ExprWhile) => { Expr::While }
+ |
+ syn!(ExprWhileLet) => { Expr::WhileLet }
+ |
+ syn!(ExprForLoop) => { Expr::ForLoop }
+ |
+ syn!(ExprLoop) => { Expr::Loop }
+ |
+ syn!(ExprMatch) => { Expr::Match }
+ |
+ syn!(ExprTryBlock) => { Expr::TryBlock }
+ |
+ syn!(ExprYield) => { Expr::Yield }
+ |
+ syn!(ExprUnsafe) => { Expr::Unsafe }
+ |
+ syn!(ExprBlock) => { Expr::Block }
+ ) >>
+ // If the next token is a `.` or a `?` it is special-cased to parse
+ // as an expression instead of a blockexpression.
+ not!(punct!(.)) >>
+ not!(punct!(?)) >>
+ (nosemi)
+ ));
+
+ impl Synom for ExprLit {
+ #[cfg(not(feature = "full"))]
+ named!(parse -> Self, do_parse!(
+ lit: syn!(Lit) >>
+ (ExprLit {
+ attrs: Vec::new(),
+ lit: lit,
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ lit: syn!(Lit) >>
+ (ExprLit {
+ attrs: attrs,
+ lit: lit,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("literal")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprMacro {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ mac: syn!(Macro) >>
+ (ExprMacro {
+ attrs: attrs,
+ mac: mac,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("macro invocation expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprGroup {
+ named!(parse -> Self, do_parse!(
+ e: grouped!(syn!(Expr)) >>
+ (ExprGroup {
+ attrs: Vec::new(),
+ expr: Box::new(e.1),
+ group_token: e.0,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("expression surrounded by invisible delimiters")
+ }
+ }
+
+ impl Synom for ExprParen {
+ #[cfg(not(feature = "full"))]
+ named!(parse -> Self, do_parse!(
+ e: parens!(syn!(Expr)) >>
+ (ExprParen {
+ attrs: Vec::new(),
+ paren_token: e.0,
+ expr: Box::new(e.1),
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ e: parens!(tuple!(
+ many0!(Attribute::parse_inner),
+ syn!(Expr),
+ )) >>
+ (ExprParen {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((e.1).0);
+ attrs
+ },
+ paren_token: e.0,
+ expr: Box::new((e.1).1),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("parenthesized expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprArray {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ elems: brackets!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Punctuated::parse_terminated),
+ )) >>
+ (ExprArray {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((elems.1).0);
+ attrs
+ },
+ bracket_token: elems.0,
+ elems: (elems.1).1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("array expression")
+ }
+ }
+
+ named!(and_call -> (token::Paren, Punctuated<Expr, Token![,]>),
+ parens!(Punctuated::parse_terminated)
+ );
+
+ #[cfg(feature = "full")]
+ named!(and_method_call -> ExprMethodCall, do_parse!(
+ dot: punct!(.) >>
+ method: syn!(Ident) >>
+ turbofish: option!(tuple!(
+ punct!(::),
+ punct!(<),
+ call!(Punctuated::parse_terminated),
+ punct!(>),
+ )) >>
+ args: parens!(Punctuated::parse_terminated) >>
+ ({
+ ExprMethodCall {
+ attrs: Vec::new(),
+ // this expr will get overwritten after being returned
+ receiver: Box::new(Expr::Verbatim(ExprVerbatim {
+ tts: TokenStream::new(),
+ })),
+
+ method: method,
+ turbofish: turbofish.map(|fish| MethodTurbofish {
+ colon2_token: fish.0,
+ lt_token: fish.1,
+ args: fish.2,
+ gt_token: fish.3,
+ }),
+ args: args.1,
+ paren_token: args.0,
+ dot_token: dot,
+ }
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for GenericMethodArgument {
+ // TODO parse const generics as well
+ named!(parse -> Self, map!(ty_no_eq_after, GenericMethodArgument::Type));
+
+ fn description() -> Option<&'static str> {
+ Some("generic method argument")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprTuple {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ elems: parens!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Punctuated::parse_terminated),
+ )) >>
+ (ExprTuple {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((elems.1).0);
+ attrs
+ },
+ elems: (elems.1).1,
+ paren_token: elems.0,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("tuple")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprIfLet {
+ named!(parse -> Self, do_parse!(
+ if_: keyword!(if) >>
+ let_: keyword!(let) >>
+ pats: call!(Punctuated::parse_separated_nonempty) >>
+ eq: punct!(=) >>
+ cond: expr_no_struct >>
+ then_block: braces!(Block::parse_within) >>
+ else_block: option!(else_block) >>
+ (ExprIfLet {
+ attrs: Vec::new(),
+ pats: pats,
+ let_token: let_,
+ eq_token: eq,
+ expr: Box::new(cond),
+ then_branch: Block {
+ brace_token: then_block.0,
+ stmts: then_block.1,
+ },
+ if_token: if_,
+ else_branch: else_block,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`if let` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprIf {
+ named!(parse -> Self, do_parse!(
+ if_: keyword!(if) >>
+ cond: expr_no_struct >>
+ then_block: braces!(Block::parse_within) >>
+ else_block: option!(else_block) >>
+ (ExprIf {
+ attrs: Vec::new(),
+ cond: Box::new(cond),
+ then_branch: Block {
+ brace_token: then_block.0,
+ stmts: then_block.1,
+ },
+ if_token: if_,
+ else_branch: else_block,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`if` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(else_block -> (Token![else], Box<Expr>), do_parse!(
+ else_: keyword!(else) >>
+ expr: alt!(
+ syn!(ExprIf) => { Expr::If }
+ |
+ syn!(ExprIfLet) => { Expr::IfLet }
+ |
+ do_parse!(
+ else_block: braces!(Block::parse_within) >>
+ (Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: Block {
+ brace_token: else_block.0,
+ stmts: else_block.1,
+ },
+ }))
+ )
+ ) >>
+ (else_, Box::new(expr))
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprForLoop {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ label: option!(syn!(Label)) >>
+ for_: keyword!(for) >>
+ pat: syn!(Pat) >>
+ in_: keyword!(in) >>
+ expr: expr_no_struct >>
+ block: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ExprForLoop {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((block.1).0);
+ attrs
+ },
+ label: label,
+ for_token: for_,
+ pat: Box::new(pat),
+ in_token: in_,
+ expr: Box::new(expr),
+ body: Block {
+ brace_token: block.0,
+ stmts: (block.1).1,
+ },
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`for` loop")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprLoop {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ label: option!(syn!(Label)) >>
+ loop_: keyword!(loop) >>
+ block: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ExprLoop {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((block.1).0);
+ attrs
+ },
+ label: label,
+ loop_token: loop_,
+ body: Block {
+ brace_token: block.0,
+ stmts: (block.1).1,
+ },
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`loop`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprMatch {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ match_: keyword!(match) >>
+ obj: expr_no_struct >>
+ braced_content: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ many0!(syn!(Arm)),
+ )) >>
+ (ExprMatch {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((braced_content.1).0);
+ attrs
+ },
+ expr: Box::new(obj),
+ match_token: match_,
+ brace_token: braced_content.0,
+ arms: (braced_content.1).1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`match` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprTryBlock {
+ named!(parse -> Self, do_parse!(
+ try_token: keyword!(try) >>
+ block: syn!(Block) >>
+ (ExprTryBlock {
+ attrs: Vec::new(),
+ try_token: try_token,
+ block: block,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`try` block")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprYield {
+ named!(parse -> Self, do_parse!(
+ yield_: keyword!(yield) >>
+ expr: option!(syn!(Expr)) >>
+ (ExprYield {
+ attrs: Vec::new(),
+ yield_token: yield_,
+ expr: expr.map(Box::new),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`yield` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for Arm {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ leading_vert: option!(punct!(|)) >>
+ pats: call!(Punctuated::parse_separated_nonempty) >>
+ guard: option!(tuple!(keyword!(if), syn!(Expr))) >>
+ fat_arrow: punct!(=>) >>
+ body: do_parse!(
+ expr: alt!(expr_nosemi | syn!(Expr)) >>
+ comma: switch!(value!(arm_expr_requires_comma(&expr)),
+ true => alt!(
+ input_end!() => { |_| None }
+ |
+ punct!(,) => { Some }
+ )
+ |
+ false => option!(punct!(,))
+ ) >>
+ (expr, comma)
+ ) >>
+ (Arm {
+ fat_arrow_token: fat_arrow,
+ attrs: attrs,
+ leading_vert: leading_vert,
+ pats: pats,
+ guard: guard.map(|(if_, guard)| (if_, Box::new(guard))),
+ body: Box::new(body.0),
+ comma: body.1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`match` arm")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(expr_closure(allow_struct: bool) -> Expr, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ asyncness: option!(keyword!(async)) >>
+ movability: option!(cond_reduce!(asyncness.is_none(), keyword!(static))) >>
+ capture: option!(keyword!(move)) >>
+ or1: punct!(|) >>
+ inputs: call!(Punctuated::parse_terminated_with, fn_arg) >>
+ or2: punct!(|) >>
+ ret_and_body: alt!(
+ do_parse!(
+ arrow: punct!(->) >>
+ ty: syn!(Type) >>
+ body: syn!(Block) >>
+ (
+ ReturnType::Type(arrow, Box::new(ty)),
+ Expr::Block(ExprBlock {
+ attrs: Vec::new(),
+ label: None,
+ block: body,
+ },
+ ))
+ )
+ |
+ map!(ambiguous_expr!(allow_struct), |e| (ReturnType::Default, e))
+ ) >>
+ (Expr::Closure(ExprClosure {
+ attrs: attrs,
+ asyncness: asyncness,
+ movability: movability,
+ capture: capture,
+ or1_token: or1,
+ inputs: inputs,
+ or2_token: or2,
+ output: ret_and_body.0,
+ body: Box::new(ret_and_body.1),
+ }))
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprAsync {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ async_token: keyword!(async) >>
+ capture: option!(keyword!(move)) >>
+ block: syn!(Block) >>
+ (ExprAsync {
+ attrs: attrs,
+ async_token: async_token,
+ capture: capture,
+ block: block,
+ })
+ ));
+ }
+
+ #[cfg(feature = "full")]
+ named!(fn_arg -> FnArg, do_parse!(
+ pat: syn!(Pat) >>
+ ty: option!(tuple!(punct!(:), syn!(Type))) >>
+ ({
+ if let Some((colon, ty)) = ty {
+ FnArg::Captured(ArgCaptured {
+ pat: pat,
+ colon_token: colon,
+ ty: ty,
+ })
+ } else {
+ FnArg::Inferred(pat)
+ }
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprWhile {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ label: option!(syn!(Label)) >>
+ while_: keyword!(while) >>
+ cond: expr_no_struct >>
+ block: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ExprWhile {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((block.1).0);
+ attrs
+ },
+ label: label,
+ while_token: while_,
+ cond: Box::new(cond),
+ body: Block {
+ brace_token: block.0,
+ stmts: (block.1).1,
+ },
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`while` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprWhileLet {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ label: option!(syn!(Label)) >>
+ while_: keyword!(while) >>
+ let_: keyword!(let) >>
+ pats: call!(Punctuated::parse_separated_nonempty) >>
+ eq: punct!(=) >>
+ value: expr_no_struct >>
+ block: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ExprWhileLet {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((block.1).0);
+ attrs
+ },
+ label: label,
+ while_token: while_,
+ let_token: let_,
+ pats: pats,
+ eq_token: eq,
+ expr: Box::new(value),
+ body: Block {
+ brace_token: block.0,
+ stmts: (block.1).1,
+ },
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`while let` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for Label {
+ named!(parse -> Self, do_parse!(
+ name: syn!(Lifetime) >>
+ colon: punct!(:) >>
+ (Label {
+ name: name,
+ colon_token: colon,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`while let` expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprContinue {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ cont: keyword!(continue) >>
+ label: option!(syn!(Lifetime)) >>
+ (ExprContinue {
+ attrs: attrs,
+ continue_token: cont,
+ label: label,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`continue`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(expr_break(allow_struct: bool) -> Expr, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ break_: keyword!(break) >>
+ label: option!(syn!(Lifetime)) >>
+ // We can't allow blocks after a `break` expression when we wouldn't
+ // allow structs, as this expression is ambiguous.
+ val: opt_ambiguous_expr!(allow_struct) >>
+ (ExprBreak {
+ attrs: attrs,
+ label: label,
+ expr: val.map(Box::new),
+ break_token: break_,
+ }.into())
+ ));
+
+ #[cfg(feature = "full")]
+ named!(expr_ret(allow_struct: bool) -> Expr, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ return_: keyword!(return) >>
+ // NOTE: return is greedy and eats blocks after it even when in a
+ // position where structs are not allowed, such as in if statement
+ // conditions. For example:
+ //
+ // if return { println!("A") } {} // Prints "A"
+ ret_value: option!(ambiguous_expr!(allow_struct)) >>
+ (ExprReturn {
+ attrs: attrs,
+ expr: ret_value.map(Box::new),
+ return_token: return_,
+ }.into())
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprStruct {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ path: syn!(Path) >>
+ data: braces!(do_parse!(
+ inner_attrs: many0!(Attribute::parse_inner) >>
+ fields: call!(Punctuated::parse_terminated) >>
+ base: option!(cond!(fields.empty_or_trailing(), do_parse!(
+ dots: punct!(..) >>
+ base: syn!(Expr) >>
+ (dots, base)
+ ))) >>
+ (inner_attrs, fields, base)
+ )) >>
+ ({
+ let (brace, (inner_attrs, fields, base)) = data;
+ let (dots, rest) = match base.and_then(|b| b) {
+ Some((dots, base)) => (Some(dots), Some(base)),
+ None => (None, None),
+ };
+ ExprStruct {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend(inner_attrs);
+ attrs
+ },
+ brace_token: brace,
+ path: path,
+ fields: fields,
+ dot2_token: dots,
+ rest: rest.map(Box::new),
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("struct literal expression")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for FieldValue {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ field_value: alt!(
+ tuple!(syn!(Member), map!(punct!(:), Some), syn!(Expr))
+ |
+ map!(syn!(Ident), |name| (
+ Member::Named(name.clone()),
+ None,
+ Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself: None,
+ path: name.into(),
+ }),
+ ))
+ ) >>
+ (FieldValue {
+ attrs: attrs,
+ member: field_value.0,
+ colon_token: field_value.1,
+ expr: field_value.2,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("field-value pair: `field: value`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprRepeat {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ data: brackets!(tuple!(
+ many0!(Attribute::parse_inner),
+ syn!(Expr),
+ punct!(;),
+ syn!(Expr),
+ )) >>
+ (ExprRepeat {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((data.1).0);
+ attrs
+ },
+ expr: Box::new((data.1).1),
+ len: Box::new((data.1).3),
+ bracket_token: data.0,
+ semi_token: (data.1).2,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("repeated array literal: `[val; N]`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprUnsafe {
+ named!(parse -> Self, do_parse!(
+ unsafe_: keyword!(unsafe) >>
+ b: syn!(Block) >>
+ (ExprUnsafe {
+ attrs: Vec::new(),
+ unsafe_token: unsafe_,
+ block: b,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("unsafe block: `unsafe { .. }`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for ExprBlock {
+ named!(parse -> Self, do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ label: option!(syn!(Label)) >>
+ block: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ExprBlock {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((block.1).0);
+ attrs
+ },
+ label: label,
+ block: Block {
+ brace_token: block.0,
+ stmts: (block.1).1,
+ },
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("block: `{ .. }`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(expr_range(allow_struct: bool) -> Expr, do_parse!(
+ limits: syn!(RangeLimits) >>
+ hi: opt_ambiguous_expr!(allow_struct) >>
+ (ExprRange {
+ attrs: Vec::new(),
+ from: None,
+ to: hi.map(Box::new),
+ limits: limits,
+ }.into())
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for RangeLimits {
+ named!(parse -> Self, alt!(
+ // Must come before Dot2
+ punct!(..=) => { RangeLimits::Closed }
+ |
+ // Must come before Dot2
+ punct!(...) => { |dot3| RangeLimits::Closed(Token) }
+ |
+ punct!(..) => { RangeLimits::HalfOpen }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("range limit: `..`, `...` or `..=`")
+ }
+ }
+
+ impl Synom for ExprPath {
+ #[cfg(not(feature = "full"))]
+ named!(parse -> Self, do_parse!(
+ pair: qpath >>
+ (ExprPath {
+ attrs: Vec::new(),
+ qself: pair.0,
+ path: pair.1,
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ pair: qpath >>
+ (ExprPath {
+ attrs: attrs,
+ qself: pair.0,
+ path: pair.1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("path: `a::b::c`")
+ }
+ }
+
+ named!(path -> Path, do_parse!(
+ colon: option!(punct!(::)) >>
+ segments: call!(Punctuated::<_, Token![::]>::parse_separated_nonempty_with, path_segment) >>
+ cond_reduce!(segments.first().map_or(true, |seg| seg.value().ident != "dyn")) >>
+ (Path {
+ leading_colon: colon,
+ segments: segments,
+ })
+ ));
+
+ named!(path_segment -> PathSegment, alt!(
+ do_parse!(
+ ident: syn!(Ident) >>
+ colon2: punct!(::) >>
+ lt: punct!(<) >>
+ args: call!(Punctuated::parse_terminated) >>
+ gt: punct!(>) >>
+ (PathSegment {
+ ident: ident,
+ arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
+ colon2_token: Some(colon2),
+ lt_token: lt,
+ args: args,
+ gt_token: gt,
+ }),
+ })
+ )
+ |
+ mod_style_path_segment
+ ));
+
+ named!(qpath -> (Option<QSelf>, Path), alt!(
+ map!(path, |p| (None, p))
+ |
+ do_parse!(
+ lt: punct!(<) >>
+ this: syn!(Type) >>
+ path: option!(tuple!(keyword!(as), syn!(Path))) >>
+ gt: punct!(>) >>
+ colon2: punct!(::) >>
+ rest: call!(Punctuated::parse_separated_nonempty_with, path_segment) >>
+ ({
+ let (pos, as_, path) = match path {
+ Some((as_, mut path)) => {
+ let pos = path.segments.len();
+ path.segments.push_punct(colon2);
+ path.segments.extend(rest.into_pairs());
+ (pos, Some(as_), path)
+ }
+ None => {
+ (0, None, Path {
+ leading_colon: Some(colon2),
+ segments: rest,
+ })
+ }
+ };
+ (Some(QSelf {
+ lt_token: lt,
+ ty: Box::new(this),
+ position: pos,
+ as_token: as_,
+ gt_token: gt,
+ }), path)
+ })
+ )
+ |
+ map!(keyword!(self), |s| (None, s.into()))
+ ));
+
+ named!(and_field -> (Token![.], Member), tuple!(punct!(.), syn!(Member)));
+
+ named!(and_index -> (token::Bracket, Expr), brackets!(syn!(Expr)));
+
+ #[cfg(feature = "full")]
+ impl Synom for Block {
+ named!(parse -> Self, do_parse!(
+ stmts: braces!(Block::parse_within) >>
+ (Block {
+ brace_token: stmts.0,
+ stmts: stmts.1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("block: `{ .. }`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Block {
+ named!(pub parse_within -> Vec<Stmt>, do_parse!(
+ many0!(punct!(;)) >>
+ mut standalone: many0!(do_parse!(
+ stmt: syn!(Stmt) >>
+ many0!(punct!(;)) >>
+ (stmt)
+ )) >>
+ last: option!(do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ mut e: syn!(Expr) >>
+ ({
+ e.replace_attrs(attrs);
+ Stmt::Expr(e)
+ })
+ )) >>
+ (match last {
+ None => standalone,
+ Some(last) => {
+ standalone.push(last);
+ standalone
+ }
+ })
+ ));
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for Stmt {
+ named!(parse -> Self, alt!(
+ stmt_mac
+ |
+ stmt_local
+ |
+ stmt_item
+ |
+ stmt_blockexpr
+ |
+ stmt_expr
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("statement")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(stmt_mac -> Stmt, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ what: call!(Path::parse_mod_style) >>
+ bang: punct!(!) >>
+ // Only parse braces here; paren and bracket will get parsed as
+ // expression statements
+ data: braces!(syn!(TokenStream)) >>
+ semi: option!(punct!(;)) >>
+ (Stmt::Item(Item::Macro(ItemMacro {
+ attrs: attrs,
+ ident: None,
+ mac: Macro {
+ path: what,
+ bang_token: bang,
+ delimiter: MacroDelimiter::Brace(data.0),
+ tts: data.1,
+ },
+ semi_token: semi,
+ })))
+ ));
+
+ #[cfg(feature = "full")]
+ named!(stmt_local -> Stmt, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ let_: keyword!(let) >>
+ pats: call!(Punctuated::parse_separated_nonempty) >>
+ ty: option!(tuple!(punct!(:), syn!(Type))) >>
+ init: option!(tuple!(punct!(=), syn!(Expr))) >>
+ semi: punct!(;) >>
+ (Stmt::Local(Local {
+ attrs: attrs,
+ let_token: let_,
+ pats: pats,
+ ty: ty.map(|(colon, ty)| (colon, Box::new(ty))),
+ init: init.map(|(eq, expr)| (eq, Box::new(expr))),
+ semi_token: semi,
+ }))
+ ));
+
+ #[cfg(feature = "full")]
+ named!(stmt_item -> Stmt, map!(syn!(Item), |i| Stmt::Item(i)));
+
+ #[cfg(feature = "full")]
+ named!(stmt_blockexpr -> Stmt, do_parse!(
+ mut attrs: many0!(Attribute::parse_outer) >>
+ mut e: expr_nosemi >>
+ semi: option!(punct!(;)) >>
+ ({
+ attrs.extend(e.replace_attrs(Vec::new()));
+ e.replace_attrs(attrs);
+ if let Some(semi) = semi {
+ Stmt::Semi(e, semi)
+ } else {
+ Stmt::Expr(e)
+ }
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ named!(stmt_expr -> Stmt, do_parse!(
+ mut attrs: many0!(Attribute::parse_outer) >>
+ mut e: syn!(Expr) >>
+ semi: punct!(;) >>
+ ({
+ attrs.extend(e.replace_attrs(Vec::new()));
+ e.replace_attrs(attrs);
+ Stmt::Semi(e, semi)
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for Pat {
+ named!(parse -> Self, alt!(
+ syn!(PatWild) => { Pat::Wild } // must be before pat_ident
+ |
+ syn!(PatBox) => { Pat::Box } // must be before pat_ident
+ |
+ syn!(PatRange) => { Pat::Range } // must be before pat_lit
+ |
+ syn!(PatTupleStruct) => { Pat::TupleStruct } // must be before pat_ident
+ |
+ syn!(PatStruct) => { Pat::Struct } // must be before pat_ident
+ |
+ syn!(PatMacro) => { Pat::Macro } // must be before pat_ident
+ |
+ syn!(PatLit) => { Pat::Lit } // must be before pat_ident
+ |
+ syn!(PatIdent) => { Pat::Ident } // must be before pat_path
+ |
+ syn!(PatPath) => { Pat::Path }
+ |
+ syn!(PatTuple) => { Pat::Tuple }
+ |
+ syn!(PatRef) => { Pat::Ref }
+ |
+ syn!(PatSlice) => { Pat::Slice }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatWild {
+ named!(parse -> Self, map!(
+ punct!(_),
+ |u| PatWild { underscore_token: u }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("wild pattern: `_`")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatBox {
+ named!(parse -> Self, do_parse!(
+ boxed: keyword!(box) >>
+ pat: syn!(Pat) >>
+ (PatBox {
+ pat: Box::new(pat),
+ box_token: boxed,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("box pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatIdent {
+ named!(parse -> Self, do_parse!(
+ by_ref: option!(keyword!(ref)) >>
+ mutability: option!(keyword!(mut)) >>
+ name: alt!(
+ syn!(Ident)
+ |
+ keyword!(self) => { Into::into }
+ ) >>
+ not!(punct!(<)) >>
+ not!(punct!(::)) >>
+ subpat: option!(tuple!(punct!(@), syn!(Pat))) >>
+ (PatIdent {
+ by_ref: by_ref,
+ mutability: mutability,
+ ident: name,
+ subpat: subpat.map(|(at, pat)| (at, Box::new(pat))),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("pattern identifier binding")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatTupleStruct {
+ named!(parse -> Self, do_parse!(
+ path: syn!(Path) >>
+ tuple: syn!(PatTuple) >>
+ (PatTupleStruct {
+ path: path,
+ pat: tuple,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("tuple struct pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatStruct {
+ named!(parse -> Self, do_parse!(
+ path: syn!(Path) >>
+ data: braces!(do_parse!(
+ fields: call!(Punctuated::parse_terminated) >>
+ base: option!(cond!(fields.empty_or_trailing(), punct!(..))) >>
+ (fields, base)
+ )) >>
+ (PatStruct {
+ path: path,
+ fields: (data.1).0,
+ brace_token: data.0,
+ dot2_token: (data.1).1.and_then(|m| m),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("struct pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for FieldPat {
+ named!(parse -> Self, alt!(
+ do_parse!(
+ member: syn!(Member) >>
+ colon: punct!(:) >>
+ pat: syn!(Pat) >>
+ (FieldPat {
+ member: member,
+ pat: Box::new(pat),
+ attrs: Vec::new(),
+ colon_token: Some(colon),
+ })
+ )
+ |
+ do_parse!(
+ boxed: option!(keyword!(box)) >>
+ by_ref: option!(keyword!(ref)) >>
+ mutability: option!(keyword!(mut)) >>
+ ident: syn!(Ident) >>
+ ({
+ let mut pat: Pat = PatIdent {
+ by_ref: by_ref,
+ mutability: mutability,
+ ident: ident.clone(),
+ subpat: None,
+ }.into();
+ if let Some(boxed) = boxed {
+ pat = PatBox {
+ pat: Box::new(pat),
+ box_token: boxed,
+ }.into();
+ }
+ FieldPat {
+ member: Member::Named(ident),
+ pat: Box::new(pat),
+ attrs: Vec::new(),
+ colon_token: None,
+ }
+ })
+ )
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("field pattern")
+ }
+ }
+
+ impl Synom for Member {
+ named!(parse -> Self, alt!(
+ syn!(Ident) => { Member::Named }
+ |
+ syn!(Index) => { Member::Unnamed }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("field member")
+ }
+ }
+
+ impl Synom for Index {
+ named!(parse -> Self, do_parse!(
+ lit: syn!(LitInt) >>
+ ({
+ if let IntSuffix::None = lit.suffix() {
+ Index { index: lit.value() as u32, span: lit.span() }
+ } else {
+ return parse_error();
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("field index")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatPath {
+ named!(parse -> Self, map!(
+ syn!(ExprPath),
+ |p| PatPath { qself: p.qself, path: p.path }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("path pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatTuple {
+ named!(parse -> Self, do_parse!(
+ data: parens!(do_parse!(
+ front: call!(Punctuated::parse_terminated) >>
+ dotdot: option!(cond_reduce!(front.empty_or_trailing(),
+ tuple!(punct!(..), option!(punct!(,)))
+ )) >>
+ back: cond!(match dotdot {
+ Some((_, Some(_))) => true,
+ _ => false,
+ },
+ Punctuated::parse_terminated) >>
+ (front, dotdot, back)
+ )) >>
+ ({
+ let (parens, (front, dotdot, back)) = data;
+ let (dotdot, trailing) = match dotdot {
+ Some((a, b)) => (Some(a), Some(b)),
+ None => (None, None),
+ };
+ PatTuple {
+ paren_token: parens,
+ front: front,
+ dot2_token: dotdot,
+ comma_token: trailing.unwrap_or_default(),
+ back: back.unwrap_or_default(),
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("tuple pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatRef {
+ named!(parse -> Self, do_parse!(
+ and: punct!(&) >>
+ mutability: option!(keyword!(mut)) >>
+ pat: syn!(Pat) >>
+ (PatRef {
+ pat: Box::new(pat),
+ mutability: mutability,
+ and_token: and,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("reference pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatLit {
+ named!(parse -> Self, do_parse!(
+ lit: pat_lit_expr >>
+ (if let Expr::Path(_) = lit {
+ return parse_error(); // these need to be parsed by pat_path
+ } else {
+ PatLit {
+ expr: Box::new(lit),
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("literal pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatRange {
+ named!(parse -> Self, do_parse!(
+ lo: pat_lit_expr >>
+ limits: syn!(RangeLimits) >>
+ hi: pat_lit_expr >>
+ (PatRange {
+ lo: Box::new(lo),
+ hi: Box::new(hi),
+ limits: limits,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("range pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ named!(pat_lit_expr -> Expr, do_parse!(
+ neg: option!(punct!(-)) >>
+ v: alt!(
+ syn!(ExprLit) => { Expr::Lit }
+ |
+ syn!(ExprPath) => { Expr::Path }
+ ) >>
+ (if let Some(neg) = neg {
+ Expr::Unary(ExprUnary {
+ attrs: Vec::new(),
+ op: UnOp::Neg(neg),
+ expr: Box::new(v)
+ })
+ } else {
+ v
+ })
+ ));
+
+ #[cfg(feature = "full")]
+ impl Synom for PatSlice {
+ named!(parse -> Self, map!(
+ brackets!(do_parse!(
+ before: call!(Punctuated::parse_terminated) >>
+ middle: option!(do_parse!(
+ dots: punct!(..) >>
+ trailing: option!(punct!(,)) >>
+ (dots, trailing)
+ )) >>
+ after: cond!(
+ match middle {
+ Some((_, ref trailing)) => trailing.is_some(),
+ _ => false,
+ },
+ Punctuated::parse_terminated
+ ) >>
+ (before, middle, after)
+ )),
+ |(brackets, (before, middle, after))| {
+ let mut before: Punctuated<Pat, Token![,]> = before;
+ let after: Option<Punctuated<Pat, Token![,]>> = after;
+ let middle: Option<(Token![..], Option<Token![,]>)> = middle;
+ PatSlice {
+ dot2_token: middle.as_ref().map(|m| Token),
+ comma_token: middle.as_ref().and_then(|m| {
+ m.1.as_ref().map(|m| Token)
+ }),
+ bracket_token: brackets,
+ middle: middle.and_then(|_| {
+ if before.empty_or_trailing() {
+ None
+ } else {
+ Some(Box::new(before.pop().unwrap().into_value()))
+ }
+ }),
+ front: before,
+ back: after.unwrap_or_default(),
+ }
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("slice pattern")
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for PatMacro {
+ named!(parse -> Self, map!(syn!(Macro), |mac| PatMacro { mac: mac }));
+
+ fn description() -> Option<&'static str> {
+ Some("macro pattern")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ #[cfg(feature = "full")]
+ use attr::FilterAttrs;
+ use proc_macro2::{Literal, TokenStream};
+ use quote::{ToTokens, TokenStreamExt};
+
+ // If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+ // before appending it to `TokenStream`.
+ #[cfg(feature = "full")]
+ fn wrap_bare_struct(tokens: &mut TokenStream, e: &Expr) {
+ if let Expr::Struct(_) = *e {
+ token::Paren::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ });
+ } else {
+ e.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn outer_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.outer());
+ }
+
+ #[cfg(feature = "full")]
+ fn inner_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) {
+ tokens.append_all(attrs.inner());
+ }
+
+ #[cfg(not(feature = "full"))]
+ fn outer_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(not(feature = "full"))]
+ fn inner_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {}
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBox {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.box_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprInPlace {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.place.to_tokens(tokens);
+ self.arrow_token.to_tokens(tokens);
+ self.value.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprArray {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ })
+ }
+ }
+
+ impl ToTokens for ExprCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.func.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMethodCall {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.receiver.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.method.to_tokens(tokens);
+ self.turbofish.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for MethodTurbofish {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.colon2_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+ self.args.to_tokens(tokens);
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for GenericMethodArgument {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ GenericMethodArgument::Type(ref t) => t.to_tokens(tokens),
+ GenericMethodArgument::Const(ref c) => c.to_tokens(tokens),
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.elems.to_tokens(tokens);
+ // If we only have one argument, we need a trailing comma to
+ // distinguish ExprTuple from ExprParen.
+ if self.elems.len() == 1 && !self.elems.trailing_punct() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ impl ToTokens for ExprBinary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprUnary {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.op.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprLit {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.lit.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprCast {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.as_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ fn maybe_wrap_else(tokens: &mut TokenStream, else_: &Option<(Token![else], Box<Expr>)>) {
+ if let Some((ref else_token, ref else_)) = *else_ {
+ else_token.to_tokens(tokens);
+
+ // If we are not one of the valid expressions to exist in an else
+ // clause, wrap ourselves in a block.
+ match **else_ {
+ Expr::If(_) | Expr::IfLet(_) | Expr::Block(_) => {
+ else_.to_tokens(tokens);
+ }
+ _ => {
+ token::Brace::default().surround(tokens, |tokens| {
+ else_.to_tokens(tokens);
+ });
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprIf {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.if_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.then_branch.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_branch);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprIfLet {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.if_token.to_tokens(tokens);
+ self.let_token.to_tokens(tokens);
+ self.pats.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.then_branch.to_tokens(tokens);
+ maybe_wrap_else(tokens, &self.else_branch);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprWhile {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.while_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.cond);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprWhileLet {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.while_token.to_tokens(tokens);
+ self.let_token.to_tokens(tokens);
+ self.pats.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprForLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.for_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ self.in_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprLoop {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.loop_token.to_tokens(tokens);
+ self.body.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.body.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMatch {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.match_token.to_tokens(tokens);
+ wrap_bare_struct(tokens, &self.expr);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ for (i, arm) in self.arms.iter().enumerate() {
+ arm.to_tokens(tokens);
+ // Ensure that we have a comma after a non-block arm, except
+ // for the last one.
+ let is_last = i == self.arms.len() - 1;
+ if !is_last && arm_expr_requires_comma(&arm.body) && arm.comma.is_none() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ }
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAsync {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.async_token.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTryBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.try_token.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprYield {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.yield_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprClosure {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.asyncness.to_tokens(tokens);
+ self.movability.to_tokens(tokens);
+ self.capture.to_tokens(tokens);
+ self.or1_token.to_tokens(tokens);
+ for input in self.inputs.pairs() {
+ match **input.value() {
+ FnArg::Captured(ArgCaptured {
+ ref pat,
+ ty: Type::Infer(_),
+ ..
+ }) => {
+ pat.to_tokens(tokens);
+ }
+ _ => input.value().to_tokens(tokens),
+ }
+ input.punct().to_tokens(tokens);
+ }
+ self.or2_token.to_tokens(tokens);
+ self.output.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprUnsafe {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.unsafe_token.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBlock {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.label.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssign {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprAssignOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.left.to_tokens(tokens);
+ self.op.to_tokens(tokens);
+ self.right.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprField {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.base.to_tokens(tokens);
+ self.dot_token.to_tokens(tokens);
+ self.member.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Member {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ Member::Named(ref ident) => ident.to_tokens(tokens),
+ Member::Unnamed(ref index) => index.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for Index {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let mut lit = Literal::i64_unsuffixed(i64::from(self.index));
+ lit.set_span(self.span);
+ tokens.append(lit);
+ }
+ }
+
+ impl ToTokens for ExprIndex {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ self.index.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRange {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.from.to_tokens(tokens);
+ match self.limits {
+ RangeLimits::HalfOpen(ref t) => t.to_tokens(tokens),
+ RangeLimits::Closed(ref t) => t.to_tokens(tokens),
+ }
+ self.to.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ ::PathTokens(&self.qself, &self.path).to_tokens(tokens)
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprBreak {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.break_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprContinue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.continue_token.to_tokens(tokens);
+ self.label.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprReturn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.return_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.fields.to_tokens(tokens);
+ if self.rest.is_some() {
+ TokensOrDefault(&self.dot2_token).to_tokens(tokens);
+ self.rest.to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprRepeat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.bracket_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ self.len.to_tokens(tokens);
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.group_token.surround(tokens, |tokens| {
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ExprParen {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ inner_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for ExprTry {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.expr.to_tokens(tokens);
+ self.question_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ExprVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Label {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.name.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for FieldValue {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.member.to_tokens(tokens);
+ if let Some(ref colon_token) = self.colon_token {
+ colon_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Arm {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.leading_vert.to_tokens(tokens);
+ self.pats.to_tokens(tokens);
+ if let Some((ref if_token, ref guard)) = self.guard {
+ if_token.to_tokens(tokens);
+ guard.to_tokens(tokens);
+ }
+ self.fat_arrow_token.to_tokens(tokens);
+ self.body.to_tokens(tokens);
+ self.comma.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatWild {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.underscore_token.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatIdent {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.by_ref.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((ref at_token, ref subpat)) = self.subpat {
+ at_token.to_tokens(tokens);
+ subpat.to_tokens(tokens);
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ self.fields.to_tokens(tokens);
+ // NOTE: We need a comma before the dot2 token if it is present.
+ if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ self.dot2_token.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatTupleStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatPath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ ::PathTokens(&self.qself, &self.path).to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.front.to_tokens(tokens);
+ if let Some(ref dot2_token) = self.dot2_token {
+ if !self.front.empty_or_trailing() {
+ // Ensure there is a comma before the .. token.
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ dot2_token.to_tokens(tokens);
+ self.comma_token.to_tokens(tokens);
+ if self.comma_token.is_none() && !self.back.is_empty() {
+ // Ensure there is a comma after the .. token.
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ }
+ self.back.to_tokens(tokens);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatBox {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.box_token.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatRef {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.and_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatLit {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.expr.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatRange {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lo.to_tokens(tokens);
+ match self.limits {
+ RangeLimits::HalfOpen(ref t) => t.to_tokens(tokens),
+ RangeLimits::Closed(ref t) => Token.to_tokens(tokens),
+ }
+ self.hi.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatSlice {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ // XXX: This is a mess, and it will be so easy to screw it up. How
+ // do we make this correct itself better?
+ self.bracket_token.surround(tokens, |tokens| {
+ self.front.to_tokens(tokens);
+
+ // If we need a comma before the middle or standalone .. token,
+ // then make sure it's present.
+ if !self.front.empty_or_trailing()
+ && (self.middle.is_some() || self.dot2_token.is_some())
+ {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+
+ // If we have an identifier, we always need a .. token.
+ if self.middle.is_some() {
+ self.middle.to_tokens(tokens);
+ TokensOrDefault(&self.dot2_token).to_tokens(tokens);
+ } else if self.dot2_token.is_some() {
+ self.dot2_token.to_tokens(tokens);
+ }
+
+ // Make sure we have a comma before the back half.
+ if !self.back.is_empty() {
+ TokensOrDefault(&self.comma_token).to_tokens(tokens);
+ self.back.to_tokens(tokens);
+ } else {
+ self.comma_token.to_tokens(tokens);
+ }
+ })
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for PatVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for FieldPat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(ref colon_token) = self.colon_token {
+ self.member.to_tokens(tokens);
+ colon_token.to_tokens(tokens);
+ }
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Block {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(&self.stmts);
+ });
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Stmt {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ Stmt::Local(ref local) => local.to_tokens(tokens),
+ Stmt::Item(ref item) => item.to_tokens(tokens),
+ Stmt::Expr(ref expr) => expr.to_tokens(tokens),
+ Stmt::Semi(ref expr, ref semi) => {
+ expr.to_tokens(tokens);
+ semi.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ #[cfg(feature = "full")]
+ impl ToTokens for Local {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ outer_attrs_to_tokens(&self.attrs, tokens);
+ self.let_token.to_tokens(tokens);
+ self.pats.to_tokens(tokens);
+ if let Some((ref colon_token, ref ty)) = self.ty {
+ colon_token.to_tokens(tokens);
+ ty.to_tokens(tokens);
+ }
+ if let Some((ref eq_token, ref init)) = self.init {
+ eq_token.to_tokens(tokens);
+ init.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..9b5b11f
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,123 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+
+ast_struct! {
+ /// A complete file of Rust source code.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Example
+ ///
+ /// Parse a Rust source file into a `syn::File` and print out a debug
+ /// representation of the syntax tree.
+ ///
+ /// ```
+ /// extern crate syn;
+ ///
+ /// use std::env;
+ /// use std::fs::File;
+ /// use std::io::Read;
+ /// use std::process;
+ ///
+ /// fn main() {
+ /// # }
+ /// #
+ /// # fn fake_main() {
+ /// let mut args = env::args();
+ /// let _ = args.next(); // executable name
+ ///
+ /// let filename = match (args.next(), args.next()) {
+ /// (Some(filename), None) => filename,
+ /// _ => {
+ /// eprintln!("Usage: dump-syntax path/to/filename.rs");
+ /// process::exit(1);
+ /// }
+ /// };
+ ///
+ /// let mut file = File::open(&filename).expect("Unable to open file");
+ ///
+ /// let mut src = String::new();
+ /// file.read_to_string(&mut src).expect("Unable to read file");
+ ///
+ /// let syntax = syn::parse_file(&src).expect("Unable to parse file");
+ /// println!("{:#?}", syntax);
+ /// }
+ /// ```
+ ///
+ /// Running with its own source code as input, this program prints output
+ /// that begins with:
+ ///
+ /// ```text
+ /// File {
+ /// shebang: None,
+ /// attrs: [],
+ /// items: [
+ /// ExternCrate(
+ /// ItemExternCrate {
+ /// attrs: [],
+ /// vis: Inherited,
+ /// extern_token: Extern,
+ /// crate_token: Crate,
+ /// ident: Ident {
+ /// term: Term(
+ /// "syn"
+ /// ),
+ /// span: Span
+ /// },
+ /// rename: None,
+ /// semi_token: Semi
+ /// }
+ /// ),
+ /// ...
+ /// ```
+ pub struct File {
+ pub shebang: Option<String>,
+ pub attrs: Vec<Attribute>,
+ pub items: Vec<Item>,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use synom::Synom;
+
+ impl Synom for File {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_inner) >>
+ items: many0!(Item::parse) >>
+ (File {
+ shebang: None,
+ attrs: attrs,
+ items: items,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("crate")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for File {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ }
+ }
+}
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
new file mode 100644
index 0000000..fe1088a
--- /dev/null
+++ b/src/gen/fold.rs
@@ -0,0 +1,3064 @@
+// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT
+
+#![allow(unreachable_code)]
+#![cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
+#[cfg(any(feature = "full", feature = "derive"))]
+use gen::helper::fold::*;
+use proc_macro2::Span;
+#[cfg(any(feature = "full", feature = "derive"))]
+use token::{Brace, Bracket, Group, Paren};
+use *;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+#[doc = r" Syntax tree traversal to transform the nodes of an owned syntax tree."]
+#[doc = r""]
+#[doc = r" See the [module documentation] for details."]
+#[doc = r""]
+#[doc = r" [module documentation]: index.html"]
+#[doc = r""]
+#[doc = r#" *This trait is available if Syn is built with the `"fold"` feature.*"#]
+pub trait Fold {
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_abi(&mut self, i: Abi) -> Abi {
+ fold_abi(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_angle_bracketed_generic_arguments(
+ &mut self,
+ i: AngleBracketedGenericArguments,
+ ) -> AngleBracketedGenericArguments {
+ fold_angle_bracketed_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_arg_captured(&mut self, i: ArgCaptured) -> ArgCaptured {
+ fold_arg_captured(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_arg_self(&mut self, i: ArgSelf) -> ArgSelf {
+ fold_arg_self(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_arg_self_ref(&mut self, i: ArgSelfRef) -> ArgSelfRef {
+ fold_arg_self_ref(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_arm(&mut self, i: Arm) -> Arm {
+ fold_arm(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_attr_style(&mut self, i: AttrStyle) -> AttrStyle {
+ fold_attr_style(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_attribute(&mut self, i: Attribute) -> Attribute {
+ fold_attribute(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_bare_fn_arg(&mut self, i: BareFnArg) -> BareFnArg {
+ fold_bare_fn_arg(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_bare_fn_arg_name(&mut self, i: BareFnArgName) -> BareFnArgName {
+ fold_bare_fn_arg_name(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_bin_op(&mut self, i: BinOp) -> BinOp {
+ fold_bin_op(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_binding(&mut self, i: Binding) -> Binding {
+ fold_binding(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_block(&mut self, i: Block) -> Block {
+ fold_block(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_bound_lifetimes(&mut self, i: BoundLifetimes) -> BoundLifetimes {
+ fold_bound_lifetimes(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_const_param(&mut self, i: ConstParam) -> ConstParam {
+ fold_const_param(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data(&mut self, i: Data) -> Data {
+ fold_data(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_enum(&mut self, i: DataEnum) -> DataEnum {
+ fold_data_enum(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_struct(&mut self, i: DataStruct) -> DataStruct {
+ fold_data_struct(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_data_union(&mut self, i: DataUnion) -> DataUnion {
+ fold_data_union(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn fold_derive_input(&mut self, i: DeriveInput) -> DeriveInput {
+ fold_derive_input(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr(&mut self, i: Expr) -> Expr {
+ fold_expr(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_array(&mut self, i: ExprArray) -> ExprArray {
+ fold_expr_array(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_assign(&mut self, i: ExprAssign) -> ExprAssign {
+ fold_expr_assign(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_assign_op(&mut self, i: ExprAssignOp) -> ExprAssignOp {
+ fold_expr_assign_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_async(&mut self, i: ExprAsync) -> ExprAsync {
+ fold_expr_async(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_binary(&mut self, i: ExprBinary) -> ExprBinary {
+ fold_expr_binary(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_block(&mut self, i: ExprBlock) -> ExprBlock {
+ fold_expr_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_box(&mut self, i: ExprBox) -> ExprBox {
+ fold_expr_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_break(&mut self, i: ExprBreak) -> ExprBreak {
+ fold_expr_break(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_call(&mut self, i: ExprCall) -> ExprCall {
+ fold_expr_call(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_cast(&mut self, i: ExprCast) -> ExprCast {
+ fold_expr_cast(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_closure(&mut self, i: ExprClosure) -> ExprClosure {
+ fold_expr_closure(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_continue(&mut self, i: ExprContinue) -> ExprContinue {
+ fold_expr_continue(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_field(&mut self, i: ExprField) -> ExprField {
+ fold_expr_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_for_loop(&mut self, i: ExprForLoop) -> ExprForLoop {
+ fold_expr_for_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_group(&mut self, i: ExprGroup) -> ExprGroup {
+ fold_expr_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_if(&mut self, i: ExprIf) -> ExprIf {
+ fold_expr_if(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_if_let(&mut self, i: ExprIfLet) -> ExprIfLet {
+ fold_expr_if_let(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_in_place(&mut self, i: ExprInPlace) -> ExprInPlace {
+ fold_expr_in_place(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_index(&mut self, i: ExprIndex) -> ExprIndex {
+ fold_expr_index(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_lit(&mut self, i: ExprLit) -> ExprLit {
+ fold_expr_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_loop(&mut self, i: ExprLoop) -> ExprLoop {
+ fold_expr_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_macro(&mut self, i: ExprMacro) -> ExprMacro {
+ fold_expr_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_match(&mut self, i: ExprMatch) -> ExprMatch {
+ fold_expr_match(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_method_call(&mut self, i: ExprMethodCall) -> ExprMethodCall {
+ fold_expr_method_call(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_paren(&mut self, i: ExprParen) -> ExprParen {
+ fold_expr_paren(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_path(&mut self, i: ExprPath) -> ExprPath {
+ fold_expr_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_range(&mut self, i: ExprRange) -> ExprRange {
+ fold_expr_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_reference(&mut self, i: ExprReference) -> ExprReference {
+ fold_expr_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_repeat(&mut self, i: ExprRepeat) -> ExprRepeat {
+ fold_expr_repeat(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_return(&mut self, i: ExprReturn) -> ExprReturn {
+ fold_expr_return(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_struct(&mut self, i: ExprStruct) -> ExprStruct {
+ fold_expr_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_try(&mut self, i: ExprTry) -> ExprTry {
+ fold_expr_try(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_try_block(&mut self, i: ExprTryBlock) -> ExprTryBlock {
+ fold_expr_try_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_tuple(&mut self, i: ExprTuple) -> ExprTuple {
+ fold_expr_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_type(&mut self, i: ExprType) -> ExprType {
+ fold_expr_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_unary(&mut self, i: ExprUnary) -> ExprUnary {
+ fold_expr_unary(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_unsafe(&mut self, i: ExprUnsafe) -> ExprUnsafe {
+ fold_expr_unsafe(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_verbatim(&mut self, i: ExprVerbatim) -> ExprVerbatim {
+ fold_expr_verbatim(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_while(&mut self, i: ExprWhile) -> ExprWhile {
+ fold_expr_while(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_while_let(&mut self, i: ExprWhileLet) -> ExprWhileLet {
+ fold_expr_while_let(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_expr_yield(&mut self, i: ExprYield) -> ExprYield {
+ fold_expr_yield(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_field(&mut self, i: Field) -> Field {
+ fold_field(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_field_pat(&mut self, i: FieldPat) -> FieldPat {
+ fold_field_pat(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_field_value(&mut self, i: FieldValue) -> FieldValue {
+ fold_field_value(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_fields(&mut self, i: Fields) -> Fields {
+ fold_fields(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_fields_named(&mut self, i: FieldsNamed) -> FieldsNamed {
+ fold_fields_named(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_fields_unnamed(&mut self, i: FieldsUnnamed) -> FieldsUnnamed {
+ fold_fields_unnamed(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_file(&mut self, i: File) -> File {
+ fold_file(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_fn_arg(&mut self, i: FnArg) -> FnArg {
+ fold_fn_arg(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_fn_decl(&mut self, i: FnDecl) -> FnDecl {
+ fold_fn_decl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item(&mut self, i: ForeignItem) -> ForeignItem {
+ fold_foreign_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_fn(&mut self, i: ForeignItemFn) -> ForeignItemFn {
+ fold_foreign_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_macro(&mut self, i: ForeignItemMacro) -> ForeignItemMacro {
+ fold_foreign_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_static(&mut self, i: ForeignItemStatic) -> ForeignItemStatic {
+ fold_foreign_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_type(&mut self, i: ForeignItemType) -> ForeignItemType {
+ fold_foreign_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_foreign_item_verbatim(&mut self, i: ForeignItemVerbatim) -> ForeignItemVerbatim {
+ fold_foreign_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_generic_argument(&mut self, i: GenericArgument) -> GenericArgument {
+ fold_generic_argument(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_generic_method_argument(&mut self, i: GenericMethodArgument) -> GenericMethodArgument {
+ fold_generic_method_argument(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_generic_param(&mut self, i: GenericParam) -> GenericParam {
+ fold_generic_param(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_generics(&mut self, i: Generics) -> Generics {
+ fold_generics(self, i)
+ }
+ fn fold_ident(&mut self, i: Ident) -> Ident {
+ fold_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem {
+ fold_impl_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_const(&mut self, i: ImplItemConst) -> ImplItemConst {
+ fold_impl_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_existential(&mut self, i: ImplItemExistential) -> ImplItemExistential {
+ fold_impl_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_macro(&mut self, i: ImplItemMacro) -> ImplItemMacro {
+ fold_impl_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_method(&mut self, i: ImplItemMethod) -> ImplItemMethod {
+ fold_impl_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_type(&mut self, i: ImplItemType) -> ImplItemType {
+ fold_impl_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_impl_item_verbatim(&mut self, i: ImplItemVerbatim) -> ImplItemVerbatim {
+ fold_impl_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_index(&mut self, i: Index) -> Index {
+ fold_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item(&mut self, i: Item) -> Item {
+ fold_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_const(&mut self, i: ItemConst) -> ItemConst {
+ fold_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_enum(&mut self, i: ItemEnum) -> ItemEnum {
+ fold_item_enum(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_existential(&mut self, i: ItemExistential) -> ItemExistential {
+ fold_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_extern_crate(&mut self, i: ItemExternCrate) -> ItemExternCrate {
+ fold_item_extern_crate(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_fn(&mut self, i: ItemFn) -> ItemFn {
+ fold_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_foreign_mod(&mut self, i: ItemForeignMod) -> ItemForeignMod {
+ fold_item_foreign_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_impl(&mut self, i: ItemImpl) -> ItemImpl {
+ fold_item_impl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_macro(&mut self, i: ItemMacro) -> ItemMacro {
+ fold_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_macro2(&mut self, i: ItemMacro2) -> ItemMacro2 {
+ fold_item_macro2(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_mod(&mut self, i: ItemMod) -> ItemMod {
+ fold_item_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_static(&mut self, i: ItemStatic) -> ItemStatic {
+ fold_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_struct(&mut self, i: ItemStruct) -> ItemStruct {
+ fold_item_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_trait(&mut self, i: ItemTrait) -> ItemTrait {
+ fold_item_trait(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_type(&mut self, i: ItemType) -> ItemType {
+ fold_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_union(&mut self, i: ItemUnion) -> ItemUnion {
+ fold_item_union(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_use(&mut self, i: ItemUse) -> ItemUse {
+ fold_item_use(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_item_verbatim(&mut self, i: ItemVerbatim) -> ItemVerbatim {
+ fold_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_label(&mut self, i: Label) -> Label {
+ fold_label(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lifetime(&mut self, i: Lifetime) -> Lifetime {
+ fold_lifetime(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lifetime_def(&mut self, i: LifetimeDef) -> LifetimeDef {
+ fold_lifetime_def(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit(&mut self, i: Lit) -> Lit {
+ fold_lit(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_bool(&mut self, i: LitBool) -> LitBool {
+ fold_lit_bool(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_byte(&mut self, i: LitByte) -> LitByte {
+ fold_lit_byte(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_byte_str(&mut self, i: LitByteStr) -> LitByteStr {
+ fold_lit_byte_str(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_char(&mut self, i: LitChar) -> LitChar {
+ fold_lit_char(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_float(&mut self, i: LitFloat) -> LitFloat {
+ fold_lit_float(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_int(&mut self, i: LitInt) -> LitInt {
+ fold_lit_int(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_str(&mut self, i: LitStr) -> LitStr {
+ fold_lit_str(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_lit_verbatim(&mut self, i: LitVerbatim) -> LitVerbatim {
+ fold_lit_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_local(&mut self, i: Local) -> Local {
+ fold_local(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_macro(&mut self, i: Macro) -> Macro {
+ fold_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_macro_delimiter(&mut self, i: MacroDelimiter) -> MacroDelimiter {
+ fold_macro_delimiter(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_member(&mut self, i: Member) -> Member {
+ fold_member(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_meta(&mut self, i: Meta) -> Meta {
+ fold_meta(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_meta_list(&mut self, i: MetaList) -> MetaList {
+ fold_meta_list(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_meta_name_value(&mut self, i: MetaNameValue) -> MetaNameValue {
+ fold_meta_name_value(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_method_sig(&mut self, i: MethodSig) -> MethodSig {
+ fold_method_sig(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_method_turbofish(&mut self, i: MethodTurbofish) -> MethodTurbofish {
+ fold_method_turbofish(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_nested_meta(&mut self, i: NestedMeta) -> NestedMeta {
+ fold_nested_meta(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_parenthesized_generic_arguments(
+ &mut self,
+ i: ParenthesizedGenericArguments,
+ ) -> ParenthesizedGenericArguments {
+ fold_parenthesized_generic_arguments(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat(&mut self, i: Pat) -> Pat {
+ fold_pat(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_box(&mut self, i: PatBox) -> PatBox {
+ fold_pat_box(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_ident(&mut self, i: PatIdent) -> PatIdent {
+ fold_pat_ident(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_lit(&mut self, i: PatLit) -> PatLit {
+ fold_pat_lit(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_macro(&mut self, i: PatMacro) -> PatMacro {
+ fold_pat_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_path(&mut self, i: PatPath) -> PatPath {
+ fold_pat_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_range(&mut self, i: PatRange) -> PatRange {
+ fold_pat_range(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_ref(&mut self, i: PatRef) -> PatRef {
+ fold_pat_ref(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_slice(&mut self, i: PatSlice) -> PatSlice {
+ fold_pat_slice(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_struct(&mut self, i: PatStruct) -> PatStruct {
+ fold_pat_struct(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_tuple(&mut self, i: PatTuple) -> PatTuple {
+ fold_pat_tuple(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_tuple_struct(&mut self, i: PatTupleStruct) -> PatTupleStruct {
+ fold_pat_tuple_struct(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_verbatim(&mut self, i: PatVerbatim) -> PatVerbatim {
+ fold_pat_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_pat_wild(&mut self, i: PatWild) -> PatWild {
+ fold_pat_wild(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_path(&mut self, i: Path) -> Path {
+ fold_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_path_arguments(&mut self, i: PathArguments) -> PathArguments {
+ fold_path_arguments(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_path_segment(&mut self, i: PathSegment) -> PathSegment {
+ fold_path_segment(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_predicate_eq(&mut self, i: PredicateEq) -> PredicateEq {
+ fold_predicate_eq(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_predicate_lifetime(&mut self, i: PredicateLifetime) -> PredicateLifetime {
+ fold_predicate_lifetime(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_predicate_type(&mut self, i: PredicateType) -> PredicateType {
+ fold_predicate_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_qself(&mut self, i: QSelf) -> QSelf {
+ fold_qself(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_range_limits(&mut self, i: RangeLimits) -> RangeLimits {
+ fold_range_limits(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_return_type(&mut self, i: ReturnType) -> ReturnType {
+ fold_return_type(self, i)
+ }
+ fn fold_span(&mut self, i: Span) -> Span {
+ fold_span(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn fold_stmt(&mut self, i: Stmt) -> Stmt {
+ fold_stmt(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_trait_bound(&mut self, i: TraitBound) -> TraitBound {
+ fold_trait_bound(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_trait_bound_modifier(&mut self, i: TraitBoundModifier) -> TraitBoundModifier {
+ fold_trait_bound_modifier(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem {
+ fold_trait_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_const(&mut self, i: TraitItemConst) -> TraitItemConst {
+ fold_trait_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_existential(&mut self, i: TraitItemExistential) -> TraitItemExistential {
+ fold_trait_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_macro(&mut self, i: TraitItemMacro) -> TraitItemMacro {
+ fold_trait_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_method(&mut self, i: TraitItemMethod) -> TraitItemMethod {
+ fold_trait_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_type(&mut self, i: TraitItemType) -> TraitItemType {
+ fold_trait_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_trait_item_verbatim(&mut self, i: TraitItemVerbatim) -> TraitItemVerbatim {
+ fold_trait_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type(&mut self, i: Type) -> Type {
+ fold_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_array(&mut self, i: TypeArray) -> TypeArray {
+ fold_type_array(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_bare_fn(&mut self, i: TypeBareFn) -> TypeBareFn {
+ fold_type_bare_fn(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_group(&mut self, i: TypeGroup) -> TypeGroup {
+ fold_type_group(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_impl_trait(&mut self, i: TypeImplTrait) -> TypeImplTrait {
+ fold_type_impl_trait(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_infer(&mut self, i: TypeInfer) -> TypeInfer {
+ fold_type_infer(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_macro(&mut self, i: TypeMacro) -> TypeMacro {
+ fold_type_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_never(&mut self, i: TypeNever) -> TypeNever {
+ fold_type_never(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_param(&mut self, i: TypeParam) -> TypeParam {
+ fold_type_param(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_param_bound(&mut self, i: TypeParamBound) -> TypeParamBound {
+ fold_type_param_bound(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_paren(&mut self, i: TypeParen) -> TypeParen {
+ fold_type_paren(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_path(&mut self, i: TypePath) -> TypePath {
+ fold_type_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_ptr(&mut self, i: TypePtr) -> TypePtr {
+ fold_type_ptr(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_reference(&mut self, i: TypeReference) -> TypeReference {
+ fold_type_reference(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_slice(&mut self, i: TypeSlice) -> TypeSlice {
+ fold_type_slice(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_trait_object(&mut self, i: TypeTraitObject) -> TypeTraitObject {
+ fold_type_trait_object(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_tuple(&mut self, i: TypeTuple) -> TypeTuple {
+ fold_type_tuple(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_type_verbatim(&mut self, i: TypeVerbatim) -> TypeVerbatim {
+ fold_type_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_un_op(&mut self, i: UnOp) -> UnOp {
+ fold_un_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_glob(&mut self, i: UseGlob) -> UseGlob {
+ fold_use_glob(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_group(&mut self, i: UseGroup) -> UseGroup {
+ fold_use_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_name(&mut self, i: UseName) -> UseName {
+ fold_use_name(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_path(&mut self, i: UsePath) -> UsePath {
+ fold_use_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_rename(&mut self, i: UseRename) -> UseRename {
+ fold_use_rename(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn fold_use_tree(&mut self, i: UseTree) -> UseTree {
+ fold_use_tree(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_variant(&mut self, i: Variant) -> Variant {
+ fold_variant(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_vis_crate(&mut self, i: VisCrate) -> VisCrate {
+ fold_vis_crate(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_vis_public(&mut self, i: VisPublic) -> VisPublic {
+ fold_vis_public(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_vis_restricted(&mut self, i: VisRestricted) -> VisRestricted {
+ fold_vis_restricted(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_visibility(&mut self, i: Visibility) -> Visibility {
+ fold_visibility(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_where_clause(&mut self, i: WhereClause) -> WhereClause {
+ fold_where_clause(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn fold_where_predicate(&mut self, i: WherePredicate) -> WherePredicate {
+ fold_where_predicate(self, i)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! fold_span_only {
+ ($f:ident : $t:ident) => {
+ pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t {
+ let span = _visitor.fold_span(_i.span());
+ _i.set_span(span);
+ _i
+ }
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_byte: LitByte);
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_byte_str: LitByteStr);
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_char: LitChar);
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_float: LitFloat);
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_int: LitInt);
+#[cfg(any(feature = "full", feature = "derive"))]
+fold_span_only!(fold_lit_str: LitStr);
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_abi<V: Fold + ?Sized>(_visitor: &mut V, _i: Abi) -> Abi {
+ Abi {
+ extern_token: Token),
+ name: (_i.name).map(|it| _visitor.fold_lit_str(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_angle_bracketed_generic_arguments<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: AngleBracketedGenericArguments,
+) -> AngleBracketedGenericArguments {
+ AngleBracketedGenericArguments {
+ colon2_token: (_i.colon2_token)
+ .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))),
+ lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)),
+ args: FoldHelper::lift(_i.args, |it| _visitor.fold_generic_argument(it)),
+ gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_arg_captured<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgCaptured) -> ArgCaptured {
+ ArgCaptured {
+ pat: _visitor.fold_pat(_i.pat),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_arg_self<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgSelf) -> ArgSelf {
+ ArgSelf {
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ self_token: Token),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_arg_self_ref<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgSelfRef) -> ArgSelfRef {
+ ArgSelfRef {
+ and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)),
+ lifetime: (_i.lifetime).map(|it| _visitor.fold_lifetime(it)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ self_token: Token),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_arm<V: Fold + ?Sized>(_visitor: &mut V, _i: Arm) -> Arm {
+ Arm {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ leading_vert: (_i.leading_vert).map(|it| Token ! [ | ](tokens_helper(_visitor, &it.spans))),
+ pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
+ guard: (_i.guard).map(|it| {
+ (
+ Token ! [ if ](tokens_helper(_visitor, &(it).0.span)),
+ Box::new(_visitor.fold_expr(*(it).1)),
+ )
+ }),
+ fat_arrow_token: Token ! [ => ](tokens_helper(_visitor, &_i.fat_arrow_token.spans)),
+ body: Box::new(_visitor.fold_expr(*_i.body)),
+ comma: (_i.comma).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_attr_style<V: Fold + ?Sized>(_visitor: &mut V, _i: AttrStyle) -> AttrStyle {
+ match _i {
+ AttrStyle::Outer => AttrStyle::Outer,
+ AttrStyle::Inner(_binding_0) => {
+ AttrStyle::Inner(Token))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_attribute<V: Fold + ?Sized>(_visitor: &mut V, _i: Attribute) -> Attribute {
+ Attribute {
+ pound_token: Token ! [ # ](tokens_helper(_visitor, &_i.pound_token.spans)),
+ style: _visitor.fold_attr_style(_i.style),
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ path: _visitor.fold_path(_i.path),
+ tts: _i.tts,
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_bare_fn_arg<V: Fold + ?Sized>(_visitor: &mut V, _i: BareFnArg) -> BareFnArg {
+ BareFnArg {
+ name: (_i.name).map(|it| {
+ (
+ _visitor.fold_bare_fn_arg_name((it).0),
+ Token ! [ : ](tokens_helper(_visitor, &(it).1.spans)),
+ )
+ }),
+ ty: _visitor.fold_type(_i.ty),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_bare_fn_arg_name<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: BareFnArgName,
+) -> BareFnArgName {
+ match _i {
+ BareFnArgName::Named(_binding_0) => BareFnArgName::Named(_visitor.fold_ident(_binding_0)),
+ BareFnArgName::Wild(_binding_0) => {
+ BareFnArgName::Wild(Token))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_bin_op<V: Fold + ?Sized>(_visitor: &mut V, _i: BinOp) -> BinOp {
+ match _i {
+ BinOp::Add(_binding_0) => {
+ BinOp::Add(Token ! [ + ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Sub(_binding_0) => {
+ BinOp::Sub(Token ! [ - ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Mul(_binding_0) => {
+ BinOp::Mul(Token ! [ * ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Div(_binding_0) => {
+ BinOp::Div(Token ! [ / ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Rem(_binding_0) => {
+ BinOp::Rem(Token ! [ % ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::And(_binding_0) => {
+ BinOp::And(Token ! [ && ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Or(_binding_0) => {
+ BinOp::Or(Token ! [ || ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitXor(_binding_0) => {
+ BinOp::BitXor(Token ! [ ^ ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitAnd(_binding_0) => {
+ BinOp::BitAnd(Token ! [ & ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitOr(_binding_0) => {
+ BinOp::BitOr(Token ! [ | ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Shl(_binding_0) => {
+ BinOp::Shl(Token ! [ << ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Shr(_binding_0) => {
+ BinOp::Shr(Token ! [ >> ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Eq(_binding_0) => {
+ BinOp::Eq(Token ! [ == ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Lt(_binding_0) => {
+ BinOp::Lt(Token ! [ < ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Le(_binding_0) => {
+ BinOp::Le(Token ! [ <= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Ne(_binding_0) => {
+ BinOp::Ne(Token ! [ != ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Ge(_binding_0) => {
+ BinOp::Ge(Token ! [ >= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::Gt(_binding_0) => {
+ BinOp::Gt(Token ! [ > ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::AddEq(_binding_0) => {
+ BinOp::AddEq(Token ! [ += ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::SubEq(_binding_0) => {
+ BinOp::SubEq(Token ! [ -= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::MulEq(_binding_0) => {
+ BinOp::MulEq(Token ! [ *= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::DivEq(_binding_0) => {
+ BinOp::DivEq(Token ! [ /= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::RemEq(_binding_0) => {
+ BinOp::RemEq(Token ! [ %= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitXorEq(_binding_0) => {
+ BinOp::BitXorEq(Token ! [ ^= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitAndEq(_binding_0) => {
+ BinOp::BitAndEq(Token ! [ &= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::BitOrEq(_binding_0) => {
+ BinOp::BitOrEq(Token ! [ |= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::ShlEq(_binding_0) => {
+ BinOp::ShlEq(Token ! [ <<= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ BinOp::ShrEq(_binding_0) => {
+ BinOp::ShrEq(Token ! [ >>= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_binding<V: Fold + ?Sized>(_visitor: &mut V, _i: Binding) -> Binding {
+ Binding {
+ ident: _visitor.fold_ident(_i.ident),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_block<V: Fold + ?Sized>(_visitor: &mut V, _i: Block) -> Block {
+ Block {
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ stmts: FoldHelper::lift(_i.stmts, |it| _visitor.fold_stmt(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_bound_lifetimes<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: BoundLifetimes,
+) -> BoundLifetimes {
+ BoundLifetimes {
+ for_token: Token ! [ for ](tokens_helper(_visitor, &_i.for_token.span)),
+ lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)),
+ lifetimes: FoldHelper::lift(_i.lifetimes, |it| _visitor.fold_lifetime_def(it)),
+ gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_const_param<V: Fold + ?Sized>(_visitor: &mut V, _i: ConstParam) -> ConstParam {
+ ConstParam {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ const_token: Token ! [ const ](tokens_helper(_visitor, &_i.const_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ eq_token: (_i.eq_token).map(|it| Token ! [ = ](tokens_helper(_visitor, &it.spans))),
+ default: (_i.default).map(|it| _visitor.fold_expr(it)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data<V: Fold + ?Sized>(_visitor: &mut V, _i: Data) -> Data {
+ match _i {
+ Data::Struct(_binding_0) => Data::Struct(_visitor.fold_data_struct(_binding_0)),
+ Data::Enum(_binding_0) => Data::Enum(_visitor.fold_data_enum(_binding_0)),
+ Data::Union(_binding_0) => Data::Union(_visitor.fold_data_union(_binding_0)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_enum<V: Fold + ?Sized>(_visitor: &mut V, _i: DataEnum) -> DataEnum {
+ DataEnum {
+ enum_token: Token ! [ enum ](tokens_helper(_visitor, &_i.enum_token.span)),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ variants: FoldHelper::lift(_i.variants, |it| _visitor.fold_variant(it)),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: DataStruct) -> DataStruct {
+ DataStruct {
+ struct_token: Token ! [ struct ](tokens_helper(_visitor, &_i.struct_token.span)),
+ fields: _visitor.fold_fields(_i.fields),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_data_union<V: Fold + ?Sized>(_visitor: &mut V, _i: DataUnion) -> DataUnion {
+ DataUnion {
+ union_token: Token),
+ fields: _visitor.fold_fields_named(_i.fields),
+ }
+}
+#[cfg(feature = "derive")]
+pub fn fold_derive_input<V: Fold + ?Sized>(_visitor: &mut V, _i: DeriveInput) -> DeriveInput {
+ DeriveInput {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ data: _visitor.fold_data(_i.data),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr<V: Fold + ?Sized>(_visitor: &mut V, _i: Expr) -> Expr {
+ match _i {
+ Expr::Box(_binding_0) => Expr::Box(full!(_visitor.fold_expr_box(_binding_0))),
+ Expr::InPlace(_binding_0) => Expr::InPlace(full!(_visitor.fold_expr_in_place(_binding_0))),
+ Expr::Array(_binding_0) => Expr::Array(full!(_visitor.fold_expr_array(_binding_0))),
+ Expr::Call(_binding_0) => Expr::Call(_visitor.fold_expr_call(_binding_0)),
+ Expr::MethodCall(_binding_0) => {
+ Expr::MethodCall(full!(_visitor.fold_expr_method_call(_binding_0)))
+ }
+ Expr::Tuple(_binding_0) => Expr::Tuple(full!(_visitor.fold_expr_tuple(_binding_0))),
+ Expr::Binary(_binding_0) => Expr::Binary(_visitor.fold_expr_binary(_binding_0)),
+ Expr::Unary(_binding_0) => Expr::Unary(_visitor.fold_expr_unary(_binding_0)),
+ Expr::Lit(_binding_0) => Expr::Lit(_visitor.fold_expr_lit(_binding_0)),
+ Expr::Cast(_binding_0) => Expr::Cast(_visitor.fold_expr_cast(_binding_0)),
+ Expr::Type(_binding_0) => Expr::Type(full!(_visitor.fold_expr_type(_binding_0))),
+ Expr::If(_binding_0) => Expr::If(full!(_visitor.fold_expr_if(_binding_0))),
+ Expr::IfLet(_binding_0) => Expr::IfLet(full!(_visitor.fold_expr_if_let(_binding_0))),
+ Expr::While(_binding_0) => Expr::While(full!(_visitor.fold_expr_while(_binding_0))),
+ Expr::WhileLet(_binding_0) => {
+ Expr::WhileLet(full!(_visitor.fold_expr_while_let(_binding_0)))
+ }
+ Expr::ForLoop(_binding_0) => Expr::ForLoop(full!(_visitor.fold_expr_for_loop(_binding_0))),
+ Expr::Loop(_binding_0) => Expr::Loop(full!(_visitor.fold_expr_loop(_binding_0))),
+ Expr::Match(_binding_0) => Expr::Match(full!(_visitor.fold_expr_match(_binding_0))),
+ Expr::Closure(_binding_0) => Expr::Closure(full!(_visitor.fold_expr_closure(_binding_0))),
+ Expr::Unsafe(_binding_0) => Expr::Unsafe(full!(_visitor.fold_expr_unsafe(_binding_0))),
+ Expr::Block(_binding_0) => Expr::Block(full!(_visitor.fold_expr_block(_binding_0))),
+ Expr::Assign(_binding_0) => Expr::Assign(full!(_visitor.fold_expr_assign(_binding_0))),
+ Expr::AssignOp(_binding_0) => {
+ Expr::AssignOp(full!(_visitor.fold_expr_assign_op(_binding_0)))
+ }
+ Expr::Field(_binding_0) => Expr::Field(_visitor.fold_expr_field(_binding_0)),
+ Expr::Index(_binding_0) => Expr::Index(_visitor.fold_expr_index(_binding_0)),
+ Expr::Range(_binding_0) => Expr::Range(full!(_visitor.fold_expr_range(_binding_0))),
+ Expr::Path(_binding_0) => Expr::Path(_visitor.fold_expr_path(_binding_0)),
+ Expr::Reference(_binding_0) => {
+ Expr::Reference(full!(_visitor.fold_expr_reference(_binding_0)))
+ }
+ Expr::Break(_binding_0) => Expr::Break(full!(_visitor.fold_expr_break(_binding_0))),
+ Expr::Continue(_binding_0) => {
+ Expr::Continue(full!(_visitor.fold_expr_continue(_binding_0)))
+ }
+ Expr::Return(_binding_0) => Expr::Return(full!(_visitor.fold_expr_return(_binding_0))),
+ Expr::Macro(_binding_0) => Expr::Macro(full!(_visitor.fold_expr_macro(_binding_0))),
+ Expr::Struct(_binding_0) => Expr::Struct(full!(_visitor.fold_expr_struct(_binding_0))),
+ Expr::Repeat(_binding_0) => Expr::Repeat(full!(_visitor.fold_expr_repeat(_binding_0))),
+ Expr::Paren(_binding_0) => Expr::Paren(_visitor.fold_expr_paren(_binding_0)),
+ Expr::Group(_binding_0) => Expr::Group(full!(_visitor.fold_expr_group(_binding_0))),
+ Expr::Try(_binding_0) => Expr::Try(full!(_visitor.fold_expr_try(_binding_0))),
+ Expr::Async(_binding_0) => Expr::Async(full!(_visitor.fold_expr_async(_binding_0))),
+ Expr::TryBlock(_binding_0) => {
+ Expr::TryBlock(full!(_visitor.fold_expr_try_block(_binding_0)))
+ }
+ Expr::Yield(_binding_0) => Expr::Yield(full!(_visitor.fold_expr_yield(_binding_0))),
+ Expr::Verbatim(_binding_0) => Expr::Verbatim(_visitor.fold_expr_verbatim(_binding_0)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_array<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprArray) -> ExprArray {
+ ExprArray {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_expr(it)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_assign<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAssign) -> ExprAssign {
+ ExprAssign {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ left: Box::new(_visitor.fold_expr(*_i.left)),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ right: Box::new(_visitor.fold_expr(*_i.right)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_assign_op<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAssignOp) -> ExprAssignOp {
+ ExprAssignOp {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ left: Box::new(_visitor.fold_expr(*_i.left)),
+ op: _visitor.fold_bin_op(_i.op),
+ right: Box::new(_visitor.fold_expr(*_i.right)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_async<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAsync) -> ExprAsync {
+ ExprAsync {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ async_token: Token),
+ capture: (_i.capture).map(|it| Token ! [ move ](tokens_helper(_visitor, &it.span))),
+ block: _visitor.fold_block(_i.block),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_binary<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBinary) -> ExprBinary {
+ ExprBinary {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ left: Box::new(_visitor.fold_expr(*_i.left)),
+ op: _visitor.fold_bin_op(_i.op),
+ right: Box::new(_visitor.fold_expr(*_i.right)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_block<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBlock) -> ExprBlock {
+ ExprBlock {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ label: (_i.label).map(|it| _visitor.fold_label(it)),
+ block: _visitor.fold_block(_i.block),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_box<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBox) -> ExprBox {
+ ExprBox {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ box_token: Token ! [ box ](tokens_helper(_visitor, &_i.box_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_break<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBreak) -> ExprBreak {
+ ExprBreak {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ break_token: Token),
+ label: (_i.label).map(|it| _visitor.fold_lifetime(it)),
+ expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_call<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprCall) -> ExprCall {
+ ExprCall {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ func: Box::new(_visitor.fold_expr(*_i.func)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ args: FoldHelper::lift(_i.args, |it| _visitor.fold_expr(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_cast<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprCast) -> ExprCast {
+ ExprCast {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ as_token: Token ! [ as ](tokens_helper(_visitor, &_i.as_token.span)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_closure<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprClosure) -> ExprClosure {
+ ExprClosure {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ asyncness: (_i.asyncness).map(|it| Token)),
+ movability: (_i.movability).map(|it| Token ! [ static ](tokens_helper(_visitor, &it.span))),
+ capture: (_i.capture).map(|it| Token ! [ move ](tokens_helper(_visitor, &it.span))),
+ or1_token: Token ! [ | ](tokens_helper(_visitor, &_i.or1_token.spans)),
+ inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_fn_arg(it)),
+ or2_token: Token ! [ | ](tokens_helper(_visitor, &_i.or2_token.spans)),
+ output: _visitor.fold_return_type(_i.output),
+ body: Box::new(_visitor.fold_expr(*_i.body)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_continue<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprContinue) -> ExprContinue {
+ ExprContinue {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ continue_token: Token),
+ label: (_i.label).map(|it| _visitor.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_field<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprField) -> ExprField {
+ ExprField {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ base: Box::new(_visitor.fold_expr(*_i.base)),
+ dot_token: Token ! [ . ](tokens_helper(_visitor, &_i.dot_token.spans)),
+ member: _visitor.fold_member(_i.member),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_for_loop<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprForLoop) -> ExprForLoop {
+ ExprForLoop {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ label: (_i.label).map(|it| _visitor.fold_label(it)),
+ for_token: Token ! [ for ](tokens_helper(_visitor, &_i.for_token.span)),
+ pat: Box::new(_visitor.fold_pat(*_i.pat)),
+ in_token: Token ! [ in ](tokens_helper(_visitor, &_i.in_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ body: _visitor.fold_block(_i.body),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_group<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprGroup) -> ExprGroup {
+ ExprGroup {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ group_token: Group(tokens_helper(_visitor, &_i.group_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_if<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIf) -> ExprIf {
+ ExprIf {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ if_token: Token ! [ if ](tokens_helper(_visitor, &_i.if_token.span)),
+ cond: Box::new(_visitor.fold_expr(*_i.cond)),
+ then_branch: _visitor.fold_block(_i.then_branch),
+ else_branch: (_i.else_branch).map(|it| {
+ (
+ Token ! [ else ](tokens_helper(_visitor, &(it).0.span)),
+ Box::new(_visitor.fold_expr(*(it).1)),
+ )
+ }),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_if_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIfLet) -> ExprIfLet {
+ ExprIfLet {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ if_token: Token ! [ if ](tokens_helper(_visitor, &_i.if_token.span)),
+ let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
+ pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ then_branch: _visitor.fold_block(_i.then_branch),
+ else_branch: (_i.else_branch).map(|it| {
+ (
+ Token ! [ else ](tokens_helper(_visitor, &(it).0.span)),
+ Box::new(_visitor.fold_expr(*(it).1)),
+ )
+ }),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_in_place<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprInPlace) -> ExprInPlace {
+ ExprInPlace {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ place: Box::new(_visitor.fold_expr(*_i.place)),
+ arrow_token: Token ! [ <- ](tokens_helper(_visitor, &_i.arrow_token.spans)),
+ value: Box::new(_visitor.fold_expr(*_i.value)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_index<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIndex) -> ExprIndex {
+ ExprIndex {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ index: Box::new(_visitor.fold_expr(*_i.index)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLit) -> ExprLit {
+ ExprLit {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ lit: _visitor.fold_lit(_i.lit),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_loop<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLoop) -> ExprLoop {
+ ExprLoop {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ label: (_i.label).map(|it| _visitor.fold_label(it)),
+ loop_token: Token ! [ loop ](tokens_helper(_visitor, &_i.loop_token.span)),
+ body: _visitor.fold_block(_i.body),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprMacro) -> ExprMacro {
+ ExprMacro {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ mac: _visitor.fold_macro(_i.mac),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_match<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprMatch) -> ExprMatch {
+ ExprMatch {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ match_token: Token ! [ match ](tokens_helper(_visitor, &_i.match_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ arms: FoldHelper::lift(_i.arms, |it| _visitor.fold_arm(it)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_method_call<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ExprMethodCall,
+) -> ExprMethodCall {
+ ExprMethodCall {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ receiver: Box::new(_visitor.fold_expr(*_i.receiver)),
+ dot_token: Token ! [ . ](tokens_helper(_visitor, &_i.dot_token.spans)),
+ method: _visitor.fold_ident(_i.method),
+ turbofish: (_i.turbofish).map(|it| _visitor.fold_method_turbofish(it)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ args: FoldHelper::lift(_i.args, |it| _visitor.fold_expr(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_paren<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprParen) -> ExprParen {
+ ExprParen {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_path<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprPath) -> ExprPath {
+ ExprPath {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ qself: (_i.qself).map(|it| _visitor.fold_qself(it)),
+ path: _visitor.fold_path(_i.path),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_range<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprRange) -> ExprRange {
+ ExprRange {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ from: (_i.from).map(|it| Box::new(_visitor.fold_expr(*it))),
+ limits: _visitor.fold_range_limits(_i.limits),
+ to: (_i.to).map(|it| Box::new(_visitor.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_reference<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprReference) -> ExprReference {
+ ExprReference {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_repeat<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprRepeat) -> ExprRepeat {
+ ExprRepeat {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ len: Box::new(_visitor.fold_expr(*_i.len)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_return<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprReturn) -> ExprReturn {
+ ExprReturn {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ return_token: Token),
+ expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprStruct) -> ExprStruct {
+ ExprStruct {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ path: _visitor.fold_path(_i.path),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ fields: FoldHelper::lift(_i.fields, |it| _visitor.fold_field_value(it)),
+ dot2_token: (_i.dot2_token).map(|it| Token)),
+ rest: (_i.rest).map(|it| Box::new(_visitor.fold_expr(*it))),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_try<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTry) -> ExprTry {
+ ExprTry {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ question_token: Token ! [ ? ](tokens_helper(_visitor, &_i.question_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_try_block<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTryBlock) -> ExprTryBlock {
+ ExprTryBlock {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ try_token: Token),
+ block: _visitor.fold_block(_i.block),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTuple) -> ExprTuple {
+ ExprTuple {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_expr(it)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprType) -> ExprType {
+ ExprType {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_unary<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprUnary) -> ExprUnary {
+ ExprUnary {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ op: _visitor.fold_un_op(_i.op),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_unsafe<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprUnsafe) -> ExprUnsafe {
+ ExprUnsafe {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ unsafe_token: Token ! [ unsafe ](tokens_helper(_visitor, &_i.unsafe_token.span)),
+ block: _visitor.fold_block(_i.block),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprVerbatim) -> ExprVerbatim {
+ ExprVerbatim { tts: _i.tts }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_while<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprWhile) -> ExprWhile {
+ ExprWhile {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ label: (_i.label).map(|it| _visitor.fold_label(it)),
+ while_token: Token ! [ while ](tokens_helper(_visitor, &_i.while_token.span)),
+ cond: Box::new(_visitor.fold_expr(*_i.cond)),
+ body: _visitor.fold_block(_i.body),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_while_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprWhileLet) -> ExprWhileLet {
+ ExprWhileLet {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ label: (_i.label).map(|it| _visitor.fold_label(it)),
+ while_token: Token ! [ while ](tokens_helper(_visitor, &_i.while_token.span)),
+ let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
+ pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ body: _visitor.fold_block(_i.body),
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_expr_yield<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprYield) -> ExprYield {
+ ExprYield {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ yield_token: Token),
+ expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_field<V: Fold + ?Sized>(_visitor: &mut V, _i: Field) -> Field {
+ Field {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ ident: (_i.ident).map(|it| _visitor.fold_ident(it)),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ ty: _visitor.fold_type(_i.ty),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_field_pat<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldPat) -> FieldPat {
+ FieldPat {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ member: _visitor.fold_member(_i.member),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ pat: Box::new(_visitor.fold_pat(*_i.pat)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_field_value<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldValue) -> FieldValue {
+ FieldValue {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ member: _visitor.fold_member(_i.member),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ expr: _visitor.fold_expr(_i.expr),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_fields<V: Fold + ?Sized>(_visitor: &mut V, _i: Fields) -> Fields {
+ match _i {
+ Fields::Named(_binding_0) => Fields::Named(_visitor.fold_fields_named(_binding_0)),
+ Fields::Unnamed(_binding_0) => Fields::Unnamed(_visitor.fold_fields_unnamed(_binding_0)),
+ Fields::Unit => Fields::Unit,
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_fields_named<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldsNamed) -> FieldsNamed {
+ FieldsNamed {
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ named: FoldHelper::lift(_i.named, |it| _visitor.fold_field(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_fields_unnamed<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldsUnnamed) -> FieldsUnnamed {
+ FieldsUnnamed {
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ unnamed: FoldHelper::lift(_i.unnamed, |it| _visitor.fold_field(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_file<V: Fold + ?Sized>(_visitor: &mut V, _i: File) -> File {
+ File {
+ shebang: _i.shebang,
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ items: FoldHelper::lift(_i.items, |it| _visitor.fold_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_fn_arg<V: Fold + ?Sized>(_visitor: &mut V, _i: FnArg) -> FnArg {
+ match _i {
+ FnArg::SelfRef(_binding_0) => FnArg::SelfRef(_visitor.fold_arg_self_ref(_binding_0)),
+ FnArg::SelfValue(_binding_0) => FnArg::SelfValue(_visitor.fold_arg_self(_binding_0)),
+ FnArg::Captured(_binding_0) => FnArg::Captured(_visitor.fold_arg_captured(_binding_0)),
+ FnArg::Inferred(_binding_0) => FnArg::Inferred(_visitor.fold_pat(_binding_0)),
+ FnArg::Ignored(_binding_0) => FnArg::Ignored(_visitor.fold_type(_binding_0)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_fn_decl<V: Fold + ?Sized>(_visitor: &mut V, _i: FnDecl) -> FnDecl {
+ FnDecl {
+ fn_token: Token ! [ fn ](tokens_helper(_visitor, &_i.fn_token.span)),
+ generics: _visitor.fold_generics(_i.generics),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_fn_arg(it)),
+ variadic: (_i.variadic).map(|it| Token ! [ ... ](tokens_helper(_visitor, &it.spans))),
+ output: _visitor.fold_return_type(_i.output),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item<V: Fold + ?Sized>(_visitor: &mut V, _i: ForeignItem) -> ForeignItem {
+ match _i {
+ ForeignItem::Fn(_binding_0) => ForeignItem::Fn(_visitor.fold_foreign_item_fn(_binding_0)),
+ ForeignItem::Static(_binding_0) => {
+ ForeignItem::Static(_visitor.fold_foreign_item_static(_binding_0))
+ }
+ ForeignItem::Type(_binding_0) => {
+ ForeignItem::Type(_visitor.fold_foreign_item_type(_binding_0))
+ }
+ ForeignItem::Macro(_binding_0) => {
+ ForeignItem::Macro(_visitor.fold_foreign_item_macro(_binding_0))
+ }
+ ForeignItem::Verbatim(_binding_0) => {
+ ForeignItem::Verbatim(_visitor.fold_foreign_item_verbatim(_binding_0))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_fn<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ForeignItemFn,
+) -> ForeignItemFn {
+ ForeignItemFn {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ ident: _visitor.fold_ident(_i.ident),
+ decl: Box::new(_visitor.fold_fn_decl(*_i.decl)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_macro<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ForeignItemMacro,
+) -> ForeignItemMacro {
+ ForeignItemMacro {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ mac: _visitor.fold_macro(_i.mac),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_static<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ForeignItemStatic,
+) -> ForeignItemStatic {
+ ForeignItemStatic {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ static_token: Token ! [ static ](tokens_helper(_visitor, &_i.static_token.span)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_type<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ForeignItemType,
+) -> ForeignItemType {
+ ForeignItemType {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_foreign_item_verbatim<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ForeignItemVerbatim,
+) -> ForeignItemVerbatim {
+ ForeignItemVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_generic_argument<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: GenericArgument,
+) -> GenericArgument {
+ match _i {
+ GenericArgument::Lifetime(_binding_0) => {
+ GenericArgument::Lifetime(_visitor.fold_lifetime(_binding_0))
+ }
+ GenericArgument::Type(_binding_0) => GenericArgument::Type(_visitor.fold_type(_binding_0)),
+ GenericArgument::Binding(_binding_0) => {
+ GenericArgument::Binding(_visitor.fold_binding(_binding_0))
+ }
+ GenericArgument::Const(_binding_0) => {
+ GenericArgument::Const(_visitor.fold_expr(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_generic_method_argument<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: GenericMethodArgument,
+) -> GenericMethodArgument {
+ match _i {
+ GenericMethodArgument::Type(_binding_0) => {
+ GenericMethodArgument::Type(_visitor.fold_type(_binding_0))
+ }
+ GenericMethodArgument::Const(_binding_0) => {
+ GenericMethodArgument::Const(_visitor.fold_expr(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_generic_param<V: Fold + ?Sized>(_visitor: &mut V, _i: GenericParam) -> GenericParam {
+ match _i {
+ GenericParam::Type(_binding_0) => GenericParam::Type(_visitor.fold_type_param(_binding_0)),
+ GenericParam::Lifetime(_binding_0) => {
+ GenericParam::Lifetime(_visitor.fold_lifetime_def(_binding_0))
+ }
+ GenericParam::Const(_binding_0) => {
+ GenericParam::Const(_visitor.fold_const_param(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_generics<V: Fold + ?Sized>(_visitor: &mut V, _i: Generics) -> Generics {
+ Generics {
+ lt_token: (_i.lt_token).map(|it| Token ! [ < ](tokens_helper(_visitor, &it.spans))),
+ params: FoldHelper::lift(_i.params, |it| _visitor.fold_generic_param(it)),
+ gt_token: (_i.gt_token).map(|it| Token ! [ > ](tokens_helper(_visitor, &it.spans))),
+ where_clause: (_i.where_clause).map(|it| _visitor.fold_where_clause(it)),
+ }
+}
+pub fn fold_ident<V: Fold + ?Sized>(_visitor: &mut V, _i: Ident) -> Ident {
+ let mut _i = _i;
+ let span = _visitor.fold_span(_i.span());
+ _i.set_span(span);
+ _i
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item<V: Fold + ?Sized>(_visitor: &mut V, _i: ImplItem) -> ImplItem {
+ match _i {
+ ImplItem::Const(_binding_0) => ImplItem::Const(_visitor.fold_impl_item_const(_binding_0)),
+ ImplItem::Method(_binding_0) => {
+ ImplItem::Method(_visitor.fold_impl_item_method(_binding_0))
+ }
+ ImplItem::Type(_binding_0) => ImplItem::Type(_visitor.fold_impl_item_type(_binding_0)),
+ ImplItem::Existential(_binding_0) => {
+ ImplItem::Existential(_visitor.fold_impl_item_existential(_binding_0))
+ }
+ ImplItem::Macro(_binding_0) => ImplItem::Macro(_visitor.fold_impl_item_macro(_binding_0)),
+ ImplItem::Verbatim(_binding_0) => {
+ ImplItem::Verbatim(_visitor.fold_impl_item_verbatim(_binding_0))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_const<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ImplItemConst,
+) -> ImplItemConst {
+ ImplItemConst {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ defaultness: (_i.defaultness).map(|it| Token)),
+ const_token: Token ! [ const ](tokens_helper(_visitor, &_i.const_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ expr: _visitor.fold_expr(_i.expr),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_existential<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ImplItemExistential,
+) -> ImplItemExistential {
+ ImplItemExistential {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ existential_token: Token),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_macro<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ImplItemMacro,
+) -> ImplItemMacro {
+ ImplItemMacro {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ mac: _visitor.fold_macro(_i.mac),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_method<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ImplItemMethod,
+) -> ImplItemMethod {
+ ImplItemMethod {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ defaultness: (_i.defaultness).map(|it| Token)),
+ sig: _visitor.fold_method_sig(_i.sig),
+ block: _visitor.fold_block(_i.block),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ImplItemType) -> ImplItemType {
+ ImplItemType {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ defaultness: (_i.defaultness).map(|it| Token)),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_impl_item_verbatim<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ImplItemVerbatim,
+) -> ImplItemVerbatim {
+ ImplItemVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_index<V: Fold + ?Sized>(_visitor: &mut V, _i: Index) -> Index {
+ Index {
+ index: _i.index,
+ span: _visitor.fold_span(_i.span),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item<V: Fold + ?Sized>(_visitor: &mut V, _i: Item) -> Item {
+ match _i {
+ Item::ExternCrate(_binding_0) => {
+ Item::ExternCrate(_visitor.fold_item_extern_crate(_binding_0))
+ }
+ Item::Use(_binding_0) => Item::Use(_visitor.fold_item_use(_binding_0)),
+ Item::Static(_binding_0) => Item::Static(_visitor.fold_item_static(_binding_0)),
+ Item::Const(_binding_0) => Item::Const(_visitor.fold_item_const(_binding_0)),
+ Item::Fn(_binding_0) => Item::Fn(_visitor.fold_item_fn(_binding_0)),
+ Item::Mod(_binding_0) => Item::Mod(_visitor.fold_item_mod(_binding_0)),
+ Item::ForeignMod(_binding_0) => {
+ Item::ForeignMod(_visitor.fold_item_foreign_mod(_binding_0))
+ }
+ Item::Type(_binding_0) => Item::Type(_visitor.fold_item_type(_binding_0)),
+ Item::Existential(_binding_0) => {
+ Item::Existential(_visitor.fold_item_existential(_binding_0))
+ }
+ Item::Struct(_binding_0) => Item::Struct(_visitor.fold_item_struct(_binding_0)),
+ Item::Enum(_binding_0) => Item::Enum(_visitor.fold_item_enum(_binding_0)),
+ Item::Union(_binding_0) => Item::Union(_visitor.fold_item_union(_binding_0)),
+ Item::Trait(_binding_0) => Item::Trait(_visitor.fold_item_trait(_binding_0)),
+ Item::Impl(_binding_0) => Item::Impl(_visitor.fold_item_impl(_binding_0)),
+ Item::Macro(_binding_0) => Item::Macro(_visitor.fold_item_macro(_binding_0)),
+ Item::Macro2(_binding_0) => Item::Macro2(_visitor.fold_item_macro2(_binding_0)),
+ Item::Verbatim(_binding_0) => Item::Verbatim(_visitor.fold_item_verbatim(_binding_0)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_const<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemConst) -> ItemConst {
+ ItemConst {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ const_token: Token ! [ const ](tokens_helper(_visitor, &_i.const_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_enum<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemEnum) -> ItemEnum {
+ ItemEnum {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ enum_token: Token ! [ enum ](tokens_helper(_visitor, &_i.enum_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ variants: FoldHelper::lift(_i.variants, |it| _visitor.fold_variant(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_existential<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ItemExistential,
+) -> ItemExistential {
+ ItemExistential {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ existential_token: Token),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_extern_crate<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ItemExternCrate,
+) -> ItemExternCrate {
+ ItemExternCrate {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ extern_token: Token),
+ crate_token: Token),
+ ident: _visitor.fold_ident(_i.ident),
+ rename: (_i.rename).map(|it| {
+ (
+ Token ! [ as ](tokens_helper(_visitor, &(it).0.span)),
+ _visitor.fold_ident((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_fn<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemFn) -> ItemFn {
+ ItemFn {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ constness: (_i.constness).map(|it| Token ! [ const ](tokens_helper(_visitor, &it.span))),
+ unsafety: (_i.unsafety).map(|it| Token ! [ unsafe ](tokens_helper(_visitor, &it.span))),
+ asyncness: (_i.asyncness).map(|it| Token)),
+ abi: (_i.abi).map(|it| _visitor.fold_abi(it)),
+ ident: _visitor.fold_ident(_i.ident),
+ decl: Box::new(_visitor.fold_fn_decl(*_i.decl)),
+ block: Box::new(_visitor.fold_block(*_i.block)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_foreign_mod<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ItemForeignMod,
+) -> ItemForeignMod {
+ ItemForeignMod {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ abi: _visitor.fold_abi(_i.abi),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ items: FoldHelper::lift(_i.items, |it| _visitor.fold_foreign_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_impl<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemImpl) -> ItemImpl {
+ ItemImpl {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ defaultness: (_i.defaultness).map(|it| Token)),
+ unsafety: (_i.unsafety).map(|it| Token ! [ unsafe ](tokens_helper(_visitor, &it.span))),
+ impl_token: Token),
+ generics: _visitor.fold_generics(_i.generics),
+ trait_: (_i.trait_).map(|it| {
+ (
+ ((it).0).map(|it| Token)),
+ _visitor.fold_path((it).1),
+ Token ! [ for ](tokens_helper(_visitor, &(it).2.span)),
+ )
+ }),
+ self_ty: Box::new(_visitor.fold_type(*_i.self_ty)),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ items: FoldHelper::lift(_i.items, |it| _visitor.fold_impl_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMacro) -> ItemMacro {
+ ItemMacro {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ ident: (_i.ident).map(|it| _visitor.fold_ident(it)),
+ mac: _visitor.fold_macro(_i.mac),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_macro2<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMacro2) -> ItemMacro2 {
+ ItemMacro2 {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ macro_token: Token ! [ macro ](tokens_helper(_visitor, &_i.macro_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ args: _i.args,
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ body: _i.body,
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_mod<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMod) -> ItemMod {
+ ItemMod {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ mod_token: Token ! [ mod ](tokens_helper(_visitor, &_i.mod_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ content: (_i.content).map(|it| {
+ (
+ Brace(tokens_helper(_visitor, &(it).0.span)),
+ FoldHelper::lift((it).1, |it| _visitor.fold_item(it)),
+ )
+ }),
+ semi: (_i.semi).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_static<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemStatic) -> ItemStatic {
+ ItemStatic {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ static_token: Token ! [ static ](tokens_helper(_visitor, &_i.static_token.span)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemStruct) -> ItemStruct {
+ ItemStruct {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ struct_token: Token ! [ struct ](tokens_helper(_visitor, &_i.struct_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ fields: _visitor.fold_fields(_i.fields),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_trait<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemTrait) -> ItemTrait {
+ ItemTrait {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ unsafety: (_i.unsafety).map(|it| Token ! [ unsafe ](tokens_helper(_visitor, &it.span))),
+ auto_token: (_i.auto_token).map(|it| Token)),
+ trait_token: Token ! [ trait ](tokens_helper(_visitor, &_i.trait_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ supertraits: FoldHelper::lift(_i.supertraits, |it| _visitor.fold_type_param_bound(it)),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ items: FoldHelper::lift(_i.items, |it| _visitor.fold_trait_item(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemType) -> ItemType {
+ ItemType {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_union<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemUnion) -> ItemUnion {
+ ItemUnion {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ union_token: Token),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ fields: _visitor.fold_fields_named(_i.fields),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_use<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemUse) -> ItemUse {
+ ItemUse {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ vis: _visitor.fold_visibility(_i.vis),
+ use_token: Token ! [ use ](tokens_helper(_visitor, &_i.use_token.span)),
+ leading_colon: (_i.leading_colon)
+ .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))),
+ tree: _visitor.fold_use_tree(_i.tree),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_item_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemVerbatim) -> ItemVerbatim {
+ ItemVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_label<V: Fold + ?Sized>(_visitor: &mut V, _i: Label) -> Label {
+ Label {
+ name: _visitor.fold_lifetime(_i.name),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_lifetime<V: Fold + ?Sized>(_visitor: &mut V, _i: Lifetime) -> Lifetime {
+ Lifetime {
+ apostrophe: _i.apostrophe,
+ ident: _visitor.fold_ident(_i.ident),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_lifetime_def<V: Fold + ?Sized>(_visitor: &mut V, _i: LifetimeDef) -> LifetimeDef {
+ LifetimeDef {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ lifetime: _visitor.fold_lifetime(_i.lifetime),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: Lit) -> Lit {
+ match _i {
+ Lit::Str(_binding_0) => Lit::Str(_visitor.fold_lit_str(_binding_0)),
+ Lit::ByteStr(_binding_0) => Lit::ByteStr(_visitor.fold_lit_byte_str(_binding_0)),
+ Lit::Byte(_binding_0) => Lit::Byte(_visitor.fold_lit_byte(_binding_0)),
+ Lit::Char(_binding_0) => Lit::Char(_visitor.fold_lit_char(_binding_0)),
+ Lit::Int(_binding_0) => Lit::Int(_visitor.fold_lit_int(_binding_0)),
+ Lit::Float(_binding_0) => Lit::Float(_visitor.fold_lit_float(_binding_0)),
+ Lit::Bool(_binding_0) => Lit::Bool(_visitor.fold_lit_bool(_binding_0)),
+ Lit::Verbatim(_binding_0) => Lit::Verbatim(_visitor.fold_lit_verbatim(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_lit_bool<V: Fold + ?Sized>(_visitor: &mut V, _i: LitBool) -> LitBool {
+ LitBool {
+ value: _i.value,
+ span: _visitor.fold_span(_i.span),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_lit_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: LitVerbatim) -> LitVerbatim {
+ LitVerbatim { token: _i.token }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_local<V: Fold + ?Sized>(_visitor: &mut V, _i: Local) -> Local {
+ Local {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ let_token: Token ! [ let ](tokens_helper(_visitor, &_i.let_token.span)),
+ pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)),
+ ty: (_i.ty).map(|it| {
+ (
+ Token ! [ : ](tokens_helper(_visitor, &(it).0.spans)),
+ Box::new(_visitor.fold_type(*(it).1)),
+ )
+ }),
+ init: (_i.init).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)),
+ Box::new(_visitor.fold_expr(*(it).1)),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: Macro) -> Macro {
+ Macro {
+ path: _visitor.fold_path(_i.path),
+ bang_token: Token),
+ delimiter: _visitor.fold_macro_delimiter(_i.delimiter),
+ tts: _i.tts,
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_macro_delimiter<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: MacroDelimiter,
+) -> MacroDelimiter {
+ match _i {
+ MacroDelimiter::Paren(_binding_0) => {
+ MacroDelimiter::Paren(Paren(tokens_helper(_visitor, &_binding_0.span)))
+ }
+ MacroDelimiter::Brace(_binding_0) => {
+ MacroDelimiter::Brace(Brace(tokens_helper(_visitor, &_binding_0.span)))
+ }
+ MacroDelimiter::Bracket(_binding_0) => {
+ MacroDelimiter::Bracket(Bracket(tokens_helper(_visitor, &_binding_0.span)))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_member<V: Fold + ?Sized>(_visitor: &mut V, _i: Member) -> Member {
+ match _i {
+ Member::Named(_binding_0) => Member::Named(_visitor.fold_ident(_binding_0)),
+ Member::Unnamed(_binding_0) => Member::Unnamed(_visitor.fold_index(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_meta<V: Fold + ?Sized>(_visitor: &mut V, _i: Meta) -> Meta {
+ match _i {
+ Meta::Word(_binding_0) => Meta::Word(_visitor.fold_ident(_binding_0)),
+ Meta::List(_binding_0) => Meta::List(_visitor.fold_meta_list(_binding_0)),
+ Meta::NameValue(_binding_0) => Meta::NameValue(_visitor.fold_meta_name_value(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_meta_list<V: Fold + ?Sized>(_visitor: &mut V, _i: MetaList) -> MetaList {
+ MetaList {
+ ident: _visitor.fold_ident(_i.ident),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ nested: FoldHelper::lift(_i.nested, |it| _visitor.fold_nested_meta(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_meta_name_value<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: MetaNameValue,
+) -> MetaNameValue {
+ MetaNameValue {
+ ident: _visitor.fold_ident(_i.ident),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ lit: _visitor.fold_lit(_i.lit),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_method_sig<V: Fold + ?Sized>(_visitor: &mut V, _i: MethodSig) -> MethodSig {
+ MethodSig {
+ constness: (_i.constness).map(|it| Token ! [ const ](tokens_helper(_visitor, &it.span))),
+ unsafety: (_i.unsafety).map(|it| Token ! [ unsafe ](tokens_helper(_visitor, &it.span))),
+ asyncness: (_i.asyncness).map(|it| Token)),
+ abi: (_i.abi).map(|it| _visitor.fold_abi(it)),
+ ident: _visitor.fold_ident(_i.ident),
+ decl: _visitor.fold_fn_decl(_i.decl),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_method_turbofish<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: MethodTurbofish,
+) -> MethodTurbofish {
+ MethodTurbofish {
+ colon2_token: Token ! [ :: ](tokens_helper(_visitor, &_i.colon2_token.spans)),
+ lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)),
+ args: FoldHelper::lift(_i.args, |it| _visitor.fold_generic_method_argument(it)),
+ gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_nested_meta<V: Fold + ?Sized>(_visitor: &mut V, _i: NestedMeta) -> NestedMeta {
+ match _i {
+ NestedMeta::Meta(_binding_0) => NestedMeta::Meta(_visitor.fold_meta(_binding_0)),
+ NestedMeta::Literal(_binding_0) => NestedMeta::Literal(_visitor.fold_lit(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_parenthesized_generic_arguments<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: ParenthesizedGenericArguments,
+) -> ParenthesizedGenericArguments {
+ ParenthesizedGenericArguments {
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_type(it)),
+ output: _visitor.fold_return_type(_i.output),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat<V: Fold + ?Sized>(_visitor: &mut V, _i: Pat) -> Pat {
+ match _i {
+ Pat::Wild(_binding_0) => Pat::Wild(_visitor.fold_pat_wild(_binding_0)),
+ Pat::Ident(_binding_0) => Pat::Ident(_visitor.fold_pat_ident(_binding_0)),
+ Pat::Struct(_binding_0) => Pat::Struct(_visitor.fold_pat_struct(_binding_0)),
+ Pat::TupleStruct(_binding_0) => {
+ Pat::TupleStruct(_visitor.fold_pat_tuple_struct(_binding_0))
+ }
+ Pat::Path(_binding_0) => Pat::Path(_visitor.fold_pat_path(_binding_0)),
+ Pat::Tuple(_binding_0) => Pat::Tuple(_visitor.fold_pat_tuple(_binding_0)),
+ Pat::Box(_binding_0) => Pat::Box(_visitor.fold_pat_box(_binding_0)),
+ Pat::Ref(_binding_0) => Pat::Ref(_visitor.fold_pat_ref(_binding_0)),
+ Pat::Lit(_binding_0) => Pat::Lit(_visitor.fold_pat_lit(_binding_0)),
+ Pat::Range(_binding_0) => Pat::Range(_visitor.fold_pat_range(_binding_0)),
+ Pat::Slice(_binding_0) => Pat::Slice(_visitor.fold_pat_slice(_binding_0)),
+ Pat::Macro(_binding_0) => Pat::Macro(_visitor.fold_pat_macro(_binding_0)),
+ Pat::Verbatim(_binding_0) => Pat::Verbatim(_visitor.fold_pat_verbatim(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_box<V: Fold + ?Sized>(_visitor: &mut V, _i: PatBox) -> PatBox {
+ PatBox {
+ box_token: Token ! [ box ](tokens_helper(_visitor, &_i.box_token.span)),
+ pat: Box::new(_visitor.fold_pat(*_i.pat)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_ident<V: Fold + ?Sized>(_visitor: &mut V, _i: PatIdent) -> PatIdent {
+ PatIdent {
+ by_ref: (_i.by_ref).map(|it| Token ! [ ref ](tokens_helper(_visitor, &it.span))),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ ident: _visitor.fold_ident(_i.ident),
+ subpat: (_i.subpat).map(|it| {
+ (
+ Token ! [ @ ](tokens_helper(_visitor, &(it).0.spans)),
+ Box::new(_visitor.fold_pat(*(it).1)),
+ )
+ }),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: PatLit) -> PatLit {
+ PatLit {
+ expr: Box::new(_visitor.fold_expr(*_i.expr)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: PatMacro) -> PatMacro {
+ PatMacro {
+ mac: _visitor.fold_macro(_i.mac),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_path<V: Fold + ?Sized>(_visitor: &mut V, _i: PatPath) -> PatPath {
+ PatPath {
+ qself: (_i.qself).map(|it| _visitor.fold_qself(it)),
+ path: _visitor.fold_path(_i.path),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_range<V: Fold + ?Sized>(_visitor: &mut V, _i: PatRange) -> PatRange {
+ PatRange {
+ lo: Box::new(_visitor.fold_expr(*_i.lo)),
+ limits: _visitor.fold_range_limits(_i.limits),
+ hi: Box::new(_visitor.fold_expr(*_i.hi)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_ref<V: Fold + ?Sized>(_visitor: &mut V, _i: PatRef) -> PatRef {
+ PatRef {
+ and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ pat: Box::new(_visitor.fold_pat(*_i.pat)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_slice<V: Fold + ?Sized>(_visitor: &mut V, _i: PatSlice) -> PatSlice {
+ PatSlice {
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ front: FoldHelper::lift(_i.front, |it| _visitor.fold_pat(it)),
+ middle: (_i.middle).map(|it| Box::new(_visitor.fold_pat(*it))),
+ dot2_token: (_i.dot2_token).map(|it| Token)),
+ comma_token: (_i.comma_token).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))),
+ back: FoldHelper::lift(_i.back, |it| _visitor.fold_pat(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: PatStruct) -> PatStruct {
+ PatStruct {
+ path: _visitor.fold_path(_i.path),
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ fields: FoldHelper::lift(_i.fields, |it| _visitor.fold_field_pat(it)),
+ dot2_token: (_i.dot2_token).map(|it| Token)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: PatTuple) -> PatTuple {
+ PatTuple {
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ front: FoldHelper::lift(_i.front, |it| _visitor.fold_pat(it)),
+ dot2_token: (_i.dot2_token).map(|it| Token)),
+ comma_token: (_i.comma_token).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))),
+ back: FoldHelper::lift(_i.back, |it| _visitor.fold_pat(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_tuple_struct<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: PatTupleStruct,
+) -> PatTupleStruct {
+ PatTupleStruct {
+ path: _visitor.fold_path(_i.path),
+ pat: _visitor.fold_pat_tuple(_i.pat),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: PatVerbatim) -> PatVerbatim {
+ PatVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_pat_wild<V: Fold + ?Sized>(_visitor: &mut V, _i: PatWild) -> PatWild {
+ PatWild {
+ underscore_token: Token),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_path<V: Fold + ?Sized>(_visitor: &mut V, _i: Path) -> Path {
+ Path {
+ leading_colon: (_i.leading_colon)
+ .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))),
+ segments: FoldHelper::lift(_i.segments, |it| _visitor.fold_path_segment(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_path_arguments<V: Fold + ?Sized>(_visitor: &mut V, _i: PathArguments) -> PathArguments {
+ match _i {
+ PathArguments::None => PathArguments::None,
+ PathArguments::AngleBracketed(_binding_0) => PathArguments::AngleBracketed(
+ _visitor.fold_angle_bracketed_generic_arguments(_binding_0),
+ ),
+ PathArguments::Parenthesized(_binding_0) => {
+ PathArguments::Parenthesized(_visitor.fold_parenthesized_generic_arguments(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_path_segment<V: Fold + ?Sized>(_visitor: &mut V, _i: PathSegment) -> PathSegment {
+ PathSegment {
+ ident: _visitor.fold_ident(_i.ident),
+ arguments: _visitor.fold_path_arguments(_i.arguments),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_predicate_eq<V: Fold + ?Sized>(_visitor: &mut V, _i: PredicateEq) -> PredicateEq {
+ PredicateEq {
+ lhs_ty: _visitor.fold_type(_i.lhs_ty),
+ eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)),
+ rhs_ty: _visitor.fold_type(_i.rhs_ty),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_predicate_lifetime<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: PredicateLifetime,
+) -> PredicateLifetime {
+ PredicateLifetime {
+ lifetime: _visitor.fold_lifetime(_i.lifetime),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_lifetime(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_predicate_type<V: Fold + ?Sized>(_visitor: &mut V, _i: PredicateType) -> PredicateType {
+ PredicateType {
+ lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)),
+ bounded_ty: _visitor.fold_type(_i.bounded_ty),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_qself<V: Fold + ?Sized>(_visitor: &mut V, _i: QSelf) -> QSelf {
+ QSelf {
+ lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)),
+ ty: Box::new(_visitor.fold_type(*_i.ty)),
+ position: _i.position,
+ as_token: (_i.as_token).map(|it| Token ! [ as ](tokens_helper(_visitor, &it.span))),
+ gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_range_limits<V: Fold + ?Sized>(_visitor: &mut V, _i: RangeLimits) -> RangeLimits {
+ match _i {
+ RangeLimits::HalfOpen(_binding_0) => {
+ RangeLimits::HalfOpen(Token))
+ }
+ RangeLimits::Closed(_binding_0) => {
+ RangeLimits::Closed(Token ! [ ..= ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_return_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ReturnType) -> ReturnType {
+ match _i {
+ ReturnType::Default => ReturnType::Default,
+ ReturnType::Type(_binding_0, _binding_1) => ReturnType::Type(
+ Token ! [ -> ](tokens_helper(_visitor, &_binding_0.spans)),
+ Box::new(_visitor.fold_type(*_binding_1)),
+ ),
+ }
+}
+pub fn fold_span<V: Fold + ?Sized>(_visitor: &mut V, _i: Span) -> Span {
+ _i
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn fold_stmt<V: Fold + ?Sized>(_visitor: &mut V, _i: Stmt) -> Stmt {
+ match _i {
+ Stmt::Local(_binding_0) => Stmt::Local(_visitor.fold_local(_binding_0)),
+ Stmt::Item(_binding_0) => Stmt::Item(_visitor.fold_item(_binding_0)),
+ Stmt::Expr(_binding_0) => Stmt::Expr(_visitor.fold_expr(_binding_0)),
+ Stmt::Semi(_binding_0, _binding_1) => Stmt::Semi(
+ _visitor.fold_expr(_binding_0),
+ Token ! [ ; ](tokens_helper(_visitor, &_binding_1.spans)),
+ ),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_trait_bound<V: Fold + ?Sized>(_visitor: &mut V, _i: TraitBound) -> TraitBound {
+ TraitBound {
+ paren_token: (_i.paren_token).map(|it| Paren(tokens_helper(_visitor, &it.span))),
+ modifier: _visitor.fold_trait_bound_modifier(_i.modifier),
+ lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)),
+ path: _visitor.fold_path(_i.path),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_trait_bound_modifier<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitBoundModifier,
+) -> TraitBoundModifier {
+ match _i {
+ TraitBoundModifier::None => TraitBoundModifier::None,
+ TraitBoundModifier::Maybe(_binding_0) => {
+ TraitBoundModifier::Maybe(Token ! [ ? ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item<V: Fold + ?Sized>(_visitor: &mut V, _i: TraitItem) -> TraitItem {
+ match _i {
+ TraitItem::Const(_binding_0) => {
+ TraitItem::Const(_visitor.fold_trait_item_const(_binding_0))
+ }
+ TraitItem::Method(_binding_0) => {
+ TraitItem::Method(_visitor.fold_trait_item_method(_binding_0))
+ }
+ TraitItem::Type(_binding_0) => TraitItem::Type(_visitor.fold_trait_item_type(_binding_0)),
+ TraitItem::Existential(_binding_0) => {
+ TraitItem::Existential(_visitor.fold_trait_item_existential(_binding_0))
+ }
+ TraitItem::Macro(_binding_0) => {
+ TraitItem::Macro(_visitor.fold_trait_item_macro(_binding_0))
+ }
+ TraitItem::Verbatim(_binding_0) => {
+ TraitItem::Verbatim(_visitor.fold_trait_item_verbatim(_binding_0))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_const<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemConst,
+) -> TraitItemConst {
+ TraitItemConst {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ const_token: Token ! [ const ](tokens_helper(_visitor, &_i.const_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)),
+ ty: _visitor.fold_type(_i.ty),
+ default: (_i.default).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)),
+ _visitor.fold_expr((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_existential<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemExistential,
+) -> TraitItemExistential {
+ TraitItemExistential {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ existential_token: Token),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_macro<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemMacro,
+) -> TraitItemMacro {
+ TraitItemMacro {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ mac: _visitor.fold_macro(_i.mac),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_method<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemMethod,
+) -> TraitItemMethod {
+ TraitItemMethod {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ sig: _visitor.fold_method_sig(_i.sig),
+ default: (_i.default).map(|it| _visitor.fold_block(it)),
+ semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_type<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemType,
+) -> TraitItemType {
+ TraitItemType {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ type_token: Token ! [ type ](tokens_helper(_visitor, &_i.type_token.span)),
+ ident: _visitor.fold_ident(_i.ident),
+ generics: _visitor.fold_generics(_i.generics),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ default: (_i.default).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)),
+ _visitor.fold_type((it).1),
+ )
+ }),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_trait_item_verbatim<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TraitItemVerbatim,
+) -> TraitItemVerbatim {
+ TraitItemVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type<V: Fold + ?Sized>(_visitor: &mut V, _i: Type) -> Type {
+ match _i {
+ Type::Slice(_binding_0) => Type::Slice(_visitor.fold_type_slice(_binding_0)),
+ Type::Array(_binding_0) => Type::Array(_visitor.fold_type_array(_binding_0)),
+ Type::Ptr(_binding_0) => Type::Ptr(_visitor.fold_type_ptr(_binding_0)),
+ Type::Reference(_binding_0) => Type::Reference(_visitor.fold_type_reference(_binding_0)),
+ Type::BareFn(_binding_0) => Type::BareFn(_visitor.fold_type_bare_fn(_binding_0)),
+ Type::Never(_binding_0) => Type::Never(_visitor.fold_type_never(_binding_0)),
+ Type::Tuple(_binding_0) => Type::Tuple(_visitor.fold_type_tuple(_binding_0)),
+ Type::Path(_binding_0) => Type::Path(_visitor.fold_type_path(_binding_0)),
+ Type::TraitObject(_binding_0) => {
+ Type::TraitObject(_visitor.fold_type_trait_object(_binding_0))
+ }
+ Type::ImplTrait(_binding_0) => Type::ImplTrait(_visitor.fold_type_impl_trait(_binding_0)),
+ Type::Paren(_binding_0) => Type::Paren(_visitor.fold_type_paren(_binding_0)),
+ Type::Group(_binding_0) => Type::Group(_visitor.fold_type_group(_binding_0)),
+ Type::Infer(_binding_0) => Type::Infer(_visitor.fold_type_infer(_binding_0)),
+ Type::Macro(_binding_0) => Type::Macro(_visitor.fold_type_macro(_binding_0)),
+ Type::Verbatim(_binding_0) => Type::Verbatim(_visitor.fold_type_verbatim(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_array<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeArray) -> TypeArray {
+ TypeArray {
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)),
+ len: _visitor.fold_expr(_i.len),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_bare_fn<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeBareFn) -> TypeBareFn {
+ TypeBareFn {
+ unsafety: (_i.unsafety).map(|it| Token ! [ unsafe ](tokens_helper(_visitor, &it.span))),
+ abi: (_i.abi).map(|it| _visitor.fold_abi(it)),
+ fn_token: Token ! [ fn ](tokens_helper(_visitor, &_i.fn_token.span)),
+ lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_bare_fn_arg(it)),
+ variadic: (_i.variadic).map(|it| Token ! [ ... ](tokens_helper(_visitor, &it.spans))),
+ output: _visitor.fold_return_type(_i.output),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_group<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeGroup) -> TypeGroup {
+ TypeGroup {
+ group_token: Group(tokens_helper(_visitor, &_i.group_token.span)),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_impl_trait<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TypeImplTrait,
+) -> TypeImplTrait {
+ TypeImplTrait {
+ impl_token: Token),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_infer<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeInfer) -> TypeInfer {
+ TypeInfer {
+ underscore_token: Token),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeMacro) -> TypeMacro {
+ TypeMacro {
+ mac: _visitor.fold_macro(_i.mac),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_never<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeNever) -> TypeNever {
+ TypeNever {
+ bang_token: Token),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_param<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeParam) -> TypeParam {
+ TypeParam {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ ident: _visitor.fold_ident(_i.ident),
+ colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ eq_token: (_i.eq_token).map(|it| Token ! [ = ](tokens_helper(_visitor, &it.spans))),
+ default: (_i.default).map(|it| _visitor.fold_type(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_param_bound<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TypeParamBound,
+) -> TypeParamBound {
+ match _i {
+ TypeParamBound::Trait(_binding_0) => {
+ TypeParamBound::Trait(_visitor.fold_trait_bound(_binding_0))
+ }
+ TypeParamBound::Lifetime(_binding_0) => {
+ TypeParamBound::Lifetime(_visitor.fold_lifetime(_binding_0))
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_paren<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeParen) -> TypeParen {
+ TypeParen {
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_path<V: Fold + ?Sized>(_visitor: &mut V, _i: TypePath) -> TypePath {
+ TypePath {
+ qself: (_i.qself).map(|it| _visitor.fold_qself(it)),
+ path: _visitor.fold_path(_i.path),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_ptr<V: Fold + ?Sized>(_visitor: &mut V, _i: TypePtr) -> TypePtr {
+ TypePtr {
+ star_token: Token ! [ * ](tokens_helper(_visitor, &_i.star_token.spans)),
+ const_token: (_i.const_token)
+ .map(|it| Token ! [ const ](tokens_helper(_visitor, &it.span))),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_reference<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeReference) -> TypeReference {
+ TypeReference {
+ and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)),
+ lifetime: (_i.lifetime).map(|it| _visitor.fold_lifetime(it)),
+ mutability: (_i.mutability).map(|it| Token ! [ mut ](tokens_helper(_visitor, &it.span))),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_slice<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeSlice) -> TypeSlice {
+ TypeSlice {
+ bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)),
+ elem: Box::new(_visitor.fold_type(*_i.elem)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_trait_object<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: TypeTraitObject,
+) -> TypeTraitObject {
+ TypeTraitObject {
+ dyn_token: (_i.dyn_token).map(|it| Token)),
+ bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeTuple) -> TypeTuple {
+ TypeTuple {
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_type(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_type_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeVerbatim) -> TypeVerbatim {
+ TypeVerbatim { tts: _i.tts }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_un_op<V: Fold + ?Sized>(_visitor: &mut V, _i: UnOp) -> UnOp {
+ match _i {
+ UnOp::Deref(_binding_0) => {
+ UnOp::Deref(Token ! [ * ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ UnOp::Not(_binding_0) => UnOp::Not(Token)),
+ UnOp::Neg(_binding_0) => {
+ UnOp::Neg(Token ! [ - ](tokens_helper(_visitor, &_binding_0.spans)))
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_glob<V: Fold + ?Sized>(_visitor: &mut V, _i: UseGlob) -> UseGlob {
+ UseGlob {
+ star_token: Token ! [ * ](tokens_helper(_visitor, &_i.star_token.spans)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_group<V: Fold + ?Sized>(_visitor: &mut V, _i: UseGroup) -> UseGroup {
+ UseGroup {
+ brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)),
+ items: FoldHelper::lift(_i.items, |it| _visitor.fold_use_tree(it)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_name<V: Fold + ?Sized>(_visitor: &mut V, _i: UseName) -> UseName {
+ UseName {
+ ident: _visitor.fold_ident(_i.ident),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_path<V: Fold + ?Sized>(_visitor: &mut V, _i: UsePath) -> UsePath {
+ UsePath {
+ ident: _visitor.fold_ident(_i.ident),
+ colon2_token: Token ! [ :: ](tokens_helper(_visitor, &_i.colon2_token.spans)),
+ tree: Box::new(_visitor.fold_use_tree(*_i.tree)),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_rename<V: Fold + ?Sized>(_visitor: &mut V, _i: UseRename) -> UseRename {
+ UseRename {
+ ident: _visitor.fold_ident(_i.ident),
+ as_token: Token ! [ as ](tokens_helper(_visitor, &_i.as_token.span)),
+ rename: _visitor.fold_ident(_i.rename),
+ }
+}
+#[cfg(feature = "full")]
+pub fn fold_use_tree<V: Fold + ?Sized>(_visitor: &mut V, _i: UseTree) -> UseTree {
+ match _i {
+ UseTree::Path(_binding_0) => UseTree::Path(_visitor.fold_use_path(_binding_0)),
+ UseTree::Name(_binding_0) => UseTree::Name(_visitor.fold_use_name(_binding_0)),
+ UseTree::Rename(_binding_0) => UseTree::Rename(_visitor.fold_use_rename(_binding_0)),
+ UseTree::Glob(_binding_0) => UseTree::Glob(_visitor.fold_use_glob(_binding_0)),
+ UseTree::Group(_binding_0) => UseTree::Group(_visitor.fold_use_group(_binding_0)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_variant<V: Fold + ?Sized>(_visitor: &mut V, _i: Variant) -> Variant {
+ Variant {
+ attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)),
+ ident: _visitor.fold_ident(_i.ident),
+ fields: _visitor.fold_fields(_i.fields),
+ discriminant: (_i.discriminant).map(|it| {
+ (
+ Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)),
+ _visitor.fold_expr((it).1),
+ )
+ }),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_vis_crate<V: Fold + ?Sized>(_visitor: &mut V, _i: VisCrate) -> VisCrate {
+ VisCrate {
+ crate_token: Token),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_vis_public<V: Fold + ?Sized>(_visitor: &mut V, _i: VisPublic) -> VisPublic {
+ VisPublic {
+ pub_token: Token ! [ pub ](tokens_helper(_visitor, &_i.pub_token.span)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_vis_restricted<V: Fold + ?Sized>(_visitor: &mut V, _i: VisRestricted) -> VisRestricted {
+ VisRestricted {
+ pub_token: Token ! [ pub ](tokens_helper(_visitor, &_i.pub_token.span)),
+ paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)),
+ in_token: (_i.in_token).map(|it| Token ! [ in ](tokens_helper(_visitor, &it.span))),
+ path: Box::new(_visitor.fold_path(*_i.path)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_visibility<V: Fold + ?Sized>(_visitor: &mut V, _i: Visibility) -> Visibility {
+ match _i {
+ Visibility::Public(_binding_0) => Visibility::Public(_visitor.fold_vis_public(_binding_0)),
+ Visibility::Crate(_binding_0) => Visibility::Crate(_visitor.fold_vis_crate(_binding_0)),
+ Visibility::Restricted(_binding_0) => {
+ Visibility::Restricted(_visitor.fold_vis_restricted(_binding_0))
+ }
+ Visibility::Inherited => Visibility::Inherited,
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_where_clause<V: Fold + ?Sized>(_visitor: &mut V, _i: WhereClause) -> WhereClause {
+ WhereClause {
+ where_token: Token ! [ where ](tokens_helper(_visitor, &_i.where_token.span)),
+ predicates: FoldHelper::lift(_i.predicates, |it| _visitor.fold_where_predicate(it)),
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn fold_where_predicate<V: Fold + ?Sized>(
+ _visitor: &mut V,
+ _i: WherePredicate,
+) -> WherePredicate {
+ match _i {
+ WherePredicate::Type(_binding_0) => {
+ WherePredicate::Type(_visitor.fold_predicate_type(_binding_0))
+ }
+ WherePredicate::Lifetime(_binding_0) => {
+ WherePredicate::Lifetime(_visitor.fold_predicate_lifetime(_binding_0))
+ }
+ WherePredicate::Eq(_binding_0) => {
+ WherePredicate::Eq(_visitor.fold_predicate_eq(_binding_0))
+ }
+ }
+}
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
new file mode 100644
index 0000000..7d15422
--- /dev/null
+++ b/src/gen/visit.rs
@@ -0,0 +1,3517 @@
+// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT
+
+#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
+#[cfg(any(feature = "full", feature = "derive"))]
+use gen::helper::visit::*;
+use proc_macro2::Span;
+#[cfg(any(feature = "full", feature = "derive"))]
+use punctuated::Punctuated;
+use *;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! skip {
+ ($($tt:tt)*) => {};
+}
+#[doc = r" Syntax tree traversal to walk a shared borrow of a syntax tree."]
+#[doc = r""]
+#[doc = r" See the [module documentation] for details."]
+#[doc = r""]
+#[doc = r" [module documentation]: index.html"]
+#[doc = r""]
+#[doc = r#" *This trait is available if Syn is built with the `"visit"` feature.*"#]
+pub trait Visit<'ast> {
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_abi(&mut self, i: &'ast Abi) {
+ visit_abi(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_angle_bracketed_generic_arguments(&mut self, i: &'ast AngleBracketedGenericArguments) {
+ visit_angle_bracketed_generic_arguments(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_captured(&mut self, i: &'ast ArgCaptured) {
+ visit_arg_captured(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_self(&mut self, i: &'ast ArgSelf) {
+ visit_arg_self(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_self_ref(&mut self, i: &'ast ArgSelfRef) {
+ visit_arg_self_ref(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_arm(&mut self, i: &'ast Arm) {
+ visit_arm(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_attr_style(&mut self, i: &'ast AttrStyle) {
+ visit_attr_style(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_attribute(&mut self, i: &'ast Attribute) {
+ visit_attribute(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bare_fn_arg(&mut self, i: &'ast BareFnArg) {
+ visit_bare_fn_arg(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bare_fn_arg_name(&mut self, i: &'ast BareFnArgName) {
+ visit_bare_fn_arg_name(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bin_op(&mut self, i: &'ast BinOp) {
+ visit_bin_op(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_binding(&mut self, i: &'ast Binding) {
+ visit_binding(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_block(&mut self, i: &'ast Block) {
+ visit_block(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bound_lifetimes(&mut self, i: &'ast BoundLifetimes) {
+ visit_bound_lifetimes(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_const_param(&mut self, i: &'ast ConstParam) {
+ visit_const_param(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data(&mut self, i: &'ast Data) {
+ visit_data(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_enum(&mut self, i: &'ast DataEnum) {
+ visit_data_enum(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_struct(&mut self, i: &'ast DataStruct) {
+ visit_data_struct(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_union(&mut self, i: &'ast DataUnion) {
+ visit_data_union(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_derive_input(&mut self, i: &'ast DeriveInput) {
+ visit_derive_input(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr(&mut self, i: &'ast Expr) {
+ visit_expr(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_array(&mut self, i: &'ast ExprArray) {
+ visit_expr_array(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_assign(&mut self, i: &'ast ExprAssign) {
+ visit_expr_assign(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_assign_op(&mut self, i: &'ast ExprAssignOp) {
+ visit_expr_assign_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_async(&mut self, i: &'ast ExprAsync) {
+ visit_expr_async(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_binary(&mut self, i: &'ast ExprBinary) {
+ visit_expr_binary(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_block(&mut self, i: &'ast ExprBlock) {
+ visit_expr_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_box(&mut self, i: &'ast ExprBox) {
+ visit_expr_box(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_break(&mut self, i: &'ast ExprBreak) {
+ visit_expr_break(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_call(&mut self, i: &'ast ExprCall) {
+ visit_expr_call(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_cast(&mut self, i: &'ast ExprCast) {
+ visit_expr_cast(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_closure(&mut self, i: &'ast ExprClosure) {
+ visit_expr_closure(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_continue(&mut self, i: &'ast ExprContinue) {
+ visit_expr_continue(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_field(&mut self, i: &'ast ExprField) {
+ visit_expr_field(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_for_loop(&mut self, i: &'ast ExprForLoop) {
+ visit_expr_for_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_group(&mut self, i: &'ast ExprGroup) {
+ visit_expr_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_if(&mut self, i: &'ast ExprIf) {
+ visit_expr_if(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_if_let(&mut self, i: &'ast ExprIfLet) {
+ visit_expr_if_let(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_in_place(&mut self, i: &'ast ExprInPlace) {
+ visit_expr_in_place(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_index(&mut self, i: &'ast ExprIndex) {
+ visit_expr_index(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_lit(&mut self, i: &'ast ExprLit) {
+ visit_expr_lit(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_loop(&mut self, i: &'ast ExprLoop) {
+ visit_expr_loop(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_macro(&mut self, i: &'ast ExprMacro) {
+ visit_expr_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_match(&mut self, i: &'ast ExprMatch) {
+ visit_expr_match(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) {
+ visit_expr_method_call(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_paren(&mut self, i: &'ast ExprParen) {
+ visit_expr_paren(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_path(&mut self, i: &'ast ExprPath) {
+ visit_expr_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_range(&mut self, i: &'ast ExprRange) {
+ visit_expr_range(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_reference(&mut self, i: &'ast ExprReference) {
+ visit_expr_reference(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_repeat(&mut self, i: &'ast ExprRepeat) {
+ visit_expr_repeat(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_return(&mut self, i: &'ast ExprReturn) {
+ visit_expr_return(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_struct(&mut self, i: &'ast ExprStruct) {
+ visit_expr_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_try(&mut self, i: &'ast ExprTry) {
+ visit_expr_try(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_try_block(&mut self, i: &'ast ExprTryBlock) {
+ visit_expr_try_block(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_tuple(&mut self, i: &'ast ExprTuple) {
+ visit_expr_tuple(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_type(&mut self, i: &'ast ExprType) {
+ visit_expr_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_unary(&mut self, i: &'ast ExprUnary) {
+ visit_expr_unary(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_unsafe(&mut self, i: &'ast ExprUnsafe) {
+ visit_expr_unsafe(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_verbatim(&mut self, i: &'ast ExprVerbatim) {
+ visit_expr_verbatim(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_while(&mut self, i: &'ast ExprWhile) {
+ visit_expr_while(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_while_let(&mut self, i: &'ast ExprWhileLet) {
+ visit_expr_while_let(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_yield(&mut self, i: &'ast ExprYield) {
+ visit_expr_yield(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_field(&mut self, i: &'ast Field) {
+ visit_field(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_field_pat(&mut self, i: &'ast FieldPat) {
+ visit_field_pat(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_field_value(&mut self, i: &'ast FieldValue) {
+ visit_field_value(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields(&mut self, i: &'ast Fields) {
+ visit_fields(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields_named(&mut self, i: &'ast FieldsNamed) {
+ visit_fields_named(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields_unnamed(&mut self, i: &'ast FieldsUnnamed) {
+ visit_fields_unnamed(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_file(&mut self, i: &'ast File) {
+ visit_file(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_arg(&mut self, i: &'ast FnArg) {
+ visit_fn_arg(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_decl(&mut self, i: &'ast FnDecl) {
+ visit_fn_decl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
+ visit_foreign_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_fn(&mut self, i: &'ast ForeignItemFn) {
+ visit_foreign_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_macro(&mut self, i: &'ast ForeignItemMacro) {
+ visit_foreign_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_static(&mut self, i: &'ast ForeignItemStatic) {
+ visit_foreign_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_type(&mut self, i: &'ast ForeignItemType) {
+ visit_foreign_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_verbatim(&mut self, i: &'ast ForeignItemVerbatim) {
+ visit_foreign_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generic_argument(&mut self, i: &'ast GenericArgument) {
+ visit_generic_argument(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_generic_method_argument(&mut self, i: &'ast GenericMethodArgument) {
+ visit_generic_method_argument(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generic_param(&mut self, i: &'ast GenericParam) {
+ visit_generic_param(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generics(&mut self, i: &'ast Generics) {
+ visit_generics(self, i)
+ }
+ fn visit_ident(&mut self, i: &'ast Ident) {
+ visit_ident(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item(&mut self, i: &'ast ImplItem) {
+ visit_impl_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_const(&mut self, i: &'ast ImplItemConst) {
+ visit_impl_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_existential(&mut self, i: &'ast ImplItemExistential) {
+ visit_impl_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_macro(&mut self, i: &'ast ImplItemMacro) {
+ visit_impl_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_method(&mut self, i: &'ast ImplItemMethod) {
+ visit_impl_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_type(&mut self, i: &'ast ImplItemType) {
+ visit_impl_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_verbatim(&mut self, i: &'ast ImplItemVerbatim) {
+ visit_impl_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_index(&mut self, i: &'ast Index) {
+ visit_index(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item(&mut self, i: &'ast Item) {
+ visit_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_const(&mut self, i: &'ast ItemConst) {
+ visit_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_enum(&mut self, i: &'ast ItemEnum) {
+ visit_item_enum(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_existential(&mut self, i: &'ast ItemExistential) {
+ visit_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_extern_crate(&mut self, i: &'ast ItemExternCrate) {
+ visit_item_extern_crate(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_fn(&mut self, i: &'ast ItemFn) {
+ visit_item_fn(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_foreign_mod(&mut self, i: &'ast ItemForeignMod) {
+ visit_item_foreign_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_impl(&mut self, i: &'ast ItemImpl) {
+ visit_item_impl(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro(&mut self, i: &'ast ItemMacro) {
+ visit_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro2(&mut self, i: &'ast ItemMacro2) {
+ visit_item_macro2(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mod(&mut self, i: &'ast ItemMod) {
+ visit_item_mod(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_static(&mut self, i: &'ast ItemStatic) {
+ visit_item_static(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_struct(&mut self, i: &'ast ItemStruct) {
+ visit_item_struct(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait(&mut self, i: &'ast ItemTrait) {
+ visit_item_trait(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_type(&mut self, i: &'ast ItemType) {
+ visit_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_union(&mut self, i: &'ast ItemUnion) {
+ visit_item_union(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_use(&mut self, i: &'ast ItemUse) {
+ visit_item_use(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_verbatim(&mut self, i: &'ast ItemVerbatim) {
+ visit_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_label(&mut self, i: &'ast Label) {
+ visit_label(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lifetime(&mut self, i: &'ast Lifetime) {
+ visit_lifetime(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lifetime_def(&mut self, i: &'ast LifetimeDef) {
+ visit_lifetime_def(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit(&mut self, i: &'ast Lit) {
+ visit_lit(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_bool(&mut self, i: &'ast LitBool) {
+ visit_lit_bool(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_byte(&mut self, i: &'ast LitByte) {
+ visit_lit_byte(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_byte_str(&mut self, i: &'ast LitByteStr) {
+ visit_lit_byte_str(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_char(&mut self, i: &'ast LitChar) {
+ visit_lit_char(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_float(&mut self, i: &'ast LitFloat) {
+ visit_lit_float(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_int(&mut self, i: &'ast LitInt) {
+ visit_lit_int(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_str(&mut self, i: &'ast LitStr) {
+ visit_lit_str(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_verbatim(&mut self, i: &'ast LitVerbatim) {
+ visit_lit_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_local(&mut self, i: &'ast Local) {
+ visit_local(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_macro(&mut self, i: &'ast Macro) {
+ visit_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_macro_delimiter(&mut self, i: &'ast MacroDelimiter) {
+ visit_macro_delimiter(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_member(&mut self, i: &'ast Member) {
+ visit_member(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta(&mut self, i: &'ast Meta) {
+ visit_meta(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta_list(&mut self, i: &'ast MetaList) {
+ visit_meta_list(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta_name_value(&mut self, i: &'ast MetaNameValue) {
+ visit_meta_name_value(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_method_sig(&mut self, i: &'ast MethodSig) {
+ visit_method_sig(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_method_turbofish(&mut self, i: &'ast MethodTurbofish) {
+ visit_method_turbofish(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_nested_meta(&mut self, i: &'ast NestedMeta) {
+ visit_nested_meta(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_parenthesized_generic_arguments(&mut self, i: &'ast ParenthesizedGenericArguments) {
+ visit_parenthesized_generic_arguments(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat(&mut self, i: &'ast Pat) {
+ visit_pat(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_box(&mut self, i: &'ast PatBox) {
+ visit_pat_box(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_ident(&mut self, i: &'ast PatIdent) {
+ visit_pat_ident(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_lit(&mut self, i: &'ast PatLit) {
+ visit_pat_lit(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_macro(&mut self, i: &'ast PatMacro) {
+ visit_pat_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_path(&mut self, i: &'ast PatPath) {
+ visit_pat_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_range(&mut self, i: &'ast PatRange) {
+ visit_pat_range(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_ref(&mut self, i: &'ast PatRef) {
+ visit_pat_ref(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_slice(&mut self, i: &'ast PatSlice) {
+ visit_pat_slice(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_struct(&mut self, i: &'ast PatStruct) {
+ visit_pat_struct(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple(&mut self, i: &'ast PatTuple) {
+ visit_pat_tuple(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_struct(&mut self, i: &'ast PatTupleStruct) {
+ visit_pat_tuple_struct(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_verbatim(&mut self, i: &'ast PatVerbatim) {
+ visit_pat_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_wild(&mut self, i: &'ast PatWild) {
+ visit_pat_wild(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path(&mut self, i: &'ast Path) {
+ visit_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path_arguments(&mut self, i: &'ast PathArguments) {
+ visit_path_arguments(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path_segment(&mut self, i: &'ast PathSegment) {
+ visit_path_segment(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_eq(&mut self, i: &'ast PredicateEq) {
+ visit_predicate_eq(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_lifetime(&mut self, i: &'ast PredicateLifetime) {
+ visit_predicate_lifetime(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_type(&mut self, i: &'ast PredicateType) {
+ visit_predicate_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_qself(&mut self, i: &'ast QSelf) {
+ visit_qself(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_range_limits(&mut self, i: &'ast RangeLimits) {
+ visit_range_limits(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_return_type(&mut self, i: &'ast ReturnType) {
+ visit_return_type(self, i)
+ }
+ fn visit_span(&mut self, i: &'ast Span) {
+ visit_span(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_stmt(&mut self, i: &'ast Stmt) {
+ visit_stmt(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_trait_bound(&mut self, i: &'ast TraitBound) {
+ visit_trait_bound(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_trait_bound_modifier(&mut self, i: &'ast TraitBoundModifier) {
+ visit_trait_bound_modifier(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item(&mut self, i: &'ast TraitItem) {
+ visit_trait_item(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_const(&mut self, i: &'ast TraitItemConst) {
+ visit_trait_item_const(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_existential(&mut self, i: &'ast TraitItemExistential) {
+ visit_trait_item_existential(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_macro(&mut self, i: &'ast TraitItemMacro) {
+ visit_trait_item_macro(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_method(&mut self, i: &'ast TraitItemMethod) {
+ visit_trait_item_method(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_type(&mut self, i: &'ast TraitItemType) {
+ visit_trait_item_type(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_verbatim(&mut self, i: &'ast TraitItemVerbatim) {
+ visit_trait_item_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type(&mut self, i: &'ast Type) {
+ visit_type(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_array(&mut self, i: &'ast TypeArray) {
+ visit_type_array(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_bare_fn(&mut self, i: &'ast TypeBareFn) {
+ visit_type_bare_fn(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_group(&mut self, i: &'ast TypeGroup) {
+ visit_type_group(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_impl_trait(&mut self, i: &'ast TypeImplTrait) {
+ visit_type_impl_trait(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_infer(&mut self, i: &'ast TypeInfer) {
+ visit_type_infer(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_macro(&mut self, i: &'ast TypeMacro) {
+ visit_type_macro(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_never(&mut self, i: &'ast TypeNever) {
+ visit_type_never(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_param(&mut self, i: &'ast TypeParam) {
+ visit_type_param(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_param_bound(&mut self, i: &'ast TypeParamBound) {
+ visit_type_param_bound(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_paren(&mut self, i: &'ast TypeParen) {
+ visit_type_paren(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_path(&mut self, i: &'ast TypePath) {
+ visit_type_path(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_ptr(&mut self, i: &'ast TypePtr) {
+ visit_type_ptr(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_reference(&mut self, i: &'ast TypeReference) {
+ visit_type_reference(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_slice(&mut self, i: &'ast TypeSlice) {
+ visit_type_slice(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_trait_object(&mut self, i: &'ast TypeTraitObject) {
+ visit_type_trait_object(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_tuple(&mut self, i: &'ast TypeTuple) {
+ visit_type_tuple(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_verbatim(&mut self, i: &'ast TypeVerbatim) {
+ visit_type_verbatim(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_un_op(&mut self, i: &'ast UnOp) {
+ visit_un_op(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_glob(&mut self, i: &'ast UseGlob) {
+ visit_use_glob(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_group(&mut self, i: &'ast UseGroup) {
+ visit_use_group(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_name(&mut self, i: &'ast UseName) {
+ visit_use_name(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_path(&mut self, i: &'ast UsePath) {
+ visit_use_path(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_rename(&mut self, i: &'ast UseRename) {
+ visit_use_rename(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_tree(&mut self, i: &'ast UseTree) {
+ visit_use_tree(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_variant(&mut self, i: &'ast Variant) {
+ visit_variant(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_crate(&mut self, i: &'ast VisCrate) {
+ visit_vis_crate(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_public(&mut self, i: &'ast VisPublic) {
+ visit_vis_public(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_restricted(&mut self, i: &'ast VisRestricted) {
+ visit_vis_restricted(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_visibility(&mut self, i: &'ast Visibility) {
+ visit_visibility(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_where_clause(&mut self, i: &'ast WhereClause) {
+ visit_where_clause(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_where_predicate(&mut self, i: &'ast WherePredicate) {
+ visit_where_predicate(self, i)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_abi<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Abi) {
+ tokens_helper(_visitor, &_i.extern_token.span);
+ if let Some(ref it) = _i.name {
+ _visitor.visit_lit_str(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_angle_bracketed_generic_arguments<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast AngleBracketedGenericArguments,
+) {
+ if let Some(ref it) = _i.colon2_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ tokens_helper(_visitor, &_i.lt_token.spans);
+ for el in Punctuated::pairs(&_i.args) {
+ let it = el.value();
+ _visitor.visit_generic_argument(it)
+ }
+ tokens_helper(_visitor, &_i.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_captured<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgCaptured) {
+ _visitor.visit_pat(&_i.pat);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&_i.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_self<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgSelf) {
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.self_token.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_self_ref<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgSelfRef) {
+ tokens_helper(_visitor, &_i.and_token.spans);
+ if let Some(ref it) = _i.lifetime {
+ _visitor.visit_lifetime(it)
+ };
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.self_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_arm<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Arm) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.leading_vert {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.pats) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ if let Some(ref it) = _i.guard {
+ tokens_helper(_visitor, &(it).0.span);
+ _visitor.visit_expr(&*(it).1);
+ };
+ tokens_helper(_visitor, &_i.fat_arrow_token.spans);
+ _visitor.visit_expr(&*_i.body);
+ if let Some(ref it) = _i.comma {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_attr_style<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast AttrStyle) {
+ match *_i {
+ AttrStyle::Outer => {}
+ AttrStyle::Inner(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_attribute<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Attribute) {
+ tokens_helper(_visitor, &_i.pound_token.spans);
+ _visitor.visit_attr_style(&_i.style);
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ _visitor.visit_path(&_i.path);
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bare_fn_arg<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast BareFnArg) {
+ if let Some(ref it) = _i.name {
+ _visitor.visit_bare_fn_arg_name(&(it).0);
+ tokens_helper(_visitor, &(it).1.spans);
+ };
+ _visitor.visit_type(&_i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bare_fn_arg_name<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast BareFnArgName,
+) {
+ match *_i {
+ BareFnArgName::Named(ref _binding_0) => {
+ _visitor.visit_ident(_binding_0);
+ }
+ BareFnArgName::Wild(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bin_op<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast BinOp) {
+ match *_i {
+ BinOp::Add(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Sub(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Mul(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Div(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Rem(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::And(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Or(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitXor(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitAnd(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitOr(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Shl(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Shr(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Eq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Lt(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Le(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Ne(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Ge(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::Gt(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::AddEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::SubEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::MulEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::DivEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::RemEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitXorEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitAndEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::BitOrEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::ShlEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ BinOp::ShrEq(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_binding<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Binding) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_type(&_i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_block<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Block) {
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for it in &_i.stmts {
+ _visitor.visit_stmt(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bound_lifetimes<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast BoundLifetimes,
+) {
+ tokens_helper(_visitor, &_i.for_token.span);
+ tokens_helper(_visitor, &_i.lt_token.spans);
+ for el in Punctuated::pairs(&_i.lifetimes) {
+ let it = el.value();
+ _visitor.visit_lifetime_def(it)
+ }
+ tokens_helper(_visitor, &_i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_const_param<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ConstParam) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.const_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&_i.ty);
+ if let Some(ref it) = _i.eq_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.default {
+ _visitor.visit_expr(it)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Data) {
+ match *_i {
+ Data::Struct(ref _binding_0) => {
+ _visitor.visit_data_struct(_binding_0);
+ }
+ Data::Enum(ref _binding_0) => {
+ _visitor.visit_data_enum(_binding_0);
+ }
+ Data::Union(ref _binding_0) => {
+ _visitor.visit_data_union(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_enum<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataEnum) {
+ tokens_helper(_visitor, &_i.enum_token.span);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.variants) {
+ let it = el.value();
+ _visitor.visit_variant(it)
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataStruct) {
+ tokens_helper(_visitor, &_i.struct_token.span);
+ _visitor.visit_fields(&_i.fields);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_union<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataUnion) {
+ tokens_helper(_visitor, &_i.union_token.span);
+ _visitor.visit_fields_named(&_i.fields);
+}
+#[cfg(feature = "derive")]
+pub fn visit_derive_input<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DeriveInput) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ _visitor.visit_data(&_i.data);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Expr) {
+ match *_i {
+ Expr::Box(ref _binding_0) => {
+ full!(_visitor.visit_expr_box(_binding_0));
+ }
+ Expr::InPlace(ref _binding_0) => {
+ full!(_visitor.visit_expr_in_place(_binding_0));
+ }
+ Expr::Array(ref _binding_0) => {
+ full!(_visitor.visit_expr_array(_binding_0));
+ }
+ Expr::Call(ref _binding_0) => {
+ _visitor.visit_expr_call(_binding_0);
+ }
+ Expr::MethodCall(ref _binding_0) => {
+ full!(_visitor.visit_expr_method_call(_binding_0));
+ }
+ Expr::Tuple(ref _binding_0) => {
+ full!(_visitor.visit_expr_tuple(_binding_0));
+ }
+ Expr::Binary(ref _binding_0) => {
+ _visitor.visit_expr_binary(_binding_0);
+ }
+ Expr::Unary(ref _binding_0) => {
+ _visitor.visit_expr_unary(_binding_0);
+ }
+ Expr::Lit(ref _binding_0) => {
+ _visitor.visit_expr_lit(_binding_0);
+ }
+ Expr::Cast(ref _binding_0) => {
+ _visitor.visit_expr_cast(_binding_0);
+ }
+ Expr::Type(ref _binding_0) => {
+ full!(_visitor.visit_expr_type(_binding_0));
+ }
+ Expr::If(ref _binding_0) => {
+ full!(_visitor.visit_expr_if(_binding_0));
+ }
+ Expr::IfLet(ref _binding_0) => {
+ full!(_visitor.visit_expr_if_let(_binding_0));
+ }
+ Expr::While(ref _binding_0) => {
+ full!(_visitor.visit_expr_while(_binding_0));
+ }
+ Expr::WhileLet(ref _binding_0) => {
+ full!(_visitor.visit_expr_while_let(_binding_0));
+ }
+ Expr::ForLoop(ref _binding_0) => {
+ full!(_visitor.visit_expr_for_loop(_binding_0));
+ }
+ Expr::Loop(ref _binding_0) => {
+ full!(_visitor.visit_expr_loop(_binding_0));
+ }
+ Expr::Match(ref _binding_0) => {
+ full!(_visitor.visit_expr_match(_binding_0));
+ }
+ Expr::Closure(ref _binding_0) => {
+ full!(_visitor.visit_expr_closure(_binding_0));
+ }
+ Expr::Unsafe(ref _binding_0) => {
+ full!(_visitor.visit_expr_unsafe(_binding_0));
+ }
+ Expr::Block(ref _binding_0) => {
+ full!(_visitor.visit_expr_block(_binding_0));
+ }
+ Expr::Assign(ref _binding_0) => {
+ full!(_visitor.visit_expr_assign(_binding_0));
+ }
+ Expr::AssignOp(ref _binding_0) => {
+ full!(_visitor.visit_expr_assign_op(_binding_0));
+ }
+ Expr::Field(ref _binding_0) => {
+ _visitor.visit_expr_field(_binding_0);
+ }
+ Expr::Index(ref _binding_0) => {
+ _visitor.visit_expr_index(_binding_0);
+ }
+ Expr::Range(ref _binding_0) => {
+ full!(_visitor.visit_expr_range(_binding_0));
+ }
+ Expr::Path(ref _binding_0) => {
+ _visitor.visit_expr_path(_binding_0);
+ }
+ Expr::Reference(ref _binding_0) => {
+ full!(_visitor.visit_expr_reference(_binding_0));
+ }
+ Expr::Break(ref _binding_0) => {
+ full!(_visitor.visit_expr_break(_binding_0));
+ }
+ Expr::Continue(ref _binding_0) => {
+ full!(_visitor.visit_expr_continue(_binding_0));
+ }
+ Expr::Return(ref _binding_0) => {
+ full!(_visitor.visit_expr_return(_binding_0));
+ }
+ Expr::Macro(ref _binding_0) => {
+ full!(_visitor.visit_expr_macro(_binding_0));
+ }
+ Expr::Struct(ref _binding_0) => {
+ full!(_visitor.visit_expr_struct(_binding_0));
+ }
+ Expr::Repeat(ref _binding_0) => {
+ full!(_visitor.visit_expr_repeat(_binding_0));
+ }
+ Expr::Paren(ref _binding_0) => {
+ _visitor.visit_expr_paren(_binding_0);
+ }
+ Expr::Group(ref _binding_0) => {
+ full!(_visitor.visit_expr_group(_binding_0));
+ }
+ Expr::Try(ref _binding_0) => {
+ full!(_visitor.visit_expr_try(_binding_0));
+ }
+ Expr::Async(ref _binding_0) => {
+ full!(_visitor.visit_expr_async(_binding_0));
+ }
+ Expr::TryBlock(ref _binding_0) => {
+ full!(_visitor.visit_expr_try_block(_binding_0));
+ }
+ Expr::Yield(ref _binding_0) => {
+ full!(_visitor.visit_expr_yield(_binding_0));
+ }
+ Expr::Verbatim(ref _binding_0) => {
+ _visitor.visit_expr_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_array<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprArray) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ for el in Punctuated::pairs(&_i.elems) {
+ let it = el.value();
+ _visitor.visit_expr(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_assign<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprAssign) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.left);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&*_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_assign_op<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprAssignOp,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.left);
+ _visitor.visit_bin_op(&_i.op);
+ _visitor.visit_expr(&*_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_async<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprAsync) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.async_token.span);
+ if let Some(ref it) = _i.capture {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_block(&_i.block);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_binary<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBinary) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.left);
+ _visitor.visit_bin_op(&_i.op);
+ _visitor.visit_expr(&*_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_block<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBlock) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.label {
+ _visitor.visit_label(it)
+ };
+ _visitor.visit_block(&_i.block);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_box<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBox) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.box_token.span);
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_break<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBreak) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.break_token.span);
+ if let Some(ref it) = _i.label {
+ _visitor.visit_lifetime(it)
+ };
+ if let Some(ref it) = _i.expr {
+ _visitor.visit_expr(&**it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_call<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprCall) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.func);
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.args) {
+ let it = el.value();
+ _visitor.visit_expr(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_cast<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprCast) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.as_token.span);
+ _visitor.visit_type(&*_i.ty);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_closure<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprClosure) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.asyncness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.movability {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.capture {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.or1_token.spans);
+ for el in Punctuated::pairs(&_i.inputs) {
+ let it = el.value();
+ _visitor.visit_fn_arg(it)
+ }
+ tokens_helper(_visitor, &_i.or2_token.spans);
+ _visitor.visit_return_type(&_i.output);
+ _visitor.visit_expr(&*_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_continue<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprContinue,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.continue_token.span);
+ if let Some(ref it) = _i.label {
+ _visitor.visit_lifetime(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_field<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprField) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.base);
+ tokens_helper(_visitor, &_i.dot_token.spans);
+ _visitor.visit_member(&_i.member);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_for_loop<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprForLoop) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.label {
+ _visitor.visit_label(it)
+ };
+ tokens_helper(_visitor, &_i.for_token.span);
+ _visitor.visit_pat(&*_i.pat);
+ tokens_helper(_visitor, &_i.in_token.span);
+ _visitor.visit_expr(&*_i.expr);
+ _visitor.visit_block(&_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprGroup) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.group_token.span);
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_if<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIf) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.if_token.span);
+ _visitor.visit_expr(&*_i.cond);
+ _visitor.visit_block(&_i.then_branch);
+ if let Some(ref it) = _i.else_branch {
+ tokens_helper(_visitor, &(it).0.span);
+ _visitor.visit_expr(&*(it).1);
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_if_let<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIfLet) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.if_token.span);
+ tokens_helper(_visitor, &_i.let_token.span);
+ for el in Punctuated::pairs(&_i.pats) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&*_i.expr);
+ _visitor.visit_block(&_i.then_branch);
+ if let Some(ref it) = _i.else_branch {
+ tokens_helper(_visitor, &(it).0.span);
+ _visitor.visit_expr(&*(it).1);
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_in_place<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprInPlace) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.place);
+ tokens_helper(_visitor, &_i.arrow_token.spans);
+ _visitor.visit_expr(&*_i.value);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_index<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIndex) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ _visitor.visit_expr(&*_i.index);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLit) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_lit(&_i.lit);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_loop<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLoop) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.label {
+ _visitor.visit_label(it)
+ };
+ tokens_helper(_visitor, &_i.loop_token.span);
+ _visitor.visit_block(&_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprMacro) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_macro(&_i.mac);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_match<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprMatch) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.match_token.span);
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for it in &_i.arms {
+ _visitor.visit_arm(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_method_call<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprMethodCall,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.receiver);
+ tokens_helper(_visitor, &_i.dot_token.spans);
+ _visitor.visit_ident(&_i.method);
+ if let Some(ref it) = _i.turbofish {
+ _visitor.visit_method_turbofish(it)
+ };
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.args) {
+ let it = el.value();
+ _visitor.visit_expr(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_paren<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprParen) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.paren_token.span);
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprPath) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.qself {
+ _visitor.visit_qself(it)
+ };
+ _visitor.visit_path(&_i.path);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_range<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprRange) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.from {
+ _visitor.visit_expr(&**it)
+ };
+ _visitor.visit_range_limits(&_i.limits);
+ if let Some(ref it) = _i.to {
+ _visitor.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_reference<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprReference,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.and_token.spans);
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_repeat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprRepeat) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+ _visitor.visit_expr(&*_i.len);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_return<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprReturn) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.return_token.span);
+ if let Some(ref it) = _i.expr {
+ _visitor.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprStruct) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_path(&_i.path);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.fields) {
+ let it = el.value();
+ _visitor.visit_field_value(it)
+ }
+ if let Some(ref it) = _i.dot2_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.rest {
+ _visitor.visit_expr(&**it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_try<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprTry) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.question_token.spans);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_try_block<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprTryBlock,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.try_token.span);
+ _visitor.visit_block(&_i.block);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprTuple) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.elems) {
+ let it = el.value();
+ _visitor.visit_expr(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprType) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&*_i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_unary<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprUnary) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_un_op(&_i.op);
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_unsafe<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprUnsafe) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.unsafe_token.span);
+ _visitor.visit_block(&_i.block);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_while<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprWhile) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.label {
+ _visitor.visit_label(it)
+ };
+ tokens_helper(_visitor, &_i.while_token.span);
+ _visitor.visit_expr(&*_i.cond);
+ _visitor.visit_block(&_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_while_let<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ExprWhileLet,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.label {
+ _visitor.visit_label(it)
+ };
+ tokens_helper(_visitor, &_i.while_token.span);
+ tokens_helper(_visitor, &_i.let_token.span);
+ for el in Punctuated::pairs(&_i.pats) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&*_i.expr);
+ _visitor.visit_block(&_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_yield<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprYield) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.yield_token.span);
+ if let Some(ref it) = _i.expr {
+ _visitor.visit_expr(&**it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_field<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Field) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.ident {
+ _visitor.visit_ident(it)
+ };
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_type(&_i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_field_pat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldPat) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_member(&_i.member);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_pat(&*_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_field_value<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldValue) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_member(&_i.member);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_expr(&_i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Fields) {
+ match *_i {
+ Fields::Named(ref _binding_0) => {
+ _visitor.visit_fields_named(_binding_0);
+ }
+ Fields::Unnamed(ref _binding_0) => {
+ _visitor.visit_fields_unnamed(_binding_0);
+ }
+ Fields::Unit => {}
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields_named<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldsNamed) {
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.named) {
+ let it = el.value();
+ _visitor.visit_field(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields_unnamed<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast FieldsUnnamed,
+) {
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.unnamed) {
+ let it = el.value();
+ _visitor.visit_field(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_file<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast File) {
+ skip!(_i.shebang);
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ for it in &_i.items {
+ _visitor.visit_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_arg<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FnArg) {
+ match *_i {
+ FnArg::SelfRef(ref _binding_0) => {
+ _visitor.visit_arg_self_ref(_binding_0);
+ }
+ FnArg::SelfValue(ref _binding_0) => {
+ _visitor.visit_arg_self(_binding_0);
+ }
+ FnArg::Captured(ref _binding_0) => {
+ _visitor.visit_arg_captured(_binding_0);
+ }
+ FnArg::Inferred(ref _binding_0) => {
+ _visitor.visit_pat(_binding_0);
+ }
+ FnArg::Ignored(ref _binding_0) => {
+ _visitor.visit_type(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_decl<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FnDecl) {
+ tokens_helper(_visitor, &_i.fn_token.span);
+ _visitor.visit_generics(&_i.generics);
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.inputs) {
+ let it = el.value();
+ _visitor.visit_fn_arg(it)
+ }
+ if let Some(ref it) = _i.variadic {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_return_type(&_i.output);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ForeignItem) {
+ match *_i {
+ ForeignItem::Fn(ref _binding_0) => {
+ _visitor.visit_foreign_item_fn(_binding_0);
+ }
+ ForeignItem::Static(ref _binding_0) => {
+ _visitor.visit_foreign_item_static(_binding_0);
+ }
+ ForeignItem::Type(ref _binding_0) => {
+ _visitor.visit_foreign_item_type(_binding_0);
+ }
+ ForeignItem::Macro(ref _binding_0) => {
+ _visitor.visit_foreign_item_macro(_binding_0);
+ }
+ ForeignItem::Verbatim(ref _binding_0) => {
+ _visitor.visit_foreign_item_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_fn<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ForeignItemFn,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_fn_decl(&*_i.decl);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_macro<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ForeignItemMacro,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_macro(&_i.mac);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_static<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ForeignItemStatic,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.static_token.span);
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&*_i.ty);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_type<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ForeignItemType,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ForeignItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generic_argument<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast GenericArgument,
+) {
+ match *_i {
+ GenericArgument::Lifetime(ref _binding_0) => {
+ _visitor.visit_lifetime(_binding_0);
+ }
+ GenericArgument::Type(ref _binding_0) => {
+ _visitor.visit_type(_binding_0);
+ }
+ GenericArgument::Binding(ref _binding_0) => {
+ _visitor.visit_binding(_binding_0);
+ }
+ GenericArgument::Const(ref _binding_0) => {
+ _visitor.visit_expr(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_generic_method_argument<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast GenericMethodArgument,
+) {
+ match *_i {
+ GenericMethodArgument::Type(ref _binding_0) => {
+ _visitor.visit_type(_binding_0);
+ }
+ GenericMethodArgument::Const(ref _binding_0) => {
+ _visitor.visit_expr(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generic_param<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast GenericParam,
+) {
+ match *_i {
+ GenericParam::Type(ref _binding_0) => {
+ _visitor.visit_type_param(_binding_0);
+ }
+ GenericParam::Lifetime(ref _binding_0) => {
+ _visitor.visit_lifetime_def(_binding_0);
+ }
+ GenericParam::Const(ref _binding_0) => {
+ _visitor.visit_const_param(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generics<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Generics) {
+ if let Some(ref it) = _i.lt_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.params) {
+ let it = el.value();
+ _visitor.visit_generic_param(it)
+ }
+ if let Some(ref it) = _i.gt_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.where_clause {
+ _visitor.visit_where_clause(it)
+ };
+}
+pub fn visit_ident<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Ident) {}
+#[cfg(feature = "full")]
+pub fn visit_impl_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ImplItem) {
+ match *_i {
+ ImplItem::Const(ref _binding_0) => {
+ _visitor.visit_impl_item_const(_binding_0);
+ }
+ ImplItem::Method(ref _binding_0) => {
+ _visitor.visit_impl_item_method(_binding_0);
+ }
+ ImplItem::Type(ref _binding_0) => {
+ _visitor.visit_impl_item_type(_binding_0);
+ }
+ ImplItem::Existential(ref _binding_0) => {
+ _visitor.visit_impl_item_existential(_binding_0);
+ }
+ ImplItem::Macro(ref _binding_0) => {
+ _visitor.visit_impl_item_macro(_binding_0);
+ }
+ ImplItem::Verbatim(ref _binding_0) => {
+ _visitor.visit_impl_item_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_const<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemConst,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.defaultness {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.const_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&_i.ty);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&_i.expr);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_existential<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemExistential,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.existential_token.span);
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_macro<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemMacro,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_macro(&_i.mac);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_method<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemMethod,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.defaultness {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_method_sig(&_i.sig);
+ _visitor.visit_block(&_i.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_type<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemType,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.defaultness {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_type(&_i.ty);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ImplItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_index<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Index) {
+ skip!(_i.index);
+ _visitor.visit_span(&_i.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Item) {
+ match *_i {
+ Item::ExternCrate(ref _binding_0) => {
+ _visitor.visit_item_extern_crate(_binding_0);
+ }
+ Item::Use(ref _binding_0) => {
+ _visitor.visit_item_use(_binding_0);
+ }
+ Item::Static(ref _binding_0) => {
+ _visitor.visit_item_static(_binding_0);
+ }
+ Item::Const(ref _binding_0) => {
+ _visitor.visit_item_const(_binding_0);
+ }
+ Item::Fn(ref _binding_0) => {
+ _visitor.visit_item_fn(_binding_0);
+ }
+ Item::Mod(ref _binding_0) => {
+ _visitor.visit_item_mod(_binding_0);
+ }
+ Item::ForeignMod(ref _binding_0) => {
+ _visitor.visit_item_foreign_mod(_binding_0);
+ }
+ Item::Type(ref _binding_0) => {
+ _visitor.visit_item_type(_binding_0);
+ }
+ Item::Existential(ref _binding_0) => {
+ _visitor.visit_item_existential(_binding_0);
+ }
+ Item::Struct(ref _binding_0) => {
+ _visitor.visit_item_struct(_binding_0);
+ }
+ Item::Enum(ref _binding_0) => {
+ _visitor.visit_item_enum(_binding_0);
+ }
+ Item::Union(ref _binding_0) => {
+ _visitor.visit_item_union(_binding_0);
+ }
+ Item::Trait(ref _binding_0) => {
+ _visitor.visit_item_trait(_binding_0);
+ }
+ Item::Impl(ref _binding_0) => {
+ _visitor.visit_item_impl(_binding_0);
+ }
+ Item::Macro(ref _binding_0) => {
+ _visitor.visit_item_macro(_binding_0);
+ }
+ Item::Macro2(ref _binding_0) => {
+ _visitor.visit_item_macro2(_binding_0);
+ }
+ Item::Verbatim(ref _binding_0) => {
+ _visitor.visit_item_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_const<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemConst) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.const_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&*_i.ty);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_enum<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemEnum) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.enum_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.variants) {
+ let it = el.value();
+ _visitor.visit_variant(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_existential<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ItemExistential,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.existential_token.span);
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_extern_crate<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ItemExternCrate,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.extern_token.span);
+ tokens_helper(_visitor, &_i.crate_token.span);
+ _visitor.visit_ident(&_i.ident);
+ if let Some(ref it) = _i.rename {
+ tokens_helper(_visitor, &(it).0.span);
+ _visitor.visit_ident(&(it).1);
+ };
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_fn<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemFn) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.constness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.unsafety {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.asyncness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.abi {
+ _visitor.visit_abi(it)
+ };
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_fn_decl(&*_i.decl);
+ _visitor.visit_block(&*_i.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_foreign_mod<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ItemForeignMod,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_abi(&_i.abi);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for it in &_i.items {
+ _visitor.visit_foreign_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_impl<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemImpl) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.defaultness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.unsafety {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.impl_token.span);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.trait_ {
+ if let Some(ref it) = (it).0 {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_path(&(it).1);
+ tokens_helper(_visitor, &(it).2.span);
+ };
+ _visitor.visit_type(&*_i.self_ty);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for it in &_i.items {
+ _visitor.visit_impl_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMacro) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ if let Some(ref it) = _i.ident {
+ _visitor.visit_ident(it)
+ };
+ _visitor.visit_macro(&_i.mac);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro2<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMacro2) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.macro_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.paren_token.span);
+ skip!(_i.args);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ skip!(_i.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mod<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMod) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.mod_token.span);
+ _visitor.visit_ident(&_i.ident);
+ if let Some(ref it) = _i.content {
+ tokens_helper(_visitor, &(it).0.span);
+ for it in &(it).1 {
+ _visitor.visit_item(it)
+ }
+ };
+ if let Some(ref it) = _i.semi {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_static<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemStatic) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.static_token.span);
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&*_i.ty);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_expr(&*_i.expr);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemStruct) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.struct_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ _visitor.visit_fields(&_i.fields);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemTrait) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ if let Some(ref it) = _i.unsafety {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.auto_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.trait_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.supertraits) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for it in &_i.items {
+ _visitor.visit_trait_item(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemType) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_type(&*_i.ty);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_union<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemUnion) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.union_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ _visitor.visit_fields_named(&_i.fields);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_use<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemUse) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_visibility(&_i.vis);
+ tokens_helper(_visitor, &_i.use_token.span);
+ if let Some(ref it) = _i.leading_colon {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_use_tree(&_i.tree);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_label<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Label) {
+ _visitor.visit_lifetime(&_i.name);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lifetime<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Lifetime) {
+ skip!(_i.apostrophe);
+ _visitor.visit_ident(&_i.ident);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lifetime_def<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LifetimeDef) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_lifetime(&_i.lifetime);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_lifetime(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Lit) {
+ match *_i {
+ Lit::Str(ref _binding_0) => {
+ _visitor.visit_lit_str(_binding_0);
+ }
+ Lit::ByteStr(ref _binding_0) => {
+ _visitor.visit_lit_byte_str(_binding_0);
+ }
+ Lit::Byte(ref _binding_0) => {
+ _visitor.visit_lit_byte(_binding_0);
+ }
+ Lit::Char(ref _binding_0) => {
+ _visitor.visit_lit_char(_binding_0);
+ }
+ Lit::Int(ref _binding_0) => {
+ _visitor.visit_lit_int(_binding_0);
+ }
+ Lit::Float(ref _binding_0) => {
+ _visitor.visit_lit_float(_binding_0);
+ }
+ Lit::Bool(ref _binding_0) => {
+ _visitor.visit_lit_bool(_binding_0);
+ }
+ Lit::Verbatim(ref _binding_0) => {
+ _visitor.visit_lit_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_bool<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitBool) {
+ skip!(_i.value);
+ _visitor.visit_span(&_i.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_byte<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitByte) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_byte_str<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitByteStr) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_char<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitChar) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_float<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitFloat) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_int<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitInt) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_str<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitStr) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_verbatim<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitVerbatim) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_local<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Local) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.let_token.span);
+ for el in Punctuated::pairs(&_i.pats) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ if let Some(ref it) = _i.ty {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_type(&*(it).1);
+ };
+ if let Some(ref it) = _i.init {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_expr(&*(it).1);
+ };
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Macro) {
+ _visitor.visit_path(&_i.path);
+ tokens_helper(_visitor, &_i.bang_token.spans);
+ _visitor.visit_macro_delimiter(&_i.delimiter);
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_macro_delimiter<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast MacroDelimiter,
+) {
+ match *_i {
+ MacroDelimiter::Paren(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.span);
+ }
+ MacroDelimiter::Brace(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.span);
+ }
+ MacroDelimiter::Bracket(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.span);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_member<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Member) {
+ match *_i {
+ Member::Named(ref _binding_0) => {
+ _visitor.visit_ident(_binding_0);
+ }
+ Member::Unnamed(ref _binding_0) => {
+ _visitor.visit_index(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Meta) {
+ match *_i {
+ Meta::Word(ref _binding_0) => {
+ _visitor.visit_ident(_binding_0);
+ }
+ Meta::List(ref _binding_0) => {
+ _visitor.visit_meta_list(_binding_0);
+ }
+ Meta::NameValue(ref _binding_0) => {
+ _visitor.visit_meta_name_value(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta_list<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast MetaList) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.nested) {
+ let it = el.value();
+ _visitor.visit_nested_meta(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta_name_value<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast MetaNameValue,
+) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_lit(&_i.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_method_sig<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast MethodSig) {
+ if let Some(ref it) = _i.constness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.unsafety {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.asyncness {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.abi {
+ _visitor.visit_abi(it)
+ };
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_fn_decl(&_i.decl);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_method_turbofish<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast MethodTurbofish,
+) {
+ tokens_helper(_visitor, &_i.colon2_token.spans);
+ tokens_helper(_visitor, &_i.lt_token.spans);
+ for el in Punctuated::pairs(&_i.args) {
+ let it = el.value();
+ _visitor.visit_generic_method_argument(it)
+ }
+ tokens_helper(_visitor, &_i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_nested_meta<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast NestedMeta) {
+ match *_i {
+ NestedMeta::Meta(ref _binding_0) => {
+ _visitor.visit_meta(_binding_0);
+ }
+ NestedMeta::Literal(ref _binding_0) => {
+ _visitor.visit_lit(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_parenthesized_generic_arguments<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast ParenthesizedGenericArguments,
+) {
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.inputs) {
+ let it = el.value();
+ _visitor.visit_type(it)
+ }
+ _visitor.visit_return_type(&_i.output);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Pat) {
+ match *_i {
+ Pat::Wild(ref _binding_0) => {
+ _visitor.visit_pat_wild(_binding_0);
+ }
+ Pat::Ident(ref _binding_0) => {
+ _visitor.visit_pat_ident(_binding_0);
+ }
+ Pat::Struct(ref _binding_0) => {
+ _visitor.visit_pat_struct(_binding_0);
+ }
+ Pat::TupleStruct(ref _binding_0) => {
+ _visitor.visit_pat_tuple_struct(_binding_0);
+ }
+ Pat::Path(ref _binding_0) => {
+ _visitor.visit_pat_path(_binding_0);
+ }
+ Pat::Tuple(ref _binding_0) => {
+ _visitor.visit_pat_tuple(_binding_0);
+ }
+ Pat::Box(ref _binding_0) => {
+ _visitor.visit_pat_box(_binding_0);
+ }
+ Pat::Ref(ref _binding_0) => {
+ _visitor.visit_pat_ref(_binding_0);
+ }
+ Pat::Lit(ref _binding_0) => {
+ _visitor.visit_pat_lit(_binding_0);
+ }
+ Pat::Range(ref _binding_0) => {
+ _visitor.visit_pat_range(_binding_0);
+ }
+ Pat::Slice(ref _binding_0) => {
+ _visitor.visit_pat_slice(_binding_0);
+ }
+ Pat::Macro(ref _binding_0) => {
+ _visitor.visit_pat_macro(_binding_0);
+ }
+ Pat::Verbatim(ref _binding_0) => {
+ _visitor.visit_pat_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_box<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatBox) {
+ tokens_helper(_visitor, &_i.box_token.span);
+ _visitor.visit_pat(&*_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_ident<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatIdent) {
+ if let Some(ref it) = _i.by_ref {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_ident(&_i.ident);
+ if let Some(ref it) = _i.subpat {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_pat(&*(it).1);
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatLit) {
+ _visitor.visit_expr(&*_i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatMacro) {
+ _visitor.visit_macro(&_i.mac);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatPath) {
+ if let Some(ref it) = _i.qself {
+ _visitor.visit_qself(it)
+ };
+ _visitor.visit_path(&_i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_range<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatRange) {
+ _visitor.visit_expr(&*_i.lo);
+ _visitor.visit_range_limits(&_i.limits);
+ _visitor.visit_expr(&*_i.hi);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_ref<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatRef) {
+ tokens_helper(_visitor, &_i.and_token.spans);
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_pat(&*_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_slice<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatSlice) {
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ for el in Punctuated::pairs(&_i.front) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ if let Some(ref it) = _i.middle {
+ _visitor.visit_pat(&**it)
+ };
+ if let Some(ref it) = _i.dot2_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.comma_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.back) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatStruct) {
+ _visitor.visit_path(&_i.path);
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.fields) {
+ let it = el.value();
+ _visitor.visit_field_pat(it)
+ }
+ if let Some(ref it) = _i.dot2_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatTuple) {
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.front) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+ if let Some(ref it) = _i.dot2_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.comma_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.back) {
+ let it = el.value();
+ _visitor.visit_pat(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_struct<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast PatTupleStruct,
+) {
+ _visitor.visit_path(&_i.path);
+ _visitor.visit_pat_tuple(&_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_verbatim<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatVerbatim) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_wild<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatWild) {
+ tokens_helper(_visitor, &_i.underscore_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Path) {
+ if let Some(ref it) = _i.leading_colon {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.segments) {
+ let it = el.value();
+ _visitor.visit_path_segment(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path_arguments<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast PathArguments,
+) {
+ match *_i {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(ref _binding_0) => {
+ _visitor.visit_angle_bracketed_generic_arguments(_binding_0);
+ }
+ PathArguments::Parenthesized(ref _binding_0) => {
+ _visitor.visit_parenthesized_generic_arguments(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path_segment<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PathSegment) {
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_path_arguments(&_i.arguments);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_eq<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PredicateEq) {
+ _visitor.visit_type(&_i.lhs_ty);
+ tokens_helper(_visitor, &_i.eq_token.spans);
+ _visitor.visit_type(&_i.rhs_ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_lifetime<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast PredicateLifetime,
+) {
+ _visitor.visit_lifetime(&_i.lifetime);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_lifetime(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_type<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast PredicateType,
+) {
+ if let Some(ref it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes(it)
+ };
+ _visitor.visit_type(&_i.bounded_ty);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_qself<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast QSelf) {
+ tokens_helper(_visitor, &_i.lt_token.spans);
+ _visitor.visit_type(&*_i.ty);
+ skip!(_i.position);
+ if let Some(ref it) = _i.as_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ tokens_helper(_visitor, &_i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_range_limits<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast RangeLimits) {
+ match *_i {
+ RangeLimits::HalfOpen(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ RangeLimits::Closed(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_return_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ReturnType) {
+ match *_i {
+ ReturnType::Default => {}
+ ReturnType::Type(ref _binding_0, ref _binding_1) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ _visitor.visit_type(&**_binding_1);
+ }
+ }
+}
+pub fn visit_span<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Span) {}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_stmt<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Stmt) {
+ match *_i {
+ Stmt::Local(ref _binding_0) => {
+ _visitor.visit_local(_binding_0);
+ }
+ Stmt::Item(ref _binding_0) => {
+ _visitor.visit_item(_binding_0);
+ }
+ Stmt::Expr(ref _binding_0) => {
+ _visitor.visit_expr(_binding_0);
+ }
+ Stmt::Semi(ref _binding_0, ref _binding_1) => {
+ _visitor.visit_expr(_binding_0);
+ tokens_helper(_visitor, &_binding_1.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_trait_bound<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TraitBound) {
+ if let Some(ref it) = _i.paren_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_trait_bound_modifier(&_i.modifier);
+ if let Some(ref it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes(it)
+ };
+ _visitor.visit_path(&_i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_trait_bound_modifier<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitBoundModifier,
+) {
+ match *_i {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TraitItem) {
+ match *_i {
+ TraitItem::Const(ref _binding_0) => {
+ _visitor.visit_trait_item_const(_binding_0);
+ }
+ TraitItem::Method(ref _binding_0) => {
+ _visitor.visit_trait_item_method(_binding_0);
+ }
+ TraitItem::Type(ref _binding_0) => {
+ _visitor.visit_trait_item_type(_binding_0);
+ }
+ TraitItem::Existential(ref _binding_0) => {
+ _visitor.visit_trait_item_existential(_binding_0);
+ }
+ TraitItem::Macro(ref _binding_0) => {
+ _visitor.visit_trait_item_macro(_binding_0);
+ }
+ TraitItem::Verbatim(ref _binding_0) => {
+ _visitor.visit_trait_item_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_const<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemConst,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.const_token.span);
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon_token.spans);
+ _visitor.visit_type(&_i.ty);
+ if let Some(ref it) = _i.default {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_expr(&(it).1);
+ };
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_existential<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemExistential,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.existential_token.span);
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_macro<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemMacro,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_macro(&_i.mac);
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_method<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemMethod,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_method_sig(&_i.sig);
+ if let Some(ref it) = _i.default {
+ _visitor.visit_block(it)
+ };
+ if let Some(ref it) = _i.semi_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_type<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemType,
+) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ tokens_helper(_visitor, &_i.type_token.span);
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_generics(&_i.generics);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ if let Some(ref it) = _i.default {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_type(&(it).1);
+ };
+ tokens_helper(_visitor, &_i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TraitItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Type) {
+ match *_i {
+ Type::Slice(ref _binding_0) => {
+ _visitor.visit_type_slice(_binding_0);
+ }
+ Type::Array(ref _binding_0) => {
+ _visitor.visit_type_array(_binding_0);
+ }
+ Type::Ptr(ref _binding_0) => {
+ _visitor.visit_type_ptr(_binding_0);
+ }
+ Type::Reference(ref _binding_0) => {
+ _visitor.visit_type_reference(_binding_0);
+ }
+ Type::BareFn(ref _binding_0) => {
+ _visitor.visit_type_bare_fn(_binding_0);
+ }
+ Type::Never(ref _binding_0) => {
+ _visitor.visit_type_never(_binding_0);
+ }
+ Type::Tuple(ref _binding_0) => {
+ _visitor.visit_type_tuple(_binding_0);
+ }
+ Type::Path(ref _binding_0) => {
+ _visitor.visit_type_path(_binding_0);
+ }
+ Type::TraitObject(ref _binding_0) => {
+ _visitor.visit_type_trait_object(_binding_0);
+ }
+ Type::ImplTrait(ref _binding_0) => {
+ _visitor.visit_type_impl_trait(_binding_0);
+ }
+ Type::Paren(ref _binding_0) => {
+ _visitor.visit_type_paren(_binding_0);
+ }
+ Type::Group(ref _binding_0) => {
+ _visitor.visit_type_group(_binding_0);
+ }
+ Type::Infer(ref _binding_0) => {
+ _visitor.visit_type_infer(_binding_0);
+ }
+ Type::Macro(ref _binding_0) => {
+ _visitor.visit_type_macro(_binding_0);
+ }
+ Type::Verbatim(ref _binding_0) => {
+ _visitor.visit_type_verbatim(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_array<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeArray) {
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ _visitor.visit_type(&*_i.elem);
+ tokens_helper(_visitor, &_i.semi_token.spans);
+ _visitor.visit_expr(&_i.len);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_bare_fn<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeBareFn) {
+ if let Some(ref it) = _i.unsafety {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.abi {
+ _visitor.visit_abi(it)
+ };
+ tokens_helper(_visitor, &_i.fn_token.span);
+ if let Some(ref it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes(it)
+ };
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.inputs) {
+ let it = el.value();
+ _visitor.visit_bare_fn_arg(it)
+ }
+ if let Some(ref it) = _i.variadic {
+ tokens_helper(_visitor, &it.spans)
+ };
+ _visitor.visit_return_type(&_i.output);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeGroup) {
+ tokens_helper(_visitor, &_i.group_token.span);
+ _visitor.visit_type(&*_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_impl_trait<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TypeImplTrait,
+) {
+ tokens_helper(_visitor, &_i.impl_token.span);
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_infer<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeInfer) {
+ tokens_helper(_visitor, &_i.underscore_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeMacro) {
+ _visitor.visit_macro(&_i.mac);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_never<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeNever) {
+ tokens_helper(_visitor, &_i.bang_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_param<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeParam) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_ident(&_i.ident);
+ if let Some(ref it) = _i.colon_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+ if let Some(ref it) = _i.eq_token {
+ tokens_helper(_visitor, &it.spans)
+ };
+ if let Some(ref it) = _i.default {
+ _visitor.visit_type(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_param_bound<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TypeParamBound,
+) {
+ match *_i {
+ TypeParamBound::Trait(ref _binding_0) => {
+ _visitor.visit_trait_bound(_binding_0);
+ }
+ TypeParamBound::Lifetime(ref _binding_0) => {
+ _visitor.visit_lifetime(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_paren<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeParen) {
+ tokens_helper(_visitor, &_i.paren_token.span);
+ _visitor.visit_type(&*_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypePath) {
+ if let Some(ref it) = _i.qself {
+ _visitor.visit_qself(it)
+ };
+ _visitor.visit_path(&_i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_ptr<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypePtr) {
+ tokens_helper(_visitor, &_i.star_token.spans);
+ if let Some(ref it) = _i.const_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_type(&*_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_reference<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TypeReference,
+) {
+ tokens_helper(_visitor, &_i.and_token.spans);
+ if let Some(ref it) = _i.lifetime {
+ _visitor.visit_lifetime(it)
+ };
+ if let Some(ref it) = _i.mutability {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_type(&*_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_slice<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeSlice) {
+ tokens_helper(_visitor, &_i.bracket_token.span);
+ _visitor.visit_type(&*_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_trait_object<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TypeTraitObject,
+) {
+ if let Some(ref it) = _i.dyn_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ for el in Punctuated::pairs(&_i.bounds) {
+ let it = el.value();
+ _visitor.visit_type_param_bound(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeTuple) {
+ tokens_helper(_visitor, &_i.paren_token.span);
+ for el in Punctuated::pairs(&_i.elems) {
+ let it = el.value();
+ _visitor.visit_type(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_verbatim<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast TypeVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_un_op<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UnOp) {
+ match *_i {
+ UnOp::Deref(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ UnOp::Not(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ UnOp::Neg(ref _binding_0) => {
+ tokens_helper(_visitor, &_binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_glob<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseGlob) {
+ tokens_helper(_visitor, &_i.star_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseGroup) {
+ tokens_helper(_visitor, &_i.brace_token.span);
+ for el in Punctuated::pairs(&_i.items) {
+ let it = el.value();
+ _visitor.visit_use_tree(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_name<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseName) {
+ _visitor.visit_ident(&_i.ident);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UsePath) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.colon2_token.spans);
+ _visitor.visit_use_tree(&*_i.tree);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_rename<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseRename) {
+ _visitor.visit_ident(&_i.ident);
+ tokens_helper(_visitor, &_i.as_token.span);
+ _visitor.visit_ident(&_i.rename);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_tree<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseTree) {
+ match *_i {
+ UseTree::Path(ref _binding_0) => {
+ _visitor.visit_use_path(_binding_0);
+ }
+ UseTree::Name(ref _binding_0) => {
+ _visitor.visit_use_name(_binding_0);
+ }
+ UseTree::Rename(ref _binding_0) => {
+ _visitor.visit_use_rename(_binding_0);
+ }
+ UseTree::Glob(ref _binding_0) => {
+ _visitor.visit_use_glob(_binding_0);
+ }
+ UseTree::Group(ref _binding_0) => {
+ _visitor.visit_use_group(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_variant<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Variant) {
+ for it in &_i.attrs {
+ _visitor.visit_attribute(it)
+ }
+ _visitor.visit_ident(&_i.ident);
+ _visitor.visit_fields(&_i.fields);
+ if let Some(ref it) = _i.discriminant {
+ tokens_helper(_visitor, &(it).0.spans);
+ _visitor.visit_expr(&(it).1);
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_crate<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast VisCrate) {
+ tokens_helper(_visitor, &_i.crate_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_public<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast VisPublic) {
+ tokens_helper(_visitor, &_i.pub_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_restricted<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast VisRestricted,
+) {
+ tokens_helper(_visitor, &_i.pub_token.span);
+ tokens_helper(_visitor, &_i.paren_token.span);
+ if let Some(ref it) = _i.in_token {
+ tokens_helper(_visitor, &it.span)
+ };
+ _visitor.visit_path(&*_i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_visibility<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Visibility) {
+ match *_i {
+ Visibility::Public(ref _binding_0) => {
+ _visitor.visit_vis_public(_binding_0);
+ }
+ Visibility::Crate(ref _binding_0) => {
+ _visitor.visit_vis_crate(_binding_0);
+ }
+ Visibility::Restricted(ref _binding_0) => {
+ _visitor.visit_vis_restricted(_binding_0);
+ }
+ Visibility::Inherited => {}
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_where_clause<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast WhereClause) {
+ tokens_helper(_visitor, &_i.where_token.span);
+ for el in Punctuated::pairs(&_i.predicates) {
+ let it = el.value();
+ _visitor.visit_where_predicate(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_where_predicate<'ast, V: Visit<'ast> + ?Sized>(
+ _visitor: &mut V,
+ _i: &'ast WherePredicate,
+) {
+ match *_i {
+ WherePredicate::Type(ref _binding_0) => {
+ _visitor.visit_predicate_type(_binding_0);
+ }
+ WherePredicate::Lifetime(ref _binding_0) => {
+ _visitor.visit_predicate_lifetime(_binding_0);
+ }
+ WherePredicate::Eq(ref _binding_0) => {
+ _visitor.visit_predicate_eq(_binding_0);
+ }
+ }
+}
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
new file mode 100644
index 0000000..8263b61
--- /dev/null
+++ b/src/gen/visit_mut.rs
@@ -0,0 +1,3425 @@
+// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT
+
+#![cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
+#[cfg(any(feature = "full", feature = "derive"))]
+use gen::helper::visit_mut::*;
+use proc_macro2::Span;
+#[cfg(any(feature = "full", feature = "derive"))]
+use punctuated::Punctuated;
+use *;
+#[cfg(feature = "full")]
+macro_rules! full {
+ ($e:expr) => {
+ $e
+ };
+}
+#[cfg(all(feature = "derive", not(feature = "full")))]
+macro_rules! full {
+ ($e:expr) => {
+ unreachable!()
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! skip {
+ ($($tt:tt)*) => {};
+}
+#[doc = r" Syntax tree traversal to mutate an exclusive borrow of a syntax tree in"]
+#[doc = r" place."]
+#[doc = r""]
+#[doc = r" See the [module documentation] for details."]
+#[doc = r""]
+#[doc = r" [module documentation]: index.html"]
+#[doc = r""]
+#[doc = r#" *This trait is available if Syn is built with the `"visit-mut"` feature.*"#]
+pub trait VisitMut {
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_abi_mut(&mut self, i: &mut Abi) {
+ visit_abi_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_angle_bracketed_generic_arguments_mut(
+ &mut self,
+ i: &mut AngleBracketedGenericArguments,
+ ) {
+ visit_angle_bracketed_generic_arguments_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_captured_mut(&mut self, i: &mut ArgCaptured) {
+ visit_arg_captured_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_self_mut(&mut self, i: &mut ArgSelf) {
+ visit_arg_self_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_arg_self_ref_mut(&mut self, i: &mut ArgSelfRef) {
+ visit_arg_self_ref_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_arm_mut(&mut self, i: &mut Arm) {
+ visit_arm_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_attr_style_mut(&mut self, i: &mut AttrStyle) {
+ visit_attr_style_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_attribute_mut(&mut self, i: &mut Attribute) {
+ visit_attribute_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bare_fn_arg_mut(&mut self, i: &mut BareFnArg) {
+ visit_bare_fn_arg_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bare_fn_arg_name_mut(&mut self, i: &mut BareFnArgName) {
+ visit_bare_fn_arg_name_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bin_op_mut(&mut self, i: &mut BinOp) {
+ visit_bin_op_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_binding_mut(&mut self, i: &mut Binding) {
+ visit_binding_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_block_mut(&mut self, i: &mut Block) {
+ visit_block_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_bound_lifetimes_mut(&mut self, i: &mut BoundLifetimes) {
+ visit_bound_lifetimes_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_const_param_mut(&mut self, i: &mut ConstParam) {
+ visit_const_param_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_mut(&mut self, i: &mut Data) {
+ visit_data_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_enum_mut(&mut self, i: &mut DataEnum) {
+ visit_data_enum_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_struct_mut(&mut self, i: &mut DataStruct) {
+ visit_data_struct_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_data_union_mut(&mut self, i: &mut DataUnion) {
+ visit_data_union_mut(self, i)
+ }
+ #[cfg(feature = "derive")]
+ fn visit_derive_input_mut(&mut self, i: &mut DeriveInput) {
+ visit_derive_input_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_mut(&mut self, i: &mut Expr) {
+ visit_expr_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_array_mut(&mut self, i: &mut ExprArray) {
+ visit_expr_array_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_assign_mut(&mut self, i: &mut ExprAssign) {
+ visit_expr_assign_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_assign_op_mut(&mut self, i: &mut ExprAssignOp) {
+ visit_expr_assign_op_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_async_mut(&mut self, i: &mut ExprAsync) {
+ visit_expr_async_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_binary_mut(&mut self, i: &mut ExprBinary) {
+ visit_expr_binary_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_block_mut(&mut self, i: &mut ExprBlock) {
+ visit_expr_block_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_box_mut(&mut self, i: &mut ExprBox) {
+ visit_expr_box_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_break_mut(&mut self, i: &mut ExprBreak) {
+ visit_expr_break_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_call_mut(&mut self, i: &mut ExprCall) {
+ visit_expr_call_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_cast_mut(&mut self, i: &mut ExprCast) {
+ visit_expr_cast_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_closure_mut(&mut self, i: &mut ExprClosure) {
+ visit_expr_closure_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_continue_mut(&mut self, i: &mut ExprContinue) {
+ visit_expr_continue_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_field_mut(&mut self, i: &mut ExprField) {
+ visit_expr_field_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_for_loop_mut(&mut self, i: &mut ExprForLoop) {
+ visit_expr_for_loop_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_group_mut(&mut self, i: &mut ExprGroup) {
+ visit_expr_group_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_if_mut(&mut self, i: &mut ExprIf) {
+ visit_expr_if_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_if_let_mut(&mut self, i: &mut ExprIfLet) {
+ visit_expr_if_let_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_in_place_mut(&mut self, i: &mut ExprInPlace) {
+ visit_expr_in_place_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_index_mut(&mut self, i: &mut ExprIndex) {
+ visit_expr_index_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_lit_mut(&mut self, i: &mut ExprLit) {
+ visit_expr_lit_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_loop_mut(&mut self, i: &mut ExprLoop) {
+ visit_expr_loop_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_macro_mut(&mut self, i: &mut ExprMacro) {
+ visit_expr_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_match_mut(&mut self, i: &mut ExprMatch) {
+ visit_expr_match_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_method_call_mut(&mut self, i: &mut ExprMethodCall) {
+ visit_expr_method_call_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_paren_mut(&mut self, i: &mut ExprParen) {
+ visit_expr_paren_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_path_mut(&mut self, i: &mut ExprPath) {
+ visit_expr_path_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_range_mut(&mut self, i: &mut ExprRange) {
+ visit_expr_range_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_reference_mut(&mut self, i: &mut ExprReference) {
+ visit_expr_reference_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_repeat_mut(&mut self, i: &mut ExprRepeat) {
+ visit_expr_repeat_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_return_mut(&mut self, i: &mut ExprReturn) {
+ visit_expr_return_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_struct_mut(&mut self, i: &mut ExprStruct) {
+ visit_expr_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_try_mut(&mut self, i: &mut ExprTry) {
+ visit_expr_try_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_try_block_mut(&mut self, i: &mut ExprTryBlock) {
+ visit_expr_try_block_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_tuple_mut(&mut self, i: &mut ExprTuple) {
+ visit_expr_tuple_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_type_mut(&mut self, i: &mut ExprType) {
+ visit_expr_type_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_unary_mut(&mut self, i: &mut ExprUnary) {
+ visit_expr_unary_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_unsafe_mut(&mut self, i: &mut ExprUnsafe) {
+ visit_expr_unsafe_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_verbatim_mut(&mut self, i: &mut ExprVerbatim) {
+ visit_expr_verbatim_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_while_mut(&mut self, i: &mut ExprWhile) {
+ visit_expr_while_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_while_let_mut(&mut self, i: &mut ExprWhileLet) {
+ visit_expr_while_let_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_expr_yield_mut(&mut self, i: &mut ExprYield) {
+ visit_expr_yield_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_field_mut(&mut self, i: &mut Field) {
+ visit_field_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_field_pat_mut(&mut self, i: &mut FieldPat) {
+ visit_field_pat_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_field_value_mut(&mut self, i: &mut FieldValue) {
+ visit_field_value_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields_mut(&mut self, i: &mut Fields) {
+ visit_fields_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields_named_mut(&mut self, i: &mut FieldsNamed) {
+ visit_fields_named_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_fields_unnamed_mut(&mut self, i: &mut FieldsUnnamed) {
+ visit_fields_unnamed_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_file_mut(&mut self, i: &mut File) {
+ visit_file_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_arg_mut(&mut self, i: &mut FnArg) {
+ visit_fn_arg_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_fn_decl_mut(&mut self, i: &mut FnDecl) {
+ visit_fn_decl_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_mut(&mut self, i: &mut ForeignItem) {
+ visit_foreign_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_fn_mut(&mut self, i: &mut ForeignItemFn) {
+ visit_foreign_item_fn_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_macro_mut(&mut self, i: &mut ForeignItemMacro) {
+ visit_foreign_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_static_mut(&mut self, i: &mut ForeignItemStatic) {
+ visit_foreign_item_static_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_type_mut(&mut self, i: &mut ForeignItemType) {
+ visit_foreign_item_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_foreign_item_verbatim_mut(&mut self, i: &mut ForeignItemVerbatim) {
+ visit_foreign_item_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generic_argument_mut(&mut self, i: &mut GenericArgument) {
+ visit_generic_argument_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_generic_method_argument_mut(&mut self, i: &mut GenericMethodArgument) {
+ visit_generic_method_argument_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generic_param_mut(&mut self, i: &mut GenericParam) {
+ visit_generic_param_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_generics_mut(&mut self, i: &mut Generics) {
+ visit_generics_mut(self, i)
+ }
+ fn visit_ident_mut(&mut self, i: &mut Ident) {
+ visit_ident_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_mut(&mut self, i: &mut ImplItem) {
+ visit_impl_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_const_mut(&mut self, i: &mut ImplItemConst) {
+ visit_impl_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_existential_mut(&mut self, i: &mut ImplItemExistential) {
+ visit_impl_item_existential_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_macro_mut(&mut self, i: &mut ImplItemMacro) {
+ visit_impl_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_method_mut(&mut self, i: &mut ImplItemMethod) {
+ visit_impl_item_method_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_type_mut(&mut self, i: &mut ImplItemType) {
+ visit_impl_item_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_impl_item_verbatim_mut(&mut self, i: &mut ImplItemVerbatim) {
+ visit_impl_item_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_index_mut(&mut self, i: &mut Index) {
+ visit_index_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mut(&mut self, i: &mut Item) {
+ visit_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_const_mut(&mut self, i: &mut ItemConst) {
+ visit_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_enum_mut(&mut self, i: &mut ItemEnum) {
+ visit_item_enum_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_existential_mut(&mut self, i: &mut ItemExistential) {
+ visit_item_existential_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_extern_crate_mut(&mut self, i: &mut ItemExternCrate) {
+ visit_item_extern_crate_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_fn_mut(&mut self, i: &mut ItemFn) {
+ visit_item_fn_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_foreign_mod_mut(&mut self, i: &mut ItemForeignMod) {
+ visit_item_foreign_mod_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) {
+ visit_item_impl_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro_mut(&mut self, i: &mut ItemMacro) {
+ visit_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_macro2_mut(&mut self, i: &mut ItemMacro2) {
+ visit_item_macro2_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_mod_mut(&mut self, i: &mut ItemMod) {
+ visit_item_mod_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_static_mut(&mut self, i: &mut ItemStatic) {
+ visit_item_static_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) {
+ visit_item_struct_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_trait_mut(&mut self, i: &mut ItemTrait) {
+ visit_item_trait_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_type_mut(&mut self, i: &mut ItemType) {
+ visit_item_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_union_mut(&mut self, i: &mut ItemUnion) {
+ visit_item_union_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_use_mut(&mut self, i: &mut ItemUse) {
+ visit_item_use_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_item_verbatim_mut(&mut self, i: &mut ItemVerbatim) {
+ visit_item_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_label_mut(&mut self, i: &mut Label) {
+ visit_label_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
+ visit_lifetime_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lifetime_def_mut(&mut self, i: &mut LifetimeDef) {
+ visit_lifetime_def_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_mut(&mut self, i: &mut Lit) {
+ visit_lit_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_bool_mut(&mut self, i: &mut LitBool) {
+ visit_lit_bool_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_byte_mut(&mut self, i: &mut LitByte) {
+ visit_lit_byte_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_byte_str_mut(&mut self, i: &mut LitByteStr) {
+ visit_lit_byte_str_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_char_mut(&mut self, i: &mut LitChar) {
+ visit_lit_char_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_float_mut(&mut self, i: &mut LitFloat) {
+ visit_lit_float_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_int_mut(&mut self, i: &mut LitInt) {
+ visit_lit_int_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_str_mut(&mut self, i: &mut LitStr) {
+ visit_lit_str_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_lit_verbatim_mut(&mut self, i: &mut LitVerbatim) {
+ visit_lit_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_local_mut(&mut self, i: &mut Local) {
+ visit_local_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_macro_mut(&mut self, i: &mut Macro) {
+ visit_macro_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_macro_delimiter_mut(&mut self, i: &mut MacroDelimiter) {
+ visit_macro_delimiter_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_member_mut(&mut self, i: &mut Member) {
+ visit_member_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta_mut(&mut self, i: &mut Meta) {
+ visit_meta_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta_list_mut(&mut self, i: &mut MetaList) {
+ visit_meta_list_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_meta_name_value_mut(&mut self, i: &mut MetaNameValue) {
+ visit_meta_name_value_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_method_sig_mut(&mut self, i: &mut MethodSig) {
+ visit_method_sig_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_method_turbofish_mut(&mut self, i: &mut MethodTurbofish) {
+ visit_method_turbofish_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_nested_meta_mut(&mut self, i: &mut NestedMeta) {
+ visit_nested_meta_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_parenthesized_generic_arguments_mut(&mut self, i: &mut ParenthesizedGenericArguments) {
+ visit_parenthesized_generic_arguments_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_mut(&mut self, i: &mut Pat) {
+ visit_pat_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_box_mut(&mut self, i: &mut PatBox) {
+ visit_pat_box_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) {
+ visit_pat_ident_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_lit_mut(&mut self, i: &mut PatLit) {
+ visit_pat_lit_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_macro_mut(&mut self, i: &mut PatMacro) {
+ visit_pat_macro_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_path_mut(&mut self, i: &mut PatPath) {
+ visit_pat_path_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_range_mut(&mut self, i: &mut PatRange) {
+ visit_pat_range_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_ref_mut(&mut self, i: &mut PatRef) {
+ visit_pat_ref_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_slice_mut(&mut self, i: &mut PatSlice) {
+ visit_pat_slice_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_struct_mut(&mut self, i: &mut PatStruct) {
+ visit_pat_struct_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_mut(&mut self, i: &mut PatTuple) {
+ visit_pat_tuple_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_tuple_struct_mut(&mut self, i: &mut PatTupleStruct) {
+ visit_pat_tuple_struct_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_verbatim_mut(&mut self, i: &mut PatVerbatim) {
+ visit_pat_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_pat_wild_mut(&mut self, i: &mut PatWild) {
+ visit_pat_wild_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path_mut(&mut self, i: &mut Path) {
+ visit_path_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path_arguments_mut(&mut self, i: &mut PathArguments) {
+ visit_path_arguments_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_path_segment_mut(&mut self, i: &mut PathSegment) {
+ visit_path_segment_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_eq_mut(&mut self, i: &mut PredicateEq) {
+ visit_predicate_eq_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_lifetime_mut(&mut self, i: &mut PredicateLifetime) {
+ visit_predicate_lifetime_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_predicate_type_mut(&mut self, i: &mut PredicateType) {
+ visit_predicate_type_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_qself_mut(&mut self, i: &mut QSelf) {
+ visit_qself_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_range_limits_mut(&mut self, i: &mut RangeLimits) {
+ visit_range_limits_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_return_type_mut(&mut self, i: &mut ReturnType) {
+ visit_return_type_mut(self, i)
+ }
+ fn visit_span_mut(&mut self, i: &mut Span) {
+ visit_span_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[cfg(feature = "full")]
+ fn visit_stmt_mut(&mut self, i: &mut Stmt) {
+ visit_stmt_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
+ visit_trait_bound_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_trait_bound_modifier_mut(&mut self, i: &mut TraitBoundModifier) {
+ visit_trait_bound_modifier_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_mut(&mut self, i: &mut TraitItem) {
+ visit_trait_item_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_const_mut(&mut self, i: &mut TraitItemConst) {
+ visit_trait_item_const_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_existential_mut(&mut self, i: &mut TraitItemExistential) {
+ visit_trait_item_existential_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_macro_mut(&mut self, i: &mut TraitItemMacro) {
+ visit_trait_item_macro_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_method_mut(&mut self, i: &mut TraitItemMethod) {
+ visit_trait_item_method_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_type_mut(&mut self, i: &mut TraitItemType) {
+ visit_trait_item_type_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_trait_item_verbatim_mut(&mut self, i: &mut TraitItemVerbatim) {
+ visit_trait_item_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_mut(&mut self, i: &mut Type) {
+ visit_type_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_array_mut(&mut self, i: &mut TypeArray) {
+ visit_type_array_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) {
+ visit_type_bare_fn_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_group_mut(&mut self, i: &mut TypeGroup) {
+ visit_type_group_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_impl_trait_mut(&mut self, i: &mut TypeImplTrait) {
+ visit_type_impl_trait_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_infer_mut(&mut self, i: &mut TypeInfer) {
+ visit_type_infer_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_macro_mut(&mut self, i: &mut TypeMacro) {
+ visit_type_macro_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_never_mut(&mut self, i: &mut TypeNever) {
+ visit_type_never_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_param_mut(&mut self, i: &mut TypeParam) {
+ visit_type_param_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_param_bound_mut(&mut self, i: &mut TypeParamBound) {
+ visit_type_param_bound_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_paren_mut(&mut self, i: &mut TypeParen) {
+ visit_type_paren_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_path_mut(&mut self, i: &mut TypePath) {
+ visit_type_path_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_ptr_mut(&mut self, i: &mut TypePtr) {
+ visit_type_ptr_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_reference_mut(&mut self, i: &mut TypeReference) {
+ visit_type_reference_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_slice_mut(&mut self, i: &mut TypeSlice) {
+ visit_type_slice_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_trait_object_mut(&mut self, i: &mut TypeTraitObject) {
+ visit_type_trait_object_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_tuple_mut(&mut self, i: &mut TypeTuple) {
+ visit_type_tuple_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_type_verbatim_mut(&mut self, i: &mut TypeVerbatim) {
+ visit_type_verbatim_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_un_op_mut(&mut self, i: &mut UnOp) {
+ visit_un_op_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_glob_mut(&mut self, i: &mut UseGlob) {
+ visit_use_glob_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_group_mut(&mut self, i: &mut UseGroup) {
+ visit_use_group_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_name_mut(&mut self, i: &mut UseName) {
+ visit_use_name_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_path_mut(&mut self, i: &mut UsePath) {
+ visit_use_path_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_rename_mut(&mut self, i: &mut UseRename) {
+ visit_use_rename_mut(self, i)
+ }
+ #[cfg(feature = "full")]
+ fn visit_use_tree_mut(&mut self, i: &mut UseTree) {
+ visit_use_tree_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_variant_mut(&mut self, i: &mut Variant) {
+ visit_variant_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_crate_mut(&mut self, i: &mut VisCrate) {
+ visit_vis_crate_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_public_mut(&mut self, i: &mut VisPublic) {
+ visit_vis_public_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_vis_restricted_mut(&mut self, i: &mut VisRestricted) {
+ visit_vis_restricted_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_visibility_mut(&mut self, i: &mut Visibility) {
+ visit_visibility_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_where_clause_mut(&mut self, i: &mut WhereClause) {
+ visit_where_clause_mut(self, i)
+ }
+ #[cfg(any(feature = "full", feature = "derive"))]
+ fn visit_where_predicate_mut(&mut self, i: &mut WherePredicate) {
+ visit_where_predicate_mut(self, i)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_abi_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Abi) {
+ tokens_helper(_visitor, &mut _i.extern_token.span);
+ if let Some(ref mut it) = _i.name {
+ _visitor.visit_lit_str_mut(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_angle_bracketed_generic_arguments_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut AngleBracketedGenericArguments,
+) {
+ if let Some(ref mut it) = _i.colon2_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ tokens_helper(_visitor, &mut _i.lt_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.args) {
+ let it = el.value_mut();
+ _visitor.visit_generic_argument_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.gt_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_captured_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgCaptured) {
+ _visitor.visit_pat_mut(&mut _i.pat);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_self_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgSelf) {
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.self_token.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_arg_self_ref_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgSelfRef) {
+ tokens_helper(_visitor, &mut _i.and_token.spans);
+ if let Some(ref mut it) = _i.lifetime {
+ _visitor.visit_lifetime_mut(it)
+ };
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.self_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_arm_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Arm) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.leading_vert {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.pats) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ if let Some(ref mut it) = _i.guard {
+ tokens_helper(_visitor, &mut (it).0.span);
+ _visitor.visit_expr_mut(&mut *(it).1);
+ };
+ tokens_helper(_visitor, &mut _i.fat_arrow_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.body);
+ if let Some(ref mut it) = _i.comma {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_attr_style_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut AttrStyle) {
+ match *_i {
+ AttrStyle::Outer => {}
+ AttrStyle::Inner(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_attribute_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Attribute) {
+ tokens_helper(_visitor, &mut _i.pound_token.spans);
+ _visitor.visit_attr_style_mut(&mut _i.style);
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ _visitor.visit_path_mut(&mut _i.path);
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bare_fn_arg_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BareFnArg) {
+ if let Some(ref mut it) = _i.name {
+ _visitor.visit_bare_fn_arg_name_mut(&mut (it).0);
+ tokens_helper(_visitor, &mut (it).1.spans);
+ };
+ _visitor.visit_type_mut(&mut _i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bare_fn_arg_name_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BareFnArgName) {
+ match *_i {
+ BareFnArgName::Named(ref mut _binding_0) => {
+ _visitor.visit_ident_mut(_binding_0);
+ }
+ BareFnArgName::Wild(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bin_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BinOp) {
+ match *_i {
+ BinOp::Add(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Sub(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Mul(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Div(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Rem(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::And(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Or(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitXor(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitAnd(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitOr(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Shl(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Shr(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Eq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Lt(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Le(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Ne(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Ge(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::Gt(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::AddEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::SubEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::MulEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::DivEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::RemEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitXorEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitAndEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::BitOrEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::ShlEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ BinOp::ShrEq(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_binding_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Binding) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Block) {
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for it in &mut _i.stmts {
+ _visitor.visit_stmt_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_bound_lifetimes_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BoundLifetimes) {
+ tokens_helper(_visitor, &mut _i.for_token.span);
+ tokens_helper(_visitor, &mut _i.lt_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.lifetimes) {
+ let it = el.value_mut();
+ _visitor.visit_lifetime_def_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_const_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ConstParam) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.const_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+ if let Some(ref mut it) = _i.eq_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.default {
+ _visitor.visit_expr_mut(it)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Data) {
+ match *_i {
+ Data::Struct(ref mut _binding_0) => {
+ _visitor.visit_data_struct_mut(_binding_0);
+ }
+ Data::Enum(ref mut _binding_0) => {
+ _visitor.visit_data_enum_mut(_binding_0);
+ }
+ Data::Union(ref mut _binding_0) => {
+ _visitor.visit_data_union_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_enum_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataEnum) {
+ tokens_helper(_visitor, &mut _i.enum_token.span);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.variants) {
+ let it = el.value_mut();
+ _visitor.visit_variant_mut(it)
+ }
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataStruct) {
+ tokens_helper(_visitor, &mut _i.struct_token.span);
+ _visitor.visit_fields_mut(&mut _i.fields);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "derive")]
+pub fn visit_data_union_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataUnion) {
+ tokens_helper(_visitor, &mut _i.union_token.span);
+ _visitor.visit_fields_named_mut(&mut _i.fields);
+}
+#[cfg(feature = "derive")]
+pub fn visit_derive_input_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DeriveInput) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ _visitor.visit_data_mut(&mut _i.data);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Expr) {
+ match *_i {
+ Expr::Box(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_box_mut(_binding_0));
+ }
+ Expr::InPlace(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_in_place_mut(_binding_0));
+ }
+ Expr::Array(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_array_mut(_binding_0));
+ }
+ Expr::Call(ref mut _binding_0) => {
+ _visitor.visit_expr_call_mut(_binding_0);
+ }
+ Expr::MethodCall(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_method_call_mut(_binding_0));
+ }
+ Expr::Tuple(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_tuple_mut(_binding_0));
+ }
+ Expr::Binary(ref mut _binding_0) => {
+ _visitor.visit_expr_binary_mut(_binding_0);
+ }
+ Expr::Unary(ref mut _binding_0) => {
+ _visitor.visit_expr_unary_mut(_binding_0);
+ }
+ Expr::Lit(ref mut _binding_0) => {
+ _visitor.visit_expr_lit_mut(_binding_0);
+ }
+ Expr::Cast(ref mut _binding_0) => {
+ _visitor.visit_expr_cast_mut(_binding_0);
+ }
+ Expr::Type(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_type_mut(_binding_0));
+ }
+ Expr::If(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_if_mut(_binding_0));
+ }
+ Expr::IfLet(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_if_let_mut(_binding_0));
+ }
+ Expr::While(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_while_mut(_binding_0));
+ }
+ Expr::WhileLet(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_while_let_mut(_binding_0));
+ }
+ Expr::ForLoop(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_for_loop_mut(_binding_0));
+ }
+ Expr::Loop(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_loop_mut(_binding_0));
+ }
+ Expr::Match(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_match_mut(_binding_0));
+ }
+ Expr::Closure(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_closure_mut(_binding_0));
+ }
+ Expr::Unsafe(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_unsafe_mut(_binding_0));
+ }
+ Expr::Block(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_block_mut(_binding_0));
+ }
+ Expr::Assign(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_assign_mut(_binding_0));
+ }
+ Expr::AssignOp(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_assign_op_mut(_binding_0));
+ }
+ Expr::Field(ref mut _binding_0) => {
+ _visitor.visit_expr_field_mut(_binding_0);
+ }
+ Expr::Index(ref mut _binding_0) => {
+ _visitor.visit_expr_index_mut(_binding_0);
+ }
+ Expr::Range(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_range_mut(_binding_0));
+ }
+ Expr::Path(ref mut _binding_0) => {
+ _visitor.visit_expr_path_mut(_binding_0);
+ }
+ Expr::Reference(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_reference_mut(_binding_0));
+ }
+ Expr::Break(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_break_mut(_binding_0));
+ }
+ Expr::Continue(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_continue_mut(_binding_0));
+ }
+ Expr::Return(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_return_mut(_binding_0));
+ }
+ Expr::Macro(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_macro_mut(_binding_0));
+ }
+ Expr::Struct(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_struct_mut(_binding_0));
+ }
+ Expr::Repeat(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_repeat_mut(_binding_0));
+ }
+ Expr::Paren(ref mut _binding_0) => {
+ _visitor.visit_expr_paren_mut(_binding_0);
+ }
+ Expr::Group(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_group_mut(_binding_0));
+ }
+ Expr::Try(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_try_mut(_binding_0));
+ }
+ Expr::Async(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_async_mut(_binding_0));
+ }
+ Expr::TryBlock(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_try_block_mut(_binding_0));
+ }
+ Expr::Yield(ref mut _binding_0) => {
+ full!(_visitor.visit_expr_yield_mut(_binding_0));
+ }
+ Expr::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_expr_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_array_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprArray) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.elems) {
+ let it = el.value_mut();
+ _visitor.visit_expr_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_assign_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAssign) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.left);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_assign_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAssignOp) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.left);
+ _visitor.visit_bin_op_mut(&mut _i.op);
+ _visitor.visit_expr_mut(&mut *_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_async_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAsync) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.async_token.span);
+ if let Some(ref mut it) = _i.capture {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_block_mut(&mut _i.block);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_binary_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBinary) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.left);
+ _visitor.visit_bin_op_mut(&mut _i.op);
+ _visitor.visit_expr_mut(&mut *_i.right);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBlock) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_label_mut(it)
+ };
+ _visitor.visit_block_mut(&mut _i.block);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_box_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBox) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.box_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_break_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBreak) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.break_token.span);
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_lifetime_mut(it)
+ };
+ if let Some(ref mut it) = _i.expr {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_call_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprCall) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.func);
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.args) {
+ let it = el.value_mut();
+ _visitor.visit_expr_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_cast_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprCast) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.as_token.span);
+ _visitor.visit_type_mut(&mut *_i.ty);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_closure_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprClosure) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.asyncness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.movability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.capture {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.or1_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.inputs) {
+ let it = el.value_mut();
+ _visitor.visit_fn_arg_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.or2_token.spans);
+ _visitor.visit_return_type_mut(&mut _i.output);
+ _visitor.visit_expr_mut(&mut *_i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_continue_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprContinue) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.continue_token.span);
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_lifetime_mut(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_field_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprField) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.base);
+ tokens_helper(_visitor, &mut _i.dot_token.spans);
+ _visitor.visit_member_mut(&mut _i.member);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_for_loop_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprForLoop) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_label_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.for_token.span);
+ _visitor.visit_pat_mut(&mut *_i.pat);
+ tokens_helper(_visitor, &mut _i.in_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ _visitor.visit_block_mut(&mut _i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprGroup) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.group_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_if_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIf) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.if_token.span);
+ _visitor.visit_expr_mut(&mut *_i.cond);
+ _visitor.visit_block_mut(&mut _i.then_branch);
+ if let Some(ref mut it) = _i.else_branch {
+ tokens_helper(_visitor, &mut (it).0.span);
+ _visitor.visit_expr_mut(&mut *(it).1);
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_if_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIfLet) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.if_token.span);
+ tokens_helper(_visitor, &mut _i.let_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.pats) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ _visitor.visit_block_mut(&mut _i.then_branch);
+ if let Some(ref mut it) = _i.else_branch {
+ tokens_helper(_visitor, &mut (it).0.span);
+ _visitor.visit_expr_mut(&mut *(it).1);
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_in_place_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprInPlace) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.place);
+ tokens_helper(_visitor, &mut _i.arrow_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.value);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_index_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIndex) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ _visitor.visit_expr_mut(&mut *_i.index);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLit) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_lit_mut(&mut _i.lit);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_loop_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLoop) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_label_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.loop_token.span);
+ _visitor.visit_block_mut(&mut _i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMacro) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_macro_mut(&mut _i.mac);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_match_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMatch) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.match_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for it in &mut _i.arms {
+ _visitor.visit_arm_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_method_call_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMethodCall) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.receiver);
+ tokens_helper(_visitor, &mut _i.dot_token.spans);
+ _visitor.visit_ident_mut(&mut _i.method);
+ if let Some(ref mut it) = _i.turbofish {
+ _visitor.visit_method_turbofish_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.args) {
+ let it = el.value_mut();
+ _visitor.visit_expr_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_paren_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprParen) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprPath) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.qself {
+ _visitor.visit_qself_mut(it)
+ };
+ _visitor.visit_path_mut(&mut _i.path);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_range_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprRange) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.from {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+ _visitor.visit_range_limits_mut(&mut _i.limits);
+ if let Some(ref mut it) = _i.to {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_reference_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprReference) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.and_token.spans);
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_repeat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprRepeat) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.len);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_return_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprReturn) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.return_token.span);
+ if let Some(ref mut it) = _i.expr {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprStruct) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_path_mut(&mut _i.path);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.fields) {
+ let it = el.value_mut();
+ _visitor.visit_field_value_mut(it)
+ }
+ if let Some(ref mut it) = _i.dot2_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.rest {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_try_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTry) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.question_token.spans);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_try_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTryBlock) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.try_token.span);
+ _visitor.visit_block_mut(&mut _i.block);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTuple) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.elems) {
+ let it = el.value_mut();
+ _visitor.visit_expr_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprType) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_unary_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprUnary) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_un_op_mut(&mut _i.op);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_unsafe_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprUnsafe) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.unsafe_token.span);
+ _visitor.visit_block_mut(&mut _i.block);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprVerbatim) {
+ skip!(_i.tts);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_while_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhile) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_label_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.while_token.span);
+ _visitor.visit_expr_mut(&mut *_i.cond);
+ _visitor.visit_block_mut(&mut _i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_while_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhileLet) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.label {
+ _visitor.visit_label_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.while_token.span);
+ tokens_helper(_visitor, &mut _i.let_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.pats) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ _visitor.visit_block_mut(&mut _i.body);
+}
+#[cfg(feature = "full")]
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_expr_yield_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprYield) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.yield_token.span);
+ if let Some(ref mut it) = _i.expr {
+ _visitor.visit_expr_mut(&mut **it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_field_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Field) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.ident {
+ _visitor.visit_ident_mut(it)
+ };
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_type_mut(&mut _i.ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_field_pat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldPat) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_member_mut(&mut _i.member);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_pat_mut(&mut *_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_field_value_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldValue) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_member_mut(&mut _i.member);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_expr_mut(&mut _i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Fields) {
+ match *_i {
+ Fields::Named(ref mut _binding_0) => {
+ _visitor.visit_fields_named_mut(_binding_0);
+ }
+ Fields::Unnamed(ref mut _binding_0) => {
+ _visitor.visit_fields_unnamed_mut(_binding_0);
+ }
+ Fields::Unit => {}
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields_named_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldsNamed) {
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.named) {
+ let it = el.value_mut();
+ _visitor.visit_field_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_fields_unnamed_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldsUnnamed) {
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.unnamed) {
+ let it = el.value_mut();
+ _visitor.visit_field_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_file_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut File) {
+ skip!(_i.shebang);
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ for it in &mut _i.items {
+ _visitor.visit_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_arg_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FnArg) {
+ match *_i {
+ FnArg::SelfRef(ref mut _binding_0) => {
+ _visitor.visit_arg_self_ref_mut(_binding_0);
+ }
+ FnArg::SelfValue(ref mut _binding_0) => {
+ _visitor.visit_arg_self_mut(_binding_0);
+ }
+ FnArg::Captured(ref mut _binding_0) => {
+ _visitor.visit_arg_captured_mut(_binding_0);
+ }
+ FnArg::Inferred(ref mut _binding_0) => {
+ _visitor.visit_pat_mut(_binding_0);
+ }
+ FnArg::Ignored(ref mut _binding_0) => {
+ _visitor.visit_type_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_fn_decl_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FnDecl) {
+ tokens_helper(_visitor, &mut _i.fn_token.span);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.inputs) {
+ let it = el.value_mut();
+ _visitor.visit_fn_arg_mut(it)
+ }
+ if let Some(ref mut it) = _i.variadic {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_return_type_mut(&mut _i.output);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ForeignItem) {
+ match *_i {
+ ForeignItem::Fn(ref mut _binding_0) => {
+ _visitor.visit_foreign_item_fn_mut(_binding_0);
+ }
+ ForeignItem::Static(ref mut _binding_0) => {
+ _visitor.visit_foreign_item_static_mut(_binding_0);
+ }
+ ForeignItem::Type(ref mut _binding_0) => {
+ _visitor.visit_foreign_item_type_mut(_binding_0);
+ }
+ ForeignItem::Macro(ref mut _binding_0) => {
+ _visitor.visit_foreign_item_macro_mut(_binding_0);
+ }
+ ForeignItem::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_foreign_item_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ForeignItemFn) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_fn_decl_mut(&mut *_i.decl);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_macro_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ForeignItemMacro,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_macro_mut(&mut _i.mac);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_static_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ForeignItemStatic,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.static_token.span);
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_type_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ForeignItemType,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_foreign_item_verbatim_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ForeignItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generic_argument_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut GenericArgument,
+) {
+ match *_i {
+ GenericArgument::Lifetime(ref mut _binding_0) => {
+ _visitor.visit_lifetime_mut(_binding_0);
+ }
+ GenericArgument::Type(ref mut _binding_0) => {
+ _visitor.visit_type_mut(_binding_0);
+ }
+ GenericArgument::Binding(ref mut _binding_0) => {
+ _visitor.visit_binding_mut(_binding_0);
+ }
+ GenericArgument::Const(ref mut _binding_0) => {
+ _visitor.visit_expr_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_generic_method_argument_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut GenericMethodArgument,
+) {
+ match *_i {
+ GenericMethodArgument::Type(ref mut _binding_0) => {
+ _visitor.visit_type_mut(_binding_0);
+ }
+ GenericMethodArgument::Const(ref mut _binding_0) => {
+ _visitor.visit_expr_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generic_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut GenericParam) {
+ match *_i {
+ GenericParam::Type(ref mut _binding_0) => {
+ _visitor.visit_type_param_mut(_binding_0);
+ }
+ GenericParam::Lifetime(ref mut _binding_0) => {
+ _visitor.visit_lifetime_def_mut(_binding_0);
+ }
+ GenericParam::Const(ref mut _binding_0) => {
+ _visitor.visit_const_param_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_generics_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Generics) {
+ if let Some(ref mut it) = _i.lt_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.params) {
+ let it = el.value_mut();
+ _visitor.visit_generic_param_mut(it)
+ }
+ if let Some(ref mut it) = _i.gt_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.where_clause {
+ _visitor.visit_where_clause_mut(it)
+ };
+}
+pub fn visit_ident_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Ident) {}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItem) {
+ match *_i {
+ ImplItem::Const(ref mut _binding_0) => {
+ _visitor.visit_impl_item_const_mut(_binding_0);
+ }
+ ImplItem::Method(ref mut _binding_0) => {
+ _visitor.visit_impl_item_method_mut(_binding_0);
+ }
+ ImplItem::Type(ref mut _binding_0) => {
+ _visitor.visit_impl_item_type_mut(_binding_0);
+ }
+ ImplItem::Existential(ref mut _binding_0) => {
+ _visitor.visit_impl_item_existential_mut(_binding_0);
+ }
+ ImplItem::Macro(ref mut _binding_0) => {
+ _visitor.visit_impl_item_macro_mut(_binding_0);
+ }
+ ImplItem::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_impl_item_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemConst) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.defaultness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.const_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut _i.expr);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_existential_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ImplItemExistential,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.existential_token.span);
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemMacro) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_macro_mut(&mut _i.mac);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_method_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemMethod) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.defaultness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_method_sig_mut(&mut _i.sig);
+ _visitor.visit_block_mut(&mut _i.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemType) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.defaultness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_impl_item_verbatim_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ImplItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_index_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Index) {
+ skip!(_i.index);
+ _visitor.visit_span_mut(&mut _i.span);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Item) {
+ match *_i {
+ Item::ExternCrate(ref mut _binding_0) => {
+ _visitor.visit_item_extern_crate_mut(_binding_0);
+ }
+ Item::Use(ref mut _binding_0) => {
+ _visitor.visit_item_use_mut(_binding_0);
+ }
+ Item::Static(ref mut _binding_0) => {
+ _visitor.visit_item_static_mut(_binding_0);
+ }
+ Item::Const(ref mut _binding_0) => {
+ _visitor.visit_item_const_mut(_binding_0);
+ }
+ Item::Fn(ref mut _binding_0) => {
+ _visitor.visit_item_fn_mut(_binding_0);
+ }
+ Item::Mod(ref mut _binding_0) => {
+ _visitor.visit_item_mod_mut(_binding_0);
+ }
+ Item::ForeignMod(ref mut _binding_0) => {
+ _visitor.visit_item_foreign_mod_mut(_binding_0);
+ }
+ Item::Type(ref mut _binding_0) => {
+ _visitor.visit_item_type_mut(_binding_0);
+ }
+ Item::Existential(ref mut _binding_0) => {
+ _visitor.visit_item_existential_mut(_binding_0);
+ }
+ Item::Struct(ref mut _binding_0) => {
+ _visitor.visit_item_struct_mut(_binding_0);
+ }
+ Item::Enum(ref mut _binding_0) => {
+ _visitor.visit_item_enum_mut(_binding_0);
+ }
+ Item::Union(ref mut _binding_0) => {
+ _visitor.visit_item_union_mut(_binding_0);
+ }
+ Item::Trait(ref mut _binding_0) => {
+ _visitor.visit_item_trait_mut(_binding_0);
+ }
+ Item::Impl(ref mut _binding_0) => {
+ _visitor.visit_item_impl_mut(_binding_0);
+ }
+ Item::Macro(ref mut _binding_0) => {
+ _visitor.visit_item_macro_mut(_binding_0);
+ }
+ Item::Macro2(ref mut _binding_0) => {
+ _visitor.visit_item_macro2_mut(_binding_0);
+ }
+ Item::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_item_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemConst) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.const_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_enum_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemEnum) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.enum_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.variants) {
+ let it = el.value_mut();
+ _visitor.visit_variant_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_existential_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ItemExistential,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.existential_token.span);
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_extern_crate_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ItemExternCrate,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.extern_token.span);
+ tokens_helper(_visitor, &mut _i.crate_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ if let Some(ref mut it) = _i.rename {
+ tokens_helper(_visitor, &mut (it).0.span);
+ _visitor.visit_ident_mut(&mut (it).1);
+ };
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemFn) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.constness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.unsafety {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.asyncness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.abi {
+ _visitor.visit_abi_mut(it)
+ };
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_fn_decl_mut(&mut *_i.decl);
+ _visitor.visit_block_mut(&mut *_i.block);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_foreign_mod_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemForeignMod) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_abi_mut(&mut _i.abi);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for it in &mut _i.items {
+ _visitor.visit_foreign_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_impl_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemImpl) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.defaultness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.unsafety {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.impl_token.span);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.trait_ {
+ if let Some(ref mut it) = (it).0 {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_path_mut(&mut (it).1);
+ tokens_helper(_visitor, &mut (it).2.span);
+ };
+ _visitor.visit_type_mut(&mut *_i.self_ty);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for it in &mut _i.items {
+ _visitor.visit_impl_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMacro) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ if let Some(ref mut it) = _i.ident {
+ _visitor.visit_ident_mut(it)
+ };
+ _visitor.visit_macro_mut(&mut _i.mac);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_macro2_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMacro2) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.macro_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ skip!(_i.args);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ skip!(_i.body);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_mod_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMod) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.mod_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ if let Some(ref mut it) = _i.content {
+ tokens_helper(_visitor, &mut (it).0.span);
+ for it in &mut (it).1 {
+ _visitor.visit_item_mut(it)
+ }
+ };
+ if let Some(ref mut it) = _i.semi {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_static_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemStatic) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.static_token.span);
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_expr_mut(&mut *_i.expr);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemStruct) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.struct_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ _visitor.visit_fields_mut(&mut _i.fields);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_item_trait_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemTrait) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ if let Some(ref mut it) = _i.unsafety {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.auto_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.trait_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.supertraits) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for it in &mut _i.items {
+ _visitor.visit_trait_item_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemType) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_union_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemUnion) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.union_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ _visitor.visit_fields_named_mut(&mut _i.fields);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_use_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemUse) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_visibility_mut(&mut _i.vis);
+ tokens_helper(_visitor, &mut _i.use_token.span);
+ if let Some(ref mut it) = _i.leading_colon {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_use_tree_mut(&mut _i.tree);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_item_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemVerbatim) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_label_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Label) {
+ _visitor.visit_lifetime_mut(&mut _i.name);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lifetime_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Lifetime) {
+ skip!(_i.apostrophe);
+ _visitor.visit_ident_mut(&mut _i.ident);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lifetime_def_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LifetimeDef) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_lifetime_mut(&mut _i.lifetime);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_lifetime_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Lit) {
+ match *_i {
+ Lit::Str(ref mut _binding_0) => {
+ _visitor.visit_lit_str_mut(_binding_0);
+ }
+ Lit::ByteStr(ref mut _binding_0) => {
+ _visitor.visit_lit_byte_str_mut(_binding_0);
+ }
+ Lit::Byte(ref mut _binding_0) => {
+ _visitor.visit_lit_byte_mut(_binding_0);
+ }
+ Lit::Char(ref mut _binding_0) => {
+ _visitor.visit_lit_char_mut(_binding_0);
+ }
+ Lit::Int(ref mut _binding_0) => {
+ _visitor.visit_lit_int_mut(_binding_0);
+ }
+ Lit::Float(ref mut _binding_0) => {
+ _visitor.visit_lit_float_mut(_binding_0);
+ }
+ Lit::Bool(ref mut _binding_0) => {
+ _visitor.visit_lit_bool_mut(_binding_0);
+ }
+ Lit::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_lit_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_bool_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitBool) {
+ skip!(_i.value);
+ _visitor.visit_span_mut(&mut _i.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_byte_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitByte) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_byte_str_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitByteStr) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_char_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitChar) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_float_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitFloat) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_int_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitInt) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_str_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitStr) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_lit_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitVerbatim) {
+ skip!(_i.token);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_local_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Local) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.let_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.pats) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ if let Some(ref mut it) = _i.ty {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_type_mut(&mut *(it).1);
+ };
+ if let Some(ref mut it) = _i.init {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_expr_mut(&mut *(it).1);
+ };
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Macro) {
+ _visitor.visit_path_mut(&mut _i.path);
+ tokens_helper(_visitor, &mut _i.bang_token.spans);
+ _visitor.visit_macro_delimiter_mut(&mut _i.delimiter);
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_macro_delimiter_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MacroDelimiter) {
+ match *_i {
+ MacroDelimiter::Paren(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.span);
+ }
+ MacroDelimiter::Brace(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.span);
+ }
+ MacroDelimiter::Bracket(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.span);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_member_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Member) {
+ match *_i {
+ Member::Named(ref mut _binding_0) => {
+ _visitor.visit_ident_mut(_binding_0);
+ }
+ Member::Unnamed(ref mut _binding_0) => {
+ _visitor.visit_index_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Meta) {
+ match *_i {
+ Meta::Word(ref mut _binding_0) => {
+ _visitor.visit_ident_mut(_binding_0);
+ }
+ Meta::List(ref mut _binding_0) => {
+ _visitor.visit_meta_list_mut(_binding_0);
+ }
+ Meta::NameValue(ref mut _binding_0) => {
+ _visitor.visit_meta_name_value_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta_list_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MetaList) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.nested) {
+ let it = el.value_mut();
+ _visitor.visit_nested_meta_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_meta_name_value_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MetaNameValue) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_lit_mut(&mut _i.lit);
+}
+#[cfg(feature = "full")]
+pub fn visit_method_sig_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MethodSig) {
+ if let Some(ref mut it) = _i.constness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.unsafety {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.asyncness {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.abi {
+ _visitor.visit_abi_mut(it)
+ };
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_fn_decl_mut(&mut _i.decl);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_method_turbofish_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut MethodTurbofish,
+) {
+ tokens_helper(_visitor, &mut _i.colon2_token.spans);
+ tokens_helper(_visitor, &mut _i.lt_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.args) {
+ let it = el.value_mut();
+ _visitor.visit_generic_method_argument_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_nested_meta_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut NestedMeta) {
+ match *_i {
+ NestedMeta::Meta(ref mut _binding_0) => {
+ _visitor.visit_meta_mut(_binding_0);
+ }
+ NestedMeta::Literal(ref mut _binding_0) => {
+ _visitor.visit_lit_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_parenthesized_generic_arguments_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut ParenthesizedGenericArguments,
+) {
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.inputs) {
+ let it = el.value_mut();
+ _visitor.visit_type_mut(it)
+ }
+ _visitor.visit_return_type_mut(&mut _i.output);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Pat) {
+ match *_i {
+ Pat::Wild(ref mut _binding_0) => {
+ _visitor.visit_pat_wild_mut(_binding_0);
+ }
+ Pat::Ident(ref mut _binding_0) => {
+ _visitor.visit_pat_ident_mut(_binding_0);
+ }
+ Pat::Struct(ref mut _binding_0) => {
+ _visitor.visit_pat_struct_mut(_binding_0);
+ }
+ Pat::TupleStruct(ref mut _binding_0) => {
+ _visitor.visit_pat_tuple_struct_mut(_binding_0);
+ }
+ Pat::Path(ref mut _binding_0) => {
+ _visitor.visit_pat_path_mut(_binding_0);
+ }
+ Pat::Tuple(ref mut _binding_0) => {
+ _visitor.visit_pat_tuple_mut(_binding_0);
+ }
+ Pat::Box(ref mut _binding_0) => {
+ _visitor.visit_pat_box_mut(_binding_0);
+ }
+ Pat::Ref(ref mut _binding_0) => {
+ _visitor.visit_pat_ref_mut(_binding_0);
+ }
+ Pat::Lit(ref mut _binding_0) => {
+ _visitor.visit_pat_lit_mut(_binding_0);
+ }
+ Pat::Range(ref mut _binding_0) => {
+ _visitor.visit_pat_range_mut(_binding_0);
+ }
+ Pat::Slice(ref mut _binding_0) => {
+ _visitor.visit_pat_slice_mut(_binding_0);
+ }
+ Pat::Macro(ref mut _binding_0) => {
+ _visitor.visit_pat_macro_mut(_binding_0);
+ }
+ Pat::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_pat_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_box_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatBox) {
+ tokens_helper(_visitor, &mut _i.box_token.span);
+ _visitor.visit_pat_mut(&mut *_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_ident_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatIdent) {
+ if let Some(ref mut it) = _i.by_ref {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_ident_mut(&mut _i.ident);
+ if let Some(ref mut it) = _i.subpat {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_pat_mut(&mut *(it).1);
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatLit) {
+ _visitor.visit_expr_mut(&mut *_i.expr);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatMacro) {
+ _visitor.visit_macro_mut(&mut _i.mac);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatPath) {
+ if let Some(ref mut it) = _i.qself {
+ _visitor.visit_qself_mut(it)
+ };
+ _visitor.visit_path_mut(&mut _i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_range_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatRange) {
+ _visitor.visit_expr_mut(&mut *_i.lo);
+ _visitor.visit_range_limits_mut(&mut _i.limits);
+ _visitor.visit_expr_mut(&mut *_i.hi);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_ref_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatRef) {
+ tokens_helper(_visitor, &mut _i.and_token.spans);
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_pat_mut(&mut *_i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_slice_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatSlice) {
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.front) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ if let Some(ref mut it) = _i.middle {
+ _visitor.visit_pat_mut(&mut **it)
+ };
+ if let Some(ref mut it) = _i.dot2_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.comma_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.back) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatStruct) {
+ _visitor.visit_path_mut(&mut _i.path);
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.fields) {
+ let it = el.value_mut();
+ _visitor.visit_field_pat_mut(it)
+ }
+ if let Some(ref mut it) = _i.dot2_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatTuple) {
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.front) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+ if let Some(ref mut it) = _i.dot2_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.comma_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.back) {
+ let it = el.value_mut();
+ _visitor.visit_pat_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_tuple_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatTupleStruct) {
+ _visitor.visit_path_mut(&mut _i.path);
+ _visitor.visit_pat_tuple_mut(&mut _i.pat);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatVerbatim) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_pat_wild_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatWild) {
+ tokens_helper(_visitor, &mut _i.underscore_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Path) {
+ if let Some(ref mut it) = _i.leading_colon {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.segments) {
+ let it = el.value_mut();
+ _visitor.visit_path_segment_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path_arguments_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PathArguments) {
+ match *_i {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(ref mut _binding_0) => {
+ _visitor.visit_angle_bracketed_generic_arguments_mut(_binding_0);
+ }
+ PathArguments::Parenthesized(ref mut _binding_0) => {
+ _visitor.visit_parenthesized_generic_arguments_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_path_segment_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PathSegment) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_path_arguments_mut(&mut _i.arguments);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_eq_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PredicateEq) {
+ _visitor.visit_type_mut(&mut _i.lhs_ty);
+ tokens_helper(_visitor, &mut _i.eq_token.spans);
+ _visitor.visit_type_mut(&mut _i.rhs_ty);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_lifetime_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut PredicateLifetime,
+) {
+ _visitor.visit_lifetime_mut(&mut _i.lifetime);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_lifetime_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_predicate_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PredicateType) {
+ if let Some(ref mut it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes_mut(it)
+ };
+ _visitor.visit_type_mut(&mut _i.bounded_ty);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_qself_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut QSelf) {
+ tokens_helper(_visitor, &mut _i.lt_token.spans);
+ _visitor.visit_type_mut(&mut *_i.ty);
+ skip!(_i.position);
+ if let Some(ref mut it) = _i.as_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ tokens_helper(_visitor, &mut _i.gt_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_range_limits_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut RangeLimits) {
+ match *_i {
+ RangeLimits::HalfOpen(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ RangeLimits::Closed(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_return_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ReturnType) {
+ match *_i {
+ ReturnType::Default => {}
+ ReturnType::Type(ref mut _binding_0, ref mut _binding_1) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ _visitor.visit_type_mut(&mut **_binding_1);
+ }
+ }
+}
+pub fn visit_span_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Span) {}
+#[cfg(any(feature = "full", feature = "derive"))]
+#[cfg(feature = "full")]
+pub fn visit_stmt_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Stmt) {
+ match *_i {
+ Stmt::Local(ref mut _binding_0) => {
+ _visitor.visit_local_mut(_binding_0);
+ }
+ Stmt::Item(ref mut _binding_0) => {
+ _visitor.visit_item_mut(_binding_0);
+ }
+ Stmt::Expr(ref mut _binding_0) => {
+ _visitor.visit_expr_mut(_binding_0);
+ }
+ Stmt::Semi(ref mut _binding_0, ref mut _binding_1) => {
+ _visitor.visit_expr_mut(_binding_0);
+ tokens_helper(_visitor, &mut _binding_1.spans);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_trait_bound_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitBound) {
+ if let Some(ref mut it) = _i.paren_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_trait_bound_modifier_mut(&mut _i.modifier);
+ if let Some(ref mut it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes_mut(it)
+ };
+ _visitor.visit_path_mut(&mut _i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_trait_bound_modifier_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut TraitBoundModifier,
+) {
+ match *_i {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItem) {
+ match *_i {
+ TraitItem::Const(ref mut _binding_0) => {
+ _visitor.visit_trait_item_const_mut(_binding_0);
+ }
+ TraitItem::Method(ref mut _binding_0) => {
+ _visitor.visit_trait_item_method_mut(_binding_0);
+ }
+ TraitItem::Type(ref mut _binding_0) => {
+ _visitor.visit_trait_item_type_mut(_binding_0);
+ }
+ TraitItem::Existential(ref mut _binding_0) => {
+ _visitor.visit_trait_item_existential_mut(_binding_0);
+ }
+ TraitItem::Macro(ref mut _binding_0) => {
+ _visitor.visit_trait_item_macro_mut(_binding_0);
+ }
+ TraitItem::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_trait_item_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemConst) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.const_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon_token.spans);
+ _visitor.visit_type_mut(&mut _i.ty);
+ if let Some(ref mut it) = _i.default {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_expr_mut(&mut (it).1);
+ };
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_existential_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut TraitItemExistential,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.existential_token.span);
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemMacro) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_macro_mut(&mut _i.mac);
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_method_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut TraitItemMethod,
+) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_method_sig_mut(&mut _i.sig);
+ if let Some(ref mut it) = _i.default {
+ _visitor.visit_block_mut(it)
+ };
+ if let Some(ref mut it) = _i.semi_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemType) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ tokens_helper(_visitor, &mut _i.type_token.span);
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_generics_mut(&mut _i.generics);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ if let Some(ref mut it) = _i.default {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_type_mut(&mut (it).1);
+ };
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_trait_item_verbatim_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut TraitItemVerbatim,
+) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Type) {
+ match *_i {
+ Type::Slice(ref mut _binding_0) => {
+ _visitor.visit_type_slice_mut(_binding_0);
+ }
+ Type::Array(ref mut _binding_0) => {
+ _visitor.visit_type_array_mut(_binding_0);
+ }
+ Type::Ptr(ref mut _binding_0) => {
+ _visitor.visit_type_ptr_mut(_binding_0);
+ }
+ Type::Reference(ref mut _binding_0) => {
+ _visitor.visit_type_reference_mut(_binding_0);
+ }
+ Type::BareFn(ref mut _binding_0) => {
+ _visitor.visit_type_bare_fn_mut(_binding_0);
+ }
+ Type::Never(ref mut _binding_0) => {
+ _visitor.visit_type_never_mut(_binding_0);
+ }
+ Type::Tuple(ref mut _binding_0) => {
+ _visitor.visit_type_tuple_mut(_binding_0);
+ }
+ Type::Path(ref mut _binding_0) => {
+ _visitor.visit_type_path_mut(_binding_0);
+ }
+ Type::TraitObject(ref mut _binding_0) => {
+ _visitor.visit_type_trait_object_mut(_binding_0);
+ }
+ Type::ImplTrait(ref mut _binding_0) => {
+ _visitor.visit_type_impl_trait_mut(_binding_0);
+ }
+ Type::Paren(ref mut _binding_0) => {
+ _visitor.visit_type_paren_mut(_binding_0);
+ }
+ Type::Group(ref mut _binding_0) => {
+ _visitor.visit_type_group_mut(_binding_0);
+ }
+ Type::Infer(ref mut _binding_0) => {
+ _visitor.visit_type_infer_mut(_binding_0);
+ }
+ Type::Macro(ref mut _binding_0) => {
+ _visitor.visit_type_macro_mut(_binding_0);
+ }
+ Type::Verbatim(ref mut _binding_0) => {
+ _visitor.visit_type_verbatim_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_array_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeArray) {
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ _visitor.visit_type_mut(&mut *_i.elem);
+ tokens_helper(_visitor, &mut _i.semi_token.spans);
+ _visitor.visit_expr_mut(&mut _i.len);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_bare_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeBareFn) {
+ if let Some(ref mut it) = _i.unsafety {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.abi {
+ _visitor.visit_abi_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.fn_token.span);
+ if let Some(ref mut it) = _i.lifetimes {
+ _visitor.visit_bound_lifetimes_mut(it)
+ };
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.inputs) {
+ let it = el.value_mut();
+ _visitor.visit_bare_fn_arg_mut(it)
+ }
+ if let Some(ref mut it) = _i.variadic {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ _visitor.visit_return_type_mut(&mut _i.output);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeGroup) {
+ tokens_helper(_visitor, &mut _i.group_token.span);
+ _visitor.visit_type_mut(&mut *_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_impl_trait_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeImplTrait) {
+ tokens_helper(_visitor, &mut _i.impl_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_infer_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeInfer) {
+ tokens_helper(_visitor, &mut _i.underscore_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeMacro) {
+ _visitor.visit_macro_mut(&mut _i.mac);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_never_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeNever) {
+ tokens_helper(_visitor, &mut _i.bang_token.spans);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParam) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_ident_mut(&mut _i.ident);
+ if let Some(ref mut it) = _i.colon_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+ if let Some(ref mut it) = _i.eq_token {
+ tokens_helper(_visitor, &mut it.spans)
+ };
+ if let Some(ref mut it) = _i.default {
+ _visitor.visit_type_mut(it)
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_param_bound_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParamBound) {
+ match *_i {
+ TypeParamBound::Trait(ref mut _binding_0) => {
+ _visitor.visit_trait_bound_mut(_binding_0);
+ }
+ TypeParamBound::Lifetime(ref mut _binding_0) => {
+ _visitor.visit_lifetime_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_paren_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParen) {
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ _visitor.visit_type_mut(&mut *_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypePath) {
+ if let Some(ref mut it) = _i.qself {
+ _visitor.visit_qself_mut(it)
+ };
+ _visitor.visit_path_mut(&mut _i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_ptr_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypePtr) {
+ tokens_helper(_visitor, &mut _i.star_token.spans);
+ if let Some(ref mut it) = _i.const_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_type_mut(&mut *_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_reference_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeReference) {
+ tokens_helper(_visitor, &mut _i.and_token.spans);
+ if let Some(ref mut it) = _i.lifetime {
+ _visitor.visit_lifetime_mut(it)
+ };
+ if let Some(ref mut it) = _i.mutability {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_type_mut(&mut *_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_slice_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeSlice) {
+ tokens_helper(_visitor, &mut _i.bracket_token.span);
+ _visitor.visit_type_mut(&mut *_i.elem);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_trait_object_mut<V: VisitMut + ?Sized>(
+ _visitor: &mut V,
+ _i: &mut TypeTraitObject,
+) {
+ if let Some(ref mut it) = _i.dyn_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ for mut el in Punctuated::pairs_mut(&mut _i.bounds) {
+ let it = el.value_mut();
+ _visitor.visit_type_param_bound_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeTuple) {
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.elems) {
+ let it = el.value_mut();
+ _visitor.visit_type_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_type_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeVerbatim) {
+ skip!(_i.tts);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_un_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UnOp) {
+ match *_i {
+ UnOp::Deref(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ UnOp::Not(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ UnOp::Neg(ref mut _binding_0) => {
+ tokens_helper(_visitor, &mut _binding_0.spans);
+ }
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_glob_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseGlob) {
+ tokens_helper(_visitor, &mut _i.star_token.spans);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseGroup) {
+ tokens_helper(_visitor, &mut _i.brace_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.items) {
+ let it = el.value_mut();
+ _visitor.visit_use_tree_mut(it)
+ }
+}
+#[cfg(feature = "full")]
+pub fn visit_use_name_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseName) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UsePath) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.colon2_token.spans);
+ _visitor.visit_use_tree_mut(&mut *_i.tree);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_rename_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseRename) {
+ _visitor.visit_ident_mut(&mut _i.ident);
+ tokens_helper(_visitor, &mut _i.as_token.span);
+ _visitor.visit_ident_mut(&mut _i.rename);
+}
+#[cfg(feature = "full")]
+pub fn visit_use_tree_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseTree) {
+ match *_i {
+ UseTree::Path(ref mut _binding_0) => {
+ _visitor.visit_use_path_mut(_binding_0);
+ }
+ UseTree::Name(ref mut _binding_0) => {
+ _visitor.visit_use_name_mut(_binding_0);
+ }
+ UseTree::Rename(ref mut _binding_0) => {
+ _visitor.visit_use_rename_mut(_binding_0);
+ }
+ UseTree::Glob(ref mut _binding_0) => {
+ _visitor.visit_use_glob_mut(_binding_0);
+ }
+ UseTree::Group(ref mut _binding_0) => {
+ _visitor.visit_use_group_mut(_binding_0);
+ }
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_variant_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Variant) {
+ for it in &mut _i.attrs {
+ _visitor.visit_attribute_mut(it)
+ }
+ _visitor.visit_ident_mut(&mut _i.ident);
+ _visitor.visit_fields_mut(&mut _i.fields);
+ if let Some(ref mut it) = _i.discriminant {
+ tokens_helper(_visitor, &mut (it).0.spans);
+ _visitor.visit_expr_mut(&mut (it).1);
+ };
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_crate_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisCrate) {
+ tokens_helper(_visitor, &mut _i.crate_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_public_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisPublic) {
+ tokens_helper(_visitor, &mut _i.pub_token.span);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_vis_restricted_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisRestricted) {
+ tokens_helper(_visitor, &mut _i.pub_token.span);
+ tokens_helper(_visitor, &mut _i.paren_token.span);
+ if let Some(ref mut it) = _i.in_token {
+ tokens_helper(_visitor, &mut it.span)
+ };
+ _visitor.visit_path_mut(&mut *_i.path);
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_visibility_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Visibility) {
+ match *_i {
+ Visibility::Public(ref mut _binding_0) => {
+ _visitor.visit_vis_public_mut(_binding_0);
+ }
+ Visibility::Crate(ref mut _binding_0) => {
+ _visitor.visit_vis_crate_mut(_binding_0);
+ }
+ Visibility::Restricted(ref mut _binding_0) => {
+ _visitor.visit_vis_restricted_mut(_binding_0);
+ }
+ Visibility::Inherited => {}
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_where_clause_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut WhereClause) {
+ tokens_helper(_visitor, &mut _i.where_token.span);
+ for mut el in Punctuated::pairs_mut(&mut _i.predicates) {
+ let it = el.value_mut();
+ _visitor.visit_where_predicate_mut(it)
+ }
+}
+#[cfg(any(feature = "full", feature = "derive"))]
+pub fn visit_where_predicate_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut WherePredicate) {
+ match *_i {
+ WherePredicate::Type(ref mut _binding_0) => {
+ _visitor.visit_predicate_type_mut(_binding_0);
+ }
+ WherePredicate::Lifetime(ref mut _binding_0) => {
+ _visitor.visit_predicate_lifetime_mut(_binding_0);
+ }
+ WherePredicate::Eq(ref mut _binding_0) => {
+ _visitor.visit_predicate_eq_mut(_binding_0);
+ }
+ }
+}
diff --git a/src/gen_helper.rs b/src/gen_helper.rs
new file mode 100644
index 0000000..fe00c8f
--- /dev/null
+++ b/src/gen_helper.rs
@@ -0,0 +1,162 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature = "fold")]
+pub mod fold {
+ use fold::Fold;
+ use proc_macro2::Span;
+ use punctuated::{Pair, Punctuated};
+
+ pub trait FoldHelper {
+ type Item;
+ fn lift<F>(self, f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item;
+ }
+
+ impl<T> FoldHelper for Vec<T> {
+ type Item = T;
+ fn lift<F>(self, f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item,
+ {
+ self.into_iter().map(f).collect()
+ }
+ }
+
+ impl<T, U> FoldHelper for Punctuated<T, U> {
+ type Item = T;
+ fn lift<F>(self, mut f: F) -> Self
+ where
+ F: FnMut(Self::Item) -> Self::Item,
+ {
+ self.into_pairs()
+ .map(Pair::into_tuple)
+ .map(|(t, u)| Pair::new(f(t), u))
+ .collect()
+ }
+ }
+
+ pub fn tokens_helper<F: Fold + ?Sized, S: Spans>(folder: &mut F, spans: &S) -> S {
+ spans.fold(folder)
+ }
+
+ pub trait Spans {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self;
+ }
+
+ impl Spans for Span {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ folder.fold_span(*self)
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [folder.fold_span(self[0])]
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [folder.fold_span(self[0]), folder.fold_span(self[1])]
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self {
+ [
+ folder.fold_span(self[0]),
+ folder.fold_span(self[1]),
+ folder.fold_span(self[2]),
+ ]
+ }
+ }
+}
+
+#[cfg(feature = "visit")]
+pub mod visit {
+ use proc_macro2::Span;
+ use visit::Visit;
+
+ pub fn tokens_helper<'ast, V: Visit<'ast> + ?Sized, S: Spans>(visitor: &mut V, spans: &'ast S) {
+ spans.visit(visitor);
+ }
+
+ pub trait Spans {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V);
+ }
+
+ impl Spans for Span {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) {
+ visitor.visit_span(self);
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ visitor.visit_span(&self[1]);
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) {
+ visitor.visit_span(&self[0]);
+ visitor.visit_span(&self[1]);
+ visitor.visit_span(&self[2]);
+ }
+ }
+}
+
+#[cfg(feature = "visit-mut")]
+pub mod visit_mut {
+ use proc_macro2::Span;
+ use visit_mut::VisitMut;
+
+ pub fn tokens_helper<V: VisitMut + ?Sized, S: Spans>(visitor: &mut V, spans: &mut S) {
+ spans.visit_mut(visitor);
+ }
+
+ pub trait Spans {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V);
+ }
+
+ impl Spans for Span {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(self);
+ }
+ }
+
+ impl Spans for [Span; 1] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ }
+ }
+
+ impl Spans for [Span; 2] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ visitor.visit_span_mut(&mut self[1]);
+ }
+ }
+
+ impl Spans for [Span; 3] {
+ fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) {
+ visitor.visit_span_mut(&mut self[0]);
+ visitor.visit_span_mut(&mut self[1]);
+ visitor.visit_span_mut(&mut self[2]);
+ }
+ }
+}
diff --git a/src/generics.rs b/src/generics.rs
new file mode 100644
index 0000000..fb8d672
--- /dev/null
+++ b/src/generics.rs
@@ -0,0 +1,1015 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use punctuated::{Iter, IterMut, Punctuated};
+
+ast_struct! {
+ /// Lifetimes and type parameters attached to a declaration of a function,
+ /// enum, trait, etc.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Default)]
+ pub struct Generics {
+ pub lt_token: Option<Token![<]>,
+ pub params: Punctuated<GenericParam, Token![,]>,
+ pub gt_token: Option<Token![>]>,
+ pub where_clause: Option<WhereClause>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
+ /// `'a: 'b`, `const LEN: usize`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum GenericParam {
+ /// A generic type parameter: `T: Into<String>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Type(TypeParam {
+ pub attrs: Vec<Attribute>,
+ pub ident: Ident,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub eq_token: Option<Token![=]>,
+ pub default: Option<Type>,
+ }),
+
+ /// A lifetime definition: `'a: 'b + 'c + 'd`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Lifetime(LifetimeDef {
+ pub attrs: Vec<Attribute>,
+ pub lifetime: Lifetime,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<Lifetime, Token![+]>,
+ }),
+
+ /// A const generic parameter: `const LENGTH: usize`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Const(ConstParam {
+ pub attrs: Vec<Attribute>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub eq_token: Option<Token![=]>,
+ pub default: Option<Expr>,
+ }),
+ }
+}
+
+impl Generics {
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &</code><a
+ /// href="struct.TypeParam.html"><code
+ /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the type parameters in `self.params`.
+ pub fn type_params(&self) -> TypeParams {
+ TypeParams(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &mut </code><a
+ /// href="struct.TypeParam.html"><code
+ /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the type parameters in `self.params`.
+ pub fn type_params_mut(&mut self) -> TypeParamsMut {
+ TypeParamsMut(self.params.iter_mut())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &</code><a
+ /// href="struct.LifetimeDef.html"><code
+ /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the lifetime parameters in `self.params`.
+ pub fn lifetimes(&self) -> Lifetimes {
+ Lifetimes(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &mut </code><a
+ /// href="struct.LifetimeDef.html"><code
+ /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the lifetime parameters in `self.params`.
+ pub fn lifetimes_mut(&mut self) -> LifetimesMut {
+ LifetimesMut(self.params.iter_mut())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &</code><a
+ /// href="struct.ConstParam.html"><code
+ /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the constant parameters in `self.params`.
+ pub fn const_params(&self) -> ConstParams {
+ ConstParams(self.params.iter())
+ }
+
+ /// Returns an
+ /// <code
+ /// style="padding-right:0;">Iterator<Item = &mut </code><a
+ /// href="struct.ConstParam.html"><code
+ /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
+ /// style="padding-left:0;">></code>
+ /// over the constant parameters in `self.params`.
+ pub fn const_params_mut(&mut self) -> ConstParamsMut {
+ ConstParamsMut(self.params.iter_mut())
+ }
+
+ /// Initializes an empty `where`-clause if there is not one present already.
+ pub fn make_where_clause(&mut self) -> &mut WhereClause {
+ // This is Option::get_or_insert_with in Rust 1.20.
+ if self.where_clause.is_none() {
+ self.where_clause = Some(WhereClause {
+ where_token: <Token![where]>::default(),
+ predicates: Punctuated::new(),
+ });
+ }
+ match self.where_clause {
+ Some(ref mut where_clause) => where_clause,
+ None => unreachable!(),
+ }
+ }
+}
+
+pub struct TypeParams<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for TypeParams<'a> {
+ type Item = &'a TypeParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Type(ref type_param) = *next {
+ Some(type_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for TypeParamsMut<'a> {
+ type Item = &'a mut TypeParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Type(ref mut type_param) = *next {
+ Some(type_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct Lifetimes<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for Lifetimes<'a> {
+ type Item = &'a LifetimeDef;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Lifetime(ref lifetime) = *next {
+ Some(lifetime)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for LifetimesMut<'a> {
+ type Item = &'a mut LifetimeDef;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Lifetime(ref mut lifetime) = *next {
+ Some(lifetime)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct ConstParams<'a>(Iter<'a, GenericParam>);
+
+impl<'a> Iterator for ConstParams<'a> {
+ type Item = &'a ConstParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Const(ref const_param) = *next {
+ Some(const_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>);
+
+impl<'a> Iterator for ConstParamsMut<'a> {
+ type Item = &'a mut ConstParam;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // FIXME: Remove this when ? on Option is stable
+ let next = match self.0.next() {
+ Some(item) => item,
+ None => return None,
+ };
+ if let GenericParam::Const(ref mut const_param) = *next {
+ Some(const_param)
+ } else {
+ self.next()
+ }
+ }
+}
+
+/// Returned by `Generics::split_for_impl`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct ImplGenerics<'a>(&'a Generics);
+
+/// Returned by `Generics::split_for_impl`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct TypeGenerics<'a>(&'a Generics);
+
+/// Returned by `TypeGenerics::as_turbofish`.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct Turbofish<'a>(&'a Generics);
+
+#[cfg(feature = "printing")]
+impl Generics {
+ /// Split a type's generics into the pieces required for impl'ing a trait
+ /// for that type.
+ ///
+ /// ```
+ /// # extern crate proc_macro2;
+ /// # extern crate syn;
+ /// # #[macro_use]
+ /// # extern crate quote;
+ /// # use proc_macro2::{Span, Ident};
+ /// # fn main() {
+ /// # let generics: syn::Generics = Default::default();
+ /// # let name = Ident::new("MyType", Span::call_site());
+ /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+ /// quote! {
+ /// impl #impl_generics MyTrait for #name #ty_generics #where_clause {
+ /// // ...
+ /// }
+ /// }
+ /// # ;
+ /// # }
+ /// ```
+ ///
+ /// *This method is available if Syn is built with the `"derive"` or
+ /// `"full"` feature and the `"printing"` feature.*
+ pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
+ (
+ ImplGenerics(self),
+ TypeGenerics(self),
+ self.where_clause.as_ref(),
+ )
+ }
+}
+
+#[cfg(feature = "printing")]
+impl<'a> TypeGenerics<'a> {
+ /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
+ ///
+ /// *This method is available if Syn is built with the `"derive"` or
+ /// `"full"` feature and the `"printing"` feature.*
+ pub fn as_turbofish(&self) -> Turbofish {
+ Turbofish(self.0)
+ }
+}
+
+ast_struct! {
+ /// A set of bound lifetimes: `for<'a, 'b, 'c>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[derive(Default)]
+ pub struct BoundLifetimes {
+ pub for_token: Token![for],
+ pub lt_token: Token![<],
+ pub lifetimes: Punctuated<LifetimeDef, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+impl LifetimeDef {
+ pub fn new(lifetime: Lifetime) -> Self {
+ LifetimeDef {
+ attrs: Vec::new(),
+ lifetime: lifetime,
+ colon_token: None,
+ bounds: Punctuated::new(),
+ }
+ }
+}
+
+impl From<Ident> for TypeParam {
+ fn from(ident: Ident) -> Self {
+ TypeParam {
+ attrs: vec![],
+ ident: ident,
+ colon_token: None,
+ bounds: Punctuated::new(),
+ eq_token: None,
+ default: None,
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// A trait or lifetime used as a bound on a type parameter.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum TypeParamBound {
+ pub Trait(TraitBound),
+ pub Lifetime(Lifetime),
+ }
+}
+
+ast_struct! {
+ /// A trait used as a bound on a type parameter.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct TraitBound {
+ pub paren_token: Option<token::Paren>,
+ pub modifier: TraitBoundModifier,
+ /// The `for<'a>` in `for<'a> Foo<&'a T>`
+ pub lifetimes: Option<BoundLifetimes>,
+ /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`
+ pub path: Path,
+ }
+}
+
+ast_enum! {
+ /// A modifier on a trait bound, currently only used for the `?` in
+ /// `?Sized`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum TraitBoundModifier {
+ None,
+ Maybe(Token![?]),
+ }
+}
+
+ast_struct! {
+ /// A `where` clause in a definition: `where T: Deserialize<'de>, D:
+ /// 'static`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct WhereClause {
+ pub where_token: Token![where],
+ pub predicates: Punctuated<WherePredicate, Token![,]>,
+ }
+}
+
+ast_enum_of_structs! {
+ /// A single predicate in a `where` clause: `T: Deserialize<'de>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum WherePredicate {
+ /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Type(PredicateType {
+ /// Any lifetimes from a `for` binding
+ pub lifetimes: Option<BoundLifetimes>,
+ /// The type being bounded
+ pub bounded_ty: Type,
+ pub colon_token: Token![:],
+ /// Trait and lifetime bounds (`Clone+Send+'static`)
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }),
+
+ /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Lifetime(PredicateLifetime {
+ pub lifetime: Lifetime,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<Lifetime, Token![+]>,
+ }),
+
+ /// An equality predicate in a `where` clause (unsupported).
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Eq(PredicateEq {
+ pub lhs_ty: Type,
+ pub eq_token: Token![=],
+ pub rhs_ty: Type,
+ }),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use punctuated::Pair;
+ use synom::Synom;
+
+ impl Synom for Generics {
+ named!(parse -> Self, map!(
+ alt!(
+ do_parse!(
+ lt: punct!(<) >>
+ lifetimes: call!(Punctuated::<LifetimeDef, Token![,]>::parse_terminated) >>
+ ty_params: cond!(
+ lifetimes.empty_or_trailing(),
+ Punctuated::<TypeParam, Token![,]>::parse_terminated
+ ) >>
+ gt: punct!(>) >>
+ (lifetimes, ty_params, Some(lt), Some(gt))
+ )
+ |
+ epsilon!() => { |_| (Punctuated::new(), None, None, None) }
+ ),
+ |(lifetimes, ty_params, lt, gt)| Generics {
+ lt_token: lt,
+ params: lifetimes.into_pairs()
+ .map(Pair::into_tuple)
+ .map(|(life, comma)| Pair::new(GenericParam::Lifetime(life), comma))
+ .chain(ty_params.unwrap_or_default()
+ .into_pairs()
+ .map(Pair::into_tuple)
+ .map(|(ty, comma)| Pair::new(GenericParam::Type(ty), comma)))
+ .collect(),
+ gt_token: gt,
+ where_clause: None,
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("generic parameters in declaration")
+ }
+ }
+
+ impl Synom for GenericParam {
+ named!(parse -> Self, alt!(
+ syn!(TypeParam) => { GenericParam::Type }
+ |
+ syn!(LifetimeDef) => { GenericParam::Lifetime }
+ |
+ syn!(ConstParam) => { GenericParam::Const }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("generic parameter")
+ }
+ }
+
+ impl Synom for LifetimeDef {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ life: syn!(Lifetime) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(
+ colon.is_some(),
+ Punctuated::parse_separated_nonempty
+ ) >>
+ (LifetimeDef {
+ attrs: attrs,
+ lifetime: life,
+ bounds: bounds.unwrap_or_default(),
+ colon_token: colon,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("lifetime definition")
+ }
+ }
+
+ impl Synom for BoundLifetimes {
+ named!(parse -> Self, do_parse!(
+ for_: keyword!(for) >>
+ lt: punct!(<) >>
+ lifetimes: call!(Punctuated::parse_terminated) >>
+ gt: punct!(>) >>
+ (BoundLifetimes {
+ for_token: for_,
+ lt_token: lt,
+ gt_token: gt,
+ lifetimes: lifetimes,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("bound lifetimes")
+ }
+ }
+
+ impl Synom for TypeParam {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ id: syn!(Ident) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(
+ colon.is_some(),
+ Punctuated::parse_separated_nonempty
+ ) >>
+ default: option!(do_parse!(
+ eq: punct!(=) >>
+ ty: syn!(Type) >>
+ (eq, ty)
+ )) >>
+ (TypeParam {
+ attrs: attrs,
+ ident: id,
+ bounds: bounds.unwrap_or_default(),
+ colon_token: colon,
+ eq_token: default.as_ref().map(|d| Token),
+ default: default.map(|d| d.1),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("type parameter")
+ }
+ }
+
+ impl Synom for TypeParamBound {
+ named!(parse -> Self, alt!(
+ syn!(Lifetime) => { TypeParamBound::Lifetime }
+ |
+ syn!(TraitBound) => { TypeParamBound::Trait }
+ |
+ parens!(syn!(TraitBound)) => {|(parens, mut bound)| {
+ bound.paren_token = Some(parens);
+ TypeParamBound::Trait(bound)
+ }}
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("type parameter bound")
+ }
+ }
+
+ impl Synom for TraitBound {
+ named!(parse -> Self, do_parse!(
+ modifier: syn!(TraitBoundModifier) >>
+ lifetimes: option!(syn!(BoundLifetimes)) >>
+ mut path: syn!(Path) >>
+ parenthesized: option!(cond_reduce!(
+ path.segments.last().unwrap().value().arguments.is_empty(),
+ syn!(ParenthesizedGenericArguments)
+ )) >>
+ ({
+ if let Some(parenthesized) = parenthesized {
+ let parenthesized = PathArguments::Parenthesized(parenthesized);
+ path.segments.last_mut().unwrap().value_mut().arguments = parenthesized;
+ }
+ TraitBound {
+ paren_token: None,
+ modifier: modifier,
+ lifetimes: lifetimes,
+ path: path,
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("trait bound")
+ }
+ }
+
+ impl Synom for TraitBoundModifier {
+ named!(parse -> Self, alt!(
+ punct!(?) => { TraitBoundModifier::Maybe }
+ |
+ epsilon!() => { |_| TraitBoundModifier::None }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("trait bound modifier")
+ }
+ }
+
+ impl Synom for ConstParam {
+ named!(parse -> Self, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ const_: keyword!(const) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ eq_def: option!(tuple!(punct!(=), syn!(Expr))) >>
+ ({
+ let (eq_token, default) = match eq_def {
+ Some((eq_token, default)) => (Some(eq_token), Some(default)),
+ None => (None, None),
+ };
+ ConstParam {
+ attrs: attrs,
+ const_token: const_,
+ ident: ident,
+ colon_token: colon,
+ ty: ty,
+ eq_token: eq_token,
+ default: default,
+ }
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("generic `const` parameter")
+ }
+ }
+
+ impl Synom for WhereClause {
+ named!(parse -> Self, do_parse!(
+ where_: keyword!(where) >>
+ predicates: call!(Punctuated::parse_terminated) >>
+ (WhereClause {
+ predicates: predicates,
+ where_token: where_,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("where clause")
+ }
+ }
+
+ impl Synom for WherePredicate {
+ named!(parse -> Self, alt!(
+ do_parse!(
+ ident: syn!(Lifetime) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(
+ colon.is_some(),
+ Punctuated::parse_separated
+ ) >>
+ (WherePredicate::Lifetime(PredicateLifetime {
+ lifetime: ident,
+ bounds: bounds.unwrap_or_default(),
+ colon_token: colon,
+ }))
+ )
+ |
+ do_parse!(
+ lifetimes: option!(syn!(BoundLifetimes)) >>
+ bounded_ty: syn!(Type) >>
+ colon: punct!(:) >>
+ bounds: call!(Punctuated::parse_separated_nonempty) >>
+ (WherePredicate::Type(PredicateType {
+ lifetimes: lifetimes,
+ bounded_ty: bounded_ty,
+ bounds: bounds,
+ colon_token: colon,
+ }))
+ )
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("predicate in where clause")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for Generics {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.lt_token).to_tokens(tokens);
+
+ // Print lifetimes before types and consts, regardless of their
+ // order in self.params.
+ //
+ // TODO: ordering rules for const parameters vs type parameters have
+ // not been settled yet. https://github.com/rust-lang/rust/issues/44580
+ let mut trailing_or_empty = true;
+ for param in self.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.params.pairs() {
+ match **param.value() {
+ GenericParam::Type(_) | GenericParam::Const(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ param.to_tokens(tokens);
+ }
+ GenericParam::Lifetime(_) => {}
+ }
+ }
+
+ TokensOrDefault(&self.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for ImplGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.0.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
+
+ // Print lifetimes before types and consts, regardless of their
+ // order in self.params.
+ //
+ // TODO: ordering rules for const parameters vs type parameters have
+ // not been settled yet. https://github.com/rust-lang/rust/issues/44580
+ let mut trailing_or_empty = true;
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ continue;
+ }
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ match **param.value() {
+ GenericParam::Lifetime(_) => unreachable!(),
+ GenericParam::Type(ref param) => {
+ // Leave off the type parameter defaults
+ tokens.append_all(param.attrs.outer());
+ param.ident.to_tokens(tokens);
+ if !param.bounds.is_empty() {
+ TokensOrDefault(¶m.colon_token).to_tokens(tokens);
+ param.bounds.to_tokens(tokens);
+ }
+ }
+ GenericParam::Const(ref param) => {
+ // Leave off the const parameter defaults
+ tokens.append_all(param.attrs.outer());
+ param.const_token.to_tokens(tokens);
+ param.ident.to_tokens(tokens);
+ param.colon_token.to_tokens(tokens);
+ param.ty.to_tokens(tokens);
+ }
+ }
+ param.punct().to_tokens(tokens);
+ }
+
+ TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for TypeGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if self.0.params.is_empty() {
+ return;
+ }
+
+ TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
+
+ // Print lifetimes before types and consts, regardless of their
+ // order in self.params.
+ //
+ // TODO: ordering rules for const parameters vs type parameters have
+ // not been settled yet. https://github.com/rust-lang/rust/issues/44580
+ let mut trailing_or_empty = true;
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(ref def) = **param.value() {
+ // Leave off the lifetime bounds and attributes
+ def.lifetime.to_tokens(tokens);
+ param.punct().to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.0.params.pairs() {
+ if let GenericParam::Lifetime(_) = **param.value() {
+ continue;
+ }
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ match **param.value() {
+ GenericParam::Lifetime(_) => unreachable!(),
+ GenericParam::Type(ref param) => {
+ // Leave off the type parameter defaults
+ param.ident.to_tokens(tokens);
+ }
+ GenericParam::Const(ref param) => {
+ // Leave off the const parameter defaults
+ param.ident.to_tokens(tokens);
+ }
+ }
+ param.punct().to_tokens(tokens);
+ }
+
+ TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for Turbofish<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.0.params.is_empty() {
+ <Token![::]>::default().to_tokens(tokens);
+ TypeGenerics(self.0).to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for BoundLifetimes {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.for_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+ self.lifetimes.to_tokens(tokens);
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LifetimeDef {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.lifetime.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for TypeParam {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.ident.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ if self.default.is_some() {
+ TokensOrDefault(&self.eq_token).to_tokens(tokens);
+ self.default.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for TraitBound {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let to_tokens = |tokens: &mut TokenStream| {
+ self.modifier.to_tokens(tokens);
+ self.lifetimes.to_tokens(tokens);
+ self.path.to_tokens(tokens);
+ };
+ match self.paren_token {
+ Some(ref paren) => paren.surround(tokens, to_tokens),
+ None => to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for TraitBoundModifier {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe(ref t) => t.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for ConstParam {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ if self.default.is_some() {
+ TokensOrDefault(&self.eq_token).to_tokens(tokens);
+ self.default.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for WhereClause {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if !self.predicates.is_empty() {
+ self.where_token.to_tokens(tokens);
+ self.predicates.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for PredicateType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetimes.to_tokens(tokens);
+ self.bounded_ty.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PredicateLifetime {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetime.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for PredicateEq {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lhs_ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.rhs_ty.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/item.rs b/src/item.rs
new file mode 100644
index 0000000..cb6184d
--- /dev/null
+++ b/src/item.rs
@@ -0,0 +1,2249 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use derive::{Data, DeriveInput};
+use proc_macro2::TokenStream;
+use punctuated::Punctuated;
+use token::{Brace, Paren};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "extra-traits")]
+use tt::TokenStreamHelper;
+
+ast_enum_of_structs! {
+ /// Things that can appear directly inside of a module or scope.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Item {
+ /// An `extern crate` item: `extern crate serde`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub ExternCrate(ItemExternCrate {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub extern_token: Token![extern],
+ pub crate_token: Token![crate],
+ pub ident: Ident,
+ pub rename: Option<(Token![as], Ident)>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A use declaration: `use std::collections::HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Use(ItemUse {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub use_token: Token![use],
+ pub leading_colon: Option<Token![::]>,
+ pub tree: UseTree,
+ pub semi_token: Token![;],
+ }),
+
+ /// A static item: `static BIKE: Shed = Shed(42)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Static(ItemStatic {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub static_token: Token![static],
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A constant item: `const MAX: u16 = 65535`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Const(ItemConst {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub eq_token: Token![=],
+ pub expr: Box<Expr>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
+ /// }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Fn(ItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub constness: Option<Token![const]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub asyncness: Option<Token![async]>,
+ pub abi: Option<Abi>,
+ pub ident: Ident,
+ pub decl: Box<FnDecl>,
+ pub block: Box<Block>,
+ }),
+
+ /// A module or module declaration: `mod m` or `mod m { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Mod(ItemMod {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub mod_token: Token![mod],
+ pub ident: Ident,
+ pub content: Option<(token::Brace, Vec<Item>)>,
+ pub semi: Option<Token![;]>,
+ }),
+
+ /// A block of foreign items: `extern "C" { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub ForeignMod(ItemForeignMod {
+ pub attrs: Vec<Attribute>,
+ pub abi: Abi,
+ pub brace_token: token::Brace,
+ pub items: Vec<ForeignItem>,
+ }),
+
+ /// A type alias: `type Result<T> = std::result::Result<T, MyError>`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Type(ItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub eq_token: Token![=],
+ pub ty: Box<Type>,
+ pub semi_token: Token![;],
+ }),
+
+ /// An existential type: `existential type Iter: Iterator<Item = u8>`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Existential(ItemExistential {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub existential_token: Token![existential],
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A struct definition: `struct Foo<A> { x: A }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Struct(ItemStruct {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub struct_token: Token![struct],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub fields: Fields,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// An enum definition: `enum Foo<A, B> { C<A>, D<B> }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Enum(ItemEnum {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub enum_token: Token![enum],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub brace_token: token::Brace,
+ pub variants: Punctuated<Variant, Token![,]>,
+ }),
+
+ /// A union definition: `union Foo<A, B> { x: A, y: B }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Union(ItemUnion {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub union_token: Token![union],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub fields: FieldsNamed,
+ }),
+
+ /// A trait definition: `pub trait Iterator { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Trait(ItemTrait {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub unsafety: Option<Token![unsafe]>,
+ pub auto_token: Option<Token![auto]>,
+ pub trait_token: Token![trait],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub supertraits: Punctuated<TypeParamBound, Token![+]>,
+ pub brace_token: token::Brace,
+ pub items: Vec<TraitItem>,
+ }),
+
+ /// An impl block providing trait or associated items: `impl<A> Trait
+ /// for Data<A> { ... }`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Impl(ItemImpl {
+ pub attrs: Vec<Attribute>,
+ pub defaultness: Option<Token![default]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub impl_token: Token![impl],
+ pub generics: Generics,
+ /// Trait this impl implements.
+ pub trait_: Option<(Option<Token![!]>, Path, Token![for])>,
+ /// The Self type of the impl.
+ pub self_ty: Box<Type>,
+ pub brace_token: token::Brace,
+ pub items: Vec<ImplItem>,
+ }),
+
+ /// A macro invocation, which includes `macro_rules!` definitions.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(ItemMacro {
+ pub attrs: Vec<Attribute>,
+ /// The `example` in `macro_rules! example { ... }`.
+ pub ident: Option<Ident>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// A 2.0-style declarative macro introduced by the `macro` keyword.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro2(ItemMacro2 #manual_extra_traits {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub macro_token: Token![macro],
+ pub ident: Ident,
+ pub paren_token: Paren,
+ pub args: TokenStream,
+ pub brace_token: Brace,
+ pub body: TokenStream,
+ }),
+
+ /// Tokens forming an item not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Verbatim(ItemVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ItemMacro2 {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ItemMacro2 {
+ fn eq(&self, other: &Self) -> bool {
+ self.attrs == other.attrs
+ && self.vis == other.vis
+ && self.macro_token == other.macro_token
+ && self.ident == other.ident
+ && self.paren_token == other.paren_token
+ && TokenStreamHelper(&self.args) == TokenStreamHelper(&other.args)
+ && self.brace_token == other.brace_token
+ && TokenStreamHelper(&self.body) == TokenStreamHelper(&other.body)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ItemMacro2 {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.attrs.hash(state);
+ self.vis.hash(state);
+ self.macro_token.hash(state);
+ self.ident.hash(state);
+ self.paren_token.hash(state);
+ TokenStreamHelper(&self.args).hash(state);
+ self.brace_token.hash(state);
+ TokenStreamHelper(&self.body).hash(state);
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ItemVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ItemVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ItemVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+impl From<DeriveInput> for Item {
+ fn from(input: DeriveInput) -> Item {
+ match input.data {
+ Data::Struct(data) => Item::Struct(ItemStruct {
+ attrs: input.attrs,
+ vis: input.vis,
+ struct_token: data.struct_token,
+ ident: input.ident,
+ generics: input.generics,
+ fields: data.fields,
+ semi_token: data.semi_token,
+ }),
+ Data::Enum(data) => Item::Enum(ItemEnum {
+ attrs: input.attrs,
+ vis: input.vis,
+ enum_token: data.enum_token,
+ ident: input.ident,
+ generics: input.generics,
+ brace_token: data.brace_token,
+ variants: data.variants,
+ }),
+ Data::Union(data) => Item::Union(ItemUnion {
+ attrs: input.attrs,
+ vis: input.vis,
+ union_token: data.union_token,
+ ident: input.ident,
+ generics: input.generics,
+ fields: data.fields,
+ }),
+ }
+ }
+}
+
+ast_enum_of_structs! {
+ /// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum UseTree {
+ /// A path prefix of imports in a `use` item: `std::...`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Path(UsePath {
+ pub ident: Ident,
+ pub colon2_token: Token![::],
+ pub tree: Box<UseTree>,
+ }),
+
+ /// An identifier imported by a `use` item: `HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Name(UseName {
+ pub ident: Ident,
+ }),
+
+ /// An renamed identifier imported by a `use` item: `HashMap as Map`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Rename(UseRename {
+ pub ident: Ident,
+ pub as_token: Token![as],
+ pub rename: Ident,
+ }),
+
+ /// A glob import in a `use` item: `*`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Glob(UseGlob {
+ pub star_token: Token![*],
+ }),
+
+ /// A braced group of imports in a `use` item: `{A, B, C}`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Group(UseGroup {
+ pub brace_token: token::Brace,
+ pub items: Punctuated<UseTree, Token![,]>,
+ }),
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item within an `extern` block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum ForeignItem {
+ /// A foreign function in an `extern` block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Fn(ForeignItemFn {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub ident: Ident,
+ pub decl: Box<FnDecl>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A foreign static item in an `extern` block: `static ext: u8`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Static(ForeignItemStatic {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub static_token: Token![static],
+ pub mutability: Option<Token![mut]>,
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Box<Type>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A foreign type in an `extern` block: `type void`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Type(ForeignItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub semi_token: Token![;],
+ }),
+
+ /// A macro invocation within an extern block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(ForeignItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// Tokens in an `extern` block not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Verbatim(ForeignItemVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ForeignItemVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ForeignItemVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ForeignItemVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item declaration within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum TraitItem {
+ /// An associated constant within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Const(TraitItemConst {
+ pub attrs: Vec<Attribute>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub default: Option<(Token![=], Expr)>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A trait method within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Method(TraitItemMethod {
+ pub attrs: Vec<Attribute>,
+ pub sig: MethodSig,
+ pub default: Option<Block>,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// An associated type within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Type(TraitItemType {
+ pub attrs: Vec<Attribute>,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub default: Option<(Token![=], Type)>,
+ pub semi_token: Token![;],
+ }),
+
+ /// An existential type within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Existential(TraitItemExistential {
+ pub attrs: Vec<Attribute>,
+ pub existential_token: Token![existential],
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A macro invocation within the definition of a trait.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(TraitItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// Tokens within the definition of a trait not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Verbatim(TraitItemVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for TraitItemVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for TraitItemVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for TraitItemVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+ast_enum_of_structs! {
+ /// An item within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum ImplItem {
+ /// An associated constant within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Const(ImplItemConst {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub const_token: Token![const],
+ pub ident: Ident,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ pub eq_token: Token![=],
+ pub expr: Expr,
+ pub semi_token: Token![;],
+ }),
+
+ /// A method within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Method(ImplItemMethod {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub sig: MethodSig,
+ pub block: Block,
+ }),
+
+ /// An associated type within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Type(ImplItemType {
+ pub attrs: Vec<Attribute>,
+ pub vis: Visibility,
+ pub defaultness: Option<Token![default]>,
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub eq_token: Token![=],
+ pub ty: Type,
+ pub semi_token: Token![;],
+ }),
+
+ /// An existential type within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Existential(ImplItemExistential {
+ pub attrs: Vec<Attribute>,
+ pub existential_token: Token![existential],
+ pub type_token: Token![type],
+ pub ident: Ident,
+ pub generics: Generics,
+ pub colon_token: Option<Token![:]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ pub semi_token: Token![;],
+ }),
+
+ /// A macro invocation within an impl block.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Macro(ImplItemMacro {
+ pub attrs: Vec<Attribute>,
+ pub mac: Macro,
+ pub semi_token: Option<Token![;]>,
+ }),
+
+ /// Tokens within an impl block not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Verbatim(ImplItemVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for ImplItemVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for ImplItemVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for ImplItemVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+ast_struct! {
+ /// A method's signature in a trait or implementation: `unsafe fn
+ /// initialize(&self)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct MethodSig {
+ pub constness: Option<Token![const]>,
+ pub unsafety: Option<Token![unsafe]>,
+ pub asyncness: Option<Token![async]>,
+ pub abi: Option<Abi>,
+ pub ident: Ident,
+ pub decl: FnDecl,
+ }
+}
+
+ast_struct! {
+ /// Header of a function declaration, without including the body.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub struct FnDecl {
+ pub fn_token: Token![fn],
+ pub generics: Generics,
+ pub paren_token: token::Paren,
+ pub inputs: Punctuated<FnArg, Token![,]>,
+ pub variadic: Option<Token![...]>,
+ pub output: ReturnType,
+ }
+}
+
+ast_enum_of_structs! {
+ /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum FnArg {
+ /// Self captured by reference in a function signature: `&self` or `&mut
+ /// self`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub SelfRef(ArgSelfRef {
+ pub and_token: Token![&],
+ pub lifetime: Option<Lifetime>,
+ pub mutability: Option<Token![mut]>,
+ pub self_token: Token![self],
+ }),
+
+ /// Self captured by value in a function signature: `self` or `mut
+ /// self`.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub SelfValue(ArgSelf {
+ pub mutability: Option<Token![mut]>,
+ pub self_token: Token![self],
+ }),
+
+ /// An explicitly typed pattern captured by a function signature.
+ ///
+ /// *This type is available if Syn is built with the `"full"` feature.*
+ pub Captured(ArgCaptured {
+ pub pat: Pat,
+ pub colon_token: Token![:],
+ pub ty: Type,
+ }),
+
+ /// A pattern whose type is inferred captured by a function signature.
+ pub Inferred(Pat),
+ /// A type not bound to any pattern in a function signature.
+ pub Ignored(Type),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use synom::Synom;
+
+ impl_synom!(Item "item" alt!(
+ syn!(ItemExternCrate) => { Item::ExternCrate }
+ |
+ syn!(ItemUse) => { Item::Use }
+ |
+ syn!(ItemStatic) => { Item::Static }
+ |
+ syn!(ItemConst) => { Item::Const }
+ |
+ syn!(ItemFn) => { Item::Fn }
+ |
+ syn!(ItemMod) => { Item::Mod }
+ |
+ syn!(ItemForeignMod) => { Item::ForeignMod }
+ |
+ syn!(ItemType) => { Item::Type }
+ |
+ syn!(ItemExistential) => { Item::Existential }
+ |
+ syn!(ItemStruct) => { Item::Struct }
+ |
+ syn!(ItemEnum) => { Item::Enum }
+ |
+ syn!(ItemUnion) => { Item::Union }
+ |
+ syn!(ItemTrait) => { Item::Trait }
+ |
+ syn!(ItemImpl) => { Item::Impl }
+ |
+ syn!(ItemMacro) => { Item::Macro }
+ |
+ syn!(ItemMacro2) => { Item::Macro2 }
+ ));
+
+ impl_synom!(ItemMacro "macro item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ what: call!(Path::parse_mod_style) >>
+ bang: punct!(!) >>
+ ident: option!(syn!(Ident)) >>
+ body: call!(tt::delimited) >>
+ semi: cond!(!is_brace(&body.0), punct!(;)) >>
+ (ItemMacro {
+ attrs: attrs,
+ ident: ident,
+ mac: Macro {
+ path: what,
+ bang_token: bang,
+ delimiter: body.0,
+ tts: body.1,
+ },
+ semi_token: semi,
+ })
+ ));
+
+ // TODO: figure out the actual grammar; is body required to be braced?
+ impl_synom!(ItemMacro2 "macro2 item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ macro_: keyword!(macro) >>
+ ident: syn!(Ident) >>
+ args: call!(tt::parenthesized) >>
+ body: call!(tt::braced) >>
+ (ItemMacro2 {
+ attrs: attrs,
+ vis: vis,
+ macro_token: macro_,
+ ident: ident,
+ paren_token: args.0,
+ args: args.1,
+ brace_token: body.0,
+ body: body.1,
+ })
+ ));
+
+ impl_synom!(ItemExternCrate "extern crate item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ extern_: keyword!(extern) >>
+ crate_: keyword!(crate) >>
+ ident: syn!(Ident) >>
+ rename: option!(tuple!(keyword!(as), syn!(Ident))) >>
+ semi: punct!(;) >>
+ (ItemExternCrate {
+ attrs: attrs,
+ vis: vis,
+ extern_token: extern_,
+ crate_token: crate_,
+ ident: ident,
+ rename: rename,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemUse "use item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ use_: keyword!(use) >>
+ leading_colon: option!(punct!(::)) >>
+ tree: syn!(UseTree) >>
+ semi: punct!(;) >>
+ (ItemUse {
+ attrs: attrs,
+ vis: vis,
+ use_token: use_,
+ leading_colon: leading_colon,
+ tree: tree,
+ semi_token: semi,
+ })
+ ));
+
+ named!(use_element -> Ident, alt!(
+ syn!(Ident)
+ |
+ keyword!(self) => { Into::into }
+ |
+ keyword!(super) => { Into::into }
+ |
+ keyword!(crate) => { Into::into }
+ |
+ keyword!(extern) => { Into::into }
+ ));
+
+ impl_synom!(UseTree "use tree" alt!(
+ syn!(UseRename) => { UseTree::Rename }
+ |
+ syn!(UsePath) => { UseTree::Path }
+ |
+ syn!(UseName) => { UseTree::Name }
+ |
+ syn!(UseGlob) => { UseTree::Glob }
+ |
+ syn!(UseGroup) => { UseTree::Group }
+ ));
+
+ impl_synom!(UsePath "use path" do_parse!(
+ ident: call!(use_element) >>
+ colon2_token: punct!(::) >>
+ tree: syn!(UseTree) >>
+ (UsePath {
+ ident: ident,
+ colon2_token: colon2_token,
+ tree: Box::new(tree),
+ })
+ ));
+
+ impl_synom!(UseName "use name" do_parse!(
+ ident: call!(use_element) >>
+ (UseName {
+ ident: ident,
+ })
+ ));
+
+ impl_synom!(UseRename "use rename" do_parse!(
+ ident: call!(use_element) >>
+ as_token: keyword!(as) >>
+ rename: syn!(Ident) >>
+ (UseRename {
+ ident: ident,
+ as_token: as_token,
+ rename: rename,
+ })
+ ));
+
+ impl_synom!(UseGlob "use glob" do_parse!(
+ star: punct!(*) >>
+ (UseGlob {
+ star_token: star,
+ })
+ ));
+
+ impl_synom!(UseGroup "use group" do_parse!(
+ list: braces!(Punctuated::parse_terminated) >>
+ (UseGroup {
+ brace_token: list.0,
+ items: list.1,
+ })
+ ));
+
+ impl_synom!(ItemStatic "static item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ static_: keyword!(static) >>
+ mutability: option!(keyword!(mut)) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ eq: punct!(=) >>
+ value: syn!(Expr) >>
+ semi: punct!(;) >>
+ (ItemStatic {
+ attrs: attrs,
+ vis: vis,
+ static_token: static_,
+ mutability: mutability,
+ ident: ident,
+ colon_token: colon,
+ ty: Box::new(ty),
+ eq_token: eq,
+ expr: Box::new(value),
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemConst "const item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ const_: keyword!(const) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ eq: punct!(=) >>
+ value: syn!(Expr) >>
+ semi: punct!(;) >>
+ (ItemConst {
+ attrs: attrs,
+ vis: vis,
+ const_token: const_,
+ ident: ident,
+ colon_token: colon,
+ ty: Box::new(ty),
+ eq_token: eq,
+ expr: Box::new(value),
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemFn "fn item" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ constness: option!(keyword!(const)) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ asyncness: option!(keyword!(async)) >>
+ abi: option!(syn!(Abi)) >>
+ fn_: keyword!(fn) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ inputs: parens!(Punctuated::parse_terminated) >>
+ ret: syn!(ReturnType) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ inner_attrs_stmts: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ItemFn {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((inner_attrs_stmts.1).0);
+ attrs
+ },
+ vis: vis,
+ constness: constness,
+ unsafety: unsafety,
+ asyncness: asyncness,
+ abi: abi,
+ decl: Box::new(FnDecl {
+ fn_token: fn_,
+ paren_token: inputs.0,
+ inputs: inputs.1,
+ output: ret,
+ variadic: None,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ }),
+ ident: ident,
+ block: Box::new(Block {
+ brace_token: inner_attrs_stmts.0,
+ stmts: (inner_attrs_stmts.1).1,
+ }),
+ })
+ ));
+
+ impl Synom for FnArg {
+ named!(parse -> Self, alt!(
+ do_parse!(
+ and: punct!(&) >>
+ lt: option!(syn!(Lifetime)) >>
+ mutability: option!(keyword!(mut)) >>
+ self_: keyword!(self) >>
+ not!(punct!(:)) >>
+ (ArgSelfRef {
+ lifetime: lt,
+ mutability: mutability,
+ and_token: and,
+ self_token: self_,
+ }.into())
+ )
+ |
+ do_parse!(
+ mutability: option!(keyword!(mut)) >>
+ self_: keyword!(self) >>
+ not!(punct!(:)) >>
+ (ArgSelf {
+ mutability: mutability,
+ self_token: self_,
+ }.into())
+ )
+ |
+ do_parse!(
+ pat: syn!(Pat) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ (ArgCaptured {
+ pat: pat,
+ ty: ty,
+ colon_token: colon,
+ }.into())
+ )
+ |
+ syn!(Type) => { FnArg::Ignored }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("function argument")
+ }
+ }
+
+ impl_synom!(ItemMod "mod item" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ mod_: keyword!(mod) >>
+ ident: syn!(Ident) >>
+ content_semi: alt!(
+ punct!(;) => {|semi| (
+ Vec::new(),
+ None,
+ Some(semi),
+ )}
+ |
+ braces!(
+ tuple!(
+ many0!(Attribute::parse_inner),
+ many0!(Item::parse),
+ )
+ ) => {|(brace, (inner_attrs, items))| (
+ inner_attrs,
+ Some((brace, items)),
+ None,
+ )}
+ ) >>
+ (ItemMod {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend(content_semi.0);
+ attrs
+ },
+ vis: vis,
+ mod_token: mod_,
+ ident: ident,
+ content: content_semi.1,
+ semi: content_semi.2,
+ })
+ ));
+
+ impl_synom!(ItemForeignMod "foreign mod item" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ abi: syn!(Abi) >>
+ braced_content: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ many0!(ForeignItem::parse),
+ )) >>
+ (ItemForeignMod {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((braced_content.1).0);
+ attrs
+ },
+ abi: abi,
+ brace_token: braced_content.0,
+ items: (braced_content.1).1,
+ })
+ ));
+
+ impl_synom!(ForeignItem "foreign item" alt!(
+ syn!(ForeignItemFn) => { ForeignItem::Fn }
+ |
+ syn!(ForeignItemStatic) => { ForeignItem::Static }
+ |
+ syn!(ForeignItemType) => { ForeignItem::Type }
+ |
+ syn!(ForeignItemMacro) => { ForeignItem::Macro }
+ ));
+
+ impl_synom!(ForeignItemFn "foreign function" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ fn_: keyword!(fn) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ inputs: parens!(do_parse!(
+ args: call!(Punctuated::parse_terminated) >>
+ variadic: option!(cond_reduce!(args.empty_or_trailing(), punct!(...))) >>
+ (args, variadic)
+ )) >>
+ ret: syn!(ReturnType) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ semi: punct!(;) >>
+ ({
+ let (parens, (inputs, variadic)) = inputs;
+ ForeignItemFn {
+ ident: ident,
+ attrs: attrs,
+ semi_token: semi,
+ decl: Box::new(FnDecl {
+ fn_token: fn_,
+ paren_token: parens,
+ inputs: inputs,
+ variadic: variadic,
+ output: ret,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ }),
+ vis: vis,
+ }
+ })
+ ));
+
+ impl_synom!(ForeignItemStatic "foreign static" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ static_: keyword!(static) >>
+ mutability: option!(keyword!(mut)) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ semi: punct!(;) >>
+ (ForeignItemStatic {
+ ident: ident,
+ attrs: attrs,
+ semi_token: semi,
+ ty: Box::new(ty),
+ mutability: mutability,
+ static_token: static_,
+ colon_token: colon,
+ vis: vis,
+ })
+ ));
+
+ impl_synom!(ForeignItemType "foreign type" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ type_: keyword!(type) >>
+ ident: syn!(Ident) >>
+ semi: punct!(;) >>
+ (ForeignItemType {
+ attrs: attrs,
+ vis: vis,
+ type_token: type_,
+ ident: ident,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ForeignItemMacro "macro in extern block" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ mac: syn!(Macro) >>
+ semi: cond!(!is_brace(&mac.delimiter), punct!(;)) >>
+ (ForeignItemMacro {
+ attrs: attrs,
+ mac: mac,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemType "type item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ type_: keyword!(type) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ eq: punct!(=) >>
+ ty: syn!(Type) >>
+ semi: punct!(;) >>
+ (ItemType {
+ attrs: attrs,
+ vis: vis,
+ type_token: type_,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ eq_token: eq,
+ ty: Box::new(ty),
+ semi_token: semi,
+ })
+ ));
+
+ named!(existential_type(vis: bool) -> ItemExistential, do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: cond_reduce!(vis, syn!(Visibility)) >>
+ existential_token: keyword!(existential) >>
+ type_token: keyword!(type) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(
+ colon.is_some(),
+ Punctuated::<TypeParamBound, Token![+]>::parse_separated_nonempty
+ ) >>
+ semi: punct!(;) >>
+ (ItemExistential {
+ attrs: attrs,
+ vis: vis,
+ existential_token: existential_token,
+ type_token: type_token,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ colon_token: colon,
+ bounds: bounds.unwrap_or_else(Punctuated::new),
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemExistential "existential type" call!(existential_type, true));
+
+ impl_synom!(ItemStruct "struct item" switch!(
+ map!(syn!(DeriveInput), Into::into),
+ Item::Struct(item) => value!(item)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(ItemEnum "enum item" switch!(
+ map!(syn!(DeriveInput), Into::into),
+ Item::Enum(item) => value!(item)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(ItemUnion "union item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ union_: keyword!(union) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ fields: syn!(FieldsNamed) >>
+ (ItemUnion {
+ attrs: attrs,
+ vis: vis,
+ union_token: union_,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ fields: fields,
+ })
+ ));
+
+ impl_synom!(ItemTrait "trait item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ auto_: option!(keyword!(auto)) >>
+ trait_: keyword!(trait) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(colon.is_some(), Punctuated::parse_separated_nonempty) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ body: braces!(many0!(TraitItem::parse)) >>
+ (ItemTrait {
+ attrs: attrs,
+ vis: vis,
+ unsafety: unsafety,
+ auto_token: auto_,
+ trait_token: trait_,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ colon_token: colon,
+ supertraits: bounds.unwrap_or_default(),
+ brace_token: body.0,
+ items: body.1,
+ })
+ ));
+
+ impl_synom!(TraitItem "trait item" alt!(
+ syn!(TraitItemConst) => { TraitItem::Const }
+ |
+ syn!(TraitItemMethod) => { TraitItem::Method }
+ |
+ syn!(TraitItemType) => { TraitItem::Type }
+ |
+ syn!(TraitItemExistential) => { TraitItem::Existential }
+ |
+ syn!(TraitItemMacro) => { TraitItem::Macro }
+ ));
+
+ impl_synom!(TraitItemConst "const trait item" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ const_: keyword!(const) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ default: option!(tuple!(punct!(=), syn!(Expr))) >>
+ semi: punct!(;) >>
+ (TraitItemConst {
+ attrs: attrs,
+ const_token: const_,
+ ident: ident,
+ colon_token: colon,
+ ty: ty,
+ default: default,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(TraitItemMethod "method trait item" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ constness: option!(keyword!(const)) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ abi: option!(syn!(Abi)) >>
+ fn_: keyword!(fn) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ inputs: parens!(Punctuated::parse_terminated) >>
+ ret: syn!(ReturnType) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ body: option!(braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ ))) >>
+ semi: cond!(body.is_none(), punct!(;)) >>
+ ({
+ let (inner_attrs, stmts) = match body {
+ Some((b, (inner_attrs, stmts))) => (inner_attrs, Some((stmts, b))),
+ None => (Vec::new(), None),
+ };
+ TraitItemMethod {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend(inner_attrs);
+ attrs
+ },
+ sig: MethodSig {
+ constness: constness,
+ unsafety: unsafety,
+ asyncness: None,
+ abi: abi,
+ ident: ident,
+ decl: FnDecl {
+ inputs: inputs.1,
+ output: ret,
+ fn_token: fn_,
+ paren_token: inputs.0,
+ variadic: None,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ },
+ },
+ default: stmts.map(|stmts| {
+ Block {
+ stmts: stmts.0,
+ brace_token: stmts.1,
+ }
+ }),
+ semi_token: semi,
+ }
+ })
+ ));
+
+ impl_synom!(TraitItemType "trait item type" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ type_: keyword!(type) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ colon: option!(punct!(:)) >>
+ bounds: cond!(colon.is_some(), Punctuated::parse_separated_nonempty) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ default: option!(tuple!(punct!(=), syn!(Type))) >>
+ semi: punct!(;) >>
+ (TraitItemType {
+ attrs: attrs,
+ type_token: type_,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ colon_token: colon,
+ bounds: bounds.unwrap_or_default(),
+ default: default,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(TraitItemExistential "trait item existential type" map!(
+ call!(existential_type, false),
+ |ety| TraitItemExistential {
+ attrs: ety.attrs,
+ existential_token: ety.existential_token,
+ type_token: ety.type_token,
+ ident: ety.ident,
+ generics: ety.generics,
+ colon_token: ety.colon_token,
+ bounds: ety.bounds,
+ semi_token: ety.semi_token,
+ }
+ ));
+
+ impl_synom!(TraitItemMacro "trait item macro" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ mac: syn!(Macro) >>
+ semi: cond!(!is_brace(&mac.delimiter), punct!(;)) >>
+ (TraitItemMacro {
+ attrs: attrs,
+ mac: mac,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ItemImpl "impl item" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ defaultness: option!(keyword!(default)) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ impl_: keyword!(impl) >>
+ generics: syn!(Generics) >>
+ polarity_path: alt!(
+ do_parse!(
+ polarity: option!(punct!(!)) >>
+ path: syn!(Path) >>
+ for_: keyword!(for) >>
+ (Some((polarity, path, for_)))
+ )
+ |
+ epsilon!() => { |_| None }
+ ) >>
+ self_ty: syn!(Type) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ inner: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ many0!(ImplItem::parse),
+ )) >>
+ (ItemImpl {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((inner.1).0);
+ attrs
+ },
+ defaultness: defaultness,
+ unsafety: unsafety,
+ impl_token: impl_,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ trait_: polarity_path,
+ self_ty: Box::new(self_ty),
+ brace_token: inner.0,
+ items: (inner.1).1,
+ })
+ ));
+
+ impl_synom!(ImplItem "item in impl block" alt!(
+ syn!(ImplItemConst) => { ImplItem::Const }
+ |
+ syn!(ImplItemMethod) => { ImplItem::Method }
+ |
+ syn!(ImplItemType) => { ImplItem::Type }
+ |
+ syn!(ImplItemExistential) => { ImplItem::Existential }
+ |
+ syn!(ImplItemMacro) => { ImplItem::Macro }
+ ));
+
+ impl_synom!(ImplItemConst "const item in impl block" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ defaultness: option!(keyword!(default)) >>
+ const_: keyword!(const) >>
+ ident: syn!(Ident) >>
+ colon: punct!(:) >>
+ ty: syn!(Type) >>
+ eq: punct!(=) >>
+ value: syn!(Expr) >>
+ semi: punct!(;) >>
+ (ImplItemConst {
+ attrs: attrs,
+ vis: vis,
+ defaultness: defaultness,
+ const_token: const_,
+ ident: ident,
+ colon_token: colon,
+ ty: ty,
+ eq_token: eq,
+ expr: value,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ImplItemMethod "method in impl block" do_parse!(
+ outer_attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ defaultness: option!(keyword!(default)) >>
+ constness: option!(keyword!(const)) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ asyncness: option!(keyword!(async)) >>
+ abi: option!(syn!(Abi)) >>
+ fn_: keyword!(fn) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ inputs: parens!(Punctuated::parse_terminated) >>
+ ret: syn!(ReturnType) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ inner_attrs_stmts: braces!(tuple!(
+ many0!(Attribute::parse_inner),
+ call!(Block::parse_within),
+ )) >>
+ (ImplItemMethod {
+ attrs: {
+ let mut attrs = outer_attrs;
+ attrs.extend((inner_attrs_stmts.1).0);
+ attrs
+ },
+ vis: vis,
+ defaultness: defaultness,
+ sig: MethodSig {
+ constness: constness,
+ unsafety: unsafety,
+ asyncness: asyncness,
+ abi: abi,
+ ident: ident,
+ decl: FnDecl {
+ fn_token: fn_,
+ paren_token: inputs.0,
+ inputs: inputs.1,
+ output: ret,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ variadic: None,
+ },
+ },
+ block: Block {
+ brace_token: inner_attrs_stmts.0,
+ stmts: (inner_attrs_stmts.1).1,
+ },
+ })
+ ));
+
+ impl_synom!(ImplItemType "type in impl block" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ vis: syn!(Visibility) >>
+ defaultness: option!(keyword!(default)) >>
+ type_: keyword!(type) >>
+ ident: syn!(Ident) >>
+ generics: syn!(Generics) >>
+ where_clause: option!(syn!(WhereClause)) >>
+ eq: punct!(=) >>
+ ty: syn!(Type) >>
+ semi: punct!(;) >>
+ (ImplItemType {
+ attrs: attrs,
+ vis: vis,
+ defaultness: defaultness,
+ type_token: type_,
+ ident: ident,
+ generics: Generics {
+ where_clause: where_clause,
+ ..generics
+ },
+ eq_token: eq,
+ ty: ty,
+ semi_token: semi,
+ })
+ ));
+
+ impl_synom!(ImplItemExistential "existential type in impl block" map!(
+ call!(existential_type, true),
+ |ety| ImplItemExistential {
+ attrs: ety.attrs,
+ existential_token: ety.existential_token,
+ type_token: ety.type_token,
+ ident: ety.ident,
+ generics: ety.generics,
+ colon_token: ety.colon_token,
+ bounds: ety.bounds,
+ semi_token: ety.semi_token,
+ }
+ ));
+
+ impl_synom!(ImplItemMacro "macro in impl block" do_parse!(
+ attrs: many0!(Attribute::parse_outer) >>
+ mac: syn!(Macro) >>
+ semi: cond!(!is_brace(&mac.delimiter), punct!(;)) >>
+ (ImplItemMacro {
+ attrs: attrs,
+ mac: mac,
+ semi_token: semi,
+ })
+ ));
+
+ fn is_brace(delimiter: &MacroDelimiter) -> bool {
+ match *delimiter {
+ MacroDelimiter::Brace(_) => true,
+ MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use attr::FilterAttrs;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for ItemExternCrate {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.extern_token.to_tokens(tokens);
+ self.crate_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((ref as_token, ref rename)) = self.rename {
+ as_token.to_tokens(tokens);
+ rename.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemUse {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.use_token.to_tokens(tokens);
+ self.leading_colon.to_tokens(tokens);
+ self.tree.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemStatic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.static_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.constness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.asyncness.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ impl ToTokens for ItemMod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.mod_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ if let Some((ref brace, ref items)) = self.content {
+ brace.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(items);
+ });
+ } else {
+ TokensOrDefault(&self.semi).to_tokens(tokens);
+ }
+ }
+ }
+
+ impl ToTokens for ItemForeignMod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.abi.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemExistential {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.existential_token.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemEnum {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.enum_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ self.variants.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ItemStruct {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.struct_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ match self.fields {
+ Fields::Named(ref fields) => {
+ self.generics.where_clause.to_tokens(tokens);
+ fields.to_tokens(tokens);
+ }
+ Fields::Unnamed(ref fields) => {
+ fields.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ Fields::Unit => {
+ self.generics.where_clause.to_tokens(tokens);
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for ItemUnion {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.union_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.fields.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemTrait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.auto_token.to_tokens(tokens);
+ self.trait_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if !self.supertraits.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.supertraits.to_tokens(tokens);
+ }
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemImpl {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.defaultness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.impl_token.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if let Some((ref polarity, ref path, ref for_token)) = self.trait_ {
+ polarity.to_tokens(tokens);
+ path.to_tokens(tokens);
+ for_token.to_tokens(tokens);
+ }
+ self.self_ty.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.items);
+ });
+ }
+ }
+
+ impl ToTokens for ItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.path.to_tokens(tokens);
+ self.mac.bang_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ match self.mac.delimiter {
+ MacroDelimiter::Paren(ref paren) => {
+ paren.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+ }
+ MacroDelimiter::Brace(ref brace) => {
+ brace.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+ }
+ MacroDelimiter::Bracket(ref bracket) => {
+ bracket.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+ }
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ItemMacro2 {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.macro_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ });
+ self.brace_token.surround(tokens, |tokens| {
+ self.body.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for ItemVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UsePath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.colon2_token.to_tokens(tokens);
+ self.tree.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseName {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseRename {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.as_token.to_tokens(tokens);
+ self.rename.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseGlob {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.star_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for UseGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.brace_token.surround(tokens, |tokens| {
+ self.items.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TraitItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ if let Some((ref eq_token, ref default)) = self.default {
+ eq_token.to_tokens(tokens);
+ default.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemMethod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.sig.to_tokens(tokens);
+ match self.default {
+ Some(ref block) => {
+ block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&block.stmts);
+ });
+ }
+ None => {
+ TokensOrDefault(&self.semi_token).to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for TraitItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ self.generics.where_clause.to_tokens(tokens);
+ if let Some((ref eq_token, ref default)) = self.default {
+ eq_token.to_tokens(tokens);
+ default.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemExistential {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.existential_token.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TraitItemVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemConst {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.const_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.expr.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemMethod {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.sig.to_tokens(tokens);
+ self.block.brace_token.surround(tokens, |tokens| {
+ tokens.append_all(self.attrs.inner());
+ tokens.append_all(&self.block.stmts);
+ });
+ }
+ }
+
+ impl ToTokens for ImplItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.defaultness.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemExistential {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.existential_token.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.generics.to_tokens(tokens);
+ self.generics.where_clause.to_tokens(tokens);
+ if !self.bounds.is_empty() {
+ TokensOrDefault(&self.colon_token).to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ImplItemVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemStatic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.static_token.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.vis.to_tokens(tokens);
+ self.type_token.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.attrs.outer());
+ self.mac.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ForeignItemVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for MethodSig {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.constness.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.asyncness.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ NamedDecl(&self.decl, &self.ident).to_tokens(tokens);
+ }
+ }
+
+ struct NamedDecl<'a>(&'a FnDecl, &'a Ident);
+
+ impl<'a> ToTokens for NamedDecl<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.fn_token.to_tokens(tokens);
+ self.1.to_tokens(tokens);
+ self.0.generics.to_tokens(tokens);
+ self.0.paren_token.surround(tokens, |tokens| {
+ self.0.inputs.to_tokens(tokens);
+ if self.0.variadic.is_some() && !self.0.inputs.empty_or_trailing() {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ self.0.variadic.to_tokens(tokens);
+ });
+ self.0.output.to_tokens(tokens);
+ self.0.generics.where_clause.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ArgSelfRef {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.and_token.to_tokens(tokens);
+ self.lifetime.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.self_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ArgSelf {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.mutability.to_tokens(tokens);
+ self.self_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ArgCaptured {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.pat.to_tokens(tokens);
+ self.colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 028ae2e..f917e30 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,9 +1,791 @@
-#![doc(html_root_url = "https://docs.rs/syn-error-experiment/0.0.0")]
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
-extern crate proc_macro2;
-extern crate syn;
+//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax
+//! tree of Rust source code.
+//!
+//! Currently this library is geared toward the [custom derive] use case but
+//! contains some APIs that may be useful for Rust procedural macros more
+//! generally.
+//!
+//! [custom derive]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
+//!
+//! - **Data structures** — Syn provides a complete syntax tree that can
+//! represent any valid Rust source code. The syntax tree is rooted at
+//! [`syn::File`] which represents a full source file, but there are other
+//! entry points that may be useful to procedural macros including
+//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`].
+//!
+//! - **Custom derives** — Of particular interest to custom derives is
+//! [`syn::DeriveInput`] which is any of the three legal input items to a
+//! derive macro. An example below shows using this type in a library that can
+//! derive implementations of a trait of your own.
+//!
+//! - **Parser combinators** — Parsing in Syn is built on a suite of public
+//! parser combinator macros that you can use for parsing any token-based
+//! syntax you dream up within a `functionlike!(...)` procedural macro. Every
+//! syntax tree node defined by Syn is individually parsable and may be used
+//! as a building block for custom syntaxes, or you may do it all yourself
+//! working from the most primitive tokens.
+//!
+//! - **Location information** — Every token parsed by Syn is associated with a
+//! `Span` that tracks line and column information back to the source of that
+//! token. These spans allow a procedural macro to display detailed error
+//! messages pointing to all the right places in the user's code. There is an
+//! example of this below.
+//!
+//! - **Feature flags** — Functionality is aggressively feature gated so your
+//! procedural macros enable only what they need, and do not pay in compile
+//! time for all the rest.
+//!
+//! [`syn::File`]: struct.File.html
+//! [`syn::Item`]: enum.Item.html
+//! [`syn::Expr`]: enum.Expr.html
+//! [`syn::Type`]: enum.Type.html
+//! [`syn::DeriveInput`]: struct.DeriveInput.html
+//!
+//! *Version requirement: Syn supports any compiler version back to Rust's very
+//! first support for procedural macros in Rust 1.15.0. Some features especially
+//! around error reporting are only available in newer compilers or on the
+//! nightly channel.*
+//!
+//! ## Example of a custom derive
+//!
+//! The canonical custom derive using Syn looks like this. We write an ordinary
+//! Rust function tagged with a `proc_macro_derive` attribute and the name of
+//! the trait we are deriving. Any time that derive appears in the user's code,
+//! the Rust compiler passes their data structure as tokens into our macro. We
+//! get to execute arbitrary Rust code to figure out what to do with those
+//! tokens, then hand some tokens back to the compiler to compile into the
+//! user's crate.
+//!
+//! [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
+//!
+//! ```toml
+//! [dependencies]
+//! syn = "0.14"
+//! quote = "0.6"
+//!
+//! [lib]
+//! proc-macro = true
+//! ```
+//!
+//! ```rust
+//! extern crate proc_macro;
+//! extern crate syn;
+//!
+//! #[macro_use]
+//! extern crate quote;
+//!
+//! use proc_macro::TokenStream;
+//! use syn::DeriveInput;
+//!
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[proc_macro_derive(MyMacro)]
+//! # };
+//! pub fn my_macro(input: TokenStream) -> TokenStream {
+//! // Parse the input tokens into a syntax tree
+//! let input: DeriveInput = syn::parse(input).unwrap();
+//!
+//! // Build the output, possibly using quasi-quotation
+//! let expanded = quote! {
+//! // ...
+//! };
+//!
+//! // Hand the output tokens back to the compiler
+//! expanded.into()
+//! }
+//! #
+//! # fn main() {}
+//! ```
+//!
+//! The [`heapsize`] example directory shows a complete working Macros 1.1
+//! implementation of a custom derive. It works on any Rust compiler \>=1.15.0.
+//! The example derives a `HeapSize` trait which computes an estimate of the
+//! amount of heap memory owned by a value.
+//!
+//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize
+//!
+//! ```rust
+//! pub trait HeapSize {
+//! /// Total number of bytes of heap memory owned by `self`.
+//! fn heap_size_of_children(&self) -> usize;
+//! }
+//! ```
+//!
+//! The custom derive allows users to write `#[derive(HeapSize)]` on data
+//! structures in their program.
+//!
+//! ```rust
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[derive(HeapSize)]
+//! # };
+//! struct Demo<'a, T: ?Sized> {
+//! a: Box<T>,
+//! b: u8,
+//! c: &'a str,
+//! d: String,
+//! }
+//! ```
+//!
+//! ## Spans and error reporting
+//!
+//! The [`heapsize2`] example directory is an extension of the `heapsize`
+//! example that demonstrates some of the hygiene and error reporting properties
+//! of Macros 2.0. This example currently requires a nightly Rust compiler
+//! \>=1.24.0-nightly but we are working to stabilize all of the APIs involved.
+//!
+//! [`heapsize2`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize2
+//!
+//! The token-based procedural macro API provides great control over where the
+//! compiler's error messages are displayed in user code. Consider the error the
+//! user sees if one of their field types does not implement `HeapSize`.
+//!
+//! ```rust
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[derive(HeapSize)]
+//! # };
+//! struct Broken {
+//! ok: String,
+//! bad: std::thread::Thread,
+//! }
+//! ```
+//!
+//! In the Macros 1.1 string-based procedural macro world, the resulting error
+//! would point unhelpfully to the invocation of the derive macro and not to the
+//! actual problematic field.
+//!
+//! ```text
+//! error[E0599]: no method named `heap_size_of_children` found for type `std::thread::Thread` in the current scope
+//! --> src/main.rs:4:10
+//! |
+//! 4 | #[derive(HeapSize)]
+//! | ^^^^^^^^
+//! ```
+//!
+//! By tracking span information all the way through the expansion of a
+//! procedural macro as shown in the `heapsize2` example, token-based macros in
+//! Syn are able to trigger errors that directly pinpoint the source of the
+//! problem.
+//!
+//! ```text
+//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied
+//! --> src/main.rs:7:5
+//! |
+//! 7 | bad: std::thread::Thread,
+//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread`
+//! ```
+//!
+//! ## Parsing a custom syntax using combinators
+//!
+//! The [`lazy-static`] example directory shows the implementation of a
+//! `functionlike!(...)` procedural macro in which the input tokens are parsed
+//! using [`nom`]-style parser combinators.
+//!
+//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static
+//! [`nom`]: https://github.com/Geal/nom
+//!
+//! The example reimplements the popular `lazy_static` crate from crates.io as a
+//! procedural macro.
+//!
+//! ```
+//! # macro_rules! lazy_static {
+//! # ($($tt:tt)*) => {}
+//! # }
+//! #
+//! lazy_static! {
+//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap();
+//! }
+//! ```
+//!
+//! The implementation shows how to trigger custom warnings and error messages
+//! on the macro input.
+//!
+//! ```text
+//! warning: come on, pick a more creative name
+//! --> src/main.rs:10:16
+//! |
+//! 10 | static ref FOO: String = "lazy_static".to_owned();
+//! | ^^^
+//! ```
+//!
+//! ## 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`] subcommand.
+//!
+//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand
+//!
+//! 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][debugging].
+//!
+//! [debugging]: 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 compile time for the most common use cases. The following features
+//! are available.
+//!
+//! - **`derive`** *(enabled by default)* — Data structures for representing the
+//! possible input to a custom derive, including structs and enums and types.
+//! - **`full`** — Data structures for representing the syntax tree of all valid
+//! Rust source code, including items and expressions.
+//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into
+//! a syntax tree node of a chosen type.
+//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree
+//! node as tokens of Rust source code.
+//! - **`visit`** — Trait for traversing a syntax tree.
+//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax
+//! tree.
+//! - **`fold`** — Trait for transforming an owned syntax tree.
+//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree
+//! types.
+//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree
+//! types.
+//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
+//! dynamic library libproc_macro from rustc toolchain.
-#[cfg(feature = "proc-macro")]
+// Syn types in rustdoc of other crates get linked to here.
+#![doc(html_root_url = "https://docs.rs/syn/0.14.9")]
+#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
+// Ignored clippy lints.
+#![cfg_attr(
+ feature = "cargo-clippy",
+ allow(
+ const_static_lifetime,
+ doc_markdown,
+ large_enum_variant,
+ match_bool,
+ redundant_closure,
+ needless_pass_by_value,
+ redundant_field_names,
+ trivially_copy_pass_by_ref
+ )
+)]
+// Ignored clippy_pedantic lints.
+#![cfg_attr(
+ feature = "cargo-clippy",
+ allow(
+ cast_possible_truncation,
+ cast_possible_wrap,
+ if_not_else,
+ indexing_slicing,
+ items_after_statements,
+ shadow_unrelated,
+ similar_names,
+ single_match_else,
+ stutter,
+ unseparated_literal_suffix,
+ use_self,
+ used_underscore_binding
+ )
+)]
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+))]
extern crate proc_macro;
+extern crate proc_macro2;
+extern crate unicode_xid;
+
+#[cfg(feature = "printing")]
+extern crate quote;
+
+#[cfg(feature = "parsing")]
+#[macro_use]
+#[doc(hidden)]
+pub mod parsers;
+
+#[macro_use]
+mod macros;
+
+#[macro_use]
+pub mod token;
+
+pub use proc_macro2::Ident;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod attr;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue, NestedMeta};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod data;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use data::{
+ Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted,
+ Visibility,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod expr;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use expr::{
+ Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprBinary, ExprBlock, ExprBox,
+ ExprBreak, ExprCall, ExprCast, ExprClosure, ExprContinue, ExprField, ExprForLoop, ExprGroup,
+ ExprIf, ExprIfLet, ExprInPlace, ExprIndex, ExprLit, ExprLoop, ExprMacro, ExprMatch,
+ ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn,
+ ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprVerbatim,
+ ExprWhile, ExprWhileLet, ExprYield, Index, Member,
+};
+
+#[cfg(feature = "full")]
+pub use expr::{
+ Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local, MethodTurbofish, Pat,
+ PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice, PatStruct, PatTuple,
+ PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod generics;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use generics::{
+ BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
+ PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound,
+ WhereClause, WherePredicate,
+};
+#[cfg(all(
+ any(feature = "full", feature = "derive"),
+ feature = "printing"
+))]
+pub use generics::{ImplGenerics, Turbofish, TypeGenerics};
+
+#[cfg(feature = "full")]
+mod item;
+#[cfg(feature = "full")]
+pub use item::{
+ ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl, ForeignItem, ForeignItemFn, ForeignItemMacro,
+ ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem, ImplItemConst,
+ ImplItemExistential, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item,
+ ItemConst, ItemEnum, ItemExistential, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl,
+ ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemType, ItemUnion,
+ ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemExistential,
+ TraitItemMacro, TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseGroup, UseName,
+ UsePath, UseRename, UseTree,
+};
+
+#[cfg(feature = "full")]
+mod file;
+#[cfg(feature = "full")]
+pub use file::File;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod lifetime;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use lifetime::Lifetime;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod lit;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use lit::{
+ FloatSuffix, IntSuffix, Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr,
+ LitVerbatim, StrStyle,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod mac;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use mac::{Macro, MacroDelimiter};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod derive;
+#[cfg(feature = "derive")]
+pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod op;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use op::{BinOp, UnOp};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod ty;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use ty::{
+ Abi, BareFnArg, BareFnArgName, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
+ TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
+ TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim,
+};
+
+#[cfg(any(feature = "full", feature = "derive"))]
+mod path;
+#[cfg(all(
+ any(feature = "full", feature = "derive"),
+ feature = "printing"
+))]
+pub use path::PathTokens;
+#[cfg(any(feature = "full", feature = "derive"))]
+pub use path::{
+ AngleBracketedGenericArguments, Binding, GenericArgument, ParenthesizedGenericArguments, Path,
+ PathArguments, PathSegment, QSelf,
+};
+
+#[cfg(feature = "parsing")]
+pub mod buffer;
+pub mod punctuated;
+#[cfg(feature = "parsing")]
+pub mod synom;
+#[cfg(any(feature = "full", feature = "derive"))]
+mod tt;
+
+// Not public API except the `parse_quote!` macro.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+pub mod parse_quote;
+
+#[cfg(all(feature = "parsing", feature = "printing"))]
+pub mod spanned;
+
+#[cfg(all(feature = "parsing", feature = "full"))]
+mod verbatim;
+
+mod gen {
+ /// Syntax tree traversal to walk a shared borrow of a syntax tree.
+ ///
+ /// Each method of the [`Visit`] trait is a hook that can be overridden to
+ /// customize the behavior when visiting the corresponding type of node. By
+ /// default, every method recursively visits the substructure of the input
+ /// by invoking the right visitor method of each of its fields.
+ ///
+ /// [`Visit`]: trait.Visit.html
+ ///
+ /// ```rust
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait Visit<'ast> {
+ /// /* ... */
+ ///
+ /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) {
+ /// for attr in &node.attrs {
+ /// self.visit_attribute(attr);
+ /// }
+ /// self.visit_expr(&*node.left);
+ /// self.visit_bin_op(&node.op);
+ /// self.visit_expr(&*node.right);
+ /// }
+ ///
+ /// /* ... */
+ /// # fn visit_attribute(&mut self, node: &'ast Attribute);
+ /// # fn visit_expr(&mut self, node: &'ast Expr);
+ /// # fn visit_bin_op(&mut self, node: &'ast BinOp);
+ /// }
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"visit"` feature.*
+ #[cfg(feature = "visit")]
+ pub mod visit;
+
+ /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in
+ /// place.
+ ///
+ /// Each method of the [`VisitMut`] trait is a hook that can be overridden
+ /// to customize the behavior when mutating the corresponding type of node.
+ /// By default, every method recursively visits the substructure of the
+ /// input by invoking the right visitor method of each of its fields.
+ ///
+ /// [`VisitMut`]: trait.VisitMut.html
+ ///
+ /// ```rust
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait VisitMut {
+ /// /* ... */
+ ///
+ /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) {
+ /// for attr in &mut node.attrs {
+ /// self.visit_attribute_mut(attr);
+ /// }
+ /// self.visit_expr_mut(&mut *node.left);
+ /// self.visit_bin_op_mut(&mut node.op);
+ /// self.visit_expr_mut(&mut *node.right);
+ /// }
+ ///
+ /// /* ... */
+ /// # fn visit_attribute_mut(&mut self, node: &mut Attribute);
+ /// # fn visit_expr_mut(&mut self, node: &mut Expr);
+ /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp);
+ /// }
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"visit-mut"`
+ /// feature.*
+ #[cfg(feature = "visit-mut")]
+ pub mod visit_mut;
+
+ /// Syntax tree traversal to transform the nodes of an owned syntax tree.
+ ///
+ /// Each method of the [`Fold`] trait is a hook that can be overridden to
+ /// customize the behavior when transforming the corresponding type of node.
+ /// By default, every method recursively visits the substructure of the
+ /// input by invoking the right visitor method of each of its fields.
+ ///
+ /// [`Fold`]: trait.Fold.html
+ ///
+ /// ```rust
+ /// # use syn::{Attribute, BinOp, Expr, ExprBinary};
+ /// #
+ /// pub trait Fold {
+ /// /* ... */
+ ///
+ /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary {
+ /// ExprBinary {
+ /// attrs: node.attrs
+ /// .into_iter()
+ /// .map(|attr| self.fold_attribute(attr))
+ /// .collect(),
+ /// left: Box::new(self.fold_expr(*node.left)),
+ /// op: self.fold_bin_op(node.op),
+ /// right: Box::new(self.fold_expr(*node.right)),
+ /// }
+ /// }
+ ///
+ /// /* ... */
+ /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute;
+ /// # fn fold_expr(&mut self, node: Expr) -> Expr;
+ /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp;
+ /// }
+ /// ```
+ ///
+ /// *This module is available if Syn is built with the `"fold"` feature.*
+ #[cfg(feature = "fold")]
+ pub mod fold;
+
+ #[cfg(any(feature = "full", feature = "derive"))]
+ #[path = "../gen_helper.rs"]
+ mod helper;
+}
+pub use gen::*;
pub mod next;
+
+////////////////////////////////////////////////////////////////////////////////
+
+#[cfg(feature = "parsing")]
+use synom::{Parser, Synom};
+
+#[cfg(feature = "parsing")]
+mod error;
+#[cfg(feature = "parsing")]
+use error::ParseError;
+
+// Not public API.
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+pub use error::parse_error;
+
+/// Parse tokens of source code into the chosen syntax tree node.
+///
+/// This is preferred over parsing a string because tokens are able to preserve
+/// information about where in the user's code they were originally written (the
+/// "span" of the token), possibly allowing the compiler to produce better error
+/// messages.
+///
+/// This function parses a `proc_macro::TokenStream` which is the type used for
+/// interop with the compiler in a procedural macro. To parse a
+/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead.
+///
+/// [`syn::parse2`]: fn.parse2.html
+///
+/// *This function is available if Syn is built with both the `"parsing"` and
+/// `"proc-macro"` features.*
+///
+/// # Examples
+///
+/// ```rust
+/// extern crate proc_macro;
+/// use proc_macro::TokenStream;
+///
+/// extern crate syn;
+///
+/// #[macro_use]
+/// extern crate quote;
+///
+/// use syn::DeriveInput;
+///
+/// # const IGNORE_TOKENS: &str = stringify! {
+/// #[proc_macro_derive(MyMacro)]
+/// # };
+/// pub fn my_macro(input: TokenStream) -> TokenStream {
+/// // Parse the tokens into a syntax tree
+/// let ast: DeriveInput = syn::parse(input).unwrap();
+///
+/// // Build the output, possibly using quasi-quotation
+/// let expanded = quote! {
+/// /* ... */
+/// };
+///
+/// // Convert into a token stream and return it
+/// expanded.into()
+/// }
+/// #
+/// # fn main() {}
+/// ```
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "parsing",
+ feature = "proc-macro"
+))]
+pub fn parse<T>(tokens: proc_macro::TokenStream) -> Result<T, ParseError>
+where
+ T: Synom,
+{
+ parse2(tokens.into())
+}
+
+/// Parse a proc-macro2 token stream into the chosen syntax tree node.
+///
+/// This function parses a `proc_macro2::TokenStream` which is commonly useful
+/// when the input comes from a node of the Syn syntax tree, for example the tts
+/// of a [`Macro`] node. When in a procedural macro parsing the
+/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`]
+/// instead.
+///
+/// [`Macro`]: struct.Macro.html
+/// [`syn::parse`]: fn.parse.html
+///
+/// *This function is available if Syn is built with the `"parsing"` feature.*
+#[cfg(feature = "parsing")]
+pub fn parse2<T>(tokens: proc_macro2::TokenStream) -> Result<T, ParseError>
+where
+ T: Synom,
+{
+ let parser = T::parse;
+ parser.parse2(tokens).map_err(|err| match T::description() {
+ Some(s) => ParseError::new(format!("failed to parse {}: {}", s, err)),
+ None => err,
+ })
+}
+
+/// Parse a string of Rust code into the chosen syntax tree node.
+///
+/// *This function is available if Syn is built with the `"parsing"` feature.*
+///
+/// # Hygiene
+///
+/// Every span in the resulting syntax tree will be set to resolve at the macro
+/// call site.
+///
+/// # Examples
+///
+/// ```rust
+/// extern crate syn;
+/// #
+/// #
+/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
+///
+/// use syn::Expr;
+///
+/// fn run() -> Result<()> {
+/// let code = "assert_eq!(u8::max_value(), 255)";
+/// let expr = syn::parse_str::<Expr>(code)?;
+/// println!("{:#?}", expr);
+/// Ok(())
+/// }
+/// #
+/// # fn main() { run().unwrap() }
+/// ```
+#[cfg(feature = "parsing")]
+pub fn parse_str<T: Synom>(s: &str) -> Result<T, ParseError> {
+ match s.parse() {
+ Ok(tts) => parse2(tts),
+ Err(_) => Err(ParseError::new("error while lexing input string")),
+ }
+}
+
+// FIXME the name parse_file makes it sound like you might pass in a path to a
+// file, rather than the content.
+/// Parse the content of a file of Rust code.
+///
+/// This is different from `syn::parse_str::<File>(content)` in two ways:
+///
+/// - It discards a leading byte order mark `\u{FEFF}` if the file has one.
+/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`.
+///
+/// If present, either of these would be an error using `from_str`.
+///
+/// *This function is available if Syn is built with the `"parsing"` and `"full"` features.*
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// extern crate syn;
+/// #
+/// #
+/// # type Result<T> = std::result::Result<T, Box<std::error::Error>>;
+///
+/// use std::fs::File;
+/// use std::io::Read;
+///
+/// fn run() -> Result<()> {
+/// let mut file = File::open("path/to/code.rs")?;
+/// let mut content = String::new();
+/// file.read_to_string(&mut content)?;
+///
+/// let ast = syn::parse_file(&content)?;
+/// if let Some(shebang) = ast.shebang {
+/// println!("{}", shebang);
+/// }
+/// println!("{} items", ast.items.len());
+///
+/// Ok(())
+/// }
+/// #
+/// # fn main() { run().unwrap() }
+/// ```
+#[cfg(all(feature = "parsing", feature = "full"))]
+pub fn parse_file(mut content: &str) -> Result<File, ParseError> {
+ // Strip the BOM if it is present
+ const BOM: &'static str = "\u{feff}";
+ if content.starts_with(BOM) {
+ content = &content[BOM.len()..];
+ }
+
+ let mut shebang = None;
+ if content.starts_with("#!") && !content.starts_with("#![") {
+ if let Some(idx) = content.find('\n') {
+ shebang = Some(content[..idx].to_string());
+ content = &content[idx..];
+ } else {
+ shebang = Some(content.to_string());
+ content = "";
+ }
+ }
+
+ let mut file: File = parse_str(content)?;
+ file.shebang = shebang;
+ Ok(file)
+}
+
+#[cfg(all(
+ any(feature = "full", feature = "derive"),
+ feature = "printing"
+))]
+struct TokensOrDefault<'a, T: 'a>(&'a Option<T>);
+
+#[cfg(all(
+ any(feature = "full", feature = "derive"),
+ feature = "printing"
+))]
+impl<'a, T> quote::ToTokens for TokensOrDefault<'a, T>
+where
+ T: quote::ToTokens + Default,
+{
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+ match *self.0 {
+ Some(ref t) => t.to_tokens(tokens),
+ None => T::default().to_tokens(tokens),
+ }
+ }
+}
diff --git a/src/lifetime.rs b/src/lifetime.rs
new file mode 100644
index 0000000..5ca876f
--- /dev/null
+++ b/src/lifetime.rs
@@ -0,0 +1,150 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp::Ordering;
+use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
+
+use proc_macro2::{Ident, Span};
+use unicode_xid::UnicodeXID;
+
+use token::Apostrophe;
+
+/// A Rust lifetime: `'a`.
+///
+/// Lifetime names must conform to the following rules:
+///
+/// - Must start with an apostrophe.
+/// - Must not consist of just an apostrophe: `'`.
+/// - Character after the apostrophe must be `_` or a Unicode code point with
+/// the XID_Start property.
+/// - All following characters must be Unicode code points with the XID_Continue
+/// property.
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature.*
+#[cfg_attr(feature = "extra-traits", derive(Debug))]
+#[derive(Clone)]
+pub struct Lifetime {
+ pub apostrophe: Apostrophe,
+ pub ident: Ident,
+}
+
+impl Lifetime {
+ pub fn new(s: &str, span: Span) -> Self {
+ if !s.starts_with('\'') {
+ panic!(
+ "lifetime name must start with apostrophe as in \"'a\", got {:?}",
+ s
+ );
+ }
+
+ if s == "'" {
+ panic!("lifetime name must not be empty");
+ }
+
+ fn xid_ok(s: &str) -> bool {
+ let mut chars = s.chars();
+ let first = chars.next().unwrap();
+ if !(UnicodeXID::is_xid_start(first) || first == '_') {
+ return false;
+ }
+ for ch in chars {
+ if !UnicodeXID::is_xid_continue(ch) {
+ return false;
+ }
+ }
+ true
+ }
+
+ if !xid_ok(&s[1..]) {
+ panic!("{:?} is not a valid lifetime name", s);
+ }
+
+ Lifetime {
+ apostrophe: Apostrophe::default(),
+ ident: Ident::new(&s[1..], span),
+ }
+ }
+}
+
+impl Display for Lifetime {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ "'".fmt(formatter)?;
+ self.ident.fmt(formatter)
+ }
+}
+
+impl PartialEq for Lifetime {
+ fn eq(&self, other: &Lifetime) -> bool {
+ self.ident.eq(&other.ident)
+ }
+}
+
+impl Eq for Lifetime {}
+
+impl PartialOrd for Lifetime {
+ fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Lifetime {
+ fn cmp(&self, other: &Lifetime) -> Ordering {
+ self.ident.cmp(&other.ident)
+ }
+}
+
+impl Hash for Lifetime {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ self.ident.hash(h)
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use buffer::Cursor;
+ use parse_error;
+ use synom::PResult;
+ use synom::Synom;
+
+ impl Synom for Lifetime {
+ fn parse(input: Cursor) -> PResult<Self> {
+ let (apostrophe, rest) = Apostrophe::parse(input)?;
+ let (ident, rest) = match rest.ident() {
+ Some(pair) => pair,
+ None => return parse_error(),
+ };
+
+ let ret = Lifetime {
+ ident: ident,
+ apostrophe: apostrophe,
+ };
+ Ok((ret, rest))
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("lifetime")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Lifetime {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.apostrophe.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/lit.rs b/src/lit.rs
new file mode 100644
index 0000000..47555d4
--- /dev/null
+++ b/src/lit.rs
@@ -0,0 +1,1026 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use proc_macro2::{Literal, Span};
+use std::str;
+
+#[cfg(feature = "printing")]
+use proc_macro2::Ident;
+
+#[cfg(feature = "parsing")]
+use proc_macro2::TokenStream;
+#[cfg(feature = "parsing")]
+use {ParseError, Synom};
+
+use proc_macro2::TokenTree;
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+ast_enum_of_structs! {
+ /// A Rust literal such as a string or integer or boolean.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Lit {
+ /// A UTF-8 string literal: `"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Str(LitStr #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// A byte string literal: `b"foo"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub ByteStr(LitByteStr #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// A byte literal: `b'f'`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Byte(LitByte #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// A character literal: `'a'`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Char(LitChar #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// An integer literal: `1` or `1u16`.
+ ///
+ /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger
+ /// integer literal.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Int(LitInt #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// A floating point literal: `1f64` or `1.0e10f64`.
+ ///
+ /// Must be finite. May not be infinte or NaN.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Float(LitFloat #manual_extra_traits {
+ token: Literal,
+ }),
+
+ /// A boolean literal: `true` or `false`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Bool(LitBool #manual_extra_traits {
+ pub value: bool,
+ pub span: Span,
+ }),
+
+ /// A raw token literal not interpreted by Syn, possibly because it
+ /// represents an integer larger than 64 bits.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Verbatim(LitVerbatim #manual_extra_traits {
+ pub token: Literal,
+ }),
+ }
+}
+
+impl LitStr {
+ pub fn new(value: &str, span: Span) -> Self {
+ let mut lit = Literal::string(value);
+ lit.set_span(span);
+ LitStr { token: lit }
+ }
+
+ pub fn value(&self) -> String {
+ value::parse_lit_str(&self.token.to_string())
+ }
+
+ /// Parse a syntax tree node from the content of this string literal.
+ ///
+ /// All spans in the syntax tree will point to the span of this `LitStr`.
+ #[cfg(feature = "parsing")]
+ pub fn parse<T: Synom>(&self) -> Result<T, ParseError> {
+ use proc_macro2::Group;
+
+ // Parse string literal into a token stream with every span equal to the
+ // original literal's span.
+ fn spanned_tokens(s: &LitStr) -> Result<TokenStream, ParseError> {
+ let stream = ::parse_str(&s.value())?;
+ Ok(respan_token_stream(stream, s.span()))
+ }
+
+ // Token stream with every span replaced by the given one.
+ fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
+ stream
+ .into_iter()
+ .map(|token| respan_token_tree(token, span))
+ .collect()
+ }
+
+ // Token tree with every span replaced by the given one.
+ fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
+ match token {
+ TokenTree::Group(ref mut g) => {
+ let stream = respan_token_stream(g.stream().clone(), span);
+ *g = Group::new(g.delimiter(), stream);
+ g.set_span(span);
+ }
+ ref mut other => other.set_span(span),
+ }
+ token
+ }
+
+ spanned_tokens(self).and_then(::parse2)
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitByteStr {
+ pub fn new(value: &[u8], span: Span) -> Self {
+ let mut token = Literal::byte_string(value);
+ token.set_span(span);
+ LitByteStr { token: token }
+ }
+
+ pub fn value(&self) -> Vec<u8> {
+ value::parse_lit_byte_str(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitByte {
+ pub fn new(value: u8, span: Span) -> Self {
+ let mut token = Literal::u8_suffixed(value);
+ token.set_span(span);
+ LitByte { token: token }
+ }
+
+ pub fn value(&self) -> u8 {
+ value::parse_lit_byte(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitChar {
+ pub fn new(value: char, span: Span) -> Self {
+ let mut token = Literal::character(value);
+ token.set_span(span);
+ LitChar { token: token }
+ }
+
+ pub fn value(&self) -> char {
+ value::parse_lit_char(&self.token.to_string())
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitInt {
+ pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self {
+ let mut token = match suffix {
+ IntSuffix::Isize => Literal::isize_suffixed(value as isize),
+ IntSuffix::I8 => Literal::i8_suffixed(value as i8),
+ IntSuffix::I16 => Literal::i16_suffixed(value as i16),
+ IntSuffix::I32 => Literal::i32_suffixed(value as i32),
+ IntSuffix::I64 => Literal::i64_suffixed(value as i64),
+ IntSuffix::I128 => value::to_literal(&format!("{}i128", value)),
+ IntSuffix::Usize => Literal::usize_suffixed(value as usize),
+ IntSuffix::U8 => Literal::u8_suffixed(value as u8),
+ IntSuffix::U16 => Literal::u16_suffixed(value as u16),
+ IntSuffix::U32 => Literal::u32_suffixed(value as u32),
+ IntSuffix::U64 => Literal::u64_suffixed(value),
+ IntSuffix::U128 => value::to_literal(&format!("{}u128", value)),
+ IntSuffix::None => Literal::u64_unsuffixed(value),
+ };
+ token.set_span(span);
+ LitInt { token: token }
+ }
+
+ pub fn value(&self) -> u64 {
+ value::parse_lit_int(&self.token.to_string()).unwrap()
+ }
+
+ pub fn suffix(&self) -> IntSuffix {
+ let value = self.token.to_string();
+ for (s, suffix) in vec![
+ ("i8", IntSuffix::I8),
+ ("i16", IntSuffix::I16),
+ ("i32", IntSuffix::I32),
+ ("i64", IntSuffix::I64),
+ ("i128", IntSuffix::I128),
+ ("isize", IntSuffix::Isize),
+ ("u8", IntSuffix::U8),
+ ("u16", IntSuffix::U16),
+ ("u32", IntSuffix::U32),
+ ("u64", IntSuffix::U64),
+ ("u128", IntSuffix::U128),
+ ("usize", IntSuffix::Usize),
+ ] {
+ if value.ends_with(s) {
+ return suffix;
+ }
+ }
+ IntSuffix::None
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+impl LitFloat {
+ pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self {
+ let mut token = match suffix {
+ FloatSuffix::F32 => Literal::f32_suffixed(value as f32),
+ FloatSuffix::F64 => Literal::f64_suffixed(value),
+ FloatSuffix::None => Literal::f64_unsuffixed(value),
+ };
+ token.set_span(span);
+ LitFloat { token: token }
+ }
+
+ pub fn value(&self) -> f64 {
+ value::parse_lit_float(&self.token.to_string())
+ }
+
+ pub fn suffix(&self) -> FloatSuffix {
+ let value = self.token.to_string();
+ for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] {
+ if value.ends_with(s) {
+ return suffix;
+ }
+ }
+ FloatSuffix::None
+ }
+
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+macro_rules! lit_extra_traits {
+ ($ty:ident, $field:ident) => {
+ #[cfg(feature = "extra-traits")]
+ impl Eq for $ty {}
+
+ #[cfg(feature = "extra-traits")]
+ impl PartialEq for $ty {
+ fn eq(&self, other: &Self) -> bool {
+ self.$field.to_string() == other.$field.to_string()
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl Hash for $ty {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.$field.to_string().hash(state);
+ }
+ }
+ };
+}
+
+impl LitVerbatim {
+ pub fn span(&self) -> Span {
+ self.token.span()
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.token.set_span(span)
+ }
+}
+
+lit_extra_traits!(LitStr, token);
+lit_extra_traits!(LitByteStr, token);
+lit_extra_traits!(LitByte, token);
+lit_extra_traits!(LitChar, token);
+lit_extra_traits!(LitInt, token);
+lit_extra_traits!(LitFloat, token);
+lit_extra_traits!(LitBool, value);
+lit_extra_traits!(LitVerbatim, token);
+
+ast_enum! {
+ /// The style of a string literal, either plain quoted or a raw string like
+ /// `r##"data"##`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum StrStyle #no_visit {
+ /// An ordinary string like `"data"`.
+ Cooked,
+ /// A raw string like `r##"data"##`.
+ ///
+ /// The unsigned integer is the number of `#` symbols used.
+ Raw(usize),
+ }
+}
+
+ast_enum! {
+ /// The suffix on an integer literal if any, like the `u8` in `127u8`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum IntSuffix #no_visit {
+ I8,
+ I16,
+ I32,
+ I64,
+ I128,
+ Isize,
+ U8,
+ U16,
+ U32,
+ U64,
+ U128,
+ Usize,
+ None,
+ }
+}
+
+ast_enum! {
+ /// The suffix on a floating point literal if any, like the `f32` in
+ /// `1.0f32`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum FloatSuffix #no_visit {
+ F32,
+ F64,
+ None,
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use buffer::Cursor;
+ use parse_error;
+ use synom::PResult;
+ use synom::Synom;
+
+ impl Synom for Lit {
+ fn parse(input: Cursor) -> PResult<Self> {
+ match input.literal() {
+ Some((lit, rest)) => {
+ if lit.to_string().starts_with('/') {
+ // Doc comment literal which is not a Syn literal
+ parse_error()
+ } else {
+ Ok((Lit::new(lit), rest))
+ }
+ }
+ _ => match input.ident() {
+ Some((ident, rest)) => Ok((
+ Lit::Bool(LitBool {
+ value: if ident == "true" {
+ true
+ } else if ident == "false" {
+ false
+ } else {
+ return parse_error();
+ },
+ span: ident.span(),
+ }),
+ rest,
+ )),
+ _ => parse_error(),
+ },
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("literal")
+ }
+ }
+
+ impl_synom!(LitStr "string literal" switch!(
+ syn!(Lit),
+ Lit::Str(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitByteStr "byte string literal" switch!(
+ syn!(Lit),
+ Lit::ByteStr(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitByte "byte literal" switch!(
+ syn!(Lit),
+ Lit::Byte(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitChar "character literal" switch!(
+ syn!(Lit),
+ Lit::Char(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitInt "integer literal" switch!(
+ syn!(Lit),
+ Lit::Int(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitFloat "floating point literal" switch!(
+ syn!(Lit),
+ Lit::Float(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+
+ impl_synom!(LitBool "boolean literal" switch!(
+ syn!(Lit),
+ Lit::Bool(lit) => value!(lit)
+ |
+ _ => reject!()
+ ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl ToTokens for LitStr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitByteStr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitByte {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitChar {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitInt {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitFloat {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for LitBool {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let s = if self.value { "true" } else { "false" };
+ tokens.append(Ident::new(s, self.span));
+ }
+ }
+
+ impl ToTokens for LitVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.token.to_tokens(tokens);
+ }
+ }
+}
+
+mod value {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use std::char;
+ use std::ops::{Index, RangeFrom};
+
+ impl Lit {
+ /// Interpret a Syn literal from a proc-macro2 literal.
+ ///
+ /// Not all proc-macro2 literals are valid Syn literals. In particular,
+ /// doc comments are considered by proc-macro2 to be literals but in Syn
+ /// they are [`Attribute`].
+ ///
+ /// [`Attribute`]: struct.Attribute.html
+ ///
+ /// # Panics
+ ///
+ /// Panics if the input is a doc comment literal.
+ pub fn new(token: Literal) -> Self {
+ let value = token.to_string();
+
+ match value::byte(&value, 0) {
+ b'"' | b'r' => return Lit::Str(LitStr { token: token }),
+ b'b' => match value::byte(&value, 1) {
+ b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }),
+ b'\'' => return Lit::Byte(LitByte { token: token }),
+ _ => {}
+ },
+ b'\'' => return Lit::Char(LitChar { token: token }),
+ b'0'...b'9' => if number_is_int(&value) {
+ return Lit::Int(LitInt { token: token });
+ } else if number_is_float(&value) {
+ return Lit::Float(LitFloat { token: token });
+ } else {
+ // number overflow
+ return Lit::Verbatim(LitVerbatim { token: token });
+ },
+ _ => if value == "true" || value == "false" {
+ return Lit::Bool(LitBool {
+ value: value == "true",
+ span: token.span(),
+ });
+ },
+ }
+
+ panic!("Unrecognized literal: {}", value);
+ }
+ }
+
+ fn number_is_int(value: &str) -> bool {
+ if number_is_float(value) {
+ false
+ } else {
+ value::parse_lit_int(value).is_some()
+ }
+ }
+
+ fn number_is_float(value: &str) -> bool {
+ if value.contains('.') {
+ true
+ } else if value.starts_with("0x") || value.ends_with("size") {
+ false
+ } else {
+ value.contains('e') || value.contains('E')
+ }
+ }
+
+ /// Get the byte at offset idx, or a default of `b'\0'` if we're looking
+ /// past the end of the input buffer.
+ pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
+ let s = s.as_ref();
+ if idx < s.len() {
+ s[idx]
+ } else {
+ 0
+ }
+ }
+
+ fn next_chr(s: &str) -> char {
+ s.chars().next().unwrap_or('\0')
+ }
+
+ pub fn parse_lit_str(s: &str) -> String {
+ match byte(s, 0) {
+ b'"' => parse_lit_str_cooked(s),
+ b'r' => parse_lit_str_raw(s),
+ _ => unreachable!(),
+ }
+ }
+
+ // Clippy false positive
+ // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
+ #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
+ fn parse_lit_str_cooked(mut s: &str) -> String {
+ assert_eq!(byte(s, 0), b'"');
+ s = &s[1..];
+
+ let mut out = String::new();
+ 'outer: loop {
+ let ch = match byte(s, 0) {
+ b'"' => break,
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (byte, rest) = backslash_x(s);
+ s = rest;
+ assert!(byte <= 0x80, "Invalid \\x byte in string literal");
+ char::from_u32(u32::from(byte)).unwrap()
+ }
+ b'u' => {
+ let (chr, rest) = backslash_u(s);
+ s = rest;
+ chr
+ }
+ b'n' => '\n',
+ b'r' => '\r',
+ b't' => '\t',
+ b'\\' => '\\',
+ b'0' => '\0',
+ b'\'' => '\'',
+ b'"' => '"',
+ b'\r' | b'\n' => loop {
+ let ch = next_chr(s);
+ if ch.is_whitespace() {
+ s = &s[ch.len_utf8()..];
+ } else {
+ continue 'outer;
+ }
+ },
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b'\r' => {
+ assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
+ s = &s[2..];
+ '\n'
+ }
+ _ => {
+ let ch = next_chr(s);
+ s = &s[ch.len_utf8()..];
+ ch
+ }
+ };
+ out.push(ch);
+ }
+
+ assert_eq!(s, "\"");
+ out
+ }
+
+ fn parse_lit_str_raw(mut s: &str) -> String {
+ assert_eq!(byte(s, 0), b'r');
+ s = &s[1..];
+
+ let mut pounds = 0;
+ while byte(s, pounds) == b'#' {
+ pounds += 1;
+ }
+ assert_eq!(byte(s, pounds), b'"');
+ assert_eq!(byte(s, s.len() - pounds - 1), b'"');
+ for end in s[s.len() - pounds..].bytes() {
+ assert_eq!(end, b'#');
+ }
+
+ s[pounds + 1..s.len() - pounds - 1].to_owned()
+ }
+
+ pub fn parse_lit_byte_str(s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ match byte(s, 1) {
+ b'"' => parse_lit_byte_str_cooked(s),
+ b'r' => parse_lit_byte_str_raw(s),
+ _ => unreachable!(),
+ }
+ }
+
+ // Clippy false positive
+ // https://github.com/rust-lang-nursery/rust-clippy/issues/2329
+ #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))]
+ fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ assert_eq!(byte(s, 1), b'"');
+ s = &s[2..];
+
+ // We're going to want to have slices which don't respect codepoint boundaries.
+ let mut s = s.as_bytes();
+
+ let mut out = Vec::new();
+ 'outer: loop {
+ let byte = match byte(s, 0) {
+ b'"' => break,
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (b, rest) = backslash_x(s);
+ s = rest;
+ b
+ }
+ b'n' => b'\n',
+ b'r' => b'\r',
+ b't' => b'\t',
+ b'\\' => b'\\',
+ b'0' => b'\0',
+ b'\'' => b'\'',
+ b'"' => b'"',
+ b'\r' | b'\n' => loop {
+ let byte = byte(s, 0);
+ let ch = char::from_u32(u32::from(byte)).unwrap();
+ if ch.is_whitespace() {
+ s = &s[1..];
+ } else {
+ continue 'outer;
+ }
+ },
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b'\r' => {
+ assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string");
+ s = &s[2..];
+ b'\n'
+ }
+ b => {
+ s = &s[1..];
+ b
+ }
+ };
+ out.push(byte);
+ }
+
+ assert_eq!(s, b"\"");
+ out
+ }
+
+ fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> {
+ assert_eq!(byte(s, 0), b'b');
+ parse_lit_str_raw(&s[1..]).into_bytes()
+ }
+
+ pub fn parse_lit_byte(s: &str) -> u8 {
+ assert_eq!(byte(s, 0), b'b');
+ assert_eq!(byte(s, 1), b'\'');
+
+ // We're going to want to have slices which don't respect codepoint boundaries.
+ let mut s = s[2..].as_bytes();
+
+ let b = match byte(s, 0) {
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (b, rest) = backslash_x(s);
+ s = rest;
+ b
+ }
+ b'n' => b'\n',
+ b'r' => b'\r',
+ b't' => b'\t',
+ b'\\' => b'\\',
+ b'0' => b'\0',
+ b'\'' => b'\'',
+ b'"' => b'"',
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ b => {
+ s = &s[1..];
+ b
+ }
+ };
+
+ assert_eq!(byte(s, 0), b'\'');
+ b
+ }
+
+ pub fn parse_lit_char(mut s: &str) -> char {
+ assert_eq!(byte(s, 0), b'\'');
+ s = &s[1..];
+
+ let ch = match byte(s, 0) {
+ b'\\' => {
+ let b = byte(s, 1);
+ s = &s[2..];
+ match b {
+ b'x' => {
+ let (byte, rest) = backslash_x(s);
+ s = rest;
+ assert!(byte <= 0x80, "Invalid \\x byte in string literal");
+ char::from_u32(u32::from(byte)).unwrap()
+ }
+ b'u' => {
+ let (chr, rest) = backslash_u(s);
+ s = rest;
+ chr
+ }
+ b'n' => '\n',
+ b'r' => '\r',
+ b't' => '\t',
+ b'\\' => '\\',
+ b'0' => '\0',
+ b'\'' => '\'',
+ b'"' => '"',
+ b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
+ }
+ }
+ _ => {
+ let ch = next_chr(s);
+ s = &s[ch.len_utf8()..];
+ ch
+ }
+ };
+ assert_eq!(s, "\'", "Expected end of char literal");
+ ch
+ }
+
+ fn backslash_x<S>(s: &S) -> (u8, &S)
+ where
+ S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized,
+ {
+ let mut ch = 0;
+ let b0 = byte(s, 0);
+ let b1 = byte(s, 1);
+ ch += 0x10 * match b0 {
+ b'0'...b'9' => b0 - b'0',
+ b'a'...b'f' => 10 + (b0 - b'a'),
+ b'A'...b'F' => 10 + (b0 - b'A'),
+ _ => panic!("unexpected non-hex character after \\x"),
+ };
+ ch += match b1 {
+ b'0'...b'9' => b1 - b'0',
+ b'a'...b'f' => 10 + (b1 - b'a'),
+ b'A'...b'F' => 10 + (b1 - b'A'),
+ _ => panic!("unexpected non-hex character after \\x"),
+ };
+ (ch, &s[2..])
+ }
+
+ fn backslash_u(mut s: &str) -> (char, &str) {
+ if byte(s, 0) != b'{' {
+ panic!("expected {{ after \\u");
+ }
+ s = &s[1..];
+
+ let mut ch = 0;
+ for _ in 0..6 {
+ let b = byte(s, 0);
+ match b {
+ b'0'...b'9' => {
+ ch *= 0x10;
+ ch += u32::from(b - b'0');
+ s = &s[1..];
+ }
+ b'a'...b'f' => {
+ ch *= 0x10;
+ ch += u32::from(10 + b - b'a');
+ s = &s[1..];
+ }
+ b'A'...b'F' => {
+ ch *= 0x10;
+ ch += u32::from(10 + b - b'A');
+ s = &s[1..];
+ }
+ b'}' => break,
+ _ => panic!("unexpected non-hex character after \\u"),
+ }
+ }
+ assert!(byte(s, 0) == b'}');
+ s = &s[1..];
+
+ if let Some(ch) = char::from_u32(ch) {
+ (ch, s)
+ } else {
+ panic!("character code {:x} is not a valid unicode character", ch);
+ }
+ }
+
+ pub fn parse_lit_int(mut s: &str) -> Option<u64> {
+ let base = match (byte(s, 0), byte(s, 1)) {
+ (b'0', b'x') => {
+ s = &s[2..];
+ 16
+ }
+ (b'0', b'o') => {
+ s = &s[2..];
+ 8
+ }
+ (b'0', b'b') => {
+ s = &s[2..];
+ 2
+ }
+ (b'0'...b'9', _) => 10,
+ _ => unreachable!(),
+ };
+
+ let mut value = 0u64;
+ loop {
+ let b = byte(s, 0);
+ let digit = match b {
+ b'0'...b'9' => u64::from(b - b'0'),
+ b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'),
+ b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'),
+ b'_' => {
+ s = &s[1..];
+ continue;
+ }
+ // NOTE: Looking at a floating point literal, we don't want to
+ // consider these integers.
+ b'.' if base == 10 => return None,
+ b'e' | b'E' if base == 10 => return None,
+ _ => break,
+ };
+
+ if digit >= base {
+ panic!("Unexpected digit {:x} out of base range", digit);
+ }
+
+ value = match value.checked_mul(base) {
+ Some(value) => value,
+ None => return None,
+ };
+ value = match value.checked_add(digit) {
+ Some(value) => value,
+ None => return None,
+ };
+ s = &s[1..];
+ }
+
+ Some(value)
+ }
+
+ pub fn parse_lit_float(input: &str) -> f64 {
+ // Rust's floating point literals are very similar to the ones parsed by
+ // the standard library, except that rust's literals can contain
+ // ignorable underscores. Let's remove those underscores.
+ let mut bytes = input.to_owned().into_bytes();
+ let mut write = 0;
+ for read in 0..bytes.len() {
+ if bytes[read] == b'_' {
+ continue; // Don't increase write
+ }
+ if write != read {
+ let x = bytes[read];
+ bytes[write] = x;
+ }
+ write += 1;
+ }
+ bytes.truncate(write);
+ let input = String::from_utf8(bytes).unwrap();
+ let end = input.find('f').unwrap_or_else(|| input.len());
+ input[..end].parse().unwrap()
+ }
+
+ pub fn to_literal(s: &str) -> Literal {
+ let stream = s.parse::<TokenStream>().unwrap();
+ match stream.into_iter().next().unwrap() {
+ TokenTree::Literal(l) => l,
+ _ => unreachable!(),
+ }
+ }
+}
diff --git a/src/mac.rs b/src/mac.rs
new file mode 100644
index 0000000..a9219fe
--- /dev/null
+++ b/src/mac.rs
@@ -0,0 +1,117 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use proc_macro2::TokenStream;
+use token::{Brace, Bracket, Paren};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "extra-traits")]
+use tt::TokenStreamHelper;
+
+ast_struct! {
+ /// A macro invocation: `println!("{}", mac)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Macro #manual_extra_traits {
+ pub path: Path,
+ pub bang_token: Token![!],
+ pub delimiter: MacroDelimiter,
+ pub tts: TokenStream,
+ }
+}
+
+ast_enum! {
+ /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum MacroDelimiter {
+ Paren(Paren),
+ Brace(Brace),
+ Bracket(Bracket),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for Macro {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for Macro {
+ fn eq(&self, other: &Self) -> bool {
+ self.path == other.path
+ && self.bang_token == other.bang_token
+ && self.delimiter == other.delimiter
+ && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for Macro {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.path.hash(state);
+ self.bang_token.hash(state);
+ self.delimiter.hash(state);
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+
+ use synom::Synom;
+
+ impl Synom for Macro {
+ named!(parse -> Self, do_parse!(
+ what: call!(Path::parse_mod_style) >>
+ bang: punct!(!) >>
+ body: call!(tt::delimited) >>
+ (Macro {
+ path: what,
+ bang_token: bang,
+ delimiter: body.0,
+ tts: body.1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("macro invocation")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Macro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.path.to_tokens(tokens);
+ self.bang_token.to_tokens(tokens);
+ match self.delimiter {
+ MacroDelimiter::Paren(ref paren) => {
+ paren.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+ }
+ MacroDelimiter::Brace(ref brace) => {
+ brace.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+ }
+ MacroDelimiter::Bracket(ref bracket) => {
+ bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+ }
+ }
+ }
+ }
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..f4e7d0a
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,196 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! ast_struct {
+ (
+ $(#[$attr:meta])*
+ pub struct $name:ident #full $($rest:tt)*
+ ) => {
+ #[cfg(feature = "full")]
+ $(#[$attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub struct $name $($rest)*
+
+ #[cfg(not(feature = "full"))]
+ $(#[$attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub struct $name {
+ _noconstruct: (),
+ }
+ };
+
+ (
+ $(#[$attr:meta])*
+ pub struct $name:ident #manual_extra_traits $($rest:tt)*
+ ) => {
+ $(#[$attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub struct $name $($rest)*
+ };
+
+ (
+ $(#[$attr:meta])*
+ pub struct $name:ident $($rest:tt)*
+ ) => {
+ $(#[$attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub struct $name $($rest)*
+ };
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! ast_enum {
+ (
+ $(#[$enum_attr:meta])*
+ pub enum $name:ident $(# $tags:ident)* { $($variants:tt)* }
+ ) => (
+ $(#[$enum_attr])*
+ #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+ #[cfg_attr(feature = "clone-impls", derive(Clone))]
+ pub enum $name {
+ $($variants)*
+ }
+ )
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! ast_enum_of_structs {
+ (
+ $(#[$enum_attr:meta])*
+ pub enum $name:ident {
+ $(
+ $(#[$variant_attr:meta])*
+ pub $variant:ident $( ($member:ident $($rest:tt)*) )*,
+ )*
+ }
+
+ $($remaining:tt)*
+ ) => (
+ ast_enum! {
+ $(#[$enum_attr])*
+ pub enum $name {
+ $(
+ $(#[$variant_attr])*
+ $variant $( ($member) )*,
+ )*
+ }
+ }
+
+ $(
+ maybe_ast_struct! {
+ $(#[$variant_attr])*
+ $(
+ pub struct $member $($rest)*
+ )*
+ }
+
+ $(
+ impl From<$member> for $name {
+ fn from(e: $member) -> $name {
+ $name::$variant(e)
+ }
+ }
+ )*
+ )*
+
+ #[cfg(feature = "printing")]
+ generate_to_tokens! {
+ $($remaining)*
+ ()
+ tokens
+ $name { $($variant $( [$($rest)*] )*,)* }
+ }
+ )
+}
+
+#[cfg(all(
+ feature = "printing",
+ any(feature = "full", feature = "derive")
+))]
+macro_rules! generate_to_tokens {
+ (do_not_generate_to_tokens $($foo:tt)*) => ();
+
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant => {})
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident [$($rest:tt)*], $($next:tt)*}) => {
+ generate_to_tokens!(
+ ($($arms)* $name::$variant(ref _e) => to_tokens_call!(_e, $tokens, $($rest)*),)
+ $tokens $name { $($next)* }
+ );
+ };
+
+ (($($arms:tt)*) $tokens:ident $name:ident {}) => {
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
+ match *self {
+ $($arms)*
+ }
+ }
+ }
+ };
+}
+
+#[cfg(all(feature = "printing", feature = "full"))]
+macro_rules! to_tokens_call {
+ ($e:ident, $tokens:ident, $($rest:tt)*) => {
+ $e.to_tokens($tokens)
+ };
+}
+
+#[cfg(all(
+ feature = "printing",
+ feature = "derive",
+ not(feature = "full")
+))]
+macro_rules! to_tokens_call {
+ // If the variant is marked as #full, don't auto-generate to-tokens for it.
+ ($e:ident, $tokens:ident, #full $($rest:tt)*) => {
+ unreachable!()
+ };
+ ($e:ident, $tokens:ident, $($rest:tt)*) => {
+ $e.to_tokens($tokens)
+ };
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+macro_rules! maybe_ast_struct {
+ (
+ $(#[$attr:meta])*
+ $(
+ pub struct $name:ident
+ )*
+ ) => ();
+
+ ($($rest:tt)*) => (ast_struct! { $($rest)* });
+}
+
+#[cfg(all(
+ feature = "parsing",
+ any(feature = "full", feature = "derive")
+))]
+macro_rules! impl_synom {
+ ($t:ident $description:tt $($parser:tt)+) => {
+ impl Synom for $t {
+ named!(parse -> Self, $($parser)+);
+
+ fn description() -> Option<&'static str> {
+ Some($description)
+ }
+ }
+ }
+}
diff --git a/src/next/error.rs b/src/next/error.rs
index 92ac21c..05473f3 100644
--- a/src/next/error.rs
+++ b/src/next/error.rs
@@ -6,7 +6,7 @@
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
};
-use syn::buffer::Cursor;
+use buffer::Cursor;
/// The result of a Syn parser.
pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/next/group.rs b/src/next/group.rs
index dca4d1c..40317bf 100644
--- a/src/next/group.rs
+++ b/src/next/group.rs
@@ -29,11 +29,22 @@
/// Parse a set of curly braces and expose their content to subsequent parsers.
///
/// ```rust
-/// # extern crate syn_error_experiment;
+/// # extern crate syn;
/// #
-/// use syn_error_experiment::{braced, token, Ident, Token};
-/// use syn_error_experiment::parse::{Parse, ParseStream, Result};
-/// # use syn_error_experiment::Field;
+/// use syn::{braced, Token};
+/// use syn::next::{token, Ident};
+/// use syn::next::parse::{Parse, ParseStream, Result};
+/// #
+/// # mod example {
+/// # use super::{syn, braced, token, Ident, Parse, ParseStream, Result};
+/// #
+/// # macro_rules! Token {
+/// # (struct) => {
+/// # syn::next::token::Struct
+/// # };
+/// # }
+/// #
+/// # type Field = Ident;
///
/// // Parse a simplified struct syntax like:
/// //
@@ -59,6 +70,9 @@
/// })
/// }
/// }
+/// # }
+/// #
+/// # fn main() {}
/// ```
#[macro_export]
macro_rules! braced {
diff --git a/src/next/lookahead.rs b/src/next/lookahead.rs
index db0fa63..256ac05 100644
--- a/src/next/lookahead.rs
+++ b/src/next/lookahead.rs
@@ -1,7 +1,7 @@
use std::cell::RefCell;
+use buffer::Cursor;
use proc_macro2::Span;
-use syn::buffer::Cursor;
use super::error;
use super::parse::Error;
diff --git a/src/next/mod.rs b/src/next/mod.rs
index aff318d..c9d4088 100644
--- a/src/next/mod.rs
+++ b/src/next/mod.rs
@@ -19,10 +19,10 @@
use std::str::FromStr;
+use buffer::TokenBuffer;
#[cfg(feature = "proc-macro")]
use proc_macro;
use proc_macro2::{self, Span};
-use syn::buffer::TokenBuffer;
use self::parse::{Parse, ParseBuffer, Result};
@@ -52,11 +52,11 @@
///
/// ```rust
/// # extern crate proc_macro;
-/// # extern crate syn_error_experiment;
+/// # extern crate syn;
/// #
/// use proc_macro::TokenStream;
-/// use syn_error_experiment::parse_macro_input;
-/// use syn_error_experiment::parse::{Parse, ParseStream, Result};
+/// use syn::parse_macro_input;
+/// use syn::next::parse::{Parse, ParseStream, Result};
///
/// struct MyMacroInput {
/// /* ... */
diff --git a/src/next/parse.rs b/src/next/parse.rs
index 5aa5505..447b8e1 100644
--- a/src/next/parse.rs
+++ b/src/next/parse.rs
@@ -6,8 +6,8 @@
use std::mem;
use std::ops::Deref;
+use buffer::Cursor;
use proc_macro2::{Ident, Span};
-use syn::buffer::Cursor;
use super::error;
diff --git a/src/next/token.rs b/src/next/token.rs
index d26f504..5b80a14 100644
--- a/src/next/token.rs
+++ b/src/next/token.rs
@@ -26,18 +26,6 @@
pub trait Sealed {}
}
-/// A type-macro that expands to the name of the Rust type representation of a
-/// given token.
-#[macro_export]
-#[cfg_attr(rustfmt, rustfmt_skip)]
-macro_rules! Token {
- (struct) => { $crate::next::token::Struct };
- (enum) => { $crate::next::token::Enum };
- (:) => { $crate::next::token::Colon };
- (,) => { $crate::next::token::Comma };
- (..) => { $crate::next::token::Dot2 };
-}
-
macro_rules! impl_token {
($token:tt $name:ident #[$doc:meta]) => {
impl Token for $name {
diff --git a/src/op.rs b/src/op.rs
new file mode 100644
index 0000000..a5188d0
--- /dev/null
+++ b/src/op.rs
@@ -0,0 +1,224 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+ast_enum! {
+ /// A binary operator: `+`, `+=`, `&`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum BinOp {
+ /// The `+` operator (addition)
+ Add(Token![+]),
+ /// The `-` operator (subtraction)
+ Sub(Token![-]),
+ /// The `*` operator (multiplication)
+ Mul(Token![*]),
+ /// The `/` operator (division)
+ Div(Token![/]),
+ /// The `%` operator (modulus)
+ Rem(Token![%]),
+ /// The `&&` operator (logical and)
+ And(Token![&&]),
+ /// The `||` operator (logical or)
+ Or(Token![||]),
+ /// The `^` operator (bitwise xor)
+ BitXor(Token![^]),
+ /// The `&` operator (bitwise and)
+ BitAnd(Token![&]),
+ /// The `|` operator (bitwise or)
+ BitOr(Token![|]),
+ /// The `<<` operator (shift left)
+ Shl(Token![<<]),
+ /// The `>>` operator (shift right)
+ Shr(Token![>>]),
+ /// The `==` operator (equality)
+ Eq(Token![==]),
+ /// The `<` operator (less than)
+ Lt(Token![<]),
+ /// The `<=` operator (less than or equal to)
+ Le(Token![<=]),
+ /// The `!=` operator (not equal to)
+ Ne(Token![!=]),
+ /// The `>=` operator (greater than or equal to)
+ Ge(Token![>=]),
+ /// The `>` operator (greater than)
+ Gt(Token![>]),
+ /// The `+=` operator
+ AddEq(Token![+=]),
+ /// The `-=` operator
+ SubEq(Token![-=]),
+ /// The `*=` operator
+ MulEq(Token![*=]),
+ /// The `/=` operator
+ DivEq(Token![/=]),
+ /// The `%=` operator
+ RemEq(Token![%=]),
+ /// The `^=` operator
+ BitXorEq(Token![^=]),
+ /// The `&=` operator
+ BitAndEq(Token![&=]),
+ /// The `|=` operator
+ BitOrEq(Token![|=]),
+ /// The `<<=` operator
+ ShlEq(Token![<<=]),
+ /// The `>>=` operator
+ ShrEq(Token![>>=]),
+ }
+}
+
+ast_enum! {
+ /// A unary operator: `*`, `!`, `-`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ #[cfg_attr(feature = "clone-impls", derive(Copy))]
+ pub enum UnOp {
+ /// The `*` operator for dereferencing
+ Deref(Token![*]),
+ /// The `!` operator for logical inversion
+ Not(Token![!]),
+ /// The `-` operator for negation
+ Neg(Token![-]),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use synom::Synom;
+
+ impl BinOp {
+ named!(pub parse_binop -> Self, alt!(
+ punct!(&&) => { BinOp::And }
+ |
+ punct!(||) => { BinOp::Or }
+ |
+ punct!(<<) => { BinOp::Shl }
+ |
+ punct!(>>) => { BinOp::Shr }
+ |
+ punct!(==) => { BinOp::Eq }
+ |
+ punct!(<=) => { BinOp::Le }
+ |
+ punct!(!=) => { BinOp::Ne }
+ |
+ punct!(>=) => { BinOp::Ge }
+ |
+ punct!(+) => { BinOp::Add }
+ |
+ punct!(-) => { BinOp::Sub }
+ |
+ punct!(*) => { BinOp::Mul }
+ |
+ punct!(/) => { BinOp::Div }
+ |
+ punct!(%) => { BinOp::Rem }
+ |
+ punct!(^) => { BinOp::BitXor }
+ |
+ punct!(&) => { BinOp::BitAnd }
+ |
+ punct!(|) => { BinOp::BitOr }
+ |
+ punct!(<) => { BinOp::Lt }
+ |
+ punct!(>) => { BinOp::Gt }
+ ));
+
+ #[cfg(feature = "full")]
+ named!(pub parse_assign_op -> Self, alt!(
+ punct!(+=) => { BinOp::AddEq }
+ |
+ punct!(-=) => { BinOp::SubEq }
+ |
+ punct!(*=) => { BinOp::MulEq }
+ |
+ punct!(/=) => { BinOp::DivEq }
+ |
+ punct!(%=) => { BinOp::RemEq }
+ |
+ punct!(^=) => { BinOp::BitXorEq }
+ |
+ punct!(&=) => { BinOp::BitAndEq }
+ |
+ punct!(|=) => { BinOp::BitOrEq }
+ |
+ punct!(<<=) => { BinOp::ShlEq }
+ |
+ punct!(>>=) => { BinOp::ShrEq }
+ ));
+ }
+
+ impl Synom for UnOp {
+ named!(parse -> Self, alt!(
+ punct!(*) => { UnOp::Deref }
+ |
+ punct!(!) => { UnOp::Not }
+ |
+ punct!(-) => { UnOp::Neg }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("unary operator: `*`, `!`, or `-`")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for BinOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ BinOp::Add(ref t) => t.to_tokens(tokens),
+ BinOp::Sub(ref t) => t.to_tokens(tokens),
+ BinOp::Mul(ref t) => t.to_tokens(tokens),
+ BinOp::Div(ref t) => t.to_tokens(tokens),
+ BinOp::Rem(ref t) => t.to_tokens(tokens),
+ BinOp::And(ref t) => t.to_tokens(tokens),
+ BinOp::Or(ref t) => t.to_tokens(tokens),
+ BinOp::BitXor(ref t) => t.to_tokens(tokens),
+ BinOp::BitAnd(ref t) => t.to_tokens(tokens),
+ BinOp::BitOr(ref t) => t.to_tokens(tokens),
+ BinOp::Shl(ref t) => t.to_tokens(tokens),
+ BinOp::Shr(ref t) => t.to_tokens(tokens),
+ BinOp::Eq(ref t) => t.to_tokens(tokens),
+ BinOp::Lt(ref t) => t.to_tokens(tokens),
+ BinOp::Le(ref t) => t.to_tokens(tokens),
+ BinOp::Ne(ref t) => t.to_tokens(tokens),
+ BinOp::Ge(ref t) => t.to_tokens(tokens),
+ BinOp::Gt(ref t) => t.to_tokens(tokens),
+ BinOp::AddEq(ref t) => t.to_tokens(tokens),
+ BinOp::SubEq(ref t) => t.to_tokens(tokens),
+ BinOp::MulEq(ref t) => t.to_tokens(tokens),
+ BinOp::DivEq(ref t) => t.to_tokens(tokens),
+ BinOp::RemEq(ref t) => t.to_tokens(tokens),
+ BinOp::BitXorEq(ref t) => t.to_tokens(tokens),
+ BinOp::BitAndEq(ref t) => t.to_tokens(tokens),
+ BinOp::BitOrEq(ref t) => t.to_tokens(tokens),
+ BinOp::ShlEq(ref t) => t.to_tokens(tokens),
+ BinOp::ShrEq(ref t) => t.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for UnOp {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ UnOp::Deref(ref t) => t.to_tokens(tokens),
+ UnOp::Not(ref t) => t.to_tokens(tokens),
+ UnOp::Neg(ref t) => t.to_tokens(tokens),
+ }
+ }
+ }
+}
diff --git a/src/parse_quote.rs b/src/parse_quote.rs
new file mode 100644
index 0000000..ec8ef5a
--- /dev/null
+++ b/src/parse_quote.rs
@@ -0,0 +1,163 @@
+/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
+/// type inference to figure out a return type for those tokens.
+///
+/// [`quote!`]: https://docs.rs/quote/0.4/quote/index.html
+///
+/// The return type can be any syntax tree node that implements the [`Synom`]
+/// trait.
+///
+/// [`Synom`]: synom/trait.Synom.html
+///
+/// ```
+/// #[macro_use]
+/// extern crate syn;
+///
+/// #[macro_use]
+/// extern crate quote;
+///
+/// use syn::Stmt;
+///
+/// fn main() {
+/// let name = quote!(v);
+/// let ty = quote!(u8);
+///
+/// let stmt: Stmt = parse_quote! {
+/// let #name: #ty = Default::default();
+/// };
+///
+/// println!("{:#?}", stmt);
+/// }
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature,
+/// although interpolation of syntax tree nodes into the quoted tokens is only
+/// supported if Syn is built with the `"printing"` feature as well.*
+///
+/// # Example
+///
+/// The following helper function adds a bound `T: HeapSize` to every type
+/// parameter `T` in the input generics.
+///
+/// ```
+/// # #[macro_use]
+/// # extern crate syn;
+/// #
+/// # #[macro_use]
+/// # extern crate quote;
+/// #
+/// # use syn::{Generics, GenericParam};
+/// #
+/// // Add a bound `T: HeapSize` to every type parameter T.
+/// fn add_trait_bounds(mut generics: Generics) -> Generics {
+/// for param in &mut generics.params {
+/// if let GenericParam::Type(ref mut type_param) = *param {
+/// type_param.bounds.push(parse_quote!(HeapSize));
+/// }
+/// }
+/// generics
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// # Special cases
+///
+/// This macro can parse the following additional types as a special case even
+/// though they do not implement the `Synom` trait.
+///
+/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
+/// or inner like `#![...]`
+/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
+/// `P` with optional trailing punctuation
+///
+/// [`Attribute`]: struct.Attribute.html
+/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
+///
+/// # Panics
+///
+/// Panics if the tokens fail to parse as the expected syntax tree type. The
+/// caller is responsible for ensuring that the input tokens are syntactically
+/// valid.
+#[macro_export]
+macro_rules! parse_quote {
+ ($($tt:tt)*) => {
+ $crate::parse_quote::parse($crate::parse_quote::From::from(quote!($($tt)*)))
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Can parse any type that implements Synom.
+
+use buffer::Cursor;
+use proc_macro2::TokenStream;
+use synom::{PResult, Parser, Synom};
+
+// Not public API.
+#[doc(hidden)]
+pub use std::convert::From;
+
+// Not public API.
+#[doc(hidden)]
+pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
+ let parser = T::parse;
+ match parser.parse2(token_stream) {
+ Ok(t) => t,
+ Err(err) => match T::description() {
+ Some(s) => panic!("failed to parse {}: {}", s, err),
+ None => panic!("{}", err),
+ },
+ }
+}
+
+// Not public API.
+#[doc(hidden)]
+pub trait ParseQuote: Sized {
+ fn parse(input: Cursor) -> PResult<Self>;
+ fn description() -> Option<&'static str>;
+}
+
+impl<T> ParseQuote for T
+where
+ T: Synom,
+{
+ fn parse(input: Cursor) -> PResult<Self> {
+ <T as Synom>::parse(input)
+ }
+
+ fn description() -> Option<&'static str> {
+ <T as Synom>::description()
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Any other types that we want `parse_quote!` to be able to parse.
+
+use punctuated::Punctuated;
+
+#[cfg(any(feature = "full", feature = "derive"))]
+use Attribute;
+
+impl<T, P> ParseQuote for Punctuated<T, P>
+where
+ T: Synom,
+ P: Synom,
+{
+ named!(parse -> Self, call!(Punctuated::parse_terminated));
+
+ fn description() -> Option<&'static str> {
+ Some("punctuated sequence")
+ }
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl ParseQuote for Attribute {
+ named!(parse -> Self, alt!(
+ call!(Attribute::parse_outer)
+ |
+ call!(Attribute::parse_inner)
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("attribute")
+ }
+}
diff --git a/src/parsers.rs b/src/parsers.rs
new file mode 100644
index 0000000..400c0ca
--- /dev/null
+++ b/src/parsers.rs
@@ -0,0 +1,1428 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use buffer::Cursor;
+use parse_error;
+use synom::PResult;
+
+/// Define a parser function with the signature expected by syn parser
+/// combinators.
+///
+/// The function may be the `parse` function of the [`Synom`] trait, or it may
+/// be a free-standing function with an arbitrary name. When implementing the
+/// `Synom` trait, the function name is `parse` and the return type is `Self`.
+///
+/// [`Synom`]: synom/trait.Synom.html
+///
+/// - **Syntax:** `named!(NAME -> TYPE, PARSER)` or `named!(pub NAME -> TYPE, PARSER)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::punctuated::Punctuated;
+/// use syn::synom::Synom;
+///
+/// /// Parses one or more Rust types separated by commas.
+/// ///
+/// /// Example: `String, Vec<T>, [u8; LEN + 1]`
+/// named!(pub comma_separated_types -> Punctuated<Type, Token![,]>,
+/// call!(Punctuated::parse_separated_nonempty)
+/// );
+///
+/// /// The same function as a `Synom` implementation.
+/// struct CommaSeparatedTypes {
+/// types: Punctuated<Type, Token![,]>,
+/// }
+///
+/// impl Synom for CommaSeparatedTypes {
+/// /// As the default behavior, we want there to be at least 1 type.
+/// named!(parse -> Self, do_parse!(
+/// types: call!(Punctuated::parse_separated_nonempty) >>
+/// (CommaSeparatedTypes { types })
+/// ));
+/// }
+///
+/// impl CommaSeparatedTypes {
+/// /// A separate parser that the user can invoke explicitly which allows
+/// /// for parsing 0 or more types, rather than the default 1 or more.
+/// named!(pub parse0 -> Self, do_parse!(
+/// types: call!(Punctuated::parse_separated) >>
+/// (CommaSeparatedTypes { types })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! named {
+ ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ fn $name(i: $crate::buffer::Cursor) -> $crate::synom::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ (pub $name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ pub fn $name(i: $crate::buffer::Cursor) -> $crate::synom::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ // These two variants are for defining named parsers which have custom
+ // arguments, and are called with `call!()`
+ ($name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ fn $name(i: $crate::buffer::Cursor, $($params)*) -> $crate::synom::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+
+ (pub $name:ident($($params:tt)*) -> $o:ty, $submac:ident!( $($args:tt)* )) => {
+ pub fn $name(i: $crate::buffer::Cursor, $($params)*) -> $crate::synom::PResult<$o> {
+ $submac!(i, $($args)*)
+ }
+ };
+}
+
+#[cfg(synom_verbose_trace)]
+#[macro_export]
+macro_rules! call {
+ ($i:expr, $fun:expr $(, $args:expr)*) => {{
+ #[allow(unused_imports)]
+ use $crate::synom::ext::*;
+ let i = $i;
+ eprintln!(concat!(" -> ", stringify!($fun), " @ {:?}"), i);
+ let r = $fun(i $(, $args)*);
+ match r {
+ Ok((_, i)) => eprintln!(concat!("OK ", stringify!($fun), " @ {:?}"), i),
+ Err(_) => eprintln!(concat!("ERR ", stringify!($fun), " @ {:?}"), i),
+ }
+ r
+ }};
+}
+
+/// Invoke the given parser function with zero or more arguments.
+///
+/// - **Syntax:** `call!(FN, ARGS...)`
+///
+/// where the signature of the function is `fn(Cursor, ARGS...) -> PResult<T>`
+///
+/// - **Output:** `T`, the result of invoking the function `FN`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::punctuated::Punctuated;
+/// use syn::synom::Synom;
+///
+/// /// Parses one or more Rust types separated by commas.
+/// ///
+/// /// Example: `String, Vec<T>, [u8; LEN + 1]`
+/// struct CommaSeparatedTypes {
+/// types: Punctuated<Type, Token![,]>,
+/// }
+///
+/// impl Synom for CommaSeparatedTypes {
+/// named!(parse -> Self, do_parse!(
+/// types: call!(Punctuated::parse_separated_nonempty) >>
+/// (CommaSeparatedTypes { types })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[cfg(not(synom_verbose_trace))]
+#[macro_export]
+macro_rules! call {
+ ($i:expr, $fun:expr $(, $args:expr)*) => {{
+ #[allow(unused_imports)]
+ use $crate::synom::ext::*;
+ $fun($i $(, $args)*)
+ }};
+}
+
+/// Transform the result of a parser by applying a function or closure.
+///
+/// - **Syntax:** `map!(THING, FN)`
+/// - **Output:** the return type of function FN applied to THING
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Expr, ExprIf};
+///
+/// /// Extracts the branch condition of an `if`-expression.
+/// fn get_cond(if_: ExprIf) -> Expr {
+/// *if_.cond
+/// }
+///
+/// /// Parses a full `if`-expression but returns the condition part only.
+/// ///
+/// /// Example: `if x > 0xFF { "big" } else { "small" }`
+/// /// The return would be the expression `x > 0xFF`.
+/// named!(if_condition -> Expr,
+/// map!(syn!(ExprIf), get_cond)
+/// );
+///
+/// /// Equivalent using a closure.
+/// named!(if_condition2 -> Expr,
+/// map!(syn!(ExprIf), |if_| *if_.cond)
+/// );
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! map {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok(($crate::parsers::invoke($g, o), i)),
+ }
+ };
+
+ ($i:expr, $f:expr, $g:expr) => {
+ map!($i, call!($f), $g)
+ };
+}
+
+// Somehow this helps with type inference in `map!` and `alt!`.
+//
+// Not public API.
+#[doc(hidden)]
+pub fn invoke<T, R, F: FnOnce(T) -> R>(f: F, t: T) -> R {
+ f(t)
+}
+
+/// Invert the result of a parser by parsing successfully if the given parser
+/// fails to parse and vice versa.
+///
+/// Does not consume any of the input.
+///
+/// - **Syntax:** `not!(THING)`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+///
+/// /// Parses any expression that does not begin with a `-` minus sign.
+/// named!(not_negative_expr -> Expr, do_parse!(
+/// not!(punct!(-)) >>
+/// e: syn!(Expr) >>
+/// (e)
+/// ));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! not {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok(_) => $crate::parse_error(),
+ ::std::result::Result::Err(_) =>
+ ::std::result::Result::Ok(((), $i)),
+ }
+ };
+}
+
+/// Execute a parser only if a condition is met, otherwise return None.
+///
+/// If you are familiar with nom, this is nom's `cond_with_error` parser.
+///
+/// - **Syntax:** `cond!(CONDITION, THING)`
+/// - **Output:** `Some(THING)` if the condition is true, else `None`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Ident, MacroDelimiter};
+/// use syn::token::{Paren, Bracket, Brace};
+/// use syn::synom::Synom;
+///
+/// /// Parses a macro call with empty input. If the macro is written with
+/// /// parentheses or brackets, a trailing semicolon is required.
+/// ///
+/// /// Example: `my_macro!{}` or `my_macro!();` or `my_macro![];`
+/// struct EmptyMacroCall {
+/// name: Ident,
+/// bang_token: Token![!],
+/// empty_body: MacroDelimiter,
+/// semi_token: Option<Token![;]>,
+/// }
+///
+/// fn requires_semi(delimiter: &MacroDelimiter) -> bool {
+/// match *delimiter {
+/// MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true,
+/// MacroDelimiter::Brace(_) => false,
+/// }
+/// }
+///
+/// impl Synom for EmptyMacroCall {
+/// named!(parse -> Self, do_parse!(
+/// name: syn!(Ident) >>
+/// bang_token: punct!(!) >>
+/// empty_body: alt!(
+/// parens!(epsilon!()) => { |d| MacroDelimiter::Paren(d.0) }
+/// |
+/// brackets!(epsilon!()) => { |d| MacroDelimiter::Bracket(d.0) }
+/// |
+/// braces!(epsilon!()) => { |d| MacroDelimiter::Brace(d.0) }
+/// ) >>
+/// semi_token: cond!(requires_semi(&empty_body), punct!(;)) >>
+/// (EmptyMacroCall {
+/// name,
+/// bang_token,
+/// empty_body,
+/// semi_token,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! cond {
+ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
+ if $cond {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok((::std::option::Option::Some(o), i)),
+ ::std::result::Result::Err(x) => ::std::result::Result::Err(x),
+ }
+ } else {
+ ::std::result::Result::Ok((::std::option::Option::None, $i))
+ }
+ };
+
+ ($i:expr, $cond:expr, $f:expr) => {
+ cond!($i, $cond, call!($f))
+ };
+}
+
+/// Execute a parser only if a condition is met, otherwise fail to parse.
+///
+/// This is typically used inside of [`option!`] or [`alt!`].
+///
+/// [`option!`]: macro.option.html
+/// [`alt!`]: macro.alt.html
+///
+/// - **Syntax:** `cond_reduce!(CONDITION, THING)`
+/// - **Output:** `THING`
+///
+/// The subparser may be omitted in which case it defaults to [`epsilon!`].
+///
+/// [`epsilon!`]: macro.epsilon.html
+///
+/// - **Syntax:** `cond_reduce!(CONDITION)`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+/// use syn::token::Paren;
+/// use syn::punctuated::Punctuated;
+/// use syn::synom::Synom;
+///
+/// /// Parses a possibly variadic function signature.
+/// ///
+/// /// Example: `fn(A) or `fn(A, B, C, ...)` or `fn(...)`
+/// /// Rejected: `fn(A, B...)`
+/// struct VariadicFn {
+/// fn_token: Token![fn],
+/// paren_token: Paren,
+/// types: Punctuated<Type, Token![,]>,
+/// variadic: Option<Token![...]>,
+/// }
+///
+/// // Example of using `cond_reduce!` inside of `option!`.
+/// impl Synom for VariadicFn {
+/// named!(parse -> Self, do_parse!(
+/// fn_token: keyword!(fn) >>
+/// params: parens!(do_parse!(
+/// types: call!(Punctuated::parse_terminated) >>
+/// // Allow, but do not require, an ending `...` but only if the
+/// // preceding list of types is empty or ends with a trailing comma.
+/// variadic: option!(cond_reduce!(types.empty_or_trailing(), punct!(...))) >>
+/// (types, variadic)
+/// )) >>
+/// ({
+/// let (paren_token, (types, variadic)) = params;
+/// VariadicFn {
+/// fn_token,
+/// paren_token,
+/// types,
+/// variadic,
+/// }
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! cond_reduce {
+ ($i:expr, $cond:expr, $submac:ident!( $($args:tt)* )) => {
+ if $cond {
+ $submac!($i, $($args)*)
+ } else {
+ $crate::parse_error()
+ }
+ };
+
+ ($i:expr, $cond:expr) => {
+ cond_reduce!($i, $cond, epsilon!())
+ };
+
+ ($i:expr, $cond:expr, $f:expr) => {
+ cond_reduce!($i, $cond, call!($f))
+ };
+}
+
+/// Parse zero or more values using the given parser.
+///
+/// - **Syntax:** `many0!(THING)`
+/// - **Output:** `Vec<THING>`
+///
+/// You may also be looking for:
+///
+/// - `call!(Punctuated::parse_separated)` - zero or more values with separator
+/// - `call!(Punctuated::parse_separated_nonempty)` - one or more values
+/// - `call!(Punctuated::parse_terminated)` - zero or more, allows trailing separator
+/// - `call!(Punctuated::parse_terminated_nonempty)` - one or more
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Ident, Item};
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
+///
+/// /// Parses a module containing zero or more Rust items.
+/// ///
+/// /// Example: `mod m { type Result<T> = ::std::result::Result<T, MyError>; }`
+/// struct SimpleMod {
+/// mod_token: Token![mod],
+/// name: Ident,
+/// brace_token: Brace,
+/// items: Vec<Item>,
+/// }
+///
+/// impl Synom for SimpleMod {
+/// named!(parse -> Self, do_parse!(
+/// mod_token: keyword!(mod) >>
+/// name: syn!(Ident) >>
+/// body: braces!(many0!(syn!(Item))) >>
+/// (SimpleMod {
+/// mod_token,
+/// name,
+/// brace_token: body.0,
+/// items: body.1,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! many0 {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {{
+ let ret;
+ let mut res = ::std::vec::Vec::new();
+ let mut input = $i;
+
+ loop {
+ if input.eof() {
+ ret = ::std::result::Result::Ok((res, input));
+ break;
+ }
+
+ match $submac!(input, $($args)*) {
+ ::std::result::Result::Err(_) => {
+ ret = ::std::result::Result::Ok((res, input));
+ break;
+ }
+ ::std::result::Result::Ok((o, i)) => {
+ // loop trip must always consume (otherwise infinite loops)
+ if i == input {
+ ret = $crate::parse_error();
+ break;
+ }
+
+ res.push(o);
+ input = i;
+ }
+ }
+ }
+
+ ret
+ }};
+
+ ($i:expr, $f:expr) => {
+ $crate::parsers::many0($i, $f)
+ };
+}
+
+// Improve compile time by compiling this loop only once per type it is used
+// with.
+//
+// Not public API.
+#[doc(hidden)]
+pub fn many0<T>(mut input: Cursor, f: fn(Cursor) -> PResult<T>) -> PResult<Vec<T>> {
+ let mut res = Vec::new();
+
+ loop {
+ if input.eof() {
+ return Ok((res, input));
+ }
+
+ match f(input) {
+ Err(_) => {
+ return Ok((res, input));
+ }
+ Ok((o, i)) => {
+ // loop trip must always consume (otherwise infinite loops)
+ if i == input {
+ return parse_error();
+ }
+
+ res.push(o);
+ input = i;
+ }
+ }
+ }
+}
+
+/// Pattern-match the result of a parser to select which other parser to run.
+///
+/// - **Syntax:** `switch!(TARGET, PAT1 => THEN1 | PAT2 => THEN2 | ...)`
+/// - **Output:** `T`, the return type of `THEN1` and `THEN2` and ...
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
+///
+/// /// Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
+/// enum UnitType {
+/// Struct {
+/// struct_token: Token![struct],
+/// name: Ident,
+/// semi_token: Token![;],
+/// },
+/// Enum {
+/// enum_token: Token![enum],
+/// name: Ident,
+/// brace_token: Brace,
+/// variant: Ident,
+/// },
+/// }
+///
+/// enum StructOrEnum {
+/// Struct(Token![struct]),
+/// Enum(Token![enum]),
+/// }
+///
+/// impl Synom for StructOrEnum {
+/// named!(parse -> Self, alt!(
+/// keyword!(struct) => { StructOrEnum::Struct }
+/// |
+/// keyword!(enum) => { StructOrEnum::Enum }
+/// ));
+/// }
+///
+/// impl Synom for UnitType {
+/// named!(parse -> Self, do_parse!(
+/// which: syn!(StructOrEnum) >>
+/// name: syn!(Ident) >>
+/// item: switch!(value!(which),
+/// StructOrEnum::Struct(struct_token) => map!(
+/// punct!(;),
+/// |semi_token| UnitType::Struct {
+/// struct_token,
+/// name,
+/// semi_token,
+/// }
+/// )
+/// |
+/// StructOrEnum::Enum(enum_token) => map!(
+/// braces!(syn!(Ident)),
+/// |(brace_token, variant)| UnitType::Enum {
+/// enum_token,
+/// name,
+/// brace_token,
+/// variant,
+/// }
+/// )
+/// ) >>
+/// (item)
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! switch {
+ ($i:expr, $submac:ident!( $($args:tt)* ), $($p:pat => $subrule:ident!( $($args2:tt)* ))|* ) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) => match o {
+ $(
+ $p => $subrule!(i, $($args2)*),
+ )*
+ }
+ }
+ };
+}
+
+/// Produce the given value without parsing anything.
+///
+/// This can be needed where you have an existing parsed value but a parser
+/// macro's syntax expects you to provide a submacro, such as in the first
+/// argument of [`switch!`] or one of the branches of [`alt!`].
+///
+/// [`switch!`]: macro.switch.html
+/// [`alt!`]: macro.alt.html
+///
+/// - **Syntax:** `value!(VALUE)`
+/// - **Output:** `VALUE`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
+///
+/// /// Parse a unit struct or enum: either `struct S;` or `enum E { V }`.
+/// enum UnitType {
+/// Struct {
+/// struct_token: Token![struct],
+/// name: Ident,
+/// semi_token: Token![;],
+/// },
+/// Enum {
+/// enum_token: Token![enum],
+/// name: Ident,
+/// brace_token: Brace,
+/// variant: Ident,
+/// },
+/// }
+///
+/// enum StructOrEnum {
+/// Struct(Token![struct]),
+/// Enum(Token![enum]),
+/// }
+///
+/// impl Synom for StructOrEnum {
+/// named!(parse -> Self, alt!(
+/// keyword!(struct) => { StructOrEnum::Struct }
+/// |
+/// keyword!(enum) => { StructOrEnum::Enum }
+/// ));
+/// }
+///
+/// impl Synom for UnitType {
+/// named!(parse -> Self, do_parse!(
+/// which: syn!(StructOrEnum) >>
+/// name: syn!(Ident) >>
+/// item: switch!(value!(which),
+/// StructOrEnum::Struct(struct_token) => map!(
+/// punct!(;),
+/// |semi_token| UnitType::Struct {
+/// struct_token,
+/// name,
+/// semi_token,
+/// }
+/// )
+/// |
+/// StructOrEnum::Enum(enum_token) => map!(
+/// braces!(syn!(Ident)),
+/// |(brace_token, variant)| UnitType::Enum {
+/// enum_token,
+/// name,
+/// brace_token,
+/// variant,
+/// }
+/// )
+/// ) >>
+/// (item)
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! value {
+ ($i:expr, $res:expr) => {
+ ::std::result::Result::Ok(($res, $i))
+ };
+}
+
+/// Unconditionally fail to parse anything.
+///
+/// This may be useful in rejecting some arms of a `switch!` parser.
+///
+/// - **Syntax:** `reject!()`
+/// - **Output:** never succeeds
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Item;
+///
+/// // Parse any item, except for a module.
+/// named!(almost_any_item -> Item,
+/// switch!(syn!(Item),
+/// Item::Mod(_) => reject!()
+/// |
+/// ok => value!(ok)
+/// )
+/// );
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! reject {
+ ($i:expr,) => {{
+ let _ = $i;
+ $crate::parse_error()
+ }};
+}
+
+/// Run a series of parsers and produce all of the results in a tuple.
+///
+/// - **Syntax:** `tuple!(A, B, C, ...)`
+/// - **Output:** `(A, B, C, ...)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Type;
+///
+/// named!(two_types -> (Type, Type), tuple!(syn!(Type), syn!(Type)));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! tuple {
+ ($i:expr, $($rest:tt)+) => {
+ tuple_parser!($i, (), $($rest)+)
+ };
+}
+
+// Internal parser, do not use directly.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! tuple_parser {
+ ($i:expr, ($($parsed:ident,)*), $e:ident) => {
+ tuple_parser!($i, ($($parsed,)*), call!($e))
+ };
+
+ ($i:expr, ($($parsed:ident,)*), $e:ident, $($rest:tt)*) => {
+ tuple_parser!($i, ($($parsed,)*), call!($e), $($rest)*)
+ };
+
+ ($i:expr, ($($parsed:ident,)*), $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok((($($parsed,)* o,), i)),
+ }
+ };
+
+ ($i:expr, ($($parsed:ident,)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) =>
+ tuple_parser!(i, ($($parsed,)* o,), $($rest)*),
+ }
+ };
+
+ ($i:expr, ($($parsed:ident,)*),) => {
+ ::std::result::Result::Ok((($($parsed,)*), $i))
+ };
+}
+
+/// Run a series of parsers, returning the result of the first one which
+/// succeeds.
+///
+/// Optionally allows for the result to be transformed.
+///
+/// - **Syntax:** `alt!(THING1 | THING2 => { FUNC } | ...)`
+/// - **Output:** `T`, the return type of `THING1` and `FUNC(THING2)` and ...
+///
+/// # Example
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+/// extern crate proc_macro2;
+///
+/// use proc_macro2::{Ident, Span};
+///
+/// // Parse any identifier token, or the `!` token in which case the
+/// // identifier is treated as `"BANG"`.
+/// named!(ident_or_bang -> Ident, alt!(
+/// syn!(Ident)
+/// |
+/// punct!(!) => { |_| Ident::new("BANG", Span::call_site()) }
+/// ));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// The `alt!` macro is most commonly seen when parsing a syntax tree enum such
+/// as the [`Item`] enum.
+///
+/// [`Item`]: enum.Item.html
+///
+/// ```
+/// # #[macro_use]
+/// # extern crate syn;
+/// #
+/// # use syn::synom::Synom;
+/// #
+/// # struct Item;
+/// #
+/// impl Synom for Item {
+/// named!(parse -> Self, alt!(
+/// # epsilon!() => { |_| unimplemented!() }
+/// # ));
+/// # }
+/// #
+/// # mod example {
+/// # use syn::*;
+/// #
+/// # named!(parse -> Item, alt!(
+/// syn!(ItemExternCrate) => { Item::ExternCrate }
+/// |
+/// syn!(ItemUse) => { Item::Use }
+/// |
+/// syn!(ItemStatic) => { Item::Static }
+/// |
+/// syn!(ItemConst) => { Item::Const }
+/// |
+/// /* ... */
+/// # syn!(ItemFn) => { Item::Fn }
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! alt {
+ ($i:expr, $e:ident | $($rest:tt)*) => {
+ alt!($i, call!($e) | $($rest)*)
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => {
+ match $subrule!($i, $($args)*) {
+ res @ ::std::result::Result::Ok(_) => res,
+ _ => alt!($i, $($rest)*)
+ }
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => {
+ match $subrule!($i, $($args)*) {
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok(($crate::parsers::invoke($gen, o), i)),
+ ::std::result::Result::Err(_) => alt!($i, $($rest)*),
+ }
+ };
+
+ ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => {
+ alt!($i, call!($e) => { $gen } | $($rest)*)
+ };
+
+ ($i:expr, $e:ident => { $gen:expr }) => {
+ alt!($i, call!($e) => { $gen })
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => {
+ match $subrule!($i, $($args)*) {
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok(($crate::parsers::invoke($gen, o), i)),
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $e:ident) => {
+ alt!($i, call!($e))
+ };
+
+ ($i:expr, $subrule:ident!( $($args:tt)*)) => {
+ $subrule!($i, $($args)*)
+ };
+}
+
+/// Run a series of parsers, optionally naming each intermediate result,
+/// followed by a step to combine the intermediate results.
+///
+/// Produces the result of evaluating the final expression in parentheses with
+/// all of the previously named results bound.
+///
+/// - **Syntax:** `do_parse!(name: THING1 >> THING2 >> (RESULT))`
+/// - **Output:** `RESULT`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+/// extern crate proc_macro2;
+///
+/// use proc_macro2::Ident;
+/// use proc_macro2::TokenStream;
+/// use syn::token::Paren;
+/// use syn::synom::Synom;
+///
+/// /// Parse a macro invocation that uses `(` `)` parentheses.
+/// ///
+/// /// Example: `stringify!($args)`.
+/// struct Macro {
+/// name: Ident,
+/// bang_token: Token![!],
+/// paren_token: Paren,
+/// tts: TokenStream,
+/// }
+///
+/// impl Synom for Macro {
+/// named!(parse -> Self, do_parse!(
+/// name: syn!(Ident) >>
+/// bang_token: punct!(!) >>
+/// body: parens!(syn!(TokenStream)) >>
+/// (Macro {
+/// name,
+/// bang_token,
+/// paren_token: body.0,
+/// tts: body.1,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! do_parse {
+ ($i:expr, ( $($rest:expr),* )) => {
+ ::std::result::Result::Ok((( $($rest),* ), $i))
+ };
+
+ ($i:expr, $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((_, i)) =>
+ do_parse!(i, $($rest)*),
+ }
+ };
+
+ ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, $field: call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) => {
+ let $field = o;
+ do_parse!(i, $($rest)*)
+ },
+ }
+ };
+
+ ($i:expr, mut $field:ident : $e:ident >> $($rest:tt)*) => {
+ do_parse!($i, mut $field: call!($e) >> $($rest)*)
+ };
+
+ ($i:expr, mut $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((o, i)) => {
+ let mut $field = o;
+ do_parse!(i, $($rest)*)
+ },
+ }
+ };
+}
+
+/// Parse nothing and succeed only if the end of the enclosing block has been
+/// reached.
+///
+/// The enclosing block may be the full input if we are parsing at the top
+/// level, or the surrounding parenthesis/bracket/brace if we are parsing within
+/// those.
+///
+/// - **Syntax:** `input_end!()`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::synom::Synom;
+///
+/// /// Parses any Rust expression followed either by a semicolon or by the end
+/// /// of the input.
+/// ///
+/// /// For example `many0!(syn!(TerminatedExpr))` would successfully parse the
+/// /// following input into three expressions.
+/// ///
+/// /// 1 + 1; second.two(); third!()
+/// ///
+/// /// Similarly within a block, `braced!(many0!(syn!(TerminatedExpr)))` would
+/// /// successfully parse three expressions.
+/// ///
+/// /// { 1 + 1; second.two(); third!() }
+/// struct TerminatedExpr {
+/// expr: Expr,
+/// semi_token: Option<Token![;]>,
+/// }
+///
+/// impl Synom for TerminatedExpr {
+/// named!(parse -> Self, do_parse!(
+/// expr: syn!(Expr) >>
+/// semi_token: alt!(
+/// input_end!() => { |_| None }
+/// |
+/// punct!(;) => { Some }
+/// ) >>
+/// (TerminatedExpr {
+/// expr,
+/// semi_token,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! input_end {
+ ($i:expr,) => {
+ $crate::parsers::input_end($i)
+ };
+}
+
+// Not a public API
+#[doc(hidden)]
+pub fn input_end(input: Cursor) -> PResult<'static, ()> {
+ if input.eof() {
+ Ok(((), Cursor::empty()))
+ } else {
+ parse_error()
+ }
+}
+
+/// Turn a failed parse into `None` and a successful parse into `Some`.
+///
+/// A failed parse consumes none of the input.
+///
+/// - **Syntax:** `option!(THING)`
+/// - **Output:** `Option<THING>`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Label, Block};
+/// use syn::synom::Synom;
+///
+/// /// Parses a Rust loop. Equivalent to syn::ExprLoop.
+/// ///
+/// /// Examples:
+/// /// loop { println!("y"); }
+/// /// 'x: loop { break 'x; }
+/// struct ExprLoop {
+/// label: Option<Label>,
+/// loop_token: Token![loop],
+/// body: Block,
+/// }
+///
+/// impl Synom for ExprLoop {
+/// named!(parse -> Self, do_parse!(
+/// // Loop may or may not have a label.
+/// label: option!(syn!(Label)) >>
+/// loop_token: keyword!(loop) >>
+/// body: syn!(Block) >>
+/// (ExprLoop {
+/// label,
+/// loop_token,
+/// body,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! option {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((o, i)) =>
+ ::std::result::Result::Ok((Some(o), i)),
+ ::std::result::Result::Err(_) =>
+ ::std::result::Result::Ok((None, $i)),
+ }
+ };
+
+ ($i:expr, $f:expr) => {
+ option!($i, call!($f));
+ };
+}
+
+/// Parses nothing and always succeeds.
+///
+/// This can be useful as a fallthrough case in [`alt!`], as shown below. Also
+/// useful for parsing empty delimiters using [`parens!`] or [`brackets!`] or
+/// [`braces!`] by parsing for example `braces!(epsilon!())` for an empty `{}`.
+///
+/// [`alt!`]: macro.alt.html
+/// [`parens!`]: macro.parens.html
+/// [`brackets!`]: macro.brackets.html
+/// [`braces!`]: macro.braces.html
+///
+/// - **Syntax:** `epsilon!()`
+/// - **Output:** `()`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::synom::Synom;
+///
+/// enum Mutability {
+/// Mutable(Token![mut]),
+/// Immutable,
+/// }
+///
+/// impl Synom for Mutability {
+/// named!(parse -> Self, alt!(
+/// keyword!(mut) => { Mutability::Mutable }
+/// |
+/// epsilon!() => { |_| Mutability::Immutable }
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! epsilon {
+ ($i:expr,) => {
+ ::std::result::Result::Ok(((), $i))
+ };
+}
+
+/// Run a parser, binding the result to a name, and then evaluating an
+/// expression.
+///
+/// Discards the result of the expression and parser.
+///
+/// - **Syntax:** `tap!(NAME : THING => EXPR)`
+/// - **Output:** `()`
+#[doc(hidden)]
+#[macro_export]
+macro_rules! tap {
+ ($i:expr, $name:ident : $submac:ident!( $($args:tt)* ) => $e:expr) => {
+ match $submac!($i, $($args)*) {
+ ::std::result::Result::Ok((o, i)) => {
+ let $name = o;
+ $e;
+ ::std::result::Result::Ok(((), i))
+ }
+ ::std::result::Result::Err(err) =>
+ ::std::result::Result::Err(err),
+ }
+ };
+
+ ($i:expr, $name:ident : $f:expr => $e:expr) => {
+ tap!($i, $name: call!($f) => $e);
+ };
+}
+
+/// Parse any type that implements the `Synom` trait.
+///
+/// Any type implementing [`Synom`] can be used with this parser, whether the
+/// implementation is provided by Syn or is one that you write.
+///
+/// [`Synom`]: synom/trait.Synom.html
+///
+/// - **Syntax:** `syn!(TYPE)`
+/// - **Output:** `TYPE`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::{Ident, Item};
+/// use syn::token::Brace;
+/// use syn::synom::Synom;
+///
+/// /// Parses a module containing zero or more Rust items.
+/// ///
+/// /// Example: `mod m { type Result<T> = ::std::result::Result<T, MyError>; }`
+/// struct SimpleMod {
+/// mod_token: Token![mod],
+/// name: Ident,
+/// brace_token: Brace,
+/// items: Vec<Item>,
+/// }
+///
+/// impl Synom for SimpleMod {
+/// named!(parse -> Self, do_parse!(
+/// mod_token: keyword!(mod) >>
+/// name: syn!(Ident) >>
+/// body: braces!(many0!(syn!(Item))) >>
+/// (SimpleMod {
+/// mod_token,
+/// name,
+/// brace_token: body.0,
+/// items: body.1,
+/// })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! syn {
+ ($i:expr, $t:ty) => {
+ <$t as $crate::synom::Synom>::parse($i)
+ };
+}
+
+/// Parse the given word as a keyword.
+///
+/// For words that are keywords in the Rust language, it is better to use the
+/// [`keyword!`] parser which returns a unique type for each keyword.
+///
+/// [`keyword!`]: macro.keyword.html
+///
+/// - **Syntax:** `custom_keyword!(KEYWORD)`
+/// - **Output:** `Ident`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Ident;
+/// use syn::synom::Synom;
+///
+/// struct Flag {
+/// name: Ident,
+/// }
+///
+/// // Parses the custom keyword `flag` followed by any name for a flag.
+/// //
+/// // Example: `flag Verbose`
+/// impl Synom for Flag {
+/// named!(parse -> Flag, do_parse!(
+/// custom_keyword!(flag) >>
+/// name: syn!(Ident) >>
+/// (Flag { name })
+/// ));
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! custom_keyword {
+ ($i:expr, $keyword:ident) => {
+ match <$crate::Ident as $crate::synom::Synom>::parse($i) {
+ ::std::result::Result::Err(err) => ::std::result::Result::Err(err),
+ ::std::result::Result::Ok((token, i)) => {
+ if token == stringify!($keyword) {
+ ::std::result::Result::Ok((token, i))
+ } else {
+ $crate::parse_error()
+ }
+ }
+ }
+ };
+}
+
+/// Parse inside of `(` `)` parentheses.
+///
+/// This macro parses a set of balanced parentheses and invokes a sub-parser on
+/// the content inside. The sub-parser is required to consume all tokens within
+/// the parentheses in order for this parser to return successfully.
+///
+/// - **Syntax:** `parens!(CONTENT)`
+/// - **Output:** `(token::Paren, CONTENT)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::token::Paren;
+///
+/// /// Parses an expression inside of parentheses.
+/// ///
+/// /// Example: `(1 + 1)`
+/// named!(expr_paren -> (Paren, Expr), parens!(syn!(Expr)));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! parens {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::token::Paren::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ parens!($i, call!($f));
+ };
+}
+
+/// Parse inside of `[` `]` square brackets.
+///
+/// This macro parses a set of balanced brackets and invokes a sub-parser on the
+/// content inside. The sub-parser is required to consume all tokens within the
+/// brackets in order for this parser to return successfully.
+///
+/// - **Syntax:** `brackets!(CONTENT)`
+/// - **Output:** `(token::Bracket, CONTENT)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::token::Bracket;
+///
+/// /// Parses an expression inside of brackets.
+/// ///
+/// /// Example: `[1 + 1]`
+/// named!(expr_paren -> (Bracket, Expr), brackets!(syn!(Expr)));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! brackets {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::token::Bracket::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ brackets!($i, call!($f));
+ };
+}
+
+/// Parse inside of `{` `}` curly braces.
+///
+/// This macro parses a set of balanced braces and invokes a sub-parser on the
+/// content inside. The sub-parser is required to consume all tokens within the
+/// braces in order for this parser to return successfully.
+///
+/// - **Syntax:** `braces!(CONTENT)`
+/// - **Output:** `(token::Brace, CONTENT)`
+///
+/// ```rust
+/// #[macro_use]
+/// extern crate syn;
+///
+/// use syn::Expr;
+/// use syn::token::Brace;
+///
+/// /// Parses an expression inside of braces.
+/// ///
+/// /// Example: `{1 + 1}`
+/// named!(expr_paren -> (Brace, Expr), braces!(syn!(Expr)));
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[macro_export]
+macro_rules! braces {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::token::Brace::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ braces!($i, call!($f));
+ };
+}
+
+// Not public API.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! grouped {
+ ($i:expr, $submac:ident!( $($args:tt)* )) => {
+ $crate::token::Group::parse($i, |i| $submac!(i, $($args)*))
+ };
+
+ ($i:expr, $f:expr) => {
+ grouped!($i, call!($f));
+ };
+}
diff --git a/src/path.rs b/src/path.rs
new file mode 100644
index 0000000..a848944
--- /dev/null
+++ b/src/path.rs
@@ -0,0 +1,577 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use punctuated::Punctuated;
+
+ast_struct! {
+ /// A path at which a named item is exported: `std::collections::HashMap`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Path {
+ pub leading_colon: Option<Token![::]>,
+ pub segments: Punctuated<PathSegment, Token![::]>,
+ }
+}
+
+impl Path {
+ pub fn global(&self) -> bool {
+ self.leading_colon.is_some()
+ }
+}
+
+/// A helper for printing a self-type qualified path as tokens.
+///
+/// ```rust
+/// extern crate syn;
+/// extern crate quote;
+/// extern crate proc_macro2;
+///
+/// use syn::{QSelf, Path, PathTokens};
+/// use proc_macro2::TokenStream;
+/// use quote::ToTokens;
+///
+/// struct MyNode {
+/// qself: Option<QSelf>,
+/// path: Path,
+/// }
+///
+/// impl ToTokens for MyNode {
+/// fn to_tokens(&self, tokens: &mut TokenStream) {
+/// PathTokens(&self.qself, &self.path).to_tokens(tokens);
+/// }
+/// }
+/// #
+/// # fn main() {}
+/// ```
+///
+/// *This type is available if Syn is built with the `"derive"` or `"full"`
+/// feature and the `"printing"` feature.*
+#[cfg(feature = "printing")]
+#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
+
+impl<T> From<T> for Path
+where
+ T: Into<PathSegment>,
+{
+ fn from(segment: T) -> Self {
+ let mut path = Path {
+ leading_colon: None,
+ segments: Punctuated::new(),
+ };
+ path.segments.push_value(segment.into());
+ path
+ }
+}
+
+ast_struct! {
+ /// A segment of a path together with any path arguments on that segment.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct PathSegment {
+ pub ident: Ident,
+ pub arguments: PathArguments,
+ }
+}
+
+impl<T> From<T> for PathSegment
+where
+ T: Into<Ident>,
+{
+ fn from(ident: T) -> Self {
+ PathSegment {
+ ident: ident.into(),
+ arguments: PathArguments::None,
+ }
+ }
+}
+
+ast_enum! {
+ /// Angle bracketed or parenthesized arguments of a path segment.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// ## Angle bracketed
+ ///
+ /// The `<'a, T>` in `std::slice::iter<'a, T>`.
+ ///
+ /// ## Parenthesized
+ ///
+ /// The `(A, B) -> C` in `Fn(A, B) -> C`.
+ pub enum PathArguments {
+ None,
+ /// The `<'a, T>` in `std::slice::iter<'a, T>`.
+ AngleBracketed(AngleBracketedGenericArguments),
+ /// The `(A, B) -> C` in `Fn(A, B) -> C`.
+ Parenthesized(ParenthesizedGenericArguments),
+ }
+}
+
+impl Default for PathArguments {
+ fn default() -> Self {
+ PathArguments::None
+ }
+}
+
+impl PathArguments {
+ pub fn is_empty(&self) -> bool {
+ match *self {
+ PathArguments::None => true,
+ PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
+ PathArguments::Parenthesized(_) => false,
+ }
+ }
+}
+
+ast_enum! {
+ /// An individual generic argument, like `'a`, `T`, or `Item = T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum GenericArgument {
+ /// A lifetime argument.
+ Lifetime(Lifetime),
+ /// A type argument.
+ Type(Type),
+ /// A binding (equality constraint) on an associated type: the `Item =
+ /// u8` in `Iterator<Item = u8>`.
+ Binding(Binding),
+ /// A const expression. Must be inside of a block.
+ ///
+ /// NOTE: Identity expressions are represented as Type arguments, as
+ /// they are indistinguishable syntactically.
+ Const(Expr),
+ }
+}
+
+ast_struct! {
+ /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
+ /// V>`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct AngleBracketedGenericArguments {
+ pub colon2_token: Option<Token![::]>,
+ pub lt_token: Token![<],
+ pub args: Punctuated<GenericArgument, Token![,]>,
+ pub gt_token: Token![>],
+ }
+}
+
+ast_struct! {
+ /// A binding (equality constraint) on an associated type: `Item = u8`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Binding {
+ pub ident: Ident,
+ pub eq_token: Token![=],
+ pub ty: Type,
+ }
+}
+
+ast_struct! {
+ /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
+ /// C`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct ParenthesizedGenericArguments {
+ pub paren_token: token::Paren,
+ /// `(A, B)`
+ pub inputs: Punctuated<Type, Token![,]>,
+ /// `C`
+ pub output: ReturnType,
+ }
+}
+
+ast_struct! {
+ /// The explicit Self type in a qualified path: the `T` in `<T as
+ /// Display>::fmt`.
+ ///
+ /// The actual path, including the trait and the associated item, is stored
+ /// separately. The `position` field represents the index of the associated
+ /// item qualified with this Self type.
+ ///
+ /// ```text
+ /// <Vec<T> as a::b::Trait>::AssociatedItem
+ /// ^~~~~~ ~~~~~~~~~~~~~~^
+ /// ty position = 3
+ ///
+ /// <Vec<T>>::AssociatedItem
+ /// ^~~~~~ ^
+ /// ty position = 0
+ /// ```
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct QSelf {
+ pub lt_token: Token![<],
+ pub ty: Box<Type>,
+ pub position: usize,
+ pub as_token: Option<Token![as]>,
+ pub gt_token: Token![>],
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use synom::Synom;
+
+ impl Synom for Path {
+ named!(parse -> Self, do_parse!(
+ colon: option!(punct!(::)) >>
+ segments: call!(Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty) >>
+ cond_reduce!(segments.first().map_or(true, |seg| seg.value().ident != "dyn")) >>
+ (Path {
+ leading_colon: colon,
+ segments: segments,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("path")
+ }
+ }
+
+ #[cfg(not(feature = "full"))]
+ impl Synom for GenericArgument {
+ named!(parse -> Self, alt!(
+ call!(ty_no_eq_after) => { GenericArgument::Type }
+ |
+ syn!(Lifetime) => { GenericArgument::Lifetime }
+ |
+ syn!(Binding) => { GenericArgument::Binding }
+ ));
+ }
+
+ #[cfg(feature = "full")]
+ impl Synom for GenericArgument {
+ named!(parse -> Self, alt!(
+ call!(ty_no_eq_after) => { GenericArgument::Type }
+ |
+ syn!(Lifetime) => { GenericArgument::Lifetime }
+ |
+ syn!(Binding) => { GenericArgument::Binding }
+ |
+ syn!(ExprLit) => { |l| GenericArgument::Const(Expr::Lit(l)) }
+ |
+ syn!(ExprBlock) => { |b| GenericArgument::Const(Expr::Block(b)) }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("generic argument")
+ }
+ }
+
+ impl Synom for AngleBracketedGenericArguments {
+ named!(parse -> Self, do_parse!(
+ colon2: option!(punct!(::)) >>
+ lt: punct!(<) >>
+ args: call!(Punctuated::parse_terminated) >>
+ gt: punct!(>) >>
+ (AngleBracketedGenericArguments {
+ colon2_token: colon2,
+ lt_token: lt,
+ args: args,
+ gt_token: gt,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("angle bracketed generic arguments")
+ }
+ }
+
+ impl Synom for ParenthesizedGenericArguments {
+ named!(parse -> Self, do_parse!(
+ data: parens!(Punctuated::parse_terminated) >>
+ output: call!(ReturnType::without_plus) >>
+ (ParenthesizedGenericArguments {
+ paren_token: data.0,
+ inputs: data.1,
+ output: output,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("parenthesized generic arguments: `Foo(A, B, ..) -> T`")
+ }
+ }
+
+ impl Synom for PathSegment {
+ named!(parse -> Self, alt!(
+ do_parse!(
+ ident: syn!(Ident) >>
+ arguments: syn!(AngleBracketedGenericArguments) >>
+ (PathSegment {
+ ident: ident,
+ arguments: PathArguments::AngleBracketed(arguments),
+ })
+ )
+ |
+ mod_style_path_segment
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("path segment")
+ }
+ }
+
+ impl Synom for Binding {
+ named!(parse -> Self, do_parse!(
+ id: syn!(Ident) >>
+ eq: punct!(=) >>
+ ty: syn!(Type) >>
+ (Binding {
+ ident: id,
+ eq_token: eq,
+ ty: ty,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("associated type binding")
+ }
+ }
+
+ impl Path {
+ named!(pub parse_mod_style -> Self, do_parse!(
+ colon: option!(punct!(::)) >>
+ segments: call!(Punctuated::parse_separated_nonempty_with,
+ mod_style_path_segment) >>
+ (Path {
+ leading_colon: colon,
+ segments: segments,
+ })
+ ));
+ }
+
+ named!(pub mod_style_path_segment -> PathSegment, alt!(
+ syn!(Ident) => { Into::into }
+ |
+ keyword!(super) => { Into::into }
+ |
+ keyword!(self) => { Into::into }
+ |
+ keyword!(Self) => { Into::into }
+ |
+ keyword!(crate) => { Into::into }
+ |
+ keyword!(extern) => { Into::into }
+ ));
+
+ named!(pub qpath -> (Option<QSelf>, Path), alt!(
+ map!(syn!(Path), |p| (None, p))
+ |
+ do_parse!(
+ lt: punct!(<) >>
+ this: syn!(Type) >>
+ path: option!(tuple!(keyword!(as), syn!(Path))) >>
+ gt: punct!(>) >>
+ colon2: punct!(::) >>
+ rest: call!(Punctuated::parse_separated_nonempty) >>
+ ({
+ let (pos, as_, path) = match path {
+ Some((as_, mut path)) => {
+ let pos = path.segments.len();
+ path.segments.push_punct(colon2);
+ path.segments.extend(rest.into_pairs());
+ (pos, Some(as_), path)
+ }
+ None => {
+ (0, None, Path {
+ leading_colon: Some(colon2),
+ segments: rest,
+ })
+ }
+ };
+ (Some(QSelf {
+ lt_token: lt,
+ ty: Box::new(this),
+ position: pos,
+ as_token: as_,
+ gt_token: gt,
+ }), path)
+ })
+ )
+ |
+ map!(keyword!(self), |s| (None, s.into()))
+ ));
+
+ named!(pub ty_no_eq_after -> Type, do_parse!(
+ ty: syn!(Type) >>
+ not!(punct!(=)) >>
+ (ty)
+ ));
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for Path {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.leading_colon.to_tokens(tokens);
+ self.segments.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PathSegment {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.arguments.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PathArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(ref arguments) => {
+ arguments.to_tokens(tokens);
+ }
+ PathArguments::Parenthesized(ref arguments) => {
+ arguments.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for GenericArgument {
+ #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
+ GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
+ GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
+ GenericArgument::Const(ref e) => match *e {
+ Expr::Lit(_) => e.to_tokens(tokens),
+
+ // NOTE: We should probably support parsing blocks with only
+ // expressions in them without the full feature for const
+ // generics.
+ #[cfg(feature = "full")]
+ Expr::Block(_) => e.to_tokens(tokens),
+
+ // ERROR CORRECTION: Add braces to make sure that the
+ // generated code is valid.
+ _ => token::Brace::default().surround(tokens, |tokens| {
+ e.to_tokens(tokens);
+ }),
+ },
+ }
+ }
+ }
+
+ impl ToTokens for AngleBracketedGenericArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.colon2_token.to_tokens(tokens);
+ self.lt_token.to_tokens(tokens);
+
+ // Print lifetimes before types and consts, all before bindings,
+ // regardless of their order in self.args.
+ //
+ // TODO: ordering rules for const arguments vs type arguments have
+ // not been settled yet. https://github.com/rust-lang/rust/issues/44580
+ let mut trailing_or_empty = true;
+ for param in self.args.pairs() {
+ if let GenericArgument::Lifetime(_) = **param.value() {
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ }
+ for param in self.args.pairs() {
+ match **param.value() {
+ GenericArgument::Type(_) | GenericArgument::Const(_) => {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ }
+ param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
+ }
+ GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
+ }
+ }
+ for param in self.args.pairs() {
+ if let GenericArgument::Binding(_) = **param.value() {
+ if !trailing_or_empty {
+ <Token![,]>::default().to_tokens(tokens);
+ trailing_or_empty = true;
+ }
+ param.to_tokens(tokens);
+ }
+ }
+
+ self.gt_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for Binding {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.ident.to_tokens(tokens);
+ self.eq_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ParenthesizedGenericArguments {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ });
+ self.output.to_tokens(tokens);
+ }
+ }
+
+ impl<'a> ToTokens for PathTokens<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ let qself = match *self.0 {
+ Some(ref qself) => qself,
+ None => return self.1.to_tokens(tokens),
+ };
+ qself.lt_token.to_tokens(tokens);
+ qself.ty.to_tokens(tokens);
+
+ // XXX: Gross.
+ let pos = if qself.position > 0 && qself.position >= self.1.segments.len() {
+ self.1.segments.len() - 1
+ } else {
+ qself.position
+ };
+ let mut segments = self.1.segments.pairs();
+ if pos > 0 {
+ TokensOrDefault(&qself.as_token).to_tokens(tokens);
+ self.1.leading_colon.to_tokens(tokens);
+ for (i, segment) in segments.by_ref().take(pos).enumerate() {
+ if i + 1 == pos {
+ segment.value().to_tokens(tokens);
+ qself.gt_token.to_tokens(tokens);
+ segment.punct().to_tokens(tokens);
+ } else {
+ segment.to_tokens(tokens);
+ }
+ }
+ } else {
+ qself.gt_token.to_tokens(tokens);
+ self.1.leading_colon.to_tokens(tokens);
+ }
+ for segment in segments {
+ segment.to_tokens(tokens);
+ }
+ }
+ }
+}
diff --git a/src/punctuated.rs b/src/punctuated.rs
new file mode 100644
index 0000000..b4a0b3f
--- /dev/null
+++ b/src/punctuated.rs
@@ -0,0 +1,807 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A punctuated sequence of syntax tree nodes separated by punctuation.
+//!
+//! Lots of things in Rust are punctuated sequences.
+//!
+//! - The fields of a struct are `Punctuated<Field, Token![,]>`.
+//! - The segments of a path are `Punctuated<PathSegment, Token![::]>`.
+//! - The bounds on a generic parameter are `Punctuated<TypeParamBound, Token![+]>`.
+//! - The arguments to a function call are `Punctuated<Expr, Token![,]>`.
+//!
+//! This module provides a common representation for these punctuated sequences
+//! in the form of the [`Punctuated<T, P>`] type. We store a vector of pairs of
+//! syntax tree node + punctuation, where every node in the sequence is followed
+//! by punctuation except for possibly the final one.
+//!
+//! [`Punctuated<T, P>`]: struct.Punctuated.html
+//!
+//! ```text
+//! a_function_call(arg1, arg2, arg3);
+//! ^^^^^ ~~~~~ ^^^^
+//! ```
+
+#[cfg(feature = "extra-traits")]
+use std::fmt::{self, Debug};
+#[cfg(any(feature = "full", feature = "derive"))]
+use std::iter;
+use std::iter::FromIterator;
+use std::ops::{Index, IndexMut};
+use std::option;
+use std::slice;
+use std::vec;
+
+#[cfg(feature = "parsing")]
+use buffer::Cursor;
+#[cfg(feature = "parsing")]
+use parse_error;
+#[cfg(feature = "parsing")]
+use synom::{PResult, Synom};
+
+/// A punctuated sequence of syntax tree nodes of type `T` separated by
+/// punctuation of type `P`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))]
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct Punctuated<T, P> {
+ inner: Vec<(T, P)>,
+ last: Option<Box<T>>,
+}
+
+impl<T, P> Punctuated<T, P> {
+ /// Creates an empty punctuated sequence.
+ pub fn new() -> Punctuated<T, P> {
+ Punctuated {
+ inner: Vec::new(),
+ last: None,
+ }
+ }
+
+ /// Determines whether this punctuated sequence is empty, meaning it
+ /// contains no syntax tree nodes or punctuation.
+ pub fn is_empty(&self) -> bool {
+ self.inner.len() == 0 && self.last.is_none()
+ }
+
+ /// Returns the number of syntax tree nodes in this punctuated sequence.
+ ///
+ /// This is the number of nodes of type `T`, not counting the punctuation of
+ /// type `P`.
+ pub fn len(&self) -> usize {
+ self.inner.len() + if self.last.is_some() { 1 } else { 0 }
+ }
+
+ /// Borrows the first punctuated pair in this sequence.
+ pub fn first(&self) -> Option<Pair<&T, &P>> {
+ self.pairs().next()
+ }
+
+ /// Borrows the last punctuated pair in this sequence.
+ pub fn last(&self) -> Option<Pair<&T, &P>> {
+ if self.last.is_some() {
+ self.last.as_ref().map(|t| Pair::End(t.as_ref()))
+ } else {
+ self.inner
+ .last()
+ .map(|&(ref t, ref d)| Pair::Punctuated(t, d))
+ }
+ }
+
+ /// Mutably borrows the last punctuated pair in this sequence.
+ pub fn last_mut(&mut self) -> Option<Pair<&mut T, &mut P>> {
+ if self.last.is_some() {
+ self.last.as_mut().map(|t| Pair::End(t.as_mut()))
+ } else {
+ self.inner
+ .last_mut()
+ .map(|&mut (ref mut t, ref mut d)| Pair::Punctuated(t, d))
+ }
+ }
+
+ /// Returns an iterator over borrowed syntax tree nodes of type `&T`.
+ pub fn iter(&self) -> Iter<T> {
+ Iter {
+ inner: Box::new(PrivateIter {
+ inner: self.inner.iter(),
+ last: self.last.as_ref().map(|t| t.as_ref()).into_iter(),
+ }),
+ }
+ }
+
+ /// Returns an iterator over mutably borrowed syntax tree nodes of type
+ /// `&mut T`.
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ IterMut {
+ inner: Box::new(PrivateIterMut {
+ inner: self.inner.iter_mut(),
+ last: self.last.as_mut().map(|t| t.as_mut()).into_iter(),
+ }),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as borrowed
+ /// punctuated pairs.
+ pub fn pairs(&self) -> Pairs<T, P> {
+ Pairs {
+ inner: self.inner.iter(),
+ last: self.last.as_ref().map(|t| t.as_ref()).into_iter(),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as mutably
+ /// borrowed punctuated pairs.
+ pub fn pairs_mut(&mut self) -> PairsMut<T, P> {
+ PairsMut {
+ inner: self.inner.iter_mut(),
+ last: self.last.as_mut().map(|t| t.as_mut()).into_iter(),
+ }
+ }
+
+ /// Returns an iterator over the contents of this sequence as owned
+ /// punctuated pairs.
+ pub fn into_pairs(self) -> IntoPairs<T, P> {
+ IntoPairs {
+ inner: self.inner.into_iter(),
+ last: self.last.map(|t| *t).into_iter(),
+ }
+ }
+
+ /// Appends a syntax tree node onto the end of this punctuated sequence. The
+ /// sequence must previously have a trailing punctuation.
+ ///
+ /// Use [`push`] instead if the punctuated sequence may or may not already
+ /// have trailing punctuation.
+ ///
+ /// [`push`]: #method.push
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence does not already have a trailing punctuation when
+ /// this method is called.
+ pub fn push_value(&mut self, value: T) {
+ assert!(self.empty_or_trailing());
+ self.last = Some(Box::new(value));
+ }
+
+ /// Appends a trailing punctuation onto the end of this punctuated sequence.
+ /// The sequence must be non-empty and must not already have trailing
+ /// punctuation.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the sequence is empty or already has a trailing punctuation.
+ pub fn push_punct(&mut self, punctuation: P) {
+ assert!(self.last.is_some());
+ let last = self.last.take().unwrap();
+ self.inner.push((*last, punctuation));
+ }
+
+ /// Removes the last punctuated pair from this sequence, or `None` if the
+ /// sequence is empty.
+ pub fn pop(&mut self) -> Option<Pair<T, P>> {
+ if self.last.is_some() {
+ self.last.take().map(|t| Pair::End(*t))
+ } else {
+ self.inner.pop().map(|(t, d)| Pair::Punctuated(t, d))
+ }
+ }
+
+ /// Determines whether this punctuated sequence ends with a trailing
+ /// punctuation.
+ pub fn trailing_punct(&self) -> bool {
+ self.last.is_none() && !self.is_empty()
+ }
+
+ /// Returns true if either this `Punctuated` is empty, or it has a trailing
+ /// punctuation.
+ ///
+ /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`.
+ pub fn empty_or_trailing(&self) -> bool {
+ self.last.is_none()
+ }
+}
+
+impl<T, P> Punctuated<T, P>
+where
+ P: Default,
+{
+ /// Appends a syntax tree node onto the end of this punctuated sequence.
+ ///
+ /// If there is not a trailing punctuation in this sequence when this method
+ /// is called, the default value of punctuation type `P` is inserted before
+ /// the given value of type `T`.
+ pub fn push(&mut self, value: T) {
+ if !self.empty_or_trailing() {
+ self.push_punct(Default::default());
+ }
+ self.push_value(value);
+ }
+
+ /// Inserts an element at position `index`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index` is greater than the number of elements previously in
+ /// this punctuated sequence.
+ pub fn insert(&mut self, index: usize, value: T) {
+ assert!(index <= self.len());
+
+ if index == self.len() {
+ self.push(value);
+ } else {
+ self.inner.insert(index, (value, Default::default()));
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<T: Debug, P: Debug> Debug for Punctuated<T, P> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut list = f.debug_list();
+ for &(ref t, ref p) in &self.inner {
+ list.entry(t);
+ list.entry(p);
+ }
+ if let Some(ref last) = self.last {
+ list.entry(last);
+ }
+ list.finish()
+ }
+}
+
+impl<T, P> FromIterator<T> for Punctuated<T, P>
+where
+ P: Default,
+{
+ fn from_iter<I: IntoIterator<Item = T>>(i: I) -> Self {
+ let mut ret = Punctuated::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, P> Extend<T> for Punctuated<T, P>
+where
+ P: Default,
+{
+ fn extend<I: IntoIterator<Item = T>>(&mut self, i: I) {
+ for value in i {
+ self.push(value);
+ }
+ }
+}
+
+impl<T, P> FromIterator<Pair<T, P>> for Punctuated<T, P> {
+ fn from_iter<I: IntoIterator<Item = Pair<T, P>>>(i: I) -> Self {
+ let mut ret = Punctuated::new();
+ ret.extend(i);
+ ret
+ }
+}
+
+impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P> {
+ fn extend<I: IntoIterator<Item = Pair<T, P>>>(&mut self, i: I) {
+ assert!(self.empty_or_trailing());
+ let mut nomore = false;
+ for pair in i {
+ if nomore {
+ panic!("Punctuated extended with items after a Pair::End");
+ }
+ match pair {
+ Pair::Punctuated(a, b) => self.inner.push((a, b)),
+ Pair::End(a) => {
+ self.last = Some(Box::new(a));
+ nomore = true;
+ }
+ }
+ }
+ }
+}
+
+impl<T, P> IntoIterator for Punctuated<T, P> {
+ type Item = T;
+ type IntoIter = IntoIter<T, P>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntoIter {
+ inner: self.inner.into_iter(),
+ last: self.last.map(|t| *t).into_iter(),
+ }
+ }
+}
+
+impl<'a, T, P> IntoIterator for &'a Punctuated<T, P> {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punctuated::iter(self)
+ }
+}
+
+impl<'a, T, P> IntoIterator for &'a mut Punctuated<T, P> {
+ type Item = &'a mut T;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punctuated::iter_mut(self)
+ }
+}
+
+impl<T, P> Default for Punctuated<T, P> {
+ fn default() -> Self {
+ Punctuated::new()
+ }
+}
+
+/// An iterator over borrowed pairs of type `Pair<&T, &P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct Pairs<'a, T: 'a, P: 'a> {
+ inner: slice::Iter<'a, (T, P)>,
+ last: option::IntoIter<&'a T>,
+}
+
+impl<'a, T, P> Iterator for Pairs<'a, T, P> {
+ type Item = Pair<&'a T, &'a P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|&(ref t, ref p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct PairsMut<'a, T: 'a, P: 'a> {
+ inner: slice::IterMut<'a, (T, P)>,
+ last: option::IntoIter<&'a mut T>,
+}
+
+impl<'a, T, P> Iterator for PairsMut<'a, T, P> {
+ type Item = Pair<&'a mut T, &'a mut P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|&mut (ref mut t, ref mut p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over owned pairs of type `Pair<T, P>`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct IntoPairs<T, P> {
+ inner: vec::IntoIter<(T, P)>,
+ last: option::IntoIter<T>,
+}
+
+impl<T, P> Iterator for IntoPairs<T, P> {
+ type Item = Pair<T, P>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|(t, p)| Pair::Punctuated(t, p))
+ .or_else(|| self.last.next().map(Pair::End))
+ }
+}
+
+impl<T, P> ExactSizeIterator for IntoPairs<T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over owned values of type `T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct IntoIter<T, P> {
+ inner: vec::IntoIter<(T, P)>,
+ last: option::IntoIter<T>,
+}
+
+impl<T, P> Iterator for IntoIter<T, P> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|pair| pair.0)
+ .or_else(|| self.last.next())
+ }
+}
+
+impl<T, P> ExactSizeIterator for IntoIter<T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over borrowed values of type `&T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct Iter<'a, T: 'a> {
+ inner: Box<ExactSizeIterator<Item = &'a T> + 'a>,
+}
+
+struct PrivateIter<'a, T: 'a, P: 'a> {
+ inner: slice::Iter<'a, (T, P)>,
+ last: option::IntoIter<&'a T>,
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl<'a, T> Iter<'a, T> {
+ // Not public API.
+ #[doc(hidden)]
+ pub fn private_empty() -> Self {
+ Iter {
+ inner: Box::new(iter::empty()),
+ }
+ }
+}
+
+impl<'a, T> Iterator for Iter<'a, T> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+}
+
+impl<'a, T> ExactSizeIterator for Iter<'a, T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+impl<'a, T, P> Iterator for PrivateIter<'a, T, P> {
+ type Item = &'a T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|pair| &pair.0)
+ .or_else(|| self.last.next())
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// An iterator over mutably borrowed values of type `&mut T`.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub struct IterMut<'a, T: 'a> {
+ inner: Box<ExactSizeIterator<Item = &'a mut T> + 'a>,
+}
+
+struct PrivateIterMut<'a, T: 'a, P: 'a> {
+ inner: slice::IterMut<'a, (T, P)>,
+ last: option::IntoIter<&'a mut T>,
+}
+
+#[cfg(any(feature = "full", feature = "derive"))]
+impl<'a, T> IterMut<'a, T> {
+ // Not public API.
+ #[doc(hidden)]
+ pub fn private_empty() -> Self {
+ IterMut {
+ inner: Box::new(iter::empty()),
+ }
+ }
+}
+
+impl<'a, T> Iterator for IterMut<'a, T> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+}
+
+impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+impl<'a, T, P> Iterator for PrivateIterMut<'a, T, P> {
+ type Item = &'a mut T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner
+ .next()
+ .map(|pair| &mut pair.0)
+ .or_else(|| self.last.next())
+ }
+}
+
+impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> {
+ fn len(&self) -> usize {
+ self.inner.len() + self.last.len()
+ }
+}
+
+/// A single syntax tree node of type `T` followed by its trailing punctuation
+/// of type `P` if any.
+///
+/// Refer to the [module documentation] for details about punctuated sequences.
+///
+/// [module documentation]: index.html
+pub enum Pair<T, P> {
+ Punctuated(T, P),
+ End(T),
+}
+
+impl<T, P> Pair<T, P> {
+ /// Extracts the syntax tree node from this punctuated pair, discarding the
+ /// following punctuation.
+ pub fn into_value(self) -> T {
+ match self {
+ Pair::Punctuated(t, _) | Pair::End(t) => t,
+ }
+ }
+
+ /// Borrows the syntax tree node from this punctuated pair.
+ pub fn value(&self) -> &T {
+ match *self {
+ Pair::Punctuated(ref t, _) | Pair::End(ref t) => t,
+ }
+ }
+
+ /// Mutably borrows the syntax tree node from this punctuated pair.
+ pub fn value_mut(&mut self) -> &mut T {
+ match *self {
+ Pair::Punctuated(ref mut t, _) | Pair::End(ref mut t) => t,
+ }
+ }
+
+ /// Borrows the punctuation from this punctuated pair, unless this pair is
+ /// the final one and there is no trailing punctuation.
+ pub fn punct(&self) -> Option<&P> {
+ match *self {
+ Pair::Punctuated(_, ref d) => Some(d),
+ Pair::End(_) => None,
+ }
+ }
+
+ /// Creates a punctuated pair out of a syntax tree node and an optional
+ /// following punctuation.
+ pub fn new(t: T, d: Option<P>) -> Self {
+ match d {
+ Some(d) => Pair::Punctuated(t, d),
+ None => Pair::End(t),
+ }
+ }
+
+ /// Produces this punctuated pair as a tuple of syntax tree node and
+ /// optional following punctuation.
+ pub fn into_tuple(self) -> (T, Option<P>) {
+ match self {
+ Pair::Punctuated(t, d) => (t, Some(d)),
+ Pair::End(t) => (t, None),
+ }
+ }
+}
+
+impl<T, P> Index<usize> for Punctuated<T, P> {
+ type Output = T;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ if index == self.len() - 1 {
+ match self.last {
+ Some(ref t) => t,
+ None => &self.inner[index].0,
+ }
+ } else {
+ &self.inner[index].0
+ }
+ }
+}
+
+impl<T, P> IndexMut<usize> for Punctuated<T, P> {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ if index == self.len() - 1 {
+ match self.last {
+ Some(ref mut t) => t,
+ None => &mut self.inner[index].0,
+ }
+ } else {
+ &mut self.inner[index].0
+ }
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl<T, P> Punctuated<T, P>
+where
+ T: Synom,
+ P: Synom,
+{
+ /// Parse **zero or more** syntax tree nodes with punctuation in between and
+ /// **no trailing** punctuation.
+ pub fn parse_separated(input: Cursor) -> PResult<Self> {
+ Self::parse_separated_with(input, T::parse)
+ }
+
+ /// Parse **one or more** syntax tree nodes with punctuation in bewteen and
+ /// **no trailing** punctuation.
+ /// allowing trailing punctuation.
+ pub fn parse_separated_nonempty(input: Cursor) -> PResult<Self> {
+ Self::parse_separated_nonempty_with(input, T::parse)
+ }
+
+ /// Parse **zero or more** syntax tree nodes with punctuation in between and
+ /// **optional trailing** punctuation.
+ pub fn parse_terminated(input: Cursor) -> PResult<Self> {
+ Self::parse_terminated_with(input, T::parse)
+ }
+
+ /// Parse **one or more** syntax tree nodes with punctuation in between and
+ /// **optional trailing** punctuation.
+ pub fn parse_terminated_nonempty(input: Cursor) -> PResult<Self> {
+ Self::parse_terminated_nonempty_with(input, T::parse)
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl<T, P> Punctuated<T, P>
+where
+ P: Synom,
+{
+ /// Parse **zero or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **no trailing** punctuation.
+ pub fn parse_separated_with(input: Cursor, parse: fn(Cursor) -> PResult<T>) -> PResult<Self> {
+ Self::parse(input, parse, false)
+ }
+
+ /// Parse **one or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **no trailing** punctuation.
+ pub fn parse_separated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ match Self::parse(input, parse, false) {
+ Ok((ref b, _)) if b.is_empty() => parse_error(),
+ other => other,
+ }
+ }
+
+ /// Parse **zero or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **optional trailing** punctuation.
+ pub fn parse_terminated_with(input: Cursor, parse: fn(Cursor) -> PResult<T>) -> PResult<Self> {
+ Self::parse(input, parse, true)
+ }
+
+ /// Parse **one or more** syntax tree nodes using the given parser with
+ /// punctuation in between and **optional trailing** punctuation.
+ pub fn parse_terminated_nonempty_with(
+ input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ ) -> PResult<Self> {
+ match Self::parse(input, parse, true) {
+ Ok((ref b, _)) if b.is_empty() => parse_error(),
+ other => other,
+ }
+ }
+
+ fn parse(
+ mut input: Cursor,
+ parse: fn(Cursor) -> PResult<T>,
+ terminated: bool,
+ ) -> PResult<Self> {
+ let mut res = Punctuated::new();
+
+ // get the first element
+ match parse(input) {
+ Err(_) => Ok((res, input)),
+ Ok((o, i)) => {
+ if i == input {
+ return parse_error();
+ }
+ input = i;
+ res.push_value(o);
+
+ // get the separator first
+ while let Ok((s, i2)) = P::parse(input) {
+ if i2 == input {
+ break;
+ }
+
+ // get the element next
+ if let Ok((o3, i3)) = parse(i2) {
+ if i3 == i2 {
+ break;
+ }
+ res.push_punct(s);
+ res.push_value(o3);
+ input = i3;
+ } else {
+ break;
+ }
+ }
+ if terminated {
+ if let Ok((sep, after)) = P::parse(input) {
+ res.push_punct(sep);
+ input = after;
+ }
+ }
+ Ok((res, input))
+ }
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::{ToTokens, TokenStreamExt};
+
+ impl<T, P> ToTokens for Punctuated<T, P>
+ where
+ T: ToTokens,
+ P: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(self.pairs())
+ }
+ }
+
+ impl<T, P> ToTokens for Pair<T, P>
+ where
+ T: ToTokens,
+ P: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ Pair::Punctuated(ref a, ref b) => {
+ a.to_tokens(tokens);
+ b.to_tokens(tokens);
+ }
+ Pair::End(ref a) => a.to_tokens(tokens),
+ }
+ }
+ }
+}
diff --git a/src/spanned.rs b/src/spanned.rs
new file mode 100644
index 0000000..6e2215d
--- /dev/null
+++ b/src/spanned.rs
@@ -0,0 +1,149 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A trait that can provide the `Span` of the complete contents of a syntax
+//! tree node.
+//!
+//! *This module is available if Syn is built with both the `"parsing"` and
+//! `"printing"` features.*
+//!
+//! # Example
+//!
+//! Suppose in a procedural macro we have a [`Type`] that we want to assert
+//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
+//! of a struct for which we are deriving a trait implementation, and we need to
+//! be able to pass a reference to one of those fields across threads.
+//!
+//! [`Type`]: ../enum.Type.html
+//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+//!
+//! If the field type does *not* implement `Sync` as required, we want the
+//! compiler to report an error pointing out exactly which type it was.
+//!
+//! The following macro code takes a variable `ty` of type `Type` and produces a
+//! static assertion that `Sync` is implemented for that type.
+//!
+//! ```
+//! #[macro_use]
+//! extern crate quote;
+//!
+//! extern crate syn;
+//! extern crate proc_macro;
+//! extern crate proc_macro2;
+//!
+//! use syn::Type;
+//! use syn::spanned::Spanned;
+//! use proc_macro::TokenStream;
+//! use proc_macro2::Span;
+//!
+//! # const IGNORE_TOKENS: &str = stringify! {
+//! #[proc_macro_derive(MyMacro)]
+//! # };
+//! pub fn my_macro(input: TokenStream) -> TokenStream {
+//! # let ty = get_a_type();
+//! /* ... */
+//!
+//! let assert_sync = quote_spanned! {ty.span()=>
+//! struct _AssertSync where #ty: Sync;
+//! };
+//!
+//! /* ... */
+//! # input
+//! }
+//! #
+//! # fn get_a_type() -> Type {
+//! # unimplemented!()
+//! # }
+//! #
+//! # fn main() {}
+//! ```
+//!
+//! By inserting this `assert_sync` fragment into the output code generated by
+//! our macro, the user's code will fail to compile if `ty` does not implement
+//! `Sync`. The errors they would see look like the following.
+//!
+//! ```text
+//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
+//! --> src/main.rs:10:21
+//! |
+//! 10 | bad_field: *const i32,
+//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
+//! ```
+//!
+//! In this technique, using the `Type`'s span for the error message makes the
+//! error appear in the correct place underlining the right type.
+
+use proc_macro2::{Span, TokenStream};
+use quote::ToTokens;
+
+/// A trait that can provide the `Span` of the complete contents of a syntax
+/// tree node.
+///
+/// This trait is automatically implemented for all types that implement
+/// [`ToTokens`] from the `quote` crate. It is sealed and cannot be implemented
+/// outside of the Syn crate other than by implementing `ToTokens`.
+///
+/// [`ToTokens`]: https://docs.rs/quote/0.4/quote/trait.ToTokens.html
+///
+/// See the [module documentation] for an example.
+///
+/// [module documentation]: index.html
+///
+/// *This trait is available if Syn is built with both the `"parsing"` and
+/// `"printing"` features.*
+pub trait Spanned: private::Sealed {
+ /// Returns a `Span` covering the complete contents of this syntax tree
+ /// node, or [`Span::call_site()`] if this node is empty.
+ ///
+ /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.2/proc_macro2/struct.Span.html#method.call_site
+ fn span(&self) -> Span;
+}
+
+mod private {
+ use quote::ToTokens;
+ pub trait Sealed {}
+ impl<T: ToTokens> Sealed for T {}
+}
+
+impl<T> Spanned for T
+where
+ T: ToTokens,
+{
+ #[cfg(procmacro2_semver_exempt)]
+ fn span(&self) -> Span {
+ let mut tokens = TokenStream::new();
+ self.to_tokens(&mut tokens);
+ let mut iter = tokens.into_iter();
+ let mut span = match iter.next() {
+ Some(tt) => tt.span(),
+ None => {
+ return Span::call_site();
+ }
+ };
+ for tt in iter {
+ if let Some(joined) = span.join(tt.span()) {
+ span = joined;
+ }
+ }
+ span
+ }
+
+ #[cfg(not(procmacro2_semver_exempt))]
+ fn span(&self) -> Span {
+ let mut tokens = TokenStream::new();
+ self.to_tokens(&mut tokens);
+ let mut iter = tokens.into_iter();
+
+ // We can't join spans without procmacro2_semver_exempt so just grab the
+ // first one.
+ match iter.next() {
+ Some(tt) => tt.span(),
+ None => Span::call_site(),
+ }
+ }
+}
diff --git a/src/synom.rs b/src/synom.rs
new file mode 100644
index 0000000..f3454eb
--- /dev/null
+++ b/src/synom.rs
@@ -0,0 +1,419 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Parsing interface for parsing a token stream into a syntax tree node.
+//!
+//! Parsing in Syn is built on parser functions that take in a [`Cursor`] and
+//! produce a [`PResult<T>`] where `T` is some syntax tree node. `Cursor` is a
+//! cheaply copyable cursor over a range of tokens in a token stream, and
+//! `PResult` is a result that packages together a parsed syntax tree node `T`
+//! with a stream of remaining unparsed tokens after `T` represented as another
+//! `Cursor`, or a [`ParseError`] if parsing failed.
+//!
+//! [`Cursor`]: ../buffer/index.html
+//! [`PResult<T>`]: type.PResult.html
+//! [`ParseError`]: struct.ParseError.html
+//!
+//! This `Cursor`- and `PResult`-based interface is convenient for parser
+//! combinators and parser implementations, but not necessarily when you just
+//! have some tokens that you want to parse. For that we expose the following
+//! two entry points.
+//!
+//! ## The `syn::parse*` functions
+//!
+//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve
+//! as an entry point for parsing syntax tree nodes that can be parsed in an
+//! obvious default way. These functions can return any syntax tree node that
+//! implements the [`Synom`] trait, which includes most types in Syn.
+//!
+//! [`syn::parse`]: ../fn.parse.html
+//! [`syn::parse2`]: ../fn.parse2.html
+//! [`syn::parse_str`]: ../fn.parse_str.html
+//! [`Synom`]: trait.Synom.html
+//!
+//! ```
+//! use syn::Type;
+//!
+//! # fn run_parser() -> Result<(), syn::synom::ParseError> {
+//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
+//! # Ok(())
+//! # }
+//! #
+//! # fn main() {
+//! # run_parser().unwrap();
+//! # }
+//! ```
+//!
+//! The [`parse_quote!`] macro also uses this approach.
+//!
+//! [`parse_quote!`]: ../macro.parse_quote.html
+//!
+//! ## The `Parser` trait
+//!
+//! Some types can be parsed in several ways depending on context. For example
+//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like
+//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`]
+//! may or may not allow trailing punctuation, and parsing it the wrong way
+//! would either reject valid input or accept invalid input.
+//!
+//! [`Attribute`]: ../struct.Attribute.html
+//! [`Punctuated`]: ../punctuated/index.html
+//!
+//! The `Synom` trait is not implemented in these cases because there is no good
+//! behavior to consider the default.
+//!
+//! ```ignore
+//! // Can't parse `Punctuated` without knowing whether trailing punctuation
+//! // should be allowed in this context.
+//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?;
+//! ```
+//!
+//! In these cases the types provide a choice of parser functions rather than a
+//! single `Synom` implementation, and those parser functions can be invoked
+//! through the [`Parser`] trait.
+//!
+//! [`Parser`]: trait.Parser.html
+//!
+//! ```
+//! # #[macro_use]
+//! # extern crate syn;
+//! #
+//! # extern crate proc_macro2;
+//! # use proc_macro2::TokenStream;
+//! #
+//! use syn::synom::Parser;
+//! use syn::punctuated::Punctuated;
+//! use syn::{PathSegment, Expr, Attribute};
+//!
+//! # fn run_parsers() -> Result<(), syn::synom::ParseError> {
+//! # let tokens = TokenStream::new().into();
+//! // Parse a nonempty sequence of path segments separated by `::` punctuation
+//! // with no trailing punctuation.
+//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty;
+//! let path = parser.parse(tokens)?;
+//!
+//! # let tokens = TokenStream::new().into();
+//! // Parse a possibly empty sequence of expressions terminated by commas with
+//! // an optional trailing punctuation.
+//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated;
+//! let args = parser.parse(tokens)?;
+//!
+//! # let tokens = TokenStream::new().into();
+//! // Parse zero or more outer attributes but not inner attributes.
+//! named!(outer_attrs -> Vec<Attribute>, many0!(Attribute::parse_outer));
+//! let attrs = outer_attrs.parse(tokens)?;
+//! #
+//! # Ok(())
+//! # }
+//! #
+//! # fn main() {}
+//! ```
+//!
+//! # Implementing a parser function
+//!
+//! Parser functions are usually implemented using the [`nom`]-style parser
+//! combinator macros provided by Syn, but may also be implemented without
+//! macros be using the low-level [`Cursor`] API directly.
+//!
+//! [`nom`]: https://github.com/Geal/nom
+//!
+//! The following parser combinator macros are available and a `Synom` parsing
+//! example is provided for each one.
+//!
+//! - [`alt!`](../macro.alt.html)
+//! - [`braces!`](../macro.braces.html)
+//! - [`brackets!`](../macro.brackets.html)
+//! - [`call!`](../macro.call.html)
+//! - [`cond!`](../macro.cond.html)
+//! - [`cond_reduce!`](../macro.cond_reduce.html)
+//! - [`custom_keyword!`](../macro.custom_keyword.html)
+//! - [`do_parse!`](../macro.do_parse.html)
+//! - [`epsilon!`](../macro.epsilon.html)
+//! - [`input_end!`](../macro.input_end.html)
+//! - [`keyword!`](../macro.keyword.html)
+//! - [`many0!`](../macro.many0.html)
+//! - [`map!`](../macro.map.html)
+//! - [`not!`](../macro.not.html)
+//! - [`option!`](../macro.option.html)
+//! - [`parens!`](../macro.parens.html)
+//! - [`punct!`](../macro.punct.html)
+//! - [`reject!`](../macro.reject.html)
+//! - [`switch!`](../macro.switch.html)
+//! - [`syn!`](../macro.syn.html)
+//! - [`tuple!`](../macro.tuple.html)
+//! - [`value!`](../macro.value.html)
+//!
+//! *This module is available if Syn is built with the `"parsing"` feature.*
+
+#[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+))]
+use proc_macro;
+use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, TokenStream, TokenTree};
+
+use error::parse_error;
+pub use error::{PResult, ParseError};
+
+use buffer::{Cursor, TokenBuffer};
+
+/// Parsing interface implemented by all types that can be parsed in a default
+/// way from a token stream.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: index.html
+///
+/// *This trait is available if Syn is built with the `"parsing"` feature.*
+pub trait Synom: Sized {
+ fn parse(input: Cursor) -> PResult<Self>;
+
+ /// A short name of the type being parsed.
+ ///
+ /// The description should only be used for a simple name. It should not
+ /// contain newlines or sentence-ending punctuation, to facilitate embedding in
+ /// larger user-facing strings. Syn will use this description when building
+ /// error messages about parse failures.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use syn::buffer::Cursor;
+ /// # use syn::synom::{Synom, PResult};
+ /// #
+ /// struct ExprMacro {
+ /// // ...
+ /// }
+ ///
+ /// impl Synom for ExprMacro {
+ /// # fn parse(input: Cursor) -> PResult<Self> { unimplemented!() }
+ /// // fn parse(...) -> ... { ... }
+ ///
+ /// fn description() -> Option<&'static str> {
+ /// // Will result in messages like
+ /// //
+ /// // "failed to parse macro invocation expression: $reason"
+ /// Some("macro invocation expression")
+ /// }
+ /// }
+ /// ```
+ fn description() -> Option<&'static str> {
+ None
+ }
+}
+
+impl Synom for TokenStream {
+ fn parse(input: Cursor) -> PResult<Self> {
+ Ok((input.token_stream(), Cursor::empty()))
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("arbitrary token stream")
+ }
+}
+
+impl Synom for TokenTree {
+ fn parse(input: Cursor) -> PResult<Self> {
+ match input.token_tree() {
+ Some((tt, rest)) => Ok((tt, rest)),
+ None => parse_error(),
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("token tree")
+ }
+}
+
+impl Synom for Group {
+ fn parse(input: Cursor) -> PResult<Self> {
+ for delim in &[Delimiter::Parenthesis, Delimiter::Brace, Delimiter::Bracket] {
+ if let Some((inside, span, rest)) = input.group(*delim) {
+ let mut group = Group::new(*delim, inside.token_stream());
+ group.set_span(span);
+ return Ok((group, rest));
+ }
+ }
+ parse_error()
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("group token")
+ }
+}
+
+impl Synom for Ident {
+ fn parse(input: Cursor) -> PResult<Self> {
+ let (ident, rest) = match input.ident() {
+ Some(ident) => ident,
+ _ => return parse_error(),
+ };
+ match &ident.to_string()[..] {
+ "_"
+ // Based on https://doc.rust-lang.org/grammar.html#keywords
+ // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md
+ | "abstract" | "as" | "become" | "box" | "break" | "const"
+ | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final"
+ | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match"
+ | "mod" | "move" | "mut" | "override" | "priv" | "proc" | "pub"
+ | "ref" | "return" | "Self" | "self" | "static" | "struct"
+ | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use"
+ | "virtual" | "where" | "while" | "yield" => return parse_error(),
+ _ => {}
+ }
+
+ Ok((ident, rest))
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("identifier")
+ }
+}
+
+impl Synom for Punct {
+ fn parse(input: Cursor) -> PResult<Self> {
+ match input.punct() {
+ Some((punct, rest)) => Ok((punct, rest)),
+ None => parse_error(),
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("punctuation token")
+ }
+}
+
+impl Synom for Literal {
+ fn parse(input: Cursor) -> PResult<Self> {
+ match input.literal() {
+ Some((literal, rest)) => Ok((literal, rest)),
+ None => parse_error(),
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("literal token")
+ }
+}
+
+/// Parser that can parse Rust tokens into a particular syntax tree node.
+///
+/// Refer to the [module documentation] for details about parsing in Syn.
+///
+/// [module documentation]: index.html
+///
+/// *This trait is available if Syn is built with the `"parsing"` feature.*
+pub trait Parser: Sized {
+ type Output;
+
+ /// Parse a proc-macro2 token stream into the chosen syntax tree node.
+ fn parse2(self, tokens: TokenStream) -> Result<Self::Output, ParseError>;
+
+ /// Parse tokens of source code into the chosen syntax tree node.
+ ///
+ /// *This method is available if Syn is built with both the `"parsing"` and
+ /// `"proc-macro"` features.*
+ #[cfg(all(
+ not(all(target_arch = "wasm32", target_os = "unknown")),
+ feature = "proc-macro"
+ ))]
+ fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output, ParseError> {
+ self.parse2(tokens.into())
+ }
+
+ /// Parse a string of Rust code into the chosen syntax tree node.
+ ///
+ /// # Hygiene
+ ///
+ /// Every span in the resulting syntax tree will be set to resolve at the
+ /// macro call site.
+ fn parse_str(self, s: &str) -> Result<Self::Output, ParseError> {
+ match s.parse() {
+ Ok(tts) => self.parse2(tts),
+ Err(_) => Err(ParseError::new("error while lexing input string")),
+ }
+ }
+}
+
+impl<F, T> Parser for F
+where
+ F: FnOnce(Cursor) -> PResult<T>,
+{
+ type Output = T;
+
+ fn parse2(self, tokens: TokenStream) -> Result<T, ParseError> {
+ let buf = TokenBuffer::new2(tokens);
+ let (t, rest) = self(buf.begin())?;
+ if rest.eof() {
+ Ok(t)
+ } else if rest == buf.begin() {
+ // parsed nothing
+ Err(ParseError::new("failed to parse anything"))
+ } else {
+ Err(ParseError::new("failed to parse all tokens"))
+ }
+ }
+}
+
+/// Extension traits that are made available within the `call!` parser.
+///
+/// *This module is available if Syn is built with the `"parsing"` feature.*
+pub mod ext {
+ use super::*;
+ use proc_macro2::Ident;
+
+ /// Additional parsing methods for `Ident`.
+ ///
+ /// This trait is sealed and cannot be implemented for types outside of Syn.
+ ///
+ /// *This trait is available if Syn is built with the `"parsing"` feature.*
+ pub trait IdentExt: Sized + private::Sealed {
+ /// Parses any identifier including keywords.
+ ///
+ /// This is useful when parsing a DSL which allows Rust keywords as
+ /// identifiers.
+ ///
+ /// ```rust
+ /// #[macro_use]
+ /// extern crate syn;
+ ///
+ /// use syn::Ident;
+ ///
+ /// // Parses input that looks like `name = NAME` where `NAME` can be
+ /// // any identifier.
+ /// //
+ /// // Examples:
+ /// //
+ /// // name = anything
+ /// // name = impl
+ /// named!(parse_dsl -> Ident, do_parse!(
+ /// custom_keyword!(name) >>
+ /// punct!(=) >>
+ /// name: call!(Ident::parse_any) >>
+ /// (name)
+ /// ));
+ /// #
+ /// # fn main() {}
+ /// ```
+ fn parse_any(input: Cursor) -> PResult<Self>;
+ }
+
+ impl IdentExt for Ident {
+ fn parse_any(input: Cursor) -> PResult<Self> {
+ input.ident().map_or_else(parse_error, Ok)
+ }
+ }
+
+ mod private {
+ use proc_macro2::Ident;
+
+ pub trait Sealed {}
+
+ impl Sealed for Ident {}
+ }
+}
diff --git a/src/token.rs b/src/token.rs
new file mode 100644
index 0000000..4ec3743
--- /dev/null
+++ b/src/token.rs
@@ -0,0 +1,955 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Tokens representing Rust punctuation, keywords, and delimiters.
+//!
+//! The type names in this module can be difficult to keep straight, so we
+//! prefer to use the [`Token!`] macro instead. This is a type-macro that
+//! expands to the token type of the given token.
+//!
+//! [`Token!`]: ../macro.Token.html
+//!
+//! # Example
+//!
+//! The [`ItemStatic`] syntax tree node is defined like this.
+//!
+//! [`ItemStatic`]: ../struct.ItemStatic.html
+//!
+//! ```
+//! # #[macro_use]
+//! # extern crate syn;
+//! #
+//! # use syn::{Attribute, Visibility, Ident, Type, Expr};
+//! #
+//! pub struct ItemStatic {
+//! pub attrs: Vec<Attribute>,
+//! pub vis: Visibility,
+//! pub static_token: Token![static],
+//! pub mutability: Option<Token![mut]>,
+//! pub ident: Ident,
+//! pub colon_token: Token![:],
+//! pub ty: Box<Type>,
+//! pub eq_token: Token![=],
+//! pub expr: Box<Expr>,
+//! pub semi_token: Token![;],
+//! }
+//! #
+//! # fn main() {}
+//! ```
+//!
+//! # Parsing
+//!
+//! These tokens can be parsed using the [`Synom`] trait and the parser
+//! combinator macros [`punct!`], [`keyword!`], [`parens!`], [`braces!`], and
+//! [`brackets!`].
+//!
+//! [`Synom`]: ../synom/trait.Synom.html
+//! [`punct!`]: ../macro.punct.html
+//! [`keyword!`]: ../macro.keyword.html
+//! [`parens!`]: ../macro.parens.html
+//! [`braces!`]: ../macro.braces.html
+//! [`brackets!`]: ../macro.brackets.html
+//!
+//! ```
+//! #[macro_use]
+//! extern crate syn;
+//!
+//! use syn::synom::Synom;
+//! use syn::{Attribute, Visibility, Ident, Type, Expr};
+//! #
+//! # struct ItemStatic;
+//! # use syn::ItemStatic as SynItemStatic;
+//!
+//! // Parse the ItemStatic struct shown above.
+//! impl Synom for ItemStatic {
+//! named!(parse -> Self, do_parse!(
+//! # (ItemStatic)
+//! # ));
+//! # }
+//! #
+//! # mod example {
+//! # use super::*;
+//! # use super::SynItemStatic as ItemStatic;
+//! #
+//! # named!(parse -> ItemStatic, do_parse!(
+//! attrs: many0!(Attribute::parse_outer) >>
+//! vis: syn!(Visibility) >>
+//! static_token: keyword!(static) >>
+//! mutability: option!(keyword!(mut)) >>
+//! ident: syn!(Ident) >>
+//! colon_token: punct!(:) >>
+//! ty: syn!(Type) >>
+//! eq_token: punct!(=) >>
+//! expr: syn!(Expr) >>
+//! semi_token: punct!(;) >>
+//! (ItemStatic {
+//! attrs, vis, static_token, mutability, ident, colon_token,
+//! ty: Box::new(ty), eq_token, expr: Box::new(expr), semi_token,
+//! })
+//! ));
+//! }
+//! #
+//! # fn main() {}
+//! ```
+
+use proc_macro2::{Ident, Span};
+
+macro_rules! tokens {
+ (
+ punct: {
+ $($punct:tt pub struct $punct_name:ident/$len:tt #[$punct_doc:meta])*
+ }
+ delimiter: {
+ $($delimiter:tt pub struct $delimiter_name:ident #[$delimiter_doc:meta])*
+ }
+ keyword: {
+ $($keyword:tt pub struct $keyword_name:ident #[$keyword_doc:meta])*
+ }
+ ) => (
+ $(token_punct_def! { #[$punct_doc] pub struct $punct_name/$len })*
+ $(token_punct_parser! { $punct pub struct $punct_name/$len })*
+ $(token_delimiter! { #[$delimiter_doc] $delimiter pub struct $delimiter_name })*
+ $(token_keyword! { #[$keyword_doc] $keyword pub struct $keyword_name })*
+ )
+}
+
+macro_rules! token_punct_def {
+ (#[$doc:meta]pub struct $name:ident / $len:tt) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[$doc]
+ ///
+ /// Don't try to remember the name of this type -- use the [`Token!`]
+ /// macro instead.
+ ///
+ /// [`Token!`]: index.html
+ pub struct $name {
+ pub spans: [Span; $len],
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name {
+ $name {
+ spans: spans.into_spans(),
+ }
+ }
+
+ impl ::std::default::Default for $name {
+ fn default() -> Self {
+ $name([Span::call_site(); $len])
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::fmt::Debug for $name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::hash::Hash for $name {
+ fn hash<H>(&self, _state: &mut H)
+ where
+ H: ::std::hash::Hasher,
+ {
+ }
+ }
+
+ impl From<Span> for $name {
+ fn from(span: Span) -> Self {
+ $name([span; $len])
+ }
+ }
+ };
+}
+
+macro_rules! token_punct_parser {
+ ($s:tt pub struct $name:ident/$len:tt) => {
+ #[cfg(feature = "printing")]
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
+ printing::punct($s, &self.spans, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl ::Synom for $name {
+ fn parse(tokens: $crate::buffer::Cursor) -> $crate::synom::PResult<$name> {
+ parsing::punct($s, tokens, $name::<[Span; $len]>)
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(concat!("`", $s, "`"))
+ }
+ }
+ };
+}
+
+macro_rules! token_keyword {
+ (#[$doc:meta] $s:tt pub struct $name:ident) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[$doc]
+ ///
+ /// Don't try to remember the name of this type -- use the [`Token!`]
+ /// macro instead.
+ ///
+ /// [`Token!`]: index.html
+ pub struct $name {
+ pub span: Span,
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
+ $name {
+ span: span.into_spans()[0],
+ }
+ }
+
+ impl ::std::default::Default for $name {
+ fn default() -> Self {
+ $name(Span::call_site())
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::fmt::Debug for $name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::hash::Hash for $name {
+ fn hash<H>(&self, _state: &mut H)
+ where
+ H: ::std::hash::Hasher,
+ {
+ }
+ }
+
+ #[cfg(feature = "printing")]
+ impl ::quote::ToTokens for $name {
+ fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
+ printing::keyword($s, &self.span, tokens);
+ }
+ }
+
+ #[cfg(feature = "parsing")]
+ impl ::Synom for $name {
+ fn parse(tokens: $crate::buffer::Cursor) -> $crate::synom::PResult<$name> {
+ parsing::keyword($s, tokens, $name)
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(concat!("`", $s, "`"))
+ }
+ }
+
+ impl From<Span> for $name {
+ fn from(span: Span) -> Self {
+ $name(span)
+ }
+ }
+ };
+}
+
+macro_rules! token_delimiter {
+ (#[$doc:meta] $s:tt pub struct $name:ident) => {
+ #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))]
+ #[$doc]
+ pub struct $name {
+ pub span: Span,
+ }
+
+ #[doc(hidden)]
+ #[allow(non_snake_case)]
+ pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
+ $name {
+ span: span.into_spans()[0],
+ }
+ }
+
+ impl ::std::default::Default for $name {
+ fn default() -> Self {
+ $name(Span::call_site())
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::fmt::Debug for $name {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ f.write_str(stringify!($name))
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::Eq for $name {}
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::cmp::PartialEq for $name {
+ fn eq(&self, _other: &$name) -> bool {
+ true
+ }
+ }
+
+ #[cfg(feature = "extra-traits")]
+ impl ::std::hash::Hash for $name {
+ fn hash<H>(&self, _state: &mut H)
+ where
+ H: ::std::hash::Hasher,
+ {
+ }
+ }
+
+ impl $name {
+ #[cfg(feature = "printing")]
+ pub fn surround<F>(&self, tokens: &mut ::proc_macro2::TokenStream, f: F)
+ where
+ F: FnOnce(&mut ::proc_macro2::TokenStream),
+ {
+ printing::delim($s, &self.span, tokens, f);
+ }
+
+ #[cfg(feature = "parsing")]
+ pub fn parse<F, R>(
+ tokens: $crate::buffer::Cursor,
+ f: F,
+ ) -> $crate::synom::PResult<($name, R)>
+ where
+ F: FnOnce($crate::buffer::Cursor) -> $crate::synom::PResult<R>,
+ {
+ parsing::delim($s, tokens, $name, f)
+ }
+ }
+
+ impl From<Span> for $name {
+ fn from(span: Span) -> Self {
+ $name(span)
+ }
+ }
+ };
+}
+
+token_punct_def! {
+ /// `_`
+ pub struct Underscore/1
+}
+
+#[cfg(feature = "printing")]
+impl ::quote::ToTokens for Underscore {
+ fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
+ use quote::TokenStreamExt;
+ tokens.append(::proc_macro2::Ident::new("_", self.spans[0]));
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl ::Synom for Underscore {
+ fn parse(input: ::buffer::Cursor) -> ::synom::PResult<Underscore> {
+ match input.ident() {
+ Some((ident, rest)) => {
+ if ident == "_" {
+ Ok((Underscore([ident.span()]), rest))
+ } else {
+ ::parse_error()
+ }
+ }
+ None => parsing::punct("_", input, Underscore::<[Span; 1]>),
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("`_`")
+ }
+}
+
+token_punct_def! {
+ /// `'`
+ pub struct Apostrophe/1
+}
+
+// Implement Clone anyway because it is required for cloning Lifetime.
+#[cfg(not(feature = "clone-impls"))]
+impl Clone for Apostrophe {
+ fn clone(&self) -> Self {
+ Apostrophe(self.spans)
+ }
+}
+
+#[cfg(feature = "printing")]
+impl ::quote::ToTokens for Apostrophe {
+ fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
+ use quote::TokenStreamExt;
+ let mut token = ::proc_macro2::Punct::new('\'', ::proc_macro2::Spacing::Joint);
+ token.set_span(self.spans[0]);
+ tokens.append(token);
+ }
+}
+
+#[cfg(feature = "parsing")]
+impl ::Synom for Apostrophe {
+ fn parse(input: ::buffer::Cursor) -> ::synom::PResult<Apostrophe> {
+ match input.punct() {
+ Some((op, rest)) => {
+ if op.as_char() == '\'' && op.spacing() == ::proc_macro2::Spacing::Joint {
+ Ok((Apostrophe([op.span()]), rest))
+ } else {
+ ::parse_error()
+ }
+ }
+ None => ::parse_error(),
+ }
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("`'`")
+ }
+}
+
+tokens! {
+ punct: {
+ "+" pub struct Add/1 /// `+`
+ "+=" pub struct AddEq/2 /// `+=`
+ "&" pub struct And/1 /// `&`
+ "&&" pub struct AndAnd/2 /// `&&`
+ "&=" pub struct AndEq/2 /// `&=`
+ "@" pub struct At/1 /// `@`
+ "!" pub struct Bang/1 /// `!`
+ "^" pub struct Caret/1 /// `^`
+ "^=" pub struct CaretEq/2 /// `^=`
+ ":" pub struct Colon/1 /// `:`
+ "::" pub struct Colon2/2 /// `::`
+ "," pub struct Comma/1 /// `,`
+ "/" pub struct Div/1 /// `/`
+ "/=" pub struct DivEq/2 /// `/=`
+ "$" pub struct Dollar/1 /// `$`
+ "." pub struct Dot/1 /// `.`
+ ".." pub struct Dot2/2 /// `..`
+ "..." pub struct Dot3/3 /// `...`
+ "..=" pub struct DotDotEq/3 /// `..=`
+ "=" pub struct Eq/1 /// `=`
+ "==" pub struct EqEq/2 /// `==`
+ ">=" pub struct Ge/2 /// `>=`
+ ">" pub struct Gt/1 /// `>`
+ "<=" pub struct Le/2 /// `<=`
+ "<" pub struct Lt/1 /// `<`
+ "*=" pub struct MulEq/2 /// `*=`
+ "!=" pub struct Ne/2 /// `!=`
+ "|" pub struct Or/1 /// `|`
+ "|=" pub struct OrEq/2 /// `|=`
+ "||" pub struct OrOr/2 /// `||`
+ "#" pub struct Pound/1 /// `#`
+ "?" pub struct Question/1 /// `?`
+ "->" pub struct RArrow/2 /// `->`
+ "<-" pub struct LArrow/2 /// `<-`
+ "%" pub struct Rem/1 /// `%`
+ "%=" pub struct RemEq/2 /// `%=`
+ "=>" pub struct FatArrow/2 /// `=>`
+ ";" pub struct Semi/1 /// `;`
+ "<<" pub struct Shl/2 /// `<<`
+ "<<=" pub struct ShlEq/3 /// `<<=`
+ ">>" pub struct Shr/2 /// `>>`
+ ">>=" pub struct ShrEq/3 /// `>>=`
+ "*" pub struct Star/1 /// `*`
+ "-" pub struct Sub/1 /// `-`
+ "-=" pub struct SubEq/2 /// `-=`
+ }
+ delimiter: {
+ "{" pub struct Brace /// `{...}`
+ "[" pub struct Bracket /// `[...]`
+ "(" pub struct Paren /// `(...)`
+ " " pub struct Group /// None-delimited group
+ }
+ keyword: {
+ "as" pub struct As /// `as`
+ "async" pub struct Async /// `async`
+ "auto" pub struct Auto /// `auto`
+ "box" pub struct Box /// `box`
+ "break" pub struct Break /// `break`
+ "Self" pub struct CapSelf /// `Self`
+ "const" pub struct Const /// `const`
+ "continue" pub struct Continue /// `continue`
+ "crate" pub struct Crate /// `crate`
+ "default" pub struct Default /// `default`
+ "dyn" pub struct Dyn /// `dyn`
+ "else" pub struct Else /// `else`
+ "enum" pub struct Enum /// `enum`
+ "existential" pub struct Existential /// `existential`
+ "extern" pub struct Extern /// `extern`
+ "fn" pub struct Fn /// `fn`
+ "for" pub struct For /// `for`
+ "if" pub struct If /// `if`
+ "impl" pub struct Impl /// `impl`
+ "in" pub struct In /// `in`
+ "let" pub struct Let /// `let`
+ "loop" pub struct Loop /// `loop`
+ "macro" pub struct Macro /// `macro`
+ "match" pub struct Match /// `match`
+ "mod" pub struct Mod /// `mod`
+ "move" pub struct Move /// `move`
+ "mut" pub struct Mut /// `mut`
+ "pub" pub struct Pub /// `pub`
+ "ref" pub struct Ref /// `ref`
+ "return" pub struct Return /// `return`
+ "self" pub struct Self_ /// `self`
+ "static" pub struct Static /// `static`
+ "struct" pub struct Struct /// `struct`
+ "super" pub struct Super /// `super`
+ "trait" pub struct Trait /// `trait`
+ "try" pub struct Try /// `try`
+ "type" pub struct Type /// `type`
+ "union" pub struct Union /// `union`
+ "unsafe" pub struct Unsafe /// `unsafe`
+ "use" pub struct Use /// `use`
+ "where" pub struct Where /// `where`
+ "while" pub struct While /// `while`
+ "yield" pub struct Yield /// `yield`
+ }
+}
+
+/// A type-macro that expands to the name of the Rust type representation of a
+/// given token.
+///
+/// See the [token module] documentation for details and examples.
+///
+/// [token module]: token/index.html
+// Unfortunate duplication due to a rustdoc bug.
+// https://github.com/rust-lang/rust/issues/45939
+#[macro_export]
+#[cfg_attr(rustfmt, rustfmt_skip)]
+macro_rules! Token {
+ (+) => { $crate::token::Add };
+ (+=) => { $crate::token::AddEq };
+ (&) => { $crate::token::And };
+ (&&) => { $crate::token::AndAnd };
+ (&=) => { $crate::token::AndEq };
+ (@) => { $crate::token::At };
+ (!) => { $crate::token::Bang };
+ (^) => { $crate::token::Caret };
+ (^=) => { $crate::token::CaretEq };
+ (:) => { $crate::token::Colon };
+ (::) => { $crate::token::Colon2 };
+ (,) => { $crate::token::Comma };
+ (/) => { $crate::token::Div };
+ (/=) => { $crate::token::DivEq };
+ (.) => { $crate::token::Dot };
+ (..) => { $crate::token::Dot2 };
+ (...) => { $crate::token::Dot3 };
+ (..=) => { $crate::token::DotDotEq };
+ (=) => { $crate::token::Eq };
+ (==) => { $crate::token::EqEq };
+ (>=) => { $crate::token::Ge };
+ (>) => { $crate::token::Gt };
+ (<=) => { $crate::token::Le };
+ (<) => { $crate::token::Lt };
+ (*=) => { $crate::token::MulEq };
+ (!=) => { $crate::token::Ne };
+ (|) => { $crate::token::Or };
+ (|=) => { $crate::token::OrEq };
+ (||) => { $crate::token::OrOr };
+ (#) => { $crate::token::Pound };
+ (?) => { $crate::token::Question };
+ (->) => { $crate::token::RArrow };
+ (<-) => { $crate::token::LArrow };
+ (%) => { $crate::token::Rem };
+ (%=) => { $crate::token::RemEq };
+ (=>) => { $crate::token::FatArrow };
+ (;) => { $crate::token::Semi };
+ (<<) => { $crate::token::Shl };
+ (<<=) => { $crate::token::ShlEq };
+ (>>) => { $crate::token::Shr };
+ (>>=) => { $crate::token::ShrEq };
+ (*) => { $crate::token::Star };
+ (-) => { $crate::token::Sub };
+ (-=) => { $crate::token::SubEq };
+ (_) => { $crate::token::Underscore };
+ (as) => { $crate::token::As };
+ (async) => { $crate::token::Async };
+ (auto) => { $crate::token::Auto };
+ (box) => { $crate::token::Box };
+ (break) => { $crate::token::Break };
+ (Self) => { $crate::token::CapSelf };
+ (const) => { $crate::token::Const };
+ (continue) => { $crate::token::Continue };
+ (crate) => { $crate::token::Crate };
+ (default) => { $crate::token::Default };
+ (dyn) => { $crate::token::Dyn };
+ (else) => { $crate::token::Else };
+ (enum) => { $crate::token::Enum };
+ (existential) => { $crate::token::Existential };
+ (extern) => { $crate::token::Extern };
+ (fn) => { $crate::token::Fn };
+ (for) => { $crate::token::For };
+ (if) => { $crate::token::If };
+ (impl) => { $crate::token::Impl };
+ (in) => { $crate::token::In };
+ (let) => { $crate::token::Let };
+ (loop) => { $crate::token::Loop };
+ (macro) => { $crate::token::Macro };
+ (match) => { $crate::token::Match };
+ (mod) => { $crate::token::Mod };
+ (move) => { $crate::token::Move };
+ (mut) => { $crate::token::Mut };
+ (pub) => { $crate::token::Pub };
+ (ref) => { $crate::token::Ref };
+ (return) => { $crate::token::Return };
+ (self) => { $crate::token::Self_ };
+ (static) => { $crate::token::Static };
+ (struct) => { $crate::token::Struct };
+ (super) => { $crate::token::Super };
+ (trait) => { $crate::token::Trait };
+ (try) => { $crate::token::Try };
+ (type) => { $crate::token::Type };
+ (union) => { $crate::token::Union };
+ (unsafe) => { $crate::token::Unsafe };
+ (use) => { $crate::token::Use };
+ (where) => { $crate::token::Where };
+ (while) => { $crate::token::While };
+ (yield) => { $crate::token::Yield };
+}
+
+/// Parse a single Rust punctuation token.
+///
+/// See the [token module] documentation for details and examples.
+///
+/// [token module]: token/index.html
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[cfg(feature = "parsing")]
+#[macro_export]
+#[cfg_attr(rustfmt, rustfmt_skip)]
+macro_rules! punct {
+ ($i:expr, +) => { call!($i, <$crate::token::Add as $crate::synom::Synom>::parse) };
+ ($i:expr, +=) => { call!($i, <$crate::token::AddEq as $crate::synom::Synom>::parse) };
+ ($i:expr, &) => { call!($i, <$crate::token::And as $crate::synom::Synom>::parse) };
+ ($i:expr, &&) => { call!($i, <$crate::token::AndAnd as $crate::synom::Synom>::parse) };
+ ($i:expr, &=) => { call!($i, <$crate::token::AndEq as $crate::synom::Synom>::parse) };
+ ($i:expr, @) => { call!($i, <$crate::token::At as $crate::synom::Synom>::parse) };
+ ($i:expr, !) => { call!($i, <$crate::token::Bang as $crate::synom::Synom>::parse) };
+ ($i:expr, ^) => { call!($i, <$crate::token::Caret as $crate::synom::Synom>::parse) };
+ ($i:expr, ^=) => { call!($i, <$crate::token::CaretEq as $crate::synom::Synom>::parse) };
+ ($i:expr, :) => { call!($i, <$crate::token::Colon as $crate::synom::Synom>::parse) };
+ ($i:expr, ::) => { call!($i, <$crate::token::Colon2 as $crate::synom::Synom>::parse) };
+ ($i:expr, ,) => { call!($i, <$crate::token::Comma as $crate::synom::Synom>::parse) };
+ ($i:expr, /) => { call!($i, <$crate::token::Div as $crate::synom::Synom>::parse) };
+ ($i:expr, /=) => { call!($i, <$crate::token::DivEq as $crate::synom::Synom>::parse) };
+ ($i:expr, .) => { call!($i, <$crate::token::Dot as $crate::synom::Synom>::parse) };
+ ($i:expr, ..) => { call!($i, <$crate::token::Dot2 as $crate::synom::Synom>::parse) };
+ ($i:expr, ...) => { call!($i, <$crate::token::Dot3 as $crate::synom::Synom>::parse) };
+ ($i:expr, ..=) => { call!($i, <$crate::token::DotDotEq as $crate::synom::Synom>::parse) };
+ ($i:expr, =) => { call!($i, <$crate::token::Eq as $crate::synom::Synom>::parse) };
+ ($i:expr, ==) => { call!($i, <$crate::token::EqEq as $crate::synom::Synom>::parse) };
+ ($i:expr, >=) => { call!($i, <$crate::token::Ge as $crate::synom::Synom>::parse) };
+ ($i:expr, >) => { call!($i, <$crate::token::Gt as $crate::synom::Synom>::parse) };
+ ($i:expr, <=) => { call!($i, <$crate::token::Le as $crate::synom::Synom>::parse) };
+ ($i:expr, <) => { call!($i, <$crate::token::Lt as $crate::synom::Synom>::parse) };
+ ($i:expr, *=) => { call!($i, <$crate::token::MulEq as $crate::synom::Synom>::parse) };
+ ($i:expr, !=) => { call!($i, <$crate::token::Ne as $crate::synom::Synom>::parse) };
+ ($i:expr, |) => { call!($i, <$crate::token::Or as $crate::synom::Synom>::parse) };
+ ($i:expr, |=) => { call!($i, <$crate::token::OrEq as $crate::synom::Synom>::parse) };
+ ($i:expr, ||) => { call!($i, <$crate::token::OrOr as $crate::synom::Synom>::parse) };
+ ($i:expr, #) => { call!($i, <$crate::token::Pound as $crate::synom::Synom>::parse) };
+ ($i:expr, ?) => { call!($i, <$crate::token::Question as $crate::synom::Synom>::parse) };
+ ($i:expr, ->) => { call!($i, <$crate::token::RArrow as $crate::synom::Synom>::parse) };
+ ($i:expr, <-) => { call!($i, <$crate::token::LArrow as $crate::synom::Synom>::parse) };
+ ($i:expr, %) => { call!($i, <$crate::token::Rem as $crate::synom::Synom>::parse) };
+ ($i:expr, %=) => { call!($i, <$crate::token::RemEq as $crate::synom::Synom>::parse) };
+ ($i:expr, =>) => { call!($i, <$crate::token::FatArrow as $crate::synom::Synom>::parse) };
+ ($i:expr, ;) => { call!($i, <$crate::token::Semi as $crate::synom::Synom>::parse) };
+ ($i:expr, <<) => { call!($i, <$crate::token::Shl as $crate::synom::Synom>::parse) };
+ ($i:expr, <<=) => { call!($i, <$crate::token::ShlEq as $crate::synom::Synom>::parse) };
+ ($i:expr, >>) => { call!($i, <$crate::token::Shr as $crate::synom::Synom>::parse) };
+ ($i:expr, >>=) => { call!($i, <$crate::token::ShrEq as $crate::synom::Synom>::parse) };
+ ($i:expr, *) => { call!($i, <$crate::token::Star as $crate::synom::Synom>::parse) };
+ ($i:expr, -) => { call!($i, <$crate::token::Sub as $crate::synom::Synom>::parse) };
+ ($i:expr, -=) => { call!($i, <$crate::token::SubEq as $crate::synom::Synom>::parse) };
+ ($i:expr, _) => { call!($i, <$crate::token::Underscore as $crate::synom::Synom>::parse) };
+}
+
+/// Parse a single Rust keyword token.
+///
+/// See the [token module] documentation for details and examples.
+///
+/// [token module]: token/index.html
+///
+/// *This macro is available if Syn is built with the `"parsing"` feature.*
+#[cfg(feature = "parsing")]
+#[macro_export]
+#[cfg_attr(rustfmt, rustfmt_skip)]
+macro_rules! keyword {
+ ($i:expr, as) => { call!($i, <$crate::token::As as $crate::synom::Synom>::parse) };
+ ($i:expr, async) => { call!($i, <$crate::token::Async as $crate::synom::Synom>::parse) };
+ ($i:expr, auto) => { call!($i, <$crate::token::Auto as $crate::synom::Synom>::parse) };
+ ($i:expr, box) => { call!($i, <$crate::token::Box as $crate::synom::Synom>::parse) };
+ ($i:expr, break) => { call!($i, <$crate::token::Break as $crate::synom::Synom>::parse) };
+ ($i:expr, Self) => { call!($i, <$crate::token::CapSelf as $crate::synom::Synom>::parse) };
+ ($i:expr, const) => { call!($i, <$crate::token::Const as $crate::synom::Synom>::parse) };
+ ($i:expr, continue) => { call!($i, <$crate::token::Continue as $crate::synom::Synom>::parse) };
+ ($i:expr, crate) => { call!($i, <$crate::token::Crate as $crate::synom::Synom>::parse) };
+ ($i:expr, default) => { call!($i, <$crate::token::Default as $crate::synom::Synom>::parse) };
+ ($i:expr, dyn) => { call!($i, <$crate::token::Dyn as $crate::synom::Synom>::parse) };
+ ($i:expr, else) => { call!($i, <$crate::token::Else as $crate::synom::Synom>::parse) };
+ ($i:expr, enum) => { call!($i, <$crate::token::Enum as $crate::synom::Synom>::parse) };
+ ($i:expr, extern) => { call!($i, <$crate::token::Extern as $crate::synom::Synom>::parse) };
+ ($i:expr, existential) => { call!($i, <$crate::token::Existential as $crate::synom::Synom>::parse) };
+ ($i:expr, fn) => { call!($i, <$crate::token::Fn as $crate::synom::Synom>::parse) };
+ ($i:expr, for) => { call!($i, <$crate::token::For as $crate::synom::Synom>::parse) };
+ ($i:expr, if) => { call!($i, <$crate::token::If as $crate::synom::Synom>::parse) };
+ ($i:expr, impl) => { call!($i, <$crate::token::Impl as $crate::synom::Synom>::parse) };
+ ($i:expr, in) => { call!($i, <$crate::token::In as $crate::synom::Synom>::parse) };
+ ($i:expr, let) => { call!($i, <$crate::token::Let as $crate::synom::Synom>::parse) };
+ ($i:expr, loop) => { call!($i, <$crate::token::Loop as $crate::synom::Synom>::parse) };
+ ($i:expr, macro) => { call!($i, <$crate::token::Macro as $crate::synom::Synom>::parse) };
+ ($i:expr, match) => { call!($i, <$crate::token::Match as $crate::synom::Synom>::parse) };
+ ($i:expr, mod) => { call!($i, <$crate::token::Mod as $crate::synom::Synom>::parse) };
+ ($i:expr, move) => { call!($i, <$crate::token::Move as $crate::synom::Synom>::parse) };
+ ($i:expr, mut) => { call!($i, <$crate::token::Mut as $crate::synom::Synom>::parse) };
+ ($i:expr, pub) => { call!($i, <$crate::token::Pub as $crate::synom::Synom>::parse) };
+ ($i:expr, ref) => { call!($i, <$crate::token::Ref as $crate::synom::Synom>::parse) };
+ ($i:expr, return) => { call!($i, <$crate::token::Return as $crate::synom::Synom>::parse) };
+ ($i:expr, self) => { call!($i, <$crate::token::Self_ as $crate::synom::Synom>::parse) };
+ ($i:expr, static) => { call!($i, <$crate::token::Static as $crate::synom::Synom>::parse) };
+ ($i:expr, struct) => { call!($i, <$crate::token::Struct as $crate::synom::Synom>::parse) };
+ ($i:expr, super) => { call!($i, <$crate::token::Super as $crate::synom::Synom>::parse) };
+ ($i:expr, trait) => { call!($i, <$crate::token::Trait as $crate::synom::Synom>::parse) };
+ ($i:expr, try) => { call!($i, <$crate::token::Try as $crate::synom::Synom>::parse) };
+ ($i:expr, type) => { call!($i, <$crate::token::Type as $crate::synom::Synom>::parse) };
+ ($i:expr, union) => { call!($i, <$crate::token::Union as $crate::synom::Synom>::parse) };
+ ($i:expr, unsafe) => { call!($i, <$crate::token::Unsafe as $crate::synom::Synom>::parse) };
+ ($i:expr, use) => { call!($i, <$crate::token::Use as $crate::synom::Synom>::parse) };
+ ($i:expr, where) => { call!($i, <$crate::token::Where as $crate::synom::Synom>::parse) };
+ ($i:expr, while) => { call!($i, <$crate::token::While as $crate::synom::Synom>::parse) };
+ ($i:expr, yield) => { call!($i, <$crate::token::Yield as $crate::synom::Synom>::parse) };
+}
+
+macro_rules! ident_from_token {
+ ($token:ident) => {
+ impl From<Token![$token]> for Ident {
+ fn from(token: Token![$token]) -> Ident {
+ Ident::new(stringify!($token), token.span)
+ }
+ }
+ };
+}
+
+ident_from_token!(self);
+ident_from_token!(Self);
+ident_from_token!(super);
+ident_from_token!(crate);
+ident_from_token!(extern);
+
+// Not public API.
+#[doc(hidden)]
+pub trait IntoSpans<S> {
+ fn into_spans(self) -> S;
+}
+
+impl IntoSpans<[Span; 1]> for Span {
+ fn into_spans(self) -> [Span; 1] {
+ [self]
+ }
+}
+
+impl IntoSpans<[Span; 2]> for Span {
+ fn into_spans(self) -> [Span; 2] {
+ [self, self]
+ }
+}
+
+impl IntoSpans<[Span; 3]> for Span {
+ fn into_spans(self) -> [Span; 3] {
+ [self, self, self]
+ }
+}
+
+impl IntoSpans<Self> for [Span; 1] {
+ fn into_spans(self) -> Self {
+ self
+ }
+}
+
+impl IntoSpans<Self> for [Span; 2] {
+ fn into_spans(self) -> Self {
+ self
+ }
+}
+
+impl IntoSpans<Self> for [Span; 3] {
+ fn into_spans(self) -> Self {
+ self
+ }
+}
+
+#[cfg(feature = "parsing")]
+mod parsing {
+ use proc_macro2::{Delimiter, Spacing, Span};
+
+ use buffer::Cursor;
+ use parse_error;
+ use synom::PResult;
+
+ pub trait FromSpans: Sized {
+ fn from_spans(spans: &[Span]) -> Self;
+ }
+
+ impl FromSpans for [Span; 1] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0]]
+ }
+ }
+
+ impl FromSpans for [Span; 2] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1]]
+ }
+ }
+
+ impl FromSpans for [Span; 3] {
+ fn from_spans(spans: &[Span]) -> Self {
+ [spans[0], spans[1], spans[2]]
+ }
+ }
+
+ pub fn punct<'a, T, R>(s: &str, mut tokens: Cursor<'a>, new: fn(T) -> R) -> PResult<'a, R>
+ where
+ T: FromSpans,
+ {
+ let mut spans = [Span::call_site(); 3];
+ assert!(s.len() <= spans.len());
+ let chars = s.chars();
+
+ for (i, (ch, slot)) in chars.zip(&mut spans).enumerate() {
+ match tokens.punct() {
+ Some((op, rest)) => {
+ if op.as_char() == ch {
+ if i != s.len() - 1 {
+ match op.spacing() {
+ Spacing::Joint => {}
+ _ => return parse_error(),
+ }
+ }
+ *slot = op.span();
+ tokens = rest;
+ } else {
+ return parse_error();
+ }
+ }
+ _ => return parse_error(),
+ }
+ }
+ Ok((new(T::from_spans(&spans)), tokens))
+ }
+
+ pub fn keyword<'a, T>(keyword: &str, tokens: Cursor<'a>, new: fn(Span) -> T) -> PResult<'a, T> {
+ if let Some((ident, rest)) = tokens.ident() {
+ if ident == keyword {
+ return Ok((new(ident.span()), rest));
+ }
+ }
+ parse_error()
+ }
+
+ pub fn delim<'a, F, R, T>(
+ delim: &str,
+ tokens: Cursor<'a>,
+ new: fn(Span) -> T,
+ f: F,
+ ) -> PResult<'a, (T, R)>
+ where
+ F: FnOnce(Cursor) -> PResult<R>,
+ {
+ // NOTE: We should support none-delimited sequences here.
+ let delim = match delim {
+ "(" => Delimiter::Parenthesis,
+ "{" => Delimiter::Brace,
+ "[" => Delimiter::Bracket,
+ " " => Delimiter::None,
+ _ => panic!("unknown delimiter: {}", delim),
+ };
+
+ if let Some((inside, span, rest)) = tokens.group(delim) {
+ match f(inside) {
+ Ok((ret, remaining)) => {
+ if remaining.eof() {
+ return Ok(((new(span), ret), rest));
+ }
+ }
+ Err(err) => return Err(err),
+ }
+ }
+ parse_error()
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
+ use quote::TokenStreamExt;
+
+ pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
+ assert_eq!(s.len(), spans.len());
+
+ let mut chars = s.chars();
+ let mut spans = spans.iter();
+ let ch = chars.next_back().unwrap();
+ let span = spans.next_back().unwrap();
+ for (ch, span) in chars.zip(spans) {
+ let mut op = Punct::new(ch, Spacing::Joint);
+ op.set_span(*span);
+ tokens.append(op);
+ }
+
+ let mut op = Punct::new(ch, Spacing::Alone);
+ op.set_span(*span);
+ tokens.append(op);
+ }
+
+ pub fn keyword(s: &str, span: &Span, tokens: &mut TokenStream) {
+ tokens.append(Ident::new(s, *span));
+ }
+
+ pub fn delim<F>(s: &str, span: &Span, tokens: &mut TokenStream, f: F)
+ where
+ F: FnOnce(&mut TokenStream),
+ {
+ let delim = match s {
+ "(" => Delimiter::Parenthesis,
+ "[" => Delimiter::Bracket,
+ "{" => Delimiter::Brace,
+ " " => Delimiter::None,
+ _ => panic!("unknown delimiter: {}", s),
+ };
+ let mut inner = TokenStream::new();
+ f(&mut inner);
+ let mut g = Group::new(delim, inner);
+ g.set_span(*span);
+ tokens.append(g);
+ }
+}
diff --git a/src/tt.rs b/src/tt.rs
new file mode 100644
index 0000000..bde82dc
--- /dev/null
+++ b/src/tt.rs
@@ -0,0 +1,170 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature = "parsing")]
+use buffer::Cursor;
+#[cfg(feature = "parsing")]
+use synom::PResult;
+#[cfg(feature = "parsing")]
+use token::{Brace, Bracket, Paren};
+#[cfg(feature = "parsing")]
+use {parse_error, MacroDelimiter};
+
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+
+#[cfg(any(feature = "parsing", feature = "extra-traits"))]
+use proc_macro2::{Delimiter, TokenStream, TokenTree};
+
+#[cfg(feature = "parsing")]
+pub fn delimited(input: Cursor) -> PResult<(MacroDelimiter, TokenStream)> {
+ if let Some((TokenTree::Group(g), rest)) = input.token_tree() {
+ let span = g.span();
+ let delimiter = match g.delimiter() {
+ Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
+ Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
+ Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
+ Delimiter::None => return parse_error(),
+ };
+
+ return Ok(((delimiter, g.stream().clone()), rest));
+ }
+ parse_error()
+}
+
+#[cfg(all(feature = "full", feature = "parsing"))]
+pub fn braced(input: Cursor) -> PResult<(Brace, TokenStream)> {
+ if let Some((TokenTree::Group(g), rest)) = input.token_tree() {
+ if g.delimiter() == Delimiter::Brace {
+ return Ok(((Brace(g.span()), g.stream().clone()), rest));
+ }
+ }
+ parse_error()
+}
+
+#[cfg(all(feature = "full", feature = "parsing"))]
+pub fn parenthesized(input: Cursor) -> PResult<(Paren, TokenStream)> {
+ if let Some((TokenTree::Group(g), rest)) = input.token_tree() {
+ if g.delimiter() == Delimiter::Parenthesis {
+ return Ok(((Paren(g.span()), g.stream().clone()), rest));
+ }
+ }
+ parse_error()
+}
+
+#[cfg(feature = "extra-traits")]
+pub struct TokenTreeHelper<'a>(pub &'a TokenTree);
+
+#[cfg(feature = "extra-traits")]
+impl<'a> PartialEq for TokenTreeHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ use proc_macro2::Spacing;
+
+ match (self.0, other.0) {
+ (&TokenTree::Group(ref g1), &TokenTree::Group(ref g2)) => {
+ match (g1.delimiter(), g2.delimiter()) {
+ (Delimiter::Parenthesis, Delimiter::Parenthesis)
+ | (Delimiter::Brace, Delimiter::Brace)
+ | (Delimiter::Bracket, Delimiter::Bracket)
+ | (Delimiter::None, Delimiter::None) => {}
+ _ => return false,
+ }
+
+ let s1 = g1.stream().clone().into_iter();
+ let mut s2 = g2.stream().clone().into_iter();
+
+ for item1 in s1 {
+ let item2 = match s2.next() {
+ Some(item) => item,
+ None => return false,
+ };
+ if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
+ return false;
+ }
+ }
+ s2.next().is_none()
+ }
+ (&TokenTree::Punct(ref o1), &TokenTree::Punct(ref o2)) => {
+ o1.as_char() == o2.as_char() && match (o1.spacing(), o2.spacing()) {
+ (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true,
+ _ => false,
+ }
+ }
+ (&TokenTree::Literal(ref l1), &TokenTree::Literal(ref l2)) => {
+ l1.to_string() == l2.to_string()
+ }
+ (&TokenTree::Ident(ref s1), &TokenTree::Ident(ref s2)) => s1 == s2,
+ _ => false,
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<'a> Hash for TokenTreeHelper<'a> {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ use proc_macro2::Spacing;
+
+ match *self.0 {
+ TokenTree::Group(ref g) => {
+ 0u8.hash(h);
+ match g.delimiter() {
+ Delimiter::Parenthesis => 0u8.hash(h),
+ Delimiter::Brace => 1u8.hash(h),
+ Delimiter::Bracket => 2u8.hash(h),
+ Delimiter::None => 3u8.hash(h),
+ }
+
+ for item in g.stream().clone() {
+ TokenTreeHelper(&item).hash(h);
+ }
+ 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
+ }
+ TokenTree::Punct(ref op) => {
+ 1u8.hash(h);
+ op.as_char().hash(h);
+ match op.spacing() {
+ Spacing::Alone => 0u8.hash(h),
+ Spacing::Joint => 1u8.hash(h),
+ }
+ }
+ TokenTree::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
+ TokenTree::Ident(ref word) => (3u8, word).hash(h),
+ }
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+pub struct TokenStreamHelper<'a>(pub &'a TokenStream);
+
+#[cfg(feature = "extra-traits")]
+impl<'a> PartialEq for TokenStreamHelper<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ let left = self.0.clone().into_iter().collect::<Vec<_>>();
+ let right = other.0.clone().into_iter().collect::<Vec<_>>();
+ if left.len() != right.len() {
+ return false;
+ }
+ for (a, b) in left.into_iter().zip(right) {
+ if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
+ return false;
+ }
+ }
+ true
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl<'a> Hash for TokenStreamHelper<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let tts = self.0.clone().into_iter().collect::<Vec<_>>();
+ tts.len().hash(state);
+ for tt in tts {
+ TokenTreeHelper(&tt).hash(state);
+ }
+ }
+}
diff --git a/src/ty.rs b/src/ty.rs
new file mode 100644
index 0000000..81e4df5
--- /dev/null
+++ b/src/ty.rs
@@ -0,0 +1,818 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use proc_macro2::TokenStream;
+use punctuated::Punctuated;
+#[cfg(feature = "extra-traits")]
+use std::hash::{Hash, Hasher};
+#[cfg(feature = "extra-traits")]
+use tt::TokenStreamHelper;
+
+ast_enum_of_structs! {
+ /// The possible types that a Rust value could have.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ ///
+ /// # Syntax tree enum
+ ///
+ /// This type is a [syntax tree enum].
+ ///
+ /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums
+ pub enum Type {
+ /// A dynamically sized slice type: `[T]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Slice(TypeSlice {
+ pub bracket_token: token::Bracket,
+ pub elem: Box<Type>,
+ }),
+
+ /// A fixed size array type: `[T; n]`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Array(TypeArray {
+ pub bracket_token: token::Bracket,
+ pub elem: Box<Type>,
+ pub semi_token: Token![;],
+ pub len: Expr,
+ }),
+
+ /// A raw pointer type: `*const T` or `*mut T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Ptr(TypePtr {
+ pub star_token: Token![*],
+ pub const_token: Option<Token![const]>,
+ pub mutability: Option<Token![mut]>,
+ pub elem: Box<Type>,
+ }),
+
+ /// A reference type: `&'a T` or `&'a mut T`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Reference(TypeReference {
+ pub and_token: Token![&],
+ pub lifetime: Option<Lifetime>,
+ pub mutability: Option<Token![mut]>,
+ pub elem: Box<Type>,
+ }),
+
+ /// A bare function type: `fn(usize) -> bool`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub BareFn(TypeBareFn {
+ pub unsafety: Option<Token![unsafe]>,
+ pub abi: Option<Abi>,
+ pub fn_token: Token![fn],
+ pub lifetimes: Option<BoundLifetimes>,
+ pub paren_token: token::Paren,
+ pub inputs: Punctuated<BareFnArg, Token![,]>,
+ pub variadic: Option<Token![...]>,
+ pub output: ReturnType,
+ }),
+
+ /// The never type: `!`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Never(TypeNever {
+ pub bang_token: Token![!],
+ }),
+
+ /// A tuple type: `(A, B, C, String)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Tuple(TypeTuple {
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Type, Token![,]>,
+ }),
+
+ /// A path like `std::slice::Iter`, optionally qualified with a
+ /// self-type as in `<Vec<T> as SomeTrait>::Associated`.
+ ///
+ /// Type arguments are stored in the Path itself.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Path(TypePath {
+ pub qself: Option<QSelf>,
+ pub path: Path,
+ }),
+
+ /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a
+ /// trait or a lifetime.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub TraitObject(TypeTraitObject {
+ pub dyn_token: Option<Token![dyn]>,
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }),
+
+ /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
+ /// a lifetime.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub ImplTrait(TypeImplTrait {
+ pub impl_token: Token![impl],
+ pub bounds: Punctuated<TypeParamBound, Token![+]>,
+ }),
+
+ /// A parenthesized type equivalent to the inner type.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Paren(TypeParen {
+ pub paren_token: token::Paren,
+ pub elem: Box<Type>,
+ }),
+
+ /// A type contained within invisible delimiters.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Group(TypeGroup {
+ pub group_token: token::Group,
+ pub elem: Box<Type>,
+ }),
+
+ /// Indication that a type should be inferred by the compiler: `_`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Infer(TypeInfer {
+ pub underscore_token: Token![_],
+ }),
+
+ /// A macro in the type position.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Macro(TypeMacro {
+ pub mac: Macro,
+ }),
+
+ /// Tokens in type position not interpreted by Syn.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or
+ /// `"full"` feature.*
+ pub Verbatim(TypeVerbatim #manual_extra_traits {
+ pub tts: TokenStream,
+ }),
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Eq for TypeVerbatim {}
+
+#[cfg(feature = "extra-traits")]
+impl PartialEq for TypeVerbatim {
+ fn eq(&self, other: &Self) -> bool {
+ TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
+ }
+}
+
+#[cfg(feature = "extra-traits")]
+impl Hash for TypeVerbatim {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ TokenStreamHelper(&self.tts).hash(state);
+ }
+}
+
+ast_struct! {
+ /// The binary interface of a function: `extern "C"`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct Abi {
+ pub extern_token: Token![extern],
+ pub name: Option<LitStr>,
+ }
+}
+
+ast_struct! {
+ /// An argument in a function type: the `usize` in `fn(usize) -> bool`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub struct BareFnArg {
+ pub name: Option<(BareFnArgName, Token![:])>,
+ pub ty: Type,
+ }
+}
+
+ast_enum! {
+ /// Name of an argument in a function type: the `n` in `fn(n: usize)`.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum BareFnArgName {
+ /// Argument given a name.
+ Named(Ident),
+ /// Argument not given a name, matched with `_`.
+ Wild(Token![_]),
+ }
+}
+
+ast_enum! {
+ /// Return type of a function signature.
+ ///
+ /// *This type is available if Syn is built with the `"derive"` or `"full"`
+ /// feature.*
+ pub enum ReturnType {
+ /// Return type is not specified.
+ ///
+ /// Functions default to `()` and closures default to type inference.
+ Default,
+ /// A particular type is returned.
+ Type(Token![->], Box<Type>),
+ }
+}
+
+#[cfg(feature = "parsing")]
+pub mod parsing {
+ use super::*;
+ use path::parsing::qpath;
+ use synom::Synom;
+
+ impl Synom for Type {
+ named!(parse -> Self, call!(ambig_ty, true));
+
+ fn description() -> Option<&'static str> {
+ Some("type")
+ }
+ }
+
+ impl Type {
+ /// In some positions, types may not contain the `+` character, to
+ /// disambiguate them. For example in the expression `1 as T`, T may not
+ /// contain a `+` character.
+ ///
+ /// This parser does not allow a `+`, while the default parser does.
+ named!(pub without_plus -> Self, call!(ambig_ty, false));
+ }
+
+ named!(ambig_ty(allow_plus: bool) -> Type, alt!(
+ syn!(TypeGroup) => { Type::Group }
+ |
+ // must be before TypeTuple
+ call!(TypeParen::parse, allow_plus) => { Type::Paren }
+ |
+ // must be before TypePath
+ syn!(TypeMacro) => { Type::Macro }
+ |
+ // must be before TypePath
+ syn!(TypeBareFn) => { Type::BareFn }
+ |
+ // must be before TypeTraitObject
+ call!(TypePath::parse, allow_plus) => { Type::Path }
+ |
+ // Don't try parsing more than one trait bound if we aren't allowing it.
+ // must be before TypeTuple
+ call!(TypeTraitObject::parse, allow_plus) => { Type::TraitObject }
+ |
+ syn!(TypeSlice) => { Type::Slice }
+ |
+ syn!(TypeArray) => { Type::Array }
+ |
+ syn!(TypePtr) => { Type::Ptr }
+ |
+ syn!(TypeReference) => { Type::Reference }
+ |
+ syn!(TypeNever) => { Type::Never }
+ |
+ syn!(TypeTuple) => { Type::Tuple }
+ |
+ syn!(TypeImplTrait) => { Type::ImplTrait }
+ |
+ syn!(TypeInfer) => { Type::Infer }
+ ));
+
+ impl Synom for TypeSlice {
+ named!(parse -> Self, map!(
+ brackets!(syn!(Type)),
+ |(b, ty)| TypeSlice {
+ elem: Box::new(ty),
+ bracket_token: b,
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("slice type")
+ }
+ }
+
+ impl Synom for TypeArray {
+ named!(parse -> Self, map!(
+ brackets!(do_parse!(
+ elem: syn!(Type) >>
+ semi: punct!(;) >>
+ len: syn!(Expr) >>
+ (elem, semi, len)
+ )),
+ |(brackets, (elem, semi, len))| {
+ TypeArray {
+ elem: Box::new(elem),
+ len: len,
+ bracket_token: brackets,
+ semi_token: semi,
+ }
+ }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("array type")
+ }
+ }
+
+ impl Synom for TypePtr {
+ named!(parse -> Self, do_parse!(
+ star: punct!(*) >>
+ mutability: alt!(
+ keyword!(const) => { |c| (None, Some(c)) }
+ |
+ keyword!(mut) => { |m| (Some(m), None) }
+ ) >>
+ target: call!(Type::without_plus) >>
+ (TypePtr {
+ const_token: mutability.1,
+ star_token: star,
+ mutability: mutability.0,
+ elem: Box::new(target),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("raw pointer type")
+ }
+ }
+
+ impl Synom for TypeReference {
+ named!(parse -> Self, do_parse!(
+ amp: punct!(&) >>
+ life: option!(syn!(Lifetime)) >>
+ mutability: option!(keyword!(mut)) >>
+ // & binds tighter than +, so we don't allow + here.
+ target: call!(Type::without_plus) >>
+ (TypeReference {
+ lifetime: life,
+ mutability: mutability,
+ elem: Box::new(target),
+ and_token: amp,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("reference type")
+ }
+ }
+
+ impl Synom for TypeBareFn {
+ named!(parse -> Self, do_parse!(
+ lifetimes: option!(syn!(BoundLifetimes)) >>
+ unsafety: option!(keyword!(unsafe)) >>
+ abi: option!(syn!(Abi)) >>
+ fn_: keyword!(fn) >>
+ parens: parens!(do_parse!(
+ inputs: call!(Punctuated::parse_terminated) >>
+ variadic: option!(cond_reduce!(inputs.empty_or_trailing(), punct!(...))) >>
+ (inputs, variadic)
+ )) >>
+ output: call!(ReturnType::without_plus) >>
+ (TypeBareFn {
+ unsafety: unsafety,
+ abi: abi,
+ lifetimes: lifetimes,
+ output: output,
+ variadic: (parens.1).1,
+ fn_token: fn_,
+ paren_token: parens.0,
+ inputs: (parens.1).0,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`fn` type")
+ }
+ }
+
+ impl Synom for TypeNever {
+ named!(parse -> Self, map!(
+ punct!(!),
+ |b| TypeNever { bang_token: b }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("never type: `!`")
+ }
+ }
+
+ impl Synom for TypeInfer {
+ named!(parse -> Self, map!(
+ punct!(_),
+ |u| TypeInfer { underscore_token: u }
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("inferred type: `_`")
+ }
+ }
+
+ impl Synom for TypeTuple {
+ named!(parse -> Self, do_parse!(
+ data: parens!(Punctuated::parse_terminated) >>
+ (TypeTuple {
+ paren_token: data.0,
+ elems: data.1,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("tuple type")
+ }
+ }
+
+ impl Synom for TypeMacro {
+ named!(parse -> Self, map!(syn!(Macro), |mac| TypeMacro { mac: mac }));
+
+ fn description() -> Option<&'static str> {
+ Some("macro invocation")
+ }
+ }
+
+ impl Synom for TypePath {
+ named!(parse -> Self, call!(Self::parse, false));
+
+ fn description() -> Option<&'static str> {
+ Some("type path")
+ }
+ }
+
+ impl TypePath {
+ named!(parse(allow_plus: bool) -> Self, do_parse!(
+ qpath: qpath >>
+ parenthesized: option!(cond_reduce!(
+ qpath.1.segments.last().unwrap().value().arguments.is_empty(),
+ syn!(ParenthesizedGenericArguments)
+ )) >>
+ cond!(allow_plus, not!(punct!(+))) >>
+ ({
+ let (qself, mut path) = qpath;
+ if let Some(parenthesized) = parenthesized {
+ let parenthesized = PathArguments::Parenthesized(parenthesized);
+ path.segments.last_mut().unwrap().value_mut().arguments = parenthesized;
+ }
+ TypePath { qself: qself, path: path }
+ })
+ ));
+ }
+
+ impl ReturnType {
+ named!(pub without_plus -> Self, call!(Self::parse, false));
+ named!(parse(allow_plus: bool) -> Self, alt!(
+ do_parse!(
+ arrow: punct!(->) >>
+ ty: call!(ambig_ty, allow_plus) >>
+ (ReturnType::Type(arrow, Box::new(ty)))
+ )
+ |
+ epsilon!() => { |_| ReturnType::Default }
+ ));
+ }
+
+ impl Synom for ReturnType {
+ named!(parse -> Self, call!(Self::parse, true));
+
+ fn description() -> Option<&'static str> {
+ Some("return type")
+ }
+ }
+
+ impl Synom for TypeTraitObject {
+ named!(parse -> Self, call!(Self::parse, true));
+
+ fn description() -> Option<&'static str> {
+ Some("trait object type")
+ }
+ }
+
+ fn at_least_one_type(bounds: &Punctuated<TypeParamBound, Token![+]>) -> bool {
+ for bound in bounds {
+ if let TypeParamBound::Trait(_) = *bound {
+ return true;
+ }
+ }
+ false
+ }
+
+ impl TypeTraitObject {
+ named!(pub without_plus -> Self, call!(Self::parse, false));
+
+ // Only allow multiple trait references if allow_plus is true.
+ named!(parse(allow_plus: bool) -> Self, do_parse!(
+ dyn_token: option!(keyword!(dyn)) >>
+ bounds: alt!(
+ cond_reduce!(allow_plus, Punctuated::parse_terminated_nonempty)
+ |
+ syn!(TypeParamBound) => {|x| {
+ let mut bounds = Punctuated::new();
+ bounds.push_value(x);
+ bounds
+ }}
+ ) >>
+ // Just lifetimes like `'a + 'b` is not a TraitObject.
+ cond_reduce!(at_least_one_type(&bounds)) >>
+ (TypeTraitObject {
+ dyn_token: dyn_token,
+ bounds: bounds,
+ })
+ ));
+ }
+
+ impl Synom for TypeImplTrait {
+ named!(parse -> Self, do_parse!(
+ impl_: keyword!(impl) >>
+ // NOTE: rust-lang/rust#34511 includes discussion about whether or
+ // not + should be allowed in ImplTrait directly without ().
+ elem: call!(Punctuated::parse_terminated_nonempty) >>
+ (TypeImplTrait {
+ impl_token: impl_,
+ bounds: elem,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`impl Trait` type")
+ }
+ }
+
+ impl Synom for TypeGroup {
+ named!(parse -> Self, do_parse!(
+ data: grouped!(syn!(Type)) >>
+ (TypeGroup {
+ group_token: data.0,
+ elem: Box::new(data.1),
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("type surrounded by invisible delimiters")
+ }
+ }
+
+ impl Synom for TypeParen {
+ named!(parse -> Self, call!(Self::parse, false));
+
+ fn description() -> Option<&'static str> {
+ Some("parenthesized type")
+ }
+ }
+
+ impl TypeParen {
+ named!(parse(allow_plus: bool) -> Self, do_parse!(
+ data: parens!(syn!(Type)) >>
+ cond!(allow_plus, not!(punct!(+))) >>
+ (TypeParen {
+ paren_token: data.0,
+ elem: Box::new(data.1),
+ })
+ ));
+ }
+
+ impl Synom for BareFnArg {
+ named!(parse -> Self, do_parse!(
+ name: option!(do_parse!(
+ name: syn!(BareFnArgName) >>
+ not!(punct!(::)) >>
+ colon: punct!(:) >>
+ (name, colon)
+ )) >>
+ ty: syn!(Type) >>
+ (BareFnArg {
+ name: name,
+ ty: ty,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("function type argument")
+ }
+ }
+
+ impl Synom for BareFnArgName {
+ named!(parse -> Self, alt!(
+ map!(syn!(Ident), BareFnArgName::Named)
+ |
+ map!(punct!(_), BareFnArgName::Wild)
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("function argument name")
+ }
+ }
+
+ impl Synom for Abi {
+ named!(parse -> Self, do_parse!(
+ extern_: keyword!(extern) >>
+ name: option!(syn!(LitStr)) >>
+ (Abi {
+ extern_token: extern_,
+ name: name,
+ })
+ ));
+
+ fn description() -> Option<&'static str> {
+ Some("`extern` ABI qualifier")
+ }
+ }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+ use super::*;
+ use proc_macro2::TokenStream;
+ use quote::ToTokens;
+
+ impl ToTokens for TypeSlice {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bracket_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeArray {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bracket_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
+ self.len.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypePtr {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.star_token.to_tokens(tokens);
+ match self.mutability {
+ Some(ref tok) => tok.to_tokens(tokens),
+ None => {
+ TokensOrDefault(&self.const_token).to_tokens(tokens);
+ }
+ }
+ self.elem.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeReference {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.and_token.to_tokens(tokens);
+ self.lifetime.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.elem.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeBareFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.lifetimes.to_tokens(tokens);
+ self.unsafety.to_tokens(tokens);
+ self.abi.to_tokens(tokens);
+ self.fn_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.inputs.to_tokens(tokens);
+ if let Some(ref variadic) = self.variadic {
+ if !self.inputs.empty_or_trailing() {
+ let span = variadic.spans[0];
+ Token.to_tokens(tokens);
+ }
+ variadic.to_tokens(tokens);
+ }
+ });
+ self.output.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeNever {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.bang_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypePath {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ PathTokens(&self.qself, &self.path).to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeTraitObject {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.dyn_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeImplTrait {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.impl_token.to_tokens(tokens);
+ self.bounds.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeGroup {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.group_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeParen {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.paren_token.surround(tokens, |tokens| {
+ self.elem.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for TypeInfer {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.underscore_token.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeMacro {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.mac.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for TypeVerbatim {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.tts.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for ReturnType {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ ReturnType::Default => {}
+ ReturnType::Type(ref arrow, ref ty) => {
+ arrow.to_tokens(tokens);
+ ty.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for BareFnArg {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some((ref name, ref colon)) = self.name {
+ name.to_tokens(tokens);
+ colon.to_tokens(tokens);
+ }
+ self.ty.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for BareFnArgName {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match *self {
+ BareFnArgName::Named(ref t) => t.to_tokens(tokens),
+ BareFnArgName::Wild(ref t) => t.to_tokens(tokens),
+ }
+ }
+ }
+
+ impl ToTokens for Abi {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.extern_token.to_tokens(tokens);
+ self.name.to_tokens(tokens);
+ }
+ }
+}
diff --git a/src/verbatim.rs b/src/verbatim.rs
new file mode 100644
index 0000000..35145d5
--- /dev/null
+++ b/src/verbatim.rs
@@ -0,0 +1,22 @@
+use std::ops::Range;
+
+use buffer::Cursor;
+use proc_macro2::TokenStream;
+use synom::PResult;
+
+#[allow(dead_code)]
+pub fn grab_cursor(cursor: Cursor) -> PResult<Cursor> {
+ Ok((cursor, cursor))
+}
+
+#[allow(dead_code)]
+pub fn token_range(range: Range<Cursor>) -> TokenStream {
+ let mut tts = Vec::new();
+ let mut cursor = range.start;
+ while cursor != range.end {
+ let (tt, next) = cursor.token_tree().expect("malformed token range");
+ tts.push(tt);
+ cursor = next;
+ }
+ tts.into_iter().collect()
+}
diff --git a/tests/clone.sh b/tests/clone.sh
new file mode 100755
index 0000000..48d9739
--- /dev/null
+++ b/tests/clone.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+REMOTE=rust
+REPO=https://github.com/rust-lang/rust
+REV=63d66494aff57411bfec1dd2a3a5f1af900feab6
+
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+mkdir -p rust
+cd rust
+
+git init
+
+if git remote | grep --fixed-strings --line-regexp --quiet "$REMOTE"; then
+ git remote set-url "$REMOTE" "$REPO"
+else
+ git remote add "$REMOTE" "$REPO"
+fi
+
+if ! git cat-file -t "$REV" >/dev/null 2>&1; then
+ git fetch "$REMOTE" master
+fi
+
+git checkout "$REV"
diff --git a/tests/common/eq.rs b/tests/common/eq.rs
new file mode 100644
index 0000000..b229890
--- /dev/null
+++ b/tests/common/eq.rs
@@ -0,0 +1,456 @@
+extern crate rustc_data_structures;
+extern crate rustc_target;
+extern crate syntax;
+extern crate syntax_pos;
+
+use std::mem;
+
+use self::rustc_data_structures::sync::Lrc;
+use self::rustc_data_structures::thin_vec::ThinVec;
+use self::rustc_target::abi::FloatTy;
+use self::rustc_target::spec::abi::Abi;
+use self::syntax::ast::{
+ AngleBracketedArgs, AnonConst, Arg, Arm, AsmDialect, AttrId, AttrStyle, Attribute, BareFnTy,
+ BinOpKind, BindingMode, Block, BlockCheckMode, CaptureBy, Constness, Crate, CrateSugar,
+ Defaultness, EnumDef, Expr, ExprKind, Field, FieldPat, FnDecl, FnHeader, ForeignItem,
+ ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs, GenericBound,
+ GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplItem, ImplItemKind,
+ ImplPolarity, InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label,
+ Lifetime, LitIntType, LitKind, Local, MacDelimiter, MacStmtStyle, Mac_, MacroDef, MethodSig,
+ Mod, Movability, MutTy, Mutability, NodeId, ParenthesisedArgs, Pat, PatKind, Path, PathSegment,
+ PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrStyle, StructField,
+ TraitBoundModifier, TraitItem, TraitItemKind, TraitObjectSyntax, TraitRef, Ty, TyKind,
+ TypeBinding, UintTy, UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, VariantData, Variant_,
+ VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
+ WhereRegionPredicate,
+};
+use self::syntax::parse::lexer::comments;
+use self::syntax::parse::token::{DelimToken, Lit, Token};
+use self::syntax::ptr::P;
+use self::syntax::source_map::Spanned;
+use self::syntax::symbol::Symbol;
+use self::syntax::tokenstream::{Delimited, ThinTokenStream, TokenStream, TokenTree};
+use self::syntax_pos::{Span, SyntaxContext, DUMMY_SP};
+
+pub trait SpanlessEq {
+ fn eq(&self, other: &Self) -> bool;
+}
+
+impl<T: SpanlessEq> SpanlessEq for P<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&**self, &**other)
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Lrc<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&**self, &**other)
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Option<T> {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (None, None) => true,
+ (Some(this), Some(other)) => SpanlessEq::eq(this, other),
+ _ => false,
+ }
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Vec<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b))
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for ThinVec<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.len() == other.len() && self
+ .iter()
+ .zip(other.iter())
+ .all(|(a, b)| SpanlessEq::eq(a, b))
+ }
+}
+
+impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.node, &other.node)
+ }
+}
+
+impl<A: SpanlessEq, B: SpanlessEq> SpanlessEq for (A, B) {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.0, &other.0) && SpanlessEq::eq(&self.1, &other.1)
+ }
+}
+
+impl<A: SpanlessEq, B: SpanlessEq, C: SpanlessEq> SpanlessEq for (A, B, C) {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&self.0, &other.0)
+ && SpanlessEq::eq(&self.1, &other.1)
+ && SpanlessEq::eq(&self.2, &other.2)
+ }
+}
+
+macro_rules! spanless_eq_true {
+ ($name:ident) => {
+ impl SpanlessEq for $name {
+ fn eq(&self, _other: &Self) -> bool {
+ true
+ }
+ }
+ };
+}
+
+spanless_eq_true!(Span);
+spanless_eq_true!(AttrId);
+spanless_eq_true!(NodeId);
+spanless_eq_true!(SyntaxContext);
+
+macro_rules! spanless_eq_partial_eq {
+ ($name:ident) => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ PartialEq::eq(self, other)
+ }
+ }
+ };
+}
+
+spanless_eq_partial_eq!(bool);
+spanless_eq_partial_eq!(u8);
+spanless_eq_partial_eq!(u16);
+spanless_eq_partial_eq!(u128);
+spanless_eq_partial_eq!(usize);
+spanless_eq_partial_eq!(char);
+spanless_eq_partial_eq!(Symbol);
+spanless_eq_partial_eq!(Abi);
+spanless_eq_partial_eq!(DelimToken);
+
+macro_rules! spanless_eq_struct {
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $(![$ignore:ident])*
+ } => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ let $name { $($field,)* $($ignore: _,)* } = self;
+ let $name { $($field: $other,)* $($ignore: _,)* } = other;
+ $(SpanlessEq::eq($field, $other))&&*
+ }
+ }
+ };
+
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $next:ident
+ $($rest:ident)*
+ $(!$ignore:ident)*
+ } => {
+ spanless_eq_struct! {
+ $name;
+ $([$field $other])*
+ [$next other]
+ $($rest)*
+ $(!$ignore)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$field:ident $other:ident])*
+ $(![$ignore:ident])*
+ !$next:ident
+ $(!$rest:ident)*
+ } => {
+ spanless_eq_struct! {
+ $name;
+ $([$field $other])*
+ $(![$ignore])*
+ ![$next]
+ $(!$rest)*
+ }
+ };
+}
+
+macro_rules! spanless_eq_enum {
+ {
+ $name:ident;
+ $([$variant:ident $([$field:tt $this:ident $other:ident])*])*
+ } => {
+ impl SpanlessEq for $name {
+ fn eq(&self, other: &Self) -> bool {
+ match self {
+ $(
+ $name::$variant { .. } => {}
+ )*
+ }
+ match (self, other) {
+ $(
+ (
+ $name::$variant { $($field: $this),* },
+ $name::$variant { $($field: $other),* },
+ ) => {
+ true $(&& SpanlessEq::eq($this, $other))*
+ }
+ )*
+ _ => false,
+ }
+ }
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident [$($named:tt)*] ( $i:tt $($field:tt)* )
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ $next [$($named)* [$i this other]] ( $($field)* )
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident [$($named:tt)*] ()
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ [$next $($named)*]
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident ( $($field:tt)* )
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ $next [] ( $($field)* )
+ $($rest)*
+ }
+ };
+
+ {
+ $name:ident;
+ $([$variant:ident $($fields:tt)*])*
+ $next:ident
+ $($rest:tt)*
+ } => {
+ spanless_eq_enum! {
+ $name;
+ $([$variant $($fields)*])*
+ [$next]
+ $($rest)*
+ }
+ };
+}
+
+spanless_eq_struct!(AngleBracketedArgs; span args bindings);
+spanless_eq_struct!(AnonConst; id value);
+spanless_eq_struct!(Arg; ty pat id);
+spanless_eq_struct!(Arm; attrs pats guard body);
+spanless_eq_struct!(Attribute; id style path tokens span !is_sugared_doc);
+spanless_eq_struct!(BareFnTy; unsafety abi generic_params decl);
+spanless_eq_struct!(Block; stmts id rules span recovered);
+spanless_eq_struct!(Crate; module attrs span);
+spanless_eq_struct!(Delimited; delim tts);
+spanless_eq_struct!(EnumDef; variants);
+spanless_eq_struct!(Expr; id node span attrs);
+spanless_eq_struct!(Field; ident expr span is_shorthand attrs);
+spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs);
+spanless_eq_struct!(FnDecl; inputs output variadic);
+spanless_eq_struct!(FnHeader; unsafety asyncness constness abi);
+spanless_eq_struct!(ForeignItem; ident attrs node id span vis);
+spanless_eq_struct!(ForeignMod; abi items);
+spanless_eq_struct!(GenericParam; id ident attrs bounds kind);
+spanless_eq_struct!(Generics; params where_clause span);
+spanless_eq_struct!(GlobalAsm; asm ctxt);
+spanless_eq_struct!(ImplItem; id ident vis defaultness attrs generics node span !tokens);
+spanless_eq_struct!(InlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect ctxt);
+spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect);
+spanless_eq_struct!(Item; ident attrs id node vis span !tokens);
+spanless_eq_struct!(Label; ident);
+spanless_eq_struct!(Lifetime; id ident);
+spanless_eq_struct!(Local; pat ty init id span attrs);
+spanless_eq_struct!(Mac_; path delim tts);
+spanless_eq_struct!(MacroDef; tokens legacy);
+spanless_eq_struct!(MethodSig; header decl);
+spanless_eq_struct!(Mod; inner items);
+spanless_eq_struct!(MutTy; ty mutbl);
+spanless_eq_struct!(ParenthesisedArgs; span inputs output);
+spanless_eq_struct!(Pat; id node span);
+spanless_eq_struct!(Path; span segments);
+spanless_eq_struct!(PathSegment; ident args);
+spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span);
+spanless_eq_struct!(QSelf; ty path_span position);
+spanless_eq_struct!(Stmt; id node span);
+spanless_eq_struct!(StructField; span ident vis id ty attrs);
+spanless_eq_struct!(TraitItem; id ident attrs generics node span !tokens);
+spanless_eq_struct!(TraitRef; path ref_id);
+spanless_eq_struct!(Ty; id node span);
+spanless_eq_struct!(TypeBinding; id ident ty span);
+spanless_eq_struct!(UseTree; prefix kind span);
+spanless_eq_struct!(Variant_; ident attrs data disr_expr);
+spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds);
+spanless_eq_struct!(WhereClause; id predicates span);
+spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty);
+spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
+spanless_eq_enum!(AsmDialect; Att Intel);
+spanless_eq_enum!(AttrStyle; Outer Inner);
+spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt);
+spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0));
+spanless_eq_enum!(BlockCheckMode; Default Unsafe(0));
+spanless_eq_enum!(CaptureBy; Value Ref);
+spanless_eq_enum!(Constness; Const NotConst);
+spanless_eq_enum!(CrateSugar; PubCrate JustCrate);
+spanless_eq_enum!(Defaultness; Default Final);
+spanless_eq_enum!(FloatTy; F32 F64);
+spanless_eq_enum!(ForeignItemKind; Fn(0 1) Static(0 1) Ty Macro(0));
+spanless_eq_enum!(FunctionRetTy; Default(0) Ty(0));
+spanless_eq_enum!(GenericArg; Lifetime(0) Type(0));
+spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0));
+spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0));
+spanless_eq_enum!(GenericParamKind; Lifetime Type(default));
+spanless_eq_enum!(ImplItemKind; Const(0 1) Method(0 1) Type(0) Existential(0) Macro(0));
+spanless_eq_enum!(ImplPolarity; Positive Negative);
+spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
+spanless_eq_enum!(IsAsync; Async(closure_id return_impl_trait_id) NotAsync);
+spanless_eq_enum!(IsAuto; Yes No);
+spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed);
+spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
+spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
+spanless_eq_enum!(Movability; Static Movable);
+spanless_eq_enum!(Mutability; Mutable Immutable);
+spanless_eq_enum!(RangeEnd; Included(0) Excluded);
+spanless_eq_enum!(RangeLimits; HalfOpen Closed);
+spanless_eq_enum!(StmtKind; Local(0) Item(0) Expr(0) Semi(0) Mac(0));
+spanless_eq_enum!(StrStyle; Cooked Raw(0));
+spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1));
+spanless_eq_enum!(TraitBoundModifier; None Maybe);
+spanless_eq_enum!(TraitItemKind; Const(0 1) Method(0 1) Type(0 1) Macro(0));
+spanless_eq_enum!(TraitObjectSyntax; Dyn None);
+spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
+spanless_eq_enum!(UnOp; Deref Not Neg);
+spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
+spanless_eq_enum!(Unsafety; Unsafe Normal);
+spanless_eq_enum!(UseTreeKind; Simple(0 1 2) Nested(0) Glob);
+spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0));
+spanless_eq_enum!(VisibilityKind; Public Crate(0) Restricted(path id) Inherited);
+spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
+spanless_eq_enum!(ExprKind; Box(0) ObsoleteInPlace(0 1) Array(0) Call(0 1)
+ MethodCall(0 1) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1)
+ If(0 1 2) IfLet(0 1 2 3) While(0 1 2) WhileLet(0 1 2 3) ForLoop(0 1 2 3)
+ Loop(0 1) Match(0 1) Closure(0 1 2 3 4 5) Block(0 1) Async(0 1 2) TryBlock(0)
+ Assign(0 1) AssignOp(0 1 2) Field(0 1) Index(0 1) Range(0 1 2) Path(0 1)
+ AddrOf(0 1) Break(0 1) Continue(0) Ret(0) InlineAsm(0) Mac(0) Struct(0 1 2)
+ Repeat(0 1) Paren(0) Try(0) Yield(0));
+spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1)
+ Fn(0 1 2 3) Mod(0) ForeignMod(0) GlobalAsm(0) Ty(0 1) Existential(0 1)
+ Enum(0 1) Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1)
+ Impl(0 1 2 3 4 5 6) Mac(0) MacroDef(0));
+spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1)
+ Float(0 1) FloatUnsuffixed(0) Bool(0));
+spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1 2)
+ Path(0 1) Tuple(0 1) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0 1 2)
+ Paren(0) Mac(0));
+spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Rptr(0 1) BareFn(0) Never
+ Tup(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1) Paren(0) Typeof(0) Infer
+ ImplicitSelf Mac(0) Err);
+
+impl SpanlessEq for Ident {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_str() == other.as_str()
+ }
+}
+
+// Give up on comparing literals inside of macros because there are so many
+// equivalent representations of the same literal; they are tested elsewhere
+impl SpanlessEq for Lit {
+ fn eq(&self, other: &Self) -> bool {
+ mem::discriminant(self) == mem::discriminant(other)
+ }
+}
+
+impl SpanlessEq for RangeSyntax {
+ fn eq(&self, _other: &Self) -> bool {
+ match self {
+ RangeSyntax::DotDotDot | RangeSyntax::DotDotEq => true,
+ }
+ }
+}
+
+impl SpanlessEq for Token {
+ fn eq(&self, other: &Self) -> bool {
+ match (self, other) {
+ (Token::Literal(this, _), Token::Literal(other, _)) => SpanlessEq::eq(this, other),
+ (Token::DotDotEq, _) | (Token::DotDotDot, _) => match other {
+ Token::DotDotEq | Token::DotDotDot => true,
+ _ => false,
+ },
+ _ => self == other,
+ }
+ }
+}
+
+impl SpanlessEq for TokenStream {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(&expand_tts(self), &expand_tts(other))
+ }
+}
+
+impl SpanlessEq for ThinTokenStream {
+ fn eq(&self, other: &Self) -> bool {
+ SpanlessEq::eq(
+ &TokenStream::from(self.clone()),
+ &TokenStream::from(other.clone()),
+ )
+ }
+}
+
+fn expand_tts(tts: &TokenStream) -> Vec<TokenTree> {
+ let mut tokens = Vec::new();
+ for tt in tts.clone().into_trees() {
+ let c = match tt {
+ TokenTree::Token(_, Token::DocComment(c)) => c,
+ _ => {
+ tokens.push(tt);
+ continue;
+ }
+ };
+ let contents = comments::strip_doc_comment_decoration(&c.as_str());
+ let style = comments::doc_comment_style(&c.as_str());
+ tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound));
+ if style == AttrStyle::Inner {
+ tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
+ }
+ let lit = Lit::Str_(Symbol::intern(&contents));
+ let mut tts = vec![
+ TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
+ TokenTree::Token(DUMMY_SP, Token::Eq),
+ TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
+ ];
+ tokens.push(TokenTree::Delimited(
+ DUMMY_SP,
+ Delimited {
+ delim: DelimToken::Bracket,
+ tts: tts.into_iter().collect::<TokenStream>().into(),
+ },
+ ));
+ }
+ tokens
+}
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
new file mode 100644
index 0000000..e09544b
--- /dev/null
+++ b/tests/common/mod.rs
@@ -0,0 +1,91 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+extern crate syntax;
+extern crate walkdir;
+
+use std;
+use std::env;
+use std::process::Command;
+
+use self::walkdir::DirEntry;
+
+pub mod eq;
+pub mod parse;
+
+pub fn check_min_stack() {
+ let min_stack_value = match env::var("RUST_MIN_STACK") {
+ Ok(s) => s,
+ Err(_) => {
+ env::set_var("RUST_MIN_STACK", 16000000.to_string());
+ return;
+ }
+ };
+ let min_stack_value: usize = min_stack_value
+ .parse()
+ .expect("RUST_MIN_STACK env var should be set since some tests require it.");
+ assert!(min_stack_value >= 16_000_000);
+}
+
+/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
+pub fn abort_after() -> usize {
+ match env::var("ABORT_AFTER_FAILURE") {
+ Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"),
+ Err(_) => std::usize::MAX,
+ }
+}
+
+pub fn base_dir_filter(entry: &DirEntry) -> bool {
+ let path = entry.path();
+ if path.is_dir() {
+ return true; // otherwise walkdir does not visit the files
+ }
+ if path.extension().map(|e| e != "rs").unwrap_or(true) {
+ return false;
+ }
+ let path_string = path.to_string_lossy();
+ let path_string = if cfg!(windows) {
+ path_string.replace('\\', "/").into()
+ } else {
+ path_string
+ };
+ // TODO assert that parsing fails on the parse-fail cases
+ if path_string.starts_with("tests/rust/src/test/parse-fail")
+ || path_string.starts_with("tests/rust/src/test/compile-fail")
+ || path_string.starts_with("tests/rust/src/test/rustfix")
+ {
+ return false;
+ }
+
+ if path_string.starts_with("tests/rust/src/test/ui") {
+ let stderr_path = path.with_extension("stderr");
+ if stderr_path.exists() {
+ // Expected to fail in some way
+ return false;
+ }
+ }
+
+ match path_string.as_ref() {
+ // Deprecated placement syntax
+ "tests/rust/src/test/run-pass/new-box-syntax.rs" |
+ "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
+ // not actually test cases
+ "tests/rust/src/test/run-pass/auxiliary/macro-comma-support.rs" |
+ "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" |
+ "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" => false,
+ _ => true,
+ }
+}
+
+pub fn clone_rust() {
+ let result = Command::new("tests/clone.sh").status().unwrap();
+ println!("result: {}", result);
+ assert!(result.success());
+}
diff --git a/tests/common/parse.rs b/tests/common/parse.rs
new file mode 100644
index 0000000..0f410e6
--- /dev/null
+++ b/tests/common/parse.rs
@@ -0,0 +1,78 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate proc_macro2;
+extern crate syn;
+extern crate syntax;
+extern crate syntax_pos;
+
+use self::syntax::ast;
+use self::syntax::parse::{self, ParseSess};
+use self::syntax::ptr::P;
+use self::syntax::source_map::FilePathMapping;
+use self::syntax_pos::edition::Edition;
+use self::syntax_pos::{hygiene, FileName};
+
+use std::panic;
+
+use self::syn::buffer::TokenBuffer;
+use self::syn::synom::Synom;
+
+pub fn libsyntax_expr(input: &str) -> Option<P<ast::Expr>> {
+ match panic::catch_unwind(|| {
+ hygiene::set_default_edition(Edition::Edition2018);
+ let sess = ParseSess::new(FilePathMapping::empty());
+ sess.span_diagnostic.set_continue_after_error(false);
+ let e = parse::new_parser_from_source_str(
+ &sess,
+ FileName::Custom("test_precedence".to_string()),
+ input.to_string(),
+ ).parse_expr();
+ match e {
+ Ok(expr) => Some(expr),
+ Err(mut diagnostic) => {
+ diagnostic.emit();
+ None
+ }
+ }
+ }) {
+ Ok(Some(e)) => Some(e),
+ Ok(None) => None,
+ Err(_) => {
+ errorf!("libsyntax panicked\n");
+ None
+ }
+ }
+}
+
+pub fn syn_expr(input: &str) -> Option<syn::Expr> {
+ match syn::parse_str(input) {
+ Ok(e) => Some(e),
+ Err(msg) => {
+ errorf!("syn failed to parse\n{:?}\n", msg);
+ None
+ }
+ }
+}
+
+pub fn syn<T: Synom>(tokens: proc_macro2::TokenStream) -> T {
+ let buf = TokenBuffer::new2(tokens);
+ let result = T::parse(buf.begin());
+ match result {
+ Ok((t, rest)) => {
+ if rest.eof() {
+ t
+ } else if rest == buf.begin() {
+ panic!("failed to parse anything")
+ } else {
+ panic!("failed to parse all tokens")
+ }
+ }
+ Err(err) => panic!("failed to parse: {}", err),
+ }
+}
diff --git a/tests/macros/mod.rs b/tests/macros/mod.rs
new file mode 100644
index 0000000..820941f
--- /dev/null
+++ b/tests/macros/mod.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_export]
+macro_rules! errorf {
+ ($($tt:tt)*) => {{
+ use ::std::io::Write;
+ let stderr = ::std::io::stderr();
+ write!(stderr.lock(), $($tt)*).unwrap();
+ }};
+}
+
+#[macro_export]
+macro_rules! punctuated {
+ ($($e:expr,)+) => {{
+ let mut seq = ::syn::punctuated::Punctuated::new();
+ $(
+ seq.push($e);
+ )+
+ seq
+ }};
+
+ ($($e:expr),+) => {
+ punctuated!($($e,)+)
+ };
+}
diff --git a/tests/test_asyncness.rs b/tests/test_asyncness.rs
new file mode 100644
index 0000000..b73537b
--- /dev/null
+++ b/tests/test_asyncness.rs
@@ -0,0 +1,71 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(all(feature = "extra-traits", feature = "full"))]
+
+extern crate proc_macro2;
+extern crate syn;
+
+use proc_macro2::Span;
+use syn::punctuated::Punctuated;
+use syn::{Block, Expr, ExprBlock, ExprClosure, FnDecl, Ident, ItemFn, ReturnType, Visibility};
+
+#[test]
+fn test_async_fn() {
+ let raw = "async fn process() {}";
+
+ let expected = ItemFn {
+ attrs: vec![],
+ vis: Visibility::Inherited,
+ constness: None,
+ unsafety: None,
+ asyncness: Some(Default::default()),
+ abi: None,
+ ident: Ident::new("process", Span::call_site()),
+ decl: Box::new(FnDecl {
+ fn_token: Default::default(),
+ generics: Default::default(),
+ paren_token: Default::default(),
+ inputs: Punctuated::new(),
+ variadic: None,
+ output: ReturnType::Default,
+ }),
+ block: Box::new(Block {
+ brace_token: Default::default(),
+ stmts: vec![],
+ }),
+ };
+
+ assert_eq!(expected, syn::parse_str(raw).unwrap());
+}
+
+#[test]
+fn test_async_closure() {
+ let raw = "async || {}";
+
+ let expected = Expr::Closure(ExprClosure {
+ attrs: vec![],
+ movability: None,
+ asyncness: Some(Default::default()),
+ capture: None,
+ or1_token: Default::default(),
+ inputs: Punctuated::new(),
+ or2_token: Default::default(),
+ output: ReturnType::Default,
+ body: Box::new(Expr::Block(ExprBlock {
+ attrs: vec![],
+ label: None,
+ block: Block {
+ brace_token: Default::default(),
+ stmts: vec![],
+ },
+ })),
+ });
+
+ assert_eq!(expected, syn::parse_str(raw).unwrap());
+}
diff --git a/tests/test_derive_input.rs b/tests/test_derive_input.rs
new file mode 100644
index 0000000..045e506
--- /dev/null
+++ b/tests/test_derive_input.rs
@@ -0,0 +1,808 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "extra-traits")]
+
+extern crate proc_macro2;
+extern crate syn;
+
+use proc_macro2::Delimiter::{Brace, Parenthesis};
+use proc_macro2::*;
+use syn::punctuated::Punctuated;
+use syn::*;
+
+use std::iter::FromIterator;
+
+#[macro_use]
+mod macros;
+
+fn op(c: char) -> TokenTree {
+ Punct::new(c, Spacing::Alone).into()
+}
+
+fn lit<T: Into<Literal>>(t: T) -> TokenTree {
+ t.into().into()
+}
+
+fn ident(sym: &str) -> Ident {
+ Ident::new(sym, Span::call_site())
+}
+
+fn word(sym: &str) -> TokenTree {
+ ident(sym).into()
+}
+
+fn delimited(delim: Delimiter, tokens: Vec<TokenTree>) -> TokenTree {
+ Group::new(delim, tokens.into_iter().collect()).into()
+}
+
+#[test]
+fn test_unit() {
+ let raw = "struct Unit;";
+
+ let expected = DeriveInput {
+ ident: ident("Unit"),
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ fields: Fields::Unit,
+ }),
+ };
+
+ assert_eq!(expected, syn::parse_str(raw).unwrap());
+}
+
+#[test]
+fn test_struct() {
+ let raw = "
+ #[derive(Debug, Clone)]
+ pub struct Item {
+ pub ident: Ident,
+ pub attrs: Vec<Attribute>
+ }
+ ";
+
+ let expected = DeriveInput {
+ ident: ident("Item"),
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ attrs: vec![Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: ident("derive").into(),
+ tts: TokenStream::from_iter(vec![delimited(
+ Parenthesis,
+ vec![word("Debug"), op(','), word("Clone")],
+ )]),
+ }],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: None,
+ struct_token: Default::default(),
+ fields: Fields::Named(FieldsNamed {
+ brace_token: Default::default(),
+ named: punctuated![
+ Field {
+ ident: Some(ident("ident")),
+ colon_token: Some(Default::default()),
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ attrs: Vec::new(),
+ ty: TypePath {
+ qself: None,
+ path: ident("Ident").into(),
+ }.into(),
+ },
+ Field {
+ ident: Some(ident("attrs")),
+ colon_token: Some(Default::default()),
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ attrs: Vec::new(),
+ ty: TypePath {
+ qself: None,
+ path: Path {
+ leading_colon: None,
+ segments: punctuated![PathSegment {
+ ident: ident("Vec"),
+ arguments: PathArguments::AngleBracketed(
+ AngleBracketedGenericArguments {
+ colon2_token: None,
+ lt_token: Default::default(),
+ args: punctuated![GenericArgument::Type(Type::from(
+ TypePath {
+ qself: None,
+ path: ident("Attribute").into(),
+ }
+ )),],
+ gt_token: Default::default(),
+ },
+ ),
+ },],
+ },
+ }.into(),
+ },
+ ],
+ }),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+
+ let expected_meta_item: Meta = MetaList {
+ ident: ident("derive"),
+ paren_token: Default::default(),
+ nested: punctuated![
+ NestedMeta::Meta(Meta::Word(ident("Debug"))),
+ NestedMeta::Meta(Meta::Word(ident("Clone"))),
+ ],
+ }.into();
+
+ assert_eq!(
+ expected_meta_item,
+ actual.attrs[0].interpret_meta().unwrap()
+ );
+}
+
+#[test]
+fn test_union() {
+ let raw = "
+ union MaybeUninit<T> {
+ uninit: (),
+ value: T
+ }
+ ";
+
+ let expected = DeriveInput {
+ ident: ident("MaybeUninit"),
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ generics: Generics {
+ lt_token: Some(Default::default()),
+ params: punctuated![GenericParam::Type(TypeParam {
+ attrs: Vec::new(),
+ ident: ident("T"),
+ bounds: Default::default(),
+ default: None,
+ colon_token: None,
+ eq_token: None,
+ }),],
+ gt_token: Some(Default::default()),
+ where_clause: None,
+ },
+ data: Data::Union(DataUnion {
+ union_token: Default::default(),
+ fields: FieldsNamed {
+ brace_token: Default::default(),
+ named: punctuated![
+ Field {
+ ident: Some(ident("uninit")),
+ colon_token: Some(Default::default()),
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ ty: TypeTuple {
+ paren_token: Default::default(),
+ elems: Punctuated::new(),
+ }.into(),
+ },
+ Field {
+ ident: Some(ident("value")),
+ colon_token: Some(Default::default()),
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ ty: TypePath {
+ qself: None,
+ path: ident("T").into(),
+ }.into(),
+ },
+ ],
+ },
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+#[cfg(feature = "full")]
+fn test_enum() {
+ let raw = r#"
+ /// See the std::result module documentation for details.
+ #[must_use]
+ pub enum Result<T, E> {
+ Ok(T),
+ Err(E),
+ Surprise = 0isize,
+
+ // Smuggling data into a proc_macro_derive,
+ // in the style of https://github.com/dtolnay/proc-macro-hack
+ ProcMacroHack = (0, "data").0
+ }
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("Result"),
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ attrs: vec![
+ Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: ident("doc").into(),
+ tts: TokenStream::from_iter(vec![
+ op('='),
+ lit(Literal::string(
+ " See the std::result module documentation for details.",
+ )),
+ ]),
+ },
+ Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: ident("must_use").into(),
+ tts: TokenStream::new(),
+ },
+ ],
+ generics: Generics {
+ lt_token: Some(Default::default()),
+ params: punctuated![
+ GenericParam::Type(TypeParam {
+ attrs: Vec::new(),
+ ident: ident("T"),
+ bounds: Default::default(),
+ default: None,
+ colon_token: None,
+ eq_token: None,
+ }),
+ GenericParam::Type(TypeParam {
+ attrs: Vec::new(),
+ ident: ident("E"),
+ bounds: Default::default(),
+ colon_token: None,
+ eq_token: None,
+ default: None,
+ }),
+ ],
+ gt_token: Some(Default::default()),
+ where_clause: None,
+ },
+ data: Data::Enum(DataEnum {
+ variants: punctuated![
+ Variant {
+ ident: ident("Ok"),
+ attrs: Vec::new(),
+ fields: Fields::Unnamed(FieldsUnnamed {
+ paren_token: Default::default(),
+ unnamed: punctuated![Field {
+ colon_token: None,
+ ident: None,
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ ty: TypePath {
+ qself: None,
+ path: ident("T").into(),
+ }.into(),
+ },],
+ }),
+ discriminant: None,
+ },
+ Variant {
+ ident: ident("Err"),
+ attrs: Vec::new(),
+ fields: Fields::Unnamed(FieldsUnnamed {
+ paren_token: Default::default(),
+ unnamed: punctuated![Field {
+ ident: None,
+ colon_token: None,
+ vis: Visibility::Inherited,
+ attrs: Vec::new(),
+ ty: TypePath {
+ qself: None,
+ path: ident("E").into(),
+ }.into(),
+ },],
+ }),
+ discriminant: None,
+ },
+ Variant {
+ ident: ident("Surprise"),
+ attrs: Vec::new(),
+ fields: Fields::Unit,
+ discriminant: Some((
+ Default::default(),
+ Expr::Lit(ExprLit {
+ attrs: Vec::new(),
+ lit: Lit::Int(LitInt::new(0, IntSuffix::Isize, Span::call_site())),
+ }),
+ )),
+ },
+ Variant {
+ ident: ident("ProcMacroHack"),
+ attrs: Vec::new(),
+ fields: Fields::Unit,
+ discriminant: Some((
+ Default::default(),
+ Expr::Field(ExprField {
+ attrs: Vec::new(),
+ base: Box::new(Expr::Tuple(ExprTuple {
+ attrs: Vec::new(),
+ paren_token: Default::default(),
+ elems: punctuated![
+ Expr::Lit(ExprLit {
+ attrs: Vec::new(),
+ lit: Lit::Int(LitInt::new(
+ 0,
+ IntSuffix::None,
+ Span::call_site()
+ )),
+ }),
+ Expr::Lit(ExprLit {
+ attrs: Vec::new(),
+ lit: Lit::Str(LitStr::new("data", Span::call_site())),
+ }),
+ ],
+ })),
+ dot_token: Default::default(),
+ member: Member::Unnamed(Index {
+ index: 0,
+ span: Span::call_site(),
+ }),
+ }),
+ )),
+ },
+ ],
+ brace_token: Default::default(),
+ enum_token: Default::default(),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+
+ let expected_meta_items = vec![
+ MetaNameValue {
+ ident: ident("doc"),
+ eq_token: Default::default(),
+ lit: Lit::Str(LitStr::new(
+ " See the std::result module documentation for details.",
+ Span::call_site(),
+ )),
+ }.into(),
+ Meta::Word(ident("must_use")),
+ ];
+
+ let actual_meta_items: Vec<_> = actual
+ .attrs
+ .into_iter()
+ .map(|attr| attr.interpret_meta().unwrap())
+ .collect();
+
+ assert_eq!(expected_meta_items, actual_meta_items);
+}
+
+#[test]
+fn test_attr_with_path() {
+ let raw = r#"
+ #[::attr_args::identity
+ fn main() { assert_eq!(foo(), "Hello, world!"); }]
+ struct Dummy;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("Dummy"),
+ vis: Visibility::Inherited,
+ attrs: vec![Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: Path {
+ leading_colon: Some(Default::default()),
+ segments: punctuated![
+ PathSegment::from(ident("attr_args")),
+ PathSegment::from(ident("identity")),
+ ],
+ },
+ tts: TokenStream::from_iter(vec![
+ word("fn"),
+ word("main"),
+ delimited(Parenthesis, vec![]),
+ delimited(
+ Brace,
+ vec![
+ word("assert_eq"),
+ op('!'),
+ delimited(
+ Parenthesis,
+ vec![
+ word("foo"),
+ delimited(Parenthesis, vec![]),
+ op(','),
+ lit(Literal::string("Hello, world!")),
+ ],
+ ),
+ op(';'),
+ ],
+ ),
+ ]),
+ }],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ fields: Fields::Unit,
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+
+ assert!(actual.attrs[0].interpret_meta().is_none());
+}
+
+#[test]
+fn test_attr_with_non_mod_style_path() {
+ let raw = r#"
+ #[inert <T>]
+ struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Inherited,
+ attrs: vec![Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: Path {
+ leading_colon: None,
+ segments: punctuated![PathSegment::from(ident("inert"))],
+ },
+ tts: TokenStream::from_iter(vec![op('<'), word("T"), op('>')]),
+ }],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ fields: Fields::Unit,
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+
+ assert!(actual.attrs[0].interpret_meta().is_none());
+}
+
+#[test]
+fn test_attr_with_mod_style_path_with_self() {
+ let raw = r#"
+ #[foo::self]
+ struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Inherited,
+ attrs: vec![Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: Path {
+ leading_colon: None,
+ segments: punctuated![
+ PathSegment::from(ident("foo")),
+ PathSegment::from(ident("self")),
+ ],
+ },
+ tts: TokenStream::new(),
+ }],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ fields: Fields::Unit,
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+
+ assert!(actual.attrs[0].interpret_meta().is_none());
+}
+
+#[test]
+fn test_pub_restricted() {
+ // Taken from tests/rust/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs
+ let raw = r#"
+ pub(in m) struct Z(pub(in m::n) u8);
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("Z"),
+ vis: Visibility::Restricted(VisRestricted {
+ path: Box::new(ident("m").into()),
+ in_token: Some(Default::default()),
+ paren_token: Default::default(),
+ pub_token: Default::default(),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ fields: Fields::Unnamed(FieldsUnnamed {
+ paren_token: Default::default(),
+ unnamed: punctuated![Field {
+ ident: None,
+ vis: Visibility::Restricted(VisRestricted {
+ path: Box::new(Path {
+ leading_colon: None,
+ segments: punctuated![
+ PathSegment::from(ident("m")),
+ PathSegment::from(ident("n")),
+ ],
+ }),
+ in_token: Some(Default::default()),
+ paren_token: Default::default(),
+ pub_token: Default::default(),
+ }),
+ colon_token: None,
+ attrs: vec![],
+ ty: TypePath {
+ qself: None,
+ path: ident("u8").into(),
+ }.into(),
+ },],
+ }),
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn test_vis_crate() {
+ let raw = r#"
+ crate struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Crate(VisCrate {
+ crate_token: Default::default(),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ fields: Fields::Unit,
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn test_pub_restricted_crate() {
+ let raw = r#"
+ pub(crate) struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Restricted(VisRestricted {
+ pub_token: Default::default(),
+ paren_token: Default::default(),
+ in_token: None,
+ path: Box::new(ident("crate").into()),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ fields: Fields::Unit,
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn test_pub_restricted_super() {
+ let raw = r#"
+ pub(super) struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Restricted(VisRestricted {
+ path: Box::new(ident("super").into()),
+ in_token: None,
+ paren_token: Default::default(),
+ pub_token: Default::default(),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ fields: Fields::Unit,
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn test_pub_restricted_in_super() {
+ let raw = r#"
+ pub(in super) struct S;
+ "#;
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Restricted(VisRestricted {
+ path: Box::new(ident("super").into()),
+ in_token: Some(Default::default()),
+ paren_token: Default::default(),
+ pub_token: Default::default(),
+ }),
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ semi_token: Some(Default::default()),
+ struct_token: Default::default(),
+ fields: Fields::Unit,
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
+
+#[test]
+fn test_fields_on_unit_struct() {
+ let raw = "struct S;";
+ let struct_body = match syn::parse_str::<DeriveInput>(raw).unwrap().data {
+ Data::Struct(body) => body,
+ _ => panic!("expected a struct"),
+ };
+
+ assert_eq!(0, struct_body.fields.iter().count());
+}
+
+#[test]
+fn test_fields_on_named_struct() {
+ let raw = "struct S {
+ foo: i32,
+ pub bar: String,
+ }";
+ let struct_body = match syn::parse_str::<DeriveInput>(raw).unwrap().data {
+ Data::Struct(body) => body,
+ _ => panic!("expected a struct"),
+ };
+
+ let expected = vec![
+ Field {
+ attrs: vec![],
+ vis: Visibility::Inherited,
+ ident: Some(ident("foo")),
+ colon_token: Some(Default::default()),
+ ty: syn::parse_str("i32").unwrap(),
+ },
+ Field {
+ attrs: vec![],
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ ident: Some(ident("bar")),
+ colon_token: Some(Default::default()),
+ ty: syn::parse_str("String").unwrap(),
+ },
+ ];
+ let expected = expected.iter().collect::<Vec<_>>();
+
+ assert_eq!(expected, struct_body.fields.iter().collect::<Vec<_>>());
+}
+
+#[test]
+fn test_fields_on_tuple_struct() {
+ let raw = "struct S(i32, pub String);";
+ let struct_body = match syn::parse_str::<DeriveInput>(raw).unwrap().data {
+ Data::Struct(body) => body,
+ _ => panic!("expected a struct"),
+ };
+
+ let expected = vec![
+ Field {
+ attrs: vec![],
+ vis: Visibility::Inherited,
+ ident: None,
+ colon_token: None,
+ ty: syn::parse_str("i32").unwrap(),
+ },
+ Field {
+ attrs: vec![],
+ vis: Visibility::Public(VisPublic {
+ pub_token: Default::default(),
+ }),
+ ident: None,
+ colon_token: None,
+ ty: syn::parse_str("String").unwrap(),
+ },
+ ];
+ let expected = expected.iter().collect::<Vec<_>>();
+
+ assert_eq!(expected, struct_body.fields.iter().collect::<Vec<_>>());
+}
+
+#[test]
+fn test_ambiguous_crate() {
+ // The field type is `(crate::X)` not `crate (::X)`.
+ let raw = "struct S(crate::X);";
+
+ let expected = DeriveInput {
+ ident: ident("S"),
+ vis: Visibility::Inherited,
+ attrs: vec![],
+ generics: Generics::default(),
+ data: Data::Struct(DataStruct {
+ struct_token: Default::default(),
+ fields: Fields::Unnamed(FieldsUnnamed {
+ paren_token: Default::default(),
+ unnamed: punctuated![Field {
+ attrs: Vec::new(),
+ vis: Visibility::Inherited,
+ ident: None,
+ colon_token: None,
+ ty: Type::Path(TypePath {
+ qself: None,
+ path: Path {
+ leading_colon: None,
+ segments: punctuated![ident("crate").into(), ident("X").into(),],
+ },
+ }),
+ }],
+ }),
+ semi_token: Some(Default::default()),
+ }),
+ };
+
+ let actual = syn::parse_str(raw).unwrap();
+
+ assert_eq!(expected, actual);
+}
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
new file mode 100644
index 0000000..33e7768
--- /dev/null
+++ b/tests/test_generics.rs
@@ -0,0 +1,175 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "extra-traits")]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+extern crate syn;
+use syn::*;
+
+#[macro_use]
+extern crate quote;
+
+extern crate proc_macro2;
+use proc_macro2::{Ident, Span, TokenStream};
+
+#[macro_use]
+mod macros;
+
+mod common;
+
+fn ident(s: &str) -> Ident {
+ Ident::new(s, Span::call_site())
+}
+
+#[test]
+fn test_split_for_impl() {
+ // <'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug
+ let generics = Generics {
+ gt_token: Some(Default::default()),
+ lt_token: Some(Default::default()),
+ params: punctuated![
+ GenericParam::Lifetime(LifetimeDef {
+ attrs: Default::default(),
+ lifetime: Lifetime::new("'a", Span::call_site()),
+ bounds: Default::default(),
+ colon_token: None,
+ }),
+ GenericParam::Lifetime(LifetimeDef {
+ attrs: Default::default(),
+ lifetime: Lifetime::new("'b", Span::call_site()),
+ bounds: punctuated![Lifetime::new("'a", Span::call_site())],
+ colon_token: Some(token::Colon::default()),
+ }),
+ GenericParam::Type(TypeParam {
+ attrs: vec![Attribute {
+ bracket_token: Default::default(),
+ pound_token: Default::default(),
+ style: AttrStyle::Outer,
+ path: ident("may_dangle").into(),
+ tts: TokenStream::new(),
+ }],
+ ident: ident("T"),
+ bounds: punctuated![TypeParamBound::Lifetime(Lifetime::new(
+ "'a",
+ Span::call_site()
+ )),],
+ default: Some(
+ TypeTuple {
+ elems: Default::default(),
+ paren_token: Default::default(),
+ }.into(),
+ ),
+ colon_token: Some(Default::default()),
+ eq_token: Default::default(),
+ }),
+ ],
+ where_clause: Some(WhereClause {
+ where_token: Default::default(),
+ predicates: punctuated![WherePredicate::Type(PredicateType {
+ lifetimes: None,
+ colon_token: Default::default(),
+ bounded_ty: TypePath {
+ qself: None,
+ path: ident("T").into(),
+ }.into(),
+ bounds: punctuated![TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path: ident("Debug").into(),
+ }),],
+ }),],
+ }),
+ };
+
+ 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 = TypeParamBound::Lifetime(Lifetime::new("'a", Span::call_site()));
+ assert_eq!(
+ expected,
+ common::parse::syn::<TypeParamBound>(tokens.into())
+ );
+
+ let tokens = quote!('_);
+ println!("{:?}", tokens);
+ let expected = TypeParamBound::Lifetime(Lifetime::new("'_", Span::call_site()));
+ assert_eq!(
+ expected,
+ common::parse::syn::<TypeParamBound>(tokens.into())
+ );
+
+ let tokens = quote!(Debug);
+ let expected = TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path: ident("Debug").into(),
+ });
+ assert_eq!(
+ expected,
+ common::parse::syn::<TypeParamBound>(tokens.into())
+ );
+
+ let tokens = quote!(?Sized);
+ let expected = TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::Maybe(Default::default()),
+ lifetimes: None,
+ path: ident("Sized").into(),
+ });
+ assert_eq!(
+ expected,
+ common::parse::syn::<TypeParamBound>(tokens.into())
+ );
+}
+
+#[test]
+fn test_fn_precedence_in_where_clause() {
+ // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not `FnOnce() -> (i32 + Send)`.
+ let sig = quote! {
+ fn f<G>()
+ where
+ G: FnOnce() -> i32 + Send,
+ {
+ }
+ };
+ let fun = common::parse::syn::<ItemFn>(sig.into());
+ let where_clause = fun.decl.generics.where_clause.as_ref().unwrap();
+ assert_eq!(where_clause.predicates.len(), 1);
+ let predicate = match where_clause.predicates[0] {
+ WherePredicate::Type(ref pred) => pred,
+ _ => panic!("wrong predicate kind"),
+ };
+ assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
+ let first_bound = &predicate.bounds[0];
+ assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32");
+ let second_bound = &predicate.bounds[1];
+ assert_eq!(quote!(#second_bound).to_string(), "Send");
+}
diff --git a/tests/test_grouping.rs b/tests/test_grouping.rs
new file mode 100644
index 0000000..96ab164
--- /dev/null
+++ b/tests/test_grouping.rs
@@ -0,0 +1,123 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(all(feature = "extra-traits", feature = "full"))]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate syn;
+use syn::token::Group;
+use syn::{BinOp, Expr, ExprBinary, ExprGroup, ExprLit, Lit};
+
+extern crate proc_macro2;
+use proc_macro2::*;
+
+#[macro_use]
+mod macros;
+
+mod common;
+
+fn expr<T: Into<Expr>>(t: T) -> Expr {
+ t.into()
+}
+
+fn lit<T: Into<Literal>>(t: T) -> Expr {
+ Expr::Lit(ExprLit {
+ attrs: Vec::new(),
+ lit: Lit::new(t.into()),
+ })
+}
+
+#[test]
+fn test_grouping() {
+ let raw: TokenStream = vec![
+ TokenTree::Literal(Literal::i32_suffixed(1)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ TokenTree::Group(proc_macro2::Group::new(
+ Delimiter::None,
+ vec![
+ TokenTree::Literal(Literal::i32_suffixed(2)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ TokenTree::Literal(Literal::i32_suffixed(3)),
+ ].into_iter()
+ .collect(),
+ )),
+ TokenTree::Punct(Punct::new('*', Spacing::Alone)),
+ TokenTree::Literal(Literal::i32_suffixed(4)),
+ ].into_iter()
+ .collect();
+
+ assert_eq!(raw.to_string(), "1i32 + 2i32 + 3i32 * 4i32");
+
+ assert_eq!(
+ common::parse::syn::<Expr>(raw),
+ expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lit(Literal::i32_suffixed(1))),
+ op: BinOp::Add(<Token![+]>::default()),
+ right: Box::new(expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(expr(ExprGroup {
+ attrs: Vec::new(),
+ group_token: Group::default(),
+ expr: Box::new(expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lit(Literal::i32_suffixed(2))),
+ op: BinOp::Add(<Token![+]>::default()),
+ right: Box::new(lit(Literal::i32_suffixed(3))),
+ })),
+ })),
+ op: BinOp::Mul(<Token![*]>::default()),
+ right: Box::new(lit(Literal::i32_suffixed(4))),
+ })),
+ })
+ );
+}
+
+#[test]
+fn test_invalid_grouping() {
+ let raw: TokenStream = vec![
+ TokenTree::Literal(Literal::i32_suffixed(1)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ TokenTree::Group(proc_macro2::Group::new(
+ Delimiter::None,
+ vec![
+ TokenTree::Literal(Literal::i32_suffixed(2)),
+ TokenTree::Punct(Punct::new('+', Spacing::Alone)),
+ ].into_iter()
+ .collect(),
+ )),
+ TokenTree::Literal(Literal::i32_suffixed(3)),
+ TokenTree::Punct(Punct::new('*', Spacing::Alone)),
+ TokenTree::Literal(Literal::i32_suffixed(4)),
+ ].into_iter()
+ .collect();
+
+ assert_eq!(raw.to_string(), "1i32 + 2i32 + 3i32 * 4i32");
+
+ assert_eq!(
+ common::parse::syn::<Expr>(raw),
+ expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lit(Literal::i32_suffixed(1))),
+ op: BinOp::Add(<Token![+]>::default()),
+ right: Box::new(lit(Literal::i32_suffixed(2))),
+ })),
+ op: BinOp::Add(<Token![+]>::default()),
+ right: Box::new(expr(ExprBinary {
+ attrs: Vec::new(),
+ left: Box::new(lit(Literal::i32_suffixed(3))),
+ op: BinOp::Mul(<Token![*]>::default()),
+ right: Box::new(lit(Literal::i32_suffixed(4))),
+ })),
+ })
+ );
+}
diff --git a/tests/test_ident.rs b/tests/test_ident.rs
new file mode 100644
index 0000000..73187d3
--- /dev/null
+++ b/tests/test_ident.rs
@@ -0,0 +1,96 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate proc_macro2;
+extern crate syn;
+
+use proc_macro2::{Ident, Span, TokenStream};
+use std::str::FromStr;
+use syn::synom::ParseError;
+
+fn parse(s: &str) -> Result<Ident, ParseError> {
+ syn::parse2(TokenStream::from_str(s).unwrap())
+}
+
+fn new(s: &str) -> Ident {
+ Ident::new(s, Span::call_site())
+}
+
+#[test]
+fn ident_parse() {
+ parse("String").unwrap();
+}
+
+#[test]
+fn ident_parse_keyword() {
+ parse("abstract").unwrap_err();
+}
+
+#[test]
+fn ident_parse_empty() {
+ parse("").unwrap_err();
+}
+
+#[test]
+fn ident_parse_lifetime() {
+ parse("'static").unwrap_err();
+}
+
+#[test]
+fn ident_parse_underscore() {
+ parse("_").unwrap_err();
+}
+
+#[test]
+fn ident_parse_number() {
+ parse("255").unwrap_err();
+}
+
+#[test]
+fn ident_parse_invalid() {
+ parse("a#").unwrap_err();
+}
+
+#[test]
+fn ident_new() {
+ new("String");
+}
+
+#[test]
+fn ident_new_keyword() {
+ new("abstract");
+}
+
+#[test]
+#[should_panic(expected = "use Option<Ident>")]
+fn ident_new_empty() {
+ new("");
+}
+
+#[test]
+#[should_panic(expected = "not a valid Ident")]
+fn ident_new_lifetime() {
+ new("'static");
+}
+
+#[test]
+fn ident_new_underscore() {
+ new("_");
+}
+
+#[test]
+#[should_panic(expected = "use Literal instead")]
+fn ident_new_number() {
+ new("255");
+}
+
+#[test]
+#[should_panic(expected = "\"a#\" is not a valid Ident")]
+fn ident_new_invalid() {
+ new("a#");
+}
diff --git a/tests/test_lit.rs b/tests/test_lit.rs
new file mode 100644
index 0000000..b0e4004
--- /dev/null
+++ b/tests/test_lit.rs
@@ -0,0 +1,196 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate proc_macro2;
+extern crate quote;
+extern crate syn;
+
+use proc_macro2::{TokenStream, TokenTree};
+use quote::ToTokens;
+use std::str::FromStr;
+use syn::{FloatSuffix, IntSuffix, Lit};
+
+fn lit(s: &str) -> Lit {
+ match TokenStream::from_str(s)
+ .unwrap()
+ .into_iter()
+ .next()
+ .unwrap()
+ {
+ TokenTree::Literal(lit) => Lit::new(lit),
+ _ => panic!(),
+ }
+}
+
+#[test]
+fn strings() {
+ fn test_string(s: &str, value: &str) {
+ match lit(s) {
+ Lit::Str(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_string(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_string("\"a\"", "a");
+ test_string("\"\\n\"", "\n");
+ test_string("\"\\r\"", "\r");
+ test_string("\"\\t\"", "\t");
+ test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
+ test_string("\"\\\"\"", "\"");
+ test_string("\"'\"", "'");
+ test_string("\"\"", "");
+ test_string("\"\\u{1F415}\"", "\u{1F415}");
+ test_string(
+ "\"contains\nnewlines\\\nescaped newlines\"",
+ "contains\nnewlinesescaped newlines",
+ );
+ test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
+}
+
+#[test]
+fn byte_strings() {
+ fn test_byte_string(s: &str, value: &[u8]) {
+ match lit(s) {
+ Lit::ByteStr(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_byte_string(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_byte_string("b\"a\"", b"a");
+ test_byte_string("b\"\\n\"", b"\n");
+ test_byte_string("b\"\\r\"", b"\r");
+ test_byte_string("b\"\\t\"", b"\t");
+ test_byte_string("b\"\\\"\"", b"\"");
+ test_byte_string("b\"'\"", b"'");
+ test_byte_string("b\"\"", b"");
+ test_byte_string(
+ "b\"contains\nnewlines\\\nescaped newlines\"",
+ b"contains\nnewlinesescaped newlines",
+ );
+ test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
+}
+
+#[test]
+fn bytes() {
+ fn test_byte(s: &str, value: u8) {
+ match lit(s) {
+ Lit::Byte(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ assert_eq!(again, s);
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_byte("b'a'", b'a');
+ test_byte("b'\\n'", b'\n');
+ test_byte("b'\\r'", b'\r');
+ test_byte("b'\\t'", b'\t');
+ test_byte("b'\\''", b'\'');
+ test_byte("b'\"'", b'"');
+}
+
+#[test]
+fn chars() {
+ fn test_char(s: &str, value: char) {
+ match lit(s) {
+ Lit::Char(lit) => {
+ assert_eq!(lit.value(), value);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_char(&again, value);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ test_char("'a'", 'a');
+ test_char("'\\n'", '\n');
+ test_char("'\\r'", '\r');
+ test_char("'\\t'", '\t');
+ test_char("'🐕'", '🐕'); // NOTE: This is an emoji
+ test_char("'\\''", '\'');
+ test_char("'\"'", '"');
+ test_char("'\\u{1F415}'", '\u{1F415}');
+}
+
+#[test]
+fn ints() {
+ fn test_int(s: &str, value: u64, suffix: IntSuffix) {
+ match lit(s) {
+ Lit::Int(lit) => {
+ assert_eq!(lit.value(), value);
+ assert_eq!(lit.suffix(), suffix);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_int(&again, value, suffix);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ use syn::IntSuffix::*;
+ test_int("5", 5, None);
+ test_int("5u32", 5, U32);
+ test_int("5_0", 50, None);
+ test_int("5_____0_____", 50, None);
+ test_int("0x7f", 127, None);
+ test_int("0x7F", 127, None);
+ test_int("0b1001", 9, None);
+ test_int("0o73", 59, None);
+ test_int("0x7Fu8", 127, U8);
+ test_int("0b1001i8", 9, I8);
+ test_int("0o73u32", 59, U32);
+ test_int("0x__7___f_", 127, None);
+ test_int("0x__7___F_", 127, None);
+ test_int("0b_1_0__01", 9, None);
+ test_int("0o_7__3", 59, None);
+ test_int("0x_7F__u8", 127, U8);
+ test_int("0b__10__0_1i8", 9, I8);
+ test_int("0o__7__________________3u32", 59, U32);
+}
+
+#[test]
+fn floats() {
+ #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
+ fn test_float(s: &str, value: f64, suffix: FloatSuffix) {
+ match lit(s) {
+ Lit::Float(lit) => {
+ assert_eq!(lit.value(), value);
+ assert_eq!(lit.suffix(), suffix);
+ let again = lit.into_token_stream().to_string();
+ if again != s {
+ test_float(&again, value, suffix);
+ }
+ }
+ wrong => panic!("{:?}", wrong),
+ }
+ }
+
+ use syn::FloatSuffix::*;
+ test_float("5.5", 5.5, None);
+ test_float("5.5E12", 5.5e12, None);
+ test_float("5.5e12", 5.5e12, None);
+ test_float("1.0__3e-12", 1.03e-12, None);
+ test_float("1.03e+12", 1.03e12, None);
+}
diff --git a/tests/test_meta_item.rs b/tests/test_meta_item.rs
new file mode 100644
index 0000000..a45e36e
--- /dev/null
+++ b/tests/test_meta_item.rs
@@ -0,0 +1,181 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "extra-traits")]
+
+extern crate proc_macro2;
+extern crate syn;
+
+use proc_macro2::{Ident, Literal, Span, TokenStream};
+use syn::buffer::TokenBuffer;
+use syn::*;
+
+#[macro_use]
+mod macros;
+
+fn lit<T: Into<Literal>>(t: T) -> Lit {
+ Lit::new(t.into())
+}
+
+fn ident(s: &str) -> Ident {
+ Ident::new(s, Span::call_site())
+}
+
+#[test]
+fn test_meta_item_word() {
+ run_test("#[foo]", Meta::Word(ident("foo")))
+}
+
+#[test]
+fn test_meta_item_name_value() {
+ run_test(
+ "#[foo = 5]",
+ MetaNameValue {
+ ident: ident("foo").into(),
+ eq_token: Default::default(),
+ lit: lit(Literal::i32_unsuffixed(5)),
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_bool_value() {
+ run_test(
+ "#[foo = true]",
+ MetaNameValue {
+ ident: ident("foo").into(),
+ eq_token: Default::default(),
+ lit: Lit::Bool(LitBool {
+ value: true,
+ span: Span::call_site(),
+ }),
+ },
+ );
+ run_test(
+ "#[foo = false]",
+ MetaNameValue {
+ ident: ident("foo").into(),
+ eq_token: Default::default(),
+ lit: Lit::Bool(LitBool {
+ value: false,
+ span: Span::call_site(),
+ }),
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_list_lit() {
+ run_test(
+ "#[foo(5)]",
+ MetaList {
+ ident: ident("foo").into(),
+ paren_token: Default::default(),
+ nested: punctuated![NestedMeta::Literal(lit(Literal::i32_unsuffixed(5)))],
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_list_word() {
+ run_test(
+ "#[foo(bar)]",
+ MetaList {
+ ident: ident("foo").into(),
+ paren_token: Default::default(),
+ nested: punctuated![NestedMeta::Meta(Meta::Word(ident("bar").into()))],
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_list_name_value() {
+ run_test(
+ "#[foo(bar = 5)]",
+ MetaList {
+ ident: ident("foo").into(),
+ paren_token: Default::default(),
+ nested: punctuated![NestedMeta::Meta(
+ MetaNameValue {
+ ident: ident("bar").into(),
+ eq_token: Default::default(),
+ lit: lit(Literal::i32_unsuffixed(5)),
+ }.into(),
+ ),],
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_list_bool_value() {
+ run_test(
+ "#[foo(bar = true)]",
+ MetaList {
+ ident: ident("foo").into(),
+ paren_token: Default::default(),
+ nested: punctuated![NestedMeta::Meta(
+ MetaNameValue {
+ ident: ident("bar").into(),
+ eq_token: Default::default(),
+ lit: Lit::Bool(LitBool {
+ value: true,
+ span: Span::call_site()
+ }),
+ }.into(),
+ ),],
+ },
+ )
+}
+
+#[test]
+fn test_meta_item_multiple() {
+ run_test(
+ "#[foo(word, name = 5, list(name2 = 6), word2)]",
+ MetaList {
+ ident: ident("foo").into(),
+ paren_token: Default::default(),
+ nested: punctuated![
+ NestedMeta::Meta(Meta::Word(ident("word").into())),
+ NestedMeta::Meta(
+ MetaNameValue {
+ ident: ident("name").into(),
+ eq_token: Default::default(),
+ lit: lit(Literal::i32_unsuffixed(5)),
+ }.into(),
+ ),
+ NestedMeta::Meta(
+ MetaList {
+ ident: ident("list").into(),
+ paren_token: Default::default(),
+ nested: punctuated![NestedMeta::Meta(
+ MetaNameValue {
+ ident: ident("name2").into(),
+ eq_token: Default::default(),
+ lit: lit(Literal::i32_unsuffixed(6)),
+ }.into(),
+ ),],
+ }.into(),
+ ),
+ NestedMeta::Meta(Meta::Word(ident("word2").into())),
+ ],
+ },
+ )
+}
+
+fn run_test<T: Into<Meta>>(input: &str, expected: T) {
+ let tokens = input.parse::<TokenStream>().unwrap();
+ let buf = TokenBuffer::new2(tokens);
+ let attr = match Attribute::parse_outer(buf.begin()) {
+ Ok((e, rest)) => {
+ assert!(rest.eof());
+ e
+ }
+ Err(err) => panic!(err),
+ };
+ assert_eq!(expected.into(), attr.interpret_meta().unwrap());
+}
diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs
new file mode 100644
index 0000000..a85bf27
--- /dev/null
+++ b/tests/test_precedence.rs
@@ -0,0 +1,365 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(all(feature = "full", feature = "fold"))]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+//! The tests in this module do the following:
+//!
+//! 1. Parse a given expression in both `syn` and `libsyntax`.
+//! 2. Fold over the expression adding brackets around each subexpression (with
+//! some complications - see the `syn_brackets` and `libsyntax_brackets`
+//! methods).
+//! 3. Serialize the `syn` expression back into a string, and re-parse it with
+//! `libsyntax`.
+//! 4. Respan all of the expressions, replacing the spans with the default
+//! spans.
+//! 5. Compare the expressions with one another, if they are not equal fail.
+
+#[macro_use]
+extern crate quote;
+extern crate rayon;
+extern crate regex;
+extern crate rustc_data_structures;
+extern crate syn;
+extern crate syntax;
+extern crate walkdir;
+
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
+use regex::Regex;
+use syntax::ast;
+use syntax::ptr::P;
+use walkdir::{DirEntry, WalkDir};
+
+use std::fs::File;
+use std::io::Read;
+use std::process;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+use common::eq::SpanlessEq;
+use common::parse;
+
+#[macro_use]
+mod macros;
+
+#[allow(dead_code)]
+mod common;
+
+/// Test some pre-set expressions chosen by us.
+#[test]
+fn test_simple_precedence() {
+ const EXPRS: &[&str] = &[
+ "1 + 2 * 3 + 4",
+ "1 + 2 * ( 3 + 4 )",
+ "{ for i in r { } *some_ptr += 1; }",
+ "{ loop { break 5; } }",
+ "{ if true { () }.mthd() }",
+ "{ for i in unsafe { 20 } { } }",
+ ];
+
+ let mut failed = 0;
+
+ for input in EXPRS {
+ let expr = if let Some(expr) = parse::syn_expr(input) {
+ expr
+ } else {
+ failed += 1;
+ continue;
+ };
+
+ let pf = match test_expressions(vec![expr]) {
+ (1, 0) => "passed",
+ (0, 1) => {
+ failed += 1;
+ "failed"
+ }
+ _ => unreachable!(),
+ };
+ errorf!("=== {}: {}\n", input, pf);
+ }
+
+ if failed > 0 {
+ panic!("Failed {} tests", failed);
+ }
+}
+
+/// Test expressions from rustc, like in `test_round_trip`.
+#[test]
+fn test_rustc_precedence() {
+ common::check_min_stack();
+ common::clone_rust();
+ let abort_after = common::abort_after();
+ if abort_after == 0 {
+ panic!("Skipping all precedence tests");
+ }
+
+ let passed = AtomicUsize::new(0);
+ let failed = AtomicUsize::new(0);
+
+ // 2018 edition is hard
+ let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();
+
+ WalkDir::new("tests/rust")
+ .sort_by(|a, b| a.file_name().cmp(b.file_name()))
+ .into_iter()
+ .filter_entry(common::base_dir_filter)
+ .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
+ .unwrap()
+ .into_par_iter()
+ .for_each(|entry| {
+ let path = entry.path();
+ if path.is_dir() {
+ return;
+ }
+
+ // Our version of `libsyntax` can't parse this tests
+ if path
+ .to_str()
+ .unwrap()
+ .ends_with("optional_comma_in_match_arm.rs")
+ {
+ return;
+ }
+
+ let mut file = File::open(path).unwrap();
+ let mut content = String::new();
+ file.read_to_string(&mut content).unwrap();
+ let content = edition_regex.replace_all(&content, "_$0");
+
+ let (l_passed, l_failed) = match syn::parse_file(&content) {
+ Ok(file) => {
+ let exprs = collect_exprs(file);
+ test_expressions(exprs)
+ }
+ Err(msg) => {
+ errorf!("syn failed to parse\n{:?}\n", msg);
+ (0, 1)
+ }
+ };
+
+ errorf!(
+ "=== {}: {} passed | {} failed\n",
+ path.display(),
+ l_passed,
+ l_failed
+ );
+
+ passed.fetch_add(l_passed, Ordering::SeqCst);
+ let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);
+
+ if prev_failed + l_failed >= abort_after {
+ process::exit(1);
+ }
+ });
+
+ let passed = passed.load(Ordering::SeqCst);
+ let failed = failed.load(Ordering::SeqCst);
+
+ errorf!("\n===== Precedence Test Results =====\n");
+ errorf!("{} passed | {} failed\n", passed, failed);
+
+ if failed > 0 {
+ panic!("{} failures", failed);
+ }
+}
+
+fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
+ let mut passed = 0;
+ let mut failed = 0;
+
+ syntax::with_globals(|| {
+ for expr in exprs {
+ let raw = quote!(#expr).to_string();
+
+ let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
+ e
+ } else {
+ failed += 1;
+ errorf!("\nFAIL - libsyntax failed to parse raw\n");
+ continue;
+ };
+
+ let syn_expr = syn_brackets(expr);
+ let syn_ast = if let Some(e) = parse::libsyntax_expr("e!(#syn_expr).to_string()) {
+ e
+ } else {
+ failed += 1;
+ errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
+ continue;
+ };
+
+ if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
+ passed += 1;
+ } else {
+ failed += 1;
+ errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
+ }
+ }
+ });
+
+ (passed, failed)
+}
+
+fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
+ parse::libsyntax_expr(input).and_then(libsyntax_brackets)
+}
+
+/// Wrap every expression which is not already wrapped in parens with parens, to
+/// reveal the precidence of the parsed expressions, and produce a stringified
+/// form of the resulting expression.
+///
+/// This method operates on libsyntax objects.
+fn libsyntax_brackets(libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
+ use rustc_data_structures::small_vec::OneVector;
+ use rustc_data_structures::thin_vec::ThinVec;
+ use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
+ use syntax::ext::quote::rt::DUMMY_SP;
+ use syntax::fold::{self, Folder};
+
+ struct BracketsFolder {
+ failed: bool,
+ };
+ impl Folder for BracketsFolder {
+ fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
+ e.map(|e| match e.node {
+ ExprKind::If(..) | ExprKind::Block(..) | ExprKind::IfLet(..) => {
+ fold::noop_fold_expr(e, self)
+ }
+ _ => Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ExprKind::Paren(P(fold::noop_fold_expr(e, self))),
+ span: DUMMY_SP,
+ attrs: ThinVec::new(),
+ },
+ })
+ }
+
+ fn fold_field(&mut self, f: Field) -> Field {
+ Field {
+ expr: if f.is_shorthand {
+ f.expr.map(|e| fold::noop_fold_expr(e, self))
+ } else {
+ self.fold_expr(f.expr)
+ },
+ ..f
+ }
+ }
+
+ // We don't want to look at expressions that might appear in patterns or
+ // types yet. We'll look into comparing those in the future. For now
+ // focus on expressions appearing in other places.
+ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
+ pat
+ }
+
+ fn fold_ty(&mut self, ty: P<Ty>) -> P<Ty> {
+ ty
+ }
+
+ fn fold_stmt(&mut self, stmt: Stmt) -> OneVector<Stmt> {
+ let node = match stmt.node {
+ // Don't wrap toplevel expressions in statements.
+ StmtKind::Expr(e) => StmtKind::Expr(e.map(|e| fold::noop_fold_expr(e, self))),
+ StmtKind::Semi(e) => StmtKind::Semi(e.map(|e| fold::noop_fold_expr(e, self))),
+ s => s,
+ };
+
+ OneVector::from_vec(vec![Stmt { node, ..stmt }])
+ }
+
+ fn fold_mac(&mut self, mac: Mac) -> Mac {
+ // By default when folding over macros, libsyntax panics. This is
+ // because it's usually not what you want, you want to run after
+ // macro expansion. We do want to do that (syn doesn't do macro
+ // expansion), so we implement fold_mac to just return the macro
+ // unchanged.
+ mac
+ }
+ }
+
+ let mut folder = BracketsFolder { failed: false };
+ let e = folder.fold_expr(libsyntax_expr);
+ if folder.failed {
+ None
+ } else {
+ Some(e)
+ }
+}
+
+/// Wrap every expression which is not already wrapped in parens with parens, to
+/// reveal the precedence of the parsed expressions, and produce a stringified
+/// form of the resulting expression.
+fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
+ use syn::fold::*;
+ use syn::*;
+
+ struct ParenthesizeEveryExpr;
+ impl Fold for ParenthesizeEveryExpr {
+ fn fold_expr(&mut self, expr: Expr) -> Expr {
+ match expr {
+ Expr::Group(_) => unreachable!(),
+ Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::IfLet(..) => {
+ fold_expr(self, expr)
+ }
+ node => Expr::Paren(ExprParen {
+ attrs: Vec::new(),
+ expr: Box::new(fold_expr(self, node)),
+ paren_token: token::Paren::default(),
+ }),
+ }
+ }
+
+ fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
+ match stmt {
+ // Don't wrap toplevel expressions in statements.
+ Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
+ Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
+ s => s,
+ }
+ }
+
+ // We don't want to look at expressions that might appear in patterns or
+ // types yet. We'll look into comparing those in the future. For now
+ // focus on expressions appearing in other places.
+ fn fold_pat(&mut self, pat: Pat) -> Pat {
+ pat
+ }
+
+ fn fold_type(&mut self, ty: Type) -> Type {
+ ty
+ }
+ }
+
+ let mut folder = ParenthesizeEveryExpr;
+ folder.fold_expr(syn_expr)
+}
+
+/// Walk through a crate collecting all expressions we can find in it.
+fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
+ use syn::fold::*;
+ use syn::punctuated::Punctuated;
+ use syn::*;
+
+ struct CollectExprs(Vec<Expr>);
+ impl Fold for CollectExprs {
+ fn fold_expr(&mut self, expr: Expr) -> Expr {
+ self.0.push(expr);
+
+ Expr::Tuple(ExprTuple {
+ attrs: vec![],
+ elems: Punctuated::new(),
+ paren_token: token::Paren::default(),
+ })
+ }
+ }
+
+ let mut folder = CollectExprs(vec![]);
+ folder.fold_file(file);
+ folder.0
+}
diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs
new file mode 100644
index 0000000..87c1a04
--- /dev/null
+++ b/tests/test_round_trip.rs
@@ -0,0 +1,156 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "full")]
+#![recursion_limit = "1024"]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate quote;
+extern crate rayon;
+extern crate syn;
+extern crate syntax;
+extern crate syntax_pos;
+extern crate walkdir;
+
+use rayon::iter::{IntoParallelIterator, ParallelIterator};
+use syntax::ast;
+use syntax::parse::{self, PResult, ParseSess};
+use syntax::source_map::FilePathMapping;
+use syntax_pos::FileName;
+use walkdir::{DirEntry, WalkDir};
+
+use std::fs::File;
+use std::io::Read;
+use std::panic;
+use std::process;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::time::Instant;
+
+#[macro_use]
+mod macros;
+
+#[allow(dead_code)]
+mod common;
+
+use common::eq::SpanlessEq;
+
+#[test]
+fn test_round_trip() {
+ common::check_min_stack();
+ common::clone_rust();
+ let abort_after = common::abort_after();
+ if abort_after == 0 {
+ panic!("Skipping all round_trip tests");
+ }
+
+ let failed = AtomicUsize::new(0);
+
+ WalkDir::new("tests/rust")
+ .sort_by(|a, b| a.file_name().cmp(b.file_name()))
+ .into_iter()
+ .filter_entry(common::base_dir_filter)
+ .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
+ .unwrap()
+ .into_par_iter()
+ .for_each(|entry| {
+ let path = entry.path();
+ if path.is_dir() {
+ return;
+ }
+
+ let mut file = File::open(path).unwrap();
+ let mut content = String::new();
+ file.read_to_string(&mut content).unwrap();
+
+ let start = Instant::now();
+ let (krate, elapsed) = match syn::parse_file(&content) {
+ Ok(krate) => (krate, start.elapsed()),
+ Err(msg) => {
+ errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
+ let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
+ if prev_failed + 1 >= abort_after {
+ process::exit(1);
+ }
+ return;
+ }
+ };
+ let back = quote!(#krate).to_string();
+
+ let equal = panic::catch_unwind(|| {
+ syntax::with_globals(|| {
+ let sess = ParseSess::new(FilePathMapping::empty());
+ let before = match libsyntax_parse(content, &sess) {
+ Ok(before) => before,
+ Err(mut diagnostic) => {
+ diagnostic.cancel();
+ if diagnostic
+ .message()
+ .starts_with("file not found for module")
+ {
+ errorf!("=== {}: ignore\n", path.display());
+ } else {
+ errorf!(
+ "=== {}: ignore - libsyntax failed to parse original content: {}\n",
+ path.display(),
+ diagnostic.message()
+ );
+ }
+ return true;
+ }
+ };
+ let after = match libsyntax_parse(back, &sess) {
+ Ok(after) => after,
+ Err(mut diagnostic) => {
+ errorf!("=== {}: libsyntax failed to parse", path.display());
+ diagnostic.emit();
+ return false;
+ }
+ };
+
+ if SpanlessEq::eq(&before, &after) {
+ errorf!(
+ "=== {}: pass in {}ms\n",
+ path.display(),
+ elapsed.as_secs() * 1000
+ + u64::from(elapsed.subsec_nanos()) / 1_000_000
+ );
+ true
+ } else {
+ errorf!(
+ "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
+ path.display(),
+ before,
+ after,
+ );
+ false
+ }
+ })
+ });
+ match equal {
+ Err(_) => errorf!("=== {}: ignoring libsyntax panic\n", path.display()),
+ Ok(true) => {}
+ Ok(false) => {
+ let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
+ if prev_failed + 1 >= abort_after {
+ process::exit(1);
+ }
+ }
+ }
+ });
+
+ let failed = failed.load(Ordering::SeqCst);
+ if failed > 0 {
+ panic!("{} failures", failed);
+ }
+}
+
+fn libsyntax_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
+ let name = FileName::Custom("test_round_trip".to_string());
+ parse::parse_crate_from_source_str(name, content, sess)
+}
diff --git a/tests/test_should_parse.rs b/tests/test_should_parse.rs
new file mode 100644
index 0000000..03096e3
--- /dev/null
+++ b/tests/test_should_parse.rs
@@ -0,0 +1,54 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate syn;
+
+macro_rules! should_parse {
+ ($name:ident, { $($in:tt)* }) => {
+ #[test]
+ fn $name() {
+ // Make sure we can parse the file!
+ syn::parse_file(stringify!($($in)*)).unwrap();
+ }
+ }
+}
+
+should_parse!(generic_associated_type, {
+ impl Foo {
+ type Item = &'a i32;
+ fn foo<'a>(&'a self) -> Self::Item<'a> {}
+ }
+});
+
+should_parse!(const_generics_use, {
+ type X = Foo<5>;
+ type Y = Foo<"foo">;
+ type Z = Foo<X>;
+ type W = Foo<{ X + 10 }>;
+});
+
+should_parse!(trailing_plus_type, {
+ type A = Box<Foo>;
+ type A = Box<Foo + 'a>;
+ type A = Box<'a + Foo>;
+});
+
+should_parse!(generic_associated_type_where, {
+ trait Foo {
+ type Item;
+ fn foo<T>(&self, t: T) -> Self::Item<T>;
+ }
+});
+
+should_parse!(match_with_block_expr, {
+ fn main() {
+ match false {
+ _ => {}.a(),
+ }
+ }
+});
diff --git a/tests/test_token_trees.rs b/tests/test_token_trees.rs
new file mode 100644
index 0000000..02d8f48
--- /dev/null
+++ b/tests/test_token_trees.rs
@@ -0,0 +1,100 @@
+// Copyright 2018 Syn Developers
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(feature = "extra-traits")]
+
+extern crate proc_macro2;
+#[macro_use]
+extern crate quote;
+extern crate syn;
+
+use proc_macro2::Delimiter::*;
+use proc_macro2::*;
+use syn::{AttrStyle, Attribute, Lit};
+
+fn alone(c: char) -> TokenTree {
+ Punct::new(c, Spacing::Alone).into()
+}
+
+fn joint(c: char) -> TokenTree {
+ Punct::new(c, Spacing::Joint).into()
+}
+
+fn delimited(delim: Delimiter, tokens: Vec<TokenTree>) -> TokenTree {
+ Group::new(delim, tokens.into_iter().collect()).into()
+}
+
+fn word(sym: &str) -> TokenTree {
+ Ident::new(sym, Span::call_site()).into()
+}
+
+#[test]
+fn test_struct() {
+ let raw = "
+ #[derive(Debug, Clone)]
+ pub struct Item {
+ pub ident: Ident,
+ pub attrs: Vec<Attribute>,
+ }
+ ";
+
+ let expected = vec![
+ alone('#'),
+ delimited(
+ Bracket,
+ vec![
+ word("derive"),
+ delimited(Parenthesis, vec![word("Debug"), alone(','), word("Clone")]),
+ ],
+ ),
+ word("pub"),
+ word("struct"),
+ word("Item"),
+ delimited(
+ Brace,
+ vec![
+ word("pub"),
+ word("ident"),
+ alone(':'),
+ word("Ident"),
+ alone(','),
+ word("pub"),
+ word("attrs"),
+ alone(':'),
+ word("Vec"),
+ alone('<'),
+ word("Attribute"),
+ joint('>'),
+ alone(','),
+ ],
+ ),
+ ];
+
+ fn wrap(tts: TokenStream) -> Attribute {
+ Attribute {
+ style: AttrStyle::Outer,
+ pound_token: Default::default(),
+ bracket_token: Default::default(),
+ path: Ident::new("test", Span::call_site()).into(),
+ tts,
+ }
+ }
+
+ let result = wrap(raw.parse().unwrap());
+ let expected = wrap(expected.into_iter().collect());
+ if result != expected {
+ panic!("{:#?}\n!=\n{:#?}", result.tts, expected.tts);
+ }
+}
+
+#[test]
+fn test_literal_mangling() {
+ let raw = "0_4";
+ let parsed: Lit = syn::parse_str(raw).unwrap();
+ assert_eq!(raw, quote!(#parsed).to_string());
+}