diff options
Diffstat (limited to 'syn')
130 files changed, 51884 insertions, 0 deletions
diff --git a/syn/.gitignore b/syn/.gitignore new file mode 100644 index 0000000..9fa6883 --- /dev/null +++ b/syn/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +tests/rust/* diff --git a/syn/.travis.yml b/syn/.travis.yml new file mode 100644 index 0000000..a8719cc --- /dev/null +++ b/syn/.travis.yml @@ -0,0 +1,76 @@ +language: rust + +before_script: + - set -o errexit + +script: + - shopt -s expand_aliases + - alias build="cargo build ${TARGET+--target=$TARGET}" + - build --no-default-features + - build + - build --features full + - build --features 'fold visit visit-mut' + - build --features 'full fold visit visit-mut' + - build --no-default-features --features derive + - build --no-default-features --features 'derive parsing' + - build --no-default-features --features 'derive printing' + - build --no-default-features --features 'proc-macro parsing printing' + - build --no-default-features --features full + - build --no-default-features --features 'full parsing' + - build --no-default-features --features 'full printing' + - build --no-default-features --features 'full parsing printing' + - build --no-default-features --features 'fold visit visit-mut parsing printing' + - build --no-default-features --features 'full fold visit visit-mut parsing printing' + +matrix: + include: + - rust: nightly + name: Tests + install: + - rustup component add rustc-dev + script: + - cargo test --all-features --release + - rust: nightly + - rust: stable + - rust: beta + - rust: 1.31.0 + - rust: nightly + name: Examples + script: + - cargo check --manifest-path examples/dump-syntax/Cargo.toml + - cargo check --manifest-path examples/heapsize/example/Cargo.toml + - cargo check --manifest-path examples/lazy-static/example/Cargo.toml + - cargo check --manifest-path examples/trace-var/example/Cargo.toml + - rust: nightly + name: Codegen + script: + - (cd codegen && cargo run) + - git diff --exit-code + - rust: nightly + name: Minimal versions + script: + - cargo update -Z minimal-versions + - cargo build --all-features + - rust: nightly + name: Clippy + script: + - rustup component add clippy || travis_terminate 0 + - cargo clippy --all-features + - rust: nightly + name: WebAssembly + env: TARGET=wasm32-unknown-unknown + install: + - rustup target add "${TARGET}" + - rust: nightly + name: WASI + env: TARGET=wasm32-wasi + install: + - rustup target add "${TARGET}" + allow_failures: + - rust: nightly + name: Clippy + fast_finish: true + +env: + global: + - RUST_MIN_STACK=20000000 diff --git a/syn/Cargo.toml b/syn/Cargo.toml new file mode 100644 index 0000000..11ad921 --- /dev/null +++ b/syn/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "syn" +version = "1.0.12" # don't forget to update html_root_url and syn.json +authors = ["David Tolnay <dtolnay@gmail.com>"] +license = "MIT OR Apache-2.0" +description = "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 = [ + "/benches/**", + "/build.rs", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src/**", + "/tests/**", +] +edition = "2018" + +[features] +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 = "1.0.7", default-features = false } +quote = { version = "1.0", optional = true, default-features = false } +unicode-xid = "0.2" + +[dev-dependencies] +anyhow = "1.0" +flate2 = "1.0" +insta = "0.12" +rayon = "1.0" +ref-cast = "1.0" +regex = "1.0" +reqwest = { version = "0.10", features = ["blocking"] } +tar = "0.4" +termcolor = "1.0" +walkdir = "2.1" + +[[bench]] +name = "rust" +harness = false +required-features = ["full", "parsing"] + +[[bench]] +name = "file" +required-features = ["full", "parsing"] + +[package.metadata.docs.rs] +all-features = true + +[package.metadata.playground] +all-features = true + +[badges] +travis-ci = { repository = "dtolnay/syn" } + +[workspace] +members = ["dev", "json"] diff --git a/syn/LICENSE-APACHE b/syn/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/syn/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/syn/LICENSE-MIT b/syn/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/syn/LICENSE-MIT @@ -0,0 +1,23 @@ +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 +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/syn/README.md b/syn/README.md new file mode 100644 index 0000000..29a7f32 --- /dev/null +++ b/syn/README.md @@ -0,0 +1,291 @@ +Parser for Rust source code +=========================== + +[![Build Status](https://api.travis-ci.org/dtolnay/syn.svg?branch=master)](https://travis-ci.org/dtolnay/syn) +[![Latest Version](https://img.shields.io/crates/v/syn.svg)](https://crates.io/crates/syn) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/syn/1.0/syn/) +[![Rustc Version 1.31+](https://img.shields.io/badge/rustc-1.31+-lightgray.svg)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.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 use in Rust procedural macros, but +contains some APIs that may be useful more generally. + +- **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`]. + +- **Derives** — Of particular interest to derive macros 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 + user-defined trait. + +- **Parsing** — Parsing in Syn is built around [parser functions] with the + signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by + Syn is individually parsable and may be used as a building block for custom + syntaxes, or you may dream up your own brand new syntax without involving any + of our syntax tree types. + +- **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/1.0/syn/struct.File.html +[`syn::Item`]: https://docs.rs/syn/1.0/syn/enum.Item.html +[`syn::Expr`]: https://docs.rs/syn/1.0/syn/enum.Expr.html +[`syn::Type`]: https://docs.rs/syn/1.0/syn/enum.Type.html +[`syn::DeriveInput`]: https://docs.rs/syn/1.0/syn/struct.DeriveInput.html +[parser functions]: https://docs.rs/syn/1.0/syn/parse/index.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 rustc 1.31 and up.* + +[*Release notes*](https://github.com/dtolnay/syn/releases) + +<br> + +## Resources + +The best way to learn about procedural macros is by writing some. Consider +working through [this procedural macro workshop][workshop] to get familiar with +the different types of procedural macros. The workshop contains relevant links +into the Syn documentation as you work through each project. + +[workshop]: https://github.com/dtolnay/proc-macro-workshop + +<br> + +## Example of a derive macro + +The canonical derive macro 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 = "1.0" +quote = "1.0" + +[lib] +proc-macro = true +``` + +```rust +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(MyMacro)] +pub fn my_macro(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + // Build the output, possibly using quasi-quotation + let expanded = quote! { + // ... + }; + + // Hand the output tokens back to the compiler + TokenStream::from(expanded) +} +``` + +The [`heapsize`] example directory shows a complete working implementation of a +derive macro. It works on any Rust compiler 1.31+. 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 derive macro 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, +} +``` + +<br> + +## Spans and error reporting + +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, +} +``` + +By tracking span information all the way through the expansion of a procedural +macro as shown in the `heapsize` 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` +``` + +<br> + +## Parsing a custom syntax + +The [`lazy-static`] example directory shows the implementation of a +`functionlike!(...)` procedural macro in which the input tokens are parsed using +Syn's parsing API. + +[`lazy-static`]: examples/lazy-static + +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(); + | ^^^ +``` + +<br> + +## Testing + +When testing macros, we often care not just that the macro can be used +successfully but also that when the macro is provided with invalid input it +produces maximally helpful error messages. Consider using the [`trybuild`] crate +to write tests for errors that are emitted by your macro or errors detected by +the Rust compiler in the expanded code following misuse of the macro. Such tests +help avoid regressions from later refactors that mistakenly make an error no +longer trigger or be less helpful than it used to be. + +[`trybuild`]: https://github.com/dtolnay/trybuild + +<br> + +## 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/ + +<br> + +## 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 derive macro, 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. + +<br> + +## Proc macro shim + +Syn operates on the token representation provided by the [proc-macro2] crate +from crates.io rather than using the compiler's built in proc-macro crate +directly. This enables code using Syn to execute outside of the context of a +procedural macro, such as in unit tests or build.rs, and we avoid needing +incompatible ecosystems for proc macros vs non-macro use cases. + +In general all of your code should be written against proc-macro2 rather than +proc-macro. The one exception is in the signatures of procedural macro entry +points, which are required by the language to use `proc_macro::TokenStream`. + +The proc-macro2 crate will automatically detect and use the compiler's data +structures when a procedural macro is active. + +[proc-macro2]: https://docs.rs/proc-macro2/1.0.0/proc_macro2/ + +<br> + +#### License + +<sup> +Licensed under either of <a href="LICENSE-APACHE">Apache License, Version +2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. +</sup> + +<br> + +<sub> +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. +</sub> diff --git a/syn/appveyor.yml b/syn/appveyor.yml new file mode 100644 index 0000000..020c8ac --- /dev/null +++ b/syn/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/syn/benches/file.rs b/syn/benches/file.rs new file mode 100644 index 0000000..58ab8df --- /dev/null +++ b/syn/benches/file.rs @@ -0,0 +1,30 @@ +// $ cargo bench --features full --bench file + +#![feature(rustc_private, test)] +#![recursion_limit = "1024"] + +extern crate test; + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[path = "../tests/common/mod.rs"] +mod common; +#[path = "../tests/repo/mod.rs"] +pub mod repo; + +use proc_macro2::TokenStream; +use std::fs; +use std::str::FromStr; +use test::Bencher; + +const FILE: &str = "tests/rust/src/libcore/str/mod.rs"; + +#[bench] +fn parse_file(b: &mut Bencher) { + repo::clone_rust(); + let content = fs::read_to_string(FILE).unwrap(); + let tokens = TokenStream::from_str(&content).unwrap(); + b.iter(|| syn::parse2::<syn::File>(tokens.clone())); +} diff --git a/syn/benches/rust.rs b/syn/benches/rust.rs new file mode 100644 index 0000000..941ecb9 --- /dev/null +++ b/syn/benches/rust.rs @@ -0,0 +1,158 @@ +// $ cargo bench --features full --bench rust +// +// Syn only, useful for profiling: +// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full --bench rust + +#![cfg_attr(not(syn_only), feature(rustc_private))] +#![recursion_limit = "1024"] + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[path = "../tests/common/mod.rs"] +mod common; +#[path = "../tests/repo/mod.rs"] +mod repo; + +use std::fs; +use std::time::{Duration, Instant}; + +#[cfg(not(syn_only))] +mod tokenstream_parse { + use proc_macro2::TokenStream; + use std::str::FromStr; + + pub fn bench(content: &str) -> Result<(), ()> { + TokenStream::from_str(content).map(drop).map_err(drop) + } +} + +mod syn_parse { + pub fn bench(content: &str) -> Result<(), ()> { + syn::parse_file(content).map(drop).map_err(drop) + } +} + +#[cfg(not(syn_only))] +mod libsyntax_parse { + extern crate rustc_data_structures; + extern crate rustc_parse; + extern crate rustc_span; + extern crate syntax; + + use rustc_data_structures::sync::Lrc; + use rustc_span::FileName; + use syntax::edition::Edition; + use syntax::errors::{emitter::Emitter, Diagnostic, Handler}; + use syntax::sess::ParseSess; + use syntax::source_map::{FilePathMapping, SourceMap}; + + pub fn bench(content: &str) -> Result<(), ()> { + struct SilentEmitter; + + impl Emitter for SilentEmitter { + fn emit_diagnostic(&mut self, _diag: &Diagnostic) {} + fn source_map(&self) -> Option<&Lrc<SourceMap>> { + None + } + } + + syntax::with_globals(Edition::Edition2018, || { + let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let emitter = Box::new(SilentEmitter); + let handler = Handler::with_emitter(false, None, emitter); + let sess = ParseSess::with_span_handler(handler, cm); + if let Err(mut diagnostic) = rustc_parse::parse_crate_from_source_str( + FileName::Custom("bench".to_owned()), + content.to_owned(), + &sess, + ) { + diagnostic.cancel(); + return Err(()); + }; + Ok(()) + }) + } +} + +#[cfg(not(syn_only))] +mod read_from_disk { + pub fn bench(content: &str) -> Result<(), ()> { + let _ = content; + Ok(()) + } +} + +fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration { + let begin = Instant::now(); + let mut success = 0; + let mut total = 0; + + walkdir::WalkDir::new("tests/rust/src") + .into_iter() + .filter_entry(repo::base_dir_filter) + .for_each(|entry| { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + return; + } + let content = fs::read_to_string(path).unwrap(); + let ok = codepath(&content).is_ok(); + success += ok as usize; + total += 1; + if !ok { + eprintln!("FAIL {}", path.display()); + } + }); + + assert_eq!(success, total); + begin.elapsed() +} + +fn main() { + repo::clone_rust(); + + macro_rules! testcases { + ($($(#[$cfg:meta])* $name:path,)*) => { + vec![ + $( + $(#[$cfg])* + (stringify!($name), $name as fn(&str) -> Result<(), ()>), + )* + ] + }; + } + + #[cfg(not(syn_only))] + { + let mut lines = 0; + let mut files = 0; + exec(|content| { + lines += content.lines().count(); + files += 1; + Ok(()) + }); + eprintln!("\n{} lines in {} files", lines, files); + } + + for (name, f) in testcases!( + #[cfg(not(syn_only))] + read_from_disk::bench, + #[cfg(not(syn_only))] + tokenstream_parse::bench, + syn_parse::bench, + #[cfg(not(syn_only))] + libsyntax_parse::bench, + ) { + eprint!("{:20}", format!("{}:", name)); + let elapsed = exec(f); + eprintln!( + "elapsed={}.{:03}s", + elapsed.as_secs(), + elapsed.subsec_millis(), + ); + } + eprintln!(); +} diff --git a/syn/build.rs b/syn/build.rs new file mode 100644 index 0000000..c6040c1 --- /dev/null +++ b/syn/build.rs @@ -0,0 +1,63 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let compiler = match rustc_version() { + Some(compiler) => compiler, + None => return, + }; + + if compiler.minor < 36 { + println!("cargo:rustc-cfg=syn_omit_await_from_token_macro"); + } + + if !compiler.nightly { + println!("cargo:rustc-cfg=syn_disable_nightly_tests"); + } +} + +struct Compiler { + minor: u32, + nightly: bool, +} + +fn rustc_version() -> Option<Compiler> { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + let minor = match u32::from_str(next) { + Ok(minor) => minor, + Err(_) => return None, + }; + + Some(Compiler { + minor, + nightly: version.contains("nightly"), + }) +} diff --git a/syn/codegen/Cargo.toml b/syn/codegen/Cargo.toml new file mode 100644 index 0000000..44d890b --- /dev/null +++ b/syn/codegen/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "syn-internal-codegen" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>", "Nika Layzell <nika@thelayzells.com>"] +edition = "2018" + +publish = false # this is an internal crate which should never be published + +[dependencies] +anyhow = "1.0" +color-backtrace = "0.2" +indexmap = { version = "1.0", features = ["serde-1"] } +inflections = "1.1" +proc-macro2 = { version = "1.0", features = ["span-locations"] } +quote = "1.0" +rustfmt = { package = "rustfmt-nightly", git = "https://github.com/rust-lang-nursery/rustfmt" } +semver = { version = "0.9", features = ["serde"] } +serde = { version = "1.0.88", features = ["derive"] } +serde_json = "1.0.38" +syn-codegen = { path = "../json" } +syn = { path = "..", features = ["full", "extra-traits"] } +thiserror = "1.0" +toml = "0.4.10" + +# work around https://github.com/crossbeam-rs/crossbeam/issues/435 +# until https://github.com/BurntSushi/ripgrep/pull/1427 is released +crossbeam-utils = "=0.6.5" + +[workspace] +# Prefer that `cargo clean` in syn's directory does not require a rebuild of +# rustfmt in the codegen directory. diff --git a/syn/codegen/README.md b/syn/codegen/README.md new file mode 100644 index 0000000..df46bd2 --- /dev/null +++ b/syn/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/syn/codegen/src/debug.rs b/syn/codegen/src/debug.rs new file mode 100644 index 0000000..9193881 --- /dev/null +++ b/syn/codegen/src/debug.rs @@ -0,0 +1,308 @@ +use crate::file; +use anyhow::Result; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::Index; +use syn_codegen::{Data, Definitions, Node, Type}; + +const DEBUG_SRC: &str = "../tests/debug/gen.rs"; + +fn rust_type(ty: &Type) -> TokenStream { + match ty { + Type::Syn(ty) => { + let ident = Ident::new(ty, Span::call_site()); + quote!(syn::#ident) + } + Type::Std(ty) => { + let ident = Ident::new(ty, Span::call_site()); + quote!(#ident) + } + Type::Ext(ty) => { + let ident = Ident::new(ty, Span::call_site()); + quote!(proc_macro2::#ident) + } + Type::Token(ty) | Type::Group(ty) => { + let ident = Ident::new(ty, Span::call_site()); + quote!(syn::token::#ident) + } + Type::Punctuated(ty) => { + let element = rust_type(&ty.element); + let punct = Ident::new(&ty.punct, Span::call_site()); + quote!(syn::punctuated::Punctuated<#element, #punct>) + } + Type::Option(ty) => { + let inner = rust_type(ty); + quote!(Option<#inner>) + } + Type::Box(ty) => { + let inner = rust_type(ty); + quote!(Box<#inner>) + } + Type::Vec(ty) => { + let inner = rust_type(ty); + quote!(Vec<#inner>) + } + Type::Tuple(ty) => { + let inner = ty.iter().map(rust_type); + quote!((#(#inner,)*)) + } + } +} + +fn is_printable(ty: &Type) -> bool { + match ty { + Type::Ext(name) => name != "Span", + Type::Box(ty) => is_printable(ty), + Type::Tuple(ty) => ty.iter().any(is_printable), + Type::Token(_) | Type::Group(_) => false, + Type::Syn(name) => name != "Reserved", + Type::Std(_) | Type::Punctuated(_) | Type::Option(_) | Type::Vec(_) => true, + } +} + +fn format_field(val: &TokenStream, ty: &Type) -> Option<TokenStream> { + if !is_printable(ty) { + return None; + } + let format = match ty { + Type::Option(ty) => { + let inner = quote!(_val); + let format = format_field(&inner, ty).map(|format| { + quote! { + formatter.write_str("(")?; + Debug::fmt(#format, formatter)?; + formatter.write_str(")")?; + } + }); + let ty = rust_type(ty); + quote!({ + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Option<#ty>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match &self.0 { + Some(#inner) => { + formatter.write_str("Some")?; + #format + Ok(()) + } + None => formatter.write_str("None"), + } + } + } + Print::ref_cast(#val) + }) + } + Type::Tuple(ty) => { + let printable: Vec<TokenStream> = ty + .iter() + .enumerate() + .filter_map(|(i, ty)| { + let index = Index::from(i); + let val = quote!(&#val.#index); + format_field(&val, ty) + }) + .collect(); + if printable.len() == 1 { + printable.into_iter().next().unwrap() + } else { + quote! { + &(#(#printable),*) + } + } + } + _ => quote! { Lite(#val) }, + }; + Some(format) +} + +fn syntax_tree_enum<'a>(outer: &str, inner: &str, fields: &'a [Type]) -> Option<&'a str> { + if fields.len() != 1 { + return None; + } + const WHITELIST: &[&str] = &["PathArguments", "Visibility"]; + match &fields[0] { + Type::Syn(ty) if WHITELIST.contains(&outer) || outer.to_owned() + inner == *ty => Some(ty), + _ => None, + } +} + +fn lookup<'a>(defs: &'a Definitions, name: &str) -> &'a Node { + for node in &defs.types { + if node.ident == name { + return node; + } + } + panic!("not found: {}", name) +} + +fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream { + let ident = Ident::new(&node.ident, Span::call_site()); + + match &node.data { + Data::Enum(variants) => { + let arms = variants.iter().map(|(v, fields)| { + let variant = Ident::new(v, Span::call_site()); + if fields.is_empty() { + quote! { + syn::#ident::#variant => formatter.write_str(#v), + } + } else if let Some(inner) = syntax_tree_enum(name, v, fields) { + let path = format!("{}::{}", name, v); + let format = expand_impl_body(defs, lookup(defs, inner), &path); + quote! { + syn::#ident::#variant(_val) => { + #format + } + } + } else if fields.len() == 1 { + let ty = &fields[0]; + let val = quote!(_val); + let format = format_field(&val, ty).map(|format| { + quote! { + formatter.write_str("(")?; + Debug::fmt(#format, formatter)?; + formatter.write_str(")")?; + } + }); + quote! { + syn::#ident::#variant(_val) => { + formatter.write_str(#v)?; + #format + Ok(()) + } + } + } else { + let pats = (0..fields.len()) + .map(|i| Ident::new(&format!("_v{}", i), Span::call_site())); + let fields = fields.iter().enumerate().filter_map(|(i, ty)| { + let index = Ident::new(&format!("_v{}", i), Span::call_site()); + let val = quote!(#index); + let format = format_field(&val, ty)?; + Some(quote! { + formatter.field(#format); + }) + }); + quote! { + syn::#ident::#variant(#(#pats),*) => { + let mut formatter = formatter.debug_tuple(#v); + #(#fields)* + formatter.finish() + } + } + } + }); + let nonexhaustive = if node.exhaustive { + None + } else { + Some(quote!(_ => unreachable!())) + }; + quote! { + match _val { + #(#arms)* + #nonexhaustive + } + } + } + Data::Struct(fields) => { + let fields = fields.iter().filter_map(|(f, ty)| { + let ident = Ident::new(f, Span::call_site()); + if let Type::Option(ty) = ty { + let inner = quote!(_val); + let format = format_field(&inner, ty).map(|format| { + quote! { + let #inner = &self.0; + formatter.write_str("(")?; + Debug::fmt(#format, formatter)?; + formatter.write_str(")")?; + } + }); + let ty = rust_type(ty); + Some(quote! { + if let Some(val) = &_val.#ident { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(#ty); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + #format + Ok(()) + } + } + formatter.field(#f, Print::ref_cast(val)); + } + }) + } else { + let val = quote!(&_val.#ident); + let format = format_field(&val, ty)?; + let mut call = quote! { + formatter.field(#f, #format); + }; + if let Type::Vec(_) | Type::Punctuated(_) = ty { + call = quote! { + if !_val.#ident.is_empty() { + #call + } + }; + } + Some(call) + } + }); + quote! { + let mut formatter = formatter.debug_struct(#name); + #(#fields)* + formatter.finish() + } + } + Data::Private => { + if node.ident == "LitInt" || node.ident == "LitFloat" { + quote! { + write!(formatter, "{}", _val) + } + } else { + quote! { + write!(formatter, "{:?}", _val.value()) + } + } + } + } +} + +fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream { + if node.ident == "Reserved" { + return TokenStream::new(); + } + + let ident = Ident::new(&node.ident, Span::call_site()); + let body = expand_impl_body(defs, node, &node.ident); + + quote! { + impl Debug for Lite<syn::#ident> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + #body + } + } + } +} + +pub fn generate(defs: &Definitions) -> Result<()> { + let mut impls = TokenStream::new(); + for node in &defs.types { + impls.extend(expand_impl(&defs, node)); + } + + file::write( + DEBUG_SRC, + quote! { + use super::{Lite, RefCast}; + use std::fmt::{self, Debug}; + + #impls + }, + )?; + + Ok(()) +} diff --git a/syn/codegen/src/file.rs b/syn/codegen/src/file.rs new file mode 100644 index 0000000..5521d75 --- /dev/null +++ b/syn/codegen/src/file.rs @@ -0,0 +1,32 @@ +use anyhow::Result; +use proc_macro2::TokenStream; +use std::fs; +use std::io::Write; +use std::path::Path; + +pub fn write<P: AsRef<Path>>(path: P, content: TokenStream) -> Result<()> { + let mut formatted = Vec::new(); + writeln!( + formatted, + "// This file is @generated by syn-internal-codegen." + )?; + writeln!(formatted, "// It is not intended for manual editing.")?; + writeln!(formatted)?; + + 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); + config.set().normalize_doc_attributes(true); + + let mut session = rustfmt::Session::new(config, Some(&mut formatted)); + session.format(rustfmt::Input::Text(content.to_string()))?; + drop(session); + + if path.as_ref().is_file() && fs::read(&path)? == formatted { + return Ok(()); + } + + fs::write(path, formatted)?; + Ok(()) +} diff --git a/syn/codegen/src/fold.rs b/syn/codegen/src/fold.rs new file mode 100644 index 0000000..6914d76 --- /dev/null +++ b/syn/codegen/src/fold.rs @@ -0,0 +1,284 @@ +use crate::{file, full, gen}; +use anyhow::Result; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::Index; +use syn_codegen::{Data, Definitions, Features, Node, Type}; + +const FOLD_SRC: &str = "../src/gen/fold.rs"; + +fn simple_visit(item: &str, name: &TokenStream) -> TokenStream { + let ident = gen::under_name(item); + let method = Ident::new(&format!("fold_{}", ident), Span::call_site()); + quote! { + f.#method(#name) + } +} + +fn visit( + ty: &Type, + features: &Features, + defs: &Definitions, + name: &TokenStream, +) -> Option<TokenStream> { + match ty { + Type::Box(t) => { + let res = visit(t, features, defs, "e!(*#name))?; + Some(quote! { + Box::new(#res) + }) + } + Type::Vec(t) => { + let operand = quote!(it); + let val = visit(t, features, defs, &operand)?; + Some(quote! { + FoldHelper::lift(#name, |it| { #val }) + }) + } + Type::Punctuated(p) => { + let operand = quote!(it); + let val = visit(&p.element, features, defs, &operand)?; + Some(quote! { + FoldHelper::lift(#name, |it| { #val }) + }) + } + Type::Option(t) => { + let it = quote!(it); + let val = visit(t, features, defs, &it)?; + Some(quote! { + (#name).map(|it| { #val }) + }) + } + Type::Tuple(t) => { + let mut code = TokenStream::new(); + for (i, elem) in t.iter().enumerate() { + let i = Index::from(i); + let it = quote!((#name).#i); + let val = visit(elem, features, defs, &it).unwrap_or(it); + code.extend(val); + code.extend(quote!(,)); + } + Some(quote! { + (#code) + }) + } + Type::Token(t) => { + let repr = &defs.tokens[t]; + let is_keyword = repr.chars().next().unwrap().is_alphabetic(); + let spans = if is_keyword { + quote!(span) + } else { + quote!(spans) + }; + let ty = if repr == "await" { + quote!(crate::token::Await) + } else { + syn::parse_str(&format!("Token![{}]", repr)).unwrap() + }; + Some(quote! { + #ty(tokens_helper(f, &#name.#spans)) + }) + } + Type::Group(t) => { + let ty = Ident::new(t, Span::call_site()); + Some(quote! { + #ty(tokens_helper(f, &#name.span)) + }) + } + Type::Syn(t) => { + fn requires_full(features: &Features) -> bool { + features.any.contains("full") && features.any.len() == 1 + } + let mut res = simple_visit(t, name); + let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap(); + if requires_full(&target.features) && !requires_full(features) { + res = quote!(full!(#res)); + } + Some(res) + } + Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)), + Type::Ext(_) | Type::Std(_) => None, + } +} + +fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) { + let under_name = gen::under_name(&s.ident); + let ty = Ident::new(&s.ident, Span::call_site()); + let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site()); + + let mut fold_impl = TokenStream::new(); + + match &s.data { + Data::Enum(variants) => { + let mut fold_variants = TokenStream::new(); + + for (variant, fields) in variants { + let variant_ident = Ident::new(variant, Span::call_site()); + + if fields.is_empty() { + fold_variants.extend(quote! { + #ty::#variant_ident => { + #ty::#variant_ident + } + }); + } else { + let mut bind_fold_fields = TokenStream::new(); + let mut fold_fields = TokenStream::new(); + + for (idx, ty) in fields.iter().enumerate() { + let name = format!("_binding_{}", idx); + let binding = Ident::new(&name, Span::call_site()); + + bind_fold_fields.extend(quote! { + #binding, + }); + + let owned_binding = quote!(#binding); + + fold_fields.extend( + visit(ty, &s.features, defs, &owned_binding).unwrap_or(owned_binding), + ); + + fold_fields.extend(quote!(,)); + } + + fold_variants.extend(quote! { + #ty::#variant_ident(#bind_fold_fields) => { + #ty::#variant_ident( + #fold_fields + ) + } + }); + } + } + + let nonexhaustive = if s.exhaustive { + None + } else { + Some(quote!(_ => unreachable!())) + }; + + fold_impl.extend(quote! { + match node { + #fold_variants + #nonexhaustive + } + }); + } + Data::Struct(fields) => { + let mut fold_fields = TokenStream::new(); + + for (field, ty) in fields { + let id = Ident::new(&field, Span::call_site()); + let ref_toks = quote!(node.#id); + + if let Type::Syn(ty) = ty { + if ty == "Reserved" { + fold_fields.extend(quote! { + #id: #ref_toks, + }); + continue; + } + } + + let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks); + + fold_fields.extend(quote! { + #id: #fold, + }); + } + + if !fields.is_empty() { + fold_impl.extend(quote! { + #ty { + #fold_fields + } + }) + } else { + if ty == "Ident" { + fold_impl.extend(quote! { + let mut node = node; + let span = f.fold_span(node.span()); + node.set_span(span); + }); + } + fold_impl.extend(quote! { + node + }); + } + } + Data::Private => { + if ty == "Ident" { + fold_impl.extend(quote! { + let mut node = node; + let span = f.fold_span(node.span()); + node.set_span(span); + }); + } + fold_impl.extend(quote! { + node + }); + } + } + + let fold_span_only = + s.data == Data::Private && !gen::TERMINAL_TYPES.contains(&s.ident.as_str()); + if fold_span_only { + fold_impl = quote! { + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node + }; + } + + traits.extend(quote! { + fn #fold_fn(&mut self, i: #ty) -> #ty { + #fold_fn(self, i) + } + }); + + impls.extend(quote! { + pub fn #fold_fn<F>(f: &mut F, node: #ty) -> #ty + where + F: Fold + ?Sized, + { + #fold_impl + } + }); +} + +pub fn generate(defs: &Definitions) -> Result<()> { + let (traits, impls) = gen::traverse(defs, node); + let full_macro = full::get_macro(); + file::write( + FOLD_SRC, + quote! { + // Unreachable code is generated sometimes without the full feature. + #![allow(unreachable_code, unused_variables)] + + use crate::*; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::token::{Brace, Bracket, Paren, Group}; + use proc_macro2::Span; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::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]: self + /// + /// *This trait is available if Syn is built with the `"fold"` feature.* + pub trait Fold { + #traits + } + + #impls + }, + )?; + Ok(()) +} diff --git a/syn/codegen/src/full.rs b/syn/codegen/src/full.rs new file mode 100644 index 0000000..a410031 --- /dev/null +++ b/syn/codegen/src/full.rs @@ -0,0 +1,20 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub fn get_macro() -> TokenStream { + quote! { + #[cfg(feature = "full")] + macro_rules! full { + ($e:expr) => { + $e + }; + } + + #[cfg(all(feature = "derive", not(feature = "full")))] + macro_rules! full { + ($e:expr) => { + unreachable!() + }; + } + } +} diff --git a/syn/codegen/src/gen.rs b/syn/codegen/src/gen.rs new file mode 100644 index 0000000..ef43182 --- /dev/null +++ b/syn/codegen/src/gen.rs @@ -0,0 +1,45 @@ +use inflections::Inflect; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn_codegen::{Data, Definitions, Features, Node}; + +pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"]; + +pub fn under_name(name: &str) -> Ident { + Ident::new(&name.to_snake_case(), Span::call_site()) +} + +pub fn traverse( + defs: &Definitions, + node: fn(&mut TokenStream, &mut TokenStream, &Node, &Definitions), +) -> (TokenStream, TokenStream) { + let mut types = defs.types.clone(); + for terminal in TERMINAL_TYPES { + types.push(Node { + ident: terminal.to_string(), + features: Features::default(), + data: Data::Private, + exhaustive: true, + }); + } + types.sort_by(|a, b| a.ident.cmp(&b.ident)); + + let mut traits = TokenStream::new(); + let mut impls = TokenStream::new(); + for s in types { + if s.ident == "Reserved" { + continue; + } + let features = &s.features.any; + let features = match features.len() { + 0 => quote!(), + 1 => quote!(#[cfg(feature = #(#features)*)]), + _ => quote!(#[cfg(any(#(feature = #features),*))]), + }; + traits.extend(features.clone()); + impls.extend(features); + node(&mut traits, &mut impls, &s, defs); + } + + (traits, impls) +} diff --git a/syn/codegen/src/json.rs b/syn/codegen/src/json.rs new file mode 100644 index 0000000..53904bf --- /dev/null +++ b/syn/codegen/src/json.rs @@ -0,0 +1,18 @@ +use anyhow::Result; +use std::fs; +use std::path::Path; +use syn_codegen::Definitions; + +pub fn generate(defs: &Definitions) -> Result<()> { + let mut j = serde_json::to_string_pretty(&defs)?; + j.push('\n'); + + let check: Definitions = serde_json::from_str(&j)?; + assert_eq!(*defs, check); + + let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR")); + let json_path = codegen_root.join("../syn.json"); + fs::write(json_path, j)?; + + Ok(()) +} diff --git a/syn/codegen/src/main.rs b/syn/codegen/src/main.rs new file mode 100644 index 0000000..9b1b5dd --- /dev/null +++ b/syn/codegen/src/main.rs @@ -0,0 +1,36 @@ +// This crate crawls the Syn source directory to find all structs and enums that +// form the Syn syntax tree. +// +// A machine-readable representation of the syntax tree is saved to syn.json in +// the repo root for other code generation tools to consume. The syn-codegen +// crate (https://docs.rs/syn-codegen/) provides the data structures for parsing +// and making use of syn.json from Rust code. +// +// Finally this crate generates the Visit, VisitMut, and Fold traits in Syn +// programmatically from the syntax tree description. + +#![recursion_limit = "128"] +#![allow(clippy::needless_pass_by_value)] + +mod debug; +mod file; +mod fold; +mod full; +mod gen; +mod json; +mod operand; +mod parse; +mod version; +mod visit; +mod visit_mut; + +fn main() -> anyhow::Result<()> { + color_backtrace::install(); + let defs = parse::parse()?; + json::generate(&defs)?; + fold::generate(&defs)?; + visit::generate(&defs)?; + visit_mut::generate(&defs)?; + debug::generate(&defs)?; + Ok(()) +} diff --git a/syn/codegen/src/operand.rs b/syn/codegen/src/operand.rs new file mode 100644 index 0000000..db3bd18 --- /dev/null +++ b/syn/codegen/src/operand.rs @@ -0,0 +1,38 @@ +use proc_macro2::TokenStream; +use quote::quote; + +pub enum Operand { + Borrowed(TokenStream), + Owned(TokenStream), +} + +pub use self::Operand::*; + +impl Operand { + pub fn tokens(&self) -> &TokenStream { + match self { + Borrowed(n) | Owned(n) => n, + } + } + + pub fn ref_tokens(&self) -> TokenStream { + match self { + Borrowed(n) => n.clone(), + Owned(n) => quote!(&#n), + } + } + + pub fn ref_mut_tokens(&self) -> TokenStream { + match self { + Borrowed(n) => n.clone(), + Owned(n) => quote!(&mut #n), + } + } + + pub fn owned_tokens(&self) -> TokenStream { + match self { + Borrowed(n) => quote!(*#n), + Owned(n) => n.clone(), + } + } +} diff --git a/syn/codegen/src/parse.rs b/syn/codegen/src/parse.rs new file mode 100644 index 0000000..cdd6085 --- /dev/null +++ b/syn/codegen/src/parse.rs @@ -0,0 +1,657 @@ +use crate::version; +use anyhow::{bail, Result}; +use indexmap::IndexMap; +use quote::quote; +use syn::parse::Parser; +use syn::{parse_quote, Data, DataStruct, DeriveInput, Ident, Item}; +use syn_codegen as types; +use thiserror::Error; + +use std::collections::BTreeMap; +use std::fs; +use std::path::{Path, PathBuf}; + +const SYN_CRATE_ROOT: &str = "../src/lib.rs"; +const TOKEN_SRC: &str = "../src/token.rs"; +const IGNORED_MODS: &[&str] = &["fold", "visit", "visit_mut"]; +const EXTRA_TYPES: &[&str] = &["Lifetime"]; +const NONEXHAUSTIVE: &str = "__Nonexhaustive"; + +// NOTE: BTreeMap is used here instead of HashMap to have deterministic output. +type ItemLookup = BTreeMap<Ident, AstItem>; +type TokenLookup = BTreeMap<String, String>; + +/// Parse the contents of `src` and return a list of AST types. +pub fn parse() -> Result<types::Definitions> { + let mut item_lookup = BTreeMap::new(); + load_file(SYN_CRATE_ROOT, &[], &mut item_lookup)?; + + let token_lookup = load_token_file(TOKEN_SRC)?; + + let version = version::get()?; + + let types = item_lookup + .values() + .map(|item| introspect_item(item, &item_lookup, &token_lookup)) + .collect(); + + let tokens = token_lookup + .into_iter() + .map(|(name, ty)| (ty, name)) + .collect(); + + Ok(types::Definitions { + version, + types, + tokens, + }) +} + +/// Data extracted from syn source +#[derive(Clone)] +pub struct AstItem { + ast: DeriveInput, + features: Vec<syn::Attribute>, +} + +fn introspect_item(item: &AstItem, items: &ItemLookup, tokens: &TokenLookup) -> types::Node { + let features = introspect_features(&item.features); + + match &item.ast.data { + Data::Enum(ref data) => types::Node { + ident: item.ast.ident.to_string(), + features, + data: types::Data::Enum(introspect_enum(data, items, tokens)), + exhaustive: data.variants.iter().all(|v| v.ident != NONEXHAUSTIVE), + }, + Data::Struct(ref data) => types::Node { + ident: item.ast.ident.to_string(), + features, + data: { + if data.fields.iter().all(|f| is_pub(&f.vis)) { + types::Data::Struct(introspect_struct(data, items, tokens)) + } else { + types::Data::Private + } + }, + exhaustive: true, + }, + Data::Union(..) => panic!("Union not supported"), + } +} + +fn introspect_enum( + item: &syn::DataEnum, + items: &ItemLookup, + tokens: &TokenLookup, +) -> types::Variants { + item.variants + .iter() + .filter_map(|variant| { + if variant.ident == NONEXHAUSTIVE { + return None; + } + let fields = match &variant.fields { + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .map(|field| introspect_type(&field.ty, items, tokens)) + .collect(), + syn::Fields::Unit => vec![], + _ => panic!("Enum representation not supported"), + }; + Some((variant.ident.to_string(), fields)) + }) + .collect() +} + +fn introspect_struct( + item: &syn::DataStruct, + items: &ItemLookup, + tokens: &TokenLookup, +) -> types::Fields { + match &item.fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .map(|field| { + ( + field.ident.as_ref().unwrap().to_string(), + introspect_type(&field.ty, items, tokens), + ) + }) + .collect(), + syn::Fields::Unit => IndexMap::new(), + _ => panic!("Struct representation not supported"), + } +} + +fn introspect_type(item: &syn::Type, items: &ItemLookup, tokens: &TokenLookup) -> types::Type { + match item { + syn::Type::Path(syn::TypePath { + qself: None, + ref path, + }) => { + let last = path.segments.last().unwrap(); + let string = last.ident.to_string(); + + match string.as_str() { + "Option" => { + let nested = introspect_type(first_arg(&last.arguments), items, tokens); + types::Type::Option(Box::new(nested)) + } + "Punctuated" => { + let nested = introspect_type(first_arg(&last.arguments), items, tokens); + let punct = match introspect_type(last_arg(&last.arguments), items, tokens) { + types::Type::Token(s) => s, + _ => panic!(), + }; + + types::Type::Punctuated(types::Punctuated { + element: Box::new(nested), + punct, + }) + } + "Vec" => { + let nested = introspect_type(first_arg(&last.arguments), items, tokens); + types::Type::Vec(Box::new(nested)) + } + "Box" => { + let nested = introspect_type(first_arg(&last.arguments), items, tokens); + types::Type::Box(Box::new(nested)) + } + "Brace" | "Bracket" | "Paren" | "Group" => types::Type::Group(string), + "TokenStream" | "Literal" | "Ident" | "Span" => types::Type::Ext(string), + "String" | "u32" | "usize" | "bool" => types::Type::Std(string), + "Await" => types::Type::Token("Await".to_string()), + _ => { + if items.get(&last.ident).is_some() || last.ident == "Reserved" { + types::Type::Syn(string) + } else { + unimplemented!("{}", string); + } + } + } + } + syn::Type::Tuple(syn::TypeTuple { ref elems, .. }) => { + let tys = elems + .iter() + .map(|ty| introspect_type(&ty, items, tokens)) + .collect(); + types::Type::Tuple(tys) + } + syn::Type::Macro(syn::TypeMacro { ref mac }) + if mac.path.segments.last().unwrap().ident == "Token" => + { + let content = mac.tokens.to_string(); + let ty = tokens.get(&content).unwrap().to_string(); + + types::Type::Token(ty) + } + _ => panic!("{}", quote!(#item).to_string()), + } +} + +fn introspect_features(attrs: &[syn::Attribute]) -> types::Features { + let mut ret = types::Features::default(); + + for attr in attrs { + if !attr.path.is_ident("cfg") { + continue; + } + + let features = parsing::parse_features.parse2(attr.tokens.clone()).unwrap(); + + if ret.any.is_empty() { + ret = features; + } else if ret.any.len() < features.any.len() { + assert!(ret.any.iter().all(|f| features.any.contains(f))); + } else { + assert!(features.any.iter().all(|f| ret.any.contains(f))); + ret = features; + } + } + + ret +} + +fn is_pub(vis: &syn::Visibility) -> bool { + match vis { + syn::Visibility::Public(_) => true, + _ => false, + } +} + +fn first_arg(params: &syn::PathArguments) -> &syn::Type { + let data = match *params { + syn::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") + { + syn::GenericArgument::Type(ref ty) => ty, + _ => panic!("Expected at least 1 type argument here"), + } +} + +fn last_arg(params: &syn::PathArguments) -> &syn::Type { + let data = match *params { + syn::PathArguments::AngleBracketed(ref data) => data, + _ => panic!("Expected at least 1 type argument here"), + }; + + match *data + .args + .last() + .expect("Expected at least 1 type argument here") + { + syn::GenericArgument::Type(ref ty) => ty, + _ => panic!("Expected at least 1 type argument here"), + } +} + +mod parsing { + use super::{AstItem, TokenLookup}; + + use proc_macro2::{TokenStream, TokenTree}; + use quote::quote; + use syn; + use syn::parse::{ParseStream, Result}; + use syn::*; + use syn_codegen as types; + + use std::collections::{BTreeMap, BTreeSet}; + + fn peek_tag(input: ParseStream, tag: &str) -> bool { + let ahead = input.fork(); + ahead.parse::<Token![#]>().is_ok() + && ahead + .parse::<Ident>() + .map(|ident| ident == tag) + .unwrap_or(false) + } + + // Parses #full - returns #[cfg(feature = "full")] if it is present, and + // nothing otherwise. + fn full(input: ParseStream) -> Vec<syn::Attribute> { + if peek_tag(input, "full") { + input.parse::<Token![#]>().unwrap(); + input.parse::<Ident>().unwrap(); + vec![parse_quote!(#[cfg(feature = "full")])] + } else { + vec![] + } + } + + fn skip_manual_extra_traits(input: ParseStream) { + if peek_tag(input, "manual_extra_traits") || peek_tag(input, "manual_extra_traits_debug") { + input.parse::<Token![#]>().unwrap(); + input.parse::<Ident>().unwrap(); + } + } + + // Parses a simple AstStruct without the `pub struct` prefix. + fn ast_struct_inner(input: ParseStream) -> Result<AstItem> { + let ident: Ident = input.parse()?; + let features = full(input); + skip_manual_extra_traits(input); + let rest: TokenStream = input.parse()?; + Ok(AstItem { + ast: syn::parse2(quote! { + pub struct #ident #rest + })?, + features, + }) + } + + pub fn ast_struct(input: ParseStream) -> Result<AstItem> { + input.call(Attribute::parse_outer)?; + input.parse::<Token![pub]>()?; + input.parse::<Token![struct]>()?; + let res = input.call(ast_struct_inner)?; + Ok(res) + } + + fn no_visit(input: ParseStream) -> bool { + if peek_tag(input, "no_visit") { + input.parse::<Token![#]>().unwrap(); + input.parse::<Ident>().unwrap(); + true + } else { + false + } + } + + pub fn ast_enum(input: ParseStream) -> Result<Option<AstItem>> { + input.call(Attribute::parse_outer)?; + input.parse::<Token![pub]>()?; + input.parse::<Token![enum]>()?; + let ident: Ident = input.parse()?; + skip_manual_extra_traits(input); + let no_visit = no_visit(input); + let rest: TokenStream = input.parse()?; + Ok(if no_visit { + None + } else { + Some(AstItem { + ast: syn::parse2(quote! { + pub enum #ident #rest + })?, + features: vec![], + }) + }) + } + + // A single variant of an ast_enum_of_structs! + struct EosVariant { + name: Ident, + member: Option<Path>, + } + fn eos_variant(input: ParseStream) -> Result<EosVariant> { + input.call(Attribute::parse_outer)?; + let variant: Ident = input.parse()?; + let member = if input.peek(token::Paren) { + let content; + parenthesized!(content in input); + let path: Path = content.parse()?; + Some(path) + } else { + None + }; + input.parse::<Token![,]>()?; + Ok(EosVariant { + name: variant, + member, + }) + } + + pub fn ast_enum_of_structs(input: ParseStream) -> Result<AstItem> { + input.call(Attribute::parse_outer)?; + input.parse::<Token![pub]>()?; + input.parse::<Token![enum]>()?; + let ident: Ident = input.parse()?; + skip_manual_extra_traits(input); + + let content; + braced!(content in input); + let mut variants = Vec::new(); + while !content.is_empty() { + variants.push(content.call(eos_variant)?); + } + + if let Some(ident) = input.parse::<Option<Ident>>()? { + assert_eq!(ident, "do_not_generate_to_tokens"); + } + + let enum_item = { + let variants = variants.iter().map(|v| { + let name = v.name.clone(); + match v.member { + Some(ref member) => quote!(#name(#member)), + None => quote!(#name), + } + }); + parse_quote! { + pub enum #ident { + #(#variants),* + } + } + }; + Ok(AstItem { + ast: enum_item, + features: vec![], + }) + } + + mod kw { + syn::custom_keyword!(macro_rules); + syn::custom_keyword!(Token); + } + + pub fn parse_token_macro(input: ParseStream) -> Result<TokenLookup> { + input.parse::<TokenTree>()?; + input.parse::<Token![=>]>()?; + + let definition; + braced!(definition in input); + definition.call(Attribute::parse_outer)?; + definition.parse::<kw::macro_rules>()?; + definition.parse::<Token![!]>()?; + definition.parse::<kw::Token>()?; + + let rules; + braced!(rules in definition); + input.parse::<Token![;]>()?; + + let mut tokens = BTreeMap::new(); + while !rules.is_empty() { + if rules.peek(Token![$]) { + rules.parse::<Token![$]>()?; + rules.parse::<TokenTree>()?; + rules.parse::<Token![*]>()?; + tokens.insert("await".to_owned(), "Await".to_owned()); + } else { + let pattern; + parenthesized!(pattern in rules); + let token = pattern.parse::<TokenStream>()?.to_string(); + rules.parse::<Token![=>]>()?; + let expansion; + braced!(expansion in rules); + rules.parse::<Token![;]>()?; + expansion.parse::<Token![$]>()?; + let path: Path = expansion.parse()?; + let ty = path.segments.last().unwrap().ident.to_string(); + tokens.insert(token, ty.to_string()); + } + } + Ok(tokens) + } + + fn parse_feature(input: ParseStream) -> Result<String> { + let i: syn::Ident = input.parse()?; + assert_eq!(i, "feature"); + + input.parse::<Token![=]>()?; + let s = input.parse::<syn::LitStr>()?; + + Ok(s.value()) + } + + pub fn parse_features(input: ParseStream) -> Result<types::Features> { + let mut features = BTreeSet::new(); + + let level_1; + parenthesized!(level_1 in input); + + let i: syn::Ident = level_1.fork().parse()?; + + if i == "any" { + level_1.parse::<syn::Ident>()?; + + let level_2; + parenthesized!(level_2 in level_1); + + while !level_2.is_empty() { + features.insert(parse_feature(&level_2)?); + + if !level_2.is_empty() { + level_2.parse::<Token![,]>()?; + } + } + } else if i == "feature" { + features.insert(parse_feature(&level_1)?); + assert!(level_1.is_empty()); + } else { + panic!("{:?}", i); + } + + assert!(input.is_empty()); + + Ok(types::Features { any: features }) + } +} + +fn get_features(attrs: &[syn::Attribute], base: &[syn::Attribute]) -> Vec<syn::Attribute> { + let mut ret = base.to_owned(); + + for attr in attrs { + if attr.path.is_ident("cfg") { + ret.push(attr.clone()); + } + } + + ret +} + +#[derive(Error, Debug)] +#[error("{path}:{line}:{column}: {error}")] +struct LoadFileError { + path: PathBuf, + line: usize, + column: usize, + error: syn::Error, +} + +fn load_file<P: AsRef<Path>>( + name: P, + features: &[syn::Attribute], + lookup: &mut ItemLookup, +) -> Result<()> { + let error = match do_load_file(&name, features, lookup).err() { + None => return Ok(()), + Some(error) => error, + }; + + let error = error.downcast::<syn::Error>()?; + let span = error.span().start(); + + bail!(LoadFileError { + path: name.as_ref().to_owned(), + line: span.line, + column: span.column + 1, + error, + }) +} + +fn do_load_file<P: AsRef<Path>>( + name: P, + features: &[syn::Attribute], + lookup: &mut ItemLookup, +) -> Result<()> { + let name = name.as_ref(); + let parent = name.parent().expect("no parent path"); + + // Parse the file + let src = fs::read_to_string(name)?; + let file = syn::parse_file(&src)?; + + // 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" { + vec![parse_quote!(#[cfg(feature = "derive")])] + } else { + get_features(&item.attrs, features) + }; + + // Look up the submodule file, and recursively parse it. + // Only handles same-directory .rs file submodules for now. + 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); + + // Try to parse the AstItem declaration out of the item. + let tts = item.mac.tokens.clone(); + let found = if item.mac.path.is_ident("ast_struct") { + Some(parsing::ast_struct.parse2(tts)?) + } else if item.mac.path.is_ident("ast_enum") { + parsing::ast_enum.parse2(tts)? + } else if item.mac.path.is_ident("ast_enum_of_structs") { + Some(parsing::ast_enum_of_structs.parse2(tts)?) + } else { + continue; + }; + + // Record our features on the parsed AstItems. + for mut item in found { + if item.ast.ident != "Reserved" { + item.features.extend(features.clone()); + 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.to_owned(), + }, + ); + } + } + _ => {} + } + } + Ok(()) +} + +fn load_token_file<P: AsRef<Path>>(name: P) -> Result<TokenLookup> { + let name = name.as_ref(); + let src = fs::read_to_string(name)?; + let file = syn::parse_file(&src)?; + for item in file.items { + match item { + Item::Macro(item) => { + match item.ident { + Some(ref i) if i == "export_token_macro" => {} + _ => continue, + } + let tokens = item.mac.parse_body_with(parsing::parse_token_macro)?; + return Ok(tokens); + } + _ => {} + } + } + + panic!("failed to parse Token macro") +} diff --git a/syn/codegen/src/version.rs b/syn/codegen/src/version.rs new file mode 100644 index 0000000..9374624 --- /dev/null +++ b/syn/codegen/src/version.rs @@ -0,0 +1,24 @@ +use anyhow::Result; +use semver::Version; +use serde::Deserialize; + +use std::fs; +use std::path::Path; + +pub fn get() -> Result<Version> { + let codegen_root = Path::new(env!("CARGO_MANIFEST_DIR")); + let syn_cargo_toml = codegen_root.join("../Cargo.toml"); + let manifest = fs::read_to_string(syn_cargo_toml)?; + let parsed: Manifest = toml::from_str(&manifest)?; + Ok(parsed.package.version) +} + +#[derive(Debug, Deserialize)] +struct Manifest { + package: Package, +} + +#[derive(Debug, Deserialize)] +struct Package { + version: Version, +} diff --git a/syn/codegen/src/visit.rs b/syn/codegen/src/visit.rs new file mode 100644 index 0000000..41bc9e9 --- /dev/null +++ b/syn/codegen/src/visit.rs @@ -0,0 +1,265 @@ +use crate::operand::{Borrowed, Operand, Owned}; +use crate::{file, full, gen}; +use anyhow::Result; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::Index; +use syn_codegen::{Data, Definitions, Features, Node, Type}; + +const VISIT_SRC: &str = "../src/gen/visit.rs"; + +fn simple_visit(item: &str, name: &Operand) -> TokenStream { + let ident = gen::under_name(item); + let method = Ident::new(&format!("visit_{}", ident), Span::call_site()); + let name = name.ref_tokens(); + quote! { + v.#method(#name) + } +} + +fn noop_visit(name: &Operand) -> TokenStream { + let name = name.tokens(); + quote! { + skip!(#name) + } +} + +fn visit( + ty: &Type, + features: &Features, + defs: &Definitions, + name: &Operand, +) -> Option<TokenStream> { + match ty { + Type::Box(t) => { + let name = name.owned_tokens(); + visit(t, features, defs, &Owned(quote!(*#name))) + } + Type::Vec(t) => { + let operand = Borrowed(quote!(it)); + let val = visit(t, features, defs, &operand)?; + let name = name.ref_tokens(); + Some(quote! { + for it in #name { + #val + } + }) + } + Type::Punctuated(p) => { + let operand = Borrowed(quote!(it)); + let val = visit(&p.element, features, defs, &operand)?; + let name = name.ref_tokens(); + Some(quote! { + for el in Punctuated::pairs(#name) { + let (it, p) = el.into_tuple(); + #val; + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + }) + } + Type::Option(t) => { + let it = Borrowed(quote!(it)); + let val = visit(t, features, defs, &it)?; + let name = name.owned_tokens(); + Some(quote! { + if let Some(it) = &#name { + #val + } + }) + } + Type::Tuple(t) => { + let mut code = TokenStream::new(); + for (i, elem) in t.iter().enumerate() { + let name = name.tokens(); + let i = Index::from(i); + let it = Owned(quote!((#name).#i)); + let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it)); + code.extend(val); + code.extend(quote!(;)); + } + Some(code) + } + Type::Token(t) => { + let name = name.tokens(); + let repr = &defs.tokens[t]; + let is_keyword = repr.chars().next().unwrap().is_alphabetic(); + let spans = if is_keyword { + quote!(span) + } else { + quote!(spans) + }; + Some(quote! { + tokens_helper(v, &#name.#spans) + }) + } + Type::Group(_) => { + let name = name.tokens(); + Some(quote! { + tokens_helper(v, &#name.span) + }) + } + Type::Syn(t) => { + fn requires_full(features: &Features) -> bool { + features.any.contains("full") && features.any.len() == 1 + } + let mut res = simple_visit(t, name); + let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap(); + if requires_full(&target.features) && !requires_full(features) { + res = quote!(full!(#res)); + } + Some(res) + } + Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)), + Type::Ext(_) | Type::Std(_) => None, + } +} + +fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) { + let under_name = gen::under_name(&s.ident); + let ty = Ident::new(&s.ident, Span::call_site()); + let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site()); + + let mut visit_impl = TokenStream::new(); + + match &s.data { + Data::Enum(variants) => { + let mut visit_variants = TokenStream::new(); + + for (variant, fields) in variants { + let variant_ident = Ident::new(variant, Span::call_site()); + + if fields.is_empty() { + visit_variants.extend(quote! { + #ty::#variant_ident => {} + }); + } else { + let mut bind_visit_fields = TokenStream::new(); + let mut visit_fields = TokenStream::new(); + + for (idx, ty) in fields.iter().enumerate() { + let name = format!("_binding_{}", idx); + let binding = Ident::new(&name, Span::call_site()); + + bind_visit_fields.extend(quote! { + #binding, + }); + + let borrowed_binding = Borrowed(quote!(#binding)); + + visit_fields.extend( + visit(ty, &s.features, defs, &borrowed_binding) + .unwrap_or_else(|| noop_visit(&borrowed_binding)), + ); + + visit_fields.extend(quote!(;)); + } + + visit_variants.extend(quote! { + #ty::#variant_ident(#bind_visit_fields) => { + #visit_fields + } + }); + } + } + + let nonexhaustive = if s.exhaustive { + None + } else { + Some(quote!(_ => unreachable!())) + }; + + visit_impl.extend(quote! { + match node { + #visit_variants + #nonexhaustive + } + }); + } + Data::Struct(fields) => { + for (field, ty) in fields { + if let Type::Syn(ty) = ty { + if ty == "Reserved" { + continue; + } + } + + let id = Ident::new(&field, Span::call_site()); + let ref_toks = Owned(quote!(node.#id)); + let visit_field = visit(&ty, &s.features, defs, &ref_toks) + .unwrap_or_else(|| noop_visit(&ref_toks)); + visit_impl.extend(quote! { + #visit_field; + }); + } + } + Data::Private => { + if ty == "Ident" { + visit_impl.extend(quote! { + v.visit_span(&node.span()); + }); + } + } + } + + let ast_lifetime = if s.ident == "Span" { + None + } else { + Some(quote!('ast)) + }; + + traits.extend(quote! { + fn #visit_fn(&mut self, i: &#ast_lifetime #ty) { + #visit_fn(self, i) + } + }); + + impls.extend(quote! { + pub fn #visit_fn<'ast, V>(v: &mut V, node: &#ast_lifetime #ty) + where + V: Visit<'ast> + ?Sized, + { + #visit_impl + } + }); +} + +pub fn generate(defs: &Definitions) -> Result<()> { + let (traits, impls) = gen::traverse(defs, node); + let full_macro = full::get_macro(); + file::write( + VISIT_SRC, + quote! { + #![allow(unused_variables)] + + use crate::*; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::punctuated::Punctuated; + use proc_macro2::Span; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::gen::helper::visit::*; + + #full_macro + + #[cfg(any(feature = "full", feature = "derive"))] + macro_rules! skip { + ($($tt:tt)*) => {}; + } + + /// Syntax tree traversal to walk a shared borrow of a syntax tree. + /// + /// See the [module documentation] for details. + /// + /// [module documentation]: self + /// + /// *This trait is available if Syn is built with the `"visit"` feature.* + pub trait Visit<'ast> { + #traits + } + + #impls + }, + )?; + Ok(()) +} diff --git a/syn/codegen/src/visit_mut.rs b/syn/codegen/src/visit_mut.rs new file mode 100644 index 0000000..71e56b3 --- /dev/null +++ b/syn/codegen/src/visit_mut.rs @@ -0,0 +1,262 @@ +use crate::operand::{Borrowed, Operand, Owned}; +use crate::{file, full, gen}; +use anyhow::Result; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::Index; +use syn_codegen::{Data, Definitions, Features, Node, Type}; + +const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs"; + +fn simple_visit(item: &str, name: &Operand) -> TokenStream { + let ident = gen::under_name(item); + let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site()); + let name = name.ref_mut_tokens(); + quote! { + v.#method(#name) + } +} + +fn noop_visit(name: &Operand) -> TokenStream { + let name = name.tokens(); + quote! { + skip!(#name) + } +} + +fn visit( + ty: &Type, + features: &Features, + defs: &Definitions, + name: &Operand, +) -> Option<TokenStream> { + match ty { + Type::Box(t) => { + let name = name.owned_tokens(); + visit(t, features, defs, &Owned(quote!(*#name))) + } + Type::Vec(t) => { + let operand = Borrowed(quote!(it)); + let val = visit(t, features, defs, &operand)?; + let name = name.ref_mut_tokens(); + Some(quote! { + for it in #name { + #val + } + }) + } + Type::Punctuated(p) => { + let operand = Borrowed(quote!(it)); + let val = visit(&p.element, features, defs, &operand)?; + let name = name.ref_mut_tokens(); + Some(quote! { + for el in Punctuated::pairs_mut(#name) { + let (it, p) = el.into_tuple(); + #val; + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + }) + } + Type::Option(t) => { + let it = Borrowed(quote!(it)); + let val = visit(t, features, defs, &it)?; + let name = name.owned_tokens(); + Some(quote! { + if let Some(it) = &mut #name { + #val + } + }) + } + Type::Tuple(t) => { + let mut code = TokenStream::new(); + for (i, elem) in t.iter().enumerate() { + let name = name.tokens(); + let i = Index::from(i); + let it = Owned(quote!((#name).#i)); + let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it)); + code.extend(val); + code.extend(quote!(;)); + } + Some(code) + } + Type::Token(t) => { + let name = name.tokens(); + let repr = &defs.tokens[t]; + let is_keyword = repr.chars().next().unwrap().is_alphabetic(); + let spans = if is_keyword { + quote!(span) + } else { + quote!(spans) + }; + Some(quote! { + tokens_helper(v, &mut #name.#spans) + }) + } + Type::Group(_) => { + let name = name.tokens(); + Some(quote! { + tokens_helper(v, &mut #name.span) + }) + } + Type::Syn(t) => { + fn requires_full(features: &Features) -> bool { + features.any.contains("full") && features.any.len() == 1 + } + let mut res = simple_visit(t, name); + let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap(); + if requires_full(&target.features) && !requires_full(features) { + res = quote!(full!(#res)); + } + Some(res) + } + Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)), + Type::Ext(_) | Type::Std(_) => None, + } +} + +fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) { + let under_name = gen::under_name(&s.ident); + let ty = Ident::new(&s.ident, Span::call_site()); + let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site()); + + let mut visit_mut_impl = TokenStream::new(); + + match &s.data { + Data::Enum(variants) => { + let mut visit_mut_variants = TokenStream::new(); + + for (variant, fields) in variants { + let variant_ident = Ident::new(variant, Span::call_site()); + + if fields.is_empty() { + visit_mut_variants.extend(quote! { + #ty::#variant_ident => {} + }); + } else { + let mut bind_visit_mut_fields = TokenStream::new(); + let mut visit_mut_fields = TokenStream::new(); + + for (idx, ty) in fields.iter().enumerate() { + let name = format!("_binding_{}", idx); + let binding = Ident::new(&name, Span::call_site()); + + bind_visit_mut_fields.extend(quote! { + #binding, + }); + + let borrowed_binding = Borrowed(quote!(#binding)); + + visit_mut_fields.extend( + visit(ty, &s.features, defs, &borrowed_binding) + .unwrap_or_else(|| noop_visit(&borrowed_binding)), + ); + + visit_mut_fields.extend(quote!(;)); + } + + visit_mut_variants.extend(quote! { + #ty::#variant_ident(#bind_visit_mut_fields) => { + #visit_mut_fields + } + }); + } + } + + let nonexhaustive = if s.exhaustive { + None + } else { + Some(quote!(_ => unreachable!())) + }; + + visit_mut_impl.extend(quote! { + match node { + #visit_mut_variants + #nonexhaustive + } + }); + } + Data::Struct(fields) => { + for (field, ty) in fields { + if let Type::Syn(ty) = ty { + if ty == "Reserved" { + continue; + } + } + + let id = Ident::new(&field, Span::call_site()); + let ref_toks = Owned(quote!(node.#id)); + let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks) + .unwrap_or_else(|| noop_visit(&ref_toks)); + visit_mut_impl.extend(quote! { + #visit_mut_field; + }); + } + } + Data::Private => { + if ty == "Ident" { + visit_mut_impl.extend(quote! { + let mut span = node.span(); + v.visit_span_mut(&mut span); + node.set_span(span); + }); + } + } + } + + traits.extend(quote! { + fn #visit_mut_fn(&mut self, i: &mut #ty) { + #visit_mut_fn(self, i) + } + }); + + impls.extend(quote! { + pub fn #visit_mut_fn<V>(v: &mut V, node: &mut #ty) + where + V: VisitMut + ?Sized, + { + #visit_mut_impl + } + }); +} + +pub fn generate(defs: &Definitions) -> Result<()> { + let (traits, impls) = gen::traverse(defs, node); + let full_macro = full::get_macro(); + file::write( + VISIT_MUT_SRC, + quote! { + #![allow(unused_variables)] + + use crate::*; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::punctuated::Punctuated; + use proc_macro2::Span; + #[cfg(any(feature = "full", feature = "derive"))] + use crate::gen::helper::visit_mut::*; + + #full_macro + + #[cfg(any(feature = "full", feature = "derive"))] + macro_rules! skip { + ($($tt:tt)*) => {}; + } + + /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in + /// place. + /// + /// See the [module documentation] for details. + /// + /// [module documentation]: self + /// + /// *This trait is available if Syn is built with the `"visit-mut"` feature.* + pub trait VisitMut { + #traits + } + + #impls + }, + )?; + Ok(()) +} diff --git a/syn/dev/Cargo.toml b/syn/dev/Cargo.toml new file mode 100644 index 0000000..79486c1 --- /dev/null +++ b/syn/dev/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "syn-dev" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[lib] +path = "parse.rs" +proc-macro = true + +[[bin]] +path = "main.rs" +name = "syn-dev" + +[dependencies] +quote = "1.0" + +[dependencies.syn] +path = ".." +default-features = false +features = ["parsing", "full", "extra-traits", "proc-macro"] diff --git a/syn/dev/README.md b/syn/dev/README.md new file mode 100644 index 0000000..91b9846 --- /dev/null +++ b/syn/dev/README.md @@ -0,0 +1,6 @@ +A little project skeleton for troubleshooting Syn's parsers during development, +especially when adding support for new Rust syntax. + +Place a sample of the syntax you are working on into main.rs and then run `cargo +check` to try parsing it, revealing the resulting syntax tree or else showing +the position and error message if the input fails to parse. diff --git a/syn/dev/main.rs b/syn/dev/main.rs new file mode 100644 index 0000000..eb67546 --- /dev/null +++ b/syn/dev/main.rs @@ -0,0 +1,4 @@ +syn_dev::r#mod! { + // Write Rust code here and run `cargo check` to have Syn parse it. + +} diff --git a/syn/dev/parse.rs b/syn/dev/parse.rs new file mode 100644 index 0000000..2a92550 --- /dev/null +++ b/syn/dev/parse.rs @@ -0,0 +1,18 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::File; + +#[proc_macro] +pub fn r#mod(input: TokenStream) -> TokenStream { + let compile_error = syn::parse::<File>(input) + .map(|file| println!("{:#?}", file)) + .map_err(|err| err.to_compile_error()) + .err(); + + TokenStream::from(quote! { + #compile_error + fn main() {} + }) +} diff --git a/syn/examples/README.md b/syn/examples/README.md new file mode 100644 index 0000000..fdd69d6 --- /dev/null +++ b/syn/examples/README.md @@ -0,0 +1,19 @@ +### [`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) + +An example implementation of a derive macro that generates trait impls. + +### [`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/syn/examples/dump-syntax/Cargo.toml b/syn/examples/dump-syntax/Cargo.toml new file mode 100644 index 0000000..0bc9f62 --- /dev/null +++ b/syn/examples/dump-syntax/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dump-syntax" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +colored = "1.7" +proc-macro2 = { version = "1.0", features = ["span-locations"] } + +[dependencies.syn] +path = "../.." +default-features = false +features = ["parsing", "full", "extra-traits"] + +[workspace] diff --git a/syn/examples/dump-syntax/README.md b/syn/examples/dump-syntax/README.md new file mode 100644 index 0000000..37c84d8 --- /dev/null +++ b/syn/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 -- src/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/syn/examples/dump-syntax/src/main.rs b/syn/examples/dump-syntax/src/main.rs new file mode 100644 index 0000000..240b7a2 --- /dev/null +++ b/syn/examples/dump-syntax/src/main.rs @@ -0,0 +1,149 @@ +//! 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 -- src/main.rs +//! +//! The output will begin with: +//! +//! File { +//! shebang: None, +//! attrs: [ +//! Attribute { +//! pound_token: Pound, +//! style: Inner( +//! ... +//! } + +use std::borrow::Cow; +use std::env; +use std::ffi::OsStr; +use std::fmt::{self, Display}; +use std::fs; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::process; + +use colored::Colorize; + +enum Error { + IncorrectUsage, + ReadFile(io::Error), + ParseFile { + error: syn::Error, + filepath: PathBuf, + source_code: String, + }, +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + + match self { + IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"), + ReadFile(error) => write!(f, "Unable to read file: {}", error), + ParseFile { + error, + filepath, + source_code, + } => render_location(f, error, filepath, source_code), + } + } +} + +fn main() { + if let Err(error) = try_main() { + let _ = writeln!(io::stderr(), "{}", error); + process::exit(1); + } +} + +fn try_main() -> Result<(), Error> { + let mut args = env::args_os(); + let _ = args.next(); // executable name + + let filepath = match (args.next(), args.next()) { + (Some(arg), None) => PathBuf::from(arg), + _ => return Err(Error::IncorrectUsage), + }; + + let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?; + let syntax = syn::parse_file(&code).map_err({ + |error| Error::ParseFile { + error, + filepath, + source_code: code, + } + })?; + println!("{:#?}", syntax); + + Ok(()) +} + +// Render a rustc-style error message, including colors. +// +// error: Syn unable to parse file +// --> main.rs:40:17 +// | +// 40 | fn fmt(&self formatter: &mut fmt::Formatter) -> fmt::Result { +// | ^^^^^^^^^ expected `,` +// +fn render_location( + formatter: &mut fmt::Formatter, + err: &syn::Error, + filepath: &Path, + code: &str, +) -> fmt::Result { + let start = err.span().start(); + let mut end = err.span().end(); + + if start.line == end.line && start.column == end.column { + return render_fallback(formatter, err); + } + + let code_line = match code.lines().nth(start.line - 1) { + Some(line) => line, + None => return render_fallback(formatter, err), + }; + + if end.line > start.line { + end.line = start.line; + end.column = code_line.len(); + } + + let filename = filepath + .file_name() + .map(OsStr::to_string_lossy) + .unwrap_or(Cow::Borrowed("main.rs")); + + write!( + formatter, + "\n\ + {error}{header}\n\ + {indent}{arrow} {filename}:{linenum}:{colnum}\n\ + {indent} {pipe}\n\ + {label} {pipe} {code}\n\ + {indent} {pipe} {offset}{underline} {message}\n\ + ", + error = "error".red().bold(), + header = ": Syn unable to parse file".bold(), + indent = " ".repeat(start.line.to_string().len()), + arrow = "-->".blue().bold(), + filename = filename, + linenum = start.line, + colnum = start.column, + pipe = "|".blue().bold(), + label = start.line.to_string().blue().bold(), + code = code_line.trim_end(), + offset = " ".repeat(start.column), + underline = "^".repeat(end.column - start.column).red().bold(), + message = err.to_string().red(), + ) +} + +fn render_fallback(formatter: &mut fmt::Formatter, err: &syn::Error) -> fmt::Result { + write!(formatter, "Unable to parse file: {}", err) +} diff --git a/syn/examples/heapsize/Cargo.toml b/syn/examples/heapsize/Cargo.toml new file mode 100644 index 0000000..9b19214 --- /dev/null +++ b/syn/examples/heapsize/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["example", "heapsize", "heapsize_derive"] diff --git a/syn/examples/heapsize/README.md b/syn/examples/heapsize/README.md new file mode 100644 index 0000000..e789559 --- /dev/null +++ b/syn/examples/heapsize/README.md @@ -0,0 +1,72 @@ +A derive macro that generates trait impls. + +- [`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 derive macro 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 derive macro 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) + } +} +``` + +The implementation of `heapsize_derive` demonstrates some attention to "spans" +of error messages. For each subexpression in the generated code we apply the +span of the input fragment under which we would want to trigger a compiler error +if the subexpression fails to compile. In this example, each recursive call to +`heap_size_of_children` is associated with the span of the corresponding struct +field. Thus we get errors in the right place if any of the field types do not +implement the `HeapSize` trait. + +``` +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/syn/examples/heapsize/example/Cargo.toml b/syn/examples/heapsize/example/Cargo.toml new file mode 100644 index 0000000..85c7699 --- /dev/null +++ b/syn/examples/heapsize/example/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "heapsize_example" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +heapsize = { path = "../heapsize" } diff --git a/syn/examples/heapsize/example/src/main.rs b/syn/examples/heapsize/example/src/main.rs new file mode 100644 index 0000000..9332b11 --- /dev/null +++ b/syn/examples/heapsize/example/src/main.rs @@ -0,0 +1,28 @@ +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/syn/examples/heapsize/heapsize/Cargo.toml b/syn/examples/heapsize/heapsize/Cargo.toml new file mode 100644 index 0000000..27bb954 --- /dev/null +++ b/syn/examples/heapsize/heapsize/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "heapsize" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +heapsize_derive = { path = "../heapsize_derive" } diff --git a/syn/examples/heapsize/heapsize/src/lib.rs b/syn/examples/heapsize/heapsize/src/lib.rs new file mode 100644 index 0000000..30bb6d6 --- /dev/null +++ b/syn/examples/heapsize/heapsize/src/lib.rs @@ -0,0 +1,64 @@ +use std::mem; + +pub use heapsize_derive::*; + +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/syn/examples/heapsize/heapsize_derive/Cargo.toml b/syn/examples/heapsize/heapsize_derive/Cargo.toml new file mode 100644 index 0000000..f4357b9 --- /dev/null +++ b/syn/examples/heapsize/heapsize_derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "heapsize_derive" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = { path = "../../.." } diff --git a/syn/examples/heapsize/heapsize_derive/src/lib.rs b/syn/examples/heapsize/heapsize_derive/src/lib.rs new file mode 100644 index 0000000..9176b29 --- /dev/null +++ b/syn/examples/heapsize/heapsize_derive/src/lib.rs @@ -0,0 +1,96 @@ +extern crate proc_macro; + +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; +use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics, Index}; + +#[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 = parse_macro_input!(input as DeriveInput); + + // 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. + proc_macro::TokenStream::from(expanded) +} + +// 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. + // + // 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; + quote_spanned! {f.span()=> + heapsize::HeapSize::heap_size_of_children(&self.#name) + } + }); + quote! { + 0 #(+ #recurse)* + } + } + Fields::Unnamed(ref fields) => { + // Expands to an expression like + // + // 0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size() + let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| { + let index = Index::from(i); + quote_spanned! {f.span()=> + heapsize::HeapSize::heap_size_of_children(&self.#index) + } + }); + 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/syn/examples/lazy-static/Cargo.toml b/syn/examples/lazy-static/Cargo.toml new file mode 100644 index 0000000..586e547 --- /dev/null +++ b/syn/examples/lazy-static/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["example", "lazy-static"] diff --git a/syn/examples/lazy-static/README.md b/syn/examples/lazy-static/README.md new file mode 100644 index 0000000..bc64585 --- /dev/null +++ b/syn/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/syn/examples/lazy-static/example/Cargo.toml b/syn/examples/lazy-static/example/Cargo.toml new file mode 100644 index 0000000..716b08c --- /dev/null +++ b/syn/examples/lazy-static/example/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +lazy_static = { path = "../lazy-static" } +regex = "0.2" diff --git a/syn/examples/lazy-static/example/src/main.rs b/syn/examples/lazy-static/example/src/main.rs new file mode 100644 index 0000000..c4f64af --- /dev/null +++ b/syn/examples/lazy-static/example/src/main.rs @@ -0,0 +1,20 @@ +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/syn/examples/lazy-static/lazy-static/Cargo.toml b/syn/examples/lazy-static/lazy-static/Cargo.toml new file mode 100644 index 0000000..bf65787 --- /dev/null +++ b/syn/examples/lazy-static/lazy-static/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "lazy_static" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = { version = "1.0", features = ["nightly"] } +quote = "1.0" +syn = { path = "../../../", features = ["full"] } diff --git a/syn/examples/lazy-static/lazy-static/src/lib.rs b/syn/examples/lazy-static/lazy-static/src/lib.rs new file mode 100644 index 0000000..254ca72 --- /dev/null +++ b/syn/examples/lazy-static/lazy-static/src/lib.rs @@ -0,0 +1,143 @@ +#![recursion_limit = "128"] +#![feature(proc_macro_diagnostic)] + +extern crate proc_macro; +use self::proc_macro::TokenStream; + +use quote::{quote, quote_spanned}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::spanned::Spanned; +use syn::{parse_macro_input, Expr, Ident, Token, Type, Visibility}; + +/// 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 Parse for LazyStatic { + fn parse(input: ParseStream) -> Result<Self> { + let visibility: Visibility = input.parse()?; + input.parse::<Token![static]>()?; + input.parse::<Token![ref]>()?; + let name: Ident = input.parse()?; + input.parse::<Token![:]>()?; + let ty: Type = input.parse()?; + input.parse::<Token![=]>()?; + let init: Expr = input.parse()?; + input.parse::<Token![;]>()?; + Ok(LazyStatic { + visibility, + name, + ty, + init, + }) + } +} + +#[proc_macro] +pub fn lazy_static(input: TokenStream) -> TokenStream { + let LazyStatic { + visibility, + name, + ty, + init, + } = parse_macro_input!(input as LazyStatic); + + // 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() + .unwrap() + .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() + .unwrap() + .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::new(); + static mut VALUE: *mut #ty = 0 as *mut #ty; + + unsafe { + ONCE.call_once(|| VALUE = #init_ptr); + &*VALUE + } + } + } + }; + + TokenStream::from(expanded) +} diff --git a/syn/examples/trace-var/Cargo.toml b/syn/examples/trace-var/Cargo.toml new file mode 100644 index 0000000..b54454d --- /dev/null +++ b/syn/examples/trace-var/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["example", "trace-var"] diff --git a/syn/examples/trace-var/README.md b/syn/examples/trace-var/README.md new file mode 100644 index 0000000..b93fae2 --- /dev/null +++ b/syn/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/1.0/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/syn/examples/trace-var/example/Cargo.toml b/syn/examples/trace-var/example/Cargo.toml new file mode 100644 index 0000000..d2ad650 --- /dev/null +++ b/syn/examples/trace-var/example/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "example" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +trace-var = { path = "../trace-var" } diff --git a/syn/examples/trace-var/example/src/main.rs b/syn/examples/trace-var/example/src/main.rs new file mode 100644 index 0000000..da2c10b --- /dev/null +++ b/syn/examples/trace-var/example/src/main.rs @@ -0,0 +1,15 @@ +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/syn/examples/trace-var/trace-var/Cargo.toml b/syn/examples/trace-var/trace-var/Cargo.toml new file mode 100644 index 0000000..72f56e9 --- /dev/null +++ b/syn/examples/trace-var/trace-var/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "trace-var" +version = "0.0.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +publish = false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = { version = "1.0", features = ["nightly"] } +quote = "1.0" +syn = { path = "../../../", features = ["full", "fold"] } diff --git a/syn/examples/trace-var/trace-var/src/lib.rs b/syn/examples/trace-var/trace-var/src/lib.rs new file mode 100644 index 0000000..0ecfb47 --- /dev/null +++ b/syn/examples/trace-var/trace-var/src/lib.rs @@ -0,0 +1,180 @@ +extern crate proc_macro; +use self::proc_macro::TokenStream; + +use quote::{quote, ToTokens}; +use std::collections::HashSet as Set; +use syn::fold::{self, Fold}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::{parse_macro_input, parse_quote, Expr, Ident, ItemFn, Local, Pat, Stmt, Token}; + +/// Parses a list of variable names separated by commas. +/// +/// a, b, c +/// +/// This is how the compiler passes in arguments to our attribute -- it is +/// everything inside the delimiters after the attribute name. +/// +/// #[trace_var(a, b, c)] +/// ^^^^^^^ +struct Args { + vars: Set<Ident>, +} + +impl Parse for Args { + fn parse(input: ParseStream) -> Result<Self> { + let vars = Punctuated::<Ident, Token![,]>::parse_terminated(input)?; + Ok(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(); + self.vars.contains(&first.ident) && first.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: &Pat) -> bool { + match p { + 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: &dyn 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 { pat, init, .. } = local; + let init = self.fold_expr(*init.unwrap().1); + let ident = match pat { + Pat::Ident(ref p) => &p.ident, + _ => unreachable!(), + }; + parse_quote! { + let #pat = { + #[allow(unused_mut)] + 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.pat) { + 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 { + let input = parse_macro_input!(input as ItemFn); + + // Parse the list of variables the user wanted to print. + let mut args = parse_macro_input!(args as Args); + + // 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. + TokenStream::from(quote!(#output)) +} diff --git a/syn/json/Cargo.toml b/syn/json/Cargo.toml new file mode 100644 index 0000000..77104dc --- /dev/null +++ b/syn/json/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "syn-codegen" +version = "0.1.0" +authors = ["David Tolnay <dtolnay@gmail.com>"] +edition = "2018" +license = "MIT OR Apache-2.0" +description = "Syntax tree describing Syn's syntax tree" +repository = "https://github.com/dtolnay/syn" +documentation = "https://docs.rs/syn-codegen" +categories = ["development-tools::procedural-macro-helpers"] + +[dependencies] +indexmap = { version = "1.0", features = ["serde-1"] } +semver = { version = "0.9", features = ["serde"] } +serde = { version = "1.0.88", features = ["derive"] } + +[dev-dependencies] +serde_json = "1.0" diff --git a/syn/json/src/lib.rs b/syn/json/src/lib.rs new file mode 100644 index 0000000..e3546d9 --- /dev/null +++ b/syn/json/src/lib.rs @@ -0,0 +1,214 @@ +//! # Data structures that describe Syn's syntax tree. +//! +//! The Syn syntax tree is made up of more than 200 types. Occasionally it can +//! come up that you need to implement some behavior across them all. +//! +//! - For example [the Rust integration for AST Explorer][astexplorer] wants to +//! turn a syntax tree from Syn into a JavaScript value understood by the +//! platform's existing cross-language syntax tree visualization code. +//! +//! [astexplorer]: https://astexplorer.net/#/gist/388150a52f74d45a355d2b5e865ded96/0c6d563f28d900472f699c21a1845ad20ae9927f +//! +//! - As another example from within Syn itself, the traits and implementations +//! of the [`visit`], [`visit_mut`], and [`fold`] modules can be generated +//! programmatically from a description of the syntax tree. +//! +//! [`visit`]: https://docs.rs/syn/1.0/syn/visit/index.html +//! [`visit_mut`]: https://docs.rs/syn/1.0/syn/visit_mut/index.html +//! [`fold`]: https://docs.rs/syn/1.0/syn/fold/index.html +//! +//! To make this type of code as easy as possible to implement in any language, +//! every Syn release comes with a machine-readable description of that version +//! of the syntax tree as a JSON file [syn.json]. This `syn-codegen` crate +//! provides the canonical data structures for parsing and making use of the +//! representation in syn.json from Rust code. +//! +//! [syn.json]: https://raw.githubusercontent.com/dtolnay/syn/master/syn.json +//! +//! ## Example +//! +//! ``` +//! use syn_codegen::Definitions; +//! +//! # const IGNORE: &str = stringify! { +//! const SYN: &str = include_str!("syn.json"); +//! # }; +//! # const SYN: &str = include_str!("../../syn.json"); +//! +//! fn main() { +//! let defs: Definitions = serde_json::from_str(SYN).unwrap(); +//! +//! for node in &defs.types { +//! println!("syn::{}", node.ident); +//! } +//! } +//! ``` + +use indexmap::IndexMap; +use semver::Version; +use serde::{Deserialize, Deserializer, Serialize}; + +use std::collections::{BTreeMap, BTreeSet}; + +/// Top-level content of the syntax tree description. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Definitions { + /// The Syn version whose syntax tree is described by this data. + pub version: Version, + + /// Syntax tree types defined by Syn. + pub types: Vec<Node>, + + /// Token types defined by Syn (keywords as well as punctuation). + /// + /// The keys in the map are the Rust type name for the token. The values in + /// the map are the printed token representation. + /// + /// These tokens are accessible in the Syn public API as `syn::token::#name` + /// or alternatively `syn::Token![#repr]`. + pub tokens: BTreeMap<String, String>, +} + +/// Syntax tree type defined by Syn. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Node { + /// Name of the type. + /// + /// This type is accessible in the Syn public API as `syn::#name`. + pub ident: String, + + /// Features behind which this type is cfg gated. + pub features: Features, + + /// Content of the data structure. + #[serde( + flatten, + skip_serializing_if = "is_private", + deserialize_with = "private_if_absent" + )] + pub data: Data, + + #[serde(skip_serializing_if = "is_true", default = "bool_true")] + pub exhaustive: bool, +} + +/// Content of a syntax tree data structure. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum Data { + /// This is an opaque type with no publicy accessible structure. + Private, + + /// This type is a braced struct with named fields. + #[serde(rename = "fields")] + Struct(Fields), + + /// This type is an enum. + #[serde(rename = "variants")] + Enum(Variants), +} + +/// Fields of a braced struct syntax tree node with named fields. +/// +/// The keys in the map are the field names. +pub type Fields = IndexMap<String, Type>; + +/// Variants of an enum syntax tree node. +/// +/// The keys in the map are the variant names. +/// +/// Variants are unit variants if they hold no data and tuple variants +/// otherwise. The Syn syntax tree does not make use of braced variants. +pub type Variants = IndexMap<String, Vec<Type>>; + +/// Type of a struct field or tuple variant field in the syntax tree. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Type { + /// Syntax tree type defined by Syn. + /// + /// This name will match the ident of some `Node`. + Syn(String), + + /// Type defined by the Rust language or standard library. + /// + /// All such types used by Syn are accessible in the Rust prelude and can be + /// used without a qualifying path in most Rust code. + Std(String), + + /// Type defined by proc-macro2. + /// + /// The type is accessible in the proc-macro2 public API as + /// `proc_macro2::#name`. + #[serde(rename = "proc_macro2")] + Ext(String), + + /// Keyword or punctuation token type defined by Syn. + /// + /// This name will match one of the keys in the `tokens` map. + Token(String), + + /// Grouping token defined by Syn. + /// + /// The type is accessible in the Syn public API as `syn::token::#name`. + Group(String), + + /// Punctuated list. + /// + /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified + /// element type and punctuation. + Punctuated(Punctuated), + + /// `std::option::Option` + Option(Box<Type>), + + /// `std::boxed::Box` + Box(Box<Type>), + + /// `std::vec::Vec` + Vec(Box<Type>), + + /// Rust tuple with two or more fields. + Tuple(Vec<Type>), +} + +/// Type of a punctuated list. +/// +/// This refers to `syn::punctuated::Punctuated<#element, #punct>`. +/// +/// The punct string will match one of the keys in the `tokens` map. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Punctuated { + pub element: Box<Type>, + pub punct: String, +} + +/// Features behind which a syntax tree type is cfg gated. +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct Features { + /// Type is accessible if at least one of these features is enabled against + /// the Syn dependency. + pub any: BTreeSet<String>, +} + +fn is_private(data: &Data) -> bool { + match data { + Data::Private => true, + Data::Struct(_) | Data::Enum(_) => false, + } +} + +fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error> +where + D: Deserializer<'de>, +{ + let option = Option::deserialize(deserializer)?; + Ok(option.unwrap_or(Data::Private)) +} + +fn is_true(b: &bool) -> bool { + *b +} + +fn bool_true() -> bool { + true +} diff --git a/syn/src/attr.rs b/syn/src/attr.rs new file mode 100644 index 0000000..a8e16ea --- /dev/null +++ b/syn/src/attr.rs @@ -0,0 +1,682 @@ +use super::*; +use crate::punctuated::Punctuated; + +use std::iter; + +use proc_macro2::TokenStream; + +#[cfg(feature = "parsing")] +use crate::parse::{Parse, ParseBuffer, ParseStream, Parser, Result}; +#[cfg(feature = "parsing")] +use crate::punctuated::Pair; +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +ast_struct! { + /// An attribute like `#[repr(transparent)]`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// <br> + /// + /// # 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 `tokens` field contains the rest of the attribute body as + /// tokens. + /// + /// ```text + /// #[derive(Copy)] #[crate::precondition x < 5] + /// ^^^^^^~~~~~~ ^^^^^^^^^^^^^^^^^^^ ~~~~~ + /// path tokens path tokens + /// ``` + /// + /// <br> + /// + /// # Parsing from tokens to Attribute + /// + /// This type does not implement the [`Parse`] trait and thus cannot be + /// parsed directly by [`ParseStream::parse`]. Instead use + /// [`ParseStream::call`] with one of the two parser functions + /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on + /// which you intend to parse. + /// + /// [`Parse`]: parse::Parse + /// [`ParseStream::parse`]: parse::ParseBuffer::parse + /// [`ParseStream::call`]: parse::ParseBuffer::call + /// + /// ``` + /// use syn::{Attribute, Ident, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a unit struct with attributes. + /// // + /// // #[path = "s.tmpl"] + /// // struct S; + /// struct UnitStruct { + /// attrs: Vec<Attribute>, + /// struct_token: Token![struct], + /// name: Ident, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for UnitStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(UnitStruct { + /// attrs: input.call(Attribute::parse_outer)?, + /// struct_token: input.parse()?, + /// name: input.parse()?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// ``` + /// + /// <p><br></p> + /// + /// # Parsing from Attribute to structured arguments + /// + /// The grammar of attributes in Rust is very flexible, which makes the + /// syntax tree not that useful on its own. In particular, arguments of the + /// attribute are held in an arbitrary `tokens: TokenStream`. Macros are + /// expected to check the `path` of the attribute, decide whether they + /// recognize it, and then parse the remaining tokens according to whatever + /// grammar they wish to require for that kind of attribute. + /// + /// If the attribute you are parsing is expected to conform to the + /// conventional structured form of attribute, use [`parse_meta()`] to + /// obtain that structured representation. If the attribute follows some + /// other grammar of its own, use [`parse_args()`] to parse that into the + /// expected data structure. + /// + /// [`parse_meta()`]: Attribute::parse_meta + /// [`parse_args()`]: Attribute::parse_args + /// + /// <p><br></p> + /// + /// # Doc comments + /// + /// The compiler transforms doc comments, such as `/// comment` and `/*! + /// comment */`, into attributes before macros are expanded. Each comment is + /// expanded into an attribute of the form `#[doc = r"comment"]`. + /// + /// As an example, the following `mod` items are expanded identically: + /// + /// ``` + /// # use syn::{ItemMod, parse_quote}; + /// let doc: ItemMod = parse_quote! { + /// /// Single line doc comments + /// /// We write so many! + /// /** + /// * Multi-line comments... + /// * May span many lines + /// */ + /// mod example { + /// //! Of course, they can be inner too + /// /*! And fit in a single line */ + /// } + /// }; + /// let attr: ItemMod = parse_quote! { + /// #[doc = r" Single line doc comments"] + /// #[doc = r" We write so many!"] + /// #[doc = r" Multi-line comments... + /// May span many lines"] + /// mod example { + /// #![doc = r" Of course, they can be inner too"] + /// #![doc = r" And fit in a single line "] + /// } + /// }; + /// assert_eq!(doc, attr); + /// ``` + pub struct Attribute #manual_extra_traits { + pub pound_token: Token![#], + pub style: AttrStyle, + pub bracket_token: token::Bracket, + pub path: Path, + pub tokens: 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.tokens) == TokenStreamHelper(&other.tokens) + } +} + +#[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.tokens).hash(state); + } +} + +impl Attribute { + /// Parses the content of the attribute, consisting of the path and tokens, + /// as a [`Meta`] if possible. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_meta(&self) -> Result<Meta> { + fn clone_ident_segment(segment: &PathSegment) -> PathSegment { + PathSegment { + ident: segment.ident.clone(), + arguments: PathArguments::None, + } + } + + let path = Path { + leading_colon: self + .path + .leading_colon + .as_ref() + .map(|colon| Token![::](colon.spans)), + segments: self + .path + .segments + .pairs() + .map(|pair| match pair { + Pair::Punctuated(seg, punct) => { + Pair::Punctuated(clone_ident_segment(seg), Token![::](punct.spans)) + } + Pair::End(seg) => Pair::End(clone_ident_segment(seg)), + }) + .collect(), + }; + + let parser = |input: ParseStream| parsing::parse_meta_after_path(path, input); + parse::Parser::parse2(parser, self.tokens.clone()) + } + + /// Parse the arguments to the attribute as a syntax tree. + /// + /// This is similar to `syn::parse2::<T>(attr.tokens)` except that: + /// + /// - the surrounding delimiters are *not* included in the input to the + /// parser; and + /// - the error message has a more useful span when `tokens` is empty. + /// + /// ```text + /// #[my_attr(value < 5)] + /// ^^^^^^^^^ what gets parsed + /// ``` + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_args<T: Parse>(&self) -> Result<T> { + self.parse_args_with(T::parse) + } + + /// Parse the arguments to the attribute using the given parser. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { + let parser = |input: ParseStream| { + let args = enter_args(self, input)?; + parse::parse_stream(parser, &args) + }; + parser.parse2(self.tokens.clone()) + } + + /// Parses zero or more outer attributes from the stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { + let mut attrs = Vec::new(); + while input.peek(Token![#]) { + attrs.push(input.call(parsing::single_parse_outer)?); + } + Ok(attrs) + } + + /// Parses zero or more inner attributes from the stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { + let mut attrs = Vec::new(); + while input.peek(Token![#]) && input.peek2(Token![!]) { + attrs.push(input.call(parsing::single_parse_inner)?); + } + Ok(attrs) + } +} + +#[cfg(feature = "parsing")] +fn error_expected_args(attr: &Attribute) -> Error { + let style = match attr.style { + AttrStyle::Outer => "#", + AttrStyle::Inner(_) => "#!", + }; + + let mut path = String::new(); + for segment in &attr.path.segments { + if !path.is_empty() || attr.path.leading_colon.is_some() { + path += "::"; + } + path += &segment.ident.to_string(); + } + + let msg = format!("expected attribute arguments: {}[{}(...)]", style, path); + + #[cfg(feature = "printing")] + return Error::new_spanned(attr, msg); + + #[cfg(not(feature = "printing"))] + return Error::new(attr.bracket_token.span, msg); +} + +#[cfg(feature = "parsing")] +fn enter_args<'a>(attr: &Attribute, input: ParseStream<'a>) -> Result<ParseBuffer<'a>> { + if input.is_empty() { + return Err(error_expected_args(attr)); + }; + + let content; + if input.peek(token::Paren) { + parenthesized!(content in input); + } else if input.peek(token::Bracket) { + bracketed!(content in input); + } else if input.peek(token::Brace) { + braced!(content in input); + } else { + return Err(input.error("unexpected token in attribute arguments")); + } + + if input.is_empty() { + Ok(content) + } else { + Err(input.error("unexpected token in attribute arguments")) + } +} + +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.* + /// + /// ## Path + /// + /// A meta path 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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Meta { + Path(Path), + + /// A structured list within an attribute, like `derive(Copy, Clone)`. + List(MetaList), + + /// A name-value pair within an attribute, like `feature = "nightly"`. + NameValue(MetaNameValue), + } +} + +ast_struct! { + /// 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 struct MetaList { + pub path: Path, + pub paren_token: token::Paren, + pub nested: Punctuated<NestedMeta, Token![,]>, + } +} + +ast_struct! { + /// 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 struct MetaNameValue { + pub path: Path, + 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 path(&self) -> &Path { + match self { + Meta::Path(path) => path, + Meta::List(meta) => &meta.path, + Meta::NameValue(meta) => &meta.path, + } + } +} + +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::Path`. + Meta(Meta), + + /// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`. + Lit(Lit), + } +} + +/// Conventional argument type associated with an invocation of an attribute +/// macro. +/// +/// For example if we are developing an attribute macro that is intended to be +/// invoked on function items as follows: +/// +/// ``` +/// # const IGNORE: &str = stringify! { +/// #[my_attribute(path = "/v1/refresh")] +/// # }; +/// pub fn refresh() { +/// /* ... */ +/// } +/// ``` +/// +/// The implementation of this macro would want to parse its attribute arguments +/// as type `AttributeArgs`. +/// +/// ``` +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::{parse_macro_input, AttributeArgs, ItemFn}; +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_attribute] +/// # }; +/// pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream { +/// let args = parse_macro_input!(args as AttributeArgs); +/// let input = parse_macro_input!(input as ItemFn); +/// +/// /* ... */ +/// # "".parse().unwrap() +/// } +/// ``` +pub type AttributeArgs = Vec<NestedMeta>; + +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 crate::ext::IdentExt; + use crate::parse::{Parse, ParseStream, Result}; + #[cfg(feature = "full")] + use crate::private; + + pub fn single_parse_inner(input: ParseStream) -> Result<Attribute> { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Inner(input.parse()?), + bracket_token: bracketed!(content in input), + path: content.call(Path::parse_mod_style)?, + tokens: content.parse()?, + }) + } + + pub fn single_parse_outer(input: ParseStream) -> Result<Attribute> { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Outer, + bracket_token: bracketed!(content in input), + path: content.call(Path::parse_mod_style)?, + tokens: content.parse()?, + }) + } + + #[cfg(feature = "full")] + impl private { + pub fn attrs(outer: Vec<Attribute>, inner: Vec<Attribute>) -> Vec<Attribute> { + let mut attrs = outer; + attrs.extend(inner); + attrs + } + } + + // Like Path::parse_mod_style but accepts keywords in the path. + fn parse_meta_path(input: ParseStream) -> Result<Path> { + Ok(Path { + leading_colon: input.parse()?, + segments: { + let mut segments = Punctuated::new(); + while input.peek(Ident::peek_any) { + let ident = Ident::parse_any(input)?; + segments.push_value(PathSegment::from(ident)); + if !input.peek(Token![::]) { + break; + } + let punct = input.parse()?; + segments.push_punct(punct); + } + if segments.is_empty() { + return Err(input.error("expected path")); + } else if segments.trailing_punct() { + return Err(input.error("expected path segment")); + } + segments + }, + }) + } + + impl Parse for Meta { + fn parse(input: ParseStream) -> Result<Self> { + let path = input.call(parse_meta_path)?; + parse_meta_after_path(path, input) + } + } + + impl Parse for MetaList { + fn parse(input: ParseStream) -> Result<Self> { + let path = input.call(parse_meta_path)?; + parse_meta_list_after_path(path, input) + } + } + + impl Parse for MetaNameValue { + fn parse(input: ParseStream) -> Result<Self> { + let path = input.call(parse_meta_path)?; + parse_meta_name_value_after_path(path, input) + } + } + + impl Parse for NestedMeta { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) { + input.parse().map(NestedMeta::Lit) + } else if input.peek(Ident::peek_any) { + input.parse().map(NestedMeta::Meta) + } else { + Err(input.error("expected identifier or literal")) + } + } + } + + pub fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> { + if input.peek(token::Paren) { + parse_meta_list_after_path(path, input).map(Meta::List) + } else if input.peek(Token![=]) { + parse_meta_name_value_after_path(path, input).map(Meta::NameValue) + } else { + Ok(Meta::Path(path)) + } + } + + fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> { + let content; + Ok(MetaList { + path, + paren_token: parenthesized!(content in input), + nested: content.parse_terminated(NestedMeta::parse)?, + }) + } + + fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> { + Ok(MetaNameValue { + path, + eq_token: input.parse()?, + lit: input.parse()?, + }) + } +} + +#[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(b) = &self.style { + b.to_tokens(tokens); + } + self.bracket_token.surround(tokens, |tokens| { + self.path.to_tokens(tokens); + self.tokens.to_tokens(tokens); + }); + } + } + + impl ToTokens for MetaList { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.path.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.path.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.lit.to_tokens(tokens); + } + } +} diff --git a/syn/src/await.rs b/syn/src/await.rs new file mode 100644 index 0000000..a8e24fd --- /dev/null +++ b/syn/src/await.rs @@ -0,0 +1,2 @@ +// See include!("await.rs") in token.rs. +export_token_macro![(await)]; diff --git a/syn/src/bigint.rs b/syn/src/bigint.rs new file mode 100644 index 0000000..5397d6b --- /dev/null +++ b/syn/src/bigint.rs @@ -0,0 +1,66 @@ +use std::ops::{AddAssign, MulAssign}; + +// For implementing base10_digits() accessor on LitInt. +pub struct BigInt { + digits: Vec<u8>, +} + +impl BigInt { + pub fn new() -> Self { + BigInt { digits: Vec::new() } + } + + pub fn to_string(&self) -> String { + let mut repr = String::with_capacity(self.digits.len()); + + let mut has_nonzero = false; + for digit in self.digits.iter().rev() { + has_nonzero |= *digit != 0; + if has_nonzero { + repr.push((*digit + b'0') as char); + } + } + + if repr.is_empty() { + repr.push('0'); + } + + repr + } + + fn reserve_two_digits(&mut self) { + let len = self.digits.len(); + let desired = + len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize; + self.digits.resize(desired, 0); + } +} + +impl AddAssign<u8> for BigInt { + // Assumes increment <16. + fn add_assign(&mut self, mut increment: u8) { + self.reserve_two_digits(); + + let mut i = 0; + while increment > 0 { + let sum = self.digits[i] + increment; + self.digits[i] = sum % 10; + increment = sum / 10; + i += 1; + } + } +} + +impl MulAssign<u8> for BigInt { + // Assumes base <=16. + fn mul_assign(&mut self, base: u8) { + self.reserve_two_digits(); + + let mut carry = 0; + for digit in &mut self.digits { + let prod = *digit * base + carry; + *digit = prod % 10; + carry = prod / 10; + } + } +} diff --git a/syn/src/buffer.rs b/syn/src/buffer.rs new file mode 100644 index 0000000..5c2dd8a --- /dev/null +++ b/syn/src/buffer.rs @@ -0,0 +1,382 @@ +//! A stably addressed token buffer supporting efficient traversal based on a +//! cheaply copyable cursor. +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +// This module is heavily commented as it contains most of the 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", any(target_os = "unknown", target_os = "wasi"))), + feature = "proc-macro" +))] +use crate::proc_macro as pm; +use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +use std::marker::PhantomData; +use std::ptr; + +use crate::Lifetime; + +/// Internal type which is used instead of `TokenTree` to represent a token tree +/// within a `TokenBuffer`. +enum Entry { + // Mimicking types from proc-macro. + Group(Group, 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. +/// +/// *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)); + 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, group) 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(group.stream(), seq_up); + entries[idx] = Entry::Group(group, 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", any(target_os = "unknown", target_os = "wasi"))), + 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. +/// +/// *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, + // Cursor is covariant in 'a. This field ensures that our 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, + 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(group, buf) = self.entry() { + if group.delimiter() == Delimiter::None { + // 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. + 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(group, buf) = self.entry() { + if group.delimiter() == delim { + return Some((buf.begin(), group.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(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(op) if op.as_char() != '\'' => 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(lit) => Some((lit.clone(), unsafe { self.bump() })), + _ => None, + } + } + + /// If the cursor is pointing at a `Lifetime`, returns it along with a + /// cursor pointing at the next `TokenTree`. + pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> { + self.ignore_none(); + match self.entry() { + Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + let next = unsafe { self.bump() }; + match next.ident() { + Some((ident, rest)) => { + let lifetime = Lifetime { + apostrophe: op.span(), + ident, + }; + Some((lifetime, rest)) + } + None => None, + } + } + _ => 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(group, _) => group.clone().into(), + Entry::Literal(lit) => lit.clone().into(), + Entry::Ident(ident) => ident.clone().into(), + Entry::Punct(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(group, _) => group.span(), + Entry::Literal(l) => l.span(), + Entry::Ident(t) => t.span(), + Entry::Punct(o) => o.span(), + Entry::End(..) => Span::call_site(), + } + } + + /// Skip over the next token without cloning it. Returns `None` if this + /// cursor points to eof. + /// + /// This method treats `'lifetimes` as a single token. + pub(crate) fn skip(self) -> Option<Cursor<'a>> { + match self.entry() { + Entry::End(..) => None, + + // Treat lifetimes as a single tt for the purposes of 'skip'. + Entry::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + let next = unsafe { self.bump() }; + match next.entry() { + Entry::Ident(_) => Some(unsafe { next.bump() }), + _ => Some(next), + } + } + _ => Some(unsafe { self.bump() }), + } + } +} + +pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool { + a.scope == b.scope +} + +pub(crate) fn open_span_of_group(cursor: Cursor) -> Span { + match cursor.entry() { + Entry::Group(group, _) => group.span_open(), + _ => cursor.span(), + } +} + +pub(crate) fn close_span_of_group(cursor: Cursor) -> Span { + match cursor.entry() { + Entry::Group(group, _) => group.span_close(), + _ => cursor.span(), + } +} diff --git a/syn/src/custom_keyword.rs b/syn/src/custom_keyword.rs new file mode 100644 index 0000000..200e847 --- /dev/null +++ b/syn/src/custom_keyword.rs @@ -0,0 +1,252 @@ +/// Define a type that supports parsing and printing a given identifier as if it +/// were a keyword. +/// +/// # Usage +/// +/// As a convention, it is recommended that this macro be invoked within a +/// module called `kw` or `keyword` and that the resulting parser be invoked +/// with a `kw::` or `keyword::` prefix. +/// +/// ``` +/// mod kw { +/// syn::custom_keyword!(whatever); +/// } +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in keyword token. +/// +/// - [Peeking] — `input.peek(kw::whatever)` +/// +/// - [Parsing] — `input.parse::<kw::whatever>()?` +/// +/// - [Printing] — `quote!( ... #whatever_token ... )` +/// +/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)` +/// +/// - Field access to its span — `let sp = whatever_token.span` +/// +/// [Peeking]: parse::ParseBuffer::peek +/// [Parsing]: parse::ParseBuffer::parse +/// [Printing]: quote::ToTokens +/// [`Span`]: proc_macro2::Span +/// +/// # Example +/// +/// This example parses input that looks like `bool = true` or `str = "value"`. +/// The key must be either the identifier `bool` or the identifier `str`. If +/// `bool`, the value may be either `true` or `false`. If `str`, the value may +/// be any string literal. +/// +/// The symbols `bool` and `str` are not reserved keywords in Rust so these are +/// not considered keywords in the `syn::token` module. Like any other +/// identifier that is not a keyword, these can be declared as custom keywords +/// by crates that need to use them as such. +/// +/// ``` +/// use syn::{LitBool, LitStr, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// mod kw { +/// syn::custom_keyword!(bool); +/// syn::custom_keyword!(str); +/// } +/// +/// enum Argument { +/// Bool { +/// bool_token: kw::bool, +/// eq_token: Token![=], +/// value: LitBool, +/// }, +/// Str { +/// str_token: kw::str, +/// eq_token: Token![=], +/// value: LitStr, +/// }, +/// } +/// +/// impl Parse for Argument { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(kw::bool) { +/// Ok(Argument::Bool { +/// bool_token: input.parse::<kw::bool>()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else if lookahead.peek(kw::str) { +/// Ok(Argument::Str { +/// str_token: input.parse::<kw::str>()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_keyword { + ($ident:ident) => { + #[allow(non_camel_case_types)] + pub struct $ident { + pub span: $crate::export::Span, + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>( + span: __S, + ) -> $ident { + $ident { + span: $crate::export::IntoSpans::into_spans(span)[0], + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident { + span: $crate::export::Span::call_site(), + } + } + } + + impl_parse_for_custom_keyword!($ident); + impl_to_tokens_for_custom_keyword!($ident); + impl_clone_for_custom_keyword!($ident); + impl_extra_traits_for_custom_keyword!($ident); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => { + // For peek. + impl $crate::token::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> $crate::export::bool { + if let Some((ident, _rest)) = cursor.ident() { + ident == stringify!($ident) + } else { + false + } + } + + fn display() -> &'static $crate::export::str { + concat!("`", stringify!($ident), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + input.step(|cursor| { + if let $crate::export::Some((ident, rest)) = cursor.ident() { + if ident == stringify!($ident) { + return $crate::export::Ok(($ident { span: ident.span() }, rest)); + } + } + $crate::export::Err(cursor.error(concat!( + "expected `", + stringify!($ident), + "`" + ))) + }) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + let ident = $crate::Ident::new(stringify!($ident), self.span); + $crate::export::TokenStreamExt::append(tokens, ident); + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::Debug for $ident { + fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { + $crate::export::Formatter::write_str( + f, + concat!("Keyword [", stringify!($ident), "]"), + ) + } + } + + impl $crate::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => {}; +} diff --git a/syn/src/custom_punctuation.rs b/syn/src/custom_punctuation.rs new file mode 100644 index 0000000..29fa448 --- /dev/null +++ b/syn/src/custom_punctuation.rs @@ -0,0 +1,309 @@ +/// Define a type that supports parsing and printing a multi-character symbol +/// as if it were a punctuation token. +/// +/// # Usage +/// +/// ``` +/// syn::custom_punctuation!(LeftRightArrow, <=>); +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in punctuation token. +/// +/// - [Peeking] — `input.peek(LeftRightArrow)` +/// +/// - [Parsing] — `input.parse::<LeftRightArrow>()?` +/// +/// - [Printing] — `quote!( ... #lrarrow ... )` +/// +/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)` +/// +/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])` +/// +/// - Field access to its spans — `let spans = lrarrow.spans` +/// +/// [Peeking]: parse::ParseBuffer::peek +/// [Parsing]: parse::ParseBuffer::parse +/// [Printing]: quote::ToTokens +/// [`Span`]: proc_macro2::Span +/// +/// # Example +/// +/// ``` +/// use proc_macro2::{TokenStream, TokenTree}; +/// use syn::parse::{Parse, ParseStream, Peek, Result}; +/// use syn::punctuated::Punctuated; +/// use syn::Expr; +/// +/// syn::custom_punctuation!(PathSeparator, </>); +/// +/// // expr </> expr </> expr ... +/// struct PathSegments { +/// segments: Punctuated<Expr, PathSeparator>, +/// } +/// +/// impl Parse for PathSegments { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let mut segments = Punctuated::new(); +/// +/// let first = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(first)?); +/// +/// while input.peek(PathSeparator) { +/// segments.push_punct(input.parse()?); +/// +/// let next = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(next)?); +/// } +/// +/// Ok(PathSegments { segments }) +/// } +/// } +/// +/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> { +/// let mut tokens = TokenStream::new(); +/// while !input.is_empty() && !input.peek(end) { +/// let next: TokenTree = input.parse()?; +/// tokens.extend(Some(next)); +/// } +/// Ok(tokens) +/// } +/// +/// fn main() { +/// let input = r#" a::b </> c::d::e "#; +/// let _: PathSegments = syn::parse_str(input).unwrap(); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + pub struct $ident { + pub spans: custom_punctuation_repr!($($tt)+), + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>( + spans: __S, + ) -> $ident { + let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*; + $ident { + spans: $crate::export::IntoSpans::into_spans(spans) + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident($crate::export::Span::call_site()) + } + } + + impl_parse_for_custom_punctuation!($ident, $($tt)+); + impl_to_tokens_for_custom_punctuation!($ident, $($tt)+); + impl_clone_for_custom_punctuation!($ident, $($tt)+); + impl_extra_traits_for_custom_punctuation!($ident, $($tt)+); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::token::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> bool { + $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+)) + } + + fn display() -> &'static $crate::export::str { + custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + let spans: custom_punctuation_repr!($($tt)+) = + $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?; + Ok($ident(spans)) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::Debug for $ident { + fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { + $crate::export::Formatter::write_str(f, stringify!($ident)) + } + } + + impl $crate::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation_repr { + ($($tt:tt)+) => { + [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+] + }; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +#[rustfmt::skip] +macro_rules! custom_punctuation_len { + ($mode:ident, +) => { 1 }; + ($mode:ident, +=) => { 2 }; + ($mode:ident, &) => { 1 }; + ($mode:ident, &&) => { 2 }; + ($mode:ident, &=) => { 2 }; + ($mode:ident, @) => { 1 }; + ($mode:ident, !) => { 1 }; + ($mode:ident, ^) => { 1 }; + ($mode:ident, ^=) => { 2 }; + ($mode:ident, :) => { 1 }; + ($mode:ident, ::) => { 2 }; + ($mode:ident, ,) => { 1 }; + ($mode:ident, /) => { 1 }; + ($mode:ident, /=) => { 2 }; + ($mode:ident, .) => { 1 }; + ($mode:ident, ..) => { 2 }; + ($mode:ident, ...) => { 3 }; + ($mode:ident, ..=) => { 3 }; + ($mode:ident, =) => { 1 }; + ($mode:ident, ==) => { 2 }; + ($mode:ident, >=) => { 2 }; + ($mode:ident, >) => { 1 }; + ($mode:ident, <=) => { 2 }; + ($mode:ident, <) => { 1 }; + ($mode:ident, *=) => { 2 }; + ($mode:ident, !=) => { 2 }; + ($mode:ident, |) => { 1 }; + ($mode:ident, |=) => { 2 }; + ($mode:ident, ||) => { 2 }; + ($mode:ident, #) => { 1 }; + ($mode:ident, ?) => { 1 }; + ($mode:ident, ->) => { 2 }; + ($mode:ident, <-) => { 2 }; + ($mode:ident, %) => { 1 }; + ($mode:ident, %=) => { 2 }; + ($mode:ident, =>) => { 2 }; + ($mode:ident, ;) => { 1 }; + ($mode:ident, <<) => { 2 }; + ($mode:ident, <<=) => { 3 }; + ($mode:ident, >>) => { 2 }; + ($mode:ident, >>=) => { 3 }; + ($mode:ident, *) => { 1 }; + ($mode:ident, -) => { 1 }; + ($mode:ident, -=) => { 2 }; + ($mode:ident, ~) => { 1 }; + (lenient, $tt:tt) => { 0 }; + (strict, $tt:tt) => {{ custom_punctuation_unexpected!($tt); 0 }}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_unexpected { + () => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! stringify_punct { + ($($tt:tt)+) => { + concat!($(stringify!($tt)),+) + }; +} + +// Not public API. +// Without this, local_inner_macros breaks when looking for concat! +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_concat { + ($($tt:tt)*) => { + concat!($($tt)*) + }; +} diff --git a/syn/src/data.rs b/syn/src/data.rs new file mode 100644 index 0000000..184a79e --- /dev/null +++ b/syn/src/data.rs @@ -0,0 +1,456 @@ +use super::*; +use crate::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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Fields { + /// Named fields of a struct or struct variant such as `Point { x: f64, + /// y: f64 }`. + Named(FieldsNamed), + + /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. + Unnamed(FieldsUnnamed), + + /// Unit struct or unit variant such as `None`. + Unit, + } +} + +ast_struct! { + /// 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 struct FieldsNamed { + pub brace_token: token::Brace, + pub named: Punctuated<Field, Token![,]>, + } +} + +ast_struct! { + /// 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 struct FieldsUnnamed { + pub paren_token: token::Paren, + pub unnamed: Punctuated<Field, Token![,]>, + } +} + +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. + pub fn iter(&self) -> punctuated::Iter<Field> { + match self { + Fields::Unit => crate::punctuated::empty_punctuated_iter(), + Fields::Named(f) => f.named.iter(), + Fields::Unnamed(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. + pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { + match self { + Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), + Fields::Named(f) => f.named.iter_mut(), + Fields::Unnamed(f) => f.unnamed.iter_mut(), + } + } + + /// Returns the number of fields. + pub fn len(&self) -> usize { + match self { + Fields::Unit => 0, + Fields::Named(f) => f.named.len(), + Fields::Unnamed(f) => f.unnamed.len(), + } + } + + /// Returns `true` if there are zero fields. + pub fn is_empty(&self) -> bool { + match self { + Fields::Unit => true, + Fields::Named(f) => f.named.is_empty(), + Fields::Unnamed(f) => f.unnamed.is_empty(), + } + } +} + +impl IntoIterator for Fields { + type Item = Field; + type IntoIter = punctuated::IntoIter<Field>; + + fn into_iter(self) -> Self::IntoIter { + match self { + Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), + Fields::Named(f) => f.named.into_iter(), + Fields::Unnamed(f) => f.unnamed.into_iter(), + } + } +} + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Visibility { + /// A public visibility level: `pub`. + Public(VisPublic), + + /// A crate-level visibility: `crate`. + Crate(VisCrate), + + /// A visibility level restricted to some path: `pub(self)` or + /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. + Restricted(VisRestricted), + + /// An inherited visibility, which usually means private. + Inherited, + } +} + +ast_struct! { + /// A public visibility level: `pub`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct VisPublic { + pub pub_token: Token![pub], + } +} + +ast_struct! { + /// A crate-level visibility: `crate`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct VisCrate { + pub crate_token: Token![crate], + } +} + +ast_struct! { + /// 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 struct VisRestricted { + pub pub_token: Token![pub], + pub paren_token: token::Paren, + pub in_token: Option<Token![in]>, + pub path: Box<Path>, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::ext::IdentExt; + use crate::parse::discouraged::Speculative; + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Variant { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Variant { + attrs: input.call(Attribute::parse_outer)?, + ident: input.parse()?, + fields: { + if input.peek(token::Brace) { + Fields::Named(input.parse()?) + } else if input.peek(token::Paren) { + Fields::Unnamed(input.parse()?) + } else { + Fields::Unit + } + }, + discriminant: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let discriminant: Expr = input.parse()?; + Some((eq_token, discriminant)) + } else { + None + } + }, + }) + } + } + + impl Parse for FieldsNamed { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(FieldsNamed { + brace_token: braced!(content in input), + named: content.parse_terminated(Field::parse_named)?, + }) + } + } + + impl Parse for FieldsUnnamed { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(FieldsUnnamed { + paren_token: parenthesized!(content in input), + unnamed: content.parse_terminated(Field::parse_unnamed)?, + }) + } + } + + impl Field { + /// Parses a named (braced struct) field. + pub fn parse_named(input: ParseStream) -> Result<Self> { + Ok(Field { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + ident: Some(input.parse()?), + colon_token: Some(input.parse()?), + ty: input.parse()?, + }) + } + + /// Parses an unnamed (tuple struct) field. + pub fn parse_unnamed(input: ParseStream) -> Result<Self> { + Ok(Field { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + ident: None, + colon_token: None, + ty: input.parse()?, + }) + } + } + + impl Parse for Visibility { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![pub]) { + Self::parse_pub(input) + } else if input.peek(Token![crate]) { + Self::parse_crate(input) + } else { + Ok(Visibility::Inherited) + } + } + } + + impl Visibility { + fn parse_pub(input: ParseStream) -> Result<Self> { + let pub_token = input.parse::<Token![pub]>()?; + + if input.peek(token::Paren) { + let ahead = input.fork(); + + let content; + let paren_token = parenthesized!(content in ahead); + if content.peek(Token![crate]) + || content.peek(Token![self]) + || content.peek(Token![super]) + { + let path = content.call(Ident::parse_any)?; + + // Ensure there are no additional tokens within `content`. + // Without explicitly checking, we may misinterpret a tuple + // field as a restricted visibility, causing a parse error. + // e.g. `pub (crate::A, crate::B)` (Issue #720). + if content.is_empty() { + input.advance_to(&ahead); + return Ok(Visibility::Restricted(VisRestricted { + pub_token, + paren_token, + in_token: None, + path: Box::new(Path::from(path)), + })); + } + } else if content.peek(Token![in]) { + let in_token: Token![in] = content.parse()?; + let path = content.call(Path::parse_mod_style)?; + + input.advance_to(&ahead); + return Ok(Visibility::Restricted(VisRestricted { + pub_token, + paren_token, + in_token: Some(in_token), + path: Box::new(path), + })); + } + } + + Ok(Visibility::Public(VisPublic { pub_token })) + } + + fn parse_crate(input: ParseStream) -> Result<Self> { + if input.peek2(Token![::]) { + Ok(Visibility::Inherited) + } else { + Ok(Visibility::Crate(VisCrate { + crate_token: input.parse()?, + })) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use crate::print::TokensOrDefault; + + 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((eq_token, 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(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| { + // TODO: 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/syn/src/derive.rs b/syn/src/derive.rs new file mode 100644 index 0000000..8cb9cf7 --- /dev/null +++ b/syn/src/derive.rs @@ -0,0 +1,273 @@ +use super::*; +use crate::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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Data { + /// A struct input to a `proc_macro_derive` macro. + Struct(DataStruct), + + /// An enum input to a `proc_macro_derive` macro. + Enum(DataEnum), + + /// An untagged union input to a `proc_macro_derive` macro. + Union(DataUnion), + } + + do_not_generate_to_tokens +} + +ast_struct! { + /// 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![;]>, + } +} + +ast_struct! { + /// An enum input to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` + /// feature.* + pub struct DataEnum { + pub enum_token: Token![enum], + pub brace_token: token::Brace, + pub variants: Punctuated<Variant, Token![,]>, + } +} + +ast_struct! { + /// An untagged union input to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` + /// feature.* + pub struct DataUnion { + pub union_token: Token![union], + pub fields: FieldsNamed, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for DeriveInput { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![struct]) { + let struct_token = input.parse::<Token![struct]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields, semi) = data_struct(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Struct(DataStruct { + struct_token, + fields, + semi_token: semi, + }), + }) + } else if lookahead.peek(Token![enum]) { + let enum_token = input.parse::<Token![enum]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, brace, variants) = data_enum(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Enum(DataEnum { + enum_token, + brace_token: brace, + variants, + }), + }) + } else if lookahead.peek(Token![union]) { + let union_token = input.parse::<Token![union]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields) = data_union(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Union(DataUnion { + union_token, + fields, + }), + }) + } else { + Err(lookahead.error()) + } + } + } + + pub fn data_struct( + input: ParseStream, + ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> { + let mut lookahead = input.lookahead1(); + let mut where_clause = None; + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if where_clause.is_none() && lookahead.peek(token::Paren) { + let fields = input.parse()?; + + lookahead = input.lookahead1(); + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unnamed(fields), Some(semi))) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(token::Brace) { + let fields = input.parse()?; + Ok((where_clause, Fields::Named(fields), None)) + } else if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unit, Some(semi))) + } else { + Err(lookahead.error()) + } + } + + pub fn data_enum( + input: ParseStream, + ) -> Result<( + Option<WhereClause>, + token::Brace, + Punctuated<Variant, Token![,]>, + )> { + let where_clause = input.parse()?; + + let content; + let brace = braced!(content in input); + let variants = content.parse_terminated(Variant::parse)?; + + Ok((where_clause, brace, variants)) + } + + pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> { + let where_clause = input.parse()?; + let fields = input.parse()?; + Ok((where_clause, fields)) + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::ToTokens; + + use crate::attr::FilterAttrs; + use crate::print::TokensOrDefault; + + 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(d) => d.struct_token.to_tokens(tokens), + Data::Enum(d) => d.enum_token.to_tokens(tokens), + Data::Union(d) => d.union_token.to_tokens(tokens), + } + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + match &self.data { + Data::Struct(data) => match &data.fields { + Fields::Named(fields) => { + self.generics.where_clause.to_tokens(tokens); + fields.to_tokens(tokens); + } + Fields::Unnamed(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(data) => { + self.generics.where_clause.to_tokens(tokens); + data.brace_token.surround(tokens, |tokens| { + data.variants.to_tokens(tokens); + }); + } + Data::Union(data) => { + self.generics.where_clause.to_tokens(tokens); + data.fields.to_tokens(tokens); + } + } + } + } +} diff --git a/syn/src/discouraged.rs b/syn/src/discouraged.rs new file mode 100644 index 0000000..29d1006 --- /dev/null +++ b/syn/src/discouraged.rs @@ -0,0 +1,195 @@ +//! Extensions to the parsing API with niche applicability. + +use super::*; + +/// Extensions to the `ParseStream` API to support speculative parsing. +pub trait Speculative { + /// Advance this parse stream to the position of a forked parse stream. + /// + /// This is the opposite operation to [`ParseStream::fork`]. You can fork a + /// parse stream, perform some speculative parsing, then join the original + /// stream to the fork to "commit" the parsing from the fork to the main + /// stream. + /// + /// If you can avoid doing this, you should, as it limits the ability to + /// generate useful errors. That said, it is often the only way to parse + /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem + /// is that when the fork fails to parse an `A`, it's impossible to tell + /// whether that was because of a syntax error and the user meant to provide + /// an `A`, or that the `A`s are finished and its time to start parsing + /// `B`s. Use with care. + /// + /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by + /// parsing `B*` and removing the leading members of `A` from the + /// repetition, bypassing the need to involve the downsides associated with + /// speculative parsing. + /// + /// [`ParseStream::fork`]: ParseBuffer::fork + /// + /// # Example + /// + /// There has been chatter about the possibility of making the colons in the + /// turbofish syntax like `path::to::<T>` no longer required by accepting + /// `path::to<T>` in expression position. Specifically, according to [RFC + /// 2544], [`PathSegment`] parsing should always try to consume a following + /// `<` token as the start of generic arguments, and reset to the `<` if + /// that fails (e.g. the token is acting as a less-than operator). + /// + /// This is the exact kind of parsing behavior which requires the "fork, + /// try, commit" behavior that [`ParseStream::fork`] discourages. With + /// `advance_to`, we can avoid having to parse the speculatively parsed + /// content a second time. + /// + /// This change in behavior can be implemented in syn by replacing just the + /// `Parse` implementation for `PathSegment`: + /// + /// ``` + /// # use syn::ext::IdentExt; + /// use syn::parse::discouraged::Speculative; + /// # use syn::parse::{Parse, ParseStream}; + /// # use syn::{Ident, PathArguments, Result, Token}; + /// + /// 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, + /// # } + /// # } + /// # } + /// + /// impl Parse for PathSegment { + /// fn parse(input: ParseStream) -> Result<Self> { + /// if input.peek(Token![super]) + /// || input.peek(Token![self]) + /// || input.peek(Token![Self]) + /// || input.peek(Token![crate]) + /// || input.peek(Token![extern]) + /// { + /// let ident = input.call(Ident::parse_any)?; + /// return Ok(PathSegment::from(ident)); + /// } + /// + /// let ident = input.parse()?; + /// if input.peek(Token![::]) && input.peek3(Token![<]) { + /// return Ok(PathSegment { + /// ident, + /// arguments: PathArguments::AngleBracketed(input.parse()?), + /// }); + /// } + /// if input.peek(Token![<]) && !input.peek(Token![<=]) { + /// let fork = input.fork(); + /// if let Ok(arguments) = fork.parse() { + /// input.advance_to(&fork); + /// return Ok(PathSegment { + /// ident, + /// arguments: PathArguments::AngleBracketed(arguments), + /// }); + /// } + /// } + /// Ok(PathSegment::from(ident)) + /// } + /// } + /// + /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap(); + /// ``` + /// + /// # Drawbacks + /// + /// The main drawback of this style of speculative parsing is in error + /// presentation. Even if the lookahead is the "correct" parse, the error + /// that is shown is that of the "fallback" parse. To use the same example + /// as the turbofish above, take the following unfinished "turbofish": + /// + /// ```text + /// let _ = f<&'a fn(), for<'a> serde::>(); + /// ``` + /// + /// If this is parsed as generic arguments, we can provide the error message + /// + /// ```text + /// error: expected identifier + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^ + /// ``` + /// + /// but if parsed using the above speculative parsing, it falls back to + /// assuming that the `<` is a less-than when it fails to parse the generic + /// arguments, and tries to interpret the `&'a` as the start of a labelled + /// loop, resulting in the much less helpful error + /// + /// ```text + /// error: expected `:` + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^^ + /// ``` + /// + /// This can be mitigated with various heuristics (two examples: show both + /// forks' parse errors, or show the one that consumed more tokens), but + /// when you can control the grammar, sticking to something that can be + /// parsed LL(3) and without the LL(*) speculative parsing this makes + /// possible, displaying reasonable errors becomes much more simple. + /// + /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544 + /// [`PathSegment`]: crate::PathSegment + /// + /// # Performance + /// + /// This method performs a cheap fixed amount of work that does not depend + /// on how far apart the two streams are positioned. + /// + /// # Panics + /// + /// The forked stream in the argument of `advance_to` must have been + /// obtained by forking `self`. Attempting to advance to any other stream + /// will cause a panic. + fn advance_to(&self, fork: &Self); +} + +impl<'a> Speculative for ParseBuffer<'a> { + fn advance_to(&self, fork: &Self) { + if !crate::buffer::same_scope(self.cursor(), fork.cursor()) { + panic!("Fork was not derived from the advancing parse stream"); + } + + let (self_unexp, self_sp) = inner_unexpected(self); + let (fork_unexp, fork_sp) = inner_unexpected(fork); + if !Rc::ptr_eq(&self_unexp, &fork_unexp) { + match (fork_sp, self_sp) { + // Unexpected set on the fork, but not on `self`, copy it over. + (Some(span), None) => { + self_unexp.set(Unexpected::Some(span)); + } + // Unexpected unset. Use chain to propagate errors from fork. + (None, None) => { + fork_unexp.set(Unexpected::Chain(self_unexp)); + + // Ensure toplevel 'unexpected' tokens from the fork don't + // bubble up the chain by replacing the root `unexpected` + // pointer, only 'unexpected' tokens from existing group + // parsers should bubble. + fork.unexpected + .set(Some(Rc::new(Cell::new(Unexpected::None)))); + } + // Unexpected has been set on `self`. No changes needed. + (_, Some(_)) => {} + } + } + + // See comment on `cell` in the struct definition. + self.cell + .set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) }) + } +} diff --git a/syn/src/error.rs b/syn/src/error.rs new file mode 100644 index 0000000..146d652 --- /dev/null +++ b/syn/src/error.rs @@ -0,0 +1,357 @@ +use std; +use std::fmt::{self, Debug, Display}; +use std::iter::FromIterator; +use std::slice; +use std::vec; + +use proc_macro2::{ + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, +}; +#[cfg(feature = "printing")] +use quote::ToTokens; + +#[cfg(feature = "parsing")] +use crate::buffer::Cursor; +use crate::thread::ThreadBound; + +/// The result of a Syn parser. +pub type Result<T> = std::result::Result<T, Error>; + +/// Error returned when a Syn parser cannot parse the input tokens. +/// +/// # Error reporting in proc macros +/// +/// The correct way to report errors back to the compiler from a procedural +/// macro is by emitting an appropriately spanned invocation of +/// [`compile_error!`] in the generated code. This produces a better diagnostic +/// message than simply panicking the macro. +/// +/// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html +/// +/// When parsing macro input, the [`parse_macro_input!`] macro handles the +/// conversion to `compile_error!` automatically. +/// +/// ``` +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::{parse_macro_input, AttributeArgs, ItemFn}; +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_attribute] +/// # }; +/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { +/// let args = parse_macro_input!(args as AttributeArgs); +/// let input = parse_macro_input!(input as ItemFn); +/// +/// /* ... */ +/// # TokenStream::new() +/// } +/// ``` +/// +/// For errors that arise later than the initial parsing stage, the +/// [`.to_compile_error()`] method can be used to perform an explicit conversion +/// to `compile_error!`. +/// +/// [`.to_compile_error()`]: Error::to_compile_error +/// +/// ``` +/// # extern crate proc_macro; +/// # +/// # use proc_macro::TokenStream; +/// # use syn::{parse_macro_input, DeriveInput}; +/// # +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_derive(MyDerive)] +/// # }; +/// pub fn my_derive(input: TokenStream) -> TokenStream { +/// let input = parse_macro_input!(input as DeriveInput); +/// +/// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream> +/// expand::my_derive(input) +/// .unwrap_or_else(|err| err.to_compile_error()) +/// .into() +/// } +/// # +/// # mod expand { +/// # use proc_macro2::TokenStream; +/// # use syn::{DeriveInput, Result}; +/// # +/// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> { +/// # unimplemented!() +/// # } +/// # } +/// ``` +#[derive(Clone)] +pub struct Error { + messages: Vec<ErrorMessage>, +} + +struct ErrorMessage { + // Span is implemented as an index into a thread-local interner to keep the + // size small. It is not safe to access from a different thread. We want + // errors to be Send and Sync to play nicely with the Failure crate, so pin + // the span we're given to its original thread and assume it is + // Span::call_site if accessed from any other thread. + start_span: ThreadBound<Span>, + end_span: ThreadBound<Span>, + message: String, +} + +#[cfg(test)] +struct _Test +where + Error: Send + Sync; + +impl Error { + /// Usually the [`ParseStream::error`] method will be used instead, which + /// automatically uses the correct span from the current position of the + /// parse stream. + /// + /// Use `Error::new` when the error needs to be triggered on some span other + /// than where the parse stream is currently positioned. + /// + /// [`ParseStream::error`]: crate::parse::ParseBuffer::error + /// + /// # Example + /// + /// ``` + /// use syn::{Error, Ident, LitStr, Result, Token}; + /// use syn::parse::ParseStream; + /// + /// // Parses input that looks like `name = "string"` where the key must be + /// // the identifier `name` and the value may be any string literal. + /// // Returns the string literal. + /// fn parse_name(input: ParseStream) -> Result<LitStr> { + /// let name_token: Ident = input.parse()?; + /// if name_token != "name" { + /// // Trigger an error not on the current position of the stream, + /// // but on the position of the unexpected identifier. + /// return Err(Error::new(name_token.span(), "expected `name`")); + /// } + /// input.parse::<Token![=]>()?; + /// let s: LitStr = input.parse()?; + /// Ok(s) + /// } + /// ``` + pub fn new<T: Display>(span: Span, message: T) -> Self { + Error { + messages: vec![ErrorMessage { + start_span: ThreadBound::new(span), + end_span: ThreadBound::new(span), + message: message.to_string(), + }], + } + } + + /// Creates an error with the specified message spanning the given syntax + /// tree node. + /// + /// Unlike the `Error::new` constructor, this constructor takes an argument + /// `tokens` which is a syntax tree node. This allows the resulting `Error` + /// to attempt to span all tokens inside of `tokens`. While you would + /// typically be able to use the `Spanned` trait with the above `Error::new` + /// constructor, implementation limitations today mean that + /// `Error::new_spanned` may provide a higher-quality error message on + /// stable Rust. + /// + /// When in doubt it's recommended to stick to `Error::new` (or + /// `ParseStream::error`)! + #[cfg(feature = "printing")] + pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self { + let mut iter = tokens.into_token_stream().into_iter(); + let start = iter.next().map_or_else(Span::call_site, |t| t.span()); + let end = iter.last().map_or(start, |t| t.span()); + Error { + messages: vec![ErrorMessage { + start_span: ThreadBound::new(start), + end_span: ThreadBound::new(end), + message: message.to_string(), + }], + } + } + + /// The source location of the error. + /// + /// Spans are not thread-safe so this function returns `Span::call_site()` + /// if called from a different thread than the one on which the `Error` was + /// originally created. + pub fn span(&self) -> Span { + let start = match self.messages[0].start_span.get() { + Some(span) => *span, + None => return Span::call_site(), + }; + let end = match self.messages[0].end_span.get() { + Some(span) => *span, + None => return Span::call_site(), + }; + start.join(end).unwrap_or(start) + } + + /// Render the error as an invocation of [`compile_error!`]. + /// + /// The [`parse_macro_input!`] macro provides a convenient way to invoke + /// this method correctly in a procedural macro. + /// + /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html + pub fn to_compile_error(&self) -> TokenStream { + self.messages + .iter() + .map(ErrorMessage::to_compile_error) + .collect() + } + + /// Add another error message to self such that when `to_compile_error()` is + /// called, both errors will be emitted together. + pub fn combine(&mut self, another: Error) { + self.messages.extend(another.messages) + } +} + +impl ErrorMessage { + fn to_compile_error(&self) -> TokenStream { + let start = self + .start_span + .get() + .cloned() + .unwrap_or_else(Span::call_site); + let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site); + + // compile_error!($message) + TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("compile_error", start)), + TokenTree::Punct({ + let mut punct = Punct::new('!', Spacing::Alone); + punct.set_span(start); + punct + }), + TokenTree::Group({ + let mut group = Group::new(Delimiter::Brace, { + TokenStream::from_iter(vec![TokenTree::Literal({ + let mut string = Literal::string(&self.message); + string.set_span(end); + string + })]) + }); + group.set_span(end); + group + }), + ]) + } +} + +#[cfg(feature = "parsing")] +pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error { + if cursor.eof() { + Error::new(scope, format!("unexpected end of input, {}", message)) + } else { + let span = crate::buffer::open_span_of_group(cursor); + Error::new(span, message) + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.messages.len() == 1 { + formatter + .debug_tuple("Error") + .field(&self.messages[0]) + .finish() + } else { + formatter + .debug_tuple("Error") + .field(&self.messages) + .finish() + } + } +} + +impl Debug for ErrorMessage { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.message, formatter) + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(&self.messages[0].message) + } +} + +impl Clone for ErrorMessage { + fn clone(&self) -> Self { + let start = self + .start_span + .get() + .cloned() + .unwrap_or_else(Span::call_site); + let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site); + ErrorMessage { + start_span: ThreadBound::new(start), + end_span: ThreadBound::new(end), + message: self.message.clone(), + } + } +} + +impl std::error::Error for Error { + fn description(&self) -> &str { + "parse error" + } +} + +impl From<LexError> for Error { + fn from(err: LexError) -> Self { + Error::new(Span::call_site(), format!("{:?}", err)) + } +} + +impl IntoIterator for Error { + type Item = Error; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { + messages: self.messages.into_iter(), + } + } +} + +pub struct IntoIter { + messages: vec::IntoIter<ErrorMessage>, +} + +impl Iterator for IntoIter { + type Item = Error; + + fn next(&mut self) -> Option<Self::Item> { + Some(Error { + messages: vec![self.messages.next()?], + }) + } +} + +impl<'a> IntoIterator for &'a Error { + type Item = Error; + type IntoIter = Iter<'a>; + + fn into_iter(self) -> Self::IntoIter { + Iter { + messages: self.messages.iter(), + } + } +} + +pub struct Iter<'a> { + messages: slice::Iter<'a, ErrorMessage>, +} + +impl<'a> Iterator for Iter<'a> { + type Item = Error; + + fn next(&mut self) -> Option<Self::Item> { + Some(Error { + messages: vec![self.messages.next()?.clone()], + }) + } +} diff --git a/syn/src/export.rs b/syn/src/export.rs new file mode 100644 index 0000000..37dc467 --- /dev/null +++ b/syn/src/export.rs @@ -0,0 +1,35 @@ +pub use std::clone::Clone; +pub use std::cmp::{Eq, PartialEq}; +pub use std::convert::From; +pub use std::default::Default; +pub use std::fmt::{self, Debug, Formatter}; +pub use std::hash::{Hash, Hasher}; +pub use std::marker::Copy; +pub use std::option::Option::{None, Some}; +pub use std::result::Result::{Err, Ok}; + +#[cfg(feature = "printing")] +pub extern crate quote; + +pub use proc_macro2::{Span, TokenStream as TokenStream2}; + +pub use crate::span::IntoSpans; + +#[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "proc-macro" +))] +pub use proc_macro::TokenStream; + +#[cfg(feature = "printing")] +pub use quote::{ToTokens, TokenStreamExt}; + +#[allow(non_camel_case_types)] +pub type bool = help::Bool; +#[allow(non_camel_case_types)] +pub type str = help::Str; + +mod help { + pub type Bool = bool; + pub type Str = str; +} diff --git a/syn/src/expr.rs b/syn/src/expr.rs new file mode 100644 index 0000000..603dc32 --- /dev/null +++ b/syn/src/expr.rs @@ -0,0 +1,3236 @@ +use super::*; +use crate::punctuated::Punctuated; +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +use proc_macro2::{Span, TokenStream}; +#[cfg(feature = "printing")] +use quote::IdentFragment; +#[cfg(feature = "printing")] +use std::fmt::{self, Display}; +use std::hash::{Hash, Hasher}; +#[cfg(all(feature = "parsing", feature = "full"))] +use std::mem; + +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::If(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 `If` case we get + /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`. + /// + /// This approach avoids repeating the variant names twice on every line. + /// + /// ``` + /// # use syn::{Expr, ExprMethodCall}; + /// # + /// # fn example(expr: Expr) { + /// // Repetitive; recommend not doing this. + /// match expr { + /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { + /// # } + /// # _ => {} + /// # } + /// # } + /// ``` + /// + /// 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(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 #manual_extra_traits { + /// A slice literal expression: `[a, b, c, d]`. + Array(ExprArray), + + /// An assignment expression: `a = compute()`. + Assign(ExprAssign), + + /// A compound assignment expression: `counter += 1`. + AssignOp(ExprAssignOp), + + /// An async block: `async { ... }`. + Async(ExprAsync), + + /// An await expression: `fut.await`. + Await(ExprAwait), + + /// A binary operation: `a + b`, `a * b`. + Binary(ExprBinary), + + /// A blocked scope: `{ ... }`. + Block(ExprBlock), + + /// A box expression: `box f`. + Box(ExprBox), + + /// A `break`, with an optional label to break and an optional + /// expression. + Break(ExprBreak), + + /// A function call expression: `invoke(a, b)`. + Call(ExprCall), + + /// A cast expression: `foo as f64`. + Cast(ExprCast), + + /// A closure expression: `|a, b| a + b`. + Closure(ExprClosure), + + /// A `continue`, with an optional label. + Continue(ExprContinue), + + /// Access of a named struct field (`obj.k`) or unnamed tuple struct + /// field (`obj.0`). + Field(ExprField), + + /// A for loop: `for pat in expr { ... }`. + ForLoop(ExprForLoop), + + /// 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`. + Group(ExprGroup), + + /// An `if` expression with an optional `else` block: `if expr { ... } + /// else { ... }`. + /// + /// The `else` branch expression may only be an `If` or `Block` + /// expression, not any of the other types of expression. + If(ExprIf), + + /// A square bracketed indexing expression: `vector[2]`. + Index(ExprIndex), + + /// A `let` guard: `let Some(x) = opt`. + Let(ExprLet), + + /// A literal in place of an expression: `1`, `"foo"`. + Lit(ExprLit), + + /// Conditionless loop: `loop { ... }`. + Loop(ExprLoop), + + /// A macro invocation expression: `format!("{}", q)`. + Macro(ExprMacro), + + /// A `match` expression: `match n { Some(n) => {}, None => {} }`. + Match(ExprMatch), + + /// A method call expression: `x.foo::<T>(a, b)`. + MethodCall(ExprMethodCall), + + /// A parenthesized expression: `(a + b)`. + Paren(ExprParen), + + /// 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. + Path(ExprPath), + + /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. + Range(ExprRange), + + /// A referencing operation: `&a` or `&mut a`. + Reference(ExprReference), + + /// An array literal constructed from one repeated element: `[0u8; N]`. + Repeat(ExprRepeat), + + /// A `return`, with an optional value to be returned. + Return(ExprReturn), + + /// 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 }`. + Struct(ExprStruct), + + /// A try-expression: `expr?`. + Try(ExprTry), + + /// A try block: `try { ... }`. + TryBlock(ExprTryBlock), + + /// A tuple expression: `(a, b, c, d)`. + Tuple(ExprTuple), + + /// A type ascription expression: `foo: f64`. + Type(ExprType), + + /// A unary operation: `!x`, `*x`. + Unary(ExprUnary), + + /// An unsafe block: `unsafe { ... }`. + Unsafe(ExprUnsafe), + + /// Tokens in expression position not interpreted by Syn. + Verbatim(TokenStream), + + /// A while loop: `while expr { ... }`. + While(ExprWhile), + + /// A yield expression: `yield expr`. + Yield(ExprYield), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// A slice literal expression: `[a, b, c, d]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprArray #full { + pub attrs: Vec<Attribute>, + pub bracket_token: token::Bracket, + pub elems: Punctuated<Expr, Token![,]>, + } +} + +ast_struct! { + /// An assignment expression: `a = compute()`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprAssign #full { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub eq_token: Token![=], + pub right: Box<Expr>, + } +} + +ast_struct! { + /// A compound assignment expression: `counter += 1`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprAssignOp #full { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub op: BinOp, + pub right: Box<Expr>, + } +} + +ast_struct! { + /// An async block: `async { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprAsync #full { + pub attrs: Vec<Attribute>, + pub async_token: Token![async], + pub capture: Option<Token![move]>, + pub block: Block, + } +} + +ast_struct! { + /// An await expression: `fut.await`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprAwait #full { + pub attrs: Vec<Attribute>, + pub base: Box<Expr>, + pub dot_token: Token![.], + pub await_token: token::Await, + } +} + +ast_struct! { + /// A binary operation: `a + b`, `a * b`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprBinary { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub op: BinOp, + pub right: Box<Expr>, + } +} + +ast_struct! { + /// A blocked scope: `{ ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprBlock #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub block: Block, + } +} + +ast_struct! { + /// A box expression: `box f`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprBox #full { + pub attrs: Vec<Attribute>, + pub box_token: Token![box], + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// 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 struct ExprBreak #full { + pub attrs: Vec<Attribute>, + pub break_token: Token![break], + pub label: Option<Lifetime>, + pub expr: Option<Box<Expr>>, + } +} + +ast_struct! { + /// A function call expression: `invoke(a, b)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprCall { + pub attrs: Vec<Attribute>, + pub func: Box<Expr>, + pub paren_token: token::Paren, + pub args: Punctuated<Expr, Token![,]>, + } +} + +ast_struct! { + /// A cast expression: `foo as f64`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprCast { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub as_token: Token![as], + pub ty: Box<Type>, + } +} + +ast_struct! { + /// A closure expression: `|a, b| a + b`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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<Pat, Token![,]>, + pub or2_token: Token![|], + pub output: ReturnType, + pub body: Box<Expr>, + } +} + +ast_struct! { + /// A `continue`, with an optional label. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprContinue #full { + pub attrs: Vec<Attribute>, + pub continue_token: Token![continue], + pub label: Option<Lifetime>, + } +} + +ast_struct! { + /// 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 struct ExprField { + pub attrs: Vec<Attribute>, + pub base: Box<Expr>, + pub dot_token: Token![.], + pub member: Member, + } +} + +ast_struct! { + /// A for loop: `for pat in expr { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprForLoop #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub for_token: Token![for], + pub pat: Pat, + pub in_token: Token![in], + pub expr: Box<Expr>, + pub body: Block, + } +} + +ast_struct! { + /// 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 struct ExprGroup #full { + pub attrs: Vec<Attribute>, + pub group_token: token::Group, + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// An `if` expression with an optional `else` block: `if expr { ... } + /// else { ... }`. + /// + /// The `else` branch expression may only be an `If` or `Block` + /// expression, not any of the other types of expression. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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>)>, + } +} + +ast_struct! { + /// A square bracketed indexing expression: `vector[2]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprIndex { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub bracket_token: token::Bracket, + pub index: Box<Expr>, + } +} + +ast_struct! { + /// A `let` guard: `let Some(x) = opt`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprLet #full { + pub attrs: Vec<Attribute>, + pub let_token: Token![let], + pub pat: Pat, + pub eq_token: Token![=], + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// A literal in place of an expression: `1`, `"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprLit { + pub attrs: Vec<Attribute>, + pub lit: Lit, + } +} + +ast_struct! { + /// Conditionless loop: `loop { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprLoop #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub loop_token: Token![loop], + pub body: Block, + } +} + +ast_struct! { + /// A macro invocation expression: `format!("{}", q)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprMacro #full { + pub attrs: Vec<Attribute>, + pub mac: Macro, + } +} + +ast_struct! { + /// A `match` expression: `match n { Some(n) => {}, None => {} }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprMatch #full { + pub attrs: Vec<Attribute>, + pub match_token: Token![match], + pub expr: Box<Expr>, + pub brace_token: token::Brace, + pub arms: Vec<Arm>, + } +} + +ast_struct! { + /// A method call expression: `x.foo::<T>(a, b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![,]>, + } +} + +ast_struct! { + /// A parenthesized expression: `(a + b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprParen { + pub attrs: Vec<Attribute>, + pub paren_token: token::Paren, + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// 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 struct ExprPath { + pub attrs: Vec<Attribute>, + pub qself: Option<QSelf>, + pub path: Path, + } +} + +ast_struct! { + /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprRange #full { + pub attrs: Vec<Attribute>, + pub from: Option<Box<Expr>>, + pub limits: RangeLimits, + pub to: Option<Box<Expr>>, + } +} + +ast_struct! { + /// A referencing operation: `&a` or `&mut a`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprReference #full { + pub attrs: Vec<Attribute>, + pub and_token: Token![&], + pub raw: Reserved, + pub mutability: Option<Token![mut]>, + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// An array literal constructed from one repeated element: `[0u8; N]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprRepeat #full { + pub attrs: Vec<Attribute>, + pub bracket_token: token::Bracket, + pub expr: Box<Expr>, + pub semi_token: Token![;], + pub len: Box<Expr>, + } +} + +ast_struct! { + /// A `return`, with an optional value to be returned. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprReturn #full { + pub attrs: Vec<Attribute>, + pub return_token: Token![return], + pub expr: Option<Box<Expr>>, + } +} + +ast_struct! { + /// 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>>, + } +} + +ast_struct! { + /// A try-expression: `expr?`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprTry #full { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub question_token: Token![?], + } +} + +ast_struct! { + /// A try block: `try { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprTryBlock #full { + pub attrs: Vec<Attribute>, + pub try_token: Token![try], + pub block: Block, + } +} + +ast_struct! { + /// A tuple expression: `(a, b, c, d)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprTuple #full { + pub attrs: Vec<Attribute>, + pub paren_token: token::Paren, + pub elems: Punctuated<Expr, Token![,]>, + } +} + +ast_struct! { + /// A type ascription expression: `foo: f64`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprType #full { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub colon_token: Token![:], + pub ty: Box<Type>, + } +} + +ast_struct! { + /// A unary operation: `!x`, `*x`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct ExprUnary { + pub attrs: Vec<Attribute>, + pub op: UnOp, + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// An unsafe block: `unsafe { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprUnsafe #full { + pub attrs: Vec<Attribute>, + pub unsafe_token: Token![unsafe], + pub block: Block, + } +} + +ast_struct! { + /// A while loop: `while expr { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprWhile #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub while_token: Token![while], + pub cond: Box<Expr>, + pub body: Block, + } +} + +ast_struct! { + /// A yield expression: `yield expr`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ExprYield #full { + pub attrs: Vec<Attribute>, + pub yield_token: Token![yield], + pub expr: Option<Box<Expr>>, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Expr {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Expr { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Expr::Array(this), Expr::Array(other)) => this == other, + (Expr::Assign(this), Expr::Assign(other)) => this == other, + (Expr::AssignOp(this), Expr::AssignOp(other)) => this == other, + (Expr::Async(this), Expr::Async(other)) => this == other, + (Expr::Await(this), Expr::Await(other)) => this == other, + (Expr::Binary(this), Expr::Binary(other)) => this == other, + (Expr::Block(this), Expr::Block(other)) => this == other, + (Expr::Box(this), Expr::Box(other)) => this == other, + (Expr::Break(this), Expr::Break(other)) => this == other, + (Expr::Call(this), Expr::Call(other)) => this == other, + (Expr::Cast(this), Expr::Cast(other)) => this == other, + (Expr::Closure(this), Expr::Closure(other)) => this == other, + (Expr::Continue(this), Expr::Continue(other)) => this == other, + (Expr::Field(this), Expr::Field(other)) => this == other, + (Expr::ForLoop(this), Expr::ForLoop(other)) => this == other, + (Expr::Group(this), Expr::Group(other)) => this == other, + (Expr::If(this), Expr::If(other)) => this == other, + (Expr::Index(this), Expr::Index(other)) => this == other, + (Expr::Let(this), Expr::Let(other)) => this == other, + (Expr::Lit(this), Expr::Lit(other)) => this == other, + (Expr::Loop(this), Expr::Loop(other)) => this == other, + (Expr::Macro(this), Expr::Macro(other)) => this == other, + (Expr::Match(this), Expr::Match(other)) => this == other, + (Expr::MethodCall(this), Expr::MethodCall(other)) => this == other, + (Expr::Paren(this), Expr::Paren(other)) => this == other, + (Expr::Path(this), Expr::Path(other)) => this == other, + (Expr::Range(this), Expr::Range(other)) => this == other, + (Expr::Reference(this), Expr::Reference(other)) => this == other, + (Expr::Repeat(this), Expr::Repeat(other)) => this == other, + (Expr::Return(this), Expr::Return(other)) => this == other, + (Expr::Struct(this), Expr::Struct(other)) => this == other, + (Expr::Try(this), Expr::Try(other)) => this == other, + (Expr::TryBlock(this), Expr::TryBlock(other)) => this == other, + (Expr::Tuple(this), Expr::Tuple(other)) => this == other, + (Expr::Type(this), Expr::Type(other)) => this == other, + (Expr::Unary(this), Expr::Unary(other)) => this == other, + (Expr::Unsafe(this), Expr::Unsafe(other)) => this == other, + (Expr::Verbatim(this), Expr::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + (Expr::While(this), Expr::While(other)) => this == other, + (Expr::Yield(this), Expr::Yield(other)) => this == other, + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Expr { + fn hash<H>(&self, hash: &mut H) + where + H: Hasher, + { + match self { + Expr::Array(expr) => { + hash.write_u8(0); + expr.hash(hash); + } + Expr::Assign(expr) => { + hash.write_u8(1); + expr.hash(hash); + } + Expr::AssignOp(expr) => { + hash.write_u8(2); + expr.hash(hash); + } + Expr::Async(expr) => { + hash.write_u8(3); + expr.hash(hash); + } + Expr::Await(expr) => { + hash.write_u8(4); + expr.hash(hash); + } + Expr::Binary(expr) => { + hash.write_u8(5); + expr.hash(hash); + } + Expr::Block(expr) => { + hash.write_u8(6); + expr.hash(hash); + } + Expr::Box(expr) => { + hash.write_u8(7); + expr.hash(hash); + } + Expr::Break(expr) => { + hash.write_u8(8); + expr.hash(hash); + } + Expr::Call(expr) => { + hash.write_u8(9); + expr.hash(hash); + } + Expr::Cast(expr) => { + hash.write_u8(10); + expr.hash(hash); + } + Expr::Closure(expr) => { + hash.write_u8(11); + expr.hash(hash); + } + Expr::Continue(expr) => { + hash.write_u8(12); + expr.hash(hash); + } + Expr::Field(expr) => { + hash.write_u8(13); + expr.hash(hash); + } + Expr::ForLoop(expr) => { + hash.write_u8(14); + expr.hash(hash); + } + Expr::Group(expr) => { + hash.write_u8(15); + expr.hash(hash); + } + Expr::If(expr) => { + hash.write_u8(16); + expr.hash(hash); + } + Expr::Index(expr) => { + hash.write_u8(17); + expr.hash(hash); + } + Expr::Let(expr) => { + hash.write_u8(18); + expr.hash(hash); + } + Expr::Lit(expr) => { + hash.write_u8(19); + expr.hash(hash); + } + Expr::Loop(expr) => { + hash.write_u8(20); + expr.hash(hash); + } + Expr::Macro(expr) => { + hash.write_u8(21); + expr.hash(hash); + } + Expr::Match(expr) => { + hash.write_u8(22); + expr.hash(hash); + } + Expr::MethodCall(expr) => { + hash.write_u8(23); + expr.hash(hash); + } + Expr::Paren(expr) => { + hash.write_u8(24); + expr.hash(hash); + } + Expr::Path(expr) => { + hash.write_u8(25); + expr.hash(hash); + } + Expr::Range(expr) => { + hash.write_u8(26); + expr.hash(hash); + } + Expr::Reference(expr) => { + hash.write_u8(27); + expr.hash(hash); + } + Expr::Repeat(expr) => { + hash.write_u8(28); + expr.hash(hash); + } + Expr::Return(expr) => { + hash.write_u8(29); + expr.hash(hash); + } + Expr::Struct(expr) => { + hash.write_u8(30); + expr.hash(hash); + } + Expr::Try(expr) => { + hash.write_u8(31); + expr.hash(hash); + } + Expr::TryBlock(expr) => { + hash.write_u8(32); + expr.hash(hash); + } + Expr::Tuple(expr) => { + hash.write_u8(33); + expr.hash(hash); + } + Expr::Type(expr) => { + hash.write_u8(34); + expr.hash(hash); + } + Expr::Unary(expr) => { + hash.write_u8(35); + expr.hash(hash); + } + Expr::Unsafe(expr) => { + hash.write_u8(36); + expr.hash(hash); + } + Expr::Verbatim(expr) => { + hash.write_u8(37); + TokenStreamHelper(expr).hash(hash); + } + Expr::While(expr) => { + hash.write_u8(38); + expr.hash(hash); + } + Expr::Yield(expr) => { + hash.write_u8(39); + expr.hash(hash); + } + Expr::__Nonexhaustive => unreachable!(), + } + } +} + +impl Expr { + #[cfg(all(feature = "parsing", feature = "full"))] + pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> { + match self { + Expr::Box(ExprBox { attrs, .. }) + | Expr::Array(ExprArray { attrs, .. }) + | Expr::Call(ExprCall { attrs, .. }) + | Expr::MethodCall(ExprMethodCall { attrs, .. }) + | Expr::Tuple(ExprTuple { attrs, .. }) + | Expr::Binary(ExprBinary { attrs, .. }) + | Expr::Unary(ExprUnary { attrs, .. }) + | Expr::Lit(ExprLit { attrs, .. }) + | Expr::Cast(ExprCast { attrs, .. }) + | Expr::Type(ExprType { attrs, .. }) + | Expr::Let(ExprLet { attrs, .. }) + | Expr::If(ExprIf { attrs, .. }) + | Expr::While(ExprWhile { attrs, .. }) + | Expr::ForLoop(ExprForLoop { attrs, .. }) + | Expr::Loop(ExprLoop { attrs, .. }) + | Expr::Match(ExprMatch { attrs, .. }) + | Expr::Closure(ExprClosure { attrs, .. }) + | Expr::Unsafe(ExprUnsafe { attrs, .. }) + | Expr::Block(ExprBlock { attrs, .. }) + | Expr::Assign(ExprAssign { attrs, .. }) + | Expr::AssignOp(ExprAssignOp { attrs, .. }) + | Expr::Field(ExprField { attrs, .. }) + | Expr::Index(ExprIndex { attrs, .. }) + | Expr::Range(ExprRange { attrs, .. }) + | Expr::Path(ExprPath { attrs, .. }) + | Expr::Reference(ExprReference { attrs, .. }) + | Expr::Break(ExprBreak { attrs, .. }) + | Expr::Continue(ExprContinue { attrs, .. }) + | Expr::Return(ExprReturn { attrs, .. }) + | Expr::Macro(ExprMacro { attrs, .. }) + | Expr::Struct(ExprStruct { attrs, .. }) + | Expr::Repeat(ExprRepeat { attrs, .. }) + | Expr::Paren(ExprParen { attrs, .. }) + | Expr::Group(ExprGroup { attrs, .. }) + | Expr::Try(ExprTry { attrs, .. }) + | Expr::Async(ExprAsync { attrs, .. }) + | Expr::Await(ExprAwait { attrs, .. }) + | Expr::TryBlock(ExprTryBlock { attrs, .. }) + | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), + Expr::Verbatim(_) => Vec::new(), + Expr::__Nonexhaustive => unreachable!(), + } + } +} + +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.* + #[derive(Eq, PartialEq, Hash)] + pub enum Member #manual_extra_traits { + /// A named field like `self.x`. + Named(Ident), + /// An unnamed field like `self.0`. + Unnamed(Index), + } +} + +#[cfg(feature = "printing")] +impl IdentFragment for Member { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Member::Named(m) => Display::fmt(m, formatter), + Member::Unnamed(m) => Display::fmt(&m.index, formatter), + } + } + + fn span(&self) -> Option<Span> { + match self { + Member::Named(m) => Some(m.span()), + Member::Unnamed(m) => Some(m.span), + } + } +} + +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(), + } + } +} + +impl Eq for Index {} + +impl PartialEq for Index { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} + +impl Hash for Index { + fn hash<H: Hasher>(&self, state: &mut H) { + self.index.hash(state); + } +} + +#[cfg(feature = "printing")] +impl IdentFragment for Index { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.index, formatter) + } + + fn span(&self) -> Option<Span> { + Some(self.span) + } +} + +#[cfg(feature = "full")] +ast_struct! { + #[derive(Default)] + pub struct Reserved { + _private: (), + } +} + +#[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! { + /// One arm of a `match` expression: `0...10 => { return true; }`. + /// + /// As in: + /// + /// ``` + /// # 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 pat: Pat, + 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(any(feature = "parsing", feature = "printing"))] +#[cfg(feature = "full")] +pub(crate) fn requires_terminator(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::Match(..) + | Expr::While(..) + | Expr::Loop(..) + | Expr::ForLoop(..) + | Expr::Async(..) + | Expr::TryBlock(..) => false, + _ => true, + } +} + +#[cfg(feature = "parsing")] +pub(crate) mod parsing { + use super::*; + + use crate::parse::discouraged::Speculative; + use crate::parse::{Parse, ParseStream, Result}; + use crate::path; + + // 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 + #[derive(Copy, Clone)] + pub struct AllowStruct(bool); + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + enum Precedence { + Any, + Assign, + Range, + Or, + And, + Compare, + BitOr, + BitXor, + BitAnd, + Shift, + Arithmetic, + Term, + Cast, + } + + impl Precedence { + fn of(op: &BinOp) -> Self { + match *op { + BinOp::Add(_) | BinOp::Sub(_) => Precedence::Arithmetic, + BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Term, + BinOp::And(_) => Precedence::And, + BinOp::Or(_) => Precedence::Or, + BinOp::BitXor(_) => Precedence::BitXor, + BinOp::BitAnd(_) => Precedence::BitAnd, + BinOp::BitOr(_) => Precedence::BitOr, + BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift, + BinOp::Eq(_) + | BinOp::Lt(_) + | BinOp::Le(_) + | BinOp::Ne(_) + | BinOp::Ge(_) + | BinOp::Gt(_) => Precedence::Compare, + BinOp::AddEq(_) + | BinOp::SubEq(_) + | BinOp::MulEq(_) + | BinOp::DivEq(_) + | BinOp::RemEq(_) + | BinOp::BitXorEq(_) + | BinOp::BitAndEq(_) + | BinOp::BitOrEq(_) + | BinOp::ShlEq(_) + | BinOp::ShrEq(_) => Precedence::Assign, + } + } + } + + impl Parse for Expr { + fn parse(input: ParseStream) -> Result<Self> { + ambiguous_expr(input, AllowStruct(true)) + } + } + + #[cfg(feature = "full")] + fn expr_no_struct(input: ParseStream) -> Result<Expr> { + ambiguous_expr(input, AllowStruct(false)) + } + + #[cfg(feature = "full")] + fn parse_expr( + input: ParseStream, + mut lhs: Expr, + allow_struct: AllowStruct, + base: Precedence, + ) -> Result<Expr> { + loop { + if input + .fork() + .parse::<BinOp>() + .ok() + .map_or(false, |op| Precedence::of(&op) >= base) + { + let op: BinOp = input.parse()?; + let precedence = Precedence::of(&op); + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > precedence || next == precedence && precedence == Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = if precedence == Precedence::Assign { + Expr::AssignOp(ExprAssignOp { + attrs: Vec::new(), + left: Box::new(lhs), + op, + right: Box::new(rhs), + }) + } else { + Expr::Binary(ExprBinary { + attrs: Vec::new(), + left: Box::new(lhs), + op, + right: Box::new(rhs), + }) + }; + } else if Precedence::Assign >= base + && input.peek(Token![=]) + && !input.peek(Token![==]) + && !input.peek(Token![=>]) + { + let eq_token: Token![=] = input.parse()?; + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next >= Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = Expr::Assign(ExprAssign { + attrs: Vec::new(), + left: Box::new(lhs), + eq_token, + right: Box::new(rhs), + }); + } else if Precedence::Range >= base && input.peek(Token![..]) { + let limits: RangeLimits = input.parse()?; + let rhs = if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > Precedence::Range { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + Some(rhs) + }; + lhs = Expr::Range(ExprRange { + attrs: Vec::new(), + from: Some(Box::new(lhs)), + limits, + to: rhs.map(Box::new), + }); + } else if Precedence::Cast >= base && input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Cast(ExprCast { + attrs: Vec::new(), + expr: Box::new(lhs), + as_token, + ty: Box::new(ty), + }); + } else if Precedence::Cast >= base && input.peek(Token![:]) && !input.peek(Token![::]) { + let colon_token: Token![:] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Type(ExprType { + attrs: Vec::new(), + expr: Box::new(lhs), + colon_token, + ty: Box::new(ty), + }); + } else { + break; + } + } + Ok(lhs) + } + + #[cfg(not(feature = "full"))] + fn parse_expr( + input: ParseStream, + mut lhs: Expr, + allow_struct: AllowStruct, + base: Precedence, + ) -> Result<Expr> { + loop { + if input + .fork() + .parse::<BinOp>() + .ok() + .map_or(false, |op| Precedence::of(&op) >= base) + { + let op: BinOp = input.parse()?; + let precedence = Precedence::of(&op); + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > precedence || next == precedence && precedence == Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = Expr::Binary(ExprBinary { + attrs: Vec::new(), + left: Box::new(lhs), + op, + right: Box::new(rhs), + }); + } else if Precedence::Cast >= base && input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Cast(ExprCast { + attrs: Vec::new(), + expr: Box::new(lhs), + as_token, + ty: Box::new(ty), + }); + } else { + break; + } + } + Ok(lhs) + } + + fn peek_precedence(input: ParseStream) -> Precedence { + if let Ok(op) = input.fork().parse() { + Precedence::of(&op) + } else if input.peek(Token![=]) && !input.peek(Token![=>]) { + Precedence::Assign + } else if input.peek(Token![..]) { + Precedence::Range + } else if input.peek(Token![as]) || input.peek(Token![:]) && !input.peek(Token![::]) { + Precedence::Cast + } else { + Precedence::Any + } + } + + // Parse an arbitrary expression. + fn ambiguous_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let lhs = unary_expr(input, allow_struct)?; + parse_expr(input, lhs, allow_struct, Precedence::Any) + } + + // <UnOp> <trailer> + // & <trailer> + // &mut <trailer> + // box <trailer> + #[cfg(feature = "full")] + fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let ahead = input.fork(); + let attrs = ahead.call(Attribute::parse_outer)?; + if ahead.peek(Token![&]) + || ahead.peek(Token![box]) + || ahead.peek(Token![*]) + || ahead.peek(Token![!]) + || ahead.peek(Token![-]) + { + input.advance_to(&ahead); + if input.peek(Token![&]) { + Ok(Expr::Reference(ExprReference { + attrs, + and_token: input.parse()?, + raw: Reserved::default(), + mutability: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else if input.peek(Token![box]) { + Ok(Expr::Box(ExprBox { + attrs, + box_token: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else { + Ok(Expr::Unary(ExprUnary { + attrs, + op: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } + } else { + trailer_expr(input, allow_struct) + } + } + + #[cfg(not(feature = "full"))] + fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let ahead = input.fork(); + let attrs = ahead.call(Attribute::parse_outer)?; + if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) { + input.advance_to(&ahead); + Ok(Expr::Unary(ExprUnary { + attrs, + op: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else { + trailer_expr(input, allow_struct) + } + } + + // <atom> (..<args>) ... + // <atom> . <ident> (..<args>) ... + // <atom> . <ident> ... + // <atom> . <lit> ... + // <atom> [ <expr> ] ... + // <atom> ? ... + #[cfg(feature = "full")] + fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(token::Group) { + return input.call(expr_group).map(Expr::Group); + } + + let outer_attrs = input.call(Attribute::parse_outer)?; + + let atom = atom_expr(input, allow_struct)?; + let mut e = trailer_helper(input, atom)?; + + let inner_attrs = e.replace_attrs(Vec::new()); + let attrs = private::attrs(outer_attrs, inner_attrs); + e.replace_attrs(attrs); + Ok(e) + } + + #[cfg(feature = "full")] + fn trailer_helper(input: ParseStream, mut e: Expr) -> Result<Expr> { + loop { + if input.peek(token::Paren) { + let content; + e = Expr::Call(ExprCall { + attrs: Vec::new(), + func: Box::new(e), + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + } else if input.peek(Token![.]) && !input.peek(Token![..]) { + let dot_token: Token![.] = input.parse()?; + + if input.peek(token::Await) { + e = Expr::Await(ExprAwait { + attrs: Vec::new(), + base: Box::new(e), + dot_token, + await_token: input.parse()?, + }); + continue; + } + + let member: Member = input.parse()?; + let turbofish = if member.is_named() && input.peek(Token![::]) { + Some(MethodTurbofish { + colon2_token: input.parse()?, + lt_token: input.parse()?, + args: { + let mut args = Punctuated::new(); + loop { + if input.peek(Token![>]) { + break; + } + let value = input.call(generic_method_argument)?; + args.push_value(value); + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + args.push_punct(punct); + } + args + }, + gt_token: input.parse()?, + }) + } else { + None + }; + + if turbofish.is_some() || input.peek(token::Paren) { + if let Member::Named(method) = member { + let content; + e = Expr::MethodCall(ExprMethodCall { + attrs: Vec::new(), + receiver: Box::new(e), + dot_token, + method, + turbofish, + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + continue; + } + } + + e = Expr::Field(ExprField { + attrs: Vec::new(), + base: Box::new(e), + dot_token, + member, + }); + } else if input.peek(token::Bracket) { + let content; + e = Expr::Index(ExprIndex { + attrs: Vec::new(), + expr: Box::new(e), + bracket_token: bracketed!(content in input), + index: content.parse()?, + }); + } else if input.peek(Token![?]) { + e = Expr::Try(ExprTry { + attrs: Vec::new(), + expr: Box::new(e), + question_token: input.parse()?, + }); + } else { + break; + } + } + Ok(e) + } + + #[cfg(not(feature = "full"))] + fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let mut e = atom_expr(input, allow_struct)?; + + loop { + if input.peek(token::Paren) { + let content; + e = Expr::Call(ExprCall { + attrs: Vec::new(), + func: Box::new(e), + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + } else if input.peek(Token![.]) && !input.peek(Token![..]) && !input.peek2(token::Await) + { + e = Expr::Field(ExprField { + attrs: Vec::new(), + base: Box::new(e), + dot_token: input.parse()?, + member: input.parse()?, + }); + } else if input.peek(token::Bracket) { + let content; + e = Expr::Index(ExprIndex { + attrs: Vec::new(), + expr: Box::new(e), + bracket_token: bracketed!(content in input), + index: content.parse()?, + }); + } else { + break; + } + } + + Ok(e) + } + + // Parse all atomic expressions which don't have to worry about precedence + // interactions, as they are fully contained. + #[cfg(feature = "full")] + fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(token::Group) { + input.call(expr_group).map(Expr::Group) + } else if input.peek(Lit) { + input.parse().map(Expr::Lit) + } else if input.peek(Token![async]) + && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace)) + { + input.call(expr_async).map(Expr::Async) + } else if input.peek(Token![try]) && input.peek2(token::Brace) { + input.call(expr_try_block).map(Expr::TryBlock) + } else if input.peek(Token![|]) + || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move])) + || input.peek(Token![static]) + || input.peek(Token![move]) + { + expr_closure(input, allow_struct).map(Expr::Closure) + } else if input.peek(Ident) + || input.peek(Token![::]) + || input.peek(Token![<]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + path_or_macro_or_struct(input, allow_struct) + } else if input.peek(token::Paren) { + paren_or_tuple(input) + } else if input.peek(Token![break]) { + expr_break(input, allow_struct).map(Expr::Break) + } else if input.peek(Token![continue]) { + input.call(expr_continue).map(Expr::Continue) + } else if input.peek(Token![return]) { + expr_ret(input, allow_struct).map(Expr::Return) + } else if input.peek(token::Bracket) { + array_or_repeat(input) + } else if input.peek(Token![let]) { + input.call(expr_let).map(Expr::Let) + } else if input.peek(Token![if]) { + input.parse().map(Expr::If) + } else if input.peek(Token![while]) { + input.parse().map(Expr::While) + } else if input.peek(Token![for]) { + input.parse().map(Expr::ForLoop) + } else if input.peek(Token![loop]) { + input.parse().map(Expr::Loop) + } else if input.peek(Token![match]) { + input.parse().map(Expr::Match) + } else if input.peek(Token![yield]) { + input.call(expr_yield).map(Expr::Yield) + } else if input.peek(Token![unsafe]) { + input.call(expr_unsafe).map(Expr::Unsafe) + } else if input.peek(token::Brace) { + input.call(expr_block).map(Expr::Block) + } else if input.peek(Token![..]) { + expr_range(input, allow_struct).map(Expr::Range) + } else if input.peek(Lifetime) { + let the_label: Label = input.parse()?; + let mut expr = if input.peek(Token![while]) { + Expr::While(input.parse()?) + } else if input.peek(Token![for]) { + Expr::ForLoop(input.parse()?) + } else if input.peek(Token![loop]) { + Expr::Loop(input.parse()?) + } else if input.peek(token::Brace) { + Expr::Block(input.call(expr_block)?) + } else { + return Err(input.error("expected loop or block expression")); + }; + match &mut expr { + Expr::While(ExprWhile { label, .. }) + | Expr::ForLoop(ExprForLoop { label, .. }) + | Expr::Loop(ExprLoop { label, .. }) + | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label), + _ => unreachable!(), + } + Ok(expr) + } else { + Err(input.error("expected expression")) + } + } + + #[cfg(not(feature = "full"))] + fn atom_expr(input: ParseStream, _allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(Lit) { + input.parse().map(Expr::Lit) + } else if input.peek(token::Paren) { + input.call(expr_paren).map(Expr::Paren) + } else if input.peek(Ident) + || input.peek(Token![::]) + || input.peek(Token![<]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + input.parse().map(Expr::Path) + } else { + Err(input.error("unsupported expression; enable syn's features=[\"full\"]")) + } + } + + #[cfg(feature = "full")] + fn path_or_macro_or_struct(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let expr: ExprPath = input.parse()?; + if expr.qself.is_some() { + return Ok(Expr::Path(expr)); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &expr.path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tokens) = mac::parse_delimiter(input)?; + return Ok(Expr::Macro(ExprMacro { + attrs: Vec::new(), + mac: Macro { + path: expr.path, + bang_token, + delimiter, + tokens, + }, + })); + } + } + + if allow_struct.0 && input.peek(token::Brace) { + let outer_attrs = Vec::new(); + expr_struct_helper(input, outer_attrs, expr.path).map(Expr::Struct) + } else { + Ok(Expr::Path(expr)) + } + } + + #[cfg(feature = "full")] + fn paren_or_tuple(input: ParseStream) -> Result<Expr> { + let content; + let paren_token = parenthesized!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + if content.is_empty() { + return Ok(Expr::Tuple(ExprTuple { + attrs: inner_attrs, + paren_token, + elems: Punctuated::new(), + })); + } + + let first: Expr = content.parse()?; + if content.is_empty() { + return Ok(Expr::Paren(ExprParen { + attrs: inner_attrs, + paren_token, + expr: Box::new(first), + })); + } + + let mut elems = Punctuated::new(); + elems.push_value(first); + while !content.is_empty() { + let punct = content.parse()?; + elems.push_punct(punct); + if content.is_empty() { + break; + } + let value = content.parse()?; + elems.push_value(value); + } + Ok(Expr::Tuple(ExprTuple { + attrs: inner_attrs, + paren_token, + elems, + })) + } + + #[cfg(feature = "full")] + fn array_or_repeat(input: ParseStream) -> Result<Expr> { + let content; + let bracket_token = bracketed!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + if content.is_empty() { + return Ok(Expr::Array(ExprArray { + attrs: inner_attrs, + bracket_token, + elems: Punctuated::new(), + })); + } + + let first: Expr = content.parse()?; + if content.is_empty() || content.peek(Token![,]) { + let mut elems = Punctuated::new(); + elems.push_value(first); + while !content.is_empty() { + let punct = content.parse()?; + elems.push_punct(punct); + if content.is_empty() { + break; + } + let value = content.parse()?; + elems.push_value(value); + } + Ok(Expr::Array(ExprArray { + attrs: inner_attrs, + bracket_token, + elems, + })) + } else if content.peek(Token![;]) { + let semi_token: Token![;] = content.parse()?; + let len: Expr = content.parse()?; + Ok(Expr::Repeat(ExprRepeat { + attrs: inner_attrs, + bracket_token, + expr: Box::new(first), + semi_token, + len: Box::new(len), + })) + } else { + Err(content.error("expected `,` or `;`")) + } + } + + #[cfg(feature = "full")] + pub(crate) fn expr_early(input: ParseStream) -> Result<Expr> { + let mut attrs = input.call(Attribute::parse_outer)?; + let mut expr = if input.peek(Token![if]) { + Expr::If(input.parse()?) + } else if input.peek(Token![while]) { + Expr::While(input.parse()?) + } else if input.peek(Token![for]) { + Expr::ForLoop(input.parse()?) + } else if input.peek(Token![loop]) { + Expr::Loop(input.parse()?) + } else if input.peek(Token![match]) { + Expr::Match(input.parse()?) + } else if input.peek(Token![try]) && input.peek2(token::Brace) { + Expr::TryBlock(input.call(expr_try_block)?) + } else if input.peek(Token![unsafe]) { + Expr::Unsafe(input.call(expr_unsafe)?) + } else if input.peek(token::Brace) { + Expr::Block(input.call(expr_block)?) + } else { + let allow_struct = AllowStruct(true); + let mut expr = unary_expr(input, allow_struct)?; + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + + return parse_expr(input, expr, allow_struct, Precedence::Any); + }; + + if input.peek(Token![.]) || input.peek(Token![?]) { + expr = trailer_helper(input, expr)?; + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + + let allow_struct = AllowStruct(true); + return parse_expr(input, expr, allow_struct, Precedence::Any); + } + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + Ok(expr) + } + + impl Parse for ExprLit { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ExprLit { + attrs: Vec::new(), + lit: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + fn expr_group(input: ParseStream) -> Result<ExprGroup> { + let group = crate::group::parse_group(input)?; + Ok(ExprGroup { + attrs: Vec::new(), + group_token: group.token, + expr: group.content.parse()?, + }) + } + + #[cfg(not(feature = "full"))] + fn expr_paren(input: ParseStream) -> Result<ExprParen> { + let content; + Ok(ExprParen { + attrs: Vec::new(), + paren_token: parenthesized!(content in input), + expr: content.parse()?, + }) + } + + #[cfg(feature = "full")] + fn generic_method_argument(input: ParseStream) -> Result<GenericMethodArgument> { + // TODO parse const generics as well + input.parse().map(GenericMethodArgument::Type) + } + + #[cfg(feature = "full")] + fn expr_let(input: ParseStream) -> Result<ExprLet> { + Ok(ExprLet { + attrs: Vec::new(), + let_token: input.parse()?, + pat: { + let leading_vert: Option<Token![|]> = input.parse()?; + let pat: Pat = input.parse()?; + if leading_vert.is_some() + || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) + { + let mut cases = Punctuated::new(); + cases.push_value(pat); + while input.peek(Token![|]) + && !input.peek(Token![||]) + && !input.peek(Token![|=]) + { + let punct = input.parse()?; + cases.push_punct(punct); + let pat: Pat = input.parse()?; + cases.push_value(pat); + } + Pat::Or(PatOr { + attrs: Vec::new(), + leading_vert, + cases, + }) + } else { + pat + } + }, + eq_token: input.parse()?, + expr: Box::new(input.call(expr_no_struct)?), + }) + } + + #[cfg(feature = "full")] + impl Parse for ExprIf { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ExprIf { + attrs: Vec::new(), + if_token: input.parse()?, + cond: Box::new(input.call(expr_no_struct)?), + then_branch: input.parse()?, + else_branch: { + if input.peek(Token![else]) { + Some(input.call(else_block)?) + } else { + None + } + }, + }) + } + } + + #[cfg(feature = "full")] + fn else_block(input: ParseStream) -> Result<(Token![else], Box<Expr>)> { + let else_token: Token![else] = input.parse()?; + + let lookahead = input.lookahead1(); + let else_branch = if input.peek(Token![if]) { + input.parse().map(Expr::If)? + } else if input.peek(token::Brace) { + Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: input.parse()?, + }) + } else { + return Err(lookahead.error()); + }; + + Ok((else_token, Box::new(else_branch))) + } + + #[cfg(feature = "full")] + impl Parse for ExprForLoop { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let for_token: Token![for] = input.parse()?; + + let leading_vert: Option<Token![|]> = input.parse()?; + let mut pat: Pat = input.parse()?; + if leading_vert.is_some() || input.peek(Token![|]) { + let mut cases = Punctuated::new(); + cases.push_value(pat); + while input.peek(Token![|]) { + let punct = input.parse()?; + cases.push_punct(punct); + let pat: Pat = input.parse()?; + cases.push_value(pat); + } + pat = Pat::Or(PatOr { + attrs: Vec::new(), + leading_vert, + cases, + }); + } + + let in_token: Token![in] = input.parse()?; + let expr: Expr = input.call(expr_no_struct)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprForLoop { + attrs: inner_attrs, + label, + for_token, + pat, + in_token, + expr: Box::new(expr), + body: Block { brace_token, stmts }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprLoop { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let loop_token: Token![loop] = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprLoop { + attrs: inner_attrs, + label, + loop_token, + body: Block { brace_token, stmts }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprMatch { + fn parse(input: ParseStream) -> Result<Self> { + let match_token: Token![match] = input.parse()?; + let expr = expr_no_struct(input)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut arms = Vec::new(); + while !content.is_empty() { + arms.push(content.call(Arm::parse)?); + } + + Ok(ExprMatch { + attrs: inner_attrs, + match_token, + expr: Box::new(expr), + brace_token, + arms, + }) + } + } + + macro_rules! impl_by_parsing_expr { + ( + $( + $expr_type:ty, $variant:ident, $msg:expr, + )* + ) => { + $( + #[cfg(all(feature = "full", feature = "printing"))] + impl Parse for $expr_type { + fn parse(input: ParseStream) -> Result<Self> { + let mut expr: Expr = input.parse()?; + loop { + match expr { + Expr::$variant(inner) => return Ok(inner), + Expr::Group(next) => expr = *next.expr, + _ => return Err(Error::new_spanned(expr, $msg)), + } + } + } + } + )* + }; + } + + impl_by_parsing_expr! { + ExprBox, Box, "expected box expression", + ExprArray, Array, "expected slice literal expression", + ExprCall, Call, "expected function call expression", + ExprMethodCall, MethodCall, "expected method call expression", + ExprTuple, Tuple, "expected tuple expression", + ExprBinary, Binary, "expected binary operation", + ExprUnary, Unary, "expected unary operation", + ExprCast, Cast, "expected cast expression", + ExprType, Type, "expected type ascription expression", + ExprLet, Let, "expected let guard", + ExprClosure, Closure, "expected closure expression", + ExprUnsafe, Unsafe, "expected unsafe block", + ExprBlock, Block, "expected blocked scope", + ExprAssign, Assign, "expected assignment expression", + ExprAssignOp, AssignOp, "expected compound assignment expression", + ExprField, Field, "expected struct field access", + ExprIndex, Index, "expected indexing expression", + ExprRange, Range, "expected range expression", + ExprReference, Reference, "expected referencing operation", + ExprBreak, Break, "expected break expression", + ExprContinue, Continue, "expected continue expression", + ExprReturn, Return, "expected return expression", + ExprMacro, Macro, "expected macro invocation expression", + ExprStruct, Struct, "expected struct literal expression", + ExprRepeat, Repeat, "expected array literal constructed from one repeated element", + ExprParen, Paren, "expected parenthesized expression", + ExprTry, Try, "expected try expression", + ExprAsync, Async, "expected async block", + ExprTryBlock, TryBlock, "expected try block", + ExprYield, Yield, "expected yield expression", + } + + #[cfg(feature = "full")] + fn expr_try_block(input: ParseStream) -> Result<ExprTryBlock> { + Ok(ExprTryBlock { + attrs: Vec::new(), + try_token: input.parse()?, + block: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn expr_yield(input: ParseStream) -> Result<ExprYield> { + Ok(ExprYield { + attrs: Vec::new(), + yield_token: input.parse()?, + expr: { + if !input.is_empty() && !input.peek(Token![,]) && !input.peek(Token![;]) { + Some(input.parse()?) + } else { + None + } + }, + }) + } + + #[cfg(feature = "full")] + fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprClosure> { + let asyncness: Option<Token![async]> = input.parse()?; + let movability: Option<Token![static]> = if asyncness.is_none() { + input.parse()? + } else { + None + }; + let capture: Option<Token![move]> = input.parse()?; + let or1_token: Token![|] = input.parse()?; + + let mut inputs = Punctuated::new(); + loop { + if input.peek(Token![|]) { + break; + } + let value = closure_arg(input)?; + inputs.push_value(value); + if input.peek(Token![|]) { + break; + } + let punct: Token![,] = input.parse()?; + inputs.push_punct(punct); + } + + let or2_token: Token![|] = input.parse()?; + + let (output, body) = if input.peek(Token![->]) { + let arrow_token: Token![->] = input.parse()?; + let ty: Type = input.parse()?; + let body: Block = input.parse()?; + let output = ReturnType::Type(arrow_token, Box::new(ty)); + let block = Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: body, + }); + (output, block) + } else { + let body = ambiguous_expr(input, allow_struct)?; + (ReturnType::Default, body) + }; + + Ok(ExprClosure { + attrs: Vec::new(), + asyncness, + movability, + capture, + or1_token, + inputs, + or2_token, + output, + body: Box::new(body), + }) + } + + #[cfg(feature = "full")] + fn expr_async(input: ParseStream) -> Result<ExprAsync> { + Ok(ExprAsync { + attrs: Vec::new(), + async_token: input.parse()?, + capture: input.parse()?, + block: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn closure_arg(input: ParseStream) -> Result<Pat> { + let attrs = input.call(Attribute::parse_outer)?; + let mut pat: Pat = input.parse()?; + + if input.peek(Token![:]) { + Ok(Pat::Type(PatType { + attrs, + pat: Box::new(pat), + colon_token: input.parse()?, + ty: input.parse()?, + })) + } else { + match &mut pat { + Pat::Box(pat) => pat.attrs = attrs, + Pat::Ident(pat) => pat.attrs = attrs, + Pat::Lit(pat) => pat.attrs = attrs, + Pat::Macro(pat) => pat.attrs = attrs, + Pat::Or(pat) => pat.attrs = attrs, + Pat::Path(pat) => pat.attrs = attrs, + Pat::Range(pat) => pat.attrs = attrs, + Pat::Reference(pat) => pat.attrs = attrs, + Pat::Rest(pat) => pat.attrs = attrs, + Pat::Slice(pat) => pat.attrs = attrs, + Pat::Struct(pat) => pat.attrs = attrs, + Pat::Tuple(pat) => pat.attrs = attrs, + Pat::TupleStruct(pat) => pat.attrs = attrs, + Pat::Type(_) => unreachable!(), + Pat::Verbatim(_) => {} + Pat::Wild(pat) => pat.attrs = attrs, + Pat::__Nonexhaustive => unreachable!(), + } + Ok(pat) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprWhile { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let while_token: Token![while] = input.parse()?; + let cond = expr_no_struct(input)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprWhile { + attrs: inner_attrs, + label, + while_token, + cond: Box::new(cond), + body: Block { brace_token, stmts }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Label { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Label { + name: input.parse()?, + colon_token: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Option<Label> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + #[cfg(feature = "full")] + fn expr_continue(input: ParseStream) -> Result<ExprContinue> { + Ok(ExprContinue { + attrs: Vec::new(), + continue_token: input.parse()?, + label: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> { + Ok(ExprBreak { + attrs: Vec::new(), + break_token: input.parse()?, + label: input.parse()?, + expr: { + if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let expr = ambiguous_expr(input, allow_struct)?; + Some(Box::new(expr)) + } + }, + }) + } + + #[cfg(feature = "full")] + fn expr_ret(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprReturn> { + Ok(ExprReturn { + attrs: Vec::new(), + return_token: input.parse()?, + expr: { + if input.is_empty() || input.peek(Token![,]) || input.peek(Token![;]) { + None + } else { + // 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" + let expr = ambiguous_expr(input, allow_struct)?; + Some(Box::new(expr)) + } + }, + }) + } + + #[cfg(feature = "full")] + impl Parse for FieldValue { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let member: Member = input.parse()?; + let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() { + let colon_token: Token![:] = input.parse()?; + let value: Expr = input.parse()?; + (Some(colon_token), value) + } else if let Member::Named(ident) = &member { + let value = Expr::Path(ExprPath { + attrs: Vec::new(), + qself: None, + path: Path::from(ident.clone()), + }); + (None, value) + } else { + unreachable!() + }; + + Ok(FieldValue { + attrs, + member, + colon_token, + expr: value, + }) + } + } + + #[cfg(feature = "full")] + fn expr_struct_helper( + input: ParseStream, + outer_attrs: Vec<Attribute>, + path: Path, + ) -> Result<ExprStruct> { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let attrs = private::attrs(outer_attrs, inner_attrs); + + let mut fields = Punctuated::new(); + while !content.is_empty() { + if content.peek(Token![..]) { + return Ok(ExprStruct { + attrs, + brace_token, + path, + fields, + dot2_token: Some(content.parse()?), + rest: Some(Box::new(content.parse()?)), + }); + } + + fields.push(content.parse()?); + if !content.peek(Token![,]) { + break; + } + let punct: Token![,] = content.parse()?; + fields.push_punct(punct); + } + + Ok(ExprStruct { + attrs, + brace_token, + path, + fields, + dot2_token: None, + rest: None, + }) + } + + #[cfg(feature = "full")] + fn expr_unsafe(input: ParseStream) -> Result<ExprUnsafe> { + let unsafe_token: Token![unsafe] = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprUnsafe { + attrs: inner_attrs, + unsafe_token, + block: Block { brace_token, stmts }, + }) + } + + #[cfg(feature = "full")] + pub fn expr_block(input: ParseStream) -> Result<ExprBlock> { + let label: Option<Label> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprBlock { + attrs: inner_attrs, + label, + block: Block { brace_token, stmts }, + }) + } + + #[cfg(feature = "full")] + fn expr_range(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprRange> { + Ok(ExprRange { + attrs: Vec::new(), + from: None, + limits: input.parse()?, + to: { + if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let to = ambiguous_expr(input, allow_struct)?; + Some(Box::new(to)) + } + }, + }) + } + + #[cfg(feature = "full")] + impl Parse for RangeLimits { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![..=]) { + input.parse().map(RangeLimits::Closed) + } else if lookahead.peek(Token![...]) { + let dot3: Token![...] = input.parse()?; + Ok(RangeLimits::Closed(Token![..=](dot3.spans))) + } else if lookahead.peek(Token![..]) { + input.parse().map(RangeLimits::HalfOpen) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ExprPath { + fn parse(input: ParseStream) -> Result<Self> { + #[cfg(not(feature = "full"))] + let attrs = Vec::new(); + #[cfg(feature = "full")] + let attrs = input.call(Attribute::parse_outer)?; + + let (qself, path) = path::parsing::qpath(input, true)?; + + Ok(ExprPath { attrs, qself, path }) + } + } + + impl Parse for Member { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Ident) { + input.parse().map(Member::Named) + } else if input.peek(LitInt) { + input.parse().map(Member::Unnamed) + } else { + Err(input.error("expected identifier or integer")) + } + } + } + + #[cfg(feature = "full")] + impl Parse for Arm { + fn parse(input: ParseStream) -> Result<Arm> { + let requires_comma; + Ok(Arm { + attrs: input.call(Attribute::parse_outer)?, + pat: { + let leading_vert: Option<Token![|]> = input.parse()?; + let pat: Pat = input.parse()?; + if leading_vert.is_some() || input.peek(Token![|]) { + let mut cases = Punctuated::new(); + cases.push_value(pat); + while input.peek(Token![|]) { + let punct = input.parse()?; + cases.push_punct(punct); + let pat: Pat = input.parse()?; + cases.push_value(pat); + } + Pat::Or(PatOr { + attrs: Vec::new(), + leading_vert, + cases, + }) + } else { + pat + } + }, + guard: { + if input.peek(Token![if]) { + let if_token: Token![if] = input.parse()?; + let guard: Expr = input.parse()?; + Some((if_token, Box::new(guard))) + } else { + None + } + }, + fat_arrow_token: input.parse()?, + body: { + let body = input.call(expr_early)?; + requires_comma = requires_terminator(&body); + Box::new(body) + }, + comma: { + if requires_comma && !input.is_empty() { + Some(input.parse()?) + } else { + input.parse()? + } + }, + }) + } + } + + impl Parse for Index { + fn parse(input: ParseStream) -> Result<Self> { + let lit: LitInt = input.parse()?; + if lit.suffix().is_empty() { + Ok(Index { + index: lit + .base10_digits() + .parse() + .map_err(|err| Error::new(lit.span(), err))?, + span: lit.span(), + }) + } else { + Err(Error::new(lit.span(), "expected unsuffixed integer")) + } + } + } + + #[cfg(feature = "full")] + impl Member { + fn is_named(&self) -> bool { + match *self { + Member::Named(_) => true, + Member::Unnamed(_) => false, + } + } + } +} + +#[cfg(feature = "printing")] +pub(crate) mod printing { + use super::*; + + use proc_macro2::{Literal, TokenStream}; + use quote::{ToTokens, TokenStreamExt}; + + #[cfg(feature = "full")] + use crate::attr::FilterAttrs; + #[cfg(feature = "full")] + use crate::print::TokensOrDefault; + + // 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")] + pub(crate) 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"))] + pub(crate) 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 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(t) => t.to_tokens(tokens), + GenericMethodArgument::Const(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((else_token, 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::Block(_) => { + else_.to_tokens(tokens); + } + _ => { + token::Brace::default().surround(tokens, |tokens| { + else_.to_tokens(tokens); + }); + } + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprLet { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.let_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.expr); + } + } + + #[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 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 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 && requires_terminator(&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 ExprAwait { + 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.await_token.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); + self.inputs.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.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.block.stmts); + }); + } + } + + #[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(ident) => ident.to_tokens(tokens), + Member::Unnamed(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(t) => t.to_tokens(tokens), + RangeLimits::Closed(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); + private::print_path(tokens, &self.qself, &self.path); + } + } + + #[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); + } + } + + #[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(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.pat.to_tokens(tokens); + if let Some((if_token, 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); + } + } +} diff --git a/syn/src/ext.rs b/syn/src/ext.rs new file mode 100644 index 0000000..d09577a --- /dev/null +++ b/syn/src/ext.rs @@ -0,0 +1,135 @@ +//! Extension traits to provide parsing methods on foreign types. +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +use proc_macro2::Ident; + +use crate::parse::{ParseStream, Result}; + +use crate::buffer::Cursor; +use crate::parse::Peek; +use crate::sealed::lookahead; +use crate::token::CustomToken; + +/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. It +/// is implemented only for `proc_macro2::Ident`. +/// +/// *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 macro input which allows Rust keywords as + /// identifiers. + /// + /// # Example + /// + /// ``` + /// use syn::{Error, Ident, Result, Token}; + /// use syn::ext::IdentExt; + /// use syn::parse::ParseStream; + /// + /// mod kw { + /// syn::custom_keyword!(name); + /// } + /// + /// // Parses input that looks like `name = NAME` where `NAME` can be + /// // any identifier. + /// // + /// // Examples: + /// // + /// // name = anything + /// // name = impl + /// fn parse_dsl(input: ParseStream) -> Result<Ident> { + /// input.parse::<kw::name>()?; + /// input.parse::<Token![=]>()?; + /// let name = input.call(Ident::parse_any)?; + /// Ok(name) + /// } + /// ``` + fn parse_any(input: ParseStream) -> Result<Self>; + + /// Peeks any identifier including keywords. Usage: + /// `input.peek(Ident::peek_any)` + /// + /// This is different from `input.peek(Ident)` which only returns true in + /// the case of an ident which is not a Rust keyword. + #[allow(non_upper_case_globals)] + const peek_any: private::PeekFn = private::PeekFn; + + /// Strips the raw marker `r#`, if any, from the beginning of an ident. + /// + /// - unraw(`x`) = `x` + /// - unraw(`move`) = `move` + /// - unraw(`r#move`) = `move` + /// + /// # Example + /// + /// In the case of interop with other languages like Python that have a + /// different set of keywords than Rust, we might come across macro input + /// that involves raw identifiers to refer to ordinary variables in the + /// other language with a name that happens to be a Rust keyword. + /// + /// The function below appends an identifier from the caller's input onto a + /// fixed prefix. Without using `unraw()`, this would tend to produce + /// invalid identifiers like `__pyo3_get_r#move`. + /// + /// ``` + /// use proc_macro2::Span; + /// use syn::Ident; + /// use syn::ext::IdentExt; + /// + /// fn ident_for_getter(variable: &Ident) -> Ident { + /// let getter = format!("__pyo3_get_{}", variable.unraw()); + /// Ident::new(&getter, Span::call_site()) + /// } + /// ``` + fn unraw(&self) -> Ident; +} + +impl IdentExt for Ident { + fn parse_any(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.ident() { + Some((ident, rest)) => Ok((ident, rest)), + None => Err(cursor.error("expected ident")), + }) + } + + fn unraw(&self) -> Ident { + let string = self.to_string(); + if string.starts_with("r#") { + Ident::new(&string[2..], self.span()) + } else { + self.clone() + } + } +} + +impl Peek for private::PeekFn { + type Token = private::IdentAny; +} + +impl CustomToken for private::IdentAny { + fn peek(cursor: Cursor) -> bool { + cursor.ident().is_some() + } + + fn display() -> &'static str { + "identifier" + } +} + +impl lookahead::Sealed for private::PeekFn {} + +mod private { + use proc_macro2::Ident; + + pub trait Sealed {} + + impl Sealed for Ident {} + + #[derive(Copy, Clone)] + pub struct PeekFn; + pub struct IdentAny; +} diff --git a/syn/src/file.rs b/syn/src/file.rs new file mode 100644 index 0000000..88c02fe --- /dev/null +++ b/syn/src/file.rs @@ -0,0 +1,113 @@ +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. + /// + /// ``` + /// 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 crate::parse::{Parse, ParseStream, Result}; + + impl Parse for File { + fn parse(input: ParseStream) -> Result<Self> { + Ok(File { + shebang: None, + attrs: input.call(Attribute::parse_inner)?, + items: { + let mut items = Vec::new(); + while !input.is_empty() { + items.push(input.parse()?); + } + items + }, + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use crate::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/syn/src/gen/fold.rs b/syn/src/gen/fold.rs new file mode 100644 index 0000000..f51218b --- /dev/null +++ b/syn/src/gen/fold.rs @@ -0,0 +1,3236 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#![allow(unreachable_code, unused_variables)] +#[cfg(any(feature = "full", feature = "derive"))] +use crate::gen::helper::fold::*; +#[cfg(any(feature = "full", feature = "derive"))] +use crate::token::{Brace, Bracket, Group, Paren}; +use crate::*; +use proc_macro2::Span; +#[cfg(feature = "full")] +macro_rules! full { + ($e:expr) => { + $e + }; +} +#[cfg(all(feature = "derive", not(feature = "full")))] +macro_rules! full { + ($e:expr) => { + unreachable!() + }; +} +/// Syntax tree traversal to transform the nodes of an owned syntax tree. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: self +/// +/// *This trait is available if Syn is built with the `"fold"` feature.* +pub trait Fold { + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_abi(&mut self, i: Abi) -> Abi { + fold_abi(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_angle_bracketed_generic_arguments( + &mut self, + i: AngleBracketedGenericArguments, + ) -> AngleBracketedGenericArguments { + fold_angle_bracketed_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn fold_arm(&mut self, i: Arm) -> Arm { + fold_arm(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_attr_style(&mut self, i: AttrStyle) -> AttrStyle { + fold_attr_style(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_attribute(&mut self, i: Attribute) -> Attribute { + fold_attribute(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bare_fn_arg(&mut self, i: BareFnArg) -> BareFnArg { + fold_bare_fn_arg(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bin_op(&mut self, i: BinOp) -> BinOp { + fold_bin_op(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_binding(&mut self, i: Binding) -> Binding { + fold_binding(self, i) + } + #[cfg(feature = "full")] + fn fold_block(&mut self, i: Block) -> Block { + fold_block(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bound_lifetimes(&mut self, i: BoundLifetimes) -> BoundLifetimes { + fold_bound_lifetimes(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_const_param(&mut self, i: ConstParam) -> ConstParam { + fold_const_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_constraint(&mut self, i: Constraint) -> Constraint { + fold_constraint(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 = "derive", feature = "full"))] + fn fold_expr(&mut self, i: Expr) -> Expr { + fold_expr(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_array(&mut self, i: ExprArray) -> ExprArray { + fold_expr_array(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_assign(&mut self, i: ExprAssign) -> ExprAssign { + fold_expr_assign(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_assign_op(&mut self, i: ExprAssignOp) -> ExprAssignOp { + fold_expr_assign_op(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_async(&mut self, i: ExprAsync) -> ExprAsync { + fold_expr_async(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_await(&mut self, i: ExprAwait) -> ExprAwait { + fold_expr_await(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_binary(&mut self, i: ExprBinary) -> ExprBinary { + fold_expr_binary(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_block(&mut self, i: ExprBlock) -> ExprBlock { + fold_expr_block(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_box(&mut self, i: ExprBox) -> ExprBox { + fold_expr_box(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_break(&mut self, i: ExprBreak) -> ExprBreak { + fold_expr_break(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_call(&mut self, i: ExprCall) -> ExprCall { + fold_expr_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_cast(&mut self, i: ExprCast) -> ExprCast { + fold_expr_cast(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_closure(&mut self, i: ExprClosure) -> ExprClosure { + fold_expr_closure(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_continue(&mut self, i: ExprContinue) -> ExprContinue { + fold_expr_continue(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_field(&mut self, i: ExprField) -> ExprField { + fold_expr_field(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_for_loop(&mut self, i: ExprForLoop) -> ExprForLoop { + fold_expr_for_loop(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_group(&mut self, i: ExprGroup) -> ExprGroup { + fold_expr_group(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_if(&mut self, i: ExprIf) -> ExprIf { + fold_expr_if(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_index(&mut self, i: ExprIndex) -> ExprIndex { + fold_expr_index(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_let(&mut self, i: ExprLet) -> ExprLet { + fold_expr_let(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_lit(&mut self, i: ExprLit) -> ExprLit { + fold_expr_lit(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_loop(&mut self, i: ExprLoop) -> ExprLoop { + fold_expr_loop(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_macro(&mut self, i: ExprMacro) -> ExprMacro { + fold_expr_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_match(&mut self, i: ExprMatch) -> ExprMatch { + fold_expr_match(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_method_call(&mut self, i: ExprMethodCall) -> ExprMethodCall { + fold_expr_method_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_paren(&mut self, i: ExprParen) -> ExprParen { + fold_expr_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_path(&mut self, i: ExprPath) -> ExprPath { + fold_expr_path(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_range(&mut self, i: ExprRange) -> ExprRange { + fold_expr_range(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_reference(&mut self, i: ExprReference) -> ExprReference { + fold_expr_reference(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_repeat(&mut self, i: ExprRepeat) -> ExprRepeat { + fold_expr_repeat(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_return(&mut self, i: ExprReturn) -> ExprReturn { + fold_expr_return(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_struct(&mut self, i: ExprStruct) -> ExprStruct { + fold_expr_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_try(&mut self, i: ExprTry) -> ExprTry { + fold_expr_try(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_try_block(&mut self, i: ExprTryBlock) -> ExprTryBlock { + fold_expr_try_block(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_tuple(&mut self, i: ExprTuple) -> ExprTuple { + fold_expr_tuple(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_type(&mut self, i: ExprType) -> ExprType { + fold_expr_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_unary(&mut self, i: ExprUnary) -> ExprUnary { + fold_expr_unary(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_unsafe(&mut self, i: ExprUnsafe) -> ExprUnsafe { + fold_expr_unsafe(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_while(&mut self, i: ExprWhile) -> ExprWhile { + fold_expr_while(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_yield(&mut self, i: ExprYield) -> ExprYield { + fold_expr_yield(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_field(&mut self, i: Field) -> Field { + fold_field(self, i) + } + #[cfg(feature = "full")] + fn fold_field_pat(&mut self, i: FieldPat) -> FieldPat { + fold_field_pat(self, i) + } + #[cfg(feature = "full")] + fn fold_field_value(&mut self, i: FieldValue) -> FieldValue { + fold_field_value(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_fields(&mut self, i: Fields) -> Fields { + fold_fields(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_fields_named(&mut self, i: FieldsNamed) -> FieldsNamed { + fold_fields_named(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn fold_generic_argument(&mut self, i: GenericArgument) -> GenericArgument { + fold_generic_argument(self, i) + } + #[cfg(feature = "full")] + fn fold_generic_method_argument(&mut self, i: GenericMethodArgument) -> GenericMethodArgument { + fold_generic_method_argument(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_generic_param(&mut self, i: GenericParam) -> GenericParam { + fold_generic_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + 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_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_trait_alias(&mut self, i: ItemTraitAlias) -> ItemTraitAlias { + fold_item_trait_alias(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_label(&mut self, i: Label) -> Label { + fold_label(self, i) + } + fn fold_lifetime(&mut self, i: Lifetime) -> Lifetime { + fold_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lifetime_def(&mut self, i: LifetimeDef) -> LifetimeDef { + fold_lifetime_def(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit(&mut self, i: Lit) -> Lit { + fold_lit(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_bool(&mut self, i: LitBool) -> LitBool { + fold_lit_bool(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_byte(&mut self, i: LitByte) -> LitByte { + fold_lit_byte(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_byte_str(&mut self, i: LitByteStr) -> LitByteStr { + fold_lit_byte_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_char(&mut self, i: LitChar) -> LitChar { + fold_lit_char(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_float(&mut self, i: LitFloat) -> LitFloat { + fold_lit_float(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_int(&mut self, i: LitInt) -> LitInt { + fold_lit_int(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_str(&mut self, i: LitStr) -> LitStr { + fold_lit_str(self, i) + } + #[cfg(feature = "full")] + fn fold_local(&mut self, i: Local) -> Local { + fold_local(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_macro(&mut self, i: Macro) -> Macro { + fold_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_macro_delimiter(&mut self, i: MacroDelimiter) -> MacroDelimiter { + fold_macro_delimiter(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_member(&mut self, i: Member) -> Member { + fold_member(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta(&mut self, i: Meta) -> Meta { + fold_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta_list(&mut self, i: MetaList) -> MetaList { + fold_meta_list(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta_name_value(&mut self, i: MetaNameValue) -> MetaNameValue { + fold_meta_name_value(self, i) + } + #[cfg(feature = "full")] + fn fold_method_turbofish(&mut self, i: MethodTurbofish) -> MethodTurbofish { + fold_method_turbofish(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_nested_meta(&mut self, i: NestedMeta) -> NestedMeta { + fold_nested_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_parenthesized_generic_arguments( + &mut self, + i: ParenthesizedGenericArguments, + ) -> ParenthesizedGenericArguments { + fold_parenthesized_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn fold_pat(&mut self, i: Pat) -> Pat { + fold_pat(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_box(&mut self, i: PatBox) -> PatBox { + fold_pat_box(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_ident(&mut self, i: PatIdent) -> PatIdent { + fold_pat_ident(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_lit(&mut self, i: PatLit) -> PatLit { + fold_pat_lit(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_macro(&mut self, i: PatMacro) -> PatMacro { + fold_pat_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_or(&mut self, i: PatOr) -> PatOr { + fold_pat_or(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_path(&mut self, i: PatPath) -> PatPath { + fold_pat_path(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_range(&mut self, i: PatRange) -> PatRange { + fold_pat_range(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_reference(&mut self, i: PatReference) -> PatReference { + fold_pat_reference(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_rest(&mut self, i: PatRest) -> PatRest { + fold_pat_rest(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_slice(&mut self, i: PatSlice) -> PatSlice { + fold_pat_slice(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_struct(&mut self, i: PatStruct) -> PatStruct { + fold_pat_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_tuple(&mut self, i: PatTuple) -> PatTuple { + fold_pat_tuple(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_tuple_struct(&mut self, i: PatTupleStruct) -> PatTupleStruct { + fold_pat_tuple_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_type(&mut self, i: PatType) -> PatType { + fold_pat_type(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_wild(&mut self, i: PatWild) -> PatWild { + fold_pat_wild(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path(&mut self, i: Path) -> Path { + fold_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path_arguments(&mut self, i: PathArguments) -> PathArguments { + fold_path_arguments(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path_segment(&mut self, i: PathSegment) -> PathSegment { + fold_path_segment(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_eq(&mut self, i: PredicateEq) -> PredicateEq { + fold_predicate_eq(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_lifetime(&mut self, i: PredicateLifetime) -> PredicateLifetime { + fold_predicate_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_type(&mut self, i: PredicateType) -> PredicateType { + fold_predicate_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_qself(&mut self, i: QSelf) -> QSelf { + fold_qself(self, i) + } + #[cfg(feature = "full")] + fn fold_range_limits(&mut self, i: RangeLimits) -> RangeLimits { + fold_range_limits(self, i) + } + #[cfg(feature = "full")] + fn fold_receiver(&mut self, i: Receiver) -> Receiver { + fold_receiver(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_return_type(&mut self, i: ReturnType) -> ReturnType { + fold_return_type(self, i) + } + #[cfg(feature = "full")] + fn fold_signature(&mut self, i: Signature) -> Signature { + fold_signature(self, i) + } + fn fold_span(&mut self, i: Span) -> Span { + fold_span(self, i) + } + #[cfg(feature = "full")] + fn fold_stmt(&mut self, i: Stmt) -> Stmt { + fold_stmt(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_trait_bound(&mut self, i: TraitBound) -> TraitBound { + fold_trait_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn fold_type(&mut self, i: Type) -> Type { + fold_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_array(&mut self, i: TypeArray) -> TypeArray { + fold_type_array(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_bare_fn(&mut self, i: TypeBareFn) -> TypeBareFn { + fold_type_bare_fn(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_group(&mut self, i: TypeGroup) -> TypeGroup { + fold_type_group(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_impl_trait(&mut self, i: TypeImplTrait) -> TypeImplTrait { + fold_type_impl_trait(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_infer(&mut self, i: TypeInfer) -> TypeInfer { + fold_type_infer(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_macro(&mut self, i: TypeMacro) -> TypeMacro { + fold_type_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_never(&mut self, i: TypeNever) -> TypeNever { + fold_type_never(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_param(&mut self, i: TypeParam) -> TypeParam { + fold_type_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_param_bound(&mut self, i: TypeParamBound) -> TypeParamBound { + fold_type_param_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_paren(&mut self, i: TypeParen) -> TypeParen { + fold_type_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_path(&mut self, i: TypePath) -> TypePath { + fold_type_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_ptr(&mut self, i: TypePtr) -> TypePtr { + fold_type_ptr(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_reference(&mut self, i: TypeReference) -> TypeReference { + fold_type_reference(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_slice(&mut self, i: TypeSlice) -> TypeSlice { + fold_type_slice(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_trait_object(&mut self, i: TypeTraitObject) -> TypeTraitObject { + fold_type_trait_object(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_tuple(&mut self, i: TypeTuple) -> TypeTuple { + fold_type_tuple(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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 = "derive", feature = "full"))] + fn fold_variadic(&mut self, i: Variadic) -> Variadic { + fold_variadic(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_variant(&mut self, i: Variant) -> Variant { + fold_variant(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_crate(&mut self, i: VisCrate) -> VisCrate { + fold_vis_crate(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_public(&mut self, i: VisPublic) -> VisPublic { + fold_vis_public(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_restricted(&mut self, i: VisRestricted) -> VisRestricted { + fold_vis_restricted(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_visibility(&mut self, i: Visibility) -> Visibility { + fold_visibility(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_where_clause(&mut self, i: WhereClause) -> WhereClause { + fold_where_clause(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_where_predicate(&mut self, i: WherePredicate) -> WherePredicate { + fold_where_predicate(self, i) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_abi<F>(f: &mut F, node: Abi) -> Abi +where + F: Fold + ?Sized, +{ + Abi { + extern_token: Token![extern](tokens_helper(f, &node.extern_token.span)), + name: (node.name).map(|it| f.fold_lit_str(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_angle_bracketed_generic_arguments<F>( + f: &mut F, + node: AngleBracketedGenericArguments, +) -> AngleBracketedGenericArguments +where + F: Fold + ?Sized, +{ + AngleBracketedGenericArguments { + colon2_token: (node.colon2_token).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), + lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + args: FoldHelper::lift(node.args, |it| f.fold_generic_argument(it)), + gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_arm<F>(f: &mut F, node: Arm) -> Arm +where + F: Fold + ?Sized, +{ + Arm { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + pat: f.fold_pat(node.pat), + guard: (node.guard).map(|it| { + ( + Token![if](tokens_helper(f, &(it).0.span)), + Box::new(f.fold_expr(*(it).1)), + ) + }), + fat_arrow_token: Token ! [ => ](tokens_helper(f, &node.fat_arrow_token.spans)), + body: Box::new(f.fold_expr(*node.body)), + comma: (node.comma).map(|it| Token ! [ , ](tokens_helper(f, &it.spans))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_attr_style<F>(f: &mut F, node: AttrStyle) -> AttrStyle +where + F: Fold + ?Sized, +{ + match node { + AttrStyle::Outer => AttrStyle::Outer, + AttrStyle::Inner(_binding_0) => { + AttrStyle::Inner(Token![!](tokens_helper(f, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_attribute<F>(f: &mut F, node: Attribute) -> Attribute +where + F: Fold + ?Sized, +{ + Attribute { + pound_token: Token ! [ # ](tokens_helper(f, &node.pound_token.spans)), + style: f.fold_attr_style(node.style), + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + path: f.fold_path(node.path), + tokens: node.tokens, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bare_fn_arg<F>(f: &mut F, node: BareFnArg) -> BareFnArg +where + F: Fold + ?Sized, +{ + BareFnArg { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + name: (node.name).map(|it| { + ( + f.fold_ident((it).0), + Token ! [ : ](tokens_helper(f, &(it).1.spans)), + ) + }), + ty: f.fold_type(node.ty), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bin_op<F>(f: &mut F, node: BinOp) -> BinOp +where + F: Fold + ?Sized, +{ + match node { + BinOp::Add(_binding_0) => BinOp::Add(Token ! [ + ](tokens_helper(f, &_binding_0.spans))), + BinOp::Sub(_binding_0) => BinOp::Sub(Token ! [ - ](tokens_helper(f, &_binding_0.spans))), + BinOp::Mul(_binding_0) => BinOp::Mul(Token ! [ * ](tokens_helper(f, &_binding_0.spans))), + BinOp::Div(_binding_0) => BinOp::Div(Token ! [ / ](tokens_helper(f, &_binding_0.spans))), + BinOp::Rem(_binding_0) => BinOp::Rem(Token ! [ % ](tokens_helper(f, &_binding_0.spans))), + BinOp::And(_binding_0) => BinOp::And(Token ! [ && ](tokens_helper(f, &_binding_0.spans))), + BinOp::Or(_binding_0) => BinOp::Or(Token ! [ || ](tokens_helper(f, &_binding_0.spans))), + BinOp::BitXor(_binding_0) => { + BinOp::BitXor(Token ! [ ^ ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::BitAnd(_binding_0) => { + BinOp::BitAnd(Token ! [ & ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::BitOr(_binding_0) => { + BinOp::BitOr(Token ! [ | ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::Shl(_binding_0) => BinOp::Shl(Token ! [ << ](tokens_helper(f, &_binding_0.spans))), + BinOp::Shr(_binding_0) => BinOp::Shr(Token ! [ >> ](tokens_helper(f, &_binding_0.spans))), + BinOp::Eq(_binding_0) => BinOp::Eq(Token ! [ == ](tokens_helper(f, &_binding_0.spans))), + BinOp::Lt(_binding_0) => BinOp::Lt(Token ! [ < ](tokens_helper(f, &_binding_0.spans))), + BinOp::Le(_binding_0) => BinOp::Le(Token ! [ <= ](tokens_helper(f, &_binding_0.spans))), + BinOp::Ne(_binding_0) => BinOp::Ne(Token ! [ != ](tokens_helper(f, &_binding_0.spans))), + BinOp::Ge(_binding_0) => BinOp::Ge(Token ! [ >= ](tokens_helper(f, &_binding_0.spans))), + BinOp::Gt(_binding_0) => BinOp::Gt(Token ! [ > ](tokens_helper(f, &_binding_0.spans))), + BinOp::AddEq(_binding_0) => { + BinOp::AddEq(Token ! [ += ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::SubEq(_binding_0) => { + BinOp::SubEq(Token ! [ -= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::MulEq(_binding_0) => { + BinOp::MulEq(Token ! [ *= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::DivEq(_binding_0) => { + BinOp::DivEq(Token ! [ /= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::RemEq(_binding_0) => { + BinOp::RemEq(Token ! [ %= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::BitXorEq(_binding_0) => { + BinOp::BitXorEq(Token ! [ ^= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::BitAndEq(_binding_0) => { + BinOp::BitAndEq(Token ! [ &= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::BitOrEq(_binding_0) => { + BinOp::BitOrEq(Token ! [ |= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::ShlEq(_binding_0) => { + BinOp::ShlEq(Token ! [ <<= ](tokens_helper(f, &_binding_0.spans))) + } + BinOp::ShrEq(_binding_0) => { + BinOp::ShrEq(Token ! [ >>= ](tokens_helper(f, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_binding<F>(f: &mut F, node: Binding) -> Binding +where + F: Fold + ?Sized, +{ + Binding { + ident: f.fold_ident(node.ident), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + ty: f.fold_type(node.ty), + } +} +#[cfg(feature = "full")] +pub fn fold_block<F>(f: &mut F, node: Block) -> Block +where + F: Fold + ?Sized, +{ + Block { + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + stmts: FoldHelper::lift(node.stmts, |it| f.fold_stmt(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bound_lifetimes<F>(f: &mut F, node: BoundLifetimes) -> BoundLifetimes +where + F: Fold + ?Sized, +{ + BoundLifetimes { + for_token: Token![for](tokens_helper(f, &node.for_token.span)), + lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + lifetimes: FoldHelper::lift(node.lifetimes, |it| f.fold_lifetime_def(it)), + gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_const_param<F>(f: &mut F, node: ConstParam) -> ConstParam +where + F: Fold + ?Sized, +{ + ConstParam { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + const_token: Token![const](tokens_helper(f, &node.const_token.span)), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: f.fold_type(node.ty), + eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))), + default: (node.default).map(|it| f.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_constraint<F>(f: &mut F, node: Constraint) -> Constraint +where + F: Fold + ?Sized, +{ + Constraint { + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data<F>(f: &mut F, node: Data) -> Data +where + F: Fold + ?Sized, +{ + match node { + Data::Struct(_binding_0) => Data::Struct(f.fold_data_struct(_binding_0)), + Data::Enum(_binding_0) => Data::Enum(f.fold_data_enum(_binding_0)), + Data::Union(_binding_0) => Data::Union(f.fold_data_union(_binding_0)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_enum<F>(f: &mut F, node: DataEnum) -> DataEnum +where + F: Fold + ?Sized, +{ + DataEnum { + enum_token: Token![enum](tokens_helper(f, &node.enum_token.span)), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + variants: FoldHelper::lift(node.variants, |it| f.fold_variant(it)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_struct<F>(f: &mut F, node: DataStruct) -> DataStruct +where + F: Fold + ?Sized, +{ + DataStruct { + struct_token: Token![struct](tokens_helper(f, &node.struct_token.span)), + fields: f.fold_fields(node.fields), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_union<F>(f: &mut F, node: DataUnion) -> DataUnion +where + F: Fold + ?Sized, +{ + DataUnion { + union_token: Token![union](tokens_helper(f, &node.union_token.span)), + fields: f.fold_fields_named(node.fields), + } +} +#[cfg(feature = "derive")] +pub fn fold_derive_input<F>(f: &mut F, node: DeriveInput) -> DeriveInput +where + F: Fold + ?Sized, +{ + DeriveInput { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + data: f.fold_data(node.data), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr<F>(f: &mut F, node: Expr) -> Expr +where + F: Fold + ?Sized, +{ + match node { + Expr::Array(_binding_0) => Expr::Array(full!(f.fold_expr_array(_binding_0))), + Expr::Assign(_binding_0) => Expr::Assign(full!(f.fold_expr_assign(_binding_0))), + Expr::AssignOp(_binding_0) => Expr::AssignOp(full!(f.fold_expr_assign_op(_binding_0))), + Expr::Async(_binding_0) => Expr::Async(full!(f.fold_expr_async(_binding_0))), + Expr::Await(_binding_0) => Expr::Await(full!(f.fold_expr_await(_binding_0))), + Expr::Binary(_binding_0) => Expr::Binary(f.fold_expr_binary(_binding_0)), + Expr::Block(_binding_0) => Expr::Block(full!(f.fold_expr_block(_binding_0))), + Expr::Box(_binding_0) => Expr::Box(full!(f.fold_expr_box(_binding_0))), + Expr::Break(_binding_0) => Expr::Break(full!(f.fold_expr_break(_binding_0))), + Expr::Call(_binding_0) => Expr::Call(f.fold_expr_call(_binding_0)), + Expr::Cast(_binding_0) => Expr::Cast(f.fold_expr_cast(_binding_0)), + Expr::Closure(_binding_0) => Expr::Closure(full!(f.fold_expr_closure(_binding_0))), + Expr::Continue(_binding_0) => Expr::Continue(full!(f.fold_expr_continue(_binding_0))), + Expr::Field(_binding_0) => Expr::Field(f.fold_expr_field(_binding_0)), + Expr::ForLoop(_binding_0) => Expr::ForLoop(full!(f.fold_expr_for_loop(_binding_0))), + Expr::Group(_binding_0) => Expr::Group(full!(f.fold_expr_group(_binding_0))), + Expr::If(_binding_0) => Expr::If(full!(f.fold_expr_if(_binding_0))), + Expr::Index(_binding_0) => Expr::Index(f.fold_expr_index(_binding_0)), + Expr::Let(_binding_0) => Expr::Let(full!(f.fold_expr_let(_binding_0))), + Expr::Lit(_binding_0) => Expr::Lit(f.fold_expr_lit(_binding_0)), + Expr::Loop(_binding_0) => Expr::Loop(full!(f.fold_expr_loop(_binding_0))), + Expr::Macro(_binding_0) => Expr::Macro(full!(f.fold_expr_macro(_binding_0))), + Expr::Match(_binding_0) => Expr::Match(full!(f.fold_expr_match(_binding_0))), + Expr::MethodCall(_binding_0) => { + Expr::MethodCall(full!(f.fold_expr_method_call(_binding_0))) + } + Expr::Paren(_binding_0) => Expr::Paren(f.fold_expr_paren(_binding_0)), + Expr::Path(_binding_0) => Expr::Path(f.fold_expr_path(_binding_0)), + Expr::Range(_binding_0) => Expr::Range(full!(f.fold_expr_range(_binding_0))), + Expr::Reference(_binding_0) => Expr::Reference(full!(f.fold_expr_reference(_binding_0))), + Expr::Repeat(_binding_0) => Expr::Repeat(full!(f.fold_expr_repeat(_binding_0))), + Expr::Return(_binding_0) => Expr::Return(full!(f.fold_expr_return(_binding_0))), + Expr::Struct(_binding_0) => Expr::Struct(full!(f.fold_expr_struct(_binding_0))), + Expr::Try(_binding_0) => Expr::Try(full!(f.fold_expr_try(_binding_0))), + Expr::TryBlock(_binding_0) => Expr::TryBlock(full!(f.fold_expr_try_block(_binding_0))), + Expr::Tuple(_binding_0) => Expr::Tuple(full!(f.fold_expr_tuple(_binding_0))), + Expr::Type(_binding_0) => Expr::Type(full!(f.fold_expr_type(_binding_0))), + Expr::Unary(_binding_0) => Expr::Unary(f.fold_expr_unary(_binding_0)), + Expr::Unsafe(_binding_0) => Expr::Unsafe(full!(f.fold_expr_unsafe(_binding_0))), + Expr::Verbatim(_binding_0) => Expr::Verbatim(_binding_0), + Expr::While(_binding_0) => Expr::While(full!(f.fold_expr_while(_binding_0))), + Expr::Yield(_binding_0) => Expr::Yield(full!(f.fold_expr_yield(_binding_0))), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_array<F>(f: &mut F, node: ExprArray) -> ExprArray +where + F: Fold + ?Sized, +{ + ExprArray { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + elems: FoldHelper::lift(node.elems, |it| f.fold_expr(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_assign<F>(f: &mut F, node: ExprAssign) -> ExprAssign +where + F: Fold + ?Sized, +{ + ExprAssign { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + left: Box::new(f.fold_expr(*node.left)), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + right: Box::new(f.fold_expr(*node.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_assign_op<F>(f: &mut F, node: ExprAssignOp) -> ExprAssignOp +where + F: Fold + ?Sized, +{ + ExprAssignOp { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + left: Box::new(f.fold_expr(*node.left)), + op: f.fold_bin_op(node.op), + right: Box::new(f.fold_expr(*node.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_async<F>(f: &mut F, node: ExprAsync) -> ExprAsync +where + F: Fold + ?Sized, +{ + ExprAsync { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + async_token: Token![async](tokens_helper(f, &node.async_token.span)), + capture: (node.capture).map(|it| Token![move](tokens_helper(f, &it.span))), + block: f.fold_block(node.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_await<F>(f: &mut F, node: ExprAwait) -> ExprAwait +where + F: Fold + ?Sized, +{ + ExprAwait { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + base: Box::new(f.fold_expr(*node.base)), + dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + await_token: crate::token::Await(tokens_helper(f, &node.await_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_binary<F>(f: &mut F, node: ExprBinary) -> ExprBinary +where + F: Fold + ?Sized, +{ + ExprBinary { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + left: Box::new(f.fold_expr(*node.left)), + op: f.fold_bin_op(node.op), + right: Box::new(f.fold_expr(*node.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_block<F>(f: &mut F, node: ExprBlock) -> ExprBlock +where + F: Fold + ?Sized, +{ + ExprBlock { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + label: (node.label).map(|it| f.fold_label(it)), + block: f.fold_block(node.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_box<F>(f: &mut F, node: ExprBox) -> ExprBox +where + F: Fold + ?Sized, +{ + ExprBox { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + box_token: Token![box](tokens_helper(f, &node.box_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_break<F>(f: &mut F, node: ExprBreak) -> ExprBreak +where + F: Fold + ?Sized, +{ + ExprBreak { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + break_token: Token![break](tokens_helper(f, &node.break_token.span)), + label: (node.label).map(|it| f.fold_lifetime(it)), + expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_call<F>(f: &mut F, node: ExprCall) -> ExprCall +where + F: Fold + ?Sized, +{ + ExprCall { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + func: Box::new(f.fold_expr(*node.func)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + args: FoldHelper::lift(node.args, |it| f.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_cast<F>(f: &mut F, node: ExprCast) -> ExprCast +where + F: Fold + ?Sized, +{ + ExprCast { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + expr: Box::new(f.fold_expr(*node.expr)), + as_token: Token![as](tokens_helper(f, &node.as_token.span)), + ty: Box::new(f.fold_type(*node.ty)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_closure<F>(f: &mut F, node: ExprClosure) -> ExprClosure +where + F: Fold + ?Sized, +{ + ExprClosure { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))), + movability: (node.movability).map(|it| Token![static](tokens_helper(f, &it.span))), + capture: (node.capture).map(|it| Token![move](tokens_helper(f, &it.span))), + or1_token: Token ! [ | ](tokens_helper(f, &node.or1_token.spans)), + inputs: FoldHelper::lift(node.inputs, |it| f.fold_pat(it)), + or2_token: Token ! [ | ](tokens_helper(f, &node.or2_token.spans)), + output: f.fold_return_type(node.output), + body: Box::new(f.fold_expr(*node.body)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_continue<F>(f: &mut F, node: ExprContinue) -> ExprContinue +where + F: Fold + ?Sized, +{ + ExprContinue { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + continue_token: Token![continue](tokens_helper(f, &node.continue_token.span)), + label: (node.label).map(|it| f.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_field<F>(f: &mut F, node: ExprField) -> ExprField +where + F: Fold + ?Sized, +{ + ExprField { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + base: Box::new(f.fold_expr(*node.base)), + dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + member: f.fold_member(node.member), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_for_loop<F>(f: &mut F, node: ExprForLoop) -> ExprForLoop +where + F: Fold + ?Sized, +{ + ExprForLoop { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + label: (node.label).map(|it| f.fold_label(it)), + for_token: Token![for](tokens_helper(f, &node.for_token.span)), + pat: f.fold_pat(node.pat), + in_token: Token![in](tokens_helper(f, &node.in_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + body: f.fold_block(node.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_group<F>(f: &mut F, node: ExprGroup) -> ExprGroup +where + F: Fold + ?Sized, +{ + ExprGroup { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + group_token: Group(tokens_helper(f, &node.group_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_if<F>(f: &mut F, node: ExprIf) -> ExprIf +where + F: Fold + ?Sized, +{ + ExprIf { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + if_token: Token![if](tokens_helper(f, &node.if_token.span)), + cond: Box::new(f.fold_expr(*node.cond)), + then_branch: f.fold_block(node.then_branch), + else_branch: (node.else_branch).map(|it| { + ( + Token![else](tokens_helper(f, &(it).0.span)), + Box::new(f.fold_expr(*(it).1)), + ) + }), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_index<F>(f: &mut F, node: ExprIndex) -> ExprIndex +where + F: Fold + ?Sized, +{ + ExprIndex { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + expr: Box::new(f.fold_expr(*node.expr)), + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + index: Box::new(f.fold_expr(*node.index)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_let<F>(f: &mut F, node: ExprLet) -> ExprLet +where + F: Fold + ?Sized, +{ + ExprLet { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + let_token: Token![let](tokens_helper(f, &node.let_token.span)), + pat: f.fold_pat(node.pat), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_lit<F>(f: &mut F, node: ExprLit) -> ExprLit +where + F: Fold + ?Sized, +{ + ExprLit { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + lit: f.fold_lit(node.lit), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_loop<F>(f: &mut F, node: ExprLoop) -> ExprLoop +where + F: Fold + ?Sized, +{ + ExprLoop { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + label: (node.label).map(|it| f.fold_label(it)), + loop_token: Token![loop](tokens_helper(f, &node.loop_token.span)), + body: f.fold_block(node.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_macro<F>(f: &mut F, node: ExprMacro) -> ExprMacro +where + F: Fold + ?Sized, +{ + ExprMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + mac: f.fold_macro(node.mac), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_match<F>(f: &mut F, node: ExprMatch) -> ExprMatch +where + F: Fold + ?Sized, +{ + ExprMatch { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + match_token: Token![match](tokens_helper(f, &node.match_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + arms: FoldHelper::lift(node.arms, |it| f.fold_arm(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_method_call<F>(f: &mut F, node: ExprMethodCall) -> ExprMethodCall +where + F: Fold + ?Sized, +{ + ExprMethodCall { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + receiver: Box::new(f.fold_expr(*node.receiver)), + dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + method: f.fold_ident(node.method), + turbofish: (node.turbofish).map(|it| f.fold_method_turbofish(it)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + args: FoldHelper::lift(node.args, |it| f.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_paren<F>(f: &mut F, node: ExprParen) -> ExprParen +where + F: Fold + ?Sized, +{ + ExprParen { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_path<F>(f: &mut F, node: ExprPath) -> ExprPath +where + F: Fold + ?Sized, +{ + ExprPath { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + qself: (node.qself).map(|it| f.fold_qself(it)), + path: f.fold_path(node.path), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_range<F>(f: &mut F, node: ExprRange) -> ExprRange +where + F: Fold + ?Sized, +{ + ExprRange { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + from: (node.from).map(|it| Box::new(f.fold_expr(*it))), + limits: f.fold_range_limits(node.limits), + to: (node.to).map(|it| Box::new(f.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_reference<F>(f: &mut F, node: ExprReference) -> ExprReference +where + F: Fold + ?Sized, +{ + ExprReference { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + raw: node.raw, + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_repeat<F>(f: &mut F, node: ExprRepeat) -> ExprRepeat +where + F: Fold + ?Sized, +{ + ExprRepeat { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + expr: Box::new(f.fold_expr(*node.expr)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + len: Box::new(f.fold_expr(*node.len)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_return<F>(f: &mut F, node: ExprReturn) -> ExprReturn +where + F: Fold + ?Sized, +{ + ExprReturn { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + return_token: Token![return](tokens_helper(f, &node.return_token.span)), + expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_struct<F>(f: &mut F, node: ExprStruct) -> ExprStruct +where + F: Fold + ?Sized, +{ + ExprStruct { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + path: f.fold_path(node.path), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + fields: FoldHelper::lift(node.fields, |it| f.fold_field_value(it)), + dot2_token: (node.dot2_token).map(|it| Token![..](tokens_helper(f, &it.spans))), + rest: (node.rest).map(|it| Box::new(f.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_try<F>(f: &mut F, node: ExprTry) -> ExprTry +where + F: Fold + ?Sized, +{ + ExprTry { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + expr: Box::new(f.fold_expr(*node.expr)), + question_token: Token ! [ ? ](tokens_helper(f, &node.question_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_try_block<F>(f: &mut F, node: ExprTryBlock) -> ExprTryBlock +where + F: Fold + ?Sized, +{ + ExprTryBlock { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + try_token: Token![try](tokens_helper(f, &node.try_token.span)), + block: f.fold_block(node.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_tuple<F>(f: &mut F, node: ExprTuple) -> ExprTuple +where + F: Fold + ?Sized, +{ + ExprTuple { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + elems: FoldHelper::lift(node.elems, |it| f.fold_expr(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_type<F>(f: &mut F, node: ExprType) -> ExprType +where + F: Fold + ?Sized, +{ + ExprType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + expr: Box::new(f.fold_expr(*node.expr)), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_unary<F>(f: &mut F, node: ExprUnary) -> ExprUnary +where + F: Fold + ?Sized, +{ + ExprUnary { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + op: f.fold_un_op(node.op), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_unsafe<F>(f: &mut F, node: ExprUnsafe) -> ExprUnsafe +where + F: Fold + ?Sized, +{ + ExprUnsafe { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + unsafe_token: Token![unsafe](tokens_helper(f, &node.unsafe_token.span)), + block: f.fold_block(node.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_while<F>(f: &mut F, node: ExprWhile) -> ExprWhile +where + F: Fold + ?Sized, +{ + ExprWhile { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + label: (node.label).map(|it| f.fold_label(it)), + while_token: Token![while](tokens_helper(f, &node.while_token.span)), + cond: Box::new(f.fold_expr(*node.cond)), + body: f.fold_block(node.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_yield<F>(f: &mut F, node: ExprYield) -> ExprYield +where + F: Fold + ?Sized, +{ + ExprYield { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + yield_token: Token![yield](tokens_helper(f, &node.yield_token.span)), + expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_field<F>(f: &mut F, node: Field) -> Field +where + F: Fold + ?Sized, +{ + Field { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + ident: (node.ident).map(|it| f.fold_ident(it)), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + ty: f.fold_type(node.ty), + } +} +#[cfg(feature = "full")] +pub fn fold_field_pat<F>(f: &mut F, node: FieldPat) -> FieldPat +where + F: Fold + ?Sized, +{ + FieldPat { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + member: f.fold_member(node.member), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + pat: Box::new(f.fold_pat(*node.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_field_value<F>(f: &mut F, node: FieldValue) -> FieldValue +where + F: Fold + ?Sized, +{ + FieldValue { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + member: f.fold_member(node.member), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + expr: f.fold_expr(node.expr), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields<F>(f: &mut F, node: Fields) -> Fields +where + F: Fold + ?Sized, +{ + match node { + Fields::Named(_binding_0) => Fields::Named(f.fold_fields_named(_binding_0)), + Fields::Unnamed(_binding_0) => Fields::Unnamed(f.fold_fields_unnamed(_binding_0)), + Fields::Unit => Fields::Unit, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields_named<F>(f: &mut F, node: FieldsNamed) -> FieldsNamed +where + F: Fold + ?Sized, +{ + FieldsNamed { + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + named: FoldHelper::lift(node.named, |it| f.fold_field(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields_unnamed<F>(f: &mut F, node: FieldsUnnamed) -> FieldsUnnamed +where + F: Fold + ?Sized, +{ + FieldsUnnamed { + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + unnamed: FoldHelper::lift(node.unnamed, |it| f.fold_field(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_file<F>(f: &mut F, node: File) -> File +where + F: Fold + ?Sized, +{ + File { + shebang: node.shebang, + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + items: FoldHelper::lift(node.items, |it| f.fold_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_fn_arg<F>(f: &mut F, node: FnArg) -> FnArg +where + F: Fold + ?Sized, +{ + match node { + FnArg::Receiver(_binding_0) => FnArg::Receiver(f.fold_receiver(_binding_0)), + FnArg::Typed(_binding_0) => FnArg::Typed(f.fold_pat_type(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item<F>(f: &mut F, node: ForeignItem) -> ForeignItem +where + F: Fold + ?Sized, +{ + match node { + ForeignItem::Fn(_binding_0) => ForeignItem::Fn(f.fold_foreign_item_fn(_binding_0)), + ForeignItem::Static(_binding_0) => { + ForeignItem::Static(f.fold_foreign_item_static(_binding_0)) + } + ForeignItem::Type(_binding_0) => ForeignItem::Type(f.fold_foreign_item_type(_binding_0)), + ForeignItem::Macro(_binding_0) => ForeignItem::Macro(f.fold_foreign_item_macro(_binding_0)), + ForeignItem::Verbatim(_binding_0) => ForeignItem::Verbatim(_binding_0), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_fn<F>(f: &mut F, node: ForeignItemFn) -> ForeignItemFn +where + F: Fold + ?Sized, +{ + ForeignItemFn { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + sig: f.fold_signature(node.sig), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_macro<F>(f: &mut F, node: ForeignItemMacro) -> ForeignItemMacro +where + F: Fold + ?Sized, +{ + ForeignItemMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + mac: f.fold_macro(node.mac), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_static<F>(f: &mut F, node: ForeignItemStatic) -> ForeignItemStatic +where + F: Fold + ?Sized, +{ + ForeignItemStatic { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + static_token: Token![static](tokens_helper(f, &node.static_token.span)), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_type<F>(f: &mut F, node: ForeignItemType) -> ForeignItemType +where + F: Fold + ?Sized, +{ + ForeignItemType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + type_token: Token![type](tokens_helper(f, &node.type_token.span)), + ident: f.fold_ident(node.ident), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generic_argument<F>(f: &mut F, node: GenericArgument) -> GenericArgument +where + F: Fold + ?Sized, +{ + match node { + GenericArgument::Lifetime(_binding_0) => { + GenericArgument::Lifetime(f.fold_lifetime(_binding_0)) + } + GenericArgument::Type(_binding_0) => GenericArgument::Type(f.fold_type(_binding_0)), + GenericArgument::Binding(_binding_0) => { + GenericArgument::Binding(f.fold_binding(_binding_0)) + } + GenericArgument::Constraint(_binding_0) => { + GenericArgument::Constraint(f.fold_constraint(_binding_0)) + } + GenericArgument::Const(_binding_0) => GenericArgument::Const(f.fold_expr(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_generic_method_argument<F>( + f: &mut F, + node: GenericMethodArgument, +) -> GenericMethodArgument +where + F: Fold + ?Sized, +{ + match node { + GenericMethodArgument::Type(_binding_0) => { + GenericMethodArgument::Type(f.fold_type(_binding_0)) + } + GenericMethodArgument::Const(_binding_0) => { + GenericMethodArgument::Const(f.fold_expr(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generic_param<F>(f: &mut F, node: GenericParam) -> GenericParam +where + F: Fold + ?Sized, +{ + match node { + GenericParam::Type(_binding_0) => GenericParam::Type(f.fold_type_param(_binding_0)), + GenericParam::Lifetime(_binding_0) => { + GenericParam::Lifetime(f.fold_lifetime_def(_binding_0)) + } + GenericParam::Const(_binding_0) => GenericParam::Const(f.fold_const_param(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generics<F>(f: &mut F, node: Generics) -> Generics +where + F: Fold + ?Sized, +{ + Generics { + lt_token: (node.lt_token).map(|it| Token ! [ < ](tokens_helper(f, &it.spans))), + params: FoldHelper::lift(node.params, |it| f.fold_generic_param(it)), + gt_token: (node.gt_token).map(|it| Token ! [ > ](tokens_helper(f, &it.spans))), + where_clause: (node.where_clause).map(|it| f.fold_where_clause(it)), + } +} +pub fn fold_ident<F>(f: &mut F, node: Ident) -> Ident +where + F: Fold + ?Sized, +{ + let mut node = node; + let span = f.fold_span(node.span()); + node.set_span(span); + node +} +#[cfg(feature = "full")] +pub fn fold_impl_item<F>(f: &mut F, node: ImplItem) -> ImplItem +where + F: Fold + ?Sized, +{ + match node { + ImplItem::Const(_binding_0) => ImplItem::Const(f.fold_impl_item_const(_binding_0)), + ImplItem::Method(_binding_0) => ImplItem::Method(f.fold_impl_item_method(_binding_0)), + ImplItem::Type(_binding_0) => ImplItem::Type(f.fold_impl_item_type(_binding_0)), + ImplItem::Macro(_binding_0) => ImplItem::Macro(f.fold_impl_item_macro(_binding_0)), + ImplItem::Verbatim(_binding_0) => ImplItem::Verbatim(_binding_0), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_const<F>(f: &mut F, node: ImplItemConst) -> ImplItemConst +where + F: Fold + ?Sized, +{ + ImplItemConst { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))), + const_token: Token![const](tokens_helper(f, &node.const_token.span)), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: f.fold_type(node.ty), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + expr: f.fold_expr(node.expr), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_macro<F>(f: &mut F, node: ImplItemMacro) -> ImplItemMacro +where + F: Fold + ?Sized, +{ + ImplItemMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + mac: f.fold_macro(node.mac), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_method<F>(f: &mut F, node: ImplItemMethod) -> ImplItemMethod +where + F: Fold + ?Sized, +{ + ImplItemMethod { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))), + sig: f.fold_signature(node.sig), + block: f.fold_block(node.block), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_type<F>(f: &mut F, node: ImplItemType) -> ImplItemType +where + F: Fold + ?Sized, +{ + ImplItemType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))), + type_token: Token![type](tokens_helper(f, &node.type_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + ty: f.fold_type(node.ty), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_index<F>(f: &mut F, node: Index) -> Index +where + F: Fold + ?Sized, +{ + Index { + index: node.index, + span: f.fold_span(node.span), + } +} +#[cfg(feature = "full")] +pub fn fold_item<F>(f: &mut F, node: Item) -> Item +where + F: Fold + ?Sized, +{ + match node { + Item::Const(_binding_0) => Item::Const(f.fold_item_const(_binding_0)), + Item::Enum(_binding_0) => Item::Enum(f.fold_item_enum(_binding_0)), + Item::ExternCrate(_binding_0) => Item::ExternCrate(f.fold_item_extern_crate(_binding_0)), + Item::Fn(_binding_0) => Item::Fn(f.fold_item_fn(_binding_0)), + Item::ForeignMod(_binding_0) => Item::ForeignMod(f.fold_item_foreign_mod(_binding_0)), + Item::Impl(_binding_0) => Item::Impl(f.fold_item_impl(_binding_0)), + Item::Macro(_binding_0) => Item::Macro(f.fold_item_macro(_binding_0)), + Item::Macro2(_binding_0) => Item::Macro2(f.fold_item_macro2(_binding_0)), + Item::Mod(_binding_0) => Item::Mod(f.fold_item_mod(_binding_0)), + Item::Static(_binding_0) => Item::Static(f.fold_item_static(_binding_0)), + Item::Struct(_binding_0) => Item::Struct(f.fold_item_struct(_binding_0)), + Item::Trait(_binding_0) => Item::Trait(f.fold_item_trait(_binding_0)), + Item::TraitAlias(_binding_0) => Item::TraitAlias(f.fold_item_trait_alias(_binding_0)), + Item::Type(_binding_0) => Item::Type(f.fold_item_type(_binding_0)), + Item::Union(_binding_0) => Item::Union(f.fold_item_union(_binding_0)), + Item::Use(_binding_0) => Item::Use(f.fold_item_use(_binding_0)), + Item::Verbatim(_binding_0) => Item::Verbatim(_binding_0), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_item_const<F>(f: &mut F, node: ItemConst) -> ItemConst +where + F: Fold + ?Sized, +{ + ItemConst { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + const_token: Token![const](tokens_helper(f, &node.const_token.span)), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + expr: Box::new(f.fold_expr(*node.expr)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_enum<F>(f: &mut F, node: ItemEnum) -> ItemEnum +where + F: Fold + ?Sized, +{ + ItemEnum { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + enum_token: Token![enum](tokens_helper(f, &node.enum_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + variants: FoldHelper::lift(node.variants, |it| f.fold_variant(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_extern_crate<F>(f: &mut F, node: ItemExternCrate) -> ItemExternCrate +where + F: Fold + ?Sized, +{ + ItemExternCrate { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + extern_token: Token![extern](tokens_helper(f, &node.extern_token.span)), + crate_token: Token![crate](tokens_helper(f, &node.crate_token.span)), + ident: f.fold_ident(node.ident), + rename: (node.rename).map(|it| { + ( + Token![as](tokens_helper(f, &(it).0.span)), + f.fold_ident((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_fn<F>(f: &mut F, node: ItemFn) -> ItemFn +where + F: Fold + ?Sized, +{ + ItemFn { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + sig: f.fold_signature(node.sig), + block: Box::new(f.fold_block(*node.block)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_foreign_mod<F>(f: &mut F, node: ItemForeignMod) -> ItemForeignMod +where + F: Fold + ?Sized, +{ + ItemForeignMod { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + abi: f.fold_abi(node.abi), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + items: FoldHelper::lift(node.items, |it| f.fold_foreign_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_impl<F>(f: &mut F, node: ItemImpl) -> ItemImpl +where + F: Fold + ?Sized, +{ + ItemImpl { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))), + unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))), + impl_token: Token![impl](tokens_helper(f, &node.impl_token.span)), + generics: f.fold_generics(node.generics), + trait_: (node.trait_).map(|it| { + ( + ((it).0).map(|it| Token![!](tokens_helper(f, &it.spans))), + f.fold_path((it).1), + Token![for](tokens_helper(f, &(it).2.span)), + ) + }), + self_ty: Box::new(f.fold_type(*node.self_ty)), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + items: FoldHelper::lift(node.items, |it| f.fold_impl_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_macro<F>(f: &mut F, node: ItemMacro) -> ItemMacro +where + F: Fold + ?Sized, +{ + ItemMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + ident: (node.ident).map(|it| f.fold_ident(it)), + mac: f.fold_macro(node.mac), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_macro2<F>(f: &mut F, node: ItemMacro2) -> ItemMacro2 +where + F: Fold + ?Sized, +{ + ItemMacro2 { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + macro_token: Token![macro](tokens_helper(f, &node.macro_token.span)), + ident: f.fold_ident(node.ident), + rules: node.rules, + } +} +#[cfg(feature = "full")] +pub fn fold_item_mod<F>(f: &mut F, node: ItemMod) -> ItemMod +where + F: Fold + ?Sized, +{ + ItemMod { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + mod_token: Token![mod](tokens_helper(f, &node.mod_token.span)), + ident: f.fold_ident(node.ident), + content: (node.content).map(|it| { + ( + Brace(tokens_helper(f, &(it).0.span)), + FoldHelper::lift((it).1, |it| f.fold_item(it)), + ) + }), + semi: (node.semi).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_static<F>(f: &mut F, node: ItemStatic) -> ItemStatic +where + F: Fold + ?Sized, +{ + ItemStatic { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + static_token: Token![static](tokens_helper(f, &node.static_token.span)), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + expr: Box::new(f.fold_expr(*node.expr)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_struct<F>(f: &mut F, node: ItemStruct) -> ItemStruct +where + F: Fold + ?Sized, +{ + ItemStruct { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + struct_token: Token![struct](tokens_helper(f, &node.struct_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + fields: f.fold_fields(node.fields), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_trait<F>(f: &mut F, node: ItemTrait) -> ItemTrait +where + F: Fold + ?Sized, +{ + ItemTrait { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))), + auto_token: (node.auto_token).map(|it| Token![auto](tokens_helper(f, &it.span))), + trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + supertraits: FoldHelper::lift(node.supertraits, |it| f.fold_type_param_bound(it)), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + items: FoldHelper::lift(node.items, |it| f.fold_trait_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_trait_alias<F>(f: &mut F, node: ItemTraitAlias) -> ItemTraitAlias +where + F: Fold + ?Sized, +{ + ItemTraitAlias { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_type<F>(f: &mut F, node: ItemType) -> ItemType +where + F: Fold + ?Sized, +{ + ItemType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + type_token: Token![type](tokens_helper(f, &node.type_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_union<F>(f: &mut F, node: ItemUnion) -> ItemUnion +where + F: Fold + ?Sized, +{ + ItemUnion { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + union_token: Token![union](tokens_helper(f, &node.union_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + fields: f.fold_fields_named(node.fields), + } +} +#[cfg(feature = "full")] +pub fn fold_item_use<F>(f: &mut F, node: ItemUse) -> ItemUse +where + F: Fold + ?Sized, +{ + ItemUse { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + vis: f.fold_visibility(node.vis), + use_token: Token![use](tokens_helper(f, &node.use_token.span)), + leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), + tree: f.fold_use_tree(node.tree), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_label<F>(f: &mut F, node: Label) -> Label +where + F: Fold + ?Sized, +{ + Label { + name: f.fold_lifetime(node.name), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + } +} +pub fn fold_lifetime<F>(f: &mut F, node: Lifetime) -> Lifetime +where + F: Fold + ?Sized, +{ + Lifetime { + apostrophe: f.fold_span(node.apostrophe), + ident: f.fold_ident(node.ident), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lifetime_def<F>(f: &mut F, node: LifetimeDef) -> LifetimeDef +where + F: Fold + ?Sized, +{ + LifetimeDef { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + lifetime: f.fold_lifetime(node.lifetime), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit<F>(f: &mut F, node: Lit) -> Lit +where + F: Fold + ?Sized, +{ + match node { + Lit::Str(_binding_0) => Lit::Str(f.fold_lit_str(_binding_0)), + Lit::ByteStr(_binding_0) => Lit::ByteStr(f.fold_lit_byte_str(_binding_0)), + Lit::Byte(_binding_0) => Lit::Byte(f.fold_lit_byte(_binding_0)), + Lit::Char(_binding_0) => Lit::Char(f.fold_lit_char(_binding_0)), + Lit::Int(_binding_0) => Lit::Int(f.fold_lit_int(_binding_0)), + Lit::Float(_binding_0) => Lit::Float(f.fold_lit_float(_binding_0)), + Lit::Bool(_binding_0) => Lit::Bool(f.fold_lit_bool(_binding_0)), + Lit::Verbatim(_binding_0) => Lit::Verbatim(_binding_0), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_bool<F>(f: &mut F, node: LitBool) -> LitBool +where + F: Fold + ?Sized, +{ + LitBool { + value: node.value, + span: f.fold_span(node.span), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_byte<F>(f: &mut F, node: LitByte) -> LitByte +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_byte_str<F>(f: &mut F, node: LitByteStr) -> LitByteStr +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_char<F>(f: &mut F, node: LitChar) -> LitChar +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_float<F>(f: &mut F, node: LitFloat) -> LitFloat +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_int<F>(f: &mut F, node: LitInt) -> LitInt +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_str<F>(f: &mut F, node: LitStr) -> LitStr +where + F: Fold + ?Sized, +{ + let span = f.fold_span(node.span()); + let mut node = node; + node.set_span(span); + node +} +#[cfg(feature = "full")] +pub fn fold_local<F>(f: &mut F, node: Local) -> Local +where + F: Fold + ?Sized, +{ + Local { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + let_token: Token![let](tokens_helper(f, &node.let_token.span)), + pat: f.fold_pat(node.pat), + init: (node.init).map(|it| { + ( + Token ! [ = ](tokens_helper(f, &(it).0.spans)), + Box::new(f.fold_expr(*(it).1)), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_macro<F>(f: &mut F, node: Macro) -> Macro +where + F: Fold + ?Sized, +{ + Macro { + path: f.fold_path(node.path), + bang_token: Token![!](tokens_helper(f, &node.bang_token.spans)), + delimiter: f.fold_macro_delimiter(node.delimiter), + tokens: node.tokens, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_macro_delimiter<F>(f: &mut F, node: MacroDelimiter) -> MacroDelimiter +where + F: Fold + ?Sized, +{ + match node { + MacroDelimiter::Paren(_binding_0) => { + MacroDelimiter::Paren(Paren(tokens_helper(f, &_binding_0.span))) + } + MacroDelimiter::Brace(_binding_0) => { + MacroDelimiter::Brace(Brace(tokens_helper(f, &_binding_0.span))) + } + MacroDelimiter::Bracket(_binding_0) => { + MacroDelimiter::Bracket(Bracket(tokens_helper(f, &_binding_0.span))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_member<F>(f: &mut F, node: Member) -> Member +where + F: Fold + ?Sized, +{ + match node { + Member::Named(_binding_0) => Member::Named(f.fold_ident(_binding_0)), + Member::Unnamed(_binding_0) => Member::Unnamed(f.fold_index(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta<F>(f: &mut F, node: Meta) -> Meta +where + F: Fold + ?Sized, +{ + match node { + Meta::Path(_binding_0) => Meta::Path(f.fold_path(_binding_0)), + Meta::List(_binding_0) => Meta::List(f.fold_meta_list(_binding_0)), + Meta::NameValue(_binding_0) => Meta::NameValue(f.fold_meta_name_value(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta_list<F>(f: &mut F, node: MetaList) -> MetaList +where + F: Fold + ?Sized, +{ + MetaList { + path: f.fold_path(node.path), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + nested: FoldHelper::lift(node.nested, |it| f.fold_nested_meta(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta_name_value<F>(f: &mut F, node: MetaNameValue) -> MetaNameValue +where + F: Fold + ?Sized, +{ + MetaNameValue { + path: f.fold_path(node.path), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + lit: f.fold_lit(node.lit), + } +} +#[cfg(feature = "full")] +pub fn fold_method_turbofish<F>(f: &mut F, node: MethodTurbofish) -> MethodTurbofish +where + F: Fold + ?Sized, +{ + MethodTurbofish { + colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)), + lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + args: FoldHelper::lift(node.args, |it| f.fold_generic_method_argument(it)), + gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_nested_meta<F>(f: &mut F, node: NestedMeta) -> NestedMeta +where + F: Fold + ?Sized, +{ + match node { + NestedMeta::Meta(_binding_0) => NestedMeta::Meta(f.fold_meta(_binding_0)), + NestedMeta::Lit(_binding_0) => NestedMeta::Lit(f.fold_lit(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_parenthesized_generic_arguments<F>( + f: &mut F, + node: ParenthesizedGenericArguments, +) -> ParenthesizedGenericArguments +where + F: Fold + ?Sized, +{ + ParenthesizedGenericArguments { + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + inputs: FoldHelper::lift(node.inputs, |it| f.fold_type(it)), + output: f.fold_return_type(node.output), + } +} +#[cfg(feature = "full")] +pub fn fold_pat<F>(f: &mut F, node: Pat) -> Pat +where + F: Fold + ?Sized, +{ + match node { + Pat::Box(_binding_0) => Pat::Box(f.fold_pat_box(_binding_0)), + Pat::Ident(_binding_0) => Pat::Ident(f.fold_pat_ident(_binding_0)), + Pat::Lit(_binding_0) => Pat::Lit(f.fold_pat_lit(_binding_0)), + Pat::Macro(_binding_0) => Pat::Macro(f.fold_pat_macro(_binding_0)), + Pat::Or(_binding_0) => Pat::Or(f.fold_pat_or(_binding_0)), + Pat::Path(_binding_0) => Pat::Path(f.fold_pat_path(_binding_0)), + Pat::Range(_binding_0) => Pat::Range(f.fold_pat_range(_binding_0)), + Pat::Reference(_binding_0) => Pat::Reference(f.fold_pat_reference(_binding_0)), + Pat::Rest(_binding_0) => Pat::Rest(f.fold_pat_rest(_binding_0)), + Pat::Slice(_binding_0) => Pat::Slice(f.fold_pat_slice(_binding_0)), + Pat::Struct(_binding_0) => Pat::Struct(f.fold_pat_struct(_binding_0)), + Pat::Tuple(_binding_0) => Pat::Tuple(f.fold_pat_tuple(_binding_0)), + Pat::TupleStruct(_binding_0) => Pat::TupleStruct(f.fold_pat_tuple_struct(_binding_0)), + Pat::Type(_binding_0) => Pat::Type(f.fold_pat_type(_binding_0)), + Pat::Verbatim(_binding_0) => Pat::Verbatim(_binding_0), + Pat::Wild(_binding_0) => Pat::Wild(f.fold_pat_wild(_binding_0)), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_box<F>(f: &mut F, node: PatBox) -> PatBox +where + F: Fold + ?Sized, +{ + PatBox { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + box_token: Token![box](tokens_helper(f, &node.box_token.span)), + pat: Box::new(f.fold_pat(*node.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_ident<F>(f: &mut F, node: PatIdent) -> PatIdent +where + F: Fold + ?Sized, +{ + PatIdent { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + by_ref: (node.by_ref).map(|it| Token![ref](tokens_helper(f, &it.span))), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + ident: f.fold_ident(node.ident), + subpat: (node.subpat).map(|it| { + ( + Token ! [ @ ](tokens_helper(f, &(it).0.spans)), + Box::new(f.fold_pat(*(it).1)), + ) + }), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_lit<F>(f: &mut F, node: PatLit) -> PatLit +where + F: Fold + ?Sized, +{ + PatLit { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + expr: Box::new(f.fold_expr(*node.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_macro<F>(f: &mut F, node: PatMacro) -> PatMacro +where + F: Fold + ?Sized, +{ + PatMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + mac: f.fold_macro(node.mac), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_or<F>(f: &mut F, node: PatOr) -> PatOr +where + F: Fold + ?Sized, +{ + PatOr { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + leading_vert: (node.leading_vert).map(|it| Token ! [ | ](tokens_helper(f, &it.spans))), + cases: FoldHelper::lift(node.cases, |it| f.fold_pat(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_path<F>(f: &mut F, node: PatPath) -> PatPath +where + F: Fold + ?Sized, +{ + PatPath { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + qself: (node.qself).map(|it| f.fold_qself(it)), + path: f.fold_path(node.path), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_range<F>(f: &mut F, node: PatRange) -> PatRange +where + F: Fold + ?Sized, +{ + PatRange { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + lo: Box::new(f.fold_expr(*node.lo)), + limits: f.fold_range_limits(node.limits), + hi: Box::new(f.fold_expr(*node.hi)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_reference<F>(f: &mut F, node: PatReference) -> PatReference +where + F: Fold + ?Sized, +{ + PatReference { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + pat: Box::new(f.fold_pat(*node.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_rest<F>(f: &mut F, node: PatRest) -> PatRest +where + F: Fold + ?Sized, +{ + PatRest { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + dot2_token: Token![..](tokens_helper(f, &node.dot2_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_slice<F>(f: &mut F, node: PatSlice) -> PatSlice +where + F: Fold + ?Sized, +{ + PatSlice { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + elems: FoldHelper::lift(node.elems, |it| f.fold_pat(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_struct<F>(f: &mut F, node: PatStruct) -> PatStruct +where + F: Fold + ?Sized, +{ + PatStruct { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + path: f.fold_path(node.path), + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + fields: FoldHelper::lift(node.fields, |it| f.fold_field_pat(it)), + dot2_token: (node.dot2_token).map(|it| Token![..](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_tuple<F>(f: &mut F, node: PatTuple) -> PatTuple +where + F: Fold + ?Sized, +{ + PatTuple { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + elems: FoldHelper::lift(node.elems, |it| f.fold_pat(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_tuple_struct<F>(f: &mut F, node: PatTupleStruct) -> PatTupleStruct +where + F: Fold + ?Sized, +{ + PatTupleStruct { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + path: f.fold_path(node.path), + pat: f.fold_pat_tuple(node.pat), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_type<F>(f: &mut F, node: PatType) -> PatType +where + F: Fold + ?Sized, +{ + PatType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + pat: Box::new(f.fold_pat(*node.pat)), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_wild<F>(f: &mut F, node: PatWild) -> PatWild +where + F: Fold + ?Sized, +{ + PatWild { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + underscore_token: Token![_](tokens_helper(f, &node.underscore_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path<F>(f: &mut F, node: Path) -> Path +where + F: Fold + ?Sized, +{ + Path { + leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), + segments: FoldHelper::lift(node.segments, |it| f.fold_path_segment(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path_arguments<F>(f: &mut F, node: PathArguments) -> PathArguments +where + F: Fold + ?Sized, +{ + match node { + PathArguments::None => PathArguments::None, + PathArguments::AngleBracketed(_binding_0) => { + PathArguments::AngleBracketed(f.fold_angle_bracketed_generic_arguments(_binding_0)) + } + PathArguments::Parenthesized(_binding_0) => { + PathArguments::Parenthesized(f.fold_parenthesized_generic_arguments(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path_segment<F>(f: &mut F, node: PathSegment) -> PathSegment +where + F: Fold + ?Sized, +{ + PathSegment { + ident: f.fold_ident(node.ident), + arguments: f.fold_path_arguments(node.arguments), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_eq<F>(f: &mut F, node: PredicateEq) -> PredicateEq +where + F: Fold + ?Sized, +{ + PredicateEq { + lhs_ty: f.fold_type(node.lhs_ty), + eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + rhs_ty: f.fold_type(node.rhs_ty), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_lifetime<F>(f: &mut F, node: PredicateLifetime) -> PredicateLifetime +where + F: Fold + ?Sized, +{ + PredicateLifetime { + lifetime: f.fold_lifetime(node.lifetime), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_type<F>(f: &mut F, node: PredicateType) -> PredicateType +where + F: Fold + ?Sized, +{ + PredicateType { + lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), + bounded_ty: f.fold_type(node.bounded_ty), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_qself<F>(f: &mut F, node: QSelf) -> QSelf +where + F: Fold + ?Sized, +{ + QSelf { + lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + ty: Box::new(f.fold_type(*node.ty)), + position: node.position, + as_token: (node.as_token).map(|it| Token![as](tokens_helper(f, &it.span))), + gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_range_limits<F>(f: &mut F, node: RangeLimits) -> RangeLimits +where + F: Fold + ?Sized, +{ + match node { + RangeLimits::HalfOpen(_binding_0) => { + RangeLimits::HalfOpen(Token![..](tokens_helper(f, &_binding_0.spans))) + } + RangeLimits::Closed(_binding_0) => { + RangeLimits::Closed(Token ! [ ..= ](tokens_helper(f, &_binding_0.spans))) + } + } +} +#[cfg(feature = "full")] +pub fn fold_receiver<F>(f: &mut F, node: Receiver) -> Receiver +where + F: Fold + ?Sized, +{ + Receiver { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + reference: (node.reference).map(|it| { + ( + Token ! [ & ](tokens_helper(f, &(it).0.spans)), + ((it).1).map(|it| f.fold_lifetime(it)), + ) + }), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + self_token: Token![self](tokens_helper(f, &node.self_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_return_type<F>(f: &mut F, node: ReturnType) -> ReturnType +where + F: Fold + ?Sized, +{ + match node { + ReturnType::Default => ReturnType::Default, + ReturnType::Type(_binding_0, _binding_1) => ReturnType::Type( + Token ! [ -> ](tokens_helper(f, &_binding_0.spans)), + Box::new(f.fold_type(*_binding_1)), + ), + } +} +#[cfg(feature = "full")] +pub fn fold_signature<F>(f: &mut F, node: Signature) -> Signature +where + F: Fold + ?Sized, +{ + Signature { + constness: (node.constness).map(|it| Token![const](tokens_helper(f, &it.span))), + asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))), + unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))), + abi: (node.abi).map(|it| f.fold_abi(it)), + fn_token: Token![fn](tokens_helper(f, &node.fn_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + inputs: FoldHelper::lift(node.inputs, |it| f.fold_fn_arg(it)), + variadic: (node.variadic).map(|it| f.fold_variadic(it)), + output: f.fold_return_type(node.output), + } +} +pub fn fold_span<F>(f: &mut F, node: Span) -> Span +where + F: Fold + ?Sized, +{ + node +} +#[cfg(feature = "full")] +pub fn fold_stmt<F>(f: &mut F, node: Stmt) -> Stmt +where + F: Fold + ?Sized, +{ + match node { + Stmt::Local(_binding_0) => Stmt::Local(f.fold_local(_binding_0)), + Stmt::Item(_binding_0) => Stmt::Item(f.fold_item(_binding_0)), + Stmt::Expr(_binding_0) => Stmt::Expr(f.fold_expr(_binding_0)), + Stmt::Semi(_binding_0, _binding_1) => Stmt::Semi( + f.fold_expr(_binding_0), + Token ! [ ; ](tokens_helper(f, &_binding_1.spans)), + ), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_trait_bound<F>(f: &mut F, node: TraitBound) -> TraitBound +where + F: Fold + ?Sized, +{ + TraitBound { + paren_token: (node.paren_token).map(|it| Paren(tokens_helper(f, &it.span))), + modifier: f.fold_trait_bound_modifier(node.modifier), + lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), + path: f.fold_path(node.path), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_trait_bound_modifier<F>(f: &mut F, node: TraitBoundModifier) -> TraitBoundModifier +where + F: Fold + ?Sized, +{ + match node { + TraitBoundModifier::None => TraitBoundModifier::None, + TraitBoundModifier::Maybe(_binding_0) => { + TraitBoundModifier::Maybe(Token ! [ ? ](tokens_helper(f, &_binding_0.spans))) + } + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item<F>(f: &mut F, node: TraitItem) -> TraitItem +where + F: Fold + ?Sized, +{ + match node { + TraitItem::Const(_binding_0) => TraitItem::Const(f.fold_trait_item_const(_binding_0)), + TraitItem::Method(_binding_0) => TraitItem::Method(f.fold_trait_item_method(_binding_0)), + TraitItem::Type(_binding_0) => TraitItem::Type(f.fold_trait_item_type(_binding_0)), + TraitItem::Macro(_binding_0) => TraitItem::Macro(f.fold_trait_item_macro(_binding_0)), + TraitItem::Verbatim(_binding_0) => TraitItem::Verbatim(_binding_0), + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_const<F>(f: &mut F, node: TraitItemConst) -> TraitItemConst +where + F: Fold + ?Sized, +{ + TraitItemConst { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + const_token: Token![const](tokens_helper(f, &node.const_token.span)), + ident: f.fold_ident(node.ident), + colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + ty: f.fold_type(node.ty), + default: (node.default).map(|it| { + ( + Token ! [ = ](tokens_helper(f, &(it).0.spans)), + f.fold_expr((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_macro<F>(f: &mut F, node: TraitItemMacro) -> TraitItemMacro +where + F: Fold + ?Sized, +{ + TraitItemMacro { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + mac: f.fold_macro(node.mac), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_method<F>(f: &mut F, node: TraitItemMethod) -> TraitItemMethod +where + F: Fold + ?Sized, +{ + TraitItemMethod { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + sig: f.fold_signature(node.sig), + default: (node.default).map(|it| f.fold_block(it)), + semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_type<F>(f: &mut F, node: TraitItemType) -> TraitItemType +where + F: Fold + ?Sized, +{ + TraitItemType { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + type_token: Token![type](tokens_helper(f, &node.type_token.span)), + ident: f.fold_ident(node.ident), + generics: f.fold_generics(node.generics), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + default: (node.default).map(|it| { + ( + Token ! [ = ](tokens_helper(f, &(it).0.spans)), + f.fold_type((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type<F>(f: &mut F, node: Type) -> Type +where + F: Fold + ?Sized, +{ + match node { + Type::Array(_binding_0) => Type::Array(f.fold_type_array(_binding_0)), + Type::BareFn(_binding_0) => Type::BareFn(f.fold_type_bare_fn(_binding_0)), + Type::Group(_binding_0) => Type::Group(f.fold_type_group(_binding_0)), + Type::ImplTrait(_binding_0) => Type::ImplTrait(f.fold_type_impl_trait(_binding_0)), + Type::Infer(_binding_0) => Type::Infer(f.fold_type_infer(_binding_0)), + Type::Macro(_binding_0) => Type::Macro(f.fold_type_macro(_binding_0)), + Type::Never(_binding_0) => Type::Never(f.fold_type_never(_binding_0)), + Type::Paren(_binding_0) => Type::Paren(f.fold_type_paren(_binding_0)), + Type::Path(_binding_0) => Type::Path(f.fold_type_path(_binding_0)), + Type::Ptr(_binding_0) => Type::Ptr(f.fold_type_ptr(_binding_0)), + Type::Reference(_binding_0) => Type::Reference(f.fold_type_reference(_binding_0)), + Type::Slice(_binding_0) => Type::Slice(f.fold_type_slice(_binding_0)), + Type::TraitObject(_binding_0) => Type::TraitObject(f.fold_type_trait_object(_binding_0)), + Type::Tuple(_binding_0) => Type::Tuple(f.fold_type_tuple(_binding_0)), + Type::Verbatim(_binding_0) => Type::Verbatim(_binding_0), + _ => unreachable!(), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_array<F>(f: &mut F, node: TypeArray) -> TypeArray +where + F: Fold + ?Sized, +{ + TypeArray { + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + elem: Box::new(f.fold_type(*node.elem)), + semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + len: f.fold_expr(node.len), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_bare_fn<F>(f: &mut F, node: TypeBareFn) -> TypeBareFn +where + F: Fold + ?Sized, +{ + TypeBareFn { + lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), + unsafety: (node.unsafety).map(|it| Token![unsafe](tokens_helper(f, &it.span))), + abi: (node.abi).map(|it| f.fold_abi(it)), + fn_token: Token![fn](tokens_helper(f, &node.fn_token.span)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + inputs: FoldHelper::lift(node.inputs, |it| f.fold_bare_fn_arg(it)), + variadic: (node.variadic).map(|it| f.fold_variadic(it)), + output: f.fold_return_type(node.output), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_group<F>(f: &mut F, node: TypeGroup) -> TypeGroup +where + F: Fold + ?Sized, +{ + TypeGroup { + group_token: Group(tokens_helper(f, &node.group_token.span)), + elem: Box::new(f.fold_type(*node.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_impl_trait<F>(f: &mut F, node: TypeImplTrait) -> TypeImplTrait +where + F: Fold + ?Sized, +{ + TypeImplTrait { + impl_token: Token![impl](tokens_helper(f, &node.impl_token.span)), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_infer<F>(f: &mut F, node: TypeInfer) -> TypeInfer +where + F: Fold + ?Sized, +{ + TypeInfer { + underscore_token: Token![_](tokens_helper(f, &node.underscore_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_macro<F>(f: &mut F, node: TypeMacro) -> TypeMacro +where + F: Fold + ?Sized, +{ + TypeMacro { + mac: f.fold_macro(node.mac), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_never<F>(f: &mut F, node: TypeNever) -> TypeNever +where + F: Fold + ?Sized, +{ + TypeNever { + bang_token: Token![!](tokens_helper(f, &node.bang_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_param<F>(f: &mut F, node: TypeParam) -> TypeParam +where + F: Fold + ?Sized, +{ + TypeParam { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + ident: f.fold_ident(node.ident), + colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))), + default: (node.default).map(|it| f.fold_type(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_param_bound<F>(f: &mut F, node: TypeParamBound) -> TypeParamBound +where + F: Fold + ?Sized, +{ + match node { + TypeParamBound::Trait(_binding_0) => TypeParamBound::Trait(f.fold_trait_bound(_binding_0)), + TypeParamBound::Lifetime(_binding_0) => { + TypeParamBound::Lifetime(f.fold_lifetime(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_paren<F>(f: &mut F, node: TypeParen) -> TypeParen +where + F: Fold + ?Sized, +{ + TypeParen { + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + elem: Box::new(f.fold_type(*node.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_path<F>(f: &mut F, node: TypePath) -> TypePath +where + F: Fold + ?Sized, +{ + TypePath { + qself: (node.qself).map(|it| f.fold_qself(it)), + path: f.fold_path(node.path), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_ptr<F>(f: &mut F, node: TypePtr) -> TypePtr +where + F: Fold + ?Sized, +{ + TypePtr { + star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)), + const_token: (node.const_token).map(|it| Token![const](tokens_helper(f, &it.span))), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + elem: Box::new(f.fold_type(*node.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_reference<F>(f: &mut F, node: TypeReference) -> TypeReference +where + F: Fold + ?Sized, +{ + TypeReference { + and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + lifetime: (node.lifetime).map(|it| f.fold_lifetime(it)), + mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), + elem: Box::new(f.fold_type(*node.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_slice<F>(f: &mut F, node: TypeSlice) -> TypeSlice +where + F: Fold + ?Sized, +{ + TypeSlice { + bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), + elem: Box::new(f.fold_type(*node.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_trait_object<F>(f: &mut F, node: TypeTraitObject) -> TypeTraitObject +where + F: Fold + ?Sized, +{ + TypeTraitObject { + dyn_token: (node.dyn_token).map(|it| Token![dyn](tokens_helper(f, &it.span))), + bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_tuple<F>(f: &mut F, node: TypeTuple) -> TypeTuple +where + F: Fold + ?Sized, +{ + TypeTuple { + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + elems: FoldHelper::lift(node.elems, |it| f.fold_type(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_un_op<F>(f: &mut F, node: UnOp) -> UnOp +where + F: Fold + ?Sized, +{ + match node { + UnOp::Deref(_binding_0) => UnOp::Deref(Token ! [ * ](tokens_helper(f, &_binding_0.spans))), + UnOp::Not(_binding_0) => UnOp::Not(Token![!](tokens_helper(f, &_binding_0.spans))), + UnOp::Neg(_binding_0) => UnOp::Neg(Token ! [ - ](tokens_helper(f, &_binding_0.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_use_glob<F>(f: &mut F, node: UseGlob) -> UseGlob +where + F: Fold + ?Sized, +{ + UseGlob { + star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_group<F>(f: &mut F, node: UseGroup) -> UseGroup +where + F: Fold + ?Sized, +{ + UseGroup { + brace_token: Brace(tokens_helper(f, &node.brace_token.span)), + items: FoldHelper::lift(node.items, |it| f.fold_use_tree(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_name<F>(f: &mut F, node: UseName) -> UseName +where + F: Fold + ?Sized, +{ + UseName { + ident: f.fold_ident(node.ident), + } +} +#[cfg(feature = "full")] +pub fn fold_use_path<F>(f: &mut F, node: UsePath) -> UsePath +where + F: Fold + ?Sized, +{ + UsePath { + ident: f.fold_ident(node.ident), + colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)), + tree: Box::new(f.fold_use_tree(*node.tree)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_rename<F>(f: &mut F, node: UseRename) -> UseRename +where + F: Fold + ?Sized, +{ + UseRename { + ident: f.fold_ident(node.ident), + as_token: Token![as](tokens_helper(f, &node.as_token.span)), + rename: f.fold_ident(node.rename), + } +} +#[cfg(feature = "full")] +pub fn fold_use_tree<F>(f: &mut F, node: UseTree) -> UseTree +where + F: Fold + ?Sized, +{ + match node { + UseTree::Path(_binding_0) => UseTree::Path(f.fold_use_path(_binding_0)), + UseTree::Name(_binding_0) => UseTree::Name(f.fold_use_name(_binding_0)), + UseTree::Rename(_binding_0) => UseTree::Rename(f.fold_use_rename(_binding_0)), + UseTree::Glob(_binding_0) => UseTree::Glob(f.fold_use_glob(_binding_0)), + UseTree::Group(_binding_0) => UseTree::Group(f.fold_use_group(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_variadic<F>(f: &mut F, node: Variadic) -> Variadic +where + F: Fold + ?Sized, +{ + Variadic { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + dots: Token ! [ ... ](tokens_helper(f, &node.dots.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_variant<F>(f: &mut F, node: Variant) -> Variant +where + F: Fold + ?Sized, +{ + Variant { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + ident: f.fold_ident(node.ident), + fields: f.fold_fields(node.fields), + discriminant: (node.discriminant).map(|it| { + ( + Token ! [ = ](tokens_helper(f, &(it).0.spans)), + f.fold_expr((it).1), + ) + }), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_crate<F>(f: &mut F, node: VisCrate) -> VisCrate +where + F: Fold + ?Sized, +{ + VisCrate { + crate_token: Token![crate](tokens_helper(f, &node.crate_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_public<F>(f: &mut F, node: VisPublic) -> VisPublic +where + F: Fold + ?Sized, +{ + VisPublic { + pub_token: Token![pub](tokens_helper(f, &node.pub_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_restricted<F>(f: &mut F, node: VisRestricted) -> VisRestricted +where + F: Fold + ?Sized, +{ + VisRestricted { + pub_token: Token![pub](tokens_helper(f, &node.pub_token.span)), + paren_token: Paren(tokens_helper(f, &node.paren_token.span)), + in_token: (node.in_token).map(|it| Token![in](tokens_helper(f, &it.span))), + path: Box::new(f.fold_path(*node.path)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_visibility<F>(f: &mut F, node: Visibility) -> Visibility +where + F: Fold + ?Sized, +{ + match node { + Visibility::Public(_binding_0) => Visibility::Public(f.fold_vis_public(_binding_0)), + Visibility::Crate(_binding_0) => Visibility::Crate(f.fold_vis_crate(_binding_0)), + Visibility::Restricted(_binding_0) => { + Visibility::Restricted(f.fold_vis_restricted(_binding_0)) + } + Visibility::Inherited => Visibility::Inherited, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_where_clause<F>(f: &mut F, node: WhereClause) -> WhereClause +where + F: Fold + ?Sized, +{ + WhereClause { + where_token: Token![where](tokens_helper(f, &node.where_token.span)), + predicates: FoldHelper::lift(node.predicates, |it| f.fold_where_predicate(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_where_predicate<F>(f: &mut F, node: WherePredicate) -> WherePredicate +where + F: Fold + ?Sized, +{ + match node { + WherePredicate::Type(_binding_0) => WherePredicate::Type(f.fold_predicate_type(_binding_0)), + WherePredicate::Lifetime(_binding_0) => { + WherePredicate::Lifetime(f.fold_predicate_lifetime(_binding_0)) + } + WherePredicate::Eq(_binding_0) => WherePredicate::Eq(f.fold_predicate_eq(_binding_0)), + } +} diff --git a/syn/src/gen/visit.rs b/syn/src/gen/visit.rs new file mode 100644 index 0000000..b667f53 --- /dev/null +++ b/syn/src/gen/visit.rs @@ -0,0 +1,3792 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#![allow(unused_variables)] +#[cfg(any(feature = "full", feature = "derive"))] +use crate::gen::helper::visit::*; +#[cfg(any(feature = "full", feature = "derive"))] +use crate::punctuated::Punctuated; +use crate::*; +use proc_macro2::Span; +#[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)*) => {}; +} +/// Syntax tree traversal to walk a shared borrow of a syntax tree. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: self +/// +/// *This trait is available if Syn is built with the `"visit"` feature.* +pub trait Visit<'ast> { + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_abi(&mut self, i: &'ast Abi) { + visit_abi(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_angle_bracketed_generic_arguments(&mut self, i: &'ast AngleBracketedGenericArguments) { + visit_angle_bracketed_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn visit_arm(&mut self, i: &'ast Arm) { + visit_arm(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attr_style(&mut self, i: &'ast AttrStyle) { + visit_attr_style(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attribute(&mut self, i: &'ast Attribute) { + visit_attribute(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg(&mut self, i: &'ast BareFnArg) { + visit_bare_fn_arg(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bin_op(&mut self, i: &'ast BinOp) { + visit_bin_op(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_binding(&mut self, i: &'ast Binding) { + visit_binding(self, i) + } + #[cfg(feature = "full")] + fn visit_block(&mut self, i: &'ast Block) { + visit_block(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bound_lifetimes(&mut self, i: &'ast BoundLifetimes) { + visit_bound_lifetimes(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_const_param(&mut self, i: &'ast ConstParam) { + visit_const_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_constraint(&mut self, i: &'ast Constraint) { + visit_constraint(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 = "derive", feature = "full"))] + fn visit_expr(&mut self, i: &'ast Expr) { + visit_expr(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_array(&mut self, i: &'ast ExprArray) { + visit_expr_array(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign(&mut self, i: &'ast ExprAssign) { + visit_expr_assign(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_op(&mut self, i: &'ast ExprAssignOp) { + visit_expr_assign_op(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_async(&mut self, i: &'ast ExprAsync) { + visit_expr_async(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_await(&mut self, i: &'ast ExprAwait) { + visit_expr_await(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_binary(&mut self, i: &'ast ExprBinary) { + visit_expr_binary(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_block(&mut self, i: &'ast ExprBlock) { + visit_expr_block(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_box(&mut self, i: &'ast ExprBox) { + visit_expr_box(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_break(&mut self, i: &'ast ExprBreak) { + visit_expr_break(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_call(&mut self, i: &'ast ExprCall) { + visit_expr_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_cast(&mut self, i: &'ast ExprCast) { + visit_expr_cast(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_closure(&mut self, i: &'ast ExprClosure) { + visit_expr_closure(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_continue(&mut self, i: &'ast ExprContinue) { + visit_expr_continue(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_field(&mut self, i: &'ast ExprField) { + visit_expr_field(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_for_loop(&mut self, i: &'ast ExprForLoop) { + visit_expr_for_loop(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_group(&mut self, i: &'ast ExprGroup) { + visit_expr_group(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_if(&mut self, i: &'ast ExprIf) { + visit_expr_if(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_index(&mut self, i: &'ast ExprIndex) { + visit_expr_index(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_let(&mut self, i: &'ast ExprLet) { + visit_expr_let(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_lit(&mut self, i: &'ast ExprLit) { + visit_expr_lit(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_loop(&mut self, i: &'ast ExprLoop) { + visit_expr_loop(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_macro(&mut self, i: &'ast ExprMacro) { + visit_expr_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_match(&mut self, i: &'ast ExprMatch) { + visit_expr_match(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) { + visit_expr_method_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_paren(&mut self, i: &'ast ExprParen) { + visit_expr_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_path(&mut self, i: &'ast ExprPath) { + visit_expr_path(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_range(&mut self, i: &'ast ExprRange) { + visit_expr_range(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_reference(&mut self, i: &'ast ExprReference) { + visit_expr_reference(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_repeat(&mut self, i: &'ast ExprRepeat) { + visit_expr_repeat(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_return(&mut self, i: &'ast ExprReturn) { + visit_expr_return(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_struct(&mut self, i: &'ast ExprStruct) { + visit_expr_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try(&mut self, i: &'ast ExprTry) { + visit_expr_try(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_block(&mut self, i: &'ast ExprTryBlock) { + visit_expr_try_block(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_tuple(&mut self, i: &'ast ExprTuple) { + visit_expr_tuple(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_type(&mut self, i: &'ast ExprType) { + visit_expr_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_unary(&mut self, i: &'ast ExprUnary) { + visit_expr_unary(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_unsafe(&mut self, i: &'ast ExprUnsafe) { + visit_expr_unsafe(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_while(&mut self, i: &'ast ExprWhile) { + visit_expr_while(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_yield(&mut self, i: &'ast ExprYield) { + visit_expr_yield(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_field(&mut self, i: &'ast Field) { + visit_field(self, i) + } + #[cfg(feature = "full")] + fn visit_field_pat(&mut self, i: &'ast FieldPat) { + visit_field_pat(self, i) + } + #[cfg(feature = "full")] + fn visit_field_value(&mut self, i: &'ast FieldValue) { + visit_field_value(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields(&mut self, i: &'ast Fields) { + visit_fields(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_named(&mut self, i: &'ast FieldsNamed) { + visit_fields_named(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn visit_generic_argument(&mut self, i: &'ast GenericArgument) { + visit_generic_argument(self, i) + } + #[cfg(feature = "full")] + fn visit_generic_method_argument(&mut self, i: &'ast GenericMethodArgument) { + visit_generic_method_argument(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_param(&mut self, i: &'ast GenericParam) { + visit_generic_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + 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_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_trait_alias(&mut self, i: &'ast ItemTraitAlias) { + visit_item_trait_alias(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_label(&mut self, i: &'ast Label) { + visit_label(self, i) + } + fn visit_lifetime(&mut self, i: &'ast Lifetime) { + visit_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lifetime_def(&mut self, i: &'ast LifetimeDef) { + visit_lifetime_def(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit(&mut self, i: &'ast Lit) { + visit_lit(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_bool(&mut self, i: &'ast LitBool) { + visit_lit_bool(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte(&mut self, i: &'ast LitByte) { + visit_lit_byte(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_str(&mut self, i: &'ast LitByteStr) { + visit_lit_byte_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_char(&mut self, i: &'ast LitChar) { + visit_lit_char(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_float(&mut self, i: &'ast LitFloat) { + visit_lit_float(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_int(&mut self, i: &'ast LitInt) { + visit_lit_int(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_str(&mut self, i: &'ast LitStr) { + visit_lit_str(self, i) + } + #[cfg(feature = "full")] + fn visit_local(&mut self, i: &'ast Local) { + visit_local(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro(&mut self, i: &'ast Macro) { + visit_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_delimiter(&mut self, i: &'ast MacroDelimiter) { + visit_macro_delimiter(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_member(&mut self, i: &'ast Member) { + visit_member(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta(&mut self, i: &'ast Meta) { + visit_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_list(&mut self, i: &'ast MetaList) { + visit_meta_list(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_name_value(&mut self, i: &'ast MetaNameValue) { + visit_meta_name_value(self, i) + } + #[cfg(feature = "full")] + fn visit_method_turbofish(&mut self, i: &'ast MethodTurbofish) { + visit_method_turbofish(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_nested_meta(&mut self, i: &'ast NestedMeta) { + visit_nested_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_parenthesized_generic_arguments(&mut self, i: &'ast ParenthesizedGenericArguments) { + visit_parenthesized_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn visit_pat(&mut self, i: &'ast Pat) { + visit_pat(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_box(&mut self, i: &'ast PatBox) { + visit_pat_box(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ident(&mut self, i: &'ast PatIdent) { + visit_pat_ident(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_lit(&mut self, i: &'ast PatLit) { + visit_pat_lit(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_macro(&mut self, i: &'ast PatMacro) { + visit_pat_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_or(&mut self, i: &'ast PatOr) { + visit_pat_or(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_path(&mut self, i: &'ast PatPath) { + visit_pat_path(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_range(&mut self, i: &'ast PatRange) { + visit_pat_range(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_reference(&mut self, i: &'ast PatReference) { + visit_pat_reference(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_rest(&mut self, i: &'ast PatRest) { + visit_pat_rest(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_slice(&mut self, i: &'ast PatSlice) { + visit_pat_slice(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_struct(&mut self, i: &'ast PatStruct) { + visit_pat_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple(&mut self, i: &'ast PatTuple) { + visit_pat_tuple(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_struct(&mut self, i: &'ast PatTupleStruct) { + visit_pat_tuple_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_type(&mut self, i: &'ast PatType) { + visit_pat_type(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_wild(&mut self, i: &'ast PatWild) { + visit_pat_wild(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path(&mut self, i: &'ast Path) { + visit_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_arguments(&mut self, i: &'ast PathArguments) { + visit_path_arguments(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_segment(&mut self, i: &'ast PathSegment) { + visit_path_segment(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_eq(&mut self, i: &'ast PredicateEq) { + visit_predicate_eq(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_lifetime(&mut self, i: &'ast PredicateLifetime) { + visit_predicate_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_type(&mut self, i: &'ast PredicateType) { + visit_predicate_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_qself(&mut self, i: &'ast QSelf) { + visit_qself(self, i) + } + #[cfg(feature = "full")] + fn visit_range_limits(&mut self, i: &'ast RangeLimits) { + visit_range_limits(self, i) + } + #[cfg(feature = "full")] + fn visit_receiver(&mut self, i: &'ast Receiver) { + visit_receiver(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_return_type(&mut self, i: &'ast ReturnType) { + visit_return_type(self, i) + } + #[cfg(feature = "full")] + fn visit_signature(&mut self, i: &'ast Signature) { + visit_signature(self, i) + } + fn visit_span(&mut self, i: &Span) { + visit_span(self, i) + } + #[cfg(feature = "full")] + fn visit_stmt(&mut self, i: &'ast Stmt) { + visit_stmt(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound(&mut self, i: &'ast TraitBound) { + visit_trait_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn visit_type(&mut self, i: &'ast Type) { + visit_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_array(&mut self, i: &'ast TypeArray) { + visit_type_array(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_bare_fn(&mut self, i: &'ast TypeBareFn) { + visit_type_bare_fn(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_group(&mut self, i: &'ast TypeGroup) { + visit_type_group(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_impl_trait(&mut self, i: &'ast TypeImplTrait) { + visit_type_impl_trait(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_infer(&mut self, i: &'ast TypeInfer) { + visit_type_infer(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_macro(&mut self, i: &'ast TypeMacro) { + visit_type_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_never(&mut self, i: &'ast TypeNever) { + visit_type_never(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param(&mut self, i: &'ast TypeParam) { + visit_type_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_bound(&mut self, i: &'ast TypeParamBound) { + visit_type_param_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_paren(&mut self, i: &'ast TypeParen) { + visit_type_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_path(&mut self, i: &'ast TypePath) { + visit_type_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_ptr(&mut self, i: &'ast TypePtr) { + visit_type_ptr(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_reference(&mut self, i: &'ast TypeReference) { + visit_type_reference(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_slice(&mut self, i: &'ast TypeSlice) { + visit_type_slice(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_trait_object(&mut self, i: &'ast TypeTraitObject) { + visit_type_trait_object(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_tuple(&mut self, i: &'ast TypeTuple) { + visit_type_tuple(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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 = "derive", feature = "full"))] + fn visit_variadic(&mut self, i: &'ast Variadic) { + visit_variadic(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_variant(&mut self, i: &'ast Variant) { + visit_variant(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_crate(&mut self, i: &'ast VisCrate) { + visit_vis_crate(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_public(&mut self, i: &'ast VisPublic) { + visit_vis_public(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_restricted(&mut self, i: &'ast VisRestricted) { + visit_vis_restricted(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_visibility(&mut self, i: &'ast Visibility) { + visit_visibility(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_clause(&mut self, i: &'ast WhereClause) { + visit_where_clause(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_predicate(&mut self, i: &'ast WherePredicate) { + visit_where_predicate(self, i) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_abi<'ast, V>(v: &mut V, node: &'ast Abi) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.extern_token.span); + if let Some(it) = &node.name { + v.visit_lit_str(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_angle_bracketed_generic_arguments<'ast, V>( + v: &mut V, + node: &'ast AngleBracketedGenericArguments, +) where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.colon2_token { + tokens_helper(v, &it.spans) + }; + tokens_helper(v, &node.lt_token.spans); + for el in Punctuated::pairs(&node.args) { + let (it, p) = el.into_tuple(); + v.visit_generic_argument(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_arm<'ast, V>(v: &mut V, node: &'ast Arm) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_pat(&node.pat); + if let Some(it) = &node.guard { + tokens_helper(v, &(it).0.span); + v.visit_expr(&*(it).1); + }; + tokens_helper(v, &node.fat_arrow_token.spans); + v.visit_expr(&*node.body); + if let Some(it) = &node.comma { + tokens_helper(v, &it.spans) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attr_style<'ast, V>(v: &mut V, node: &'ast AttrStyle) +where + V: Visit<'ast> + ?Sized, +{ + match node { + AttrStyle::Outer => {} + AttrStyle::Inner(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attribute<'ast, V>(v: &mut V, node: &'ast Attribute) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.pound_token.spans); + v.visit_attr_style(&node.style); + tokens_helper(v, &node.bracket_token.span); + v.visit_path(&node.path); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg<'ast, V>(v: &mut V, node: &'ast BareFnArg) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.name { + v.visit_ident(&(it).0); + tokens_helper(v, &(it).1.spans); + }; + v.visit_type(&node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bin_op<'ast, V>(v: &mut V, node: &'ast BinOp) +where + V: Visit<'ast> + ?Sized, +{ + match node { + BinOp::Add(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Sub(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Mul(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Div(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Rem(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::And(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Or(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitXor(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitAnd(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitOr(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Shl(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Shr(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Eq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Lt(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Le(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Ne(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Ge(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::Gt(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::AddEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::SubEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::MulEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::DivEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::RemEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitXorEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitAndEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::BitOrEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::ShlEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + BinOp::ShrEq(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_binding<'ast, V>(v: &mut V, node: &'ast Binding) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + tokens_helper(v, &node.eq_token.spans); + v.visit_type(&node.ty); +} +#[cfg(feature = "full")] +pub fn visit_block<'ast, V>(v: &mut V, node: &'ast Block) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.brace_token.span); + for it in &node.stmts { + v.visit_stmt(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bound_lifetimes<'ast, V>(v: &mut V, node: &'ast BoundLifetimes) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.for_token.span); + tokens_helper(v, &node.lt_token.spans); + for el in Punctuated::pairs(&node.lifetimes) { + let (it, p) = el.into_tuple(); + v.visit_lifetime_def(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_const_param<'ast, V>(v: &mut V, node: &'ast ConstParam) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.const_token.span); + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&node.ty); + if let Some(it) = &node.eq_token { + tokens_helper(v, &it.spans) + }; + if let Some(it) = &node.default { + v.visit_expr(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_constraint<'ast, V>(v: &mut V, node: &'ast Constraint) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data<'ast, V>(v: &mut V, node: &'ast Data) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Data::Struct(_binding_0) => { + v.visit_data_struct(_binding_0); + } + Data::Enum(_binding_0) => { + v.visit_data_enum(_binding_0); + } + Data::Union(_binding_0) => { + v.visit_data_union(_binding_0); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_enum<'ast, V>(v: &mut V, node: &'ast DataEnum) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.enum_token.span); + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.variants) { + let (it, p) = el.into_tuple(); + v.visit_variant(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_struct<'ast, V>(v: &mut V, node: &'ast DataStruct) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.struct_token.span); + v.visit_fields(&node.fields); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "derive")] +pub fn visit_data_union<'ast, V>(v: &mut V, node: &'ast DataUnion) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.union_token.span); + v.visit_fields_named(&node.fields); +} +#[cfg(feature = "derive")] +pub fn visit_derive_input<'ast, V>(v: &mut V, node: &'ast DeriveInput) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_data(&node.data); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr<'ast, V>(v: &mut V, node: &'ast Expr) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Expr::Array(_binding_0) => { + full!(v.visit_expr_array(_binding_0)); + } + Expr::Assign(_binding_0) => { + full!(v.visit_expr_assign(_binding_0)); + } + Expr::AssignOp(_binding_0) => { + full!(v.visit_expr_assign_op(_binding_0)); + } + Expr::Async(_binding_0) => { + full!(v.visit_expr_async(_binding_0)); + } + Expr::Await(_binding_0) => { + full!(v.visit_expr_await(_binding_0)); + } + Expr::Binary(_binding_0) => { + v.visit_expr_binary(_binding_0); + } + Expr::Block(_binding_0) => { + full!(v.visit_expr_block(_binding_0)); + } + Expr::Box(_binding_0) => { + full!(v.visit_expr_box(_binding_0)); + } + Expr::Break(_binding_0) => { + full!(v.visit_expr_break(_binding_0)); + } + Expr::Call(_binding_0) => { + v.visit_expr_call(_binding_0); + } + Expr::Cast(_binding_0) => { + v.visit_expr_cast(_binding_0); + } + Expr::Closure(_binding_0) => { + full!(v.visit_expr_closure(_binding_0)); + } + Expr::Continue(_binding_0) => { + full!(v.visit_expr_continue(_binding_0)); + } + Expr::Field(_binding_0) => { + v.visit_expr_field(_binding_0); + } + Expr::ForLoop(_binding_0) => { + full!(v.visit_expr_for_loop(_binding_0)); + } + Expr::Group(_binding_0) => { + full!(v.visit_expr_group(_binding_0)); + } + Expr::If(_binding_0) => { + full!(v.visit_expr_if(_binding_0)); + } + Expr::Index(_binding_0) => { + v.visit_expr_index(_binding_0); + } + Expr::Let(_binding_0) => { + full!(v.visit_expr_let(_binding_0)); + } + Expr::Lit(_binding_0) => { + v.visit_expr_lit(_binding_0); + } + Expr::Loop(_binding_0) => { + full!(v.visit_expr_loop(_binding_0)); + } + Expr::Macro(_binding_0) => { + full!(v.visit_expr_macro(_binding_0)); + } + Expr::Match(_binding_0) => { + full!(v.visit_expr_match(_binding_0)); + } + Expr::MethodCall(_binding_0) => { + full!(v.visit_expr_method_call(_binding_0)); + } + Expr::Paren(_binding_0) => { + v.visit_expr_paren(_binding_0); + } + Expr::Path(_binding_0) => { + v.visit_expr_path(_binding_0); + } + Expr::Range(_binding_0) => { + full!(v.visit_expr_range(_binding_0)); + } + Expr::Reference(_binding_0) => { + full!(v.visit_expr_reference(_binding_0)); + } + Expr::Repeat(_binding_0) => { + full!(v.visit_expr_repeat(_binding_0)); + } + Expr::Return(_binding_0) => { + full!(v.visit_expr_return(_binding_0)); + } + Expr::Struct(_binding_0) => { + full!(v.visit_expr_struct(_binding_0)); + } + Expr::Try(_binding_0) => { + full!(v.visit_expr_try(_binding_0)); + } + Expr::TryBlock(_binding_0) => { + full!(v.visit_expr_try_block(_binding_0)); + } + Expr::Tuple(_binding_0) => { + full!(v.visit_expr_tuple(_binding_0)); + } + Expr::Type(_binding_0) => { + full!(v.visit_expr_type(_binding_0)); + } + Expr::Unary(_binding_0) => { + v.visit_expr_unary(_binding_0); + } + Expr::Unsafe(_binding_0) => { + full!(v.visit_expr_unsafe(_binding_0)); + } + Expr::Verbatim(_binding_0) => { + skip!(_binding_0); + } + Expr::While(_binding_0) => { + full!(v.visit_expr_while(_binding_0)); + } + Expr::Yield(_binding_0) => { + full!(v.visit_expr_yield(_binding_0)); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_expr_array<'ast, V>(v: &mut V, node: &'ast ExprArray) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.bracket_token.span); + for el in Punctuated::pairs(&node.elems) { + let (it, p) = el.into_tuple(); + v.visit_expr(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_assign<'ast, V>(v: &mut V, node: &'ast ExprAssign) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.left); + tokens_helper(v, &node.eq_token.spans); + v.visit_expr(&*node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_op<'ast, V>(v: &mut V, node: &'ast ExprAssignOp) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.left); + v.visit_bin_op(&node.op); + v.visit_expr(&*node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_async<'ast, V>(v: &mut V, node: &'ast ExprAsync) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.async_token.span); + if let Some(it) = &node.capture { + tokens_helper(v, &it.span) + }; + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_await<'ast, V>(v: &mut V, node: &'ast ExprAwait) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.base); + tokens_helper(v, &node.dot_token.spans); + tokens_helper(v, &node.await_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.left); + v.visit_bin_op(&node.op); + v.visit_expr(&*node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_block<'ast, V>(v: &mut V, node: &'ast ExprBlock) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.label { + v.visit_label(it) + }; + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_box<'ast, V>(v: &mut V, node: &'ast ExprBox) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.box_token.span); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_break<'ast, V>(v: &mut V, node: &'ast ExprBreak) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.break_token.span); + if let Some(it) = &node.label { + v.visit_lifetime(it) + }; + if let Some(it) = &node.expr { + v.visit_expr(&**it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_call<'ast, V>(v: &mut V, node: &'ast ExprCall) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.func); + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.args) { + let (it, p) = el.into_tuple(); + v.visit_expr(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_cast<'ast, V>(v: &mut V, node: &'ast ExprCast) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.expr); + tokens_helper(v, &node.as_token.span); + v.visit_type(&*node.ty); +} +#[cfg(feature = "full")] +pub fn visit_expr_closure<'ast, V>(v: &mut V, node: &'ast ExprClosure) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.asyncness { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.movability { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.capture { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.or1_token.spans); + for el in Punctuated::pairs(&node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_pat(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.or2_token.spans); + v.visit_return_type(&node.output); + v.visit_expr(&*node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_continue<'ast, V>(v: &mut V, node: &'ast ExprContinue) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.continue_token.span); + if let Some(it) = &node.label { + v.visit_lifetime(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_field<'ast, V>(v: &mut V, node: &'ast ExprField) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.base); + tokens_helper(v, &node.dot_token.spans); + v.visit_member(&node.member); +} +#[cfg(feature = "full")] +pub fn visit_expr_for_loop<'ast, V>(v: &mut V, node: &'ast ExprForLoop) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.label { + v.visit_label(it) + }; + tokens_helper(v, &node.for_token.span); + v.visit_pat(&node.pat); + tokens_helper(v, &node.in_token.span); + v.visit_expr(&*node.expr); + v.visit_block(&node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_group<'ast, V>(v: &mut V, node: &'ast ExprGroup) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.group_token.span); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_if<'ast, V>(v: &mut V, node: &'ast ExprIf) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.if_token.span); + v.visit_expr(&*node.cond); + v.visit_block(&node.then_branch); + if let Some(it) = &node.else_branch { + tokens_helper(v, &(it).0.span); + v.visit_expr(&*(it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_index<'ast, V>(v: &mut V, node: &'ast ExprIndex) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.expr); + tokens_helper(v, &node.bracket_token.span); + v.visit_expr(&*node.index); +} +#[cfg(feature = "full")] +pub fn visit_expr_let<'ast, V>(v: &mut V, node: &'ast ExprLet) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.let_token.span); + v.visit_pat(&node.pat); + tokens_helper(v, &node.eq_token.spans); + v.visit_expr(&*node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_lit<'ast, V>(v: &mut V, node: &'ast ExprLit) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_lit(&node.lit); +} +#[cfg(feature = "full")] +pub fn visit_expr_loop<'ast, V>(v: &mut V, node: &'ast ExprLoop) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.label { + v.visit_label(it) + }; + tokens_helper(v, &node.loop_token.span); + v.visit_block(&node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_macro<'ast, V>(v: &mut V, node: &'ast ExprMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_macro(&node.mac); +} +#[cfg(feature = "full")] +pub fn visit_expr_match<'ast, V>(v: &mut V, node: &'ast ExprMatch) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.match_token.span); + v.visit_expr(&*node.expr); + tokens_helper(v, &node.brace_token.span); + for it in &node.arms { + v.visit_arm(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_method_call<'ast, V>(v: &mut V, node: &'ast ExprMethodCall) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.receiver); + tokens_helper(v, &node.dot_token.spans); + v.visit_ident(&node.method); + if let Some(it) = &node.turbofish { + v.visit_method_turbofish(it) + }; + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.args) { + let (it, p) = el.into_tuple(); + v.visit_expr(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_paren<'ast, V>(v: &mut V, node: &'ast ExprParen) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.paren_token.span); + v.visit_expr(&*node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_path<'ast, V>(v: &mut V, node: &'ast ExprPath) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.qself { + v.visit_qself(it) + }; + v.visit_path(&node.path); +} +#[cfg(feature = "full")] +pub fn visit_expr_range<'ast, V>(v: &mut V, node: &'ast ExprRange) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.from { + v.visit_expr(&**it) + }; + v.visit_range_limits(&node.limits); + if let Some(it) = &node.to { + v.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_reference<'ast, V>(v: &mut V, node: &'ast ExprReference) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.and_token.spans); + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_repeat<'ast, V>(v: &mut V, node: &'ast ExprRepeat) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.bracket_token.span); + v.visit_expr(&*node.expr); + tokens_helper(v, &node.semi_token.spans); + v.visit_expr(&*node.len); +} +#[cfg(feature = "full")] +pub fn visit_expr_return<'ast, V>(v: &mut V, node: &'ast ExprReturn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.return_token.span); + if let Some(it) = &node.expr { + v.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_struct<'ast, V>(v: &mut V, node: &'ast ExprStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_path(&node.path); + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.fields) { + let (it, p) = el.into_tuple(); + v.visit_field_value(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.dot2_token { + tokens_helper(v, &it.spans) + }; + if let Some(it) = &node.rest { + v.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_try<'ast, V>(v: &mut V, node: &'ast ExprTry) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.expr); + tokens_helper(v, &node.question_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_expr_try_block<'ast, V>(v: &mut V, node: &'ast ExprTryBlock) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.try_token.span); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_tuple<'ast, V>(v: &mut V, node: &'ast ExprTuple) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.elems) { + let (it, p) = el.into_tuple(); + v.visit_expr(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_type<'ast, V>(v: &mut V, node: &'ast ExprType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.expr); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&*node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_unary<'ast, V>(v: &mut V, node: &'ast ExprUnary) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_un_op(&node.op); + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_unsafe<'ast, V>(v: &mut V, node: &'ast ExprUnsafe) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.unsafe_token.span); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_while<'ast, V>(v: &mut V, node: &'ast ExprWhile) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.label { + v.visit_label(it) + }; + tokens_helper(v, &node.while_token.span); + v.visit_expr(&*node.cond); + v.visit_block(&node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_yield<'ast, V>(v: &mut V, node: &'ast ExprYield) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.yield_token.span); + if let Some(it) = &node.expr { + v.visit_expr(&**it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_field<'ast, V>(v: &mut V, node: &'ast Field) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + if let Some(it) = &node.ident { + v.visit_ident(it) + }; + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + v.visit_type(&node.ty); +} +#[cfg(feature = "full")] +pub fn visit_field_pat<'ast, V>(v: &mut V, node: &'ast FieldPat) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_member(&node.member); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + v.visit_pat(&*node.pat); +} +#[cfg(feature = "full")] +pub fn visit_field_value<'ast, V>(v: &mut V, node: &'ast FieldValue) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_member(&node.member); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + v.visit_expr(&node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields<'ast, V>(v: &mut V, node: &'ast Fields) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Fields::Named(_binding_0) => { + v.visit_fields_named(_binding_0); + } + Fields::Unnamed(_binding_0) => { + v.visit_fields_unnamed(_binding_0); + } + Fields::Unit => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_named<'ast, V>(v: &mut V, node: &'ast FieldsNamed) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.named) { + let (it, p) = el.into_tuple(); + v.visit_field(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_unnamed<'ast, V>(v: &mut V, node: &'ast FieldsUnnamed) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.unnamed) { + let (it, p) = el.into_tuple(); + v.visit_field(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_file<'ast, V>(v: &mut V, node: &'ast File) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.shebang); + for it in &node.attrs { + v.visit_attribute(it) + } + for it in &node.items { + v.visit_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_fn_arg<'ast, V>(v: &mut V, node: &'ast FnArg) +where + V: Visit<'ast> + ?Sized, +{ + match node { + FnArg::Receiver(_binding_0) => { + v.visit_receiver(_binding_0); + } + FnArg::Typed(_binding_0) => { + v.visit_pat_type(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item<'ast, V>(v: &mut V, node: &'ast ForeignItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + ForeignItem::Fn(_binding_0) => { + v.visit_foreign_item_fn(_binding_0); + } + ForeignItem::Static(_binding_0) => { + v.visit_foreign_item_static(_binding_0); + } + ForeignItem::Type(_binding_0) => { + v.visit_foreign_item_type(_binding_0); + } + ForeignItem::Macro(_binding_0) => { + v.visit_foreign_item_macro(_binding_0); + } + ForeignItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_fn<'ast, V>(v: &mut V, node: &'ast ForeignItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + v.visit_signature(&node.sig); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_macro<'ast, V>(v: &mut V, node: &'ast ForeignItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_macro(&node.mac); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_static<'ast, V>(v: &mut V, node: &'ast ForeignItemStatic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.static_token.span); + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&*node.ty); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_type<'ast, V>(v: &mut V, node: &'ast ForeignItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.type_token.span); + v.visit_ident(&node.ident); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_argument<'ast, V>(v: &mut V, node: &'ast GenericArgument) +where + V: Visit<'ast> + ?Sized, +{ + match node { + GenericArgument::Lifetime(_binding_0) => { + v.visit_lifetime(_binding_0); + } + GenericArgument::Type(_binding_0) => { + v.visit_type(_binding_0); + } + GenericArgument::Binding(_binding_0) => { + v.visit_binding(_binding_0); + } + GenericArgument::Constraint(_binding_0) => { + v.visit_constraint(_binding_0); + } + GenericArgument::Const(_binding_0) => { + v.visit_expr(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_generic_method_argument<'ast, V>(v: &mut V, node: &'ast GenericMethodArgument) +where + V: Visit<'ast> + ?Sized, +{ + match node { + GenericMethodArgument::Type(_binding_0) => { + v.visit_type(_binding_0); + } + GenericMethodArgument::Const(_binding_0) => { + v.visit_expr(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_param<'ast, V>(v: &mut V, node: &'ast GenericParam) +where + V: Visit<'ast> + ?Sized, +{ + match node { + GenericParam::Type(_binding_0) => { + v.visit_type_param(_binding_0); + } + GenericParam::Lifetime(_binding_0) => { + v.visit_lifetime_def(_binding_0); + } + GenericParam::Const(_binding_0) => { + v.visit_const_param(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generics<'ast, V>(v: &mut V, node: &'ast Generics) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.lt_token { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.params) { + let (it, p) = el.into_tuple(); + v.visit_generic_param(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.gt_token { + tokens_helper(v, &it.spans) + }; + if let Some(it) = &node.where_clause { + v.visit_where_clause(it) + }; +} +pub fn visit_ident<'ast, V>(v: &mut V, node: &'ast Ident) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_span(&node.span()); +} +#[cfg(feature = "full")] +pub fn visit_impl_item<'ast, V>(v: &mut V, node: &'ast ImplItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + ImplItem::Const(_binding_0) => { + v.visit_impl_item_const(_binding_0); + } + ImplItem::Method(_binding_0) => { + v.visit_impl_item_method(_binding_0); + } + ImplItem::Type(_binding_0) => { + v.visit_impl_item_type(_binding_0); + } + ImplItem::Macro(_binding_0) => { + v.visit_impl_item_macro(_binding_0); + } + ImplItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_impl_item_const<'ast, V>(v: &mut V, node: &'ast ImplItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + if let Some(it) = &node.defaultness { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.const_token.span); + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&node.ty); + tokens_helper(v, &node.eq_token.spans); + v.visit_expr(&node.expr); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_macro<'ast, V>(v: &mut V, node: &'ast ImplItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_macro(&node.mac); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item_method<'ast, V>(v: &mut V, node: &'ast ImplItemMethod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + if let Some(it) = &node.defaultness { + tokens_helper(v, &it.span) + }; + v.visit_signature(&node.sig); + v.visit_block(&node.block); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_type<'ast, V>(v: &mut V, node: &'ast ImplItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + if let Some(it) = &node.defaultness { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.type_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + tokens_helper(v, &node.eq_token.spans); + v.visit_type(&node.ty); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_index<'ast, V>(v: &mut V, node: &'ast Index) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.index); + v.visit_span(&node.span); +} +#[cfg(feature = "full")] +pub fn visit_item<'ast, V>(v: &mut V, node: &'ast Item) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Item::Const(_binding_0) => { + v.visit_item_const(_binding_0); + } + Item::Enum(_binding_0) => { + v.visit_item_enum(_binding_0); + } + Item::ExternCrate(_binding_0) => { + v.visit_item_extern_crate(_binding_0); + } + Item::Fn(_binding_0) => { + v.visit_item_fn(_binding_0); + } + Item::ForeignMod(_binding_0) => { + v.visit_item_foreign_mod(_binding_0); + } + Item::Impl(_binding_0) => { + v.visit_item_impl(_binding_0); + } + Item::Macro(_binding_0) => { + v.visit_item_macro(_binding_0); + } + Item::Macro2(_binding_0) => { + v.visit_item_macro2(_binding_0); + } + Item::Mod(_binding_0) => { + v.visit_item_mod(_binding_0); + } + Item::Static(_binding_0) => { + v.visit_item_static(_binding_0); + } + Item::Struct(_binding_0) => { + v.visit_item_struct(_binding_0); + } + Item::Trait(_binding_0) => { + v.visit_item_trait(_binding_0); + } + Item::TraitAlias(_binding_0) => { + v.visit_item_trait_alias(_binding_0); + } + Item::Type(_binding_0) => { + v.visit_item_type(_binding_0); + } + Item::Union(_binding_0) => { + v.visit_item_union(_binding_0); + } + Item::Use(_binding_0) => { + v.visit_item_use(_binding_0); + } + Item::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_item_const<'ast, V>(v: &mut V, node: &'ast ItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.const_token.span); + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&*node.ty); + tokens_helper(v, &node.eq_token.spans); + v.visit_expr(&*node.expr); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_enum<'ast, V>(v: &mut V, node: &'ast ItemEnum) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.enum_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.variants) { + let (it, p) = el.into_tuple(); + v.visit_variant(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_item_extern_crate<'ast, V>(v: &mut V, node: &'ast ItemExternCrate) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.extern_token.span); + tokens_helper(v, &node.crate_token.span); + v.visit_ident(&node.ident); + if let Some(it) = &node.rename { + tokens_helper(v, &(it).0.span); + v.visit_ident(&(it).1); + }; + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_fn<'ast, V>(v: &mut V, node: &'ast ItemFn) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + v.visit_signature(&node.sig); + v.visit_block(&*node.block); +} +#[cfg(feature = "full")] +pub fn visit_item_foreign_mod<'ast, V>(v: &mut V, node: &'ast ItemForeignMod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_abi(&node.abi); + tokens_helper(v, &node.brace_token.span); + for it in &node.items { + v.visit_foreign_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_impl<'ast, V>(v: &mut V, node: &'ast ItemImpl) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.defaultness { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.unsafety { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.impl_token.span); + v.visit_generics(&node.generics); + if let Some(it) = &node.trait_ { + if let Some(it) = &(it).0 { + tokens_helper(v, &it.spans) + }; + v.visit_path(&(it).1); + tokens_helper(v, &(it).2.span); + }; + v.visit_type(&*node.self_ty); + tokens_helper(v, &node.brace_token.span); + for it in &node.items { + v.visit_impl_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_macro<'ast, V>(v: &mut V, node: &'ast ItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.ident { + v.visit_ident(it) + }; + v.visit_macro(&node.mac); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_macro2<'ast, V>(v: &mut V, node: &'ast ItemMacro2) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.macro_token.span); + v.visit_ident(&node.ident); + skip!(node.rules); +} +#[cfg(feature = "full")] +pub fn visit_item_mod<'ast, V>(v: &mut V, node: &'ast ItemMod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.mod_token.span); + v.visit_ident(&node.ident); + if let Some(it) = &node.content { + tokens_helper(v, &(it).0.span); + for it in &(it).1 { + v.visit_item(it) + } + }; + if let Some(it) = &node.semi { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_static<'ast, V>(v: &mut V, node: &'ast ItemStatic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.static_token.span); + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&*node.ty); + tokens_helper(v, &node.eq_token.spans); + v.visit_expr(&*node.expr); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_struct<'ast, V>(v: &mut V, node: &'ast ItemStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.struct_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_fields(&node.fields); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_trait<'ast, V>(v: &mut V, node: &'ast ItemTrait) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + if let Some(it) = &node.unsafety { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.auto_token { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.trait_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.supertraits) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.brace_token.span); + for it in &node.items { + v.visit_trait_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_trait_alias<'ast, V>(v: &mut V, node: &'ast ItemTraitAlias) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.trait_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + tokens_helper(v, &node.eq_token.spans); + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_type<'ast, V>(v: &mut V, node: &'ast ItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.type_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + tokens_helper(v, &node.eq_token.spans); + v.visit_type(&*node.ty); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_union<'ast, V>(v: &mut V, node: &'ast ItemUnion) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.union_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + v.visit_fields_named(&node.fields); +} +#[cfg(feature = "full")] +pub fn visit_item_use<'ast, V>(v: &mut V, node: &'ast ItemUse) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_visibility(&node.vis); + tokens_helper(v, &node.use_token.span); + if let Some(it) = &node.leading_colon { + tokens_helper(v, &it.spans) + }; + v.visit_use_tree(&node.tree); + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_label<'ast, V>(v: &mut V, node: &'ast Label) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_lifetime(&node.name); + tokens_helper(v, &node.colon_token.spans); +} +pub fn visit_lifetime<'ast, V>(v: &mut V, node: &'ast Lifetime) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_span(&node.apostrophe); + v.visit_ident(&node.ident); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lifetime_def<'ast, V>(v: &mut V, node: &'ast LifetimeDef) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_lifetime(&node.lifetime); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_lifetime(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit<'ast, V>(v: &mut V, node: &'ast Lit) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Lit::Str(_binding_0) => { + v.visit_lit_str(_binding_0); + } + Lit::ByteStr(_binding_0) => { + v.visit_lit_byte_str(_binding_0); + } + Lit::Byte(_binding_0) => { + v.visit_lit_byte(_binding_0); + } + Lit::Char(_binding_0) => { + v.visit_lit_char(_binding_0); + } + Lit::Int(_binding_0) => { + v.visit_lit_int(_binding_0); + } + Lit::Float(_binding_0) => { + v.visit_lit_float(_binding_0); + } + Lit::Bool(_binding_0) => { + v.visit_lit_bool(_binding_0); + } + Lit::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_bool<'ast, V>(v: &mut V, node: &'ast LitBool) +where + V: Visit<'ast> + ?Sized, +{ + skip!(node.value); + v.visit_span(&node.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte<'ast, V>(v: &mut V, node: &'ast LitByte) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_str<'ast, V>(v: &mut V, node: &'ast LitByteStr) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_char<'ast, V>(v: &mut V, node: &'ast LitChar) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_float<'ast, V>(v: &mut V, node: &'ast LitFloat) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_int<'ast, V>(v: &mut V, node: &'ast LitInt) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_str<'ast, V>(v: &mut V, node: &'ast LitStr) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(feature = "full")] +pub fn visit_local<'ast, V>(v: &mut V, node: &'ast Local) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.let_token.span); + v.visit_pat(&node.pat); + if let Some(it) = &node.init { + tokens_helper(v, &(it).0.spans); + v.visit_expr(&*(it).1); + }; + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro<'ast, V>(v: &mut V, node: &'ast Macro) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + tokens_helper(v, &node.bang_token.spans); + v.visit_macro_delimiter(&node.delimiter); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_delimiter<'ast, V>(v: &mut V, node: &'ast MacroDelimiter) +where + V: Visit<'ast> + ?Sized, +{ + match node { + MacroDelimiter::Paren(_binding_0) => { + tokens_helper(v, &_binding_0.span); + } + MacroDelimiter::Brace(_binding_0) => { + tokens_helper(v, &_binding_0.span); + } + MacroDelimiter::Bracket(_binding_0) => { + tokens_helper(v, &_binding_0.span); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_member<'ast, V>(v: &mut V, node: &'ast Member) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Member::Named(_binding_0) => { + v.visit_ident(_binding_0); + } + Member::Unnamed(_binding_0) => { + v.visit_index(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta<'ast, V>(v: &mut V, node: &'ast Meta) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Meta::Path(_binding_0) => { + v.visit_path(_binding_0); + } + Meta::List(_binding_0) => { + v.visit_meta_list(_binding_0); + } + Meta::NameValue(_binding_0) => { + v.visit_meta_name_value(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_list<'ast, V>(v: &mut V, node: &'ast MetaList) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.nested) { + let (it, p) = el.into_tuple(); + v.visit_nested_meta(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_name_value<'ast, V>(v: &mut V, node: &'ast MetaNameValue) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_path(&node.path); + tokens_helper(v, &node.eq_token.spans); + v.visit_lit(&node.lit); +} +#[cfg(feature = "full")] +pub fn visit_method_turbofish<'ast, V>(v: &mut V, node: &'ast MethodTurbofish) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.colon2_token.spans); + tokens_helper(v, &node.lt_token.spans); + for el in Punctuated::pairs(&node.args) { + let (it, p) = el.into_tuple(); + v.visit_generic_method_argument(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + tokens_helper(v, &node.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_nested_meta<'ast, V>(v: &mut V, node: &'ast NestedMeta) +where + V: Visit<'ast> + ?Sized, +{ + match node { + NestedMeta::Meta(_binding_0) => { + v.visit_meta(_binding_0); + } + NestedMeta::Lit(_binding_0) => { + v.visit_lit(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_parenthesized_generic_arguments<'ast, V>( + v: &mut V, + node: &'ast ParenthesizedGenericArguments, +) where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_type(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + v.visit_return_type(&node.output); +} +#[cfg(feature = "full")] +pub fn visit_pat<'ast, V>(v: &mut V, node: &'ast Pat) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Pat::Box(_binding_0) => { + v.visit_pat_box(_binding_0); + } + Pat::Ident(_binding_0) => { + v.visit_pat_ident(_binding_0); + } + Pat::Lit(_binding_0) => { + v.visit_pat_lit(_binding_0); + } + Pat::Macro(_binding_0) => { + v.visit_pat_macro(_binding_0); + } + Pat::Or(_binding_0) => { + v.visit_pat_or(_binding_0); + } + Pat::Path(_binding_0) => { + v.visit_pat_path(_binding_0); + } + Pat::Range(_binding_0) => { + v.visit_pat_range(_binding_0); + } + Pat::Reference(_binding_0) => { + v.visit_pat_reference(_binding_0); + } + Pat::Rest(_binding_0) => { + v.visit_pat_rest(_binding_0); + } + Pat::Slice(_binding_0) => { + v.visit_pat_slice(_binding_0); + } + Pat::Struct(_binding_0) => { + v.visit_pat_struct(_binding_0); + } + Pat::Tuple(_binding_0) => { + v.visit_pat_tuple(_binding_0); + } + Pat::TupleStruct(_binding_0) => { + v.visit_pat_tuple_struct(_binding_0); + } + Pat::Type(_binding_0) => { + v.visit_pat_type(_binding_0); + } + Pat::Verbatim(_binding_0) => { + skip!(_binding_0); + } + Pat::Wild(_binding_0) => { + v.visit_pat_wild(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_pat_box<'ast, V>(v: &mut V, node: &'ast PatBox) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.box_token.span); + v.visit_pat(&*node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_ident<'ast, V>(v: &mut V, node: &'ast PatIdent) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.by_ref { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_ident(&node.ident); + if let Some(it) = &node.subpat { + tokens_helper(v, &(it).0.spans); + v.visit_pat(&*(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_lit<'ast, V>(v: &mut V, node: &'ast PatLit) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.expr); +} +#[cfg(feature = "full")] +pub fn visit_pat_macro<'ast, V>(v: &mut V, node: &'ast PatMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_macro(&node.mac); +} +#[cfg(feature = "full")] +pub fn visit_pat_or<'ast, V>(v: &mut V, node: &'ast PatOr) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.leading_vert { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.cases) { + let (it, p) = el.into_tuple(); + v.visit_pat(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_path<'ast, V>(v: &mut V, node: &'ast PatPath) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.qself { + v.visit_qself(it) + }; + v.visit_path(&node.path); +} +#[cfg(feature = "full")] +pub fn visit_pat_range<'ast, V>(v: &mut V, node: &'ast PatRange) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_expr(&*node.lo); + v.visit_range_limits(&node.limits); + v.visit_expr(&*node.hi); +} +#[cfg(feature = "full")] +pub fn visit_pat_reference<'ast, V>(v: &mut V, node: &'ast PatReference) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.and_token.spans); + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_pat(&*node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_rest<'ast, V>(v: &mut V, node: &'ast PatRest) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.dot2_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_pat_slice<'ast, V>(v: &mut V, node: &'ast PatSlice) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.bracket_token.span); + for el in Punctuated::pairs(&node.elems) { + let (it, p) = el.into_tuple(); + v.visit_pat(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_struct<'ast, V>(v: &mut V, node: &'ast PatStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_path(&node.path); + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.fields) { + let (it, p) = el.into_tuple(); + v.visit_field_pat(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.dot2_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple<'ast, V>(v: &mut V, node: &'ast PatTuple) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.elems) { + let (it, p) = el.into_tuple(); + v.visit_pat(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_struct<'ast, V>(v: &mut V, node: &'ast PatTupleStruct) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_path(&node.path); + v.visit_pat_tuple(&node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_type<'ast, V>(v: &mut V, node: &'ast PatType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_pat(&*node.pat); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&*node.ty); +} +#[cfg(feature = "full")] +pub fn visit_pat_wild<'ast, V>(v: &mut V, node: &'ast PatWild) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path<'ast, V>(v: &mut V, node: &'ast Path) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.leading_colon { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.segments) { + let (it, p) = el.into_tuple(); + v.visit_path_segment(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_arguments<'ast, V>(v: &mut V, node: &'ast PathArguments) +where + V: Visit<'ast> + ?Sized, +{ + match node { + PathArguments::None => {} + PathArguments::AngleBracketed(_binding_0) => { + v.visit_angle_bracketed_generic_arguments(_binding_0); + } + PathArguments::Parenthesized(_binding_0) => { + v.visit_parenthesized_generic_arguments(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_segment<'ast, V>(v: &mut V, node: &'ast PathSegment) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + v.visit_path_arguments(&node.arguments); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_eq<'ast, V>(v: &mut V, node: &'ast PredicateEq) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_type(&node.lhs_ty); + tokens_helper(v, &node.eq_token.spans); + v.visit_type(&node.rhs_ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_lifetime<'ast, V>(v: &mut V, node: &'ast PredicateLifetime) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_lifetime(&node.lifetime); + tokens_helper(v, &node.colon_token.spans); + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_lifetime(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_type<'ast, V>(v: &mut V, node: &'ast PredicateType) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it) + }; + v.visit_type(&node.bounded_ty); + tokens_helper(v, &node.colon_token.spans); + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_qself<'ast, V>(v: &mut V, node: &'ast QSelf) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.lt_token.spans); + v.visit_type(&*node.ty); + skip!(node.position); + if let Some(it) = &node.as_token { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_range_limits<'ast, V>(v: &mut V, node: &'ast RangeLimits) +where + V: Visit<'ast> + ?Sized, +{ + match node { + RangeLimits::HalfOpen(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + RangeLimits::Closed(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_receiver<'ast, V>(v: &mut V, node: &'ast Receiver) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + if let Some(it) = &node.reference { + tokens_helper(v, &(it).0.spans); + if let Some(it) = &(it).1 { + v.visit_lifetime(it) + }; + }; + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + tokens_helper(v, &node.self_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_return_type<'ast, V>(v: &mut V, node: &'ast ReturnType) +where + V: Visit<'ast> + ?Sized, +{ + match node { + ReturnType::Default => {} + ReturnType::Type(_binding_0, _binding_1) => { + tokens_helper(v, &_binding_0.spans); + v.visit_type(&**_binding_1); + } + } +} +#[cfg(feature = "full")] +pub fn visit_signature<'ast, V>(v: &mut V, node: &'ast Signature) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.constness { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.asyncness { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.unsafety { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.abi { + v.visit_abi(it) + }; + tokens_helper(v, &node.fn_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_fn_arg(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.variadic { + v.visit_variadic(it) + }; + v.visit_return_type(&node.output); +} +pub fn visit_span<'ast, V>(v: &mut V, node: &Span) +where + V: Visit<'ast> + ?Sized, +{ +} +#[cfg(feature = "full")] +pub fn visit_stmt<'ast, V>(v: &mut V, node: &'ast Stmt) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Stmt::Local(_binding_0) => { + v.visit_local(_binding_0); + } + Stmt::Item(_binding_0) => { + v.visit_item(_binding_0); + } + Stmt::Expr(_binding_0) => { + v.visit_expr(_binding_0); + } + Stmt::Semi(_binding_0, _binding_1) => { + v.visit_expr(_binding_0); + tokens_helper(v, &_binding_1.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound<'ast, V>(v: &mut V, node: &'ast TraitBound) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.paren_token { + tokens_helper(v, &it.span) + }; + v.visit_trait_bound_modifier(&node.modifier); + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it) + }; + v.visit_path(&node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_modifier<'ast, V>(v: &mut V, node: &'ast TraitBoundModifier) +where + V: Visit<'ast> + ?Sized, +{ + match node { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item<'ast, V>(v: &mut V, node: &'ast TraitItem) +where + V: Visit<'ast> + ?Sized, +{ + match node { + TraitItem::Const(_binding_0) => { + v.visit_trait_item_const(_binding_0); + } + TraitItem::Method(_binding_0) => { + v.visit_trait_item_method(_binding_0); + } + TraitItem::Type(_binding_0) => { + v.visit_trait_item_type(_binding_0); + } + TraitItem::Macro(_binding_0) => { + v.visit_trait_item_macro(_binding_0); + } + TraitItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_const<'ast, V>(v: &mut V, node: &'ast TraitItemConst) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.const_token.span); + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon_token.spans); + v.visit_type(&node.ty); + if let Some(it) = &node.default { + tokens_helper(v, &(it).0.spans); + v.visit_expr(&(it).1); + }; + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_macro<'ast, V>(v: &mut V, node: &'ast TraitItemMacro) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_macro(&node.mac); + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_method<'ast, V>(v: &mut V, node: &'ast TraitItemMethod) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_signature(&node.sig); + if let Some(it) = &node.default { + v.visit_block(it) + }; + if let Some(it) = &node.semi_token { + tokens_helper(v, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_type<'ast, V>(v: &mut V, node: &'ast TraitItemType) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.type_token.span); + v.visit_ident(&node.ident); + v.visit_generics(&node.generics); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.default { + tokens_helper(v, &(it).0.spans); + v.visit_type(&(it).1); + }; + tokens_helper(v, &node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type<'ast, V>(v: &mut V, node: &'ast Type) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Type::Array(_binding_0) => { + v.visit_type_array(_binding_0); + } + Type::BareFn(_binding_0) => { + v.visit_type_bare_fn(_binding_0); + } + Type::Group(_binding_0) => { + v.visit_type_group(_binding_0); + } + Type::ImplTrait(_binding_0) => { + v.visit_type_impl_trait(_binding_0); + } + Type::Infer(_binding_0) => { + v.visit_type_infer(_binding_0); + } + Type::Macro(_binding_0) => { + v.visit_type_macro(_binding_0); + } + Type::Never(_binding_0) => { + v.visit_type_never(_binding_0); + } + Type::Paren(_binding_0) => { + v.visit_type_paren(_binding_0); + } + Type::Path(_binding_0) => { + v.visit_type_path(_binding_0); + } + Type::Ptr(_binding_0) => { + v.visit_type_ptr(_binding_0); + } + Type::Reference(_binding_0) => { + v.visit_type_reference(_binding_0); + } + Type::Slice(_binding_0) => { + v.visit_type_slice(_binding_0); + } + Type::TraitObject(_binding_0) => { + v.visit_type_trait_object(_binding_0); + } + Type::Tuple(_binding_0) => { + v.visit_type_tuple(_binding_0); + } + Type::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_array<'ast, V>(v: &mut V, node: &'ast TypeArray) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.bracket_token.span); + v.visit_type(&*node.elem); + tokens_helper(v, &node.semi_token.spans); + v.visit_expr(&node.len); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_bare_fn<'ast, V>(v: &mut V, node: &'ast TypeBareFn) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it) + }; + if let Some(it) = &node.unsafety { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.abi { + v.visit_abi(it) + }; + tokens_helper(v, &node.fn_token.span); + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_bare_fn_arg(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.variadic { + v.visit_variadic(it) + }; + v.visit_return_type(&node.output); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_group<'ast, V>(v: &mut V, node: &'ast TypeGroup) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.group_token.span); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_impl_trait<'ast, V>(v: &mut V, node: &'ast TypeImplTrait) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.impl_token.span); + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_infer<'ast, V>(v: &mut V, node: &'ast TypeInfer) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_macro<'ast, V>(v: &mut V, node: &'ast TypeMacro) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_macro(&node.mac); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_never<'ast, V>(v: &mut V, node: &'ast TypeNever) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.bang_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param<'ast, V>(v: &mut V, node: &'ast TypeParam) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_ident(&node.ident); + if let Some(it) = &node.colon_token { + tokens_helper(v, &it.spans) + }; + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } + if let Some(it) = &node.eq_token { + tokens_helper(v, &it.spans) + }; + if let Some(it) = &node.default { + v.visit_type(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_bound<'ast, V>(v: &mut V, node: &'ast TypeParamBound) +where + V: Visit<'ast> + ?Sized, +{ + match node { + TypeParamBound::Trait(_binding_0) => { + v.visit_trait_bound(_binding_0); + } + TypeParamBound::Lifetime(_binding_0) => { + v.visit_lifetime(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_paren<'ast, V>(v: &mut V, node: &'ast TypeParen) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.paren_token.span); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_path<'ast, V>(v: &mut V, node: &'ast TypePath) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.qself { + v.visit_qself(it) + }; + v.visit_path(&node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_ptr<'ast, V>(v: &mut V, node: &'ast TypePtr) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.star_token.spans); + if let Some(it) = &node.const_token { + tokens_helper(v, &it.span) + }; + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_reference<'ast, V>(v: &mut V, node: &'ast TypeReference) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.and_token.spans); + if let Some(it) = &node.lifetime { + v.visit_lifetime(it) + }; + if let Some(it) = &node.mutability { + tokens_helper(v, &it.span) + }; + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_slice<'ast, V>(v: &mut V, node: &'ast TypeSlice) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.bracket_token.span); + v.visit_type(&*node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_trait_object<'ast, V>(v: &mut V, node: &'ast TypeTraitObject) +where + V: Visit<'ast> + ?Sized, +{ + if let Some(it) = &node.dyn_token { + tokens_helper(v, &it.span) + }; + for el in Punctuated::pairs(&node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_tuple<'ast, V>(v: &mut V, node: &'ast TypeTuple) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.paren_token.span); + for el in Punctuated::pairs(&node.elems) { + let (it, p) = el.into_tuple(); + v.visit_type(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_un_op<'ast, V>(v: &mut V, node: &'ast UnOp) +where + V: Visit<'ast> + ?Sized, +{ + match node { + UnOp::Deref(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + UnOp::Not(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + UnOp::Neg(_binding_0) => { + tokens_helper(v, &_binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_glob<'ast, V>(v: &mut V, node: &'ast UseGlob) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.star_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_use_group<'ast, V>(v: &mut V, node: &'ast UseGroup) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.brace_token.span); + for el in Punctuated::pairs(&node.items) { + let (it, p) = el.into_tuple(); + v.visit_use_tree(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_name<'ast, V>(v: &mut V, node: &'ast UseName) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); +} +#[cfg(feature = "full")] +pub fn visit_use_path<'ast, V>(v: &mut V, node: &'ast UsePath) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + tokens_helper(v, &node.colon2_token.spans); + v.visit_use_tree(&*node.tree); +} +#[cfg(feature = "full")] +pub fn visit_use_rename<'ast, V>(v: &mut V, node: &'ast UseRename) +where + V: Visit<'ast> + ?Sized, +{ + v.visit_ident(&node.ident); + tokens_helper(v, &node.as_token.span); + v.visit_ident(&node.rename); +} +#[cfg(feature = "full")] +pub fn visit_use_tree<'ast, V>(v: &mut V, node: &'ast UseTree) +where + V: Visit<'ast> + ?Sized, +{ + match node { + UseTree::Path(_binding_0) => { + v.visit_use_path(_binding_0); + } + UseTree::Name(_binding_0) => { + v.visit_use_name(_binding_0); + } + UseTree::Rename(_binding_0) => { + v.visit_use_rename(_binding_0); + } + UseTree::Glob(_binding_0) => { + v.visit_use_glob(_binding_0); + } + UseTree::Group(_binding_0) => { + v.visit_use_group(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variadic<'ast, V>(v: &mut V, node: &'ast Variadic) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + tokens_helper(v, &node.dots.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variant<'ast, V>(v: &mut V, node: &'ast Variant) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it) + } + v.visit_ident(&node.ident); + v.visit_fields(&node.fields); + if let Some(it) = &node.discriminant { + tokens_helper(v, &(it).0.spans); + v.visit_expr(&(it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_crate<'ast, V>(v: &mut V, node: &'ast VisCrate) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.crate_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_public<'ast, V>(v: &mut V, node: &'ast VisPublic) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.pub_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_restricted<'ast, V>(v: &mut V, node: &'ast VisRestricted) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.pub_token.span); + tokens_helper(v, &node.paren_token.span); + if let Some(it) = &node.in_token { + tokens_helper(v, &it.span) + }; + v.visit_path(&*node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_visibility<'ast, V>(v: &mut V, node: &'ast Visibility) +where + V: Visit<'ast> + ?Sized, +{ + match node { + Visibility::Public(_binding_0) => { + v.visit_vis_public(_binding_0); + } + Visibility::Crate(_binding_0) => { + v.visit_vis_crate(_binding_0); + } + Visibility::Restricted(_binding_0) => { + v.visit_vis_restricted(_binding_0); + } + Visibility::Inherited => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_clause<'ast, V>(v: &mut V, node: &'ast WhereClause) +where + V: Visit<'ast> + ?Sized, +{ + tokens_helper(v, &node.where_token.span); + for el in Punctuated::pairs(&node.predicates) { + let (it, p) = el.into_tuple(); + v.visit_where_predicate(it); + if let Some(p) = p { + tokens_helper(v, &p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_predicate<'ast, V>(v: &mut V, node: &'ast WherePredicate) +where + V: Visit<'ast> + ?Sized, +{ + match node { + WherePredicate::Type(_binding_0) => { + v.visit_predicate_type(_binding_0); + } + WherePredicate::Lifetime(_binding_0) => { + v.visit_predicate_lifetime(_binding_0); + } + WherePredicate::Eq(_binding_0) => { + v.visit_predicate_eq(_binding_0); + } + } +} diff --git a/syn/src/gen/visit_mut.rs b/syn/src/gen/visit_mut.rs new file mode 100644 index 0000000..5cddb82 --- /dev/null +++ b/syn/src/gen/visit_mut.rs @@ -0,0 +1,3798 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#![allow(unused_variables)] +#[cfg(any(feature = "full", feature = "derive"))] +use crate::gen::helper::visit_mut::*; +#[cfg(any(feature = "full", feature = "derive"))] +use crate::punctuated::Punctuated; +use crate::*; +use proc_macro2::Span; +#[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)*) => {}; +} +/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in +/// place. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: self +/// +/// *This trait is available if Syn is built with the `"visit-mut"` feature.* +pub trait VisitMut { + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_abi_mut(&mut self, i: &mut Abi) { + visit_abi_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_arm_mut(&mut self, i: &mut Arm) { + visit_arm_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attr_style_mut(&mut self, i: &mut AttrStyle) { + visit_attr_style_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attribute_mut(&mut self, i: &mut Attribute) { + visit_attribute_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg_mut(&mut self, i: &mut BareFnArg) { + visit_bare_fn_arg_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bin_op_mut(&mut self, i: &mut BinOp) { + visit_bin_op_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_binding_mut(&mut self, i: &mut Binding) { + visit_binding_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_block_mut(&mut self, i: &mut Block) { + visit_block_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bound_lifetimes_mut(&mut self, i: &mut BoundLifetimes) { + visit_bound_lifetimes_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_const_param_mut(&mut self, i: &mut ConstParam) { + visit_const_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_constraint_mut(&mut self, i: &mut Constraint) { + visit_constraint_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 = "derive", feature = "full"))] + fn visit_expr_mut(&mut self, i: &mut Expr) { + visit_expr_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_array_mut(&mut self, i: &mut ExprArray) { + visit_expr_array_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_mut(&mut self, i: &mut ExprAssign) { + visit_expr_assign_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_op_mut(&mut self, i: &mut ExprAssignOp) { + visit_expr_assign_op_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_async_mut(&mut self, i: &mut ExprAsync) { + visit_expr_async_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_await_mut(&mut self, i: &mut ExprAwait) { + visit_expr_await_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_binary_mut(&mut self, i: &mut ExprBinary) { + visit_expr_binary_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_block_mut(&mut self, i: &mut ExprBlock) { + visit_expr_block_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_box_mut(&mut self, i: &mut ExprBox) { + visit_expr_box_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_break_mut(&mut self, i: &mut ExprBreak) { + visit_expr_break_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_call_mut(&mut self, i: &mut ExprCall) { + visit_expr_call_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_cast_mut(&mut self, i: &mut ExprCast) { + visit_expr_cast_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_closure_mut(&mut self, i: &mut ExprClosure) { + visit_expr_closure_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_continue_mut(&mut self, i: &mut ExprContinue) { + visit_expr_continue_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_field_mut(&mut self, i: &mut ExprField) { + visit_expr_field_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_for_loop_mut(&mut self, i: &mut ExprForLoop) { + visit_expr_for_loop_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_group_mut(&mut self, i: &mut ExprGroup) { + visit_expr_group_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_if_mut(&mut self, i: &mut ExprIf) { + visit_expr_if_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_index_mut(&mut self, i: &mut ExprIndex) { + visit_expr_index_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_let_mut(&mut self, i: &mut ExprLet) { + visit_expr_let_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_lit_mut(&mut self, i: &mut ExprLit) { + visit_expr_lit_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_loop_mut(&mut self, i: &mut ExprLoop) { + visit_expr_loop_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_macro_mut(&mut self, i: &mut ExprMacro) { + visit_expr_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_match_mut(&mut self, i: &mut ExprMatch) { + visit_expr_match_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_method_call_mut(&mut self, i: &mut ExprMethodCall) { + visit_expr_method_call_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_paren_mut(&mut self, i: &mut ExprParen) { + visit_expr_paren_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_path_mut(&mut self, i: &mut ExprPath) { + visit_expr_path_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_range_mut(&mut self, i: &mut ExprRange) { + visit_expr_range_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_reference_mut(&mut self, i: &mut ExprReference) { + visit_expr_reference_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_repeat_mut(&mut self, i: &mut ExprRepeat) { + visit_expr_repeat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_return_mut(&mut self, i: &mut ExprReturn) { + visit_expr_return_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_struct_mut(&mut self, i: &mut ExprStruct) { + visit_expr_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_mut(&mut self, i: &mut ExprTry) { + visit_expr_try_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_block_mut(&mut self, i: &mut ExprTryBlock) { + visit_expr_try_block_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_tuple_mut(&mut self, i: &mut ExprTuple) { + visit_expr_tuple_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_type_mut(&mut self, i: &mut ExprType) { + visit_expr_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_unary_mut(&mut self, i: &mut ExprUnary) { + visit_expr_unary_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_unsafe_mut(&mut self, i: &mut ExprUnsafe) { + visit_expr_unsafe_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_while_mut(&mut self, i: &mut ExprWhile) { + visit_expr_while_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_yield_mut(&mut self, i: &mut ExprYield) { + visit_expr_yield_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_field_mut(&mut self, i: &mut Field) { + visit_field_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_field_pat_mut(&mut self, i: &mut FieldPat) { + visit_field_pat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_field_value_mut(&mut self, i: &mut FieldValue) { + visit_field_value_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_mut(&mut self, i: &mut Fields) { + visit_fields_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_named_mut(&mut self, i: &mut FieldsNamed) { + visit_fields_named_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn visit_generic_argument_mut(&mut self, i: &mut GenericArgument) { + visit_generic_argument_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_generic_method_argument_mut(&mut self, i: &mut GenericMethodArgument) { + visit_generic_method_argument_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_param_mut(&mut self, i: &mut GenericParam) { + visit_generic_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + 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_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_trait_alias_mut(&mut self, i: &mut ItemTraitAlias) { + visit_item_trait_alias_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_label_mut(&mut self, i: &mut Label) { + visit_label_mut(self, i) + } + fn visit_lifetime_mut(&mut self, i: &mut Lifetime) { + visit_lifetime_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lifetime_def_mut(&mut self, i: &mut LifetimeDef) { + visit_lifetime_def_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_mut(&mut self, i: &mut Lit) { + visit_lit_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_bool_mut(&mut self, i: &mut LitBool) { + visit_lit_bool_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_mut(&mut self, i: &mut LitByte) { + visit_lit_byte_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_str_mut(&mut self, i: &mut LitByteStr) { + visit_lit_byte_str_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_char_mut(&mut self, i: &mut LitChar) { + visit_lit_char_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_float_mut(&mut self, i: &mut LitFloat) { + visit_lit_float_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_int_mut(&mut self, i: &mut LitInt) { + visit_lit_int_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_str_mut(&mut self, i: &mut LitStr) { + visit_lit_str_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_local_mut(&mut self, i: &mut Local) { + visit_local_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_mut(&mut self, i: &mut Macro) { + visit_macro_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_delimiter_mut(&mut self, i: &mut MacroDelimiter) { + visit_macro_delimiter_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_member_mut(&mut self, i: &mut Member) { + visit_member_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_mut(&mut self, i: &mut Meta) { + visit_meta_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_list_mut(&mut self, i: &mut MetaList) { + visit_meta_list_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_name_value_mut(&mut self, i: &mut MetaNameValue) { + visit_meta_name_value_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_method_turbofish_mut(&mut self, i: &mut MethodTurbofish) { + visit_method_turbofish_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_nested_meta_mut(&mut self, i: &mut NestedMeta) { + visit_nested_meta_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_parenthesized_generic_arguments_mut(&mut self, i: &mut ParenthesizedGenericArguments) { + visit_parenthesized_generic_arguments_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_mut(&mut self, i: &mut Pat) { + visit_pat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_box_mut(&mut self, i: &mut PatBox) { + visit_pat_box_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) { + visit_pat_ident_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_lit_mut(&mut self, i: &mut PatLit) { + visit_pat_lit_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_macro_mut(&mut self, i: &mut PatMacro) { + visit_pat_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_or_mut(&mut self, i: &mut PatOr) { + visit_pat_or_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_path_mut(&mut self, i: &mut PatPath) { + visit_pat_path_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_range_mut(&mut self, i: &mut PatRange) { + visit_pat_range_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_reference_mut(&mut self, i: &mut PatReference) { + visit_pat_reference_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_rest_mut(&mut self, i: &mut PatRest) { + visit_pat_rest_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_slice_mut(&mut self, i: &mut PatSlice) { + visit_pat_slice_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_struct_mut(&mut self, i: &mut PatStruct) { + visit_pat_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_mut(&mut self, i: &mut PatTuple) { + visit_pat_tuple_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_struct_mut(&mut self, i: &mut PatTupleStruct) { + visit_pat_tuple_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_type_mut(&mut self, i: &mut PatType) { + visit_pat_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_wild_mut(&mut self, i: &mut PatWild) { + visit_pat_wild_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_mut(&mut self, i: &mut Path) { + visit_path_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_arguments_mut(&mut self, i: &mut PathArguments) { + visit_path_arguments_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_segment_mut(&mut self, i: &mut PathSegment) { + visit_path_segment_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_eq_mut(&mut self, i: &mut PredicateEq) { + visit_predicate_eq_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_lifetime_mut(&mut self, i: &mut PredicateLifetime) { + visit_predicate_lifetime_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_type_mut(&mut self, i: &mut PredicateType) { + visit_predicate_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_qself_mut(&mut self, i: &mut QSelf) { + visit_qself_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_range_limits_mut(&mut self, i: &mut RangeLimits) { + visit_range_limits_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_receiver_mut(&mut self, i: &mut Receiver) { + visit_receiver_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_return_type_mut(&mut self, i: &mut ReturnType) { + visit_return_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_signature_mut(&mut self, i: &mut Signature) { + visit_signature_mut(self, i) + } + fn visit_span_mut(&mut self, i: &mut Span) { + visit_span_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_stmt_mut(&mut self, i: &mut Stmt) { + visit_stmt_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) { + visit_trait_bound_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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_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(any(feature = "derive", feature = "full"))] + fn visit_type_mut(&mut self, i: &mut Type) { + visit_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_array_mut(&mut self, i: &mut TypeArray) { + visit_type_array_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) { + visit_type_bare_fn_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_group_mut(&mut self, i: &mut TypeGroup) { + visit_type_group_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_impl_trait_mut(&mut self, i: &mut TypeImplTrait) { + visit_type_impl_trait_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_infer_mut(&mut self, i: &mut TypeInfer) { + visit_type_infer_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_macro_mut(&mut self, i: &mut TypeMacro) { + visit_type_macro_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_never_mut(&mut self, i: &mut TypeNever) { + visit_type_never_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_mut(&mut self, i: &mut TypeParam) { + visit_type_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_bound_mut(&mut self, i: &mut TypeParamBound) { + visit_type_param_bound_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_paren_mut(&mut self, i: &mut TypeParen) { + visit_type_paren_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_path_mut(&mut self, i: &mut TypePath) { + visit_type_path_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_ptr_mut(&mut self, i: &mut TypePtr) { + visit_type_ptr_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_reference_mut(&mut self, i: &mut TypeReference) { + visit_type_reference_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_slice_mut(&mut self, i: &mut TypeSlice) { + visit_type_slice_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_trait_object_mut(&mut self, i: &mut TypeTraitObject) { + visit_type_trait_object_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_tuple_mut(&mut self, i: &mut TypeTuple) { + visit_type_tuple_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + 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 = "derive", feature = "full"))] + fn visit_variadic_mut(&mut self, i: &mut Variadic) { + visit_variadic_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_variant_mut(&mut self, i: &mut Variant) { + visit_variant_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_crate_mut(&mut self, i: &mut VisCrate) { + visit_vis_crate_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_public_mut(&mut self, i: &mut VisPublic) { + visit_vis_public_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_restricted_mut(&mut self, i: &mut VisRestricted) { + visit_vis_restricted_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_visibility_mut(&mut self, i: &mut Visibility) { + visit_visibility_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_clause_mut(&mut self, i: &mut WhereClause) { + visit_where_clause_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_predicate_mut(&mut self, i: &mut WherePredicate) { + visit_where_predicate_mut(self, i) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_abi_mut<V>(v: &mut V, node: &mut Abi) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.extern_token.span); + if let Some(it) = &mut node.name { + v.visit_lit_str_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_angle_bracketed_generic_arguments_mut<V>( + v: &mut V, + node: &mut AngleBracketedGenericArguments, +) where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.colon2_token { + tokens_helper(v, &mut it.spans) + }; + tokens_helper(v, &mut node.lt_token.spans); + for el in Punctuated::pairs_mut(&mut node.args) { + let (it, p) = el.into_tuple(); + v.visit_generic_argument_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_arm_mut<V>(v: &mut V, node: &mut Arm) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_pat_mut(&mut node.pat); + if let Some(it) = &mut node.guard { + tokens_helper(v, &mut (it).0.span); + v.visit_expr_mut(&mut *(it).1); + }; + tokens_helper(v, &mut node.fat_arrow_token.spans); + v.visit_expr_mut(&mut *node.body); + if let Some(it) = &mut node.comma { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attr_style_mut<V>(v: &mut V, node: &mut AttrStyle) +where + V: VisitMut + ?Sized, +{ + match node { + AttrStyle::Outer => {} + AttrStyle::Inner(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attribute_mut<V>(v: &mut V, node: &mut Attribute) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.pound_token.spans); + v.visit_attr_style_mut(&mut node.style); + tokens_helper(v, &mut node.bracket_token.span); + v.visit_path_mut(&mut node.path); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg_mut<V>(v: &mut V, node: &mut BareFnArg) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.name { + v.visit_ident_mut(&mut (it).0); + tokens_helper(v, &mut (it).1.spans); + }; + v.visit_type_mut(&mut node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bin_op_mut<V>(v: &mut V, node: &mut BinOp) +where + V: VisitMut + ?Sized, +{ + match node { + BinOp::Add(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Sub(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Mul(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Div(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Rem(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::And(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Or(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitXor(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitAnd(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitOr(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Shl(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Shr(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Eq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Lt(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Le(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Ne(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Ge(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::Gt(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::AddEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::SubEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::MulEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::DivEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::RemEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitXorEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitAndEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::BitOrEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::ShlEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + BinOp::ShrEq(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_binding_mut<V>(v: &mut V, node: &mut Binding) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_type_mut(&mut node.ty); +} +#[cfg(feature = "full")] +pub fn visit_block_mut<V>(v: &mut V, node: &mut Block) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.brace_token.span); + for it in &mut node.stmts { + v.visit_stmt_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bound_lifetimes_mut<V>(v: &mut V, node: &mut BoundLifetimes) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.for_token.span); + tokens_helper(v, &mut node.lt_token.spans); + for el in Punctuated::pairs_mut(&mut node.lifetimes) { + let (it, p) = el.into_tuple(); + v.visit_lifetime_def_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_const_param_mut<V>(v: &mut V, node: &mut ConstParam) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.const_token.span); + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut node.ty); + if let Some(it) = &mut node.eq_token { + tokens_helper(v, &mut it.spans) + }; + if let Some(it) = &mut node.default { + v.visit_expr_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_constraint_mut<V>(v: &mut V, node: &mut Constraint) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_mut<V>(v: &mut V, node: &mut Data) +where + V: VisitMut + ?Sized, +{ + match node { + Data::Struct(_binding_0) => { + v.visit_data_struct_mut(_binding_0); + } + Data::Enum(_binding_0) => { + v.visit_data_enum_mut(_binding_0); + } + Data::Union(_binding_0) => { + v.visit_data_union_mut(_binding_0); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_enum_mut<V>(v: &mut V, node: &mut DataEnum) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.enum_token.span); + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.variants) { + let (it, p) = el.into_tuple(); + v.visit_variant_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_struct_mut<V>(v: &mut V, node: &mut DataStruct) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.struct_token.span); + v.visit_fields_mut(&mut node.fields); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "derive")] +pub fn visit_data_union_mut<V>(v: &mut V, node: &mut DataUnion) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.union_token.span); + v.visit_fields_named_mut(&mut node.fields); +} +#[cfg(feature = "derive")] +pub fn visit_derive_input_mut<V>(v: &mut V, node: &mut DeriveInput) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + v.visit_data_mut(&mut node.data); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_mut<V>(v: &mut V, node: &mut Expr) +where + V: VisitMut + ?Sized, +{ + match node { + Expr::Array(_binding_0) => { + full!(v.visit_expr_array_mut(_binding_0)); + } + Expr::Assign(_binding_0) => { + full!(v.visit_expr_assign_mut(_binding_0)); + } + Expr::AssignOp(_binding_0) => { + full!(v.visit_expr_assign_op_mut(_binding_0)); + } + Expr::Async(_binding_0) => { + full!(v.visit_expr_async_mut(_binding_0)); + } + Expr::Await(_binding_0) => { + full!(v.visit_expr_await_mut(_binding_0)); + } + Expr::Binary(_binding_0) => { + v.visit_expr_binary_mut(_binding_0); + } + Expr::Block(_binding_0) => { + full!(v.visit_expr_block_mut(_binding_0)); + } + Expr::Box(_binding_0) => { + full!(v.visit_expr_box_mut(_binding_0)); + } + Expr::Break(_binding_0) => { + full!(v.visit_expr_break_mut(_binding_0)); + } + Expr::Call(_binding_0) => { + v.visit_expr_call_mut(_binding_0); + } + Expr::Cast(_binding_0) => { + v.visit_expr_cast_mut(_binding_0); + } + Expr::Closure(_binding_0) => { + full!(v.visit_expr_closure_mut(_binding_0)); + } + Expr::Continue(_binding_0) => { + full!(v.visit_expr_continue_mut(_binding_0)); + } + Expr::Field(_binding_0) => { + v.visit_expr_field_mut(_binding_0); + } + Expr::ForLoop(_binding_0) => { + full!(v.visit_expr_for_loop_mut(_binding_0)); + } + Expr::Group(_binding_0) => { + full!(v.visit_expr_group_mut(_binding_0)); + } + Expr::If(_binding_0) => { + full!(v.visit_expr_if_mut(_binding_0)); + } + Expr::Index(_binding_0) => { + v.visit_expr_index_mut(_binding_0); + } + Expr::Let(_binding_0) => { + full!(v.visit_expr_let_mut(_binding_0)); + } + Expr::Lit(_binding_0) => { + v.visit_expr_lit_mut(_binding_0); + } + Expr::Loop(_binding_0) => { + full!(v.visit_expr_loop_mut(_binding_0)); + } + Expr::Macro(_binding_0) => { + full!(v.visit_expr_macro_mut(_binding_0)); + } + Expr::Match(_binding_0) => { + full!(v.visit_expr_match_mut(_binding_0)); + } + Expr::MethodCall(_binding_0) => { + full!(v.visit_expr_method_call_mut(_binding_0)); + } + Expr::Paren(_binding_0) => { + v.visit_expr_paren_mut(_binding_0); + } + Expr::Path(_binding_0) => { + v.visit_expr_path_mut(_binding_0); + } + Expr::Range(_binding_0) => { + full!(v.visit_expr_range_mut(_binding_0)); + } + Expr::Reference(_binding_0) => { + full!(v.visit_expr_reference_mut(_binding_0)); + } + Expr::Repeat(_binding_0) => { + full!(v.visit_expr_repeat_mut(_binding_0)); + } + Expr::Return(_binding_0) => { + full!(v.visit_expr_return_mut(_binding_0)); + } + Expr::Struct(_binding_0) => { + full!(v.visit_expr_struct_mut(_binding_0)); + } + Expr::Try(_binding_0) => { + full!(v.visit_expr_try_mut(_binding_0)); + } + Expr::TryBlock(_binding_0) => { + full!(v.visit_expr_try_block_mut(_binding_0)); + } + Expr::Tuple(_binding_0) => { + full!(v.visit_expr_tuple_mut(_binding_0)); + } + Expr::Type(_binding_0) => { + full!(v.visit_expr_type_mut(_binding_0)); + } + Expr::Unary(_binding_0) => { + v.visit_expr_unary_mut(_binding_0); + } + Expr::Unsafe(_binding_0) => { + full!(v.visit_expr_unsafe_mut(_binding_0)); + } + Expr::Verbatim(_binding_0) => { + skip!(_binding_0); + } + Expr::While(_binding_0) => { + full!(v.visit_expr_while_mut(_binding_0)); + } + Expr::Yield(_binding_0) => { + full!(v.visit_expr_yield_mut(_binding_0)); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_expr_array_mut<V>(v: &mut V, node: &mut ExprArray) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.bracket_token.span); + for el in Punctuated::pairs_mut(&mut node.elems) { + let (it, p) = el.into_tuple(); + v.visit_expr_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_mut<V>(v: &mut V, node: &mut ExprAssign) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.left); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_expr_mut(&mut *node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_op_mut<V>(v: &mut V, node: &mut ExprAssignOp) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.left); + v.visit_bin_op_mut(&mut node.op); + v.visit_expr_mut(&mut *node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_async_mut<V>(v: &mut V, node: &mut ExprAsync) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.async_token.span); + if let Some(it) = &mut node.capture { + tokens_helper(v, &mut it.span) + }; + v.visit_block_mut(&mut node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_await_mut<V>(v: &mut V, node: &mut ExprAwait) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.base); + tokens_helper(v, &mut node.dot_token.spans); + tokens_helper(v, &mut node.await_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.left); + v.visit_bin_op_mut(&mut node.op); + v.visit_expr_mut(&mut *node.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_block_mut<V>(v: &mut V, node: &mut ExprBlock) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.label { + v.visit_label_mut(it) + }; + v.visit_block_mut(&mut node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_box_mut<V>(v: &mut V, node: &mut ExprBox) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.box_token.span); + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_break_mut<V>(v: &mut V, node: &mut ExprBreak) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.break_token.span); + if let Some(it) = &mut node.label { + v.visit_lifetime_mut(it) + }; + if let Some(it) = &mut node.expr { + v.visit_expr_mut(&mut **it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_call_mut<V>(v: &mut V, node: &mut ExprCall) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.func); + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.args) { + let (it, p) = el.into_tuple(); + v.visit_expr_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_cast_mut<V>(v: &mut V, node: &mut ExprCast) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.as_token.span); + v.visit_type_mut(&mut *node.ty); +} +#[cfg(feature = "full")] +pub fn visit_expr_closure_mut<V>(v: &mut V, node: &mut ExprClosure) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.asyncness { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.movability { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.capture { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.or1_token.spans); + for el in Punctuated::pairs_mut(&mut node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_pat_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.or2_token.spans); + v.visit_return_type_mut(&mut node.output); + v.visit_expr_mut(&mut *node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_continue_mut<V>(v: &mut V, node: &mut ExprContinue) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.continue_token.span); + if let Some(it) = &mut node.label { + v.visit_lifetime_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_field_mut<V>(v: &mut V, node: &mut ExprField) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.base); + tokens_helper(v, &mut node.dot_token.spans); + v.visit_member_mut(&mut node.member); +} +#[cfg(feature = "full")] +pub fn visit_expr_for_loop_mut<V>(v: &mut V, node: &mut ExprForLoop) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.label { + v.visit_label_mut(it) + }; + tokens_helper(v, &mut node.for_token.span); + v.visit_pat_mut(&mut node.pat); + tokens_helper(v, &mut node.in_token.span); + v.visit_expr_mut(&mut *node.expr); + v.visit_block_mut(&mut node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_group_mut<V>(v: &mut V, node: &mut ExprGroup) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.group_token.span); + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_if_mut<V>(v: &mut V, node: &mut ExprIf) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.if_token.span); + v.visit_expr_mut(&mut *node.cond); + v.visit_block_mut(&mut node.then_branch); + if let Some(it) = &mut node.else_branch { + tokens_helper(v, &mut (it).0.span); + v.visit_expr_mut(&mut *(it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_index_mut<V>(v: &mut V, node: &mut ExprIndex) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.bracket_token.span); + v.visit_expr_mut(&mut *node.index); +} +#[cfg(feature = "full")] +pub fn visit_expr_let_mut<V>(v: &mut V, node: &mut ExprLet) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.let_token.span); + v.visit_pat_mut(&mut node.pat); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_lit_mut<V>(v: &mut V, node: &mut ExprLit) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_lit_mut(&mut node.lit); +} +#[cfg(feature = "full")] +pub fn visit_expr_loop_mut<V>(v: &mut V, node: &mut ExprLoop) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.label { + v.visit_label_mut(it) + }; + tokens_helper(v, &mut node.loop_token.span); + v.visit_block_mut(&mut node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_macro_mut<V>(v: &mut V, node: &mut ExprMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_macro_mut(&mut node.mac); +} +#[cfg(feature = "full")] +pub fn visit_expr_match_mut<V>(v: &mut V, node: &mut ExprMatch) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.match_token.span); + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.brace_token.span); + for it in &mut node.arms { + v.visit_arm_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_method_call_mut<V>(v: &mut V, node: &mut ExprMethodCall) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.receiver); + tokens_helper(v, &mut node.dot_token.spans); + v.visit_ident_mut(&mut node.method); + if let Some(it) = &mut node.turbofish { + v.visit_method_turbofish_mut(it) + }; + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.args) { + let (it, p) = el.into_tuple(); + v.visit_expr_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_paren_mut<V>(v: &mut V, node: &mut ExprParen) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.paren_token.span); + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_path_mut<V>(v: &mut V, node: &mut ExprPath) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.qself { + v.visit_qself_mut(it) + }; + v.visit_path_mut(&mut node.path); +} +#[cfg(feature = "full")] +pub fn visit_expr_range_mut<V>(v: &mut V, node: &mut ExprRange) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.from { + v.visit_expr_mut(&mut **it) + }; + v.visit_range_limits_mut(&mut node.limits); + if let Some(it) = &mut node.to { + v.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_reference_mut<V>(v: &mut V, node: &mut ExprReference) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.and_token.spans); + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_repeat_mut<V>(v: &mut V, node: &mut ExprRepeat) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.bracket_token.span); + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.semi_token.spans); + v.visit_expr_mut(&mut *node.len); +} +#[cfg(feature = "full")] +pub fn visit_expr_return_mut<V>(v: &mut V, node: &mut ExprReturn) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.return_token.span); + if let Some(it) = &mut node.expr { + v.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_struct_mut<V>(v: &mut V, node: &mut ExprStruct) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_path_mut(&mut node.path); + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.fields) { + let (it, p) = el.into_tuple(); + v.visit_field_value_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.dot2_token { + tokens_helper(v, &mut it.spans) + }; + if let Some(it) = &mut node.rest { + v.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_try_mut<V>(v: &mut V, node: &mut ExprTry) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.question_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_expr_try_block_mut<V>(v: &mut V, node: &mut ExprTryBlock) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.try_token.span); + v.visit_block_mut(&mut node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_tuple_mut<V>(v: &mut V, node: &mut ExprTuple) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.elems) { + let (it, p) = el.into_tuple(); + v.visit_expr_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_type_mut<V>(v: &mut V, node: &mut ExprType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut *node.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_unary_mut<V>(v: &mut V, node: &mut ExprUnary) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_un_op_mut(&mut node.op); + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_unsafe_mut<V>(v: &mut V, node: &mut ExprUnsafe) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.unsafe_token.span); + v.visit_block_mut(&mut node.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_while_mut<V>(v: &mut V, node: &mut ExprWhile) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.label { + v.visit_label_mut(it) + }; + tokens_helper(v, &mut node.while_token.span); + v.visit_expr_mut(&mut *node.cond); + v.visit_block_mut(&mut node.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_yield_mut<V>(v: &mut V, node: &mut ExprYield) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.yield_token.span); + if let Some(it) = &mut node.expr { + v.visit_expr_mut(&mut **it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_field_mut<V>(v: &mut V, node: &mut Field) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + if let Some(it) = &mut node.ident { + v.visit_ident_mut(it) + }; + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + v.visit_type_mut(&mut node.ty); +} +#[cfg(feature = "full")] +pub fn visit_field_pat_mut<V>(v: &mut V, node: &mut FieldPat) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_member_mut(&mut node.member); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + v.visit_pat_mut(&mut *node.pat); +} +#[cfg(feature = "full")] +pub fn visit_field_value_mut<V>(v: &mut V, node: &mut FieldValue) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_member_mut(&mut node.member); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + v.visit_expr_mut(&mut node.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_mut<V>(v: &mut V, node: &mut Fields) +where + V: VisitMut + ?Sized, +{ + match node { + Fields::Named(_binding_0) => { + v.visit_fields_named_mut(_binding_0); + } + Fields::Unnamed(_binding_0) => { + v.visit_fields_unnamed_mut(_binding_0); + } + Fields::Unit => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_named_mut<V>(v: &mut V, node: &mut FieldsNamed) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.named) { + let (it, p) = el.into_tuple(); + v.visit_field_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_unnamed_mut<V>(v: &mut V, node: &mut FieldsUnnamed) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.unnamed) { + let (it, p) = el.into_tuple(); + v.visit_field_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_file_mut<V>(v: &mut V, node: &mut File) +where + V: VisitMut + ?Sized, +{ + skip!(node.shebang); + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + for it in &mut node.items { + v.visit_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_fn_arg_mut<V>(v: &mut V, node: &mut FnArg) +where + V: VisitMut + ?Sized, +{ + match node { + FnArg::Receiver(_binding_0) => { + v.visit_receiver_mut(_binding_0); + } + FnArg::Typed(_binding_0) => { + v.visit_pat_type_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_mut<V>(v: &mut V, node: &mut ForeignItem) +where + V: VisitMut + ?Sized, +{ + match node { + ForeignItem::Fn(_binding_0) => { + v.visit_foreign_item_fn_mut(_binding_0); + } + ForeignItem::Static(_binding_0) => { + v.visit_foreign_item_static_mut(_binding_0); + } + ForeignItem::Type(_binding_0) => { + v.visit_foreign_item_type_mut(_binding_0); + } + ForeignItem::Macro(_binding_0) => { + v.visit_foreign_item_macro_mut(_binding_0); + } + ForeignItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_fn_mut<V>(v: &mut V, node: &mut ForeignItemFn) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + v.visit_signature_mut(&mut node.sig); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_macro_mut<V>(v: &mut V, node: &mut ForeignItemMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_macro_mut(&mut node.mac); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_static_mut<V>(v: &mut V, node: &mut ForeignItemStatic) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.static_token.span); + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut *node.ty); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_type_mut<V>(v: &mut V, node: &mut ForeignItemType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.type_token.span); + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_argument_mut<V>(v: &mut V, node: &mut GenericArgument) +where + V: VisitMut + ?Sized, +{ + match node { + GenericArgument::Lifetime(_binding_0) => { + v.visit_lifetime_mut(_binding_0); + } + GenericArgument::Type(_binding_0) => { + v.visit_type_mut(_binding_0); + } + GenericArgument::Binding(_binding_0) => { + v.visit_binding_mut(_binding_0); + } + GenericArgument::Constraint(_binding_0) => { + v.visit_constraint_mut(_binding_0); + } + GenericArgument::Const(_binding_0) => { + v.visit_expr_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_generic_method_argument_mut<V>(v: &mut V, node: &mut GenericMethodArgument) +where + V: VisitMut + ?Sized, +{ + match node { + GenericMethodArgument::Type(_binding_0) => { + v.visit_type_mut(_binding_0); + } + GenericMethodArgument::Const(_binding_0) => { + v.visit_expr_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_param_mut<V>(v: &mut V, node: &mut GenericParam) +where + V: VisitMut + ?Sized, +{ + match node { + GenericParam::Type(_binding_0) => { + v.visit_type_param_mut(_binding_0); + } + GenericParam::Lifetime(_binding_0) => { + v.visit_lifetime_def_mut(_binding_0); + } + GenericParam::Const(_binding_0) => { + v.visit_const_param_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generics_mut<V>(v: &mut V, node: &mut Generics) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.lt_token { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.params) { + let (it, p) = el.into_tuple(); + v.visit_generic_param_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.gt_token { + tokens_helper(v, &mut it.spans) + }; + if let Some(it) = &mut node.where_clause { + v.visit_where_clause_mut(it) + }; +} +pub fn visit_ident_mut<V>(v: &mut V, node: &mut Ident) +where + V: VisitMut + ?Sized, +{ + let mut span = node.span(); + v.visit_span_mut(&mut span); + node.set_span(span); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_mut<V>(v: &mut V, node: &mut ImplItem) +where + V: VisitMut + ?Sized, +{ + match node { + ImplItem::Const(_binding_0) => { + v.visit_impl_item_const_mut(_binding_0); + } + ImplItem::Method(_binding_0) => { + v.visit_impl_item_method_mut(_binding_0); + } + ImplItem::Type(_binding_0) => { + v.visit_impl_item_type_mut(_binding_0); + } + ImplItem::Macro(_binding_0) => { + v.visit_impl_item_macro_mut(_binding_0); + } + ImplItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_impl_item_const_mut<V>(v: &mut V, node: &mut ImplItemConst) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + if let Some(it) = &mut node.defaultness { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.const_token.span); + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut node.ty); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_expr_mut(&mut node.expr); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_macro_mut<V>(v: &mut V, node: &mut ImplItemMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_macro_mut(&mut node.mac); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item_method_mut<V>(v: &mut V, node: &mut ImplItemMethod) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + if let Some(it) = &mut node.defaultness { + tokens_helper(v, &mut it.span) + }; + v.visit_signature_mut(&mut node.sig); + v.visit_block_mut(&mut node.block); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_type_mut<V>(v: &mut V, node: &mut ImplItemType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + if let Some(it) = &mut node.defaultness { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.type_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_type_mut(&mut node.ty); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_index_mut<V>(v: &mut V, node: &mut Index) +where + V: VisitMut + ?Sized, +{ + skip!(node.index); + v.visit_span_mut(&mut node.span); +} +#[cfg(feature = "full")] +pub fn visit_item_mut<V>(v: &mut V, node: &mut Item) +where + V: VisitMut + ?Sized, +{ + match node { + Item::Const(_binding_0) => { + v.visit_item_const_mut(_binding_0); + } + Item::Enum(_binding_0) => { + v.visit_item_enum_mut(_binding_0); + } + Item::ExternCrate(_binding_0) => { + v.visit_item_extern_crate_mut(_binding_0); + } + Item::Fn(_binding_0) => { + v.visit_item_fn_mut(_binding_0); + } + Item::ForeignMod(_binding_0) => { + v.visit_item_foreign_mod_mut(_binding_0); + } + Item::Impl(_binding_0) => { + v.visit_item_impl_mut(_binding_0); + } + Item::Macro(_binding_0) => { + v.visit_item_macro_mut(_binding_0); + } + Item::Macro2(_binding_0) => { + v.visit_item_macro2_mut(_binding_0); + } + Item::Mod(_binding_0) => { + v.visit_item_mod_mut(_binding_0); + } + Item::Static(_binding_0) => { + v.visit_item_static_mut(_binding_0); + } + Item::Struct(_binding_0) => { + v.visit_item_struct_mut(_binding_0); + } + Item::Trait(_binding_0) => { + v.visit_item_trait_mut(_binding_0); + } + Item::TraitAlias(_binding_0) => { + v.visit_item_trait_alias_mut(_binding_0); + } + Item::Type(_binding_0) => { + v.visit_item_type_mut(_binding_0); + } + Item::Union(_binding_0) => { + v.visit_item_union_mut(_binding_0); + } + Item::Use(_binding_0) => { + v.visit_item_use_mut(_binding_0); + } + Item::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_item_const_mut<V>(v: &mut V, node: &mut ItemConst) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.const_token.span); + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut *node.ty); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_enum_mut<V>(v: &mut V, node: &mut ItemEnum) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.enum_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.variants) { + let (it, p) = el.into_tuple(); + v.visit_variant_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_item_extern_crate_mut<V>(v: &mut V, node: &mut ItemExternCrate) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.extern_token.span); + tokens_helper(v, &mut node.crate_token.span); + v.visit_ident_mut(&mut node.ident); + if let Some(it) = &mut node.rename { + tokens_helper(v, &mut (it).0.span); + v.visit_ident_mut(&mut (it).1); + }; + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_fn_mut<V>(v: &mut V, node: &mut ItemFn) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + v.visit_signature_mut(&mut node.sig); + v.visit_block_mut(&mut *node.block); +} +#[cfg(feature = "full")] +pub fn visit_item_foreign_mod_mut<V>(v: &mut V, node: &mut ItemForeignMod) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_abi_mut(&mut node.abi); + tokens_helper(v, &mut node.brace_token.span); + for it in &mut node.items { + v.visit_foreign_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_impl_mut<V>(v: &mut V, node: &mut ItemImpl) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.defaultness { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.unsafety { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.impl_token.span); + v.visit_generics_mut(&mut node.generics); + if let Some(it) = &mut node.trait_ { + if let Some(it) = &mut (it).0 { + tokens_helper(v, &mut it.spans) + }; + v.visit_path_mut(&mut (it).1); + tokens_helper(v, &mut (it).2.span); + }; + v.visit_type_mut(&mut *node.self_ty); + tokens_helper(v, &mut node.brace_token.span); + for it in &mut node.items { + v.visit_impl_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_macro_mut<V>(v: &mut V, node: &mut ItemMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.ident { + v.visit_ident_mut(it) + }; + v.visit_macro_mut(&mut node.mac); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_macro2_mut<V>(v: &mut V, node: &mut ItemMacro2) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.macro_token.span); + v.visit_ident_mut(&mut node.ident); + skip!(node.rules); +} +#[cfg(feature = "full")] +pub fn visit_item_mod_mut<V>(v: &mut V, node: &mut ItemMod) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.mod_token.span); + v.visit_ident_mut(&mut node.ident); + if let Some(it) = &mut node.content { + tokens_helper(v, &mut (it).0.span); + for it in &mut (it).1 { + v.visit_item_mut(it) + } + }; + if let Some(it) = &mut node.semi { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_static_mut<V>(v: &mut V, node: &mut ItemStatic) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.static_token.span); + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut *node.ty); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_expr_mut(&mut *node.expr); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_struct_mut<V>(v: &mut V, node: &mut ItemStruct) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.struct_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + v.visit_fields_mut(&mut node.fields); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_trait_mut<V>(v: &mut V, node: &mut ItemTrait) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + if let Some(it) = &mut node.unsafety { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.auto_token { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.trait_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.supertraits) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.brace_token.span); + for it in &mut node.items { + v.visit_trait_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_trait_alias_mut<V>(v: &mut V, node: &mut ItemTraitAlias) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.trait_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + tokens_helper(v, &mut node.eq_token.spans); + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_type_mut<V>(v: &mut V, node: &mut ItemType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.type_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_type_mut(&mut *node.ty); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_union_mut<V>(v: &mut V, node: &mut ItemUnion) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.union_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + v.visit_fields_named_mut(&mut node.fields); +} +#[cfg(feature = "full")] +pub fn visit_item_use_mut<V>(v: &mut V, node: &mut ItemUse) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_visibility_mut(&mut node.vis); + tokens_helper(v, &mut node.use_token.span); + if let Some(it) = &mut node.leading_colon { + tokens_helper(v, &mut it.spans) + }; + v.visit_use_tree_mut(&mut node.tree); + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_label_mut<V>(v: &mut V, node: &mut Label) +where + V: VisitMut + ?Sized, +{ + v.visit_lifetime_mut(&mut node.name); + tokens_helper(v, &mut node.colon_token.spans); +} +pub fn visit_lifetime_mut<V>(v: &mut V, node: &mut Lifetime) +where + V: VisitMut + ?Sized, +{ + v.visit_span_mut(&mut node.apostrophe); + v.visit_ident_mut(&mut node.ident); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lifetime_def_mut<V>(v: &mut V, node: &mut LifetimeDef) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_lifetime_mut(&mut node.lifetime); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_lifetime_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_mut<V>(v: &mut V, node: &mut Lit) +where + V: VisitMut + ?Sized, +{ + match node { + Lit::Str(_binding_0) => { + v.visit_lit_str_mut(_binding_0); + } + Lit::ByteStr(_binding_0) => { + v.visit_lit_byte_str_mut(_binding_0); + } + Lit::Byte(_binding_0) => { + v.visit_lit_byte_mut(_binding_0); + } + Lit::Char(_binding_0) => { + v.visit_lit_char_mut(_binding_0); + } + Lit::Int(_binding_0) => { + v.visit_lit_int_mut(_binding_0); + } + Lit::Float(_binding_0) => { + v.visit_lit_float_mut(_binding_0); + } + Lit::Bool(_binding_0) => { + v.visit_lit_bool_mut(_binding_0); + } + Lit::Verbatim(_binding_0) => { + skip!(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_bool_mut<V>(v: &mut V, node: &mut LitBool) +where + V: VisitMut + ?Sized, +{ + skip!(node.value); + v.visit_span_mut(&mut node.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_mut<V>(v: &mut V, node: &mut LitByte) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_str_mut<V>(v: &mut V, node: &mut LitByteStr) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_char_mut<V>(v: &mut V, node: &mut LitChar) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_float_mut<V>(v: &mut V, node: &mut LitFloat) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_int_mut<V>(v: &mut V, node: &mut LitInt) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_str_mut<V>(v: &mut V, node: &mut LitStr) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(feature = "full")] +pub fn visit_local_mut<V>(v: &mut V, node: &mut Local) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.let_token.span); + v.visit_pat_mut(&mut node.pat); + if let Some(it) = &mut node.init { + tokens_helper(v, &mut (it).0.spans); + v.visit_expr_mut(&mut *(it).1); + }; + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_mut<V>(v: &mut V, node: &mut Macro) +where + V: VisitMut + ?Sized, +{ + v.visit_path_mut(&mut node.path); + tokens_helper(v, &mut node.bang_token.spans); + v.visit_macro_delimiter_mut(&mut node.delimiter); + skip!(node.tokens); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_delimiter_mut<V>(v: &mut V, node: &mut MacroDelimiter) +where + V: VisitMut + ?Sized, +{ + match node { + MacroDelimiter::Paren(_binding_0) => { + tokens_helper(v, &mut _binding_0.span); + } + MacroDelimiter::Brace(_binding_0) => { + tokens_helper(v, &mut _binding_0.span); + } + MacroDelimiter::Bracket(_binding_0) => { + tokens_helper(v, &mut _binding_0.span); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_member_mut<V>(v: &mut V, node: &mut Member) +where + V: VisitMut + ?Sized, +{ + match node { + Member::Named(_binding_0) => { + v.visit_ident_mut(_binding_0); + } + Member::Unnamed(_binding_0) => { + v.visit_index_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_mut<V>(v: &mut V, node: &mut Meta) +where + V: VisitMut + ?Sized, +{ + match node { + Meta::Path(_binding_0) => { + v.visit_path_mut(_binding_0); + } + Meta::List(_binding_0) => { + v.visit_meta_list_mut(_binding_0); + } + Meta::NameValue(_binding_0) => { + v.visit_meta_name_value_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_list_mut<V>(v: &mut V, node: &mut MetaList) +where + V: VisitMut + ?Sized, +{ + v.visit_path_mut(&mut node.path); + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.nested) { + let (it, p) = el.into_tuple(); + v.visit_nested_meta_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_name_value_mut<V>(v: &mut V, node: &mut MetaNameValue) +where + V: VisitMut + ?Sized, +{ + v.visit_path_mut(&mut node.path); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_lit_mut(&mut node.lit); +} +#[cfg(feature = "full")] +pub fn visit_method_turbofish_mut<V>(v: &mut V, node: &mut MethodTurbofish) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.colon2_token.spans); + tokens_helper(v, &mut node.lt_token.spans); + for el in Punctuated::pairs_mut(&mut node.args) { + let (it, p) = el.into_tuple(); + v.visit_generic_method_argument_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + tokens_helper(v, &mut node.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_nested_meta_mut<V>(v: &mut V, node: &mut NestedMeta) +where + V: VisitMut + ?Sized, +{ + match node { + NestedMeta::Meta(_binding_0) => { + v.visit_meta_mut(_binding_0); + } + NestedMeta::Lit(_binding_0) => { + v.visit_lit_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_parenthesized_generic_arguments_mut<V>( + v: &mut V, + node: &mut ParenthesizedGenericArguments, +) where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_type_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + v.visit_return_type_mut(&mut node.output); +} +#[cfg(feature = "full")] +pub fn visit_pat_mut<V>(v: &mut V, node: &mut Pat) +where + V: VisitMut + ?Sized, +{ + match node { + Pat::Box(_binding_0) => { + v.visit_pat_box_mut(_binding_0); + } + Pat::Ident(_binding_0) => { + v.visit_pat_ident_mut(_binding_0); + } + Pat::Lit(_binding_0) => { + v.visit_pat_lit_mut(_binding_0); + } + Pat::Macro(_binding_0) => { + v.visit_pat_macro_mut(_binding_0); + } + Pat::Or(_binding_0) => { + v.visit_pat_or_mut(_binding_0); + } + Pat::Path(_binding_0) => { + v.visit_pat_path_mut(_binding_0); + } + Pat::Range(_binding_0) => { + v.visit_pat_range_mut(_binding_0); + } + Pat::Reference(_binding_0) => { + v.visit_pat_reference_mut(_binding_0); + } + Pat::Rest(_binding_0) => { + v.visit_pat_rest_mut(_binding_0); + } + Pat::Slice(_binding_0) => { + v.visit_pat_slice_mut(_binding_0); + } + Pat::Struct(_binding_0) => { + v.visit_pat_struct_mut(_binding_0); + } + Pat::Tuple(_binding_0) => { + v.visit_pat_tuple_mut(_binding_0); + } + Pat::TupleStruct(_binding_0) => { + v.visit_pat_tuple_struct_mut(_binding_0); + } + Pat::Type(_binding_0) => { + v.visit_pat_type_mut(_binding_0); + } + Pat::Verbatim(_binding_0) => { + skip!(_binding_0); + } + Pat::Wild(_binding_0) => { + v.visit_pat_wild_mut(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_pat_box_mut<V>(v: &mut V, node: &mut PatBox) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.box_token.span); + v.visit_pat_mut(&mut *node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_ident_mut<V>(v: &mut V, node: &mut PatIdent) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.by_ref { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_ident_mut(&mut node.ident); + if let Some(it) = &mut node.subpat { + tokens_helper(v, &mut (it).0.spans); + v.visit_pat_mut(&mut *(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_lit_mut<V>(v: &mut V, node: &mut PatLit) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.expr); +} +#[cfg(feature = "full")] +pub fn visit_pat_macro_mut<V>(v: &mut V, node: &mut PatMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_macro_mut(&mut node.mac); +} +#[cfg(feature = "full")] +pub fn visit_pat_or_mut<V>(v: &mut V, node: &mut PatOr) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.leading_vert { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.cases) { + let (it, p) = el.into_tuple(); + v.visit_pat_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_path_mut<V>(v: &mut V, node: &mut PatPath) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.qself { + v.visit_qself_mut(it) + }; + v.visit_path_mut(&mut node.path); +} +#[cfg(feature = "full")] +pub fn visit_pat_range_mut<V>(v: &mut V, node: &mut PatRange) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_expr_mut(&mut *node.lo); + v.visit_range_limits_mut(&mut node.limits); + v.visit_expr_mut(&mut *node.hi); +} +#[cfg(feature = "full")] +pub fn visit_pat_reference_mut<V>(v: &mut V, node: &mut PatReference) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.and_token.spans); + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_pat_mut(&mut *node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_rest_mut<V>(v: &mut V, node: &mut PatRest) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.dot2_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_pat_slice_mut<V>(v: &mut V, node: &mut PatSlice) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.bracket_token.span); + for el in Punctuated::pairs_mut(&mut node.elems) { + let (it, p) = el.into_tuple(); + v.visit_pat_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_struct_mut<V>(v: &mut V, node: &mut PatStruct) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_path_mut(&mut node.path); + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.fields) { + let (it, p) = el.into_tuple(); + v.visit_field_pat_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.dot2_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_mut<V>(v: &mut V, node: &mut PatTuple) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.elems) { + let (it, p) = el.into_tuple(); + v.visit_pat_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_struct_mut<V>(v: &mut V, node: &mut PatTupleStruct) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_path_mut(&mut node.path); + v.visit_pat_tuple_mut(&mut node.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_type_mut<V>(v: &mut V, node: &mut PatType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_pat_mut(&mut *node.pat); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut *node.ty); +} +#[cfg(feature = "full")] +pub fn visit_pat_wild_mut<V>(v: &mut V, node: &mut PatWild) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_mut<V>(v: &mut V, node: &mut Path) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.leading_colon { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.segments) { + let (it, p) = el.into_tuple(); + v.visit_path_segment_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_arguments_mut<V>(v: &mut V, node: &mut PathArguments) +where + V: VisitMut + ?Sized, +{ + match node { + PathArguments::None => {} + PathArguments::AngleBracketed(_binding_0) => { + v.visit_angle_bracketed_generic_arguments_mut(_binding_0); + } + PathArguments::Parenthesized(_binding_0) => { + v.visit_parenthesized_generic_arguments_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_segment_mut<V>(v: &mut V, node: &mut PathSegment) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); + v.visit_path_arguments_mut(&mut node.arguments); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_eq_mut<V>(v: &mut V, node: &mut PredicateEq) +where + V: VisitMut + ?Sized, +{ + v.visit_type_mut(&mut node.lhs_ty); + tokens_helper(v, &mut node.eq_token.spans); + v.visit_type_mut(&mut node.rhs_ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_lifetime_mut<V>(v: &mut V, node: &mut PredicateLifetime) +where + V: VisitMut + ?Sized, +{ + v.visit_lifetime_mut(&mut node.lifetime); + tokens_helper(v, &mut node.colon_token.spans); + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_lifetime_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_type_mut<V>(v: &mut V, node: &mut PredicateType) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.lifetimes { + v.visit_bound_lifetimes_mut(it) + }; + v.visit_type_mut(&mut node.bounded_ty); + tokens_helper(v, &mut node.colon_token.spans); + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_qself_mut<V>(v: &mut V, node: &mut QSelf) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.lt_token.spans); + v.visit_type_mut(&mut *node.ty); + skip!(node.position); + if let Some(it) = &mut node.as_token { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_range_limits_mut<V>(v: &mut V, node: &mut RangeLimits) +where + V: VisitMut + ?Sized, +{ + match node { + RangeLimits::HalfOpen(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + RangeLimits::Closed(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_receiver_mut<V>(v: &mut V, node: &mut Receiver) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + if let Some(it) = &mut node.reference { + tokens_helper(v, &mut (it).0.spans); + if let Some(it) = &mut (it).1 { + v.visit_lifetime_mut(it) + }; + }; + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + tokens_helper(v, &mut node.self_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_return_type_mut<V>(v: &mut V, node: &mut ReturnType) +where + V: VisitMut + ?Sized, +{ + match node { + ReturnType::Default => {} + ReturnType::Type(_binding_0, _binding_1) => { + tokens_helper(v, &mut _binding_0.spans); + v.visit_type_mut(&mut **_binding_1); + } + } +} +#[cfg(feature = "full")] +pub fn visit_signature_mut<V>(v: &mut V, node: &mut Signature) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.constness { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.asyncness { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.unsafety { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.abi { + v.visit_abi_mut(it) + }; + tokens_helper(v, &mut node.fn_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_fn_arg_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.variadic { + v.visit_variadic_mut(it) + }; + v.visit_return_type_mut(&mut node.output); +} +pub fn visit_span_mut<V>(v: &mut V, node: &mut Span) +where + V: VisitMut + ?Sized, +{ +} +#[cfg(feature = "full")] +pub fn visit_stmt_mut<V>(v: &mut V, node: &mut Stmt) +where + V: VisitMut + ?Sized, +{ + match node { + Stmt::Local(_binding_0) => { + v.visit_local_mut(_binding_0); + } + Stmt::Item(_binding_0) => { + v.visit_item_mut(_binding_0); + } + Stmt::Expr(_binding_0) => { + v.visit_expr_mut(_binding_0); + } + Stmt::Semi(_binding_0, _binding_1) => { + v.visit_expr_mut(_binding_0); + tokens_helper(v, &mut _binding_1.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_mut<V>(v: &mut V, node: &mut TraitBound) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.paren_token { + tokens_helper(v, &mut it.span) + }; + v.visit_trait_bound_modifier_mut(&mut node.modifier); + if let Some(it) = &mut node.lifetimes { + v.visit_bound_lifetimes_mut(it) + }; + v.visit_path_mut(&mut node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_modifier_mut<V>(v: &mut V, node: &mut TraitBoundModifier) +where + V: VisitMut + ?Sized, +{ + match node { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_mut<V>(v: &mut V, node: &mut TraitItem) +where + V: VisitMut + ?Sized, +{ + match node { + TraitItem::Const(_binding_0) => { + v.visit_trait_item_const_mut(_binding_0); + } + TraitItem::Method(_binding_0) => { + v.visit_trait_item_method_mut(_binding_0); + } + TraitItem::Type(_binding_0) => { + v.visit_trait_item_type_mut(_binding_0); + } + TraitItem::Macro(_binding_0) => { + v.visit_trait_item_macro_mut(_binding_0); + } + TraitItem::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_const_mut<V>(v: &mut V, node: &mut TraitItemConst) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.const_token.span); + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon_token.spans); + v.visit_type_mut(&mut node.ty); + if let Some(it) = &mut node.default { + tokens_helper(v, &mut (it).0.spans); + v.visit_expr_mut(&mut (it).1); + }; + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_macro_mut<V>(v: &mut V, node: &mut TraitItemMacro) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_macro_mut(&mut node.mac); + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_method_mut<V>(v: &mut V, node: &mut TraitItemMethod) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_signature_mut(&mut node.sig); + if let Some(it) = &mut node.default { + v.visit_block_mut(it) + }; + if let Some(it) = &mut node.semi_token { + tokens_helper(v, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_type_mut<V>(v: &mut V, node: &mut TraitItemType) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.type_token.span); + v.visit_ident_mut(&mut node.ident); + v.visit_generics_mut(&mut node.generics); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.default { + tokens_helper(v, &mut (it).0.spans); + v.visit_type_mut(&mut (it).1); + }; + tokens_helper(v, &mut node.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_mut<V>(v: &mut V, node: &mut Type) +where + V: VisitMut + ?Sized, +{ + match node { + Type::Array(_binding_0) => { + v.visit_type_array_mut(_binding_0); + } + Type::BareFn(_binding_0) => { + v.visit_type_bare_fn_mut(_binding_0); + } + Type::Group(_binding_0) => { + v.visit_type_group_mut(_binding_0); + } + Type::ImplTrait(_binding_0) => { + v.visit_type_impl_trait_mut(_binding_0); + } + Type::Infer(_binding_0) => { + v.visit_type_infer_mut(_binding_0); + } + Type::Macro(_binding_0) => { + v.visit_type_macro_mut(_binding_0); + } + Type::Never(_binding_0) => { + v.visit_type_never_mut(_binding_0); + } + Type::Paren(_binding_0) => { + v.visit_type_paren_mut(_binding_0); + } + Type::Path(_binding_0) => { + v.visit_type_path_mut(_binding_0); + } + Type::Ptr(_binding_0) => { + v.visit_type_ptr_mut(_binding_0); + } + Type::Reference(_binding_0) => { + v.visit_type_reference_mut(_binding_0); + } + Type::Slice(_binding_0) => { + v.visit_type_slice_mut(_binding_0); + } + Type::TraitObject(_binding_0) => { + v.visit_type_trait_object_mut(_binding_0); + } + Type::Tuple(_binding_0) => { + v.visit_type_tuple_mut(_binding_0); + } + Type::Verbatim(_binding_0) => { + skip!(_binding_0); + } + _ => unreachable!(), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_array_mut<V>(v: &mut V, node: &mut TypeArray) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.bracket_token.span); + v.visit_type_mut(&mut *node.elem); + tokens_helper(v, &mut node.semi_token.spans); + v.visit_expr_mut(&mut node.len); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_bare_fn_mut<V>(v: &mut V, node: &mut TypeBareFn) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.lifetimes { + v.visit_bound_lifetimes_mut(it) + }; + if let Some(it) = &mut node.unsafety { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.abi { + v.visit_abi_mut(it) + }; + tokens_helper(v, &mut node.fn_token.span); + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.inputs) { + let (it, p) = el.into_tuple(); + v.visit_bare_fn_arg_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.variadic { + v.visit_variadic_mut(it) + }; + v.visit_return_type_mut(&mut node.output); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_group_mut<V>(v: &mut V, node: &mut TypeGroup) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.group_token.span); + v.visit_type_mut(&mut *node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_impl_trait_mut<V>(v: &mut V, node: &mut TypeImplTrait) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.impl_token.span); + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_infer_mut<V>(v: &mut V, node: &mut TypeInfer) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_macro_mut<V>(v: &mut V, node: &mut TypeMacro) +where + V: VisitMut + ?Sized, +{ + v.visit_macro_mut(&mut node.mac); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_never_mut<V>(v: &mut V, node: &mut TypeNever) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.bang_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_mut<V>(v: &mut V, node: &mut TypeParam) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_ident_mut(&mut node.ident); + if let Some(it) = &mut node.colon_token { + tokens_helper(v, &mut it.spans) + }; + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } + if let Some(it) = &mut node.eq_token { + tokens_helper(v, &mut it.spans) + }; + if let Some(it) = &mut node.default { + v.visit_type_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_bound_mut<V>(v: &mut V, node: &mut TypeParamBound) +where + V: VisitMut + ?Sized, +{ + match node { + TypeParamBound::Trait(_binding_0) => { + v.visit_trait_bound_mut(_binding_0); + } + TypeParamBound::Lifetime(_binding_0) => { + v.visit_lifetime_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_paren_mut<V>(v: &mut V, node: &mut TypeParen) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.paren_token.span); + v.visit_type_mut(&mut *node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_path_mut<V>(v: &mut V, node: &mut TypePath) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.qself { + v.visit_qself_mut(it) + }; + v.visit_path_mut(&mut node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_ptr_mut<V>(v: &mut V, node: &mut TypePtr) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.star_token.spans); + if let Some(it) = &mut node.const_token { + tokens_helper(v, &mut it.span) + }; + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_type_mut(&mut *node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_reference_mut<V>(v: &mut V, node: &mut TypeReference) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.and_token.spans); + if let Some(it) = &mut node.lifetime { + v.visit_lifetime_mut(it) + }; + if let Some(it) = &mut node.mutability { + tokens_helper(v, &mut it.span) + }; + v.visit_type_mut(&mut *node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_slice_mut<V>(v: &mut V, node: &mut TypeSlice) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.bracket_token.span); + v.visit_type_mut(&mut *node.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_trait_object_mut<V>(v: &mut V, node: &mut TypeTraitObject) +where + V: VisitMut + ?Sized, +{ + if let Some(it) = &mut node.dyn_token { + tokens_helper(v, &mut it.span) + }; + for el in Punctuated::pairs_mut(&mut node.bounds) { + let (it, p) = el.into_tuple(); + v.visit_type_param_bound_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_tuple_mut<V>(v: &mut V, node: &mut TypeTuple) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.paren_token.span); + for el in Punctuated::pairs_mut(&mut node.elems) { + let (it, p) = el.into_tuple(); + v.visit_type_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_un_op_mut<V>(v: &mut V, node: &mut UnOp) +where + V: VisitMut + ?Sized, +{ + match node { + UnOp::Deref(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + UnOp::Not(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + UnOp::Neg(_binding_0) => { + tokens_helper(v, &mut _binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_glob_mut<V>(v: &mut V, node: &mut UseGlob) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.star_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_use_group_mut<V>(v: &mut V, node: &mut UseGroup) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.brace_token.span); + for el in Punctuated::pairs_mut(&mut node.items) { + let (it, p) = el.into_tuple(); + v.visit_use_tree_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_name_mut<V>(v: &mut V, node: &mut UseName) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); +} +#[cfg(feature = "full")] +pub fn visit_use_path_mut<V>(v: &mut V, node: &mut UsePath) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.colon2_token.spans); + v.visit_use_tree_mut(&mut *node.tree); +} +#[cfg(feature = "full")] +pub fn visit_use_rename_mut<V>(v: &mut V, node: &mut UseRename) +where + V: VisitMut + ?Sized, +{ + v.visit_ident_mut(&mut node.ident); + tokens_helper(v, &mut node.as_token.span); + v.visit_ident_mut(&mut node.rename); +} +#[cfg(feature = "full")] +pub fn visit_use_tree_mut<V>(v: &mut V, node: &mut UseTree) +where + V: VisitMut + ?Sized, +{ + match node { + UseTree::Path(_binding_0) => { + v.visit_use_path_mut(_binding_0); + } + UseTree::Name(_binding_0) => { + v.visit_use_name_mut(_binding_0); + } + UseTree::Rename(_binding_0) => { + v.visit_use_rename_mut(_binding_0); + } + UseTree::Glob(_binding_0) => { + v.visit_use_glob_mut(_binding_0); + } + UseTree::Group(_binding_0) => { + v.visit_use_group_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variadic_mut<V>(v: &mut V, node: &mut Variadic) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + tokens_helper(v, &mut node.dots.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variant_mut<V>(v: &mut V, node: &mut Variant) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it) + } + v.visit_ident_mut(&mut node.ident); + v.visit_fields_mut(&mut node.fields); + if let Some(it) = &mut node.discriminant { + tokens_helper(v, &mut (it).0.spans); + v.visit_expr_mut(&mut (it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_crate_mut<V>(v: &mut V, node: &mut VisCrate) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.crate_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_public_mut<V>(v: &mut V, node: &mut VisPublic) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.pub_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_restricted_mut<V>(v: &mut V, node: &mut VisRestricted) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.pub_token.span); + tokens_helper(v, &mut node.paren_token.span); + if let Some(it) = &mut node.in_token { + tokens_helper(v, &mut it.span) + }; + v.visit_path_mut(&mut *node.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_visibility_mut<V>(v: &mut V, node: &mut Visibility) +where + V: VisitMut + ?Sized, +{ + match node { + Visibility::Public(_binding_0) => { + v.visit_vis_public_mut(_binding_0); + } + Visibility::Crate(_binding_0) => { + v.visit_vis_crate_mut(_binding_0); + } + Visibility::Restricted(_binding_0) => { + v.visit_vis_restricted_mut(_binding_0); + } + Visibility::Inherited => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_clause_mut<V>(v: &mut V, node: &mut WhereClause) +where + V: VisitMut + ?Sized, +{ + tokens_helper(v, &mut node.where_token.span); + for el in Punctuated::pairs_mut(&mut node.predicates) { + let (it, p) = el.into_tuple(); + v.visit_where_predicate_mut(it); + if let Some(p) = p { + tokens_helper(v, &mut p.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_predicate_mut<V>(v: &mut V, node: &mut WherePredicate) +where + V: VisitMut + ?Sized, +{ + match node { + WherePredicate::Type(_binding_0) => { + v.visit_predicate_type_mut(_binding_0); + } + WherePredicate::Lifetime(_binding_0) => { + v.visit_predicate_lifetime_mut(_binding_0); + } + WherePredicate::Eq(_binding_0) => { + v.visit_predicate_eq_mut(_binding_0); + } + } +} diff --git a/syn/src/gen_helper.rs b/syn/src/gen_helper.rs new file mode 100644 index 0000000..b279612 --- /dev/null +++ b/syn/src/gen_helper.rs @@ -0,0 +1,154 @@ +#[cfg(feature = "fold")] +pub mod fold { + use crate::fold::Fold; + use crate::punctuated::{Pair, Punctuated}; + use proc_macro2::Span; + + 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 crate::visit::Visit; + use proc_macro2::Span; + + pub fn tokens_helper<'ast, V: Visit<'ast> + ?Sized, S: Spans>(visitor: &mut V, spans: &S) { + spans.visit(visitor); + } + + pub trait Spans { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V); + } + + impl Spans for Span { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) { + visitor.visit_span(self); + } + } + + impl Spans for [Span; 1] { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&self, visitor: &mut V) { + visitor.visit_span(&self[0]); + } + } + + impl Spans for [Span; 2] { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&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>(&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 crate::visit_mut::VisitMut; + use proc_macro2::Span; + + 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/syn/src/generics.rs b/syn/src/generics.rs new file mode 100644 index 0000000..9feeab9 --- /dev/null +++ b/syn/src/generics.rs @@ -0,0 +1,1152 @@ +use super::*; +use crate::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>`. + Type(TypeParam), + + /// A lifetime definition: `'a: 'b + 'c + 'd`. + Lifetime(LifetimeDef), + + /// A const generic parameter: `const LENGTH: usize`. + Const(ConstParam), + } +} + +ast_struct! { + /// A generic type parameter: `T: Into<String>`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct 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>, + } +} + +ast_struct! { + /// A lifetime definition: `'a: 'b + 'c + 'd`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LifetimeDef { + pub attrs: Vec<Attribute>, + pub lifetime: Lifetime, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<Lifetime, Token![+]>, + } +} + +ast_struct! { + /// A const generic parameter: `const LENGTH: usize`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct 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 &mut self.where_clause { + Some(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Type(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Type(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Lifetime(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Lifetime(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Const(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> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Const(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. + /// + /// ``` + /// # use proc_macro2::{Span, Ident}; + /// # use quote::quote; + /// # + /// # 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, + colon_token: None, + bounds: Punctuated::new(), + } + } +} + +impl From<Ident> for TypeParam { + fn from(ident: Ident) -> Self { + TypeParam { + attrs: vec![], + 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 { + Trait(TraitBound), + 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>`. + Type(PredicateType), + + /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. + Lifetime(PredicateLifetime), + + /// An equality predicate in a `where` clause (unsupported). + Eq(PredicateEq), + } +} + +ast_struct! { + /// 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 struct 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![+]>, + } +} + +ast_struct! { + /// 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 struct PredicateLifetime { + pub lifetime: Lifetime, + pub colon_token: Token![:], + pub bounds: Punctuated<Lifetime, Token![+]>, + } +} + +ast_struct! { + /// An equality predicate in a `where` clause (unsupported). + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct PredicateEq { + pub lhs_ty: Type, + pub eq_token: Token![=], + pub rhs_ty: Type, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Generics { + fn parse(input: ParseStream) -> Result<Self> { + if !input.peek(Token![<]) { + return Ok(Generics::default()); + } + + let lt_token: Token![<] = input.parse()?; + + let mut params = Punctuated::new(); + let mut allow_lifetime_param = true; + let mut allow_type_param = true; + loop { + if input.peek(Token![>]) { + break; + } + + let attrs = input.call(Attribute::parse_outer)?; + let lookahead = input.lookahead1(); + if allow_lifetime_param && lookahead.peek(Lifetime) { + params.push_value(GenericParam::Lifetime(LifetimeDef { + attrs, + ..input.parse()? + })); + } else if allow_type_param && lookahead.peek(Ident) { + allow_lifetime_param = false; + params.push_value(GenericParam::Type(TypeParam { + attrs, + ..input.parse()? + })); + } else if lookahead.peek(Token![const]) { + allow_lifetime_param = false; + allow_type_param = false; + params.push_value(GenericParam::Const(ConstParam { + attrs, + ..input.parse()? + })); + } else { + return Err(lookahead.error()); + } + + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + params.push_punct(punct); + } + + let gt_token: Token![>] = input.parse()?; + + Ok(Generics { + lt_token: Some(lt_token), + params, + gt_token: Some(gt_token), + where_clause: None, + }) + } + } + + impl Parse for GenericParam { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) { + Ok(GenericParam::Type(TypeParam { + attrs, + ..input.parse()? + })) + } else if lookahead.peek(Lifetime) { + Ok(GenericParam::Lifetime(LifetimeDef { + attrs, + ..input.parse()? + })) + } else if lookahead.peek(Token![const]) { + Ok(GenericParam::Const(ConstParam { + attrs, + ..input.parse()? + })) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for LifetimeDef { + fn parse(input: ParseStream) -> Result<Self> { + let has_colon; + Ok(LifetimeDef { + attrs: input.call(Attribute::parse_outer)?, + lifetime: input.parse()?, + colon_token: { + if input.peek(Token![:]) { + has_colon = true; + Some(input.parse()?) + } else { + has_colon = false; + None + } + }, + bounds: { + let mut bounds = Punctuated::new(); + if has_colon { + loop { + if input.peek(Token![,]) || input.peek(Token![>]) { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + } + bounds + }, + }) + } + } + + impl Parse for BoundLifetimes { + fn parse(input: ParseStream) -> Result<Self> { + Ok(BoundLifetimes { + for_token: input.parse()?, + lt_token: input.parse()?, + lifetimes: { + let mut lifetimes = Punctuated::new(); + while !input.peek(Token![>]) { + lifetimes.push_value(input.parse()?); + if input.peek(Token![>]) { + break; + } + lifetimes.push_punct(input.parse()?); + } + lifetimes + }, + gt_token: input.parse()?, + }) + } + } + + impl Parse for Option<BoundLifetimes> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![for]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + impl Parse for TypeParam { + fn parse(input: ParseStream) -> Result<Self> { + let has_colon; + let has_default; + Ok(TypeParam { + attrs: input.call(Attribute::parse_outer)?, + ident: input.parse()?, + colon_token: { + if input.peek(Token![:]) { + has_colon = true; + Some(input.parse()?) + } else { + has_colon = false; + None + } + }, + bounds: { + let mut bounds = Punctuated::new(); + if has_colon { + loop { + if input.peek(Token![,]) + || input.peek(Token![>]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + } + bounds + }, + eq_token: { + if input.peek(Token![=]) { + has_default = true; + Some(input.parse()?) + } else { + has_default = false; + None + } + }, + default: { + if has_default { + Some(input.parse()?) + } else { + None + } + }, + }) + } + } + + impl Parse for TypeParamBound { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) { + return input.parse().map(TypeParamBound::Lifetime); + } + + if input.peek(token::Paren) { + let content; + let paren_token = parenthesized!(content in input); + let mut bound: TraitBound = content.parse()?; + bound.paren_token = Some(paren_token); + return Ok(TypeParamBound::Trait(bound)); + } + + input.parse().map(TypeParamBound::Trait) + } + } + + impl Parse for TraitBound { + fn parse(input: ParseStream) -> Result<Self> { + let modifier: TraitBoundModifier = input.parse()?; + let lifetimes: Option<BoundLifetimes> = input.parse()?; + + let mut path: Path = input.parse()?; + if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) { + let parenthesized = PathArguments::Parenthesized(input.parse()?); + path.segments.last_mut().unwrap().arguments = parenthesized; + } + + Ok(TraitBound { + paren_token: None, + modifier, + lifetimes, + path, + }) + } + } + + impl Parse for TraitBoundModifier { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![?]) { + input.parse().map(TraitBoundModifier::Maybe) + } else { + Ok(TraitBoundModifier::None) + } + } + } + + impl Parse for ConstParam { + fn parse(input: ParseStream) -> Result<Self> { + let mut default = None; + Ok(ConstParam { + attrs: input.call(Attribute::parse_outer)?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: { + if input.peek(Token![=]) { + let eq_token = input.parse()?; + default = Some(input.parse::<Expr>()?); + Some(eq_token) + } else { + None + } + }, + default, + }) + } + } + + impl Parse for WhereClause { + fn parse(input: ParseStream) -> Result<Self> { + Ok(WhereClause { + where_token: input.parse()?, + predicates: { + let mut predicates = Punctuated::new(); + loop { + if input.is_empty() + || input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) && !input.peek(Token![::]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + predicates.push_value(value); + if !input.peek(Token![,]) { + break; + } + let punct = input.parse()?; + predicates.push_punct(punct); + } + predicates + }, + }) + } + } + + impl Parse for Option<WhereClause> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![where]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + impl Parse for WherePredicate { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) && input.peek2(Token![:]) { + Ok(WherePredicate::Lifetime(PredicateLifetime { + lifetime: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.is_empty() + || input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + })) + } else { + Ok(WherePredicate::Type(PredicateType { + lifetimes: input.parse()?, + bounded_ty: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.is_empty() + || input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) && !input.peek(Token![::]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + })) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use crate::attr::FilterAttrs; + use crate::print::TokensOrDefault; + + 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(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(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(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(param) => { + // Leave off the type parameter defaults + param.ident.to_tokens(tokens); + } + GenericParam::Const(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(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(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); + 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/syn/src/group.rs b/syn/src/group.rs new file mode 100644 index 0000000..ed5b151 --- /dev/null +++ b/syn/src/group.rs @@ -0,0 +1,280 @@ +use proc_macro2::{Delimiter, Span}; + +use crate::error::Result; +use crate::parse::ParseBuffer; +use crate::token; + +// Not public API. +#[doc(hidden)] +pub struct Parens<'a> { + pub token: token::Paren, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub struct Braces<'a> { + pub token: token::Brace, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub struct Brackets<'a> { + pub token: token::Bracket, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[cfg(any(feature = "full", feature = "derive"))] +#[doc(hidden)] +pub struct Group<'a> { + pub token: token::Group, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub fn parse_parens<'a>(input: &ParseBuffer<'a>) -> Result<Parens<'a>> { + parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens { + token: token::Paren(span), + content, + }) +} + +// Not public API. +#[doc(hidden)] +pub fn parse_braces<'a>(input: &ParseBuffer<'a>) -> Result<Braces<'a>> { + parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces { + token: token::Brace(span), + content, + }) +} + +// Not public API. +#[doc(hidden)] +pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> { + parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets { + token: token::Bracket(span), + content, + }) +} + +#[cfg(any(feature = "full", feature = "derive"))] +pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> { + parse_delimited(input, Delimiter::None).map(|(span, content)| Group { + token: token::Group(span), + content, + }) +} + +fn parse_delimited<'a>( + input: &ParseBuffer<'a>, + delimiter: Delimiter, +) -> Result<(Span, ParseBuffer<'a>)> { + input.step(|cursor| { + if let Some((content, span, rest)) = cursor.group(delimiter) { + let scope = crate::buffer::close_span_of_group(*cursor); + let nested = crate::parse::advance_step_cursor(cursor, content); + let unexpected = crate::parse::get_unexpected(input); + let content = crate::parse::new_parse_buffer(scope, nested, unexpected); + Ok(((span, content), rest)) + } else { + let message = match delimiter { + Delimiter::Parenthesis => "expected parentheses", + Delimiter::Brace => "expected curly braces", + Delimiter::Bracket => "expected square brackets", + Delimiter::None => "expected invisible group", + }; + Err(cursor.error(message)) + } + }) +} + +/// Parse a set of parentheses and expose their content to subsequent parsers. +/// +/// # Example +/// +/// ``` +/// # use quote::quote; +/// # +/// use syn::{parenthesized, token, Ident, Result, Token, Type}; +/// use syn::parse::{Parse, ParseStream}; +/// use syn::punctuated::Punctuated; +/// +/// // Parse a simplified tuple struct syntax like: +/// // +/// // struct S(A, B); +/// struct TupleStruct { +/// struct_token: Token![struct], +/// ident: Ident, +/// paren_token: token::Paren, +/// fields: Punctuated<Type, Token![,]>, +/// semi_token: Token![;], +/// } +/// +/// impl Parse for TupleStruct { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(TupleStruct { +/// struct_token: input.parse()?, +/// ident: input.parse()?, +/// paren_token: parenthesized!(content in input), +/// fields: content.parse_terminated(Type::parse)?, +/// semi_token: input.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # struct S(A, B); +/// # }; +/// # syn::parse2::<TupleStruct>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! parenthesized { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_parens(&$cursor) { + $crate::export::Ok(parens) => { + $content = parens.content; + parens.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} + +/// Parse a set of curly braces and expose their content to subsequent parsers. +/// +/// # Example +/// +/// ``` +/// # use quote::quote; +/// # +/// use syn::{braced, token, Ident, Result, Token, Type}; +/// use syn::parse::{Parse, ParseStream}; +/// use syn::punctuated::Punctuated; +/// +/// // Parse a simplified struct syntax like: +/// // +/// // struct S { +/// // a: A, +/// // b: B, +/// // } +/// struct Struct { +/// struct_token: Token![struct], +/// ident: Ident, +/// brace_token: token::Brace, +/// fields: Punctuated<Field, Token![,]>, +/// } +/// +/// struct Field { +/// name: Ident, +/// colon_token: Token![:], +/// ty: Type, +/// } +/// +/// impl Parse for Struct { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(Struct { +/// struct_token: input.parse()?, +/// ident: input.parse()?, +/// brace_token: braced!(content in input), +/// fields: content.parse_terminated(Field::parse)?, +/// }) +/// } +/// } +/// +/// impl Parse for Field { +/// fn parse(input: ParseStream) -> Result<Self> { +/// Ok(Field { +/// name: input.parse()?, +/// colon_token: input.parse()?, +/// ty: input.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # struct S { +/// # a: A, +/// # b: B, +/// # } +/// # }; +/// # syn::parse2::<Struct>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! braced { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_braces(&$cursor) { + $crate::export::Ok(braces) => { + $content = braces.content; + braces.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} + +/// Parse a set of square brackets and expose their content to subsequent +/// parsers. +/// +/// # Example +/// +/// ``` +/// # use quote::quote; +/// # +/// use proc_macro2::TokenStream; +/// use syn::{bracketed, token, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// // Parse an outer attribute like: +/// // +/// // #[repr(C, packed)] +/// struct OuterAttribute { +/// pound_token: Token![#], +/// bracket_token: token::Bracket, +/// content: TokenStream, +/// } +/// +/// impl Parse for OuterAttribute { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(OuterAttribute { +/// pound_token: input.parse()?, +/// bracket_token: bracketed!(content in input), +/// content: content.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # #[repr(C, packed)] +/// # }; +/// # syn::parse2::<OuterAttribute>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! bracketed { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_brackets(&$cursor) { + $crate::export::Ok(brackets) => { + $content = brackets.content; + brackets.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} diff --git a/syn/src/ident.rs b/syn/src/ident.rs new file mode 100644 index 0000000..4ca7484 --- /dev/null +++ b/syn/src/ident.rs @@ -0,0 +1,101 @@ +#[cfg(feature = "parsing")] +use crate::buffer::Cursor; +#[cfg(feature = "parsing")] +use crate::lookahead; +#[cfg(feature = "parsing")] +use crate::parse::{Parse, ParseStream, Result}; +#[cfg(feature = "parsing")] +use crate::token::Token; +use unicode_xid::UnicodeXID; + +pub use proc_macro2::Ident; + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Ident(marker: lookahead::TokenMarker) -> Ident { + match marker {} +} + +#[cfg(feature = "parsing")] +fn accept_as_ident(ident: &Ident) -> bool { + match ident.to_string().as_str() { + "_" | + // Based on https://doc.rust-lang.org/grammar.html#keywords + // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md + // and https://github.com/rust-lang/rfcs/blob/master/text/2420-unreserve-proc.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" | "pub" | "ref" | + "return" | "Self" | "self" | "static" | "struct" | "super" | "trait" | + "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | + "where" | "while" | "yield" => false, + _ => true, + } +} + +#[cfg(feature = "parsing")] +impl Parse for Ident { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if accept_as_ident(&ident) { + return Ok((ident, rest)); + } + } + Err(cursor.error("expected identifier")) + }) + } +} + +#[cfg(feature = "parsing")] +impl Token for Ident { + fn peek(cursor: Cursor) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + accept_as_ident(&ident) + } else { + false + } + } + + fn display() -> &'static str { + "identifier" + } +} + +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); + +impl From<Token![_]> for Ident { + fn from(token: Token![_]) -> Ident { + Ident::new("_", token.span) + } +} + +pub fn xid_ok(symbol: &str) -> bool { + let mut chars = symbol.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 +} diff --git a/syn/src/item.rs b/syn/src/item.rs new file mode 100644 index 0000000..67284a2 --- /dev/null +++ b/syn/src/item.rs @@ -0,0 +1,3104 @@ +use super::*; +use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; +use crate::punctuated::Punctuated; +use proc_macro2::TokenStream; + +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(feature = "parsing")] +use std::mem; + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Item #manual_extra_traits { + /// A constant item: `const MAX: u16 = 65535`. + Const(ItemConst), + + /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`. + Enum(ItemEnum), + + /// An `extern crate` item: `extern crate serde`. + ExternCrate(ItemExternCrate), + + /// A free-standing function: `fn process(n: usize) -> Result<()> { ... + /// }`. + Fn(ItemFn), + + /// A block of foreign items: `extern "C" { ... }`. + ForeignMod(ItemForeignMod), + + /// An impl block providing trait or associated items: `impl<A> Trait + /// for Data<A> { ... }`. + Impl(ItemImpl), + + /// A macro invocation, which includes `macro_rules!` definitions. + Macro(ItemMacro), + + /// A 2.0-style declarative macro introduced by the `macro` keyword. + Macro2(ItemMacro2), + + /// A module or module declaration: `mod m` or `mod m { ... }`. + Mod(ItemMod), + + /// A static item: `static BIKE: Shed = Shed(42)`. + Static(ItemStatic), + + /// A struct definition: `struct Foo<A> { x: A }`. + Struct(ItemStruct), + + /// A trait definition: `pub trait Iterator { ... }`. + Trait(ItemTrait), + + /// A trait alias: `pub trait SharableIterator = Iterator + Sync`. + TraitAlias(ItemTraitAlias), + + /// A type alias: `type Result<T> = std::result::Result<T, MyError>`. + Type(ItemType), + + /// A union definition: `union Foo<A, B> { x: A, y: B }`. + Union(ItemUnion), + + /// A use declaration: `use std::collections::HashMap`. + Use(ItemUse), + + /// Tokens forming an item not interpreted by Syn. + Verbatim(TokenStream), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// A constant item: `const MAX: u16 = 65535`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![,]>, + } +} + +ast_struct! { + /// An `extern crate` item: `extern crate serde`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A free-standing function: `fn process(n: usize) -> Result<()> { ... + /// }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemFn { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub sig: Signature, + pub block: Box<Block>, + } +} + +ast_struct! { + /// A block of foreign items: `extern "C" { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemForeignMod { + pub attrs: Vec<Attribute>, + pub abi: Abi, + pub brace_token: token::Brace, + pub items: Vec<ForeignItem>, + } +} + +ast_struct! { + /// 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 struct 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>, + } +} + +ast_struct! { + /// A macro invocation, which includes `macro_rules!` definitions. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemMacro { + pub attrs: Vec<Attribute>, + /// The `example` in `macro_rules! example { ... }`. + pub ident: Option<Ident>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + } +} + +ast_struct! { + /// A 2.0-style declarative macro introduced by the `macro` keyword. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemMacro2 #manual_extra_traits { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub macro_token: Token![macro], + pub ident: Ident, + pub rules: TokenStream, + } +} + +ast_struct! { + /// A module or module declaration: `mod m` or `mod m { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;]>, + } +} + +ast_struct! { + /// A static item: `static BIKE: Shed = Shed(42)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + 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![;], + } +} + +ast_struct! { + /// 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![;]>, + } +} + +ast_struct! { + /// A trait definition: `pub trait Iterator { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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>, + } +} + +ast_struct! { + /// A trait alias: `pub trait SharableIterator = Iterator + Sync`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemTraitAlias { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub trait_token: Token![trait], + pub ident: Ident, + pub generics: Generics, + pub eq_token: Token![=], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub semi_token: Token![;], + } +} + +ast_struct! { + /// A type alias: `type Result<T> = std::result::Result<T, MyError>`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A union definition: `union Foo<A, B> { x: A, y: B }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ItemUnion { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub union_token: Token![union], + pub ident: Ident, + pub generics: Generics, + pub fields: FieldsNamed, + } +} + +ast_struct! { + /// A use declaration: `use std::collections::HashMap`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Item {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Item { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Item::Const(this), Item::Const(other)) => this == other, + (Item::Enum(this), Item::Enum(other)) => this == other, + (Item::ExternCrate(this), Item::ExternCrate(other)) => this == other, + (Item::Fn(this), Item::Fn(other)) => this == other, + (Item::ForeignMod(this), Item::ForeignMod(other)) => this == other, + (Item::Impl(this), Item::Impl(other)) => this == other, + (Item::Macro(this), Item::Macro(other)) => this == other, + (Item::Macro2(this), Item::Macro2(other)) => this == other, + (Item::Mod(this), Item::Mod(other)) => this == other, + (Item::Static(this), Item::Static(other)) => this == other, + (Item::Struct(this), Item::Struct(other)) => this == other, + (Item::Trait(this), Item::Trait(other)) => this == other, + (Item::TraitAlias(this), Item::TraitAlias(other)) => this == other, + (Item::Type(this), Item::Type(other)) => this == other, + (Item::Union(this), Item::Union(other)) => this == other, + (Item::Use(this), Item::Use(other)) => this == other, + (Item::Verbatim(this), Item::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Item { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + match self { + Item::Const(item) => { + state.write_u8(0); + item.hash(state); + } + Item::Enum(item) => { + state.write_u8(1); + item.hash(state); + } + Item::ExternCrate(item) => { + state.write_u8(2); + item.hash(state); + } + Item::Fn(item) => { + state.write_u8(3); + item.hash(state); + } + Item::ForeignMod(item) => { + state.write_u8(4); + item.hash(state); + } + Item::Impl(item) => { + state.write_u8(5); + item.hash(state); + } + Item::Macro(item) => { + state.write_u8(6); + item.hash(state); + } + Item::Macro2(item) => { + state.write_u8(7); + item.hash(state); + } + Item::Mod(item) => { + state.write_u8(8); + item.hash(state); + } + Item::Static(item) => { + state.write_u8(9); + item.hash(state); + } + Item::Struct(item) => { + state.write_u8(10); + item.hash(state); + } + Item::Trait(item) => { + state.write_u8(11); + item.hash(state); + } + Item::TraitAlias(item) => { + state.write_u8(12); + item.hash(state); + } + Item::Type(item) => { + state.write_u8(13); + item.hash(state); + } + Item::Union(item) => { + state.write_u8(14); + item.hash(state); + } + Item::Use(item) => { + state.write_u8(15); + item.hash(state); + } + Item::Verbatim(item) => { + state.write_u8(16); + TokenStreamHelper(item).hash(state); + } + Item::__Nonexhaustive => unreachable!(), + } + } +} + +impl Item { + #[cfg(feature = "parsing")] + pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> { + match self { + Item::ExternCrate(ItemExternCrate { attrs, .. }) + | Item::Use(ItemUse { attrs, .. }) + | Item::Static(ItemStatic { attrs, .. }) + | Item::Const(ItemConst { attrs, .. }) + | Item::Fn(ItemFn { attrs, .. }) + | Item::Mod(ItemMod { attrs, .. }) + | Item::ForeignMod(ItemForeignMod { attrs, .. }) + | Item::Type(ItemType { attrs, .. }) + | Item::Struct(ItemStruct { attrs, .. }) + | Item::Enum(ItemEnum { attrs, .. }) + | Item::Union(ItemUnion { attrs, .. }) + | Item::Trait(ItemTrait { attrs, .. }) + | Item::TraitAlias(ItemTraitAlias { attrs, .. }) + | Item::Impl(ItemImpl { attrs, .. }) + | Item::Macro(ItemMacro { attrs, .. }) + | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), + Item::Verbatim(_) => Vec::new(), + Item::__Nonexhaustive => unreachable!(), + } + } +} + +#[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 + && TokenStreamHelper(&self.rules) == TokenStreamHelper(&other.rules) + } +} + +#[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); + TokenStreamHelper(&self.rules).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, + }), + } + } +} + +impl From<ItemStruct> for DeriveInput { + fn from(input: ItemStruct) -> DeriveInput { + DeriveInput { + attrs: input.attrs, + vis: input.vis, + ident: input.ident, + generics: input.generics, + data: Data::Struct(DataStruct { + struct_token: input.struct_token, + fields: input.fields, + semi_token: input.semi_token, + }), + } + } +} + +impl From<ItemEnum> for DeriveInput { + fn from(input: ItemEnum) -> DeriveInput { + DeriveInput { + attrs: input.attrs, + vis: input.vis, + ident: input.ident, + generics: input.generics, + data: Data::Enum(DataEnum { + enum_token: input.enum_token, + brace_token: input.brace_token, + variants: input.variants, + }), + } + } +} + +impl From<ItemUnion> for DeriveInput { + fn from(input: ItemUnion) -> DeriveInput { + DeriveInput { + attrs: input.attrs, + vis: input.vis, + ident: input.ident, + generics: input.generics, + data: Data::Union(DataUnion { + union_token: input.union_token, + fields: input.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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum UseTree { + /// A path prefix of imports in a `use` item: `std::...`. + Path(UsePath), + + /// An identifier imported by a `use` item: `HashMap`. + Name(UseName), + + /// An renamed identifier imported by a `use` item: `HashMap as Map`. + Rename(UseRename), + + /// A glob import in a `use` item: `*`. + Glob(UseGlob), + + /// A braced group of imports in a `use` item: `{A, B, C}`. + Group(UseGroup), + } +} + +ast_struct! { + /// A path prefix of imports in a `use` item: `std::...`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct UsePath { + pub ident: Ident, + pub colon2_token: Token![::], + pub tree: Box<UseTree>, + } +} + +ast_struct! { + /// An identifier imported by a `use` item: `HashMap`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct UseName { + pub ident: Ident, + } +} + +ast_struct! { + /// An renamed identifier imported by a `use` item: `HashMap as Map`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct UseRename { + pub ident: Ident, + pub as_token: Token![as], + pub rename: Ident, + } +} + +ast_struct! { + /// A glob import in a `use` item: `*`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct UseGlob { + pub star_token: Token![*], + } +} + +ast_struct! { + /// 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 struct 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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum ForeignItem #manual_extra_traits { + /// A foreign function in an `extern` block. + Fn(ForeignItemFn), + + /// A foreign static item in an `extern` block: `static ext: u8`. + Static(ForeignItemStatic), + + /// A foreign type in an `extern` block: `type void`. + Type(ForeignItemType), + + /// A macro invocation within an extern block. + Macro(ForeignItemMacro), + + /// Tokens in an `extern` block not interpreted by Syn. + Verbatim(TokenStream), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// A foreign function in an `extern` block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ForeignItemFn { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub sig: Signature, + pub semi_token: Token![;], + } +} + +ast_struct! { + /// A foreign static item in an `extern` block: `static ext: u8`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A foreign type in an `extern` block: `type void`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ForeignItemType { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub type_token: Token![type], + pub ident: Ident, + pub semi_token: Token![;], + } +} + +ast_struct! { + /// A macro invocation within an extern block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ForeignItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ForeignItem {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ForeignItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (ForeignItem::Fn(this), ForeignItem::Fn(other)) => this == other, + (ForeignItem::Static(this), ForeignItem::Static(other)) => this == other, + (ForeignItem::Type(this), ForeignItem::Type(other)) => this == other, + (ForeignItem::Macro(this), ForeignItem::Macro(other)) => this == other, + (ForeignItem::Verbatim(this), ForeignItem::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ForeignItem { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + match self { + ForeignItem::Fn(item) => { + state.write_u8(0); + item.hash(state); + } + ForeignItem::Static(item) => { + state.write_u8(1); + item.hash(state); + } + ForeignItem::Type(item) => { + state.write_u8(2); + item.hash(state); + } + ForeignItem::Macro(item) => { + state.write_u8(3); + item.hash(state); + } + ForeignItem::Verbatim(item) => { + state.write_u8(4); + TokenStreamHelper(item).hash(state); + } + ForeignItem::__Nonexhaustive => unreachable!(), + } + } +} + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum TraitItem #manual_extra_traits { + /// An associated constant within the definition of a trait. + Const(TraitItemConst), + + /// A trait method within the definition of a trait. + Method(TraitItemMethod), + + /// An associated type within the definition of a trait. + Type(TraitItemType), + + /// A macro invocation within the definition of a trait. + Macro(TraitItemMacro), + + /// Tokens within the definition of a trait not interpreted by Syn. + Verbatim(TokenStream), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// An associated constant within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A trait method within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct TraitItemMethod { + pub attrs: Vec<Attribute>, + pub sig: Signature, + pub default: Option<Block>, + pub semi_token: Option<Token![;]>, + } +} + +ast_struct! { + /// An associated type within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A macro invocation within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct TraitItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for TraitItem {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for TraitItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TraitItem::Const(this), TraitItem::Const(other)) => this == other, + (TraitItem::Method(this), TraitItem::Method(other)) => this == other, + (TraitItem::Type(this), TraitItem::Type(other)) => this == other, + (TraitItem::Macro(this), TraitItem::Macro(other)) => this == other, + (TraitItem::Verbatim(this), TraitItem::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for TraitItem { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + match self { + TraitItem::Const(item) => { + state.write_u8(0); + item.hash(state); + } + TraitItem::Method(item) => { + state.write_u8(1); + item.hash(state); + } + TraitItem::Type(item) => { + state.write_u8(2); + item.hash(state); + } + TraitItem::Macro(item) => { + state.write_u8(3); + item.hash(state); + } + TraitItem::Verbatim(item) => { + state.write_u8(4); + TokenStreamHelper(item).hash(state); + } + TraitItem::__Nonexhaustive => unreachable!(), + } + } +} + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum ImplItem #manual_extra_traits { + /// An associated constant within an impl block. + Const(ImplItemConst), + + /// A method within an impl block. + Method(ImplItemMethod), + + /// An associated type within an impl block. + Type(ImplItemType), + + /// A macro invocation within an impl block. + Macro(ImplItemMacro), + + /// Tokens within an impl block not interpreted by Syn. + Verbatim(TokenStream), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// An associated constant within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A method within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ImplItemMethod { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub defaultness: Option<Token![default]>, + pub sig: Signature, + pub block: Block, + } +} + +ast_struct! { + /// An associated type within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct 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![;], + } +} + +ast_struct! { + /// A macro invocation within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct ImplItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ImplItem {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ImplItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (ImplItem::Const(this), ImplItem::Const(other)) => this == other, + (ImplItem::Method(this), ImplItem::Method(other)) => this == other, + (ImplItem::Type(this), ImplItem::Type(other)) => this == other, + (ImplItem::Macro(this), ImplItem::Macro(other)) => this == other, + (ImplItem::Verbatim(this), ImplItem::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ImplItem { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + match self { + ImplItem::Const(item) => { + state.write_u8(0); + item.hash(state); + } + ImplItem::Method(item) => { + state.write_u8(1); + item.hash(state); + } + ImplItem::Type(item) => { + state.write_u8(2); + item.hash(state); + } + ImplItem::Macro(item) => { + state.write_u8(3); + item.hash(state); + } + ImplItem::Verbatim(item) => { + state.write_u8(4); + TokenStreamHelper(item).hash(state); + } + ImplItem::__Nonexhaustive => unreachable!(), + } + } +} + +ast_struct! { + /// A function signature in a trait or implementation: `unsafe fn + /// initialize(&self)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Signature { + pub constness: Option<Token![const]>, + pub asyncness: Option<Token![async]>, + pub unsafety: Option<Token![unsafe]>, + pub abi: Option<Abi>, + pub fn_token: Token![fn], + pub ident: Ident, + pub generics: Generics, + pub paren_token: token::Paren, + pub inputs: Punctuated<FnArg, Token![,]>, + pub variadic: Option<Variadic>, + pub output: ReturnType, + } +} + +impl Signature { + /// A method's `self` receiver, such as `&self` or `self: Box<Self>`. + pub fn receiver(&self) -> Option<&FnArg> { + let arg = self.inputs.first()?; + match arg { + FnArg::Receiver(_) => Some(arg), + FnArg::Typed(PatType { pat, .. }) => { + if let Pat::Ident(PatIdent { ident, .. }) = &**pat { + if ident == "self" { + return Some(arg); + } + } + None + } + } + } +} + +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.* + pub enum FnArg { + /// The `self` argument of an associated method, whether taken by value + /// or by reference. + /// + /// Note that `self` receivers with a specified type, such as `self: + /// Box<Self>`, are parsed as a `FnArg::Typed`. + Receiver(Receiver), + + /// A function argument accepted by pattern and type. + Typed(PatType), + } +} + +ast_struct! { + /// The `self` argument of an associated method, whether taken by value + /// or by reference. + /// + /// Note that `self` receivers with a specified type, such as `self: + /// Box<Self>`, are parsed as a `FnArg::Typed`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Receiver { + pub attrs: Vec<Attribute>, + pub reference: Option<(Token![&], Option<Lifetime>)>, + pub mutability: Option<Token![mut]>, + pub self_token: Token![self], + } +} + +impl Receiver { + pub fn lifetime(&self) -> Option<&Lifetime> { + self.reference.as_ref()?.1.as_ref() + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::ext::IdentExt; + use crate::parse::discouraged::Speculative; + use crate::parse::{Parse, ParseStream, Result}; + use crate::token::Brace; + use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenTree}; + use std::iter::{self, FromIterator}; + + crate::custom_keyword!(existential); + + impl Parse for Item { + fn parse(input: ParseStream) -> Result<Self> { + let mut attrs = input.call(Attribute::parse_outer)?; + let ahead = input.fork(); + let vis: Visibility = ahead.parse()?; + + let lookahead = ahead.lookahead1(); + let mut item = if lookahead.peek(Token![extern]) { + ahead.parse::<Token![extern]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![crate]) { + input.parse().map(Item::ExternCrate) + } else if lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else if lookahead.peek(token::Brace) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(LitStr) { + ahead.parse::<LitStr>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(token::Brace) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![use]) { + input.parse().map(Item::Use) + } else if lookahead.peek(Token![static]) { + input.parse().map(Item::Static) + } else if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) || lookahead.peek(Token![_]) { + input.parse().map(Item::Const) + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![unsafe]) { + ahead.parse::<Token![unsafe]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![trait]) + || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) + { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) { + input.parse().map(Item::Impl) + } else if lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![async]) || lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else if lookahead.peek(Token![mod]) { + input.parse().map(Item::Mod) + } else if lookahead.peek(Token![type]) { + input.parse().map(Item::Type) + } else if lookahead.peek(existential) { + input.call(item_existential).map(Item::Verbatim) + } else if lookahead.peek(Token![struct]) { + input.parse().map(Item::Struct) + } else if lookahead.peek(Token![enum]) { + input.parse().map(Item::Enum) + } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) { + input.parse().map(Item::Union) + } else if lookahead.peek(Token![trait]) { + input.call(parse_trait_or_trait_alias) + } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) + || lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) + { + input.parse().map(Item::Impl) + } else if lookahead.peek(Token![macro]) { + input.parse().map(Item::Macro2) + } else if vis.is_inherited() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(Item::Macro) + } else { + Err(lookahead.error()) + }?; + + attrs.extend(item.replace_attrs(Vec::new())); + item.replace_attrs(attrs); + Ok(item) + } + } + + impl Parse for ItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let path = input.call(Path::parse_mod_style)?; + let bang_token: Token![!] = input.parse()?; + let ident: Option<Ident> = input.parse()?; + let (delimiter, tokens) = input.call(mac::parse_delimiter)?; + let semi_token: Option<Token![;]> = if !delimiter.is_brace() { + Some(input.parse()?) + } else { + None + }; + Ok(ItemMacro { + attrs, + ident, + mac: Macro { + path, + bang_token, + delimiter, + tokens, + }, + semi_token, + }) + } + } + + impl Parse for ItemMacro2 { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let macro_token: Token![macro] = input.parse()?; + let ident: Ident = input.parse()?; + let mut rules = TokenStream::new(); + + let mut lookahead = input.lookahead1(); + if lookahead.peek(token::Paren) { + let paren_content; + let paren_token = parenthesized!(paren_content in input); + let args: TokenStream = paren_content.parse()?; + let mut args = Group::new(Delimiter::Parenthesis, args); + args.set_span(paren_token.span); + rules.extend(iter::once(TokenTree::Group(args))); + lookahead = input.lookahead1(); + } + + if lookahead.peek(token::Brace) { + let brace_content; + let brace_token = braced!(brace_content in input); + let body: TokenStream = brace_content.parse()?; + let mut body = Group::new(Delimiter::Brace, body); + body.set_span(brace_token.span); + rules.extend(iter::once(TokenTree::Group(body))); + } else { + return Err(lookahead.error()); + } + + Ok(ItemMacro2 { + attrs, + vis, + macro_token, + ident, + rules, + }) + } + } + + impl Parse for ItemExternCrate { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemExternCrate { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + extern_token: input.parse()?, + crate_token: input.parse()?, + ident: { + if input.peek(Token![self]) { + input.call(Ident::parse_any)? + } else { + input.parse()? + } + }, + rename: { + if input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let rename: Ident = if input.peek(Token![_]) { + Ident::from(input.parse::<Token![_]>()?) + } else { + input.parse()? + }; + Some((as_token, rename)) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemUse { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemUse { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + use_token: input.parse()?, + leading_colon: input.parse()?, + tree: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for UseTree { + fn parse(input: ParseStream) -> Result<UseTree> { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![extern]) + { + let ident = input.call(Ident::parse_any)?; + if input.peek(Token![::]) { + Ok(UseTree::Path(UsePath { + ident, + colon2_token: input.parse()?, + tree: Box::new(input.parse()?), + })) + } else if input.peek(Token![as]) { + Ok(UseTree::Rename(UseRename { + ident, + as_token: input.parse()?, + rename: { + if input.peek(Ident) { + input.parse()? + } else if input.peek(Token![_]) { + Ident::from(input.parse::<Token![_]>()?) + } else { + return Err(input.error("expected identifier or underscore")); + } + }, + })) + } else { + Ok(UseTree::Name(UseName { ident })) + } + } else if lookahead.peek(Token![*]) { + Ok(UseTree::Glob(UseGlob { + star_token: input.parse()?, + })) + } else if lookahead.peek(token::Brace) { + let content; + Ok(UseTree::Group(UseGroup { + brace_token: braced!(content in input), + items: content.parse_terminated(UseTree::parse)?, + })) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ItemStatic { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemStatic { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + static_token: input.parse()?, + mutability: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemConst { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + const_token: input.parse()?, + ident: { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) || lookahead.peek(Token![_]) { + input.call(Ident::parse_any)? + } else { + return Err(lookahead.error()); + } + }, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemFn { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let constness: Option<Token![const]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = parse_fn_args(&content)?; + let variadic = inputs.last().as_ref().and_then(get_variadic); + + fn get_variadic(input: &&FnArg) -> Option<Variadic> { + if let FnArg::Typed(PatType { ty, .. }) = input { + if let Type::Verbatim(tokens) = &**ty { + if let Ok(dots) = parse2(tokens.clone()) { + return Some(Variadic { + attrs: Vec::new(), + dots, + }); + } + } + } + None + } + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ItemFn { + attrs: private::attrs(outer_attrs, inner_attrs), + vis, + sig: Signature { + constness, + asyncness, + unsafety, + abi, + fn_token, + ident, + paren_token, + inputs, + output, + variadic, + generics: Generics { + where_clause, + ..generics + }, + }, + block: Box::new(Block { brace_token, stmts }), + }) + } + } + + impl Parse for FnArg { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + + let ahead = input.fork(); + if let Ok(mut receiver) = ahead.parse::<Receiver>() { + if !ahead.peek(Token![:]) { + input.advance_to(&ahead); + receiver.attrs = attrs; + return Ok(FnArg::Receiver(receiver)); + } + } + + let mut typed = input.call(fn_arg_typed)?; + typed.attrs = attrs; + Ok(FnArg::Typed(typed)) + } + } + + impl Parse for Receiver { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Receiver { + attrs: Vec::new(), + reference: { + if input.peek(Token![&]) { + Some((input.parse()?, input.parse()?)) + } else { + None + } + }, + mutability: input.parse()?, + self_token: input.parse()?, + }) + } + } + + fn parse_fn_args(input: ParseStream) -> Result<Punctuated<FnArg, Token![,]>> { + let mut args = Punctuated::new(); + let mut has_receiver = false; + loop { + if input.is_empty() { + break; + } + let arg: FnArg = input.parse()?; + if let FnArg::Receiver(receiver) = &arg { + if has_receiver { + return Err(Error::new( + receiver.self_token.span, + "unexpected second method receiver", + )); + } else if !args.is_empty() { + return Err(Error::new( + receiver.self_token.span, + "unexpected method receiver", + )); + } + has_receiver = true; + } + args.push_value(arg); + if input.is_empty() { + break; + } + let comma: Token![,] = input.parse()?; + args.push_punct(comma); + } + Ok(args) + } + + fn fn_arg_typed(input: ParseStream) -> Result<PatType> { + // Hack to parse pre-2018 syntax in + // test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs + // because the rest of the test case is valuable. + if input.peek(Ident) && input.peek2(Token![<]) { + let span = input.fork().parse::<Ident>()?.span(); + return Ok(PatType { + attrs: Vec::new(), + pat: Box::new(Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + })), + colon_token: Token![:](span), + ty: input.parse()?, + }); + } + + Ok(PatType { + attrs: Vec::new(), + pat: input.parse()?, + colon_token: input.parse()?, + ty: Box::new(match input.parse::<Option<Token![...]>>()? { + Some(dot3) => { + let args = vec![ + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Alone)), + ]; + let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map( + |(mut arg, span)| { + arg.set_span(*span); + arg + }, + )); + Type::Verbatim(tokens) + } + None => input.parse()?, + }), + }) + } + + impl Parse for ItemMod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let mod_token: Token![mod] = input.parse()?; + let ident: Ident = input.parse()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![;]) { + Ok(ItemMod { + attrs: outer_attrs, + vis, + mod_token, + ident, + content: None, + semi: Some(input.parse()?), + }) + } else if lookahead.peek(token::Brace) { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemMod { + attrs: private::attrs(outer_attrs, inner_attrs), + vis, + mod_token, + ident, + content: Some((brace_token, items)), + semi: None, + }) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ItemForeignMod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let abi: Abi = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemForeignMod { + attrs: private::attrs(outer_attrs, inner_attrs), + abi, + brace_token, + items, + }) + } + } + + impl Parse for ForeignItem { + fn parse(input: ParseStream) -> Result<Self> { + let mut attrs = input.call(Attribute::parse_outer)?; + let ahead = input.fork(); + let vis: Visibility = ahead.parse()?; + + let lookahead = ahead.lookahead1(); + let mut item = if lookahead.peek(Token![fn]) { + input.parse().map(ForeignItem::Fn) + } else if lookahead.peek(Token![static]) { + input.parse().map(ForeignItem::Static) + } else if lookahead.peek(Token![type]) { + input.parse().map(ForeignItem::Type) + } else if vis.is_inherited() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(ForeignItem::Macro) + } else { + Err(lookahead.error()) + }?; + + { + let item_attrs = match &mut item { + ForeignItem::Fn(item) => &mut item.attrs, + ForeignItem::Static(item) => &mut item.attrs, + ForeignItem::Type(item) => &mut item.attrs, + ForeignItem::Macro(item) => &mut item.attrs, + ForeignItem::Verbatim(_) | ForeignItem::__Nonexhaustive => unreachable!(), + }; + attrs.extend(item_attrs.drain(..)); + *item_attrs = attrs; + } + + Ok(item) + } + } + + impl Parse for ForeignItemFn { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let mut inputs = Punctuated::new(); + let mut variadic = None; + while !content.is_empty() { + let attrs = content.call(Attribute::parse_outer)?; + + if let Some(dots) = content.parse()? { + variadic = Some(Variadic { attrs, dots }); + break; + } + + let mut arg = content.call(fn_arg_typed)?; + arg.attrs = attrs; + inputs.push_value(FnArg::Typed(arg)); + if content.is_empty() { + break; + } + + inputs.push_punct(content.parse()?); + } + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + let semi_token: Token![;] = input.parse()?; + + Ok(ForeignItemFn { + attrs, + vis, + sig: Signature { + constness: None, + asyncness: None, + unsafety: None, + abi: None, + fn_token, + ident, + paren_token, + inputs, + output, + variadic, + generics: Generics { + where_clause, + ..generics + }, + }, + semi_token, + }) + } + } + + impl Parse for ForeignItemStatic { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ForeignItemStatic { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + static_token: input.parse()?, + mutability: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ForeignItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ForeignItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ForeignItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(ForeignItemMacro { + attrs, + mac, + semi_token, + }) + } + } + + impl Parse for ItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + generics: { + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + generics + }, + eq_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + #[cfg(not(feature = "printing"))] + fn item_existential(input: ParseStream) -> Result<TokenStream> { + Err(input.error("existential type is not supported")) + } + + #[cfg(feature = "printing")] + fn item_existential(input: ParseStream) -> Result<TokenStream> { + use crate::attr::FilterAttrs; + use quote::{ToTokens, TokenStreamExt}; + + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let existential_token: existential = input.parse()?; + let type_token: Token![type] = input.parse()?; + let ident: Ident = input.parse()?; + + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + + let colon_token: Token![:] = input.parse()?; + + let mut bounds = Punctuated::new(); + while !input.peek(Token![;]) { + if !bounds.is_empty() { + bounds.push_punct(input.parse::<Token![+]>()?); + } + bounds.push_value(input.parse::<TypeParamBound>()?); + } + + let semi_token: Token![;] = input.parse()?; + + let mut tokens = TokenStream::new(); + tokens.append_all(attrs.outer()); + vis.to_tokens(&mut tokens); + existential_token.to_tokens(&mut tokens); + type_token.to_tokens(&mut tokens); + ident.to_tokens(&mut tokens); + generics.to_tokens(&mut tokens); + generics.where_clause.to_tokens(&mut tokens); + if !bounds.is_empty() { + colon_token.to_tokens(&mut tokens); + bounds.to_tokens(&mut tokens); + } + semi_token.to_tokens(&mut tokens); + Ok(tokens) + } + + impl Parse for ItemStruct { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let struct_token = input.parse::<Token![struct]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields, semi_token) = derive::parsing::data_struct(input)?; + Ok(ItemStruct { + attrs, + vis, + struct_token, + ident, + generics: Generics { + where_clause, + ..generics + }, + fields, + semi_token, + }) + } + } + + impl Parse for ItemEnum { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let enum_token = input.parse::<Token![enum]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, brace_token, variants) = derive::parsing::data_enum(input)?; + Ok(ItemEnum { + attrs, + vis, + enum_token, + ident, + generics: Generics { + where_clause, + ..generics + }, + brace_token, + variants, + }) + } + } + + impl Parse for ItemUnion { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let union_token = input.parse::<Token![union]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields) = derive::parsing::data_union(input)?; + Ok(ItemUnion { + attrs, + vis, + union_token, + ident, + generics: Generics { + where_clause, + ..generics + }, + fields, + }) + } + } + + fn parse_trait_or_trait_alias(input: ParseStream) -> Result<Item> { + let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; + let lookahead = input.lookahead1(); + if lookahead.peek(token::Brace) + || lookahead.peek(Token![:]) + || lookahead.peek(Token![where]) + { + let unsafety = None; + let auto_token = None; + parse_rest_of_trait( + input, + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + ) + .map(Item::Trait) + } else if lookahead.peek(Token![=]) { + parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) + .map(Item::TraitAlias) + } else { + Err(lookahead.error()) + } + } + + impl Parse for ItemTrait { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let auto_token: Option<Token![auto]> = input.parse()?; + let trait_token: Token![trait] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + parse_rest_of_trait( + input, + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + ) + } + } + + fn parse_rest_of_trait( + input: ParseStream, + attrs: Vec<Attribute>, + vis: Visibility, + unsafety: Option<Token![unsafe]>, + auto_token: Option<Token![auto]>, + trait_token: Token![trait], + ident: Ident, + mut generics: Generics, + ) -> Result<ItemTrait> { + let colon_token: Option<Token![:]> = input.parse()?; + + let mut supertraits = Punctuated::new(); + if colon_token.is_some() { + loop { + supertraits.push_value(input.parse()?); + if input.peek(Token![where]) || input.peek(token::Brace) { + break; + } + supertraits.push_punct(input.parse()?); + if input.peek(Token![where]) || input.peek(token::Brace) { + break; + } + } + } + + generics.where_clause = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemTrait { + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + colon_token, + supertraits, + brace_token, + items, + }) + } + + impl Parse for ItemTraitAlias { + fn parse(input: ParseStream) -> Result<Self> { + let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; + parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) + } + } + + fn parse_start_of_trait_alias( + input: ParseStream, + ) -> Result<(Vec<Attribute>, Visibility, Token![trait], Ident, Generics)> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let trait_token: Token![trait] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + Ok((attrs, vis, trait_token, ident, generics)) + } + + fn parse_rest_of_trait_alias( + input: ParseStream, + attrs: Vec<Attribute>, + vis: Visibility, + trait_token: Token![trait], + ident: Ident, + mut generics: Generics, + ) -> Result<ItemTraitAlias> { + let eq_token: Token![=] = input.parse()?; + + let mut bounds = Punctuated::new(); + loop { + if input.peek(Token![where]) || input.peek(Token![;]) { + break; + } + bounds.push_value(input.parse()?); + if input.peek(Token![where]) || input.peek(Token![;]) { + break; + } + bounds.push_punct(input.parse()?); + } + + generics.where_clause = input.parse()?; + let semi_token: Token![;] = input.parse()?; + + Ok(ItemTraitAlias { + attrs, + vis, + trait_token, + ident, + generics, + eq_token, + bounds, + semi_token, + }) + } + + impl Parse for TraitItem { + fn parse(input: ParseStream) -> Result<Self> { + let mut attrs = input.call(Attribute::parse_outer)?; + let ahead = input.fork(); + + let lookahead = ahead.lookahead1(); + let mut item = if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) { + input.parse().map(TraitItem::Const) + } else if lookahead.peek(Token![async]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(TraitItem::Method) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![async]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(TraitItem::Method) + } else if lookahead.peek(Token![type]) { + input.parse().map(TraitItem::Type) + } else if lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::]) + { + input.parse().map(TraitItem::Macro) + } else { + Err(lookahead.error()) + }?; + + { + let item_attrs = match &mut item { + TraitItem::Const(item) => &mut item.attrs, + TraitItem::Method(item) => &mut item.attrs, + TraitItem::Type(item) => &mut item.attrs, + TraitItem::Macro(item) => &mut item.attrs, + TraitItem::Verbatim(_) | TraitItem::__Nonexhaustive => unreachable!(), + }; + attrs.extend(item_attrs.drain(..)); + *item_attrs = attrs; + } + + Ok(item) + } + } + + impl Parse for TraitItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TraitItemConst { + attrs: input.call(Attribute::parse_outer)?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + default: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let default: Expr = input.parse()?; + Some((eq_token, default)) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + } + + impl Parse for TraitItemMethod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let constness: Option<Token![const]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = parse_fn_args(&content)?; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let lookahead = input.lookahead1(); + let (brace_token, inner_attrs, stmts, semi_token) = if lookahead.peek(token::Brace) { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + (Some(brace_token), inner_attrs, stmts, None) + } else if lookahead.peek(Token![;]) { + let semi_token: Token![;] = input.parse()?; + (None, Vec::new(), Vec::new(), Some(semi_token)) + } else { + return Err(lookahead.error()); + }; + + Ok(TraitItemMethod { + attrs: private::attrs(outer_attrs, inner_attrs), + sig: Signature { + constness, + asyncness, + unsafety, + abi, + fn_token, + ident, + paren_token, + inputs, + output, + variadic: None, + generics: Generics { + where_clause, + ..generics + }, + }, + default: brace_token.map(|brace_token| Block { brace_token, stmts }), + semi_token, + }) + } + } + + impl Parse for TraitItemType { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let type_token: Token![type] = input.parse()?; + let ident: Ident = input.parse()?; + let mut generics: Generics = input.parse()?; + let colon_token: Option<Token![:]> = input.parse()?; + + let mut bounds = Punctuated::new(); + if colon_token.is_some() { + while !input.peek(Token![where]) && !input.peek(Token![=]) && !input.peek(Token![;]) + { + if !bounds.is_empty() { + bounds.push_punct(input.parse()?); + } + bounds.push_value(input.parse()?); + } + } + + generics.where_clause = input.parse()?; + let default = if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let default: Type = input.parse()?; + Some((eq_token, default)) + } else { + None + }; + let semi_token: Token![;] = input.parse()?; + + Ok(TraitItemType { + attrs, + type_token, + ident, + generics, + colon_token, + bounds, + default, + semi_token, + }) + } + } + + impl Parse for TraitItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(TraitItemMacro { + attrs, + mac, + semi_token, + }) + } + } + + impl Parse for ItemImpl { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let defaultness: Option<Token![default]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let impl_token: Token![impl] = input.parse()?; + + let has_generics = input.peek(Token![<]) + && (input.peek2(Token![>]) + || input.peek2(Token![#]) + || (input.peek2(Ident) || input.peek2(Lifetime)) + && (input.peek3(Token![:]) + || input.peek3(Token![,]) + || input.peek3(Token![>]))); + let generics: Generics = if has_generics { + input.parse()? + } else { + Generics::default() + }; + + let trait_ = (|| -> Option<_> { + let ahead = input.fork(); + let polarity: Option<Token![!]> = ahead.parse().ok()?; + let path: Path = ahead.parse().ok()?; + let for_token: Token![for] = ahead.parse().ok()?; + input.advance_to(&ahead); + Some((polarity, path, for_token)) + })(); + let self_ty: Type = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemImpl { + attrs: private::attrs(outer_attrs, inner_attrs), + defaultness, + unsafety, + impl_token, + generics: Generics { + where_clause, + ..generics + }, + trait_, + self_ty: Box::new(self_ty), + brace_token, + items, + }) + } + } + + impl Parse for ImplItem { + fn parse(input: ParseStream) -> Result<Self> { + let mut attrs = input.call(Attribute::parse_outer)?; + let ahead = input.fork(); + let vis: Visibility = ahead.parse()?; + + let mut lookahead = ahead.lookahead1(); + let defaultness = if lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) { + let defaultness: Token![default] = ahead.parse()?; + lookahead = ahead.lookahead1(); + Some(defaultness) + } else { + None + }; + + let mut item = if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) { + input.parse().map(ImplItem::Const) + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(ImplItem::Method) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(ImplItem::Method) + } else if lookahead.peek(Token![type]) { + input.parse().map(ImplItem::Type) + } else if vis.is_inherited() && defaultness.is_none() && lookahead.peek(existential) { + input.call(item_existential).map(ImplItem::Verbatim) + } else if vis.is_inherited() + && defaultness.is_none() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(ImplItem::Macro) + } else { + Err(lookahead.error()) + }?; + + { + let item_attrs = match &mut item { + ImplItem::Const(item) => &mut item.attrs, + ImplItem::Method(item) => &mut item.attrs, + ImplItem::Type(item) => &mut item.attrs, + ImplItem::Macro(item) => &mut item.attrs, + ImplItem::Verbatim(_) => return Ok(item), + ImplItem::__Nonexhaustive => unreachable!(), + }; + attrs.extend(item_attrs.drain(..)); + *item_attrs = attrs; + } + + Ok(item) + } + } + + impl Parse for ImplItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ImplItemConst { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ImplItemMethod { + fn parse(input: ParseStream) -> Result<Self> { + let mut attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness: Option<Token![default]> = input.parse()?; + let constness: Option<Token![const]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = parse_fn_args(&content)?; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let block = if let Some(semi) = input.parse::<Option<Token![;]>>()? { + // Accept methods without a body in an impl block because + // rustc's *parser* does not reject them (the compilation error + // is emitted later than parsing) and it can be useful for macro + // DSLs. + let mut punct = Punct::new(';', Spacing::Alone); + punct.set_span(semi.span); + let tokens = TokenStream::from_iter(vec![TokenTree::Punct(punct)]); + Block { + brace_token: Brace::default(), + stmts: vec![Stmt::Item(Item::Verbatim(tokens))], + } + } else { + let content; + let brace_token = braced!(content in input); + attrs.extend(content.call(Attribute::parse_inner)?); + Block { + brace_token, + stmts: content.call(Block::parse_within)?, + } + }; + + Ok(ImplItemMethod { + attrs, + vis, + defaultness, + sig: Signature { + constness, + asyncness, + unsafety, + abi, + fn_token, + ident, + paren_token, + inputs, + output, + variadic: None, + generics: Generics { + where_clause, + ..generics + }, + }, + block, + }) + } + } + + impl Parse for ImplItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ImplItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + generics: { + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + generics + }, + eq_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ImplItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(ImplItemMacro { + attrs, + mac, + semi_token, + }) + } + } + + impl Visibility { + fn is_inherited(&self) -> bool { + match *self { + Visibility::Inherited => true, + _ => false, + } + } + } + + impl MacroDelimiter { + fn is_brace(&self) -> bool { + match *self { + MacroDelimiter::Brace(_) => true, + MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false, + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use crate::attr::FilterAttrs; + use crate::print::TokensOrDefault; + + 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((as_token, 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.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 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((brace, 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 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(fields) => { + self.generics.where_clause.to_tokens(tokens); + fields.to_tokens(tokens); + } + Fields::Unnamed(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 ItemTraitAlias { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.trait_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + 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((polarity, path, 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(paren) => { + paren.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens)); + } + MacroDelimiter::Brace(brace) => { + brace.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens)); + } + MacroDelimiter::Bracket(bracket) => { + bracket.surround(tokens, |tokens| self.mac.tokens.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.rules.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((eq_token, 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(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((eq_token, default)) = &self.default { + eq_token.to_tokens(tokens); + default.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 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); + if self.block.stmts.len() == 1 { + if let Stmt::Item(Item::Verbatim(verbatim)) = &self.block.stmts[0] { + if verbatim.to_string() == ";" { + verbatim.to_tokens(tokens); + return; + } + } + } + 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 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 ForeignItemFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.sig.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); + } + } + + fn has_variadic(inputs: &Punctuated<FnArg, Token![,]>) -> bool { + let last = match inputs.last() { + Some(last) => last, + None => return false, + }; + + let pat = match last { + FnArg::Typed(pat) => pat, + FnArg::Receiver(_) => return false, + }; + + let tokens = match pat.ty.as_ref() { + Type::Verbatim(tokens) => tokens, + _ => return false, + }; + + tokens.to_string() == "..." + } + + impl ToTokens for Signature { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.constness.to_tokens(tokens); + self.asyncness.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.abi.to_tokens(tokens); + self.fn_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.inputs.to_tokens(tokens); + if self.variadic.is_some() && !has_variadic(&self.inputs) { + if !self.inputs.empty_or_trailing() { + <Token![,]>::default().to_tokens(tokens); + } + self.variadic.to_tokens(tokens); + } + }); + self.output.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + } + } + + impl ToTokens for Receiver { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + if let Some((ampersand, lifetime)) = &self.reference { + ampersand.to_tokens(tokens); + lifetime.to_tokens(tokens); + } + self.mutability.to_tokens(tokens); + self.self_token.to_tokens(tokens); + } + } +} diff --git a/syn/src/keyword.rs b/syn/src/keyword.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/syn/src/keyword.rs diff --git a/syn/src/lib.rs b/syn/src/lib.rs new file mode 100644 index 0000000..0f71014 --- /dev/null +++ b/syn/src/lib.rs @@ -0,0 +1,947 @@ +//! 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 use in Rust procedural macros, but +//! contains some APIs that may be useful more generally. +//! +//! - **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`]. +//! +//! - **Derives** — Of particular interest to derive macros 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 user-defined trait. +//! +//! - **Parsing** — Parsing in Syn is built around [parser functions] with the +//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined +//! by Syn is individually parsable and may be used as a building block for +//! custom syntaxes, or you may dream up your own brand new syntax without +//! involving any of our syntax tree types. +//! +//! - **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 +//! [parser functions]: parse/index.html +//! +//! <br> +//! +//! # Example of a derive macro +//! +//! The canonical derive macro 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 = "1.0" +//! quote = "1.0" +//! +//! [lib] +//! proc-macro = true +//! ``` +//! +//! ``` +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use quote::quote; +//! use syn::{parse_macro_input, 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 = parse_macro_input!(input as DeriveInput); +//! +//! // Build the output, possibly using quasi-quotation +//! let expanded = quote! { +//! // ... +//! }; +//! +//! // Hand the output tokens back to the compiler +//! TokenStream::from(expanded) +//! } +//! ``` +//! +//! The [`heapsize`] example directory shows a complete working implementation +//! of a derive macro. It works on any Rust compiler 1.31+. 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 +//! +//! ``` +//! pub trait HeapSize { +//! /// Total number of bytes of heap memory owned by `self`. +//! fn heap_size_of_children(&self) -> usize; +//! } +//! ``` +//! +//! The derive macro allows users to write `#[derive(HeapSize)]` on data +//! structures in their program. +//! +//! ``` +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[derive(HeapSize)] +//! # }; +//! struct Demo<'a, T: ?Sized> { +//! a: Box<T>, +//! b: u8, +//! c: &'a str, +//! d: String, +//! } +//! ``` +//! +//! <p><br></p> +//! +//! # Spans and error reporting +//! +//! 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`. +//! +//! ``` +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[derive(HeapSize)] +//! # }; +//! struct Broken { +//! ok: String, +//! bad: std::thread::Thread, +//! } +//! ``` +//! +//! By tracking span information all the way through the expansion of a +//! procedural macro as shown in the `heapsize` 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` +//! ``` +//! +//! <br> +//! +//! # Parsing a custom syntax +//! +//! The [`lazy-static`] example directory shows the implementation of a +//! `functionlike!(...)` procedural macro in which the input tokens are parsed +//! using Syn's parsing API. +//! +//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static +//! +//! 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(); +//! | ^^^ +//! ``` +//! +//! <br> +//! +//! # Testing +//! +//! When testing macros, we often care not just that the macro can be used +//! successfully but also that when the macro is provided with invalid input it +//! produces maximally helpful error messages. Consider using the [`trybuild`] +//! crate to write tests for errors that are emitted by your macro or errors +//! detected by the Rust compiler in the expanded code following misuse of the +//! macro. Such tests help avoid regressions from later refactors that +//! mistakenly make an error no longer trigger or be less helpful than it used +//! to be. +//! +//! [`trybuild`]: https://github.com/dtolnay/trybuild +//! +//! <br> +//! +//! # 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/ +//! +//! <br> +//! +//! # 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 derive macro, 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. + +// Syn types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/syn/1.0.12")] +#![deny(clippy::all, clippy::pedantic)] +// Ignored clippy lints. +#![allow( + clippy::block_in_if_condition_stmt, + clippy::cognitive_complexity, + clippy::doc_markdown, + clippy::eval_order_dependence, + clippy::inherent_to_string, + clippy::large_enum_variant, + clippy::needless_doctest_main, + clippy::needless_pass_by_value, + clippy::never_loop, + clippy::suspicious_op_assign_impl, + clippy::too_many_arguments, + clippy::trivially_copy_pass_by_ref +)] +// Ignored clippy_pedantic lints. +#![allow( + clippy::cast_possible_truncation, + clippy::empty_enum, + clippy::if_not_else, + clippy::items_after_statements, + clippy::missing_errors_doc, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::shadow_unrelated, + clippy::similar_names, + clippy::single_match_else, + clippy::too_many_lines, + clippy::unseparated_literal_suffix, + clippy::use_self, + clippy::used_underscore_binding +)] + +#[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "proc-macro" +))] +extern crate proc_macro; +extern crate proc_macro2; +extern crate unicode_xid; + +#[cfg(feature = "printing")] +extern crate quote; + +#[cfg(any(feature = "full", feature = "derive"))] +#[macro_use] +mod macros; + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_use] +pub mod group; + +#[macro_use] +pub mod token; + +mod ident; +pub use crate::ident::Ident; + +#[cfg(any(feature = "full", feature = "derive"))] +mod attr; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::attr::{ + AttrStyle, Attribute, AttributeArgs, Meta, MetaList, MetaNameValue, NestedMeta, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod bigint; + +#[cfg(any(feature = "full", feature = "derive"))] +mod data; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::data::{ + Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted, + Visibility, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod expr; +#[cfg(feature = "full")] +pub use crate::expr::{ + Arm, FieldValue, GenericMethodArgument, Label, MethodTurbofish, RangeLimits, +}; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::expr::{ + Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, + ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprContinue, ExprField, ExprForLoop, + ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, + ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, + ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, Index, Member, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod generics; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::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 crate::generics::{ImplGenerics, Turbofish, TypeGenerics}; + +#[cfg(feature = "full")] +mod item; +#[cfg(feature = "full")] +pub use crate::item::{ + FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, + ImplItem, ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, Item, ItemConst, + ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2, ItemMod, + ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, + Signature, TraitItem, TraitItemConst, TraitItemMacro, TraitItemMethod, TraitItemType, UseGlob, + UseGroup, UseName, UsePath, UseRename, UseTree, +}; + +#[cfg(feature = "full")] +mod file; +#[cfg(feature = "full")] +pub use crate::file::File; + +mod lifetime; +pub use crate::lifetime::Lifetime; + +#[cfg(any(feature = "full", feature = "derive"))] +mod lit; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::lit::{ + Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr, StrStyle, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod mac; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::mac::{Macro, MacroDelimiter}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod derive; +#[cfg(feature = "derive")] +pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod op; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::op::{BinOp, UnOp}; + +#[cfg(feature = "full")] +mod stmt; +#[cfg(feature = "full")] +pub use crate::stmt::{Block, Local, Stmt}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod ty; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::ty::{ + Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer, + TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, + TypeTuple, Variadic, +}; + +#[cfg(feature = "full")] +mod pat; +#[cfg(feature = "full")] +pub use crate::pat::{ + FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference, + PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod path; +#[cfg(any(feature = "full", feature = "derive"))] +pub use crate::path::{ + AngleBracketedGenericArguments, Binding, Constraint, GenericArgument, + ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, +}; + +#[cfg(feature = "parsing")] +pub mod buffer; +#[cfg(feature = "parsing")] +pub mod ext; +pub mod punctuated; +#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))] +mod tt; + +// Not public API except the `parse_quote!` macro. +#[cfg(feature = "parsing")] +#[doc(hidden)] +pub mod parse_quote; + +// Not public API except the `parse_macro_input!` macro. +#[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "parsing", + feature = "proc-macro" +))] +#[doc(hidden)] +pub mod parse_macro_input; + +#[cfg(all(feature = "parsing", feature = "printing"))] +pub mod spanned; + +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`]: visit::Visit + /// + /// ``` + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait Visit<'ast> { + /// /* ... */ + /// + /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) { + /// visit_expr_binary(self, node); + /// } + /// + /// /* ... */ + /// # 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); + /// } + /// + /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary) + /// where + /// V: Visit<'ast> + ?Sized, + /// { + /// for attr in &node.attrs { + /// v.visit_attribute(attr); + /// } + /// v.visit_expr(&*node.left); + /// v.visit_bin_op(&node.op); + /// v.visit_expr(&*node.right); + /// } + /// + /// /* ... */ + /// ``` + /// + /// *This module is available if Syn is built with the `"visit"` feature.* + /// + /// <br> + /// + /// # Example + /// + /// This visitor will print the name of every freestanding function in the + /// syntax tree, including nested functions. + /// + /// ``` + /// // [dependencies] + /// // quote = "1.0" + /// // syn = { version = "1.0", features = ["full", "visit"] } + /// + /// use quote::quote; + /// use syn::visit::{self, Visit}; + /// use syn::{File, ItemFn}; + /// + /// struct FnVisitor; + /// + /// impl<'ast> Visit<'ast> for FnVisitor { + /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { + /// println!("Function with name={}", node.sig.ident); + /// + /// // Delegate to the default impl to visit any nested functions. + /// visit::visit_item_fn(self, node); + /// } + /// } + /// + /// fn main() { + /// let code = quote! { + /// pub fn f() { + /// fn g() {} + /// } + /// }; + /// + /// let syntax_tree: File = syn::parse2(code).unwrap(); + /// FnVisitor.visit_file(&syntax_tree); + /// } + /// ``` + /// + /// The `'ast` lifetime on the input references means that the syntax tree + /// outlives the complete recursive visit call, so the visitor is allowed to + /// hold on to references into the syntax tree. + /// + /// ``` + /// use quote::quote; + /// use syn::visit::{self, Visit}; + /// use syn::{File, ItemFn}; + /// + /// struct FnVisitor<'ast> { + /// functions: Vec<&'ast ItemFn>, + /// } + /// + /// impl<'ast> Visit<'ast> for FnVisitor<'ast> { + /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { + /// self.functions.push(node); + /// visit::visit_item_fn(self, node); + /// } + /// } + /// + /// fn main() { + /// let code = quote! { + /// pub fn f() { + /// fn g() {} + /// } + /// }; + /// + /// let syntax_tree: File = syn::parse2(code).unwrap(); + /// let mut visitor = FnVisitor { functions: Vec::new() }; + /// visitor.visit_file(&syntax_tree); + /// for f in visitor.functions { + /// println!("Function with name={}", f.sig.ident); + /// } + /// } + /// ``` + #[cfg(feature = "visit")] + #[rustfmt::skip] + 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`]: visit_mut::VisitMut + /// + /// ``` + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait VisitMut { + /// /* ... */ + /// + /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) { + /// visit_expr_binary_mut(self, node); + /// } + /// + /// /* ... */ + /// # 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); + /// } + /// + /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary) + /// where + /// V: VisitMut + ?Sized, + /// { + /// for attr in &mut node.attrs { + /// v.visit_attribute_mut(attr); + /// } + /// v.visit_expr_mut(&mut *node.left); + /// v.visit_bin_op_mut(&mut node.op); + /// v.visit_expr_mut(&mut *node.right); + /// } + /// + /// /* ... */ + /// ``` + /// + /// *This module is available if Syn is built with the `"visit-mut"` + /// feature.* + /// + /// <br> + /// + /// # Example + /// + /// This mut visitor replace occurrences of u256 suffixed integer literals + /// like `999u256` with a macro invocation `bigint::u256!(999)`. + /// + /// ``` + /// // [dependencies] + /// // quote = "1.0" + /// // syn = { version = "1.0", features = ["full", "visit-mut"] } + /// + /// use quote::quote; + /// use syn::visit_mut::{self, VisitMut}; + /// use syn::{parse_quote, Expr, File, Lit, LitInt}; + /// + /// struct BigintReplace; + /// + /// impl VisitMut for BigintReplace { + /// fn visit_expr_mut(&mut self, node: &mut Expr) { + /// if let Expr::Lit(expr) = &node { + /// if let Lit::Int(int) = &expr.lit { + /// if int.suffix() == "u256" { + /// let digits = int.base10_digits(); + /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap(); + /// *node = parse_quote!(bigint::u256!(#unsuffixed)); + /// return; + /// } + /// } + /// } + /// + /// // Delegate to the default impl to visit nested expressions. + /// visit_mut::visit_expr_mut(self, node); + /// } + /// } + /// + /// fn main() { + /// let code = quote! { + /// fn main() { + /// let _ = 999u256; + /// } + /// }; + /// + /// let mut syntax_tree: File = syn::parse2(code).unwrap(); + /// BigintReplace.visit_file_mut(&mut syntax_tree); + /// println!("{}", quote!(#syntax_tree)); + /// } + /// ``` + #[cfg(feature = "visit-mut")] + #[rustfmt::skip] + 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`]: fold::Fold + /// + /// ``` + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait Fold { + /// /* ... */ + /// + /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary { + /// fold_expr_binary(self, node) + /// } + /// + /// /* ... */ + /// # 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; + /// } + /// + /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary + /// where + /// V: Fold + ?Sized, + /// { + /// ExprBinary { + /// attrs: node + /// .attrs + /// .into_iter() + /// .map(|attr| v.fold_attribute(attr)) + /// .collect(), + /// left: Box::new(v.fold_expr(*node.left)), + /// op: v.fold_bin_op(node.op), + /// right: Box::new(v.fold_expr(*node.right)), + /// } + /// } + /// + /// /* ... */ + /// ``` + /// + /// *This module is available if Syn is built with the `"fold"` feature.* + /// + /// <br> + /// + /// # Example + /// + /// This fold inserts parentheses to fully parenthesizes any expression. + /// + /// ``` + /// // [dependencies] + /// // quote = "1.0" + /// // syn = { version = "1.0", features = ["fold", "full"] } + /// + /// use quote::quote; + /// use syn::fold::{fold_expr, Fold}; + /// use syn::{token, Expr, ExprParen}; + /// + /// struct ParenthesizeEveryExpr; + /// + /// impl Fold for ParenthesizeEveryExpr { + /// fn fold_expr(&mut self, expr: Expr) -> Expr { + /// Expr::Paren(ExprParen { + /// attrs: Vec::new(), + /// expr: Box::new(fold_expr(self, expr)), + /// paren_token: token::Paren::default(), + /// }) + /// } + /// } + /// + /// fn main() { + /// let code = quote! { a() + b(1) * c.d }; + /// let expr: Expr = syn::parse2(code).unwrap(); + /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr); + /// println!("{}", quote!(#parenthesized)); + /// + /// // Output: (((a)()) + (((b)((1))) * ((c).d))) + /// } + /// ``` + #[cfg(feature = "fold")] + #[rustfmt::skip] + pub mod fold; + + #[cfg(any(feature = "full", feature = "derive"))] + #[path = "../gen_helper.rs"] + mod helper; +} +pub use crate::gen::*; + +// Not public API. +#[doc(hidden)] +pub mod export; + +mod custom_keyword; +mod custom_punctuation; +mod sealed; + +#[cfg(feature = "parsing")] +mod lookahead; + +#[cfg(feature = "parsing")] +pub mod parse; + +mod span; + +#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] +mod print; + +mod thread; + +//////////////////////////////////////////////////////////////////////////////// + +#[allow(dead_code, non_camel_case_types)] +struct private; + +// https://github.com/rust-lang/rust/issues/62830 +#[cfg(feature = "parsing")] +mod rustdoc_workaround { + pub use crate::parse::{self as parse_module}; +} + +//////////////////////////////////////////////////////////////////////////////// + +mod error; +pub use crate::error::{Error, Result}; + +/// 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`]: parse2 +/// +/// *This function is available if Syn is built with both the `"parsing"` and +/// `"proc-macro"` features.* +/// +/// # Examples +/// +/// ``` +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use quote::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() +/// } +/// ``` +#[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "parsing", + feature = "proc-macro" +))] +pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> { + parse::Parser::parse(T::parse, tokens) +} + +/// 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 +/// body tokens of a [`Macro`] node. When in a procedural macro parsing the +/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] +/// instead. +/// +/// [`syn::parse`]: parse() +/// +/// *This function is available if Syn is built with the `"parsing"` feature.* +#[cfg(feature = "parsing")] +pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> { + parse::Parser::parse2(T::parse, tokens) +} + +/// 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 +/// +/// ``` +/// use syn::{Expr, Result}; +/// +/// fn run() -> Result<()> { +/// let code = "assert_eq!(u8::max_value(), 255)"; +/// let expr = syn::parse_str::<Expr>(code)?; +/// println!("{:#?}", expr); +/// Ok(()) +/// } +/// # +/// # run().unwrap(); +/// ``` +#[cfg(feature = "parsing")] +pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> { + parse::Parser::parse_str(T::parse, s) +} + +// 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 +/// +/// ```no_run +/// use std::error::Error; +/// use std::fs::File; +/// use std::io::Read; +/// +/// fn run() -> Result<(), Box<Error>> { +/// 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(()) +/// } +/// # +/// # run().unwrap(); +/// ``` +#[cfg(all(feature = "parsing", feature = "full"))] +pub fn parse_file(mut content: &str) -> Result<File> { + // Strip the BOM if it is present + const BOM: &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) +} diff --git a/syn/src/lifetime.rs b/syn/src/lifetime.rs new file mode 100644 index 0000000..d51c48e --- /dev/null +++ b/syn/src/lifetime.rs @@ -0,0 +1,140 @@ +use std::cmp::Ordering; +use std::fmt::{self, Display}; +use std::hash::{Hash, Hasher}; + +use proc_macro2::{Ident, Span}; + +#[cfg(feature = "parsing")] +use crate::lookahead; + +/// 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: Span, + pub ident: Ident, +} + +impl Lifetime { + /// # Panics + /// + /// Panics if the lifetime does not conform to the bulleted rules above. + /// + /// # Invocation + /// + /// ``` + /// # use proc_macro2::Span; + /// # use syn::Lifetime; + /// # + /// # fn f() -> Lifetime { + /// Lifetime::new("'a", Span::call_site()) + /// # } + /// ``` + pub fn new(symbol: &str, span: Span) -> Self { + if !symbol.starts_with('\'') { + panic!( + "lifetime name must start with apostrophe as in \"'a\", got {:?}", + symbol + ); + } + + if symbol == "'" { + panic!("lifetime name must not be empty"); + } + + if !crate::ident::xid_ok(&symbol[1..]) { + panic!("{:?} is not a valid lifetime name", symbol); + } + + Lifetime { + apostrophe: span, + ident: Ident::new(&symbol[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")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime { + match marker {} +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Lifetime { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + cursor + .lifetime() + .ok_or_else(|| cursor.error("expected lifetime")) + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::{Punct, Spacing, TokenStream}; + use quote::{ToTokens, TokenStreamExt}; + + impl ToTokens for Lifetime { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut apostrophe = Punct::new('\'', Spacing::Joint); + apostrophe.set_span(self.apostrophe); + tokens.append(apostrophe); + self.ident.to_tokens(tokens); + } + } +} diff --git a/syn/src/lit.rs b/syn/src/lit.rs new file mode 100644 index 0000000..abc4ec2 --- /dev/null +++ b/syn/src/lit.rs @@ -0,0 +1,1382 @@ +use proc_macro2::{Literal, Span}; +use std::fmt::{self, Display}; +use std::str::{self, FromStr}; + +#[cfg(feature = "printing")] +use proc_macro2::Ident; + +#[cfg(feature = "parsing")] +use proc_macro2::TokenStream; + +use proc_macro2::TokenTree; + +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +#[cfg(feature = "parsing")] +use crate::lookahead; +#[cfg(feature = "parsing")] +use crate::parse::{Parse, Parser}; +use crate::{Error, Result}; + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Lit #manual_extra_traits { + /// A UTF-8 string literal: `"foo"`. + Str(LitStr), + + /// A byte string literal: `b"foo"`. + ByteStr(LitByteStr), + + /// A byte literal: `b'f'`. + Byte(LitByte), + + /// A character literal: `'a'`. + Char(LitChar), + + /// An integer literal: `1` or `1u16`. + Int(LitInt), + + /// A floating point literal: `1f64` or `1.0e10f64`. + /// + /// Must be finite. May not be infinte or NaN. + Float(LitFloat), + + /// A boolean literal: `true` or `false`. + Bool(LitBool), + + /// A raw token literal not interpreted by Syn. + Verbatim(Literal), + } +} + +ast_struct! { + /// A UTF-8 string literal: `"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitStr #manual_extra_traits_debug { + repr: Box<LitStrRepr>, + } +} + +#[cfg_attr(feature = "clone-impls", derive(Clone))] +struct LitStrRepr { + token: Literal, + suffix: Box<str>, +} + +ast_struct! { + /// A byte string literal: `b"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitByteStr #manual_extra_traits_debug { + token: Literal, + } +} + +ast_struct! { + /// A byte literal: `b'f'`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitByte #manual_extra_traits_debug { + token: Literal, + } +} + +ast_struct! { + /// A character literal: `'a'`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitChar #manual_extra_traits_debug { + token: Literal, + } +} + +ast_struct! { + /// An integer literal: `1` or `1u16`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitInt #manual_extra_traits_debug { + repr: Box<LitIntRepr>, + } +} + +#[cfg_attr(feature = "clone-impls", derive(Clone))] +struct LitIntRepr { + token: Literal, + digits: Box<str>, + suffix: Box<str>, +} + +ast_struct! { + /// 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 struct LitFloat #manual_extra_traits_debug { + repr: Box<LitFloatRepr>, + } +} + +#[cfg_attr(feature = "clone-impls", derive(Clone))] +struct LitFloatRepr { + token: Literal, + digits: Box<str>, + suffix: Box<str>, +} + +ast_struct! { + /// A boolean literal: `true` or `false`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct LitBool #manual_extra_traits_debug { + pub value: bool, + pub span: Span, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Lit {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Lit { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Lit::Str(this), Lit::Str(other)) => this == other, + (Lit::ByteStr(this), Lit::ByteStr(other)) => this == other, + (Lit::Byte(this), Lit::Byte(other)) => this == other, + (Lit::Char(this), Lit::Char(other)) => this == other, + (Lit::Int(this), Lit::Int(other)) => this == other, + (Lit::Float(this), Lit::Float(other)) => this == other, + (Lit::Bool(this), Lit::Bool(other)) => this == other, + (Lit::Verbatim(this), Lit::Verbatim(other)) => this.to_string() == other.to_string(), + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Lit { + fn hash<H>(&self, hash: &mut H) + where + H: Hasher, + { + match self { + Lit::Str(lit) => { + hash.write_u8(0); + lit.hash(hash); + } + Lit::ByteStr(lit) => { + hash.write_u8(1); + lit.hash(hash); + } + Lit::Byte(lit) => { + hash.write_u8(2); + lit.hash(hash); + } + Lit::Char(lit) => { + hash.write_u8(3); + lit.hash(hash); + } + Lit::Int(lit) => { + hash.write_u8(4); + lit.hash(hash); + } + Lit::Float(lit) => { + hash.write_u8(5); + lit.hash(hash); + } + Lit::Bool(lit) => { + hash.write_u8(6); + lit.hash(hash); + } + Lit::Verbatim(lit) => { + hash.write_u8(7); + lit.to_string().hash(hash); + } + } + } +} + +impl LitStr { + pub fn new(value: &str, span: Span) -> Self { + let mut lit = Literal::string(value); + lit.set_span(span); + LitStr { + repr: Box::new(LitStrRepr { + token: lit, + suffix: Box::<str>::default(), + }), + } + } + + pub fn value(&self) -> String { + let (value, _) = value::parse_lit_str(&self.repr.token.to_string()); + String::from(value) + } + + /// 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`. + /// + /// # Example + /// + /// ``` + /// use proc_macro2::Span; + /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result}; + /// + /// // Parses the path from an attribute that looks like: + /// // + /// // #[path = "a::b::c"] + /// // + /// // or returns `None` if the input is some other attribute. + /// fn get_path(attr: &Attribute) -> Result<Option<Path>> { + /// if !attr.path.is_ident("path") { + /// return Ok(None); + /// } + /// + /// match attr.parse_meta()? { + /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => { + /// lit_str.parse().map(Some) + /// } + /// _ => { + /// let message = "expected #[path = \"...\"]"; + /// Err(Error::new_spanned(attr, message)) + /// } + /// } + /// } + /// ``` + #[cfg(feature = "parsing")] + pub fn parse<T: Parse>(&self) -> Result<T> { + self.parse_with(T::parse) + } + + /// Invoke parser on the content of this string literal. + /// + /// All spans in the syntax tree will point to the span of this `LitStr`. + /// + /// # Example + /// + /// ``` + /// # use proc_macro2::Span; + /// # use syn::{LitStr, Result}; + /// # + /// # fn main() -> Result<()> { + /// # let lit_str = LitStr::new("a::b::c", Span::call_site()); + /// # + /// # const IGNORE: &str = stringify! { + /// let lit_str: LitStr = /* ... */; + /// # }; + /// + /// // Parse a string literal like "a::b::c" into a Path, not allowing + /// // generic arguments on any of the path segments. + /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "parsing")] + pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> { + use proc_macro2::Group; + + // 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 &mut token { + TokenTree::Group(g) => { + let stream = respan_token_stream(g.stream(), span); + *g = Group::new(g.delimiter(), stream); + g.set_span(span); + } + other => other.set_span(span), + } + token + } + + // Parse string literal into a token stream with every span equal to the + // original literal's span. + let mut tokens = crate::parse_str(&self.value())?; + tokens = respan_token_stream(tokens, self.span()); + + parser.parse2(tokens) + } + + pub fn span(&self) -> Span { + self.repr.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.repr.token.set_span(span) + } + + pub fn suffix(&self) -> &str { + &self.repr.suffix + } +} + +impl LitByteStr { + pub fn new(value: &[u8], span: Span) -> Self { + let mut token = Literal::byte_string(value); + token.set_span(span); + LitByteStr { 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 } + } + + 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 } + } + + 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(repr: &str, span: Span) -> Self { + if let Some((digits, suffix)) = value::parse_lit_int(repr) { + let mut token = value::to_literal(repr); + token.set_span(span); + LitInt { + repr: Box::new(LitIntRepr { + token, + digits, + suffix, + }), + } + } else { + panic!("Not an integer literal: `{}`", repr); + } + } + + pub fn base10_digits(&self) -> &str { + &self.repr.digits + } + + /// Parses the literal into a selected number type. + /// + /// This is equivalent to `lit.base10_digits().parse()` except that the + /// resulting errors will be correctly spanned to point to the literal token + /// in the macro input. + /// + /// ``` + /// use syn::LitInt; + /// use syn::parse::{Parse, ParseStream, Result}; + /// + /// struct Port { + /// value: u16, + /// } + /// + /// impl Parse for Port { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let lit: LitInt = input.parse()?; + /// let value = lit.base10_parse::<u16>()?; + /// Ok(Port { value }) + /// } + /// } + /// ``` + pub fn base10_parse<N>(&self) -> Result<N> + where + N: FromStr, + N::Err: Display, + { + self.base10_digits() + .parse() + .map_err(|err| Error::new(self.span(), err)) + } + + pub fn suffix(&self) -> &str { + &self.repr.suffix + } + + pub fn span(&self) -> Span { + self.repr.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.repr.token.set_span(span) + } +} + +impl From<Literal> for LitInt { + fn from(token: Literal) -> Self { + let repr = token.to_string(); + if let Some((digits, suffix)) = value::parse_lit_int(&repr) { + LitInt { + repr: Box::new(LitIntRepr { + token, + digits, + suffix, + }), + } + } else { + panic!("Not an integer literal: `{}`", repr); + } + } +} + +impl Display for LitInt { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.repr.token.fmt(formatter) + } +} + +impl LitFloat { + pub fn new(repr: &str, span: Span) -> Self { + if let Some((digits, suffix)) = value::parse_lit_float(repr) { + let mut token = value::to_literal(repr); + token.set_span(span); + LitFloat { + repr: Box::new(LitFloatRepr { + token, + digits, + suffix, + }), + } + } else { + panic!("Not a float literal: `{}`", repr); + } + } + + pub fn base10_digits(&self) -> &str { + &self.repr.digits + } + + pub fn base10_parse<N>(&self) -> Result<N> + where + N: FromStr, + N::Err: Display, + { + self.base10_digits() + .parse() + .map_err(|err| Error::new(self.span(), err)) + } + + pub fn suffix(&self) -> &str { + &self.repr.suffix + } + + pub fn span(&self) -> Span { + self.repr.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.repr.token.set_span(span) + } +} + +impl From<Literal> for LitFloat { + fn from(token: Literal) -> Self { + let repr = token.to_string(); + if let Some((digits, suffix)) = value::parse_lit_float(&repr) { + LitFloat { + repr: Box::new(LitFloatRepr { + token, + digits, + suffix, + }), + } + } else { + panic!("Not a float literal: `{}`", repr); + } + } +} + +impl Display for LitFloat { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.repr.token.fmt(formatter) + } +} + +#[cfg(feature = "extra-traits")] +mod debug_impls { + use super::*; + use std::fmt::{self, Debug}; + + impl Debug for LitStr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitStr") + .field("token", &format_args!("{}", self.repr.token)) + .finish() + } + } + + impl Debug for LitByteStr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitByteStr") + .field("token", &format_args!("{}", self.token)) + .finish() + } + } + + impl Debug for LitByte { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitByte") + .field("token", &format_args!("{}", self.token)) + .finish() + } + } + + impl Debug for LitChar { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitChar") + .field("token", &format_args!("{}", self.token)) + .finish() + } + } + + impl Debug for LitInt { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitInt") + .field("token", &format_args!("{}", self.repr.token)) + .finish() + } + } + + impl Debug for LitFloat { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitFloat") + .field("token", &format_args!("{}", self.repr.token)) + .finish() + } + } + + impl Debug for LitBool { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("LitBool") + .field("value", &self.value) + .finish() + } + } +} + +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); + } + } + + #[cfg(feature = "parsing")] + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ty(marker: lookahead::TokenMarker) -> $ty { + match marker {} + } + }; +} + +lit_extra_traits!(LitStr, repr.token); +lit_extra_traits!(LitByteStr, token); +lit_extra_traits!(LitByte, token); +lit_extra_traits!(LitChar, token); +lit_extra_traits!(LitInt, repr.token); +lit_extra_traits!(LitFloat, repr.token); +lit_extra_traits!(LitBool, value); + +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), + } +} + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Lit(marker: lookahead::TokenMarker) -> Lit { + match marker {} +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Lit { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((lit, rest)) = cursor.literal() { + return Ok((Lit::new(lit), rest)); + } + while let Some((ident, rest)) = cursor.ident() { + let value = if ident == "true" { + true + } else if ident == "false" { + false + } else { + break; + }; + let lit_bool = LitBool { + value, + span: ident.span(), + }; + return Ok((Lit::Bool(lit_bool), rest)); + } + Err(cursor.error("expected literal")) + }) + } + } + + impl Parse for LitStr { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Str(lit) => Ok(lit), + _ => Err(head.error("expected string literal")), + } + } + } + + impl Parse for LitByteStr { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::ByteStr(lit) => Ok(lit), + _ => Err(head.error("expected byte string literal")), + } + } + } + + impl Parse for LitByte { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Byte(lit) => Ok(lit), + _ => Err(head.error("expected byte literal")), + } + } + } + + impl Parse for LitChar { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Char(lit) => Ok(lit), + _ => Err(head.error("expected character literal")), + } + } + } + + impl Parse for LitInt { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Int(lit) => Ok(lit), + _ => Err(head.error("expected integer literal")), + } + } + } + + impl Parse for LitFloat { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Float(lit) => Ok(lit), + _ => Err(head.error("expected floating point literal")), + } + } + } + + impl Parse for LitBool { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Bool(lit) => Ok(lit), + _ => Err(head.error("expected boolean literal")), + } + } + } +} + +#[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.repr.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.repr.token.to_tokens(tokens); + } + } + + impl ToTokens for LitFloat { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.repr.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)); + } + } +} + +mod value { + use super::*; + use crate::bigint::BigInt; + use proc_macro2::TokenStream; + use std::char; + use std::ops::{Index, RangeFrom}; + + impl Lit { + /// Interpret a Syn literal from a proc-macro2 literal. + pub fn new(token: Literal) -> Self { + let repr = token.to_string(); + + match byte(&repr, 0) { + b'"' | b'r' => { + let (_, suffix) = parse_lit_str(&repr); + return Lit::Str(LitStr { + repr: Box::new(LitStrRepr { token, suffix }), + }); + } + b'b' => match byte(&repr, 1) { + b'"' | b'r' => { + return Lit::ByteStr(LitByteStr { token }); + } + b'\'' => { + return Lit::Byte(LitByte { token }); + } + _ => {} + }, + b'\'' => { + return Lit::Char(LitChar { token }); + } + b'0'..=b'9' | b'-' => { + if !(repr.ends_with("f32") || repr.ends_with("f64")) { + if let Some((digits, suffix)) = parse_lit_int(&repr) { + return Lit::Int(LitInt { + repr: Box::new(LitIntRepr { + token, + digits, + suffix, + }), + }); + } + } + if let Some((digits, suffix)) = parse_lit_float(&repr) { + return Lit::Float(LitFloat { + repr: Box::new(LitFloatRepr { + token, + digits, + suffix, + }), + }); + } + } + b't' | b'f' => { + if repr == "true" || repr == "false" { + return Lit::Bool(LitBool { + value: repr == "true", + span: token.span(), + }); + } + } + _ => {} + } + + panic!("Unrecognized literal: `{}`", repr); + } + } + + /// 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') + } + + // Returns (content, suffix). + pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) { + 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 + #[allow(clippy::needless_continue)] + fn parse_lit_str_cooked(mut s: &str) -> (Box<str>, Box<str>) { + assert_eq!(byte(s, 0), b'"'); + s = &s[1..]; + + let mut content = 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 + } + }; + content.push(ch); + } + + assert!(s.starts_with('"')); + let content = content.into_boxed_str(); + let suffix = s[1..].to_owned().into_boxed_str(); + (content, suffix) + } + + fn parse_lit_str_raw(mut s: &str) -> (Box<str>, Box<str>) { + 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'#'); + } + + let content = s[pounds + 1..s.len() - pounds - 1] + .to_owned() + .into_boxed_str(); + let suffix = Box::<str>::default(); // todo + (content, suffix) + } + + 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 + #[allow(clippy::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'); + String::from(parse_lit_str_raw(&s[1..]).0).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); + } + } + + // Returns base 10 digits and suffix. + pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> { + let negative = byte(s, 0) == b'-'; + if negative { + s = &s[1..]; + } + + 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, + _ => return None, + }; + + let mut value = BigInt::new(); + loop { + let b = byte(s, 0); + let digit = match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' if base > 10 => b - b'a' + 10, + b'A'..=b'F' if base > 10 => b - b'A' + 10, + 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 { + return None; + } + + value *= base; + value += digit; + s = &s[1..]; + } + + let suffix = s; + if suffix.is_empty() || crate::ident::xid_ok(&suffix) { + let mut repr = value.to_string(); + if negative { + repr.insert(0, '-'); + } + Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str())) + } else { + None + } + } + + // Returns base 10 digits and suffix. + pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> { + // 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 start = (*bytes.get(0)? == b'-') as usize; + match bytes.get(start)? { + b'0'..=b'9' => {} + _ => return None, + } + + let mut read = start; + let mut write = start; + let mut has_dot = false; + let mut has_e = false; + let mut has_sign = false; + let mut has_exponent = false; + while read < bytes.len() { + match bytes[read] { + b'_' => { + // Don't increase write + read += 1; + continue; + } + b'0'..=b'9' => { + if has_e { + has_exponent = true; + } + bytes[write] = bytes[read]; + } + b'.' => { + if has_e || has_dot { + return None; + } + has_dot = true; + bytes[write] = b'.'; + } + b'e' | b'E' => { + if has_e { + return None; + } + has_e = true; + bytes[write] = b'e'; + } + b'-' | b'+' => { + if has_sign || has_exponent || !has_e { + return None; + } + has_sign = true; + if bytes[read] == b'-' { + bytes[write] = bytes[read]; + } else { + // Omit '+' + read += 1; + continue; + } + } + _ => break, + } + read += 1; + write += 1; + } + + if has_e && !has_exponent { + return None; + } + + let mut digits = String::from_utf8(bytes).unwrap(); + let suffix = digits.split_off(read); + digits.truncate(write); + if suffix.is_empty() || crate::ident::xid_ok(&suffix) { + Some((digits.into_boxed_str(), suffix.into_boxed_str())) + } else { + None + } + } + + 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/syn/src/lookahead.rs b/syn/src/lookahead.rs new file mode 100644 index 0000000..6a67909 --- /dev/null +++ b/syn/src/lookahead.rs @@ -0,0 +1,168 @@ +use std::cell::RefCell; + +use proc_macro2::{Delimiter, Span}; + +use crate::buffer::Cursor; +use crate::error::{self, Error}; +use crate::sealed::lookahead::Sealed; +use crate::span::IntoSpans; +use crate::token::Token; + +/// Support for checking the next token in a stream to decide how to parse. +/// +/// An important advantage over [`ParseStream::peek`] is that here we +/// automatically construct an appropriate error message based on the token +/// alternatives that get peeked. If you are producing your own error message, +/// go ahead and use `ParseStream::peek` instead. +/// +/// Use [`ParseStream::lookahead1`] to construct this object. +/// +/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek +/// [`ParseStream::lookahead1`]: crate::parse::ParseBuffer::lookahead1 +/// +/// # Example +/// +/// ``` +/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// // A generic parameter, a single one of the comma-separated elements inside +/// // angle brackets in: +/// // +/// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } +/// // +/// // On invalid input, lookahead gives us a reasonable error message. +/// // +/// // error: expected one of: identifier, lifetime, `const` +/// // | +/// // 5 | fn f<!Sized>() {} +/// // | ^ +/// enum GenericParam { +/// Type(TypeParam), +/// Lifetime(LifetimeDef), +/// Const(ConstParam), +/// } +/// +/// impl Parse for GenericParam { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(Ident) { +/// input.parse().map(GenericParam::Type) +/// } else if lookahead.peek(Lifetime) { +/// input.parse().map(GenericParam::Lifetime) +/// } else if lookahead.peek(Token![const]) { +/// input.parse().map(GenericParam::Const) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +pub struct Lookahead1<'a> { + scope: Span, + cursor: Cursor<'a>, + comparisons: RefCell<Vec<&'static str>>, +} + +pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 { + Lookahead1 { + scope, + cursor, + comparisons: RefCell::new(Vec::new()), + } +} + +fn peek_impl( + lookahead: &Lookahead1, + peek: fn(Cursor) -> bool, + display: fn() -> &'static str, +) -> bool { + if peek(lookahead.cursor) { + return true; + } + lookahead.comparisons.borrow_mut().push(display()); + false +} + +impl<'a> Lookahead1<'a> { + /// Looks at the next token in the parse stream to determine whether it + /// matches the requested type of token. + /// + /// # Syntax + /// + /// Note that this method does not use turbofish syntax. Pass the peek type + /// inside of parentheses. + /// + /// - `input.peek(Token![struct])` + /// - `input.peek(Token![==])` + /// - `input.peek(Ident)` *(does not accept keywords)* + /// - `input.peek(Ident::peek_any)` + /// - `input.peek(Lifetime)` + /// - `input.peek(token::Brace)` + pub fn peek<T: Peek>(&self, token: T) -> bool { + let _ = token; + peek_impl(self, T::Token::peek, T::Token::display) + } + + /// Triggers an error at the current position of the parse stream. + /// + /// The error message will identify all of the expected token types that + /// have been peeked against this lookahead instance. + pub fn error(self) -> Error { + let comparisons = self.comparisons.borrow(); + match comparisons.len() { + 0 => { + if self.cursor.eof() { + Error::new(self.scope, "unexpected end of input") + } else { + Error::new(self.cursor.span(), "unexpected token") + } + } + 1 => { + let message = format!("expected {}", comparisons[0]); + error::new_at(self.scope, self.cursor, message) + } + 2 => { + let message = format!("expected {} or {}", comparisons[0], comparisons[1]); + error::new_at(self.scope, self.cursor, message) + } + _ => { + let join = comparisons.join(", "); + let message = format!("expected one of: {}", join); + error::new_at(self.scope, self.cursor, message) + } + } + } +} + +/// Types that can be parsed by looking at just one token. +/// +/// Use [`ParseStream::peek`] to peek one of these types in a parse stream +/// without consuming it from the stream. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. +/// +/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek +pub trait Peek: Sealed { + // Not public API. + #[doc(hidden)] + type Token: Token; +} + +impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F { + type Token = T; +} + +pub enum TokenMarker {} + +impl<S> IntoSpans<S> for TokenMarker { + fn into_spans(self) -> S { + match self {} + } +} + +pub fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool { + cursor.group(delimiter).is_some() +} + +impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {} diff --git a/syn/src/mac.rs b/syn/src/mac.rs new file mode 100644 index 0000000..6c3dcae --- /dev/null +++ b/syn/src/mac.rs @@ -0,0 +1,239 @@ +use super::*; +use crate::token::{Brace, Bracket, Paren}; +use proc_macro2::TokenStream; +#[cfg(feature = "parsing")] +use proc_macro2::{Delimiter, Span, TokenTree}; + +#[cfg(feature = "parsing")] +use crate::parse::{Parse, ParseStream, Parser, Result}; +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +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 tokens: 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.tokens) == TokenStreamHelper(&other.tokens) + } +} + +#[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.tokens).hash(state); + } +} + +#[cfg(feature = "parsing")] +fn delimiter_span(delimiter: &MacroDelimiter) -> Span { + match delimiter { + MacroDelimiter::Paren(token) => token.span, + MacroDelimiter::Brace(token) => token.span, + MacroDelimiter::Bracket(token) => token.span, + } +} + +impl Macro { + /// Parse the tokens within the macro invocation's delimiters into a syntax + /// tree. + /// + /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it + /// produces a more useful span when `tokens` is empty. + /// + /// # Example + /// + /// ``` + /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token}; + /// use syn::ext::IdentExt; + /// use syn::parse::{Error, Parse, ParseStream, Result}; + /// use syn::punctuated::Punctuated; + /// + /// // The arguments expected by libcore's format_args macro, and as a + /// // result most other formatting and printing macros like println. + /// // + /// // println!("{} is {number:.prec$}", "x", prec=5, number=0.01) + /// struct FormatArgs { + /// format_string: Expr, + /// positional_args: Vec<Expr>, + /// named_args: Vec<(Ident, Expr)>, + /// } + /// + /// impl Parse for FormatArgs { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let format_string: Expr; + /// let mut positional_args = Vec::new(); + /// let mut named_args = Vec::new(); + /// + /// format_string = input.parse()?; + /// while !input.is_empty() { + /// input.parse::<Token![,]>()?; + /// if input.is_empty() { + /// break; + /// } + /// if input.peek(Ident::peek_any) && input.peek2(Token![=]) { + /// while !input.is_empty() { + /// let name: Ident = input.call(Ident::parse_any)?; + /// input.parse::<Token![=]>()?; + /// let value: Expr = input.parse()?; + /// named_args.push((name, value)); + /// if input.is_empty() { + /// break; + /// } + /// input.parse::<Token![,]>()?; + /// } + /// break; + /// } + /// positional_args.push(input.parse()?); + /// } + /// + /// Ok(FormatArgs { + /// format_string, + /// positional_args, + /// named_args, + /// }) + /// } + /// } + /// + /// // Extract the first argument, the format string literal, from an + /// // invocation of a formatting or printing macro. + /// fn get_format_string(m: &Macro) -> Result<LitStr> { + /// let args: FormatArgs = m.parse_body()?; + /// match args.format_string { + /// Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit), + /// other => { + /// // First argument was not a string literal expression. + /// // Maybe something like: println!(concat!(...), ...) + /// Err(Error::new_spanned(other, "format string must be a string literal")) + /// } + /// } + /// } + /// + /// fn main() { + /// let invocation = parse_quote! { + /// println!("{:?}", Instant::now()) + /// }; + /// let lit = get_format_string(&invocation).unwrap(); + /// assert_eq!(lit.value(), "{:?}"); + /// } + /// ``` + #[cfg(feature = "parsing")] + pub fn parse_body<T: Parse>(&self) -> Result<T> { + self.parse_body_with(T::parse) + } + + /// Parse the tokens within the macro invocation's delimiters using the + /// given parser. + #[cfg(feature = "parsing")] + pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> { + // TODO: see if we can get a group.span_close() span in here as the + // scope, rather than the span of the whole group. + let scope = delimiter_span(&self.delimiter); + crate::parse::parse_scoped(parser, scope, self.tokens.clone()) + } +} + +#[cfg(feature = "parsing")] +pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> { + input.step(|cursor| { + if let Some((TokenTree::Group(g), rest)) = cursor.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 Err(cursor.error("expected delimiter")); + } + }; + Ok(((delimiter, g.stream()), rest)) + } else { + Err(cursor.error("expected delimiter")) + } + }) +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Macro { + fn parse(input: ParseStream) -> Result<Self> { + let tokens; + Ok(Macro { + path: input.call(Path::parse_mod_style)?, + bang_token: input.parse()?, + delimiter: { + let (delimiter, content) = parse_delimiter(input)?; + tokens = content; + delimiter + }, + tokens, + }) + } + } +} + +#[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(paren) => { + paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens)); + } + MacroDelimiter::Brace(brace) => { + brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens)); + } + MacroDelimiter::Bracket(bracket) => { + bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens)); + } + } + } + } +} diff --git a/syn/src/macros.rs b/syn/src/macros.rs new file mode 100644 index 0000000..57091c0 --- /dev/null +++ b/syn/src/macros.rs @@ -0,0 +1,191 @@ +macro_rules! ast_struct { + ( + [$($attrs_pub:tt)*] + struct $name:ident #full $($rest:tt)* + ) => { + #[cfg(feature = "full")] + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* struct $name $($rest)* + + #[cfg(not(feature = "full"))] + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* struct $name { + _noconstruct: (), + } + + #[cfg(all(not(feature = "full"), feature = "printing"))] + impl ::quote::ToTokens for $name { + fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) { + unreachable!() + } + } + }; + + ( + [$($attrs_pub:tt)*] + struct $name:ident #manual_extra_traits $($rest:tt)* + ) => { + #[cfg_attr(feature = "extra-traits", derive(Debug))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* struct $name $($rest)* + }; + + ( + [$($attrs_pub:tt)*] + struct $name:ident #manual_extra_traits_debug $($rest:tt)* + ) => { + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* struct $name $($rest)* + }; + + ( + [$($attrs_pub:tt)*] + struct $name:ident $($rest:tt)* + ) => { + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* struct $name $($rest)* + }; + + ($($t:tt)*) => { + strip_attrs_pub!(ast_struct!($($t)*)); + }; +} + +macro_rules! ast_enum { + // Drop the `#no_visit` attribute, if present. + ( + [$($attrs_pub:tt)*] + enum $name:ident #no_visit $($rest:tt)* + ) => ( + ast_enum!([$($attrs_pub)*] enum $name $($rest)*); + ); + + ( + [$($attrs_pub:tt)*] + enum $name:ident #manual_extra_traits $($rest:tt)* + ) => ( + #[cfg_attr(feature = "extra-traits", derive(Debug))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* enum $name $($rest)* + ); + + ( + [$($attrs_pub:tt)*] + enum $name:ident $($rest:tt)* + ) => ( + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + $($attrs_pub)* enum $name $($rest)* + ); + + ($($t:tt)*) => { + strip_attrs_pub!(ast_enum!($($t)*)); + }; +} + +macro_rules! ast_enum_of_structs { + ( + $(#[$enum_attr:meta])* + $pub:ident $enum:ident $name:ident #$tag:ident $body:tt + $($remaining:tt)* + ) => { + ast_enum!($(#[$enum_attr])* $pub $enum $name #$tag $body); + ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*); + }; + + ( + $(#[$enum_attr:meta])* + $pub:ident $enum:ident $name:ident $body:tt + $($remaining:tt)* + ) => { + ast_enum!($(#[$enum_attr])* $pub $enum $name $body); + ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*); + }; +} + +macro_rules! ast_enum_of_structs_impl { + ( + $pub:ident $enum:ident $name:ident { + $( + $(#[$variant_attr:meta])* + $variant:ident $( ($member:ident) )*, + )* + } + + $($remaining:tt)* + ) => { + check_keyword_matches!(pub $pub); + check_keyword_matches!(enum $enum); + + $($( + ast_enum_from_struct!($name::$variant, $member); + )*)* + + #[cfg(feature = "printing")] + generate_to_tokens! { + $($remaining)* + () + tokens + $name { $($variant $($member)*,)* } + } + }; +} + +macro_rules! ast_enum_from_struct { + // No From<TokenStream> for verbatim variants. + ($name:ident::Verbatim, $member:ident) => {}; + + ($name:ident::$variant:ident, $member:ident) => { + impl From<$member> for $name { + fn from(e: $member) -> $name { + $name::$variant(e) + } + } + }; +} + +#[cfg(feature = "printing")] +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 $member:ident, $($next:tt)*}) => { + generate_to_tokens!( + ($($arms)* $name::$variant(_e) => _e.to_tokens($tokens),) + $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)* + } + } + } + }; +} + +macro_rules! strip_attrs_pub { + ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => { + check_keyword_matches!(pub $pub); + + $mac!([$(#[$m])* $pub] $($t)*); + }; +} + +macro_rules! check_keyword_matches { + (struct struct) => {}; + (enum enum) => {}; + (pub pub) => {}; +} diff --git a/syn/src/op.rs b/syn/src/op.rs new file mode 100644 index 0000000..49fb853 --- /dev/null +++ b/syn/src/op.rs @@ -0,0 +1,231 @@ +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 crate::parse::{Parse, ParseStream, Result}; + + fn parse_binop(input: ParseStream) -> Result<BinOp> { + if input.peek(Token![&&]) { + input.parse().map(BinOp::And) + } else if input.peek(Token![||]) { + input.parse().map(BinOp::Or) + } else if input.peek(Token![<<]) { + input.parse().map(BinOp::Shl) + } else if input.peek(Token![>>]) { + input.parse().map(BinOp::Shr) + } else if input.peek(Token![==]) { + input.parse().map(BinOp::Eq) + } else if input.peek(Token![<=]) { + input.parse().map(BinOp::Le) + } else if input.peek(Token![!=]) { + input.parse().map(BinOp::Ne) + } else if input.peek(Token![>=]) { + input.parse().map(BinOp::Ge) + } else if input.peek(Token![+]) { + input.parse().map(BinOp::Add) + } else if input.peek(Token![-]) { + input.parse().map(BinOp::Sub) + } else if input.peek(Token![*]) { + input.parse().map(BinOp::Mul) + } else if input.peek(Token![/]) { + input.parse().map(BinOp::Div) + } else if input.peek(Token![%]) { + input.parse().map(BinOp::Rem) + } else if input.peek(Token![^]) { + input.parse().map(BinOp::BitXor) + } else if input.peek(Token![&]) { + input.parse().map(BinOp::BitAnd) + } else if input.peek(Token![|]) { + input.parse().map(BinOp::BitOr) + } else if input.peek(Token![<]) { + input.parse().map(BinOp::Lt) + } else if input.peek(Token![>]) { + input.parse().map(BinOp::Gt) + } else { + Err(input.error("expected binary operator")) + } + } + + impl Parse for BinOp { + #[cfg(not(feature = "full"))] + fn parse(input: ParseStream) -> Result<Self> { + parse_binop(input) + } + + #[cfg(feature = "full")] + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![+=]) { + input.parse().map(BinOp::AddEq) + } else if input.peek(Token![-=]) { + input.parse().map(BinOp::SubEq) + } else if input.peek(Token![*=]) { + input.parse().map(BinOp::MulEq) + } else if input.peek(Token![/=]) { + input.parse().map(BinOp::DivEq) + } else if input.peek(Token![%=]) { + input.parse().map(BinOp::RemEq) + } else if input.peek(Token![^=]) { + input.parse().map(BinOp::BitXorEq) + } else if input.peek(Token![&=]) { + input.parse().map(BinOp::BitAndEq) + } else if input.peek(Token![|=]) { + input.parse().map(BinOp::BitOrEq) + } else if input.peek(Token![<<=]) { + input.parse().map(BinOp::ShlEq) + } else if input.peek(Token![>>=]) { + input.parse().map(BinOp::ShrEq) + } else { + parse_binop(input) + } + } + } + + impl Parse for UnOp { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![*]) { + input.parse().map(UnOp::Deref) + } else if lookahead.peek(Token![!]) { + input.parse().map(UnOp::Not) + } else if lookahead.peek(Token![-]) { + input.parse().map(UnOp::Neg) + } else { + Err(lookahead.error()) + } + } + } +} + +#[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(t) => t.to_tokens(tokens), + BinOp::Sub(t) => t.to_tokens(tokens), + BinOp::Mul(t) => t.to_tokens(tokens), + BinOp::Div(t) => t.to_tokens(tokens), + BinOp::Rem(t) => t.to_tokens(tokens), + BinOp::And(t) => t.to_tokens(tokens), + BinOp::Or(t) => t.to_tokens(tokens), + BinOp::BitXor(t) => t.to_tokens(tokens), + BinOp::BitAnd(t) => t.to_tokens(tokens), + BinOp::BitOr(t) => t.to_tokens(tokens), + BinOp::Shl(t) => t.to_tokens(tokens), + BinOp::Shr(t) => t.to_tokens(tokens), + BinOp::Eq(t) => t.to_tokens(tokens), + BinOp::Lt(t) => t.to_tokens(tokens), + BinOp::Le(t) => t.to_tokens(tokens), + BinOp::Ne(t) => t.to_tokens(tokens), + BinOp::Ge(t) => t.to_tokens(tokens), + BinOp::Gt(t) => t.to_tokens(tokens), + BinOp::AddEq(t) => t.to_tokens(tokens), + BinOp::SubEq(t) => t.to_tokens(tokens), + BinOp::MulEq(t) => t.to_tokens(tokens), + BinOp::DivEq(t) => t.to_tokens(tokens), + BinOp::RemEq(t) => t.to_tokens(tokens), + BinOp::BitXorEq(t) => t.to_tokens(tokens), + BinOp::BitAndEq(t) => t.to_tokens(tokens), + BinOp::BitOrEq(t) => t.to_tokens(tokens), + BinOp::ShlEq(t) => t.to_tokens(tokens), + BinOp::ShrEq(t) => t.to_tokens(tokens), + } + } + } + + impl ToTokens for UnOp { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + UnOp::Deref(t) => t.to_tokens(tokens), + UnOp::Not(t) => t.to_tokens(tokens), + UnOp::Neg(t) => t.to_tokens(tokens), + } + } + } +} diff --git a/syn/src/parse.rs b/syn/src/parse.rs new file mode 100644 index 0000000..96eecce --- /dev/null +++ b/syn/src/parse.rs @@ -0,0 +1,1222 @@ +//! Parsing interface for parsing a token stream into a syntax tree node. +//! +//! Parsing in Syn is built on parser functions that take in a [`ParseStream`] +//! and produce a [`Result<T>`] where `T` is some syntax tree node. Underlying +//! these parser functions is a lower level mechanism built around the +//! [`Cursor`] type. `Cursor` is a cheaply copyable cursor over a range of +//! tokens in a token stream. +//! +//! [`ParseStream`]: type.ParseStream.html +//! [`Result<T>`]: type.Result.html +//! [`Cursor`]: ../buffer/index.html +//! +//! # Example +//! +//! Here is a snippet of parsing code to get a feel for the style of the +//! library. We define data structures for a subset of Rust syntax including +//! enums (not shown) and structs, then provide implementations of the [`Parse`] +//! trait to parse these syntax tree data structures from a token stream. +//! +//! Once `Parse` impls have been defined, they can be called conveniently from a +//! procedural macro through [`parse_macro_input!`] as shown at the bottom of +//! the snippet. If the caller provides syntactically invalid input to the +//! procedural macro, they will receive a helpful compiler error message +//! pointing out the exact token that triggered the failure to parse. +//! +//! [`parse_macro_input!`]: ../macro.parse_macro_input.html +//! +//! ``` +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use syn::{braced, parse_macro_input, token, Field, Ident, Result, Token}; +//! use syn::parse::{Parse, ParseStream}; +//! use syn::punctuated::Punctuated; +//! +//! enum Item { +//! Struct(ItemStruct), +//! Enum(ItemEnum), +//! } +//! +//! struct ItemStruct { +//! struct_token: Token![struct], +//! ident: Ident, +//! brace_token: token::Brace, +//! fields: Punctuated<Field, Token![,]>, +//! } +//! # +//! # enum ItemEnum {} +//! +//! impl Parse for Item { +//! fn parse(input: ParseStream) -> Result<Self> { +//! let lookahead = input.lookahead1(); +//! if lookahead.peek(Token![struct]) { +//! input.parse().map(Item::Struct) +//! } else if lookahead.peek(Token![enum]) { +//! input.parse().map(Item::Enum) +//! } else { +//! Err(lookahead.error()) +//! } +//! } +//! } +//! +//! impl Parse for ItemStruct { +//! fn parse(input: ParseStream) -> Result<Self> { +//! let content; +//! Ok(ItemStruct { +//! struct_token: input.parse()?, +//! ident: input.parse()?, +//! brace_token: braced!(content in input), +//! fields: content.parse_terminated(Field::parse_named)?, +//! }) +//! } +//! } +//! # +//! # impl Parse for ItemEnum { +//! # fn parse(input: ParseStream) -> Result<Self> { +//! # unimplemented!() +//! # } +//! # } +//! +//! # const IGNORE: &str = stringify! { +//! #[proc_macro] +//! # }; +//! pub fn my_macro(tokens: TokenStream) -> TokenStream { +//! let input = parse_macro_input!(tokens as Item); +//! +//! /* ... */ +//! # "".parse().unwrap() +//! } +//! ``` +//! +//! # 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 [`Parse`] trait, which includes most types in Syn. +//! +//! [`syn::parse`]: ../fn.parse.html +//! [`syn::parse2`]: ../fn.parse2.html +//! [`syn::parse_str`]: ../fn.parse_str.html +//! [`Parse`]: trait.Parse.html +//! +//! ``` +//! use syn::Type; +//! +//! # fn run_parser() -> syn::Result<()> { +//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?; +//! # Ok(()) +//! # } +//! # +//! # 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 `Parse` trait is not implemented in these cases because there is no good +//! behavior to consider the default. +//! +//! ```compile_fail +//! # extern crate proc_macro; +//! # +//! # use syn::punctuated::Punctuated; +//! # use syn::{PathSegment, Result, Token}; +//! # +//! # fn f(tokens: proc_macro::TokenStream) -> Result<()> { +//! # +//! // Can't parse `Punctuated` without knowing whether trailing punctuation +//! // should be allowed in this context. +//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?; +//! # +//! # Ok(()) +//! # } +//! ``` +//! +//! In these cases the types provide a choice of parser functions rather than a +//! single `Parse` implementation, and those parser functions can be invoked +//! through the [`Parser`] trait. +//! +//! [`Parser`]: trait.Parser.html +//! +//! ``` +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use syn::parse::Parser; +//! use syn::punctuated::Punctuated; +//! use syn::{Attribute, Expr, PathSegment, Result, Token}; +//! +//! fn call_some_parser_methods(input: TokenStream) -> Result<()> { +//! // Parse a nonempty sequence of path segments separated by `::` punctuation +//! // with no trailing punctuation. +//! let tokens = input.clone(); +//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty; +//! let _path = parser.parse(tokens)?; +//! +//! // Parse a possibly empty sequence of expressions terminated by commas with +//! // an optional trailing punctuation. +//! let tokens = input.clone(); +//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated; +//! let _args = parser.parse(tokens)?; +//! +//! // Parse zero or more outer attributes but not inner attributes. +//! let tokens = input.clone(); +//! let parser = Attribute::parse_outer; +//! let _attrs = parser.parse(tokens)?; +//! +//! Ok(()) +//! } +//! ``` +//! +//! --- +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +#[path = "discouraged.rs"] +pub mod discouraged; + +use std::cell::Cell; +use std::fmt::{self, Debug, Display}; +use std::marker::PhantomData; +use std::mem; +use std::ops::Deref; +use std::rc::Rc; +use std::str::FromStr; + +#[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "proc-macro" +))] +use crate::proc_macro; +use proc_macro2::{self, Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree}; + +use crate::buffer::{Cursor, TokenBuffer}; +use crate::error; +use crate::lookahead; +use crate::punctuated::Punctuated; +use crate::token::Token; + +pub use crate::error::{Error, Result}; +pub use crate::lookahead::{Lookahead1, Peek}; + +/// Parsing interface implemented by all types that can be parsed in a default +/// way from a token stream. +pub trait Parse: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +/// Input to a Syn parser function. +/// +/// See the methods of this type under the documentation of [`ParseBuffer`]. For +/// an overview of parsing in Syn, refer to the [module documentation]. +/// +/// [module documentation]: self +pub type ParseStream<'a> = &'a ParseBuffer<'a>; + +/// Cursor position within a buffered token stream. +/// +/// This type is more commonly used through the type alias [`ParseStream`] which +/// is an alias for `&ParseBuffer`. +/// +/// `ParseStream` is the input type for all parser functions in Syn. They have +/// the signature `fn(ParseStream) -> Result<T>`. +/// +/// ## Calling a parser function +/// +/// There is no public way to construct a `ParseBuffer`. Instead, if you are +/// looking to invoke a parser function that requires `ParseStream` as input, +/// you will need to go through one of the public parsing entry points. +/// +/// - The [`parse_macro_input!`] macro if parsing input of a procedural macro; +/// - One of [the `syn::parse*` functions][syn-parse]; or +/// - A method of the [`Parser`] trait. +/// +/// [syn-parse]: index.html#the-synparse-functions +pub struct ParseBuffer<'a> { + scope: Span, + // Instead of Cell<Cursor<'a>> so that ParseBuffer<'a> is covariant in 'a. + // The rest of the code in this module needs to be careful that only a + // cursor derived from this `cell` is ever assigned to this `cell`. + // + // Cell<Cursor<'a>> cannot be covariant in 'a because then we could take a + // ParseBuffer<'a>, upcast to ParseBuffer<'short> for some lifetime shorter + // than 'a, and then assign a Cursor<'short> into the Cell. + // + // By extension, it would not be safe to expose an API that accepts a + // Cursor<'a> and trusts that it lives as long as the cursor currently in + // the cell. + cell: Cell<Cursor<'static>>, + marker: PhantomData<Cursor<'a>>, + unexpected: Cell<Option<Rc<Cell<Unexpected>>>>, +} + +impl<'a> Drop for ParseBuffer<'a> { + fn drop(&mut self) { + if !self.is_empty() { + let (inner, old_span) = inner_unexpected(self); + if old_span.is_none() { + inner.set(Unexpected::Some(self.cursor().span())); + } + } + } +} + +impl<'a> Display for ParseBuffer<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.cursor().token_stream(), f) + } +} + +impl<'a> Debug for ParseBuffer<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.cursor().token_stream(), f) + } +} + +/// Cursor state associated with speculative parsing. +/// +/// This type is the input of the closure provided to [`ParseStream::step`]. +/// +/// [`ParseStream::step`]: ParseBuffer::step +/// +/// # Example +/// +/// ``` +/// use proc_macro2::TokenTree; +/// use syn::Result; +/// use syn::parse::ParseStream; +/// +/// // This function advances the stream past the next occurrence of `@`. If +/// // no `@` is present in the stream, the stream position is unchanged and +/// // an error is returned. +/// fn skip_past_next_at(input: ParseStream) -> Result<()> { +/// input.step(|cursor| { +/// let mut rest = *cursor; +/// while let Some((tt, next)) = rest.token_tree() { +/// match &tt { +/// TokenTree::Punct(punct) if punct.as_char() == '@' => { +/// return Ok(((), next)); +/// } +/// _ => rest = next, +/// } +/// } +/// Err(cursor.error("no `@` was found after this point")) +/// }) +/// } +/// # +/// # fn remainder_after_skipping_past_next_at( +/// # input: ParseStream, +/// # ) -> Result<proc_macro2::TokenStream> { +/// # skip_past_next_at(input)?; +/// # input.parse() +/// # } +/// # +/// # use syn::parse::Parser; +/// # let remainder = remainder_after_skipping_past_next_at +/// # .parse_str("a @ b c") +/// # .unwrap(); +/// # assert_eq!(remainder.to_string(), "b c"); +/// ``` +#[derive(Copy, Clone)] +pub struct StepCursor<'c, 'a> { + scope: Span, + // This field is covariant in 'c. + cursor: Cursor<'c>, + // This field is contravariant in 'c. Together these make StepCursor + // invariant in 'c. Also covariant in 'a. The user cannot cast 'c to a + // different lifetime but can upcast into a StepCursor with a shorter + // lifetime 'a. + // + // As long as we only ever construct a StepCursor for which 'c outlives 'a, + // this means if ever a StepCursor<'c, 'a> exists we are guaranteed that 'c + // outlives 'a. + marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>, +} + +impl<'c, 'a> Deref for StepCursor<'c, 'a> { + type Target = Cursor<'c>; + + fn deref(&self) -> &Self::Target { + &self.cursor + } +} + +impl<'c, 'a> StepCursor<'c, 'a> { + /// Triggers an error at the current position of the parse stream. + /// + /// The `ParseStream::step` invocation will return this same error without + /// advancing the stream state. + pub fn error<T: Display>(self, message: T) -> Error { + error::new_at(self.scope, self.cursor, message) + } +} + +pub(crate) fn advance_step_cursor<'c, 'a>(proof: StepCursor<'c, 'a>, to: Cursor<'c>) -> Cursor<'a> { + // Refer to the comments within the StepCursor definition. We use the + // fact that a StepCursor<'c, 'a> exists as proof that 'c outlives 'a. + // Cursor is covariant in its lifetime parameter so we can cast a + // Cursor<'c> to one with the shorter lifetime Cursor<'a>. + let _ = proof; + unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) } +} + +pub(crate) fn new_parse_buffer( + scope: Span, + cursor: Cursor, + unexpected: Rc<Cell<Unexpected>>, +) -> ParseBuffer { + ParseBuffer { + scope, + // See comment on `cell` in the struct definition. + cell: Cell::new(unsafe { mem::transmute::<Cursor, Cursor<'static>>(cursor) }), + marker: PhantomData, + unexpected: Cell::new(Some(unexpected)), + } +} + +#[derive(Clone)] +pub(crate) enum Unexpected { + None, + Some(Span), + Chain(Rc<Cell<Unexpected>>), +} + +impl Default for Unexpected { + fn default() -> Self { + Unexpected::None + } +} + +// We call this on Cell<Unexpected> and Cell<Option<T>> where temporarily +// swapping in a None is cheap. +fn cell_clone<T: Default + Clone>(cell: &Cell<T>) -> T { + let prev = cell.take(); + let ret = prev.clone(); + cell.set(prev); + ret +} + +fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<Span>) { + let mut unexpected = get_unexpected(buffer); + loop { + match cell_clone(&unexpected) { + Unexpected::None => return (unexpected, None), + Unexpected::Some(span) => return (unexpected, Some(span)), + Unexpected::Chain(next) => unexpected = next, + } + } +} + +pub(crate) fn get_unexpected(buffer: &ParseBuffer) -> Rc<Cell<Unexpected>> { + cell_clone(&buffer.unexpected).unwrap() +} + +impl<'a> ParseBuffer<'a> { + /// Parses a syntax tree node of type `T`, advancing the position of our + /// parse stream past it. + pub fn parse<T: Parse>(&self) -> Result<T> { + T::parse(self) + } + + /// Calls the given parser function to parse a syntax tree node of type `T` + /// from this stream. + /// + /// # Example + /// + /// The parser below invokes [`Attribute::parse_outer`] to parse a vector of + /// zero or more outer attributes. + /// + /// [`Attribute::parse_outer`]: crate::Attribute::parse_outer + /// + /// ``` + /// use syn::{Attribute, Ident, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a unit struct with attributes. + /// // + /// // #[path = "s.tmpl"] + /// // struct S; + /// struct UnitStruct { + /// attrs: Vec<Attribute>, + /// struct_token: Token![struct], + /// name: Ident, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for UnitStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(UnitStruct { + /// attrs: input.call(Attribute::parse_outer)?, + /// struct_token: input.parse()?, + /// name: input.parse()?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// ``` + pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> { + function(self) + } + + /// Looks at the next token in the parse stream to determine whether it + /// matches the requested type of token. + /// + /// Does not advance the position of the parse stream. + /// + /// # Syntax + /// + /// Note that this method does not use turbofish syntax. Pass the peek type + /// inside of parentheses. + /// + /// - `input.peek(Token![struct])` + /// - `input.peek(Token![==])` + /// - `input.peek(Ident)` *(does not accept keywords)* + /// - `input.peek(Ident::peek_any)` + /// - `input.peek(Lifetime)` + /// - `input.peek(token::Brace)` + /// + /// # Example + /// + /// In this example we finish parsing the list of supertraits when the next + /// token in the input is either `where` or an opening curly brace. + /// + /// ``` + /// use syn::{braced, token, Generics, Ident, Result, Token, TypeParamBound}; + /// use syn::parse::{Parse, ParseStream}; + /// use syn::punctuated::Punctuated; + /// + /// // Parses a trait definition containing no associated items. + /// // + /// // trait Marker<'de, T>: A + B<'de> where Box<T>: Clone {} + /// struct MarkerTrait { + /// trait_token: Token![trait], + /// ident: Ident, + /// generics: Generics, + /// colon_token: Option<Token![:]>, + /// supertraits: Punctuated<TypeParamBound, Token![+]>, + /// brace_token: token::Brace, + /// } + /// + /// impl Parse for MarkerTrait { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let trait_token: Token![trait] = input.parse()?; + /// let ident: Ident = input.parse()?; + /// let mut generics: Generics = input.parse()?; + /// let colon_token: Option<Token![:]> = input.parse()?; + /// + /// let mut supertraits = Punctuated::new(); + /// if colon_token.is_some() { + /// loop { + /// supertraits.push_value(input.parse()?); + /// if input.peek(Token![where]) || input.peek(token::Brace) { + /// break; + /// } + /// supertraits.push_punct(input.parse()?); + /// } + /// } + /// + /// generics.where_clause = input.parse()?; + /// let content; + /// let empty_brace_token = braced!(content in input); + /// + /// Ok(MarkerTrait { + /// trait_token, + /// ident, + /// generics, + /// colon_token, + /// supertraits, + /// brace_token: empty_brace_token, + /// }) + /// } + /// } + /// ``` + pub fn peek<T: Peek>(&self, token: T) -> bool { + let _ = token; + T::Token::peek(self.cursor()) + } + + /// Looks at the second-next token in the parse stream. + /// + /// This is commonly useful as a way to implement contextual keywords. + /// + /// # Example + /// + /// This example needs to use `peek2` because the symbol `union` is not a + /// keyword in Rust. We can't use just `peek` and decide to parse a union if + /// the very next token is `union`, because someone is free to write a `mod + /// union` and a macro invocation that looks like `union::some_macro! { ... + /// }`. In other words `union` is a contextual keyword. + /// + /// ``` + /// use syn::{Ident, ItemUnion, Macro, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses either a union or a macro invocation. + /// enum UnionOrMacro { + /// // union MaybeUninit<T> { uninit: (), value: T } + /// Union(ItemUnion), + /// // lazy_static! { ... } + /// Macro(Macro), + /// } + /// + /// impl Parse for UnionOrMacro { + /// fn parse(input: ParseStream) -> Result<Self> { + /// if input.peek(Token![union]) && input.peek2(Ident) { + /// input.parse().map(UnionOrMacro::Union) + /// } else { + /// input.parse().map(UnionOrMacro::Macro) + /// } + /// } + /// } + /// ``` + pub fn peek2<T: Peek>(&self, token: T) -> bool { + let _ = token; + self.cursor().skip().map_or(false, T::Token::peek) + } + + /// Looks at the third-next token in the parse stream. + pub fn peek3<T: Peek>(&self, token: T) -> bool { + let _ = token; + self.cursor() + .skip() + .and_then(Cursor::skip) + .map_or(false, T::Token::peek) + } + + /// Parses zero or more occurrences of `T` separated by punctuation of type + /// `P`, with optional trailing punctuation. + /// + /// Parsing continues until the end of this parse stream. The entire content + /// of this parse stream must consist of `T` and `P`. + /// + /// # Example + /// + /// ``` + /// # use quote::quote; + /// # + /// use syn::{parenthesized, token, Ident, Result, Token, Type}; + /// use syn::parse::{Parse, ParseStream}; + /// use syn::punctuated::Punctuated; + /// + /// // Parse a simplified tuple struct syntax like: + /// // + /// // struct S(A, B); + /// struct TupleStruct { + /// struct_token: Token![struct], + /// ident: Ident, + /// paren_token: token::Paren, + /// fields: Punctuated<Type, Token![,]>, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for TupleStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let content; + /// Ok(TupleStruct { + /// struct_token: input.parse()?, + /// ident: input.parse()?, + /// paren_token: parenthesized!(content in input), + /// fields: content.parse_terminated(Type::parse)?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// # + /// # let input = quote! { + /// # struct S(A, B); + /// # }; + /// # syn::parse2::<TupleStruct>(input).unwrap(); + /// ``` + pub fn parse_terminated<T, P: Parse>( + &self, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Punctuated<T, P>> { + Punctuated::parse_terminated_with(self, parser) + } + + /// Returns whether there are tokens remaining in this stream. + /// + /// This method returns true at the end of the content of a set of + /// delimiters, as well as at the very end of the complete macro input. + /// + /// # Example + /// + /// ``` + /// use syn::{braced, token, Ident, Item, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a Rust `mod m { ... }` containing zero or more items. + /// struct Mod { + /// mod_token: Token![mod], + /// name: Ident, + /// brace_token: token::Brace, + /// items: Vec<Item>, + /// } + /// + /// impl Parse for Mod { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let content; + /// Ok(Mod { + /// mod_token: input.parse()?, + /// name: input.parse()?, + /// brace_token: braced!(content in input), + /// items: { + /// let mut items = Vec::new(); + /// while !content.is_empty() { + /// items.push(content.parse()?); + /// } + /// items + /// }, + /// }) + /// } + /// } + /// ``` + pub fn is_empty(&self) -> bool { + self.cursor().eof() + } + + /// Constructs a helper for peeking at the next token in this stream and + /// building an error message if it is not one of a set of expected tokens. + /// + /// # Example + /// + /// ``` + /// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // A generic parameter, a single one of the comma-separated elements inside + /// // angle brackets in: + /// // + /// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } + /// // + /// // On invalid input, lookahead gives us a reasonable error message. + /// // + /// // error: expected one of: identifier, lifetime, `const` + /// // | + /// // 5 | fn f<!Sized>() {} + /// // | ^ + /// enum GenericParam { + /// Type(TypeParam), + /// Lifetime(LifetimeDef), + /// Const(ConstParam), + /// } + /// + /// impl Parse for GenericParam { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let lookahead = input.lookahead1(); + /// if lookahead.peek(Ident) { + /// input.parse().map(GenericParam::Type) + /// } else if lookahead.peek(Lifetime) { + /// input.parse().map(GenericParam::Lifetime) + /// } else if lookahead.peek(Token![const]) { + /// input.parse().map(GenericParam::Const) + /// } else { + /// Err(lookahead.error()) + /// } + /// } + /// } + /// ``` + pub fn lookahead1(&self) -> Lookahead1<'a> { + lookahead::new(self.scope, self.cursor()) + } + + /// Forks a parse stream so that parsing tokens out of either the original + /// or the fork does not advance the position of the other. + /// + /// # Performance + /// + /// Forking a parse stream is a cheap fixed amount of work and does not + /// involve copying token buffers. Where you might hit performance problems + /// is if your macro ends up parsing a large amount of content more than + /// once. + /// + /// ``` + /// # use syn::{Expr, Result}; + /// # use syn::parse::ParseStream; + /// # + /// # fn bad(input: ParseStream) -> Result<Expr> { + /// // Do not do this. + /// if input.fork().parse::<Expr>().is_ok() { + /// return input.parse::<Expr>(); + /// } + /// # unimplemented!() + /// # } + /// ``` + /// + /// As a rule, avoid parsing an unbounded amount of tokens out of a forked + /// parse stream. Only use a fork when the amount of work performed against + /// the fork is small and bounded. + /// + /// When complex speculative parsing against the forked stream is + /// unavoidable, use [`parse::discouraged::Speculative`] to advance the + /// original stream once the fork's parse is determined to have been + /// successful. + /// + /// For a lower level way to perform speculative parsing at the token level, + /// consider using [`ParseStream::step`] instead. + /// + /// [`parse::discouraged::Speculative`]: discouraged::Speculative + /// [`ParseStream::step`]: ParseBuffer::step + /// + /// # Example + /// + /// The parse implementation shown here parses possibly restricted `pub` + /// visibilities. + /// + /// - `pub` + /// - `pub(crate)` + /// - `pub(self)` + /// - `pub(super)` + /// - `pub(in some::path)` + /// + /// To handle the case of visibilities inside of tuple structs, the parser + /// needs to distinguish parentheses that specify visibility restrictions + /// from parentheses that form part of a tuple type. + /// + /// ``` + /// # struct A; + /// # struct B; + /// # struct C; + /// # + /// struct S(pub(crate) A, pub (B, C)); + /// ``` + /// + /// In this example input the first tuple struct element of `S` has + /// `pub(crate)` visibility while the second tuple struct element has `pub` + /// visibility; the parentheses around `(B, C)` are part of the type rather + /// than part of a visibility restriction. + /// + /// The parser uses a forked parse stream to check the first token inside of + /// parentheses after the `pub` keyword. This is a small bounded amount of + /// work performed against the forked parse stream. + /// + /// ``` + /// use syn::{parenthesized, token, Ident, Path, Result, Token}; + /// use syn::ext::IdentExt; + /// use syn::parse::{Parse, ParseStream}; + /// + /// struct PubVisibility { + /// pub_token: Token![pub], + /// restricted: Option<Restricted>, + /// } + /// + /// struct Restricted { + /// paren_token: token::Paren, + /// in_token: Option<Token![in]>, + /// path: Path, + /// } + /// + /// impl Parse for PubVisibility { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let pub_token: Token![pub] = input.parse()?; + /// + /// if input.peek(token::Paren) { + /// let ahead = input.fork(); + /// let mut content; + /// parenthesized!(content in ahead); + /// + /// if content.peek(Token![crate]) + /// || content.peek(Token![self]) + /// || content.peek(Token![super]) + /// { + /// return Ok(PubVisibility { + /// pub_token, + /// restricted: Some(Restricted { + /// paren_token: parenthesized!(content in input), + /// in_token: None, + /// path: Path::from(content.call(Ident::parse_any)?), + /// }), + /// }); + /// } else if content.peek(Token![in]) { + /// return Ok(PubVisibility { + /// pub_token, + /// restricted: Some(Restricted { + /// paren_token: parenthesized!(content in input), + /// in_token: Some(content.parse()?), + /// path: content.call(Path::parse_mod_style)?, + /// }), + /// }); + /// } + /// } + /// + /// Ok(PubVisibility { + /// pub_token, + /// restricted: None, + /// }) + /// } + /// } + /// ``` + pub fn fork(&self) -> Self { + ParseBuffer { + scope: self.scope, + cell: self.cell.clone(), + marker: PhantomData, + // Not the parent's unexpected. Nothing cares whether the clone + // parses all the way unless we `advance_to`. + unexpected: Cell::new(Some(Rc::new(Cell::new(Unexpected::None)))), + } + } + + /// Triggers an error at the current position of the parse stream. + /// + /// # Example + /// + /// ``` + /// use syn::{Expr, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Some kind of loop: `while` or `for` or `loop`. + /// struct Loop { + /// expr: Expr, + /// } + /// + /// impl Parse for Loop { + /// fn parse(input: ParseStream) -> Result<Self> { + /// if input.peek(Token![while]) + /// || input.peek(Token![for]) + /// || input.peek(Token![loop]) + /// { + /// Ok(Loop { + /// expr: input.parse()?, + /// }) + /// } else { + /// Err(input.error("expected some kind of loop")) + /// } + /// } + /// } + /// ``` + pub fn error<T: Display>(&self, message: T) -> Error { + error::new_at(self.scope, self.cursor(), message) + } + + /// Speculatively parses tokens from this parse stream, advancing the + /// position of this stream only if parsing succeeds. + /// + /// This is a powerful low-level API used for defining the `Parse` impls of + /// the basic built-in token types. It is not something that will be used + /// widely outside of the Syn codebase. + /// + /// # Example + /// + /// ``` + /// use proc_macro2::TokenTree; + /// use syn::Result; + /// use syn::parse::ParseStream; + /// + /// // This function advances the stream past the next occurrence of `@`. If + /// // no `@` is present in the stream, the stream position is unchanged and + /// // an error is returned. + /// fn skip_past_next_at(input: ParseStream) -> Result<()> { + /// input.step(|cursor| { + /// let mut rest = *cursor; + /// while let Some((tt, next)) = rest.token_tree() { + /// match &tt { + /// TokenTree::Punct(punct) if punct.as_char() == '@' => { + /// return Ok(((), next)); + /// } + /// _ => rest = next, + /// } + /// } + /// Err(cursor.error("no `@` was found after this point")) + /// }) + /// } + /// # + /// # fn remainder_after_skipping_past_next_at( + /// # input: ParseStream, + /// # ) -> Result<proc_macro2::TokenStream> { + /// # skip_past_next_at(input)?; + /// # input.parse() + /// # } + /// # + /// # use syn::parse::Parser; + /// # let remainder = remainder_after_skipping_past_next_at + /// # .parse_str("a @ b c") + /// # .unwrap(); + /// # assert_eq!(remainder.to_string(), "b c"); + /// ``` + pub fn step<F, R>(&self, function: F) -> Result<R> + where + F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, + { + // Since the user's function is required to work for any 'c, we know + // that the Cursor<'c> they return is either derived from the input + // StepCursor<'c, 'a> or from a Cursor<'static>. + // + // It would not be legal to write this function without the invariant + // lifetime 'c in StepCursor<'c, 'a>. If this function were written only + // in terms of 'a, the user could take our ParseBuffer<'a>, upcast it to + // a ParseBuffer<'short> which some shorter lifetime than 'a, invoke + // `step` on their ParseBuffer<'short> with a closure that returns + // Cursor<'short>, and we would wrongly write that Cursor<'short> into + // the Cell intended to hold Cursor<'a>. + // + // In some cases it may be necessary for R to contain a Cursor<'a>. + // Within Syn we solve this using `advance_step_cursor` which uses the + // existence of a StepCursor<'c, 'a> as proof that it is safe to cast + // from Cursor<'c> to Cursor<'a>. If needed outside of Syn, it would be + // safe to expose that API as a method on StepCursor. + let (node, rest) = function(StepCursor { + scope: self.scope, + cursor: self.cell.get(), + marker: PhantomData, + })?; + self.cell.set(rest); + Ok(node) + } + + /// Returns the `Span` of the next token in the parse stream, or + /// `Span::call_site()` if this parse stream has completely exhausted its + /// input `TokenStream`. + pub fn span(&self) -> Span { + let cursor = self.cursor(); + if cursor.eof() { + self.scope + } else { + crate::buffer::open_span_of_group(cursor) + } + } + + /// Provides low-level access to the token representation underlying this + /// parse stream. + /// + /// Cursors are immutable so no operations you perform against the cursor + /// will affect the state of this parse stream. + pub fn cursor(&self) -> Cursor<'a> { + self.cell.get() + } + + fn check_unexpected(&self) -> Result<()> { + match inner_unexpected(self).1 { + Some(span) => Err(Error::new(span, "unexpected token")), + None => Ok(()), + } + } +} + +impl<T: Parse> Parse for Box<T> { + fn parse(input: ParseStream) -> Result<Self> { + input.parse().map(Box::new) + } +} + +impl<T: Parse + Token> Parse for Option<T> { + fn parse(input: ParseStream) -> Result<Self> { + if T::peek(input.cursor()) { + Ok(Some(input.parse()?)) + } else { + Ok(None) + } + } +} + +impl Parse for TokenStream { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| Ok((cursor.token_stream(), Cursor::empty()))) + } +} + +impl Parse for TokenTree { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.token_tree() { + Some((tt, rest)) => Ok((tt, rest)), + None => Err(cursor.error("expected token tree")), + }) + } +} + +impl Parse for Group { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + for delim in &[Delimiter::Parenthesis, Delimiter::Brace, Delimiter::Bracket] { + if let Some((inside, span, rest)) = cursor.group(*delim) { + let mut group = Group::new(*delim, inside.token_stream()); + group.set_span(span); + return Ok((group, rest)); + } + } + Err(cursor.error("expected group token")) + }) + } +} + +impl Parse for Punct { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.punct() { + Some((punct, rest)) => Ok((punct, rest)), + None => Err(cursor.error("expected punctuation token")), + }) + } +} + +impl Parse for Literal { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.literal() { + Some((literal, rest)) => Ok((literal, rest)), + None => Err(cursor.error("expected 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]: self +/// +/// *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. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the stream, an error is returned. + fn parse2(self, tokens: TokenStream) -> Result<Self::Output>; + + /// Parse tokens of source code into the chosen syntax tree node. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the stream, an error is returned. + /// + /// *This method is available if Syn is built with both the `"parsing"` and + /// `"proc-macro"` features.* + #[cfg(all( + not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))), + feature = "proc-macro" + ))] + fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> { + self.parse2(proc_macro2::TokenStream::from(tokens)) + } + + /// Parse a string of Rust code into the chosen syntax tree node. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the string, an error is returned. + /// + /// # 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> { + self.parse2(proc_macro2::TokenStream::from_str(s)?) + } + + // Not public API. + #[doc(hidden)] + fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> { + let _ = scope; + self.parse2(tokens) + } + + // Not public API. + #[doc(hidden)] + fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> { + input.parse().and_then(|tokens| self.parse2(tokens)) + } +} + +fn tokens_to_parse_buffer(tokens: &TokenBuffer) -> ParseBuffer { + let scope = Span::call_site(); + let cursor = tokens.begin(); + let unexpected = Rc::new(Cell::new(Unexpected::None)); + new_parse_buffer(scope, cursor, unexpected) +} + +impl<F, T> Parser for F +where + F: FnOnce(ParseStream) -> Result<T>, +{ + type Output = T; + + fn parse2(self, tokens: TokenStream) -> Result<T> { + let buf = TokenBuffer::new2(tokens); + let state = tokens_to_parse_buffer(&buf); + let node = self(&state)?; + state.check_unexpected()?; + if state.is_empty() { + Ok(node) + } else { + Err(state.error("unexpected token")) + } + } + + #[doc(hidden)] + fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> { + let buf = TokenBuffer::new2(tokens); + let cursor = buf.begin(); + let unexpected = Rc::new(Cell::new(Unexpected::None)); + let state = new_parse_buffer(scope, cursor, unexpected); + let node = self(&state)?; + state.check_unexpected()?; + if state.is_empty() { + Ok(node) + } else { + Err(state.error("unexpected token")) + } + } + + #[doc(hidden)] + fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> { + self(input) + } +} + +pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> { + f.__parse_scoped(scope, tokens) +} + +pub(crate) fn parse_stream<F: Parser>(f: F, input: ParseStream) -> Result<F::Output> { + f.__parse_stream(input) +} + +/// An empty syntax tree node that consumes no tokens when parsed. +/// +/// This is useful for attribute macros that want to ensure they are not +/// provided any attribute args. +/// +/// ``` +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::parse_macro_input; +/// use syn::parse::Nothing; +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_attribute] +/// # }; +/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { +/// parse_macro_input!(args as Nothing); +/// +/// /* ... */ +/// # "".parse().unwrap() +/// } +/// ``` +/// +/// ```text +/// error: unexpected token +/// --> src/main.rs:3:19 +/// | +/// 3 | #[my_attr(asdf)] +/// | ^^^^ +/// ``` +pub struct Nothing; + +impl Parse for Nothing { + fn parse(_input: ParseStream) -> Result<Self> { + Ok(Nothing) + } +} diff --git a/syn/src/parse_macro_input.rs b/syn/src/parse_macro_input.rs new file mode 100644 index 0000000..d6e0725 --- /dev/null +++ b/syn/src/parse_macro_input.rs @@ -0,0 +1,110 @@ +/// Parse the input TokenStream of a macro, triggering a compile error if the +/// tokens fail to parse. +/// +/// Refer to the [`parse` module] documentation for more details about parsing +/// in Syn. +/// +/// [`parse` module]: crate::rustdoc_workaround::parse_module +/// +/// <br> +/// +/// # Intended usage +/// +/// This macro must be called from a function that returns +/// `proc_macro::TokenStream`. Usually this will be your proc macro entry point, +/// the function that has the #\[proc_macro\] / #\[proc_macro_derive\] / +/// #\[proc_macro_attribute\] attribute. +/// +/// ``` +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::{parse_macro_input, Result}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// struct MyMacroInput { +/// /* ... */ +/// } +/// +/// impl Parse for MyMacroInput { +/// fn parse(input: ParseStream) -> Result<Self> { +/// /* ... */ +/// # Ok(MyMacroInput {}) +/// } +/// } +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro] +/// # }; +/// pub fn my_macro(tokens: TokenStream) -> TokenStream { +/// let input = parse_macro_input!(tokens as MyMacroInput); +/// +/// /* ... */ +/// # "".parse().unwrap() +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! parse_macro_input { + ($tokenstream:ident as $ty:ty) => { + match $crate::parse_macro_input::parse::<$ty>($tokenstream) { + $crate::export::Ok(data) => data, + $crate::export::Err(err) => { + return $crate::export::TokenStream::from(err.to_compile_error()); + } + } + }; + ($tokenstream:ident) => { + parse_macro_input!($tokenstream as _) + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Can parse any type that implements Parse. + +use crate::parse::{Parse, ParseStream, Parser, Result}; +use proc_macro::TokenStream; + +// Not public API. +#[doc(hidden)] +pub fn parse<T: ParseMacroInput>(token_stream: TokenStream) -> Result<T> { + T::parse.parse(token_stream) +} + +// Not public API. +#[doc(hidden)] +pub trait ParseMacroInput: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +impl<T: Parse> ParseMacroInput for T { + fn parse(input: ParseStream) -> Result<Self> { + <T as Parse>::parse(input) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Any other types that we want `parse_macro_input!` to be able to parse. + +#[cfg(any(feature = "full", feature = "derive"))] +use crate::AttributeArgs; + +#[cfg(any(feature = "full", feature = "derive"))] +impl ParseMacroInput for AttributeArgs { + fn parse(input: ParseStream) -> Result<Self> { + let mut metas = Vec::new(); + + loop { + if input.is_empty() { + break; + } + let value = input.parse()?; + metas.push(value); + if input.is_empty() { + break; + } + input.parse::<Token![,]>()?; + } + + Ok(metas) + } +} diff --git a/syn/src/parse_quote.rs b/syn/src/parse_quote.rs new file mode 100644 index 0000000..18a47b9 --- /dev/null +++ b/syn/src/parse_quote.rs @@ -0,0 +1,131 @@ +/// 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/1.0/quote/index.html +/// +/// The return type can be any syntax tree node that implements the [`Parse`] +/// trait. +/// +/// [`Parse`]: parse::Parse +/// +/// ``` +/// use quote::quote; +/// use syn::{parse_quote, 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. +/// +/// ``` +/// use syn::{parse_quote, 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(type_param) = param { +/// type_param.bounds.push(parse_quote!(HeapSize)); +/// } +/// } +/// generics +/// } +/// ``` +/// +/// # Special cases +/// +/// This macro can parse the following additional types as a special case even +/// though they do not implement the `Parse` 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 +/// +/// [`Punctuated<T, P>`]: punctuated::Punctuated +/// +/// # 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. +// +// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on +// https://github.com/rust-lang/rust/issues/62834 +#[macro_export(local_inner_macros)] +macro_rules! parse_quote { + ($($tt:tt)*) => { + $crate::parse_quote::parse( + $crate::export::From::from( + $crate::export::quote::quote!($($tt)*) + ) + ) + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Can parse any type that implements Parse. + +use crate::parse::{Parse, ParseStream, Parser, Result}; +use proc_macro2::TokenStream; + +// 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) => panic!("{}", err), + } +} + +// Not public API. +#[doc(hidden)] +pub trait ParseQuote: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +impl<T: Parse> ParseQuote for T { + fn parse(input: ParseStream) -> Result<Self> { + <T as Parse>::parse(input) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Any other types that we want `parse_quote!` to be able to parse. + +use crate::punctuated::Punctuated; +#[cfg(any(feature = "full", feature = "derive"))] +use crate::{attr, Attribute}; + +#[cfg(any(feature = "full", feature = "derive"))] +impl ParseQuote for Attribute { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![#]) && input.peek2(Token![!]) { + attr::parsing::single_parse_inner(input) + } else { + attr::parsing::single_parse_outer(input) + } + } +} + +impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_terminated(input) + } +} diff --git a/syn/src/pat.rs b/syn/src/pat.rs new file mode 100644 index 0000000..262129b --- /dev/null +++ b/syn/src/pat.rs @@ -0,0 +1,903 @@ +use super::*; +use crate::punctuated::Punctuated; +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +use proc_macro2::TokenStream; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Pat #manual_extra_traits { + /// A box pattern: `box v`. + Box(PatBox), + + /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. + Ident(PatIdent), + + /// A literal pattern: `0`. + /// + /// This holds an `Expr` rather than a `Lit` because negative numbers + /// are represented as an `Expr::Unary`. + Lit(PatLit), + + /// A macro in pattern position. + Macro(PatMacro), + + /// A pattern that matches any one of a set of cases. + Or(PatOr), + + /// A path pattern like `Color::Red`, optionally qualified with a + /// self-type. + /// + /// Unqualified path patterns can legally refer to variants, structs, + /// constants or associated constants. Qualified path patterns like + /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to + /// associated constants. + Path(PatPath), + + /// A range pattern: `1..=2`. + Range(PatRange), + + /// A reference pattern: `&mut var`. + Reference(PatReference), + + /// The dots in a tuple or slice pattern: `[0, 1, ..]` + Rest(PatRest), + + /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. + Slice(PatSlice), + + /// A struct or struct variant pattern: `Variant { x, y, .. }`. + Struct(PatStruct), + + /// A tuple pattern: `(a, b)`. + Tuple(PatTuple), + + /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. + TupleStruct(PatTupleStruct), + + /// A type ascription pattern: `foo: f64`. + Type(PatType), + + /// Tokens in pattern position not interpreted by Syn. + Verbatim(TokenStream), + + /// A pattern that matches any value: `_`. + Wild(PatWild), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// A box pattern: `box v`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatBox { + pub attrs: Vec<Attribute>, + pub box_token: Token![box], + pub pat: Box<Pat>, + } +} + +ast_struct! { + /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatIdent { + pub attrs: Vec<Attribute>, + pub by_ref: Option<Token![ref]>, + pub mutability: Option<Token![mut]>, + pub ident: Ident, + pub subpat: Option<(Token![@], Box<Pat>)>, + } +} + +ast_struct! { + /// 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 struct PatLit { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + } +} + +ast_struct! { + /// A macro in pattern position. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + } +} + +ast_struct! { + /// A pattern that matches any one of a set of cases. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatOr { + pub attrs: Vec<Attribute>, + pub leading_vert: Option<Token![|]>, + pub cases: Punctuated<Pat, Token![|]>, + } +} + +ast_struct! { + /// A path pattern like `Color::Red`, optionally qualified with a + /// self-type. + /// + /// Unqualified path patterns can legally refer to variants, structs, + /// constants or associated constants. Qualified 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 struct PatPath { + pub attrs: Vec<Attribute>, + pub qself: Option<QSelf>, + pub path: Path, + } +} + +ast_struct! { + /// A range pattern: `1..=2`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatRange { + pub attrs: Vec<Attribute>, + pub lo: Box<Expr>, + pub limits: RangeLimits, + pub hi: Box<Expr>, + } +} + +ast_struct! { + /// A reference pattern: `&mut var`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatReference { + pub attrs: Vec<Attribute>, + pub and_token: Token![&], + pub mutability: Option<Token![mut]>, + pub pat: Box<Pat>, + } +} + +ast_struct! { + /// The dots in a tuple or slice pattern: `[0, 1, ..]` + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatRest { + pub attrs: Vec<Attribute>, + pub dot2_token: Token![..], + } +} + +ast_struct! { + /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatSlice { + pub attrs: Vec<Attribute>, + pub bracket_token: token::Bracket, + pub elems: Punctuated<Pat, Token![,]>, + } +} + +ast_struct! { + /// 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 attrs: Vec<Attribute>, + pub path: Path, + pub brace_token: token::Brace, + pub fields: Punctuated<FieldPat, Token![,]>, + pub dot2_token: Option<Token![..]>, + } +} + +ast_struct! { + /// A tuple pattern: `(a, b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatTuple { + pub attrs: Vec<Attribute>, + pub paren_token: token::Paren, + pub elems: Punctuated<Pat, Token![,]>, + } +} + +ast_struct! { + /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatTupleStruct { + pub attrs: Vec<Attribute>, + pub path: Path, + pub pat: PatTuple, + } +} + +ast_struct! { + /// A type ascription pattern: `foo: f64`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatType { + pub attrs: Vec<Attribute>, + pub pat: Box<Pat>, + pub colon_token: Token![:], + pub ty: Box<Type>, + } +} + +ast_struct! { + /// A pattern that matches any value: `_`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct PatWild { + pub attrs: Vec<Attribute>, + pub underscore_token: Token![_], + } +} + +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(feature = "extra-traits")] +impl Eq for Pat {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Pat { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Pat::Box(this), Pat::Box(other)) => this == other, + (Pat::Ident(this), Pat::Ident(other)) => this == other, + (Pat::Lit(this), Pat::Lit(other)) => this == other, + (Pat::Macro(this), Pat::Macro(other)) => this == other, + (Pat::Or(this), Pat::Or(other)) => this == other, + (Pat::Path(this), Pat::Path(other)) => this == other, + (Pat::Range(this), Pat::Range(other)) => this == other, + (Pat::Reference(this), Pat::Reference(other)) => this == other, + (Pat::Rest(this), Pat::Rest(other)) => this == other, + (Pat::Slice(this), Pat::Slice(other)) => this == other, + (Pat::Struct(this), Pat::Struct(other)) => this == other, + (Pat::Tuple(this), Pat::Tuple(other)) => this == other, + (Pat::TupleStruct(this), Pat::TupleStruct(other)) => this == other, + (Pat::Type(this), Pat::Type(other)) => this == other, + (Pat::Verbatim(this), Pat::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + (Pat::Wild(this), Pat::Wild(other)) => this == other, + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Pat { + fn hash<H>(&self, hash: &mut H) + where + H: Hasher, + { + match self { + Pat::Box(pat) => { + hash.write_u8(0); + pat.hash(hash); + } + Pat::Ident(pat) => { + hash.write_u8(1); + pat.hash(hash); + } + Pat::Lit(pat) => { + hash.write_u8(2); + pat.hash(hash); + } + Pat::Macro(pat) => { + hash.write_u8(3); + pat.hash(hash); + } + Pat::Or(pat) => { + hash.write_u8(4); + pat.hash(hash); + } + Pat::Path(pat) => { + hash.write_u8(5); + pat.hash(hash); + } + Pat::Range(pat) => { + hash.write_u8(6); + pat.hash(hash); + } + Pat::Reference(pat) => { + hash.write_u8(7); + pat.hash(hash); + } + Pat::Rest(pat) => { + hash.write_u8(8); + pat.hash(hash); + } + Pat::Slice(pat) => { + hash.write_u8(9); + pat.hash(hash); + } + Pat::Struct(pat) => { + hash.write_u8(10); + pat.hash(hash); + } + Pat::Tuple(pat) => { + hash.write_u8(11); + pat.hash(hash); + } + Pat::TupleStruct(pat) => { + hash.write_u8(12); + pat.hash(hash); + } + Pat::Type(pat) => { + hash.write_u8(13); + pat.hash(hash); + } + Pat::Verbatim(pat) => { + hash.write_u8(14); + TokenStreamHelper(pat).hash(hash); + } + Pat::Wild(pat) => { + hash.write_u8(15); + pat.hash(hash); + } + Pat::__Nonexhaustive => unreachable!(), + } + } +} + +#[cfg(feature = "parsing")] +mod parsing { + use super::*; + + use crate::ext::IdentExt; + use crate::parse::{Parse, ParseStream, Result}; + use crate::path; + + impl Parse for Pat { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) + && ({ + input.peek2(Token![::]) + || input.peek2(Token![!]) + || input.peek2(token::Brace) + || input.peek2(token::Paren) + || input.peek2(Token![..]) + && !{ + let ahead = input.fork(); + ahead.parse::<Ident>()?; + ahead.parse::<RangeLimits>()?; + ahead.is_empty() || ahead.peek(Token![,]) + } + }) + || input.peek(Token![self]) && input.peek2(Token![::]) + || lookahead.peek(Token![::]) + || lookahead.peek(Token![<]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + pat_path_or_macro_or_struct_or_range(input) + } else if lookahead.peek(Token![_]) { + input.call(pat_wild).map(Pat::Wild) + } else if input.peek(Token![box]) { + input.call(pat_box).map(Pat::Box) + } else if input.peek(Token![-]) || lookahead.peek(Lit) { + pat_lit_or_range(input) + } else if lookahead.peek(Token![ref]) + || lookahead.peek(Token![mut]) + || input.peek(Token![self]) + || input.peek(Ident) + { + input.call(pat_ident).map(Pat::Ident) + } else if lookahead.peek(Token![&]) { + input.call(pat_reference).map(Pat::Reference) + } else if lookahead.peek(token::Paren) { + input.call(pat_tuple).map(Pat::Tuple) + } else if lookahead.peek(token::Bracket) { + input.call(pat_slice).map(Pat::Slice) + } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) { + input.call(pat_rest).map(Pat::Rest) + } else { + Err(lookahead.error()) + } + } + } + + fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { + let (qself, path) = path::parsing::qpath(input, true)?; + + if input.peek(Token![..]) { + return pat_range(input, qself, path).map(Pat::Range); + } + + if qself.is_some() { + return Ok(Pat::Path(PatPath { + attrs: Vec::new(), + qself, + path, + })); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tokens) = mac::parse_delimiter(input)?; + return Ok(Pat::Macro(PatMacro { + attrs: Vec::new(), + mac: Macro { + path, + bang_token, + delimiter, + tokens, + }, + })); + } + } + + if input.peek(token::Brace) { + pat_struct(input, path).map(Pat::Struct) + } else if input.peek(token::Paren) { + pat_tuple_struct(input, path).map(Pat::TupleStruct) + } else if input.peek(Token![..]) { + pat_range(input, qself, path).map(Pat::Range) + } else { + Ok(Pat::Path(PatPath { + attrs: Vec::new(), + qself, + path, + })) + } + } + + fn pat_wild(input: ParseStream) -> Result<PatWild> { + Ok(PatWild { + attrs: Vec::new(), + underscore_token: input.parse()?, + }) + } + + fn pat_box(input: ParseStream) -> Result<PatBox> { + Ok(PatBox { + attrs: Vec::new(), + box_token: input.parse()?, + pat: input.parse()?, + }) + } + + fn pat_ident(input: ParseStream) -> Result<PatIdent> { + Ok(PatIdent { + attrs: Vec::new(), + by_ref: input.parse()?, + mutability: input.parse()?, + ident: input.call(Ident::parse_any)?, + subpat: { + if input.peek(Token![@]) { + let at_token: Token![@] = input.parse()?; + let subpat: Pat = input.parse()?; + Some((at_token, Box::new(subpat))) + } else { + None + } + }, + }) + } + + fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> { + Ok(PatTupleStruct { + attrs: Vec::new(), + path, + pat: input.call(pat_tuple)?, + }) + } + + fn pat_struct(input: ParseStream, path: Path) -> Result<PatStruct> { + let content; + let brace_token = braced!(content in input); + + let mut fields = Punctuated::new(); + while !content.is_empty() && !content.peek(Token![..]) { + let value = content.call(field_pat)?; + fields.push_value(value); + if !content.peek(Token![,]) { + break; + } + let punct: Token![,] = content.parse()?; + fields.push_punct(punct); + } + + let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) { + Some(content.parse()?) + } else { + None + }; + + Ok(PatStruct { + attrs: Vec::new(), + path, + brace_token, + fields, + dot2_token, + }) + } + + impl Member { + fn is_unnamed(&self) -> bool { + match *self { + Member::Named(_) => false, + Member::Unnamed(_) => true, + } + } + } + + fn field_pat(input: ParseStream) -> Result<FieldPat> { + let attrs = input.call(Attribute::parse_outer)?; + let boxed: Option<Token![box]> = input.parse()?; + let by_ref: Option<Token![ref]> = input.parse()?; + let mutability: Option<Token![mut]> = input.parse()?; + let member: Member = input.parse()?; + + if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) + || member.is_unnamed() + { + return Ok(FieldPat { + attrs, + member, + colon_token: input.parse()?, + pat: input.parse()?, + }); + } + + let ident = match member { + Member::Named(ident) => ident, + Member::Unnamed(_) => unreachable!(), + }; + + let mut pat = Pat::Ident(PatIdent { + attrs: Vec::new(), + by_ref, + mutability, + ident: ident.clone(), + subpat: None, + }); + + if let Some(boxed) = boxed { + pat = Pat::Box(PatBox { + attrs: Vec::new(), + box_token: boxed, + pat: Box::new(pat), + }); + } + + Ok(FieldPat { + attrs, + member: Member::Named(ident), + colon_token: None, + pat: Box::new(pat), + }) + } + + fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatRange> { + Ok(PatRange { + attrs: Vec::new(), + lo: Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself, + path, + })), + limits: input.parse()?, + hi: input.call(pat_lit_expr)?, + }) + } + + fn pat_tuple(input: ParseStream) -> Result<PatTuple> { + let content; + let paren_token = parenthesized!(content in input); + + let mut elems = Punctuated::new(); + while !content.is_empty() { + let value: Pat = content.parse()?; + elems.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + elems.push_punct(punct); + } + + Ok(PatTuple { + attrs: Vec::new(), + paren_token, + elems, + }) + } + + fn pat_reference(input: ParseStream) -> Result<PatReference> { + Ok(PatReference { + attrs: Vec::new(), + and_token: input.parse()?, + mutability: input.parse()?, + pat: input.parse()?, + }) + } + + fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { + let lo = input.call(pat_lit_expr)?; + if input.peek(Token![..]) { + Ok(Pat::Range(PatRange { + attrs: Vec::new(), + lo, + limits: input.parse()?, + hi: input.call(pat_lit_expr)?, + })) + } else { + Ok(Pat::Lit(PatLit { + attrs: Vec::new(), + expr: lo, + })) + } + } + + fn pat_lit_expr(input: ParseStream) -> Result<Box<Expr>> { + let neg: Option<Token![-]> = input.parse()?; + + let lookahead = input.lookahead1(); + let expr = if lookahead.peek(Lit) { + Expr::Lit(input.parse()?) + } else if lookahead.peek(Ident) + || lookahead.peek(Token![::]) + || lookahead.peek(Token![<]) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![Self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + { + Expr::Path(input.parse()?) + } else { + return Err(lookahead.error()); + }; + + Ok(Box::new(if let Some(neg) = neg { + Expr::Unary(ExprUnary { + attrs: Vec::new(), + op: UnOp::Neg(neg), + expr: Box::new(expr), + }) + } else { + expr + })) + } + + fn pat_slice(input: ParseStream) -> Result<PatSlice> { + let content; + let bracket_token = bracketed!(content in input); + + let mut elems = Punctuated::new(); + while !content.is_empty() { + let value: Pat = content.parse()?; + elems.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + elems.push_punct(punct); + } + + Ok(PatSlice { + attrs: Vec::new(), + bracket_token, + elems, + }) + } + + fn pat_rest(input: ParseStream) -> Result<PatRest> { + Ok(PatRest { + attrs: Vec::new(), + dot2_token: input.parse()?, + }) + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use crate::attr::FilterAttrs; + + impl ToTokens for PatWild { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.underscore_token.to_tokens(tokens); + } + } + + impl ToTokens for PatIdent { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.by_ref.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.ident.to_tokens(tokens); + if let Some((at_token, subpat)) = &self.subpat { + at_token.to_tokens(tokens); + subpat.to_tokens(tokens); + } + } + } + + impl ToTokens for PatStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + 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); + }); + } + } + + impl ToTokens for PatTupleStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.path.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + impl ToTokens for PatType { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.pat.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + } + } + + impl ToTokens for PatPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + private::print_path(tokens, &self.qself, &self.path); + } + } + + impl ToTokens for PatTuple { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.paren_token.surround(tokens, |tokens| { + self.elems.to_tokens(tokens); + }); + } + } + + impl ToTokens for PatBox { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.box_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + impl ToTokens for PatReference { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.and_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + impl ToTokens for PatRest { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.dot2_token.to_tokens(tokens); + } + } + + impl ToTokens for PatLit { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.expr.to_tokens(tokens); + } + } + + impl ToTokens for PatRange { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.lo.to_tokens(tokens); + match &self.limits { + RangeLimits::HalfOpen(t) => t.to_tokens(tokens), + RangeLimits::Closed(t) => t.to_tokens(tokens), + } + self.hi.to_tokens(tokens); + } + } + + impl ToTokens for PatSlice { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.bracket_token.surround(tokens, |tokens| { + self.elems.to_tokens(tokens); + }); + } + } + + impl ToTokens for PatMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.mac.to_tokens(tokens); + } + } + + impl ToTokens for PatOr { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.leading_vert.to_tokens(tokens); + self.cases.to_tokens(tokens); + } + } + + impl ToTokens for FieldPat { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + if let Some(colon_token) = &self.colon_token { + self.member.to_tokens(tokens); + colon_token.to_tokens(tokens); + } + self.pat.to_tokens(tokens); + } + } +} diff --git a/syn/src/path.rs b/syn/src/path.rs new file mode 100644 index 0000000..8dda43e --- /dev/null +++ b/syn/src/path.rs @@ -0,0 +1,744 @@ +use super::*; +use crate::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<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(bracketed) => bracketed.args.is_empty(), + PathArguments::Parenthesized(_) => false, + } + } + + #[cfg(feature = "parsing")] + fn is_none(&self) -> bool { + match *self { + PathArguments::None => true, + PathArguments::AngleBracketed(_) | 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), + /// An associated type bound: `Iterator<Item: Display>`. + Constraint(Constraint), + /// 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! { + /// An associated type bound: `Iterator<Item: Display>`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Constraint { + pub ident: Ident, + pub colon_token: Token![:], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + } +} + +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::*; + + #[cfg(feature = "full")] + use crate::expr; + use crate::ext::IdentExt; + use crate::parse::{Parse, ParseStream, Result}; + + impl Parse for Path { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_helper(input, false) + } + } + + impl Parse for GenericArgument { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) && !input.peek2(Token![+]) { + return Ok(GenericArgument::Lifetime(input.parse()?)); + } + + if input.peek(Ident) && input.peek2(Token![=]) { + return Ok(GenericArgument::Binding(input.parse()?)); + } + + #[cfg(feature = "full")] + { + if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) { + return Ok(GenericArgument::Constraint(input.parse()?)); + } + + if input.peek(Lit) { + let lit = input.parse()?; + return Ok(GenericArgument::Const(Expr::Lit(lit))); + } + + if input.peek(token::Brace) { + let block = input.call(expr::parsing::expr_block)?; + return Ok(GenericArgument::Const(Expr::Block(block))); + } + } + + input.parse().map(GenericArgument::Type) + } + } + + impl Parse for AngleBracketedGenericArguments { + fn parse(input: ParseStream) -> Result<Self> { + Ok(AngleBracketedGenericArguments { + colon2_token: input.parse()?, + lt_token: input.parse()?, + args: { + let mut args = Punctuated::new(); + loop { + if input.peek(Token![>]) { + break; + } + let value = input.parse()?; + args.push_value(value); + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + args.push_punct(punct); + } + args + }, + gt_token: input.parse()?, + }) + } + } + + impl Parse for ParenthesizedGenericArguments { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(ParenthesizedGenericArguments { + paren_token: parenthesized!(content in input), + inputs: content.parse_terminated(Type::parse)?, + output: input.call(ReturnType::without_plus)?, + }) + } + } + + impl Parse for PathSegment { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_helper(input, false) + } + } + + impl PathSegment { + fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { + if input.peek(Token![super]) + || input.peek(Token![self]) + || input.peek(Token![crate]) + || input.peek(Token![extern]) + { + let ident = input.call(Ident::parse_any)?; + return Ok(PathSegment::from(ident)); + } + + let ident = if input.peek(Token![Self]) { + input.call(Ident::parse_any)? + } else { + input.parse()? + }; + + if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) + || input.peek(Token![::]) && input.peek3(Token![<]) + { + Ok(PathSegment { + ident, + arguments: PathArguments::AngleBracketed(input.parse()?), + }) + } else { + Ok(PathSegment::from(ident)) + } + } + } + + impl Parse for Binding { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Binding { + ident: input.parse()?, + eq_token: input.parse()?, + ty: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Constraint { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Constraint { + ident: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.peek(Token![,]) || input.peek(Token![>]) { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + }) + } + } + + impl Path { + /// Parse a `Path` containing no path arguments on any of its segments. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + /// + /// # Example + /// + /// ``` + /// use syn::{Path, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // A simplified single `use` statement like: + /// // + /// // use std::collections::HashMap; + /// // + /// // Note that generic parameters are not allowed in a `use` statement + /// // so the following must not be accepted. + /// // + /// // use a::<b>::c; + /// struct SingleUse { + /// use_token: Token![use], + /// path: Path, + /// } + /// + /// impl Parse for SingleUse { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(SingleUse { + /// use_token: input.parse()?, + /// path: input.call(Path::parse_mod_style)?, + /// }) + /// } + /// } + /// ``` + pub fn parse_mod_style(input: ParseStream) -> Result<Self> { + Ok(Path { + leading_colon: input.parse()?, + segments: { + let mut segments = Punctuated::new(); + loop { + if !input.peek(Ident) + && !input.peek(Token![super]) + && !input.peek(Token![self]) + && !input.peek(Token![Self]) + && !input.peek(Token![crate]) + && !input.peek(Token![extern]) + { + break; + } + let ident = Ident::parse_any(input)?; + segments.push_value(PathSegment::from(ident)); + if !input.peek(Token![::]) { + break; + } + let punct = input.parse()?; + segments.push_punct(punct); + } + if segments.is_empty() { + return Err(input.error("expected path")); + } else if segments.trailing_punct() { + return Err(input.error("expected path segment")); + } + segments + }, + }) + } + + /// Determines whether this is a path of length 1 equal to the given + /// ident. + /// + /// For them to compare equal, it must be the case that: + /// + /// - the path has no leading colon, + /// - the number of path segments is 1, + /// - the first path segment has no angle bracketed or parenthesized + /// path arguments, and + /// - the ident of the first path segment is equal to the given one. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + /// + /// # Example + /// + /// ``` + /// use syn::{Attribute, Error, Meta, NestedMeta, Result}; + /// # use std::iter::FromIterator; + /// + /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> { + /// if attr.path.is_ident("serde") { + /// match attr.parse_meta()? { + /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)), + /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), + /// } + /// } else { + /// Ok(Vec::new()) + /// } + /// } + /// ``` + pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool + where + Ident: PartialEq<I>, + { + match self.get_ident() { + Some(id) => id == ident, + None => false, + } + } + + /// If this path consists of a single ident, returns the ident. + /// + /// A path is considered an ident if: + /// + /// - the path has no leading colon, + /// - the number of path segments is 1, and + /// - the first path segment has no angle bracketed or parenthesized + /// path arguments. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + pub fn get_ident(&self) -> Option<&Ident> { + if self.leading_colon.is_none() + && self.segments.len() == 1 + && self.segments[0].arguments.is_none() + { + Some(&self.segments[0].ident) + } else { + None + } + } + + fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { + Ok(Path { + leading_colon: input.parse()?, + segments: { + let mut segments = Punctuated::new(); + let value = PathSegment::parse_helper(input, expr_style)?; + segments.push_value(value); + while input.peek(Token![::]) { + let punct: Token![::] = input.parse()?; + segments.push_punct(punct); + let value = PathSegment::parse_helper(input, expr_style)?; + segments.push_value(value); + } + segments + }, + }) + } + } + + pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { + if input.peek(Token![<]) { + let lt_token: Token![<] = input.parse()?; + let this: Type = input.parse()?; + let path = if input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let path: Path = input.parse()?; + Some((as_token, path)) + } else { + None + }; + let gt_token: Token![>] = input.parse()?; + let colon2_token: Token![::] = input.parse()?; + let mut rest = Punctuated::new(); + loop { + let path = PathSegment::parse_helper(input, expr_style)?; + rest.push_value(path); + if !input.peek(Token![::]) { + break; + } + let punct: Token![::] = input.parse()?; + rest.push_punct(punct); + } + let (position, as_token, path) = match path { + Some((as_token, mut path)) => { + let pos = path.segments.len(); + path.segments.push_punct(colon2_token); + path.segments.extend(rest.into_pairs()); + (pos, Some(as_token), path) + } + None => { + let path = Path { + leading_colon: Some(colon2_token), + segments: rest, + }; + (0, None, path) + } + }; + let qself = QSelf { + lt_token, + ty: Box::new(this), + position, + as_token, + gt_token, + }; + Ok((Some(qself), path)) + } else { + let path = Path::parse_helper(input, expr_style)?; + Ok((None, path)) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::ToTokens; + + use crate::print::TokensOrDefault; + + 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(arguments) => { + arguments.to_tokens(tokens); + } + PathArguments::Parenthesized(arguments) => { + arguments.to_tokens(tokens); + } + } + } + } + + impl ToTokens for GenericArgument { + #[allow(clippy::match_same_arms)] + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), + GenericArgument::Type(ty) => ty.to_tokens(tokens), + GenericArgument::Binding(tb) => tb.to_tokens(tokens), + GenericArgument::Constraint(tc) => tc.to_tokens(tokens), + GenericArgument::Const(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() { + match **param.value() { + GenericArgument::Lifetime(_) => { + param.to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + GenericArgument::Type(_) + | GenericArgument::Binding(_) + | GenericArgument::Constraint(_) + | GenericArgument::Const(_) => {} + } + } + 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(_) + | GenericArgument::Constraint(_) => {} + } + } + for param in self.args.pairs() { + match **param.value() { + GenericArgument::Binding(_) | GenericArgument::Constraint(_) => { + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + trailing_or_empty = true; + } + param.to_tokens(tokens); + } + GenericArgument::Lifetime(_) + | GenericArgument::Type(_) + | GenericArgument::Const(_) => {} + } + } + + 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 Constraint { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.bounds.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 private { + pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { + let qself = match qself { + Some(qself) => qself, + None => { + path.to_tokens(tokens); + return; + } + }; + qself.lt_token.to_tokens(tokens); + qself.ty.to_tokens(tokens); + + let pos = if qself.position > 0 && qself.position >= path.segments.len() { + path.segments.len() - 1 + } else { + qself.position + }; + let mut segments = path.segments.pairs(); + if pos > 0 { + TokensOrDefault(&qself.as_token).to_tokens(tokens); + path.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); + path.leading_colon.to_tokens(tokens); + } + for segment in segments { + segment.to_tokens(tokens); + } + } + } +} diff --git a/syn/src/print.rs b/syn/src/print.rs new file mode 100644 index 0000000..da4e07e --- /dev/null +++ b/syn/src/print.rs @@ -0,0 +1,16 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +pub struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>); + +impl<'a, T> ToTokens for TokensOrDefault<'a, T> +where + T: ToTokens + Default, +{ + fn to_tokens(&self, tokens: &mut TokenStream) { + match self.0 { + Some(t) => t.to_tokens(tokens), + None => T::default().to_tokens(tokens), + } + } +} diff --git a/syn/src/punctuated.rs b/syn/src/punctuated.rs new file mode 100644 index 0000000..38c7bf4 --- /dev/null +++ b/syn/src/punctuated.rs @@ -0,0 +1,918 @@ +//! 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 crate::parse::{Parse, ParseStream, Result}; +#[cfg(feature = "parsing")] +use crate::token::Token; + +/// 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]: self +#[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 element in this sequence. + pub fn first(&self) -> Option<&T> { + self.iter().next() + } + + /// Borrows the last element in this sequence. + pub fn last(&self) -> Option<&T> { + if self.last.is_some() { + self.last.as_ref().map(Box::as_ref) + } else { + self.inner.last().map(|pair| &pair.0) + } + } + + /// Mutably borrows the last element in this sequence. + pub fn last_mut(&mut self) -> Option<&mut T> { + if self.last.is_some() { + self.last.as_mut().map(Box::as_mut) + } else { + self.inner.last_mut().map(|pair| &mut pair.0) + } + } + + /// 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(Box::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(Box::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(Box::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(Box::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`]: Punctuated::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() + } + + /// 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) + where + P: Default, + { + 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) + where + P: Default, + { + assert!(index <= self.len()); + + if index == self.len() { + self.push(value); + } else { + self.inner.insert(index, (value, Default::default())); + } + } + + /// Parses zero or more occurrences of `T` separated by punctuation of type + /// `P`, with optional trailing punctuation. + /// + /// Parsing continues until the end of this parse stream. The entire content + /// of this parse stream must consist of `T` and `P`. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_terminated(input: ParseStream) -> Result<Self> + where + T: Parse, + P: Parse, + { + Self::parse_terminated_with(input, T::parse) + } + + /// Parses zero or more occurrences of `T` using the given parse function, + /// separated by punctuation of type `P`, with optional trailing + /// punctuation. + /// + /// Like [`parse_terminated`], the entire content of this stream is expected + /// to be parsed. + /// + /// [`parse_terminated`]: Punctuated::parse_terminated + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_terminated_with( + input: ParseStream, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Self> + where + P: Parse, + { + let mut punctuated = Punctuated::new(); + + loop { + if input.is_empty() { + break; + } + let value = parser(input)?; + punctuated.push_value(value); + if input.is_empty() { + break; + } + let punct = input.parse()?; + punctuated.push_punct(punct); + } + + Ok(punctuated) + } + + /// Parses one or more occurrences of `T` separated by punctuation of type + /// `P`, not accepting trailing punctuation. + /// + /// Parsing continues as long as punctuation `P` is present at the head of + /// the stream. This method returns upon parsing a `T` and observing that it + /// is not followed by a `P`, even if there are remaining tokens in the + /// stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self> + where + T: Parse, + P: Token + Parse, + { + Self::parse_separated_nonempty_with(input, T::parse) + } + + /// Parses one or more occurrences of `T` using the given parse function, + /// separated by punctuation of type `P`, not accepting trailing + /// punctuation. + /// + /// Like [`parse_separated_nonempty`], may complete early without parsing + /// the entire content of this stream. + /// + /// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_separated_nonempty_with( + input: ParseStream, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Self> + where + P: Token + Parse, + { + let mut punctuated = Punctuated::new(); + + loop { + let value = parser(input)?; + punctuated.push_value(value); + if !P::peek(input.cursor()) { + break; + } + let punct = input.parse()?; + punctuated.push_punct(punct); + } + + Ok(punctuated) + } +} + +#[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 (t, p) in &self.inner { + list.entry(t); + list.entry(p); + } + if let Some(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>; + + fn into_iter(self) -> Self::IntoIter { + let mut elements = Vec::with_capacity(self.len()); + elements.extend(self.inner.into_iter().map(|pair| pair.0)); + elements.extend(self.last.map(|t| *t)); + + IntoIter { + inner: elements.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]: self +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(|(t, p)| Pair::Punctuated(t, p)) + .or_else(|| self.last.next().map(Pair::End)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, T, P> DoubleEndedIterator for Pairs<'a, T, P> { + fn next_back(&mut self) -> Option<Self::Item> { + self.last + .next() + .map(Pair::End) + .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) + } +} + +impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +// No Clone bound on T or P. +impl<'a, T, P> Clone for Pairs<'a, T, P> { + fn clone(&self) -> Self { + Pairs { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + +/// 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]: self +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(|(t, p)| Pair::Punctuated(t, p)) + .or_else(|| self.last.next().map(Pair::End)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, T, P> DoubleEndedIterator for PairsMut<'a, T, P> { + fn next_back(&mut self) -> Option<Self::Item> { + self.last + .next() + .map(Pair::End) + .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) + } +} + +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]: self +#[derive(Clone)] +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)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<T, P> DoubleEndedIterator for IntoPairs<T, P> { + fn next_back(&mut self) -> Option<Self::Item> { + self.last + .next() + .map(Pair::End) + .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) + } +} + +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]: self +#[derive(Clone)] +pub struct IntoIter<T> { + inner: vec::IntoIter<T>, +} + +impl<T> Iterator for IntoIter<T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<T> DoubleEndedIterator for IntoIter<T> { + fn next_back(&mut self) -> Option<Self::Item> { + self.inner.next_back() + } +} + +impl<T> ExactSizeIterator for IntoIter<T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +/// An iterator over borrowed values of type `&T`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: self +pub struct Iter<'a, T: 'a> { + // The `Item = &'a T` needs to be specified to support rustc 1.31 and older. + // On modern compilers we would be able to write just IterTrait<'a, T> where + // Item can be inferred unambiguously from the supertrait. + inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>, +} + +trait IterTrait<'a, T: 'a>: + DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T> +{ + fn clone_box(&self) -> Box<dyn IterTrait<'a, T, 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"))] +pub(crate) fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> { + Iter { + inner: Box::new(iter::empty()), + } +} + +// No Clone bound on T. +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone_box(), + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option<Self::Item> { + self.inner.next_back() + } +} + +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> DoubleEndedIterator for PrivateIter<'a, T, P> { + fn next_back(&mut self) -> Option<Self::Item> { + self.last + .next() + .or_else(|| self.inner.next_back().map(|pair| &pair.0)) + } +} + +impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +// No Clone bound on T or P. +impl<'a, T, P> Clone for PrivateIter<'a, T, P> { + fn clone(&self) -> Self { + PrivateIter { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + +impl<'a, T: 'a, I: 'a> IterTrait<'a, T> for I +where + I: DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T> + Clone, +{ + fn clone_box(&self) -> Box<dyn IterTrait<'a, T, Item = &'a T> + 'a> { + Box::new(self.clone()) + } +} + +/// An iterator over mutably borrowed values of type `&mut T`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: self +pub struct IterMut<'a, T: 'a> { + inner: Box<dyn IterMutTrait<'a, T, Item = &'a mut T> + 'a>, +} + +trait IterMutTrait<'a, T: 'a>: + DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T> +{ +} + +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"))] +pub(crate) fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> { + 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() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.len(), Some(self.len())) + } +} + +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option<Self::Item> { + self.inner.next_back() + } +} + +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> DoubleEndedIterator for PrivateIterMut<'a, T, P> { + fn next_back(&mut self) -> Option<Self::Item> { + self.last + .next() + .or_else(|| self.inner.next_back().map(|pair| &mut pair.0)) + } +} + +impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +impl<'a, T: 'a, I: 'a> IterMutTrait<'a, T> for I where + I: DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T> +{ +} + +/// 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]: self +#[cfg_attr(feature = "clone-impls", derive(Clone))] +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(t, _) | Pair::End(t) => t, + } + } + + /// Mutably borrows the syntax tree node from this punctuated pair. + pub fn value_mut(&mut self) -> &mut T { + match self { + Pair::Punctuated(t, _) | Pair::End(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(_, 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(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 &mut self.last { + Some(t) => t, + None => &mut self.inner[index].0, + } + } else { + &mut self.inner[index].0 + } + } +} + +#[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(a, b) => { + a.to_tokens(tokens); + b.to_tokens(tokens); + } + Pair::End(a) => a.to_tokens(tokens), + } + } + } +} diff --git a/syn/src/sealed.rs b/syn/src/sealed.rs new file mode 100644 index 0000000..0b11bc9 --- /dev/null +++ b/syn/src/sealed.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "parsing")] +pub mod lookahead { + pub trait Sealed: Copy {} +} diff --git a/syn/src/span.rs b/syn/src/span.rs new file mode 100644 index 0000000..27a7fe8 --- /dev/null +++ b/syn/src/span.rs @@ -0,0 +1,67 @@ +use proc_macro2::Span; + +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<[Span; 1]> for [Span; 1] { + fn into_spans(self) -> [Span; 1] { + self + } +} + +impl IntoSpans<[Span; 2]> for [Span; 2] { + fn into_spans(self) -> [Span; 2] { + self + } +} + +impl IntoSpans<[Span; 3]> for [Span; 3] { + fn into_spans(self) -> [Span; 3] { + self + } +} + +#[cfg(feature = "parsing")] +pub trait FromSpans: Sized { + fn from_spans(spans: &[Span]) -> Self; +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 1] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0]] + } +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 2] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0], spans[1]] + } +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 3] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0], spans[1], spans[2]] + } +} diff --git a/syn/src/spanned.rs b/syn/src/spanned.rs new file mode 100644 index 0000000..71ffe26 --- /dev/null +++ b/syn/src/spanned.rs @@ -0,0 +1,114 @@ +//! 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.* +//! +//! <br> +//! +//! # 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. +//! +//! ``` +//! # extern crate proc_macro; +//! # +//! use proc_macro::TokenStream; +//! use proc_macro2::Span; +//! use quote::quote_spanned; +//! use syn::Type; +//! use syn::spanned::Spanned; +//! +//! # 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!() +//! # } +//! ``` +//! +//! 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. +//! +//! <br> +//! +//! # Limitations +//! +//! The underlying [`proc_macro::Span::join`] method is nightly-only. When +//! called from within a procedural macro in a nightly compiler, `Spanned` will +//! use `join` to produce the intended span. When not using a nightly compiler, +//! only the span of the *first token* of the syntax tree node is returned. +//! +//! In the common case of wanting to use the joined span as the span of a +//! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is +//! able to span the error correctly under the complete syntax tree node without +//! needing the unstable `join`. +//! +//! [`syn::Error::new_spanned`]: crate::Error::new_spanned + +use proc_macro2::Span; +use quote::spanned::Spanned as 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, as well as for `Span` itself. +/// +/// [`ToTokens`]: quote::ToTokens +/// +/// See the [module documentation] for an example. +/// +/// [module documentation]: self +/// +/// *This trait is available if Syn is built with both the `"parsing"` and +/// `"printing"` features.* +pub trait Spanned { + /// Returns a `Span` covering the complete contents of this syntax tree + /// node, or [`Span::call_site()`] if this node is empty. + /// + /// [`Span::call_site()`]: proc_macro2::Span::call_site + fn span(&self) -> Span; +} + +impl<T: ?Sized + ToTokens> Spanned for T { + fn span(&self) -> Span { + self.__span() + } +} diff --git a/syn/src/stmt.rs b/syn/src/stmt.rs new file mode 100644 index 0000000..acee5a3 --- /dev/null +++ b/syn/src/stmt.rs @@ -0,0 +1,333 @@ +use super::*; + +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>, + } +} + +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![;]), + } +} + +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 pat: Pat, + pub init: Option<(Token![=], Box<Expr>)>, + pub semi_token: Token![;], + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use crate::parse::discouraged::Speculative; + use crate::parse::{Parse, ParseStream, Result}; + use crate::punctuated::Punctuated; + use proc_macro2::TokenStream; + + impl Block { + /// Parse the body of a block as zero or more statements, possibly + /// including one trailing expression. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + /// + /// # Example + /// + /// ``` + /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parse a function with no generics or parameter list. + /// // + /// // fn playground { + /// // let mut x = 1; + /// // x += 1; + /// // println!("{}", x); + /// // } + /// struct MiniFunction { + /// attrs: Vec<Attribute>, + /// fn_token: Token![fn], + /// name: Ident, + /// brace_token: token::Brace, + /// stmts: Vec<Stmt>, + /// } + /// + /// impl Parse for MiniFunction { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let outer_attrs = input.call(Attribute::parse_outer)?; + /// let fn_token: Token![fn] = input.parse()?; + /// let name: Ident = input.parse()?; + /// + /// let content; + /// let brace_token = braced!(content in input); + /// let inner_attrs = content.call(Attribute::parse_inner)?; + /// let stmts = content.call(Block::parse_within)?; + /// + /// Ok(MiniFunction { + /// attrs: { + /// let mut attrs = outer_attrs; + /// attrs.extend(inner_attrs); + /// attrs + /// }, + /// fn_token, + /// name, + /// brace_token, + /// stmts, + /// }) + /// } + /// } + /// ``` + pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { + let mut stmts = Vec::new(); + loop { + while let Some(semi) = input.parse::<Option<Token![;]>>()? { + stmts.push(Stmt::Semi(Expr::Verbatim(TokenStream::new()), semi)); + } + if input.is_empty() { + break; + } + let s = parse_stmt(input, true)?; + let requires_semicolon = if let Stmt::Expr(s) = &s { + expr::requires_terminator(s) + } else { + false + }; + stmts.push(s); + if input.is_empty() { + break; + } else if requires_semicolon { + return Err(input.error("unexpected token")); + } + } + Ok(stmts) + } + } + + impl Parse for Block { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(Block { + brace_token: braced!(content in input), + stmts: content.call(Block::parse_within)?, + }) + } + } + + impl Parse for Stmt { + fn parse(input: ParseStream) -> Result<Self> { + parse_stmt(input, false) + } + } + + fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> { + let mut attrs = input.call(Attribute::parse_outer)?; + + // brace-style macros; paren and bracket macros get parsed as + // expression statements. + let ahead = input.fork(); + if let Ok(path) = ahead.call(Path::parse_mod_style) { + if ahead.peek(Token![!]) && (ahead.peek2(token::Brace) || ahead.peek2(Ident)) { + input.advance_to(&ahead); + return stmt_mac(input, attrs, path); + } + } + + if input.peek(Token![let]) { + stmt_local(input, attrs).map(Stmt::Local) + } else if input.peek(Token![pub]) + || input.peek(Token![crate]) && !input.peek2(Token![::]) + || input.peek(Token![extern]) && !input.peek2(Token![::]) + || input.peek(Token![use]) + || input.peek(Token![static]) && (input.peek2(Token![mut]) || input.peek2(Ident)) + || input.peek(Token![const]) + || input.peek(Token![unsafe]) && !input.peek2(token::Brace) + || input.peek(Token![async]) + && (input.peek2(Token![unsafe]) + || input.peek2(Token![extern]) + || input.peek2(Token![fn])) + || input.peek(Token![fn]) + || input.peek(Token![mod]) + || input.peek(Token![type]) + || input.peek(item::parsing::existential) && input.peek2(Token![type]) + || input.peek(Token![struct]) + || input.peek(Token![enum]) + || input.peek(Token![union]) && input.peek2(Ident) + || input.peek(Token![auto]) && input.peek2(Token![trait]) + || input.peek(Token![trait]) + || input.peek(Token![default]) + && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) + || input.peek(Token![impl]) + || input.peek(Token![macro]) + { + let mut item: Item = input.parse()?; + attrs.extend(item.replace_attrs(Vec::new())); + item.replace_attrs(attrs); + Ok(Stmt::Item(item)) + } else { + stmt_expr(input, allow_nosemi, attrs) + } + } + + fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> { + let bang_token: Token![!] = input.parse()?; + let ident: Option<Ident> = input.parse()?; + let (delimiter, tokens) = mac::parse_delimiter(input)?; + let semi_token: Option<Token![;]> = input.parse()?; + + Ok(Stmt::Item(Item::Macro(ItemMacro { + attrs, + ident, + mac: Macro { + path, + bang_token, + delimiter, + tokens, + }, + semi_token, + }))) + } + + fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> { + Ok(Local { + attrs, + let_token: input.parse()?, + pat: { + let leading_vert: Option<Token![|]> = input.parse()?; + let mut pat: Pat = input.parse()?; + if leading_vert.is_some() + || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) + { + let mut cases = Punctuated::new(); + cases.push_value(pat); + while input.peek(Token![|]) + && !input.peek(Token![||]) + && !input.peek(Token![|=]) + { + let punct = input.parse()?; + cases.push_punct(punct); + let pat: Pat = input.parse()?; + cases.push_value(pat); + } + pat = Pat::Or(PatOr { + attrs: Vec::new(), + leading_vert, + cases, + }); + } + if input.peek(Token![:]) { + let colon_token: Token![:] = input.parse()?; + let ty: Type = input.parse()?; + pat = Pat::Type(PatType { + attrs: Vec::new(), + pat: Box::new(pat), + colon_token, + ty: Box::new(ty), + }); + } + pat + }, + init: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let init: Expr = input.parse()?; + Some((eq_token, Box::new(init))) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + + fn stmt_expr( + input: ParseStream, + allow_nosemi: bool, + mut attrs: Vec<Attribute>, + ) -> Result<Stmt> { + let mut e = expr::parsing::expr_early(input)?; + + attrs.extend(e.replace_attrs(Vec::new())); + e.replace_attrs(attrs); + + if input.peek(Token![;]) { + return Ok(Stmt::Semi(e, input.parse()?)); + } + + if allow_nosemi || !expr::requires_terminator(&e) { + Ok(Stmt::Expr(e)) + } else { + Err(input.error("expected semicolon")) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + impl ToTokens for Block { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(&self.stmts); + }); + } + } + + impl ToTokens for Stmt { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Stmt::Local(local) => local.to_tokens(tokens), + Stmt::Item(item) => item.to_tokens(tokens), + Stmt::Expr(expr) => expr.to_tokens(tokens), + Stmt::Semi(expr, semi) => { + expr.to_tokens(tokens); + semi.to_tokens(tokens); + } + } + } + } + + impl ToTokens for Local { + fn to_tokens(&self, tokens: &mut TokenStream) { + expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); + self.let_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + if let Some((eq_token, init)) = &self.init { + eq_token.to_tokens(tokens); + init.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } +} diff --git a/syn/src/thread.rs b/syn/src/thread.rs new file mode 100644 index 0000000..9e5d8ad --- /dev/null +++ b/syn/src/thread.rs @@ -0,0 +1,41 @@ +use std::fmt::{self, Debug}; +use std::thread::{self, ThreadId}; + +/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value +/// of type T only from the original thread on which the ThreadBound was +/// constructed. +pub struct ThreadBound<T> { + value: T, + thread_id: ThreadId, +} + +unsafe impl<T> Sync for ThreadBound<T> {} + +// Send bound requires Copy, as otherwise Drop could run in the wrong place. +unsafe impl<T: Copy> Send for ThreadBound<T> {} + +impl<T> ThreadBound<T> { + pub fn new(value: T) -> Self { + ThreadBound { + value, + thread_id: thread::current().id(), + } + } + + pub fn get(&self) -> Option<&T> { + if thread::current().id() == self.thread_id { + Some(&self.value) + } else { + None + } + } +} + +impl<T: Debug> Debug for ThreadBound<T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(value) => Debug::fmt(value, formatter), + None => formatter.write_str("unknown"), + } + } +} diff --git a/syn/src/token.rs b/syn/src/token.rs new file mode 100644 index 0000000..a9f787a --- /dev/null +++ b/syn/src/token.rs @@ -0,0 +1,956 @@ +//! 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 +//! +//! ``` +//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility}; +//! # +//! 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![;], +//! } +//! ``` +//! +//! # Parsing +//! +//! Keywords and punctuation can be parsed through the [`ParseStream::parse`] +//! method. Delimiter tokens are parsed using the [`parenthesized!`], +//! [`bracketed!`] and [`braced!`] macros. +//! +//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse +//! [`parenthesized!`]: ../macro.parenthesized.html +//! [`bracketed!`]: ../macro.bracketed.html +//! [`braced!`]: ../macro.braced.html +//! +//! ``` +//! use syn::{Attribute, Result}; +//! use syn::parse::{Parse, ParseStream}; +//! # +//! # enum ItemStatic {} +//! +//! // Parse the ItemStatic struct shown above. +//! impl Parse for ItemStatic { +//! fn parse(input: ParseStream) -> Result<Self> { +//! # use syn::ItemStatic; +//! # fn parse(input: ParseStream) -> Result<ItemStatic> { +//! Ok(ItemStatic { +//! attrs: input.call(Attribute::parse_outer)?, +//! vis: input.parse()?, +//! static_token: input.parse()?, +//! mutability: input.parse()?, +//! ident: input.parse()?, +//! colon_token: input.parse()?, +//! ty: input.parse()?, +//! eq_token: input.parse()?, +//! expr: input.parse()?, +//! semi_token: input.parse()?, +//! }) +//! # } +//! # unimplemented!() +//! } +//! } +//! ``` +//! +//! # Other operations +//! +//! Every keyword and punctuation token supports the following operations. +//! +//! - [Peeking] — `input.peek(Token![...])` +//! +//! - [Parsing] — `input.parse::<Token![...]>()?` +//! +//! - [Printing] — `quote!( ... #the_token ... )` +//! +//! - Construction from a [`Span`] — `let the_token = Token![...](sp)` +//! +//! - Field access to its span — `let sp = the_token.span` +//! +//! [Peeking]: ../parse/struct.ParseBuffer.html#method.peek +//! [Parsing]: ../parse/struct.ParseBuffer.html#method.parse +//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html +//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html + +use std; +#[cfg(feature = "extra-traits")] +use std::cmp; +#[cfg(feature = "extra-traits")] +use std::fmt::{self, Debug}; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; + +#[cfg(feature = "parsing")] +use proc_macro2::Delimiter; +#[cfg(any(feature = "parsing", feature = "printing"))] +use proc_macro2::Ident; +use proc_macro2::Span; +#[cfg(feature = "printing")] +use proc_macro2::TokenStream; +#[cfg(feature = "printing")] +use quote::{ToTokens, TokenStreamExt}; + +use self::private::WithSpan; +#[cfg(feature = "parsing")] +use crate::buffer::Cursor; +#[cfg(feature = "parsing")] +use crate::error::Result; +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +use crate::lifetime::Lifetime; +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; +#[cfg(feature = "parsing")] +use crate::lookahead; +#[cfg(feature = "parsing")] +use crate::parse::{Parse, ParseStream}; +use crate::span::IntoSpans; + +/// Marker trait for types that represent single tokens. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. +#[cfg(feature = "parsing")] +pub trait Token: private::Sealed { + // Not public API. + #[doc(hidden)] + fn peek(cursor: Cursor) -> bool; + + // Not public API. + #[doc(hidden)] + fn display() -> &'static str; +} + +mod private { + use proc_macro2::Span; + + #[cfg(feature = "parsing")] + pub trait Sealed {} + + /// Support writing `token.span` rather than `token.spans[0]` on tokens that + /// hold a single span. + #[repr(C)] + pub struct WithSpan { + pub span: Span, + } +} + +#[cfg(feature = "parsing")] +impl private::Sealed for Ident {} + +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { + use crate::parse::Unexpected; + use std::cell::Cell; + use std::rc::Rc; + + let scope = Span::call_site(); + let unexpected = Rc::new(Cell::new(Unexpected::None)); + let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected); + peek(&buffer) +} + +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! impl_token { + ($name:ident $display:expr) => { + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + fn peek(input: ParseStream) -> bool { + <$name as Parse>::parse(input).is_ok() + } + peek_impl(cursor, peek) + } + + fn display() -> &'static str { + $display + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + }; +} + +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(Lifetime "lifetime"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(Lit "literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitStr "string literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitByteStr "byte string literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitByte "byte literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitChar "character literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitInt "integer literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitFloat "floating point literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitBool "boolean literal"); + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "parsing")] +pub trait CustomToken { + fn peek(cursor: Cursor) -> bool; + fn display() -> &'static str; +} + +#[cfg(feature = "parsing")] +impl<T: CustomToken> private::Sealed for T {} + +#[cfg(feature = "parsing")] +impl<T: CustomToken> Token for T { + fn peek(cursor: Cursor) -> bool { + <Self as CustomToken>::peek(cursor) + } + + fn display() -> &'static str { + <Self as CustomToken>::display() + } +} + +macro_rules! define_keywords { + ($($token:tt pub struct $name:ident #[$doc:meta])*) => { + $( + #[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!`]: crate::token + 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: Span::call_site(), + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + #[cfg(feature = "printing")] + impl ToTokens for $name { + fn to_tokens(&self, tokens: &mut TokenStream) { + printing::keyword($token, self.span, tokens); + } + } + + #[cfg(feature = "parsing")] + impl Parse for $name { + fn parse(input: ParseStream) -> Result<Self> { + Ok($name { + span: parsing::keyword(input, $token)?, + }) + } + } + + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + parsing::peek_keyword(cursor, $token) + } + + fn display() -> &'static str { + concat!("`", $token, "`") + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +macro_rules! impl_deref_if_len_is_1 { + ($name:ident/1) => { + impl Deref for $name { + type Target = WithSpan; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const WithSpan) } + } + } + + impl DerefMut for $name { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut WithSpan) } + } + } + }; + + ($name:ident/$len:tt) => {}; +} + +macro_rules! define_punctuation_structs { + ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => { + $( + #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] + #[repr(C)] + #[$doc] + /// + /// Don't try to remember the name of this type — use the + /// [`Token!`] macro instead. + /// + /// [`Token!`]: crate::token + 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 { + spans: [Span::call_site(); $len], + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + impl_deref_if_len_is_1!($name/$len); + )* + }; +} + +macro_rules! define_punctuation { + ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => { + $( + define_punctuation_structs! { + $token pub struct $name/$len #[$doc] + } + + #[cfg(feature = "printing")] + impl ToTokens for $name { + fn to_tokens(&self, tokens: &mut TokenStream) { + printing::punct($token, &self.spans, tokens); + } + } + + #[cfg(feature = "parsing")] + impl Parse for $name { + fn parse(input: ParseStream) -> Result<Self> { + Ok($name { + spans: parsing::punct(input, $token)?, + }) + } + } + + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + parsing::peek_punct(cursor, $token) + } + + fn display() -> &'static str { + concat!("`", $token, "`") + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +macro_rules! define_delimiters { + ($($token:tt pub struct $name:ident #[$doc:meta])*) => { + $( + #[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: Span::call_site(), + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + impl $name { + #[cfg(feature = "printing")] + pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) + where + F: FnOnce(&mut TokenStream), + { + printing::delim($token, self.span, tokens, f); + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +define_punctuation_structs! { + "_" pub struct Underscore/1 /// `_` +} + +#[cfg(feature = "printing")] +impl ToTokens for Underscore { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Ident::new("_", self.span)); + } +} + +#[cfg(feature = "parsing")] +impl Parse for Underscore { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if ident == "_" { + return Ok((Underscore(ident.span()), rest)); + } + } + if let Some((punct, rest)) = cursor.punct() { + if punct.as_char() == '_' { + return Ok((Underscore(punct.span()), rest)); + } + } + Err(cursor.error("expected `_`")) + }) + } +} + +#[cfg(feature = "parsing")] +impl Token for Underscore { + fn peek(cursor: Cursor) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + return ident == "_"; + } + if let Some((punct, _rest)) = cursor.punct() { + return punct.as_char() == '_'; + } + false + } + + fn display() -> &'static str { + "`_`" + } +} + +#[cfg(feature = "parsing")] +impl private::Sealed for Underscore {} + +#[cfg(feature = "parsing")] +impl Token for Paren { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Parenthesis) + } + + fn display() -> &'static str { + "parentheses" + } +} + +#[cfg(feature = "parsing")] +impl Token for Brace { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Brace) + } + + fn display() -> &'static str { + "curly braces" + } +} + +#[cfg(feature = "parsing")] +impl Token for Bracket { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Bracket) + } + + fn display() -> &'static str { + "square brackets" + } +} + +#[cfg(feature = "parsing")] +impl Token for Group { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::None) + } + + fn display() -> &'static str { + "invisible group" + } +} + +define_keywords! { + "abstract" pub struct Abstract /// `abstract` + "as" pub struct As /// `as` + "async" pub struct Async /// `async` + "auto" pub struct Auto /// `auto` + "await" pub struct Await /// `await` + "become" pub struct Become /// `become` + "box" pub struct Box /// `box` + "break" pub struct Break /// `break` + "const" pub struct Const /// `const` + "continue" pub struct Continue /// `continue` + "crate" pub struct Crate /// `crate` + "default" pub struct Default /// `default` + "do" pub struct Do /// `do` + "dyn" pub struct Dyn /// `dyn` + "else" pub struct Else /// `else` + "enum" pub struct Enum /// `enum` + "extern" pub struct Extern /// `extern` + "final" pub struct Final /// `final` + "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` + "override" pub struct Override /// `override` + "priv" pub struct Priv /// `priv` + "pub" pub struct Pub /// `pub` + "ref" pub struct Ref /// `ref` + "return" pub struct Return /// `return` + "Self" pub struct SelfType /// `Self` + "self" pub struct SelfValue /// `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` + "typeof" pub struct Typeof /// `typeof` + "union" pub struct Union /// `union` + "unsafe" pub struct Unsafe /// `unsafe` + "unsized" pub struct Unsized /// `unsized` + "use" pub struct Use /// `use` + "virtual" pub struct Virtual /// `virtual` + "where" pub struct Where /// `where` + "while" pub struct While /// `while` + "yield" pub struct Yield /// `yield` +} + +define_punctuation! { + "+" 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 /// `-=` + "~" pub struct Tilde/1 /// `~` +} + +define_delimiters! { + "{" pub struct Brace /// `{...}` + "[" pub struct Bracket /// `[...]` + "(" pub struct Paren /// `(...)` + " " pub struct Group /// None-delimited group +} + +macro_rules! export_token_macro { + ($($await_rule:tt)*) => { + /// 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]: crate::token + // Unfortunate duplication due to a rustdoc bug. + // https://github.com/rust-lang/rust/issues/45939 + #[macro_export] + macro_rules! Token { + (abstract) => { $crate::token::Abstract }; + (as) => { $crate::token::As }; + (async) => { $crate::token::Async }; + (auto) => { $crate::token::Auto }; + $($await_rule => { $crate::token::Await };)* + (become) => { $crate::token::Become }; + (box) => { $crate::token::Box }; + (break) => { $crate::token::Break }; + (const) => { $crate::token::Const }; + (continue) => { $crate::token::Continue }; + (crate) => { $crate::token::Crate }; + (default) => { $crate::token::Default }; + (do) => { $crate::token::Do }; + (dyn) => { $crate::token::Dyn }; + (else) => { $crate::token::Else }; + (enum) => { $crate::token::Enum }; + (extern) => { $crate::token::Extern }; + (final) => { $crate::token::Final }; + (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 }; + (override) => { $crate::token::Override }; + (priv) => { $crate::token::Priv }; + (pub) => { $crate::token::Pub }; + (ref) => { $crate::token::Ref }; + (return) => { $crate::token::Return }; + (Self) => { $crate::token::SelfType }; + (self) => { $crate::token::SelfValue }; + (static) => { $crate::token::Static }; + (struct) => { $crate::token::Struct }; + (super) => { $crate::token::Super }; + (trait) => { $crate::token::Trait }; + (try) => { $crate::token::Try }; + (type) => { $crate::token::Type }; + (typeof) => { $crate::token::Typeof }; + (union) => { $crate::token::Union }; + (unsafe) => { $crate::token::Unsafe }; + (unsized) => { $crate::token::Unsized }; + (use) => { $crate::token::Use }; + (virtual) => { $crate::token::Virtual }; + (where) => { $crate::token::Where }; + (while) => { $crate::token::While }; + (yield) => { $crate::token::Yield }; + (+) => { $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::Dollar }; + (.) => { $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::Tilde }; + (_) => { $crate::token::Underscore }; + } + }; +} + +// Old rustc does not permit `await` appearing anywhere in the source file. +// https://github.com/rust-lang/rust/issues/57919 +// We put the Token![await] rule in a place that is not lexed by old rustc. +#[cfg(not(syn_omit_await_from_token_macro))] +include!("await.rs"); // export_token_macro![(await)]; +#[cfg(syn_omit_await_from_token_macro)] +export_token_macro![]; + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "parsing")] +pub mod parsing { + use proc_macro2::{Spacing, Span}; + + use crate::buffer::Cursor; + use crate::error::{Error, Result}; + use crate::parse::ParseStream; + use crate::span::FromSpans; + + pub fn keyword(input: ParseStream, token: &str) -> Result<Span> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if ident == token { + return Ok((ident.span(), rest)); + } + } + Err(cursor.error(format!("expected `{}`", token))) + }) + } + + pub fn peek_keyword(cursor: Cursor, token: &str) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + ident == token + } else { + false + } + } + + pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> { + let mut spans = [input.span(); 3]; + punct_helper(input, token, &mut spans)?; + Ok(S::from_spans(&spans)) + } + + fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> { + input.step(|cursor| { + let mut cursor = *cursor; + assert!(token.len() <= spans.len()); + + for (i, ch) in token.chars().enumerate() { + match cursor.punct() { + Some((punct, rest)) => { + spans[i] = punct.span(); + if punct.as_char() != ch { + break; + } else if i == token.len() - 1 { + return Ok(((), rest)); + } else if punct.spacing() != Spacing::Joint { + break; + } + cursor = rest; + } + None => break, + } + } + + Err(Error::new(spans[0], format!("expected `{}`", token))) + }) + } + + pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool { + for (i, ch) in token.chars().enumerate() { + match cursor.punct() { + Some((punct, rest)) => { + if punct.as_char() != ch { + break; + } else if i == token.len() - 1 { + return true; + } else if punct.spacing() != Spacing::Joint { + break; + } + cursor = rest; + } + None => break, + } + } + false + } +} + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "printing")] +pub 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/syn/src/tt.rs b/syn/src/tt.rs new file mode 100644 index 0000000..8dba062 --- /dev/null +++ b/syn/src/tt.rs @@ -0,0 +1,108 @@ +use std::hash::{Hash, Hasher}; + +use proc_macro2::{Delimiter, TokenStream, TokenTree}; + +pub struct TokenTreeHelper<'a>(pub &'a TokenTree); + +impl<'a> PartialEq for TokenTreeHelper<'a> { + fn eq(&self, other: &Self) -> bool { + use proc_macro2::Spacing; + + match (self.0, other.0) { + (TokenTree::Group(g1), TokenTree::Group(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().into_iter(); + let mut s2 = g2.stream().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(o1), TokenTree::Punct(o2)) => { + o1.as_char() == o2.as_char() + && match (o1.spacing(), o2.spacing()) { + (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true, + _ => false, + } + } + (TokenTree::Literal(l1), TokenTree::Literal(l2)) => l1.to_string() == l2.to_string(), + (TokenTree::Ident(s1), TokenTree::Ident(s2)) => s1 == s2, + _ => false, + } + } +} + +impl<'a> Hash for TokenTreeHelper<'a> { + fn hash<H: Hasher>(&self, h: &mut H) { + use proc_macro2::Spacing; + + match self.0 { + TokenTree::Group(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() { + TokenTreeHelper(&item).hash(h); + } + 0xffu8.hash(h); // terminator w/ a variant we don't normally hash + } + TokenTree::Punct(op) => { + 1u8.hash(h); + op.as_char().hash(h); + match op.spacing() { + Spacing::Alone => 0u8.hash(h), + Spacing::Joint => 1u8.hash(h), + } + } + TokenTree::Literal(lit) => (2u8, lit.to_string()).hash(h), + TokenTree::Ident(word) => (3u8, word).hash(h), + } + } +} + +pub struct TokenStreamHelper<'a>(pub &'a TokenStream); + +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 + } +} + +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/syn/src/ty.rs b/syn/src/ty.rs new file mode 100644 index 0000000..b2e086b --- /dev/null +++ b/syn/src/ty.rs @@ -0,0 +1,1178 @@ +use super::*; +use crate::punctuated::Punctuated; +#[cfg(feature = "extra-traits")] +use crate::tt::TokenStreamHelper; +use proc_macro2::TokenStream; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +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 + // + // TODO: change syntax-tree-enum link to an intra rustdoc link, currently + // blocked on https://github.com/rust-lang/rust/issues/62833 + pub enum Type #manual_extra_traits { + /// A fixed size array type: `[T; n]`. + Array(TypeArray), + + /// A bare function type: `fn(usize) -> bool`. + BareFn(TypeBareFn), + + /// A type contained within invisible delimiters. + Group(TypeGroup), + + /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or + /// a lifetime. + ImplTrait(TypeImplTrait), + + /// Indication that a type should be inferred by the compiler: `_`. + Infer(TypeInfer), + + /// A macro in the type position. + Macro(TypeMacro), + + /// The never type: `!`. + Never(TypeNever), + + /// A parenthesized type equivalent to the inner type. + Paren(TypeParen), + + /// A path like `std::slice::Iter`, optionally qualified with a + /// self-type as in `<Vec<T> as SomeTrait>::Associated`. + Path(TypePath), + + /// A raw pointer type: `*const T` or `*mut T`. + Ptr(TypePtr), + + /// A reference type: `&'a T` or `&'a mut T`. + Reference(TypeReference), + + /// A dynamically sized slice type: `[T]`. + Slice(TypeSlice), + + /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a + /// trait or a lifetime. + TraitObject(TypeTraitObject), + + /// A tuple type: `(A, B, C, String)`. + Tuple(TypeTuple), + + /// Tokens in type position not interpreted by Syn. + Verbatim(TokenStream), + + #[doc(hidden)] + __Nonexhaustive, + } +} + +ast_struct! { + /// A fixed size array type: `[T; n]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeArray { + pub bracket_token: token::Bracket, + pub elem: Box<Type>, + pub semi_token: Token![;], + pub len: Expr, + } +} + +ast_struct! { + /// A bare function type: `fn(usize) -> bool`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeBareFn { + pub lifetimes: Option<BoundLifetimes>, + pub unsafety: Option<Token![unsafe]>, + pub abi: Option<Abi>, + pub fn_token: Token![fn], + pub paren_token: token::Paren, + pub inputs: Punctuated<BareFnArg, Token![,]>, + pub variadic: Option<Variadic>, + pub output: ReturnType, + } +} + +ast_struct! { + /// A type contained within invisible delimiters. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeGroup { + pub group_token: token::Group, + pub elem: Box<Type>, + } +} + +ast_struct! { + /// 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 struct TypeImplTrait { + pub impl_token: Token![impl], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + } +} + +ast_struct! { + /// 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 struct TypeInfer { + pub underscore_token: Token![_], + } +} + +ast_struct! { + /// A macro in the type position. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeMacro { + pub mac: Macro, + } +} + +ast_struct! { + /// The never type: `!`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeNever { + pub bang_token: Token![!], + } +} + +ast_struct! { + /// A parenthesized type equivalent to the inner type. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeParen { + pub paren_token: token::Paren, + pub elem: Box<Type>, + } +} + +ast_struct! { + /// A path like `std::slice::Iter`, optionally qualified with a + /// self-type as in `<Vec<T> as SomeTrait>::Associated`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypePath { + pub qself: Option<QSelf>, + pub path: Path, + } +} + +ast_struct! { + /// A raw pointer type: `*const T` or `*mut T`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypePtr { + pub star_token: Token![*], + pub const_token: Option<Token![const]>, + pub mutability: Option<Token![mut]>, + pub elem: Box<Type>, + } +} + +ast_struct! { + /// A reference type: `&'a T` or `&'a mut T`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeReference { + pub and_token: Token![&], + pub lifetime: Option<Lifetime>, + pub mutability: Option<Token![mut]>, + pub elem: Box<Type>, + } +} + +ast_struct! { + /// A dynamically sized slice type: `[T]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeSlice { + pub bracket_token: token::Bracket, + pub elem: Box<Type>, + } +} + +ast_struct! { + /// 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 struct TypeTraitObject { + pub dyn_token: Option<Token![dyn]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + } +} + +ast_struct! { + /// A tuple type: `(A, B, C, String)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub struct TypeTuple { + pub paren_token: token::Paren, + pub elems: Punctuated<Type, Token![,]>, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Type {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Type::Array(this), Type::Array(other)) => this == other, + (Type::BareFn(this), Type::BareFn(other)) => this == other, + (Type::Group(this), Type::Group(other)) => this == other, + (Type::ImplTrait(this), Type::ImplTrait(other)) => this == other, + (Type::Infer(this), Type::Infer(other)) => this == other, + (Type::Macro(this), Type::Macro(other)) => this == other, + (Type::Never(this), Type::Never(other)) => this == other, + (Type::Paren(this), Type::Paren(other)) => this == other, + (Type::Path(this), Type::Path(other)) => this == other, + (Type::Ptr(this), Type::Ptr(other)) => this == other, + (Type::Reference(this), Type::Reference(other)) => this == other, + (Type::Slice(this), Type::Slice(other)) => this == other, + (Type::TraitObject(this), Type::TraitObject(other)) => this == other, + (Type::Tuple(this), Type::Tuple(other)) => this == other, + (Type::Verbatim(this), Type::Verbatim(other)) => { + TokenStreamHelper(this) == TokenStreamHelper(other) + } + _ => false, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Type { + fn hash<H>(&self, hash: &mut H) + where + H: Hasher, + { + match self { + Type::Array(ty) => { + hash.write_u8(0); + ty.hash(hash); + } + Type::BareFn(ty) => { + hash.write_u8(1); + ty.hash(hash); + } + Type::Group(ty) => { + hash.write_u8(2); + ty.hash(hash); + } + Type::ImplTrait(ty) => { + hash.write_u8(3); + ty.hash(hash); + } + Type::Infer(ty) => { + hash.write_u8(4); + ty.hash(hash); + } + Type::Macro(ty) => { + hash.write_u8(5); + ty.hash(hash); + } + Type::Never(ty) => { + hash.write_u8(6); + ty.hash(hash); + } + Type::Paren(ty) => { + hash.write_u8(7); + ty.hash(hash); + } + Type::Path(ty) => { + hash.write_u8(8); + ty.hash(hash); + } + Type::Ptr(ty) => { + hash.write_u8(9); + ty.hash(hash); + } + Type::Reference(ty) => { + hash.write_u8(10); + ty.hash(hash); + } + Type::Slice(ty) => { + hash.write_u8(11); + ty.hash(hash); + } + Type::TraitObject(ty) => { + hash.write_u8(12); + ty.hash(hash); + } + Type::Tuple(ty) => { + hash.write_u8(13); + ty.hash(hash); + } + Type::Verbatim(ty) => { + hash.write_u8(14); + TokenStreamHelper(ty).hash(hash); + } + Type::__Nonexhaustive => unreachable!(), + } + } +} + +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 attrs: Vec<Attribute>, + pub name: Option<(Ident, Token![:])>, + pub ty: Type, + } +} + +ast_struct! { + /// The variadic argument of a foreign function. + /// + /// ```rust + /// # struct c_char; + /// # struct c_int; + /// # + /// extern "C" { + /// fn printf(format: *const c_char, ...) -> c_int; + /// // ^^^ + /// } + /// ``` + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Variadic { + pub attrs: Vec<Attribute>, + pub dots: 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 crate::ext::IdentExt; + use crate::parse::{Parse, ParseStream, Result}; + use crate::path; + use proc_macro2::{Punct, Spacing, TokenTree}; + use std::iter::FromIterator; + + impl Parse for Type { + fn parse(input: ParseStream) -> Result<Self> { + ambig_ty(input, true) + } + } + + 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. + pub fn without_plus(input: ParseStream) -> Result<Self> { + ambig_ty(input, false) + } + } + + fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> { + if input.peek(token::Group) { + return input.parse().map(Type::Group); + } + + let mut lifetimes = None::<BoundLifetimes>; + let mut lookahead = input.lookahead1(); + if lookahead.peek(Token![for]) { + lifetimes = input.parse()?; + lookahead = input.lookahead1(); + if !lookahead.peek(Ident) + && !lookahead.peek(Token![fn]) + && !lookahead.peek(Token![unsafe]) + && !lookahead.peek(Token![extern]) + && !lookahead.peek(Token![super]) + && !lookahead.peek(Token![self]) + && !lookahead.peek(Token![Self]) + && !lookahead.peek(Token![crate]) + { + return Err(lookahead.error()); + } + } + + if lookahead.peek(token::Paren) { + let content; + let paren_token = parenthesized!(content in input); + if content.is_empty() { + return Ok(Type::Tuple(TypeTuple { + paren_token, + elems: Punctuated::new(), + })); + } + if content.peek(Lifetime) { + return Ok(Type::Paren(TypeParen { + paren_token, + elem: Box::new(Type::TraitObject(content.parse()?)), + })); + } + if content.peek(Token![?]) { + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds: { + let mut bounds = Punctuated::new(); + bounds.push_value(TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + ..content.parse()? + })); + while let Some(plus) = input.parse()? { + bounds.push_punct(plus); + bounds.push_value(input.parse()?); + } + bounds + }, + })); + } + let mut first: Type = content.parse()?; + if content.peek(Token![,]) { + return Ok(Type::Tuple(TypeTuple { + paren_token, + elems: { + let mut elems = Punctuated::new(); + elems.push_value(first); + elems.push_punct(content.parse()?); + let rest: Punctuated<Type, Token![,]> = + content.parse_terminated(Parse::parse)?; + elems.extend(rest); + elems + }, + })); + } + if allow_plus && input.peek(Token![+]) { + loop { + let first = match first { + Type::Path(TypePath { qself: None, path }) => { + TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + modifier: TraitBoundModifier::None, + lifetimes: None, + path, + }) + } + Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds, + }) => { + if bounds.len() > 1 || bounds.trailing_punct() { + first = Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds, + }); + break; + } + match bounds.into_iter().next().unwrap() { + TypeParamBound::Trait(trait_bound) => { + TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + ..trait_bound + }) + } + other => other, + } + } + _ => break, + }; + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds: { + let mut bounds = Punctuated::new(); + bounds.push_value(first); + while let Some(plus) = input.parse()? { + bounds.push_punct(plus); + bounds.push_value(input.parse()?); + } + bounds + }, + })); + } + } + Ok(Type::Paren(TypeParen { + paren_token, + elem: Box::new(first), + })) + } else if lookahead.peek(Token![fn]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) && !input.peek2(Token![::]) + { + let mut bare_fn: TypeBareFn = input.parse()?; + bare_fn.lifetimes = lifetimes; + Ok(Type::BareFn(bare_fn)) + } else if lookahead.peek(Ident) + || input.peek(Token![super]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![crate]) + || input.peek(Token![extern]) + || lookahead.peek(Token![::]) + || lookahead.peek(Token![<]) + { + if input.peek(Token![dyn]) { + let mut trait_object: TypeTraitObject = input.parse()?; + if lifetimes.is_some() { + match trait_object.bounds.iter_mut().next().unwrap() { + TypeParamBound::Trait(trait_bound) => { + trait_bound.lifetimes = lifetimes; + } + TypeParamBound::Lifetime(_) => unreachable!(), + } + } + return Ok(Type::TraitObject(trait_object)); + } + + let ty: TypePath = input.parse()?; + if ty.qself.is_some() { + return Ok(Type::Path(ty)); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &ty.path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tokens) = mac::parse_delimiter(input)?; + return Ok(Type::Macro(TypeMacro { + mac: Macro { + path: ty.path, + bang_token, + delimiter, + tokens, + }, + })); + } + } + + if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { + let mut bounds = Punctuated::new(); + bounds.push_value(TypeParamBound::Trait(TraitBound { + paren_token: None, + modifier: TraitBoundModifier::None, + lifetimes, + path: ty.path, + })); + if allow_plus { + while input.peek(Token![+]) { + bounds.push_punct(input.parse()?); + if input.peek(Token![>]) { + break; + } + bounds.push_value(input.parse()?); + } + } + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds, + })); + } + + Ok(Type::Path(ty)) + } else if lookahead.peek(token::Bracket) { + let content; + let bracket_token = bracketed!(content in input); + let elem: Type = content.parse()?; + if content.peek(Token![;]) { + Ok(Type::Array(TypeArray { + bracket_token, + elem: Box::new(elem), + semi_token: content.parse()?, + len: content.parse()?, + })) + } else { + Ok(Type::Slice(TypeSlice { + bracket_token, + elem: Box::new(elem), + })) + } + } else if lookahead.peek(Token![*]) { + input.parse().map(Type::Ptr) + } else if lookahead.peek(Token![&]) { + input.parse().map(Type::Reference) + } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { + input.parse().map(Type::Never) + } else if lookahead.peek(Token![impl]) { + input.parse().map(Type::ImplTrait) + } else if lookahead.peek(Token![_]) { + input.parse().map(Type::Infer) + } else if lookahead.peek(Lifetime) { + input.parse().map(Type::TraitObject) + } else { + Err(lookahead.error()) + } + } + + impl Parse for TypeSlice { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(TypeSlice { + bracket_token: bracketed!(content in input), + elem: content.parse()?, + }) + } + } + + impl Parse for TypeArray { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(TypeArray { + bracket_token: bracketed!(content in input), + elem: content.parse()?, + semi_token: content.parse()?, + len: content.parse()?, + }) + } + } + + impl Parse for TypePtr { + fn parse(input: ParseStream) -> Result<Self> { + let star_token: Token![*] = input.parse()?; + + let lookahead = input.lookahead1(); + let (const_token, mutability) = if lookahead.peek(Token![const]) { + (Some(input.parse()?), None) + } else if lookahead.peek(Token![mut]) { + (None, Some(input.parse()?)) + } else { + return Err(lookahead.error()); + }; + + Ok(TypePtr { + star_token, + const_token, + mutability, + elem: Box::new(input.call(Type::without_plus)?), + }) + } + } + + impl Parse for TypeReference { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeReference { + and_token: input.parse()?, + lifetime: input.parse()?, + mutability: input.parse()?, + // & binds tighter than +, so we don't allow + here. + elem: Box::new(input.call(Type::without_plus)?), + }) + } + } + + impl Parse for TypeBareFn { + fn parse(input: ParseStream) -> Result<Self> { + let args; + let mut variadic = None; + Ok(TypeBareFn { + lifetimes: input.parse()?, + unsafety: input.parse()?, + abi: input.parse()?, + fn_token: input.parse()?, + paren_token: parenthesized!(args in input), + inputs: { + let mut inputs = Punctuated::new(); + + while !args.is_empty() { + let attrs = args.call(Attribute::parse_outer)?; + + if inputs.empty_or_trailing() && args.peek(Token![...]) { + variadic = Some(Variadic { + attrs, + dots: args.parse()?, + }); + break; + } + + inputs.push_value(BareFnArg { + attrs, + ..args.parse()? + }); + if args.is_empty() { + break; + } + + inputs.push_punct(args.parse()?); + } + + inputs + }, + variadic, + output: input.call(ReturnType::without_plus)?, + }) + } + } + + impl Parse for TypeNever { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeNever { + bang_token: input.parse()?, + }) + } + } + + impl Parse for TypeInfer { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeInfer { + underscore_token: input.parse()?, + }) + } + } + + impl Parse for TypeTuple { + fn parse(input: ParseStream) -> Result<Self> { + let content; + let paren_token = parenthesized!(content in input); + + if content.is_empty() { + return Ok(TypeTuple { + paren_token, + elems: Punctuated::new(), + }); + } + + let first: Type = content.parse()?; + Ok(TypeTuple { + paren_token, + elems: { + let mut elems = Punctuated::new(); + elems.push_value(first); + elems.push_punct(content.parse()?); + let rest: Punctuated<Type, Token![,]> = + content.parse_terminated(Parse::parse)?; + elems.extend(rest); + elems + }, + }) + } + } + + impl Parse for TypeMacro { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeMacro { + mac: input.parse()?, + }) + } + } + + impl Parse for TypePath { + fn parse(input: ParseStream) -> Result<Self> { + let (qself, mut path) = path::parsing::qpath(input, false)?; + + if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) { + let args: ParenthesizedGenericArguments = input.parse()?; + let parenthesized = PathArguments::Parenthesized(args); + path.segments.last_mut().unwrap().arguments = parenthesized; + } + + Ok(TypePath { qself, path }) + } + } + + impl ReturnType { + pub fn without_plus(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + + pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + if input.peek(Token![->]) { + let arrow = input.parse()?; + let ty = ambig_ty(input, allow_plus)?; + Ok(ReturnType::Type(arrow, Box::new(ty))) + } else { + Ok(ReturnType::Default) + } + } + } + + impl Parse for ReturnType { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, true) + } + } + + impl Parse for TypeTraitObject { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, true) + } + } + + fn at_least_one_type(bounds: &Punctuated<TypeParamBound, Token![+]>) -> bool { + for bound in bounds { + if let TypeParamBound::Trait(_) = *bound { + return true; + } + } + false + } + + impl TypeTraitObject { + pub fn without_plus(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + + // Only allow multiple trait references if allow_plus is true. + pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + Ok(TypeTraitObject { + dyn_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + if allow_plus { + loop { + bounds.push_value(input.parse()?); + if !input.peek(Token![+]) { + break; + } + bounds.push_punct(input.parse()?); + if input.peek(Token![>]) { + break; + } + } + } else { + bounds.push_value(input.parse()?); + } + // Just lifetimes like `'a + 'b` is not a TraitObject. + if !at_least_one_type(&bounds) { + return Err(input.error("expected at least one type")); + } + bounds + }, + }) + } + } + + impl Parse for TypeImplTrait { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeImplTrait { + impl_token: input.parse()?, + // NOTE: rust-lang/rust#34511 includes discussion about whether + // or not + should be allowed in ImplTrait directly without (). + bounds: { + let mut bounds = Punctuated::new(); + loop { + bounds.push_value(input.parse()?); + if !input.peek(Token![+]) { + break; + } + bounds.push_punct(input.parse()?); + } + bounds + }, + }) + } + } + + impl Parse for TypeGroup { + fn parse(input: ParseStream) -> Result<Self> { + let group = crate::group::parse_group(input)?; + Ok(TypeGroup { + group_token: group.token, + elem: group.content.parse()?, + }) + } + } + + impl Parse for TypeParen { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + } + + impl TypeParen { + fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + let content; + Ok(TypeParen { + paren_token: parenthesized!(content in input), + elem: Box::new(ambig_ty(&content, allow_plus)?), + }) + } + } + + impl Parse for BareFnArg { + fn parse(input: ParseStream) -> Result<Self> { + Ok(BareFnArg { + attrs: input.call(Attribute::parse_outer)?, + name: { + if (input.peek(Ident) || input.peek(Token![_])) + && input.peek2(Token![:]) + && !input.peek2(Token![::]) + { + let name = input.call(Ident::parse_any)?; + let colon: Token![:] = input.parse()?; + Some((name, colon)) + } else { + None + } + }, + ty: match input.parse::<Option<Token![...]>>()? { + Some(dot3) => { + let args = vec![ + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Alone)), + ]; + let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map( + |(mut arg, span)| { + arg.set_span(*span); + arg + }, + )); + Type::Verbatim(tokens) + } + None => input.parse()?, + }, + }) + } + } + + impl Parse for Abi { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Abi { + extern_token: input.parse()?, + name: input.parse()?, + }) + } + } + + impl Parse for Option<Abi> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![extern]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use crate::attr::FilterAttrs; + use crate::print::TokensOrDefault; + + 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(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(variadic) = &self.variadic { + if !self.inputs.empty_or_trailing() { + let span = variadic.dots.spans[0]; + Token![,](span).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) { + private::print_path(tokens, &self.qself, &self.path); + } + } + + 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 ReturnType { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + ReturnType::Default => {} + ReturnType::Type(arrow, ty) => { + arrow.to_tokens(tokens); + ty.to_tokens(tokens); + } + } + } + } + + impl ToTokens for BareFnArg { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + if let Some((name, colon)) = &self.name { + name.to_tokens(tokens); + colon.to_tokens(tokens); + } + self.ty.to_tokens(tokens); + } + } + + impl ToTokens for Variadic { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.dots.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/syn/syn.json b/syn/syn.json new file mode 100644 index 0000000..c600700 --- /dev/null +++ b/syn/syn.json @@ -0,0 +1,5616 @@ +{ + "version": "1.0.12", + "types": [ + { + "ident": "Abi", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "extern_token": { + "token": "Extern" + }, + "name": { + "option": { + "syn": "LitStr" + } + } + } + }, + { + "ident": "AngleBracketedGenericArguments", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "colon2_token": { + "option": { + "token": "Colon2" + } + }, + "lt_token": { + "token": "Lt" + }, + "args": { + "punctuated": { + "element": { + "syn": "GenericArgument" + }, + "punct": "Comma" + } + }, + "gt_token": { + "token": "Gt" + } + } + }, + { + "ident": "Arm", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "pat": { + "syn": "Pat" + }, + "guard": { + "option": { + "tuple": [ + { + "token": "If" + }, + { + "box": { + "syn": "Expr" + } + } + ] + } + }, + "fat_arrow_token": { + "token": "FatArrow" + }, + "body": { + "box": { + "syn": "Expr" + } + }, + "comma": { + "option": { + "token": "Comma" + } + } + } + }, + { + "ident": "AttrStyle", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Outer": [], + "Inner": [ + { + "token": "Bang" + } + ] + } + }, + { + "ident": "Attribute", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "pound_token": { + "token": "Pound" + }, + "style": { + "syn": "AttrStyle" + }, + "bracket_token": { + "group": "Bracket" + }, + "path": { + "syn": "Path" + }, + "tokens": { + "proc_macro2": "TokenStream" + } + } + }, + { + "ident": "BareFnArg", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "name": { + "option": { + "tuple": [ + { + "proc_macro2": "Ident" + }, + { + "token": "Colon" + } + ] + } + }, + "ty": { + "syn": "Type" + } + } + }, + { + "ident": "BinOp", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Add": [ + { + "token": "Add" + } + ], + "Sub": [ + { + "token": "Sub" + } + ], + "Mul": [ + { + "token": "Star" + } + ], + "Div": [ + { + "token": "Div" + } + ], + "Rem": [ + { + "token": "Rem" + } + ], + "And": [ + { + "token": "AndAnd" + } + ], + "Or": [ + { + "token": "OrOr" + } + ], + "BitXor": [ + { + "token": "Caret" + } + ], + "BitAnd": [ + { + "token": "And" + } + ], + "BitOr": [ + { + "token": "Or" + } + ], + "Shl": [ + { + "token": "Shl" + } + ], + "Shr": [ + { + "token": "Shr" + } + ], + "Eq": [ + { + "token": "EqEq" + } + ], + "Lt": [ + { + "token": "Lt" + } + ], + "Le": [ + { + "token": "Le" + } + ], + "Ne": [ + { + "token": "Ne" + } + ], + "Ge": [ + { + "token": "Ge" + } + ], + "Gt": [ + { + "token": "Gt" + } + ], + "AddEq": [ + { + "token": "AddEq" + } + ], + "SubEq": [ + { + "token": "SubEq" + } + ], + "MulEq": [ + { + "token": "MulEq" + } + ], + "DivEq": [ + { + "token": "DivEq" + } + ], + "RemEq": [ + { + "token": "RemEq" + } + ], + "BitXorEq": [ + { + "token": "CaretEq" + } + ], + "BitAndEq": [ + { + "token": "AndEq" + } + ], + "BitOrEq": [ + { + "token": "OrEq" + } + ], + "ShlEq": [ + { + "token": "ShlEq" + } + ], + "ShrEq": [ + { + "token": "ShrEq" + } + ] + } + }, + { + "ident": "Binding", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + }, + "eq_token": { + "token": "Eq" + }, + "ty": { + "syn": "Type" + } + } + }, + { + "ident": "Block", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "brace_token": { + "group": "Brace" + }, + "stmts": { + "vec": { + "syn": "Stmt" + } + } + } + }, + { + "ident": "BoundLifetimes", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "for_token": { + "token": "For" + }, + "lt_token": { + "token": "Lt" + }, + "lifetimes": { + "punctuated": { + "element": { + "syn": "LifetimeDef" + }, + "punct": "Comma" + } + }, + "gt_token": { + "token": "Gt" + } + } + }, + { + "ident": "ConstParam", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "const_token": { + "token": "Const" + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "syn": "Type" + }, + "eq_token": { + "option": { + "token": "Eq" + } + }, + "default": { + "option": { + "syn": "Expr" + } + } + } + }, + { + "ident": "Constraint", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "Data", + "features": { + "any": [ + "derive" + ] + }, + "variants": { + "Struct": [ + { + "syn": "DataStruct" + } + ], + "Enum": [ + { + "syn": "DataEnum" + } + ], + "Union": [ + { + "syn": "DataUnion" + } + ] + } + }, + { + "ident": "DataEnum", + "features": { + "any": [ + "derive" + ] + }, + "fields": { + "enum_token": { + "token": "Enum" + }, + "brace_token": { + "group": "Brace" + }, + "variants": { + "punctuated": { + "element": { + "syn": "Variant" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "DataStruct", + "features": { + "any": [ + "derive" + ] + }, + "fields": { + "struct_token": { + "token": "Struct" + }, + "fields": { + "syn": "Fields" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "DataUnion", + "features": { + "any": [ + "derive" + ] + }, + "fields": { + "union_token": { + "token": "Union" + }, + "fields": { + "syn": "FieldsNamed" + } + } + }, + { + "ident": "DeriveInput", + "features": { + "any": [ + "derive" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "data": { + "syn": "Data" + } + } + }, + { + "ident": "Expr", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Array": [ + { + "syn": "ExprArray" + } + ], + "Assign": [ + { + "syn": "ExprAssign" + } + ], + "AssignOp": [ + { + "syn": "ExprAssignOp" + } + ], + "Async": [ + { + "syn": "ExprAsync" + } + ], + "Await": [ + { + "syn": "ExprAwait" + } + ], + "Binary": [ + { + "syn": "ExprBinary" + } + ], + "Block": [ + { + "syn": "ExprBlock" + } + ], + "Box": [ + { + "syn": "ExprBox" + } + ], + "Break": [ + { + "syn": "ExprBreak" + } + ], + "Call": [ + { + "syn": "ExprCall" + } + ], + "Cast": [ + { + "syn": "ExprCast" + } + ], + "Closure": [ + { + "syn": "ExprClosure" + } + ], + "Continue": [ + { + "syn": "ExprContinue" + } + ], + "Field": [ + { + "syn": "ExprField" + } + ], + "ForLoop": [ + { + "syn": "ExprForLoop" + } + ], + "Group": [ + { + "syn": "ExprGroup" + } + ], + "If": [ + { + "syn": "ExprIf" + } + ], + "Index": [ + { + "syn": "ExprIndex" + } + ], + "Let": [ + { + "syn": "ExprLet" + } + ], + "Lit": [ + { + "syn": "ExprLit" + } + ], + "Loop": [ + { + "syn": "ExprLoop" + } + ], + "Macro": [ + { + "syn": "ExprMacro" + } + ], + "Match": [ + { + "syn": "ExprMatch" + } + ], + "MethodCall": [ + { + "syn": "ExprMethodCall" + } + ], + "Paren": [ + { + "syn": "ExprParen" + } + ], + "Path": [ + { + "syn": "ExprPath" + } + ], + "Range": [ + { + "syn": "ExprRange" + } + ], + "Reference": [ + { + "syn": "ExprReference" + } + ], + "Repeat": [ + { + "syn": "ExprRepeat" + } + ], + "Return": [ + { + "syn": "ExprReturn" + } + ], + "Struct": [ + { + "syn": "ExprStruct" + } + ], + "Try": [ + { + "syn": "ExprTry" + } + ], + "TryBlock": [ + { + "syn": "ExprTryBlock" + } + ], + "Tuple": [ + { + "syn": "ExprTuple" + } + ], + "Type": [ + { + "syn": "ExprType" + } + ], + "Unary": [ + { + "syn": "ExprUnary" + } + ], + "Unsafe": [ + { + "syn": "ExprUnsafe" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ], + "While": [ + { + "syn": "ExprWhile" + } + ], + "Yield": [ + { + "syn": "ExprYield" + } + ] + }, + "exhaustive": false + }, + { + "ident": "ExprArray", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "bracket_token": { + "group": "Bracket" + }, + "elems": { + "punctuated": { + "element": { + "syn": "Expr" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "ExprAssign", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "left": { + "box": { + "syn": "Expr" + } + }, + "eq_token": { + "token": "Eq" + }, + "right": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprAssignOp", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "left": { + "box": { + "syn": "Expr" + } + }, + "op": { + "syn": "BinOp" + }, + "right": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprAsync", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "async_token": { + "token": "Async" + }, + "capture": { + "option": { + "token": "Move" + } + }, + "block": { + "syn": "Block" + } + } + }, + { + "ident": "ExprAwait", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "base": { + "box": { + "syn": "Expr" + } + }, + "dot_token": { + "token": "Dot" + }, + "await_token": { + "token": "Await" + } + } + }, + { + "ident": "ExprBinary", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "left": { + "box": { + "syn": "Expr" + } + }, + "op": { + "syn": "BinOp" + }, + "right": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprBlock", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "label": { + "option": { + "syn": "Label" + } + }, + "block": { + "syn": "Block" + } + } + }, + { + "ident": "ExprBox", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "box_token": { + "token": "Box" + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprBreak", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "break_token": { + "token": "Break" + }, + "label": { + "option": { + "syn": "Lifetime" + } + }, + "expr": { + "option": { + "box": { + "syn": "Expr" + } + } + } + } + }, + { + "ident": "ExprCall", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "func": { + "box": { + "syn": "Expr" + } + }, + "paren_token": { + "group": "Paren" + }, + "args": { + "punctuated": { + "element": { + "syn": "Expr" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "ExprCast", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "as_token": { + "token": "As" + }, + "ty": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "ExprClosure", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "asyncness": { + "option": { + "token": "Async" + } + }, + "movability": { + "option": { + "token": "Static" + } + }, + "capture": { + "option": { + "token": "Move" + } + }, + "or1_token": { + "token": "Or" + }, + "inputs": { + "punctuated": { + "element": { + "syn": "Pat" + }, + "punct": "Comma" + } + }, + "or2_token": { + "token": "Or" + }, + "output": { + "syn": "ReturnType" + }, + "body": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprContinue", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "continue_token": { + "token": "Continue" + }, + "label": { + "option": { + "syn": "Lifetime" + } + } + } + }, + { + "ident": "ExprField", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "base": { + "box": { + "syn": "Expr" + } + }, + "dot_token": { + "token": "Dot" + }, + "member": { + "syn": "Member" + } + } + }, + { + "ident": "ExprForLoop", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "label": { + "option": { + "syn": "Label" + } + }, + "for_token": { + "token": "For" + }, + "pat": { + "syn": "Pat" + }, + "in_token": { + "token": "In" + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "body": { + "syn": "Block" + } + } + }, + { + "ident": "ExprGroup", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "group_token": { + "group": "Group" + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprIf", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "if_token": { + "token": "If" + }, + "cond": { + "box": { + "syn": "Expr" + } + }, + "then_branch": { + "syn": "Block" + }, + "else_branch": { + "option": { + "tuple": [ + { + "token": "Else" + }, + { + "box": { + "syn": "Expr" + } + } + ] + } + } + } + }, + { + "ident": "ExprIndex", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "bracket_token": { + "group": "Bracket" + }, + "index": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprLet", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "let_token": { + "token": "Let" + }, + "pat": { + "syn": "Pat" + }, + "eq_token": { + "token": "Eq" + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprLit", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "lit": { + "syn": "Lit" + } + } + }, + { + "ident": "ExprLoop", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "label": { + "option": { + "syn": "Label" + } + }, + "loop_token": { + "token": "Loop" + }, + "body": { + "syn": "Block" + } + } + }, + { + "ident": "ExprMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "mac": { + "syn": "Macro" + } + } + }, + { + "ident": "ExprMatch", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "match_token": { + "token": "Match" + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "brace_token": { + "group": "Brace" + }, + "arms": { + "vec": { + "syn": "Arm" + } + } + } + }, + { + "ident": "ExprMethodCall", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "receiver": { + "box": { + "syn": "Expr" + } + }, + "dot_token": { + "token": "Dot" + }, + "method": { + "proc_macro2": "Ident" + }, + "turbofish": { + "option": { + "syn": "MethodTurbofish" + } + }, + "paren_token": { + "group": "Paren" + }, + "args": { + "punctuated": { + "element": { + "syn": "Expr" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "ExprParen", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "paren_token": { + "group": "Paren" + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprPath", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "qself": { + "option": { + "syn": "QSelf" + } + }, + "path": { + "syn": "Path" + } + } + }, + { + "ident": "ExprRange", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "from": { + "option": { + "box": { + "syn": "Expr" + } + } + }, + "limits": { + "syn": "RangeLimits" + }, + "to": { + "option": { + "box": { + "syn": "Expr" + } + } + } + } + }, + { + "ident": "ExprReference", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "and_token": { + "token": "And" + }, + "raw": { + "syn": "Reserved" + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprRepeat", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "bracket_token": { + "group": "Bracket" + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "semi_token": { + "token": "Semi" + }, + "len": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprReturn", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "return_token": { + "token": "Return" + }, + "expr": { + "option": { + "box": { + "syn": "Expr" + } + } + } + } + }, + { + "ident": "ExprStruct", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "path": { + "syn": "Path" + }, + "brace_token": { + "group": "Brace" + }, + "fields": { + "punctuated": { + "element": { + "syn": "FieldValue" + }, + "punct": "Comma" + } + }, + "dot2_token": { + "option": { + "token": "Dot2" + } + }, + "rest": { + "option": { + "box": { + "syn": "Expr" + } + } + } + } + }, + { + "ident": "ExprTry", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "question_token": { + "token": "Question" + } + } + }, + { + "ident": "ExprTryBlock", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "try_token": { + "token": "Try" + }, + "block": { + "syn": "Block" + } + } + }, + { + "ident": "ExprTuple", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "paren_token": { + "group": "Paren" + }, + "elems": { + "punctuated": { + "element": { + "syn": "Expr" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "ExprType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "ExprUnary", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "op": { + "syn": "UnOp" + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "ExprUnsafe", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "unsafe_token": { + "token": "Unsafe" + }, + "block": { + "syn": "Block" + } + } + }, + { + "ident": "ExprWhile", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "label": { + "option": { + "syn": "Label" + } + }, + "while_token": { + "token": "While" + }, + "cond": { + "box": { + "syn": "Expr" + } + }, + "body": { + "syn": "Block" + } + } + }, + { + "ident": "ExprYield", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "yield_token": { + "token": "Yield" + }, + "expr": { + "option": { + "box": { + "syn": "Expr" + } + } + } + } + }, + { + "ident": "Field", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "ident": { + "option": { + "proc_macro2": "Ident" + } + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "ty": { + "syn": "Type" + } + } + }, + { + "ident": "FieldPat", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "member": { + "syn": "Member" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "pat": { + "box": { + "syn": "Pat" + } + } + } + }, + { + "ident": "FieldValue", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "member": { + "syn": "Member" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "expr": { + "syn": "Expr" + } + } + }, + { + "ident": "Fields", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Named": [ + { + "syn": "FieldsNamed" + } + ], + "Unnamed": [ + { + "syn": "FieldsUnnamed" + } + ], + "Unit": [] + } + }, + { + "ident": "FieldsNamed", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "brace_token": { + "group": "Brace" + }, + "named": { + "punctuated": { + "element": { + "syn": "Field" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "FieldsUnnamed", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "paren_token": { + "group": "Paren" + }, + "unnamed": { + "punctuated": { + "element": { + "syn": "Field" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "File", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "shebang": { + "option": { + "std": "String" + } + }, + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "items": { + "vec": { + "syn": "Item" + } + } + } + }, + { + "ident": "FnArg", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Receiver": [ + { + "syn": "Receiver" + } + ], + "Typed": [ + { + "syn": "PatType" + } + ] + } + }, + { + "ident": "ForeignItem", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Fn": [ + { + "syn": "ForeignItemFn" + } + ], + "Static": [ + { + "syn": "ForeignItemStatic" + } + ], + "Type": [ + { + "syn": "ForeignItemType" + } + ], + "Macro": [ + { + "syn": "ForeignItemMacro" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ] + }, + "exhaustive": false + }, + { + "ident": "ForeignItemFn", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "sig": { + "syn": "Signature" + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ForeignItemMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "mac": { + "syn": "Macro" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "ForeignItemStatic", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "static_token": { + "token": "Static" + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "box": { + "syn": "Type" + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ForeignItemType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "type_token": { + "token": "Type" + }, + "ident": { + "proc_macro2": "Ident" + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "GenericArgument", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Lifetime": [ + { + "syn": "Lifetime" + } + ], + "Type": [ + { + "syn": "Type" + } + ], + "Binding": [ + { + "syn": "Binding" + } + ], + "Constraint": [ + { + "syn": "Constraint" + } + ], + "Const": [ + { + "syn": "Expr" + } + ] + } + }, + { + "ident": "GenericMethodArgument", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Type": [ + { + "syn": "Type" + } + ], + "Const": [ + { + "syn": "Expr" + } + ] + } + }, + { + "ident": "GenericParam", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Type": [ + { + "syn": "TypeParam" + } + ], + "Lifetime": [ + { + "syn": "LifetimeDef" + } + ], + "Const": [ + { + "syn": "ConstParam" + } + ] + } + }, + { + "ident": "Generics", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lt_token": { + "option": { + "token": "Lt" + } + }, + "params": { + "punctuated": { + "element": { + "syn": "GenericParam" + }, + "punct": "Comma" + } + }, + "gt_token": { + "option": { + "token": "Gt" + } + }, + "where_clause": { + "option": { + "syn": "WhereClause" + } + } + } + }, + { + "ident": "ImplItem", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Const": [ + { + "syn": "ImplItemConst" + } + ], + "Method": [ + { + "syn": "ImplItemMethod" + } + ], + "Type": [ + { + "syn": "ImplItemType" + } + ], + "Macro": [ + { + "syn": "ImplItemMacro" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ] + }, + "exhaustive": false + }, + { + "ident": "ImplItemConst", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "defaultness": { + "option": { + "token": "Default" + } + }, + "const_token": { + "token": "Const" + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "syn": "Type" + }, + "eq_token": { + "token": "Eq" + }, + "expr": { + "syn": "Expr" + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ImplItemMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "mac": { + "syn": "Macro" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "ImplItemMethod", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "defaultness": { + "option": { + "token": "Default" + } + }, + "sig": { + "syn": "Signature" + }, + "block": { + "syn": "Block" + } + } + }, + { + "ident": "ImplItemType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "defaultness": { + "option": { + "token": "Default" + } + }, + "type_token": { + "token": "Type" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "eq_token": { + "token": "Eq" + }, + "ty": { + "syn": "Type" + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "Index", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "index": { + "std": "u32" + }, + "span": { + "proc_macro2": "Span" + } + } + }, + { + "ident": "Item", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Const": [ + { + "syn": "ItemConst" + } + ], + "Enum": [ + { + "syn": "ItemEnum" + } + ], + "ExternCrate": [ + { + "syn": "ItemExternCrate" + } + ], + "Fn": [ + { + "syn": "ItemFn" + } + ], + "ForeignMod": [ + { + "syn": "ItemForeignMod" + } + ], + "Impl": [ + { + "syn": "ItemImpl" + } + ], + "Macro": [ + { + "syn": "ItemMacro" + } + ], + "Macro2": [ + { + "syn": "ItemMacro2" + } + ], + "Mod": [ + { + "syn": "ItemMod" + } + ], + "Static": [ + { + "syn": "ItemStatic" + } + ], + "Struct": [ + { + "syn": "ItemStruct" + } + ], + "Trait": [ + { + "syn": "ItemTrait" + } + ], + "TraitAlias": [ + { + "syn": "ItemTraitAlias" + } + ], + "Type": [ + { + "syn": "ItemType" + } + ], + "Union": [ + { + "syn": "ItemUnion" + } + ], + "Use": [ + { + "syn": "ItemUse" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ] + }, + "exhaustive": false + }, + { + "ident": "ItemConst", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "const_token": { + "token": "Const" + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "box": { + "syn": "Type" + } + }, + "eq_token": { + "token": "Eq" + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ItemEnum", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "enum_token": { + "token": "Enum" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "brace_token": { + "group": "Brace" + }, + "variants": { + "punctuated": { + "element": { + "syn": "Variant" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "ItemExternCrate", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "extern_token": { + "token": "Extern" + }, + "crate_token": { + "token": "Crate" + }, + "ident": { + "proc_macro2": "Ident" + }, + "rename": { + "option": { + "tuple": [ + { + "token": "As" + }, + { + "proc_macro2": "Ident" + } + ] + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ItemFn", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "sig": { + "syn": "Signature" + }, + "block": { + "box": { + "syn": "Block" + } + } + } + }, + { + "ident": "ItemForeignMod", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "abi": { + "syn": "Abi" + }, + "brace_token": { + "group": "Brace" + }, + "items": { + "vec": { + "syn": "ForeignItem" + } + } + } + }, + { + "ident": "ItemImpl", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "defaultness": { + "option": { + "token": "Default" + } + }, + "unsafety": { + "option": { + "token": "Unsafe" + } + }, + "impl_token": { + "token": "Impl" + }, + "generics": { + "syn": "Generics" + }, + "trait_": { + "option": { + "tuple": [ + { + "option": { + "token": "Bang" + } + }, + { + "syn": "Path" + }, + { + "token": "For" + } + ] + } + }, + "self_ty": { + "box": { + "syn": "Type" + } + }, + "brace_token": { + "group": "Brace" + }, + "items": { + "vec": { + "syn": "ImplItem" + } + } + } + }, + { + "ident": "ItemMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "ident": { + "option": { + "proc_macro2": "Ident" + } + }, + "mac": { + "syn": "Macro" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "ItemMacro2", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "macro_token": { + "token": "Macro" + }, + "ident": { + "proc_macro2": "Ident" + }, + "rules": { + "proc_macro2": "TokenStream" + } + } + }, + { + "ident": "ItemMod", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "mod_token": { + "token": "Mod" + }, + "ident": { + "proc_macro2": "Ident" + }, + "content": { + "option": { + "tuple": [ + { + "group": "Brace" + }, + { + "vec": { + "syn": "Item" + } + } + ] + } + }, + "semi": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "ItemStatic", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "static_token": { + "token": "Static" + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "box": { + "syn": "Type" + } + }, + "eq_token": { + "token": "Eq" + }, + "expr": { + "box": { + "syn": "Expr" + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ItemStruct", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "struct_token": { + "token": "Struct" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "fields": { + "syn": "Fields" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "ItemTrait", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "unsafety": { + "option": { + "token": "Unsafe" + } + }, + "auto_token": { + "option": { + "token": "Auto" + } + }, + "trait_token": { + "token": "Trait" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "supertraits": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + }, + "brace_token": { + "group": "Brace" + }, + "items": { + "vec": { + "syn": "TraitItem" + } + } + } + }, + { + "ident": "ItemTraitAlias", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "trait_token": { + "token": "Trait" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "eq_token": { + "token": "Eq" + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ItemType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "type_token": { + "token": "Type" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "eq_token": { + "token": "Eq" + }, + "ty": { + "box": { + "syn": "Type" + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "ItemUnion", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "union_token": { + "token": "Union" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "fields": { + "syn": "FieldsNamed" + } + } + }, + { + "ident": "ItemUse", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "vis": { + "syn": "Visibility" + }, + "use_token": { + "token": "Use" + }, + "leading_colon": { + "option": { + "token": "Colon2" + } + }, + "tree": { + "syn": "UseTree" + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "Label", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "name": { + "syn": "Lifetime" + }, + "colon_token": { + "token": "Colon" + } + } + }, + { + "ident": "Lifetime", + "features": { + "any": [] + }, + "fields": { + "apostrophe": { + "proc_macro2": "Span" + }, + "ident": { + "proc_macro2": "Ident" + } + } + }, + { + "ident": "LifetimeDef", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "lifetime": { + "syn": "Lifetime" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "bounds": { + "punctuated": { + "element": { + "syn": "Lifetime" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "Lit", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Str": [ + { + "syn": "LitStr" + } + ], + "ByteStr": [ + { + "syn": "LitByteStr" + } + ], + "Byte": [ + { + "syn": "LitByte" + } + ], + "Char": [ + { + "syn": "LitChar" + } + ], + "Int": [ + { + "syn": "LitInt" + } + ], + "Float": [ + { + "syn": "LitFloat" + } + ], + "Bool": [ + { + "syn": "LitBool" + } + ], + "Verbatim": [ + { + "proc_macro2": "Literal" + } + ] + } + }, + { + "ident": "LitBool", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "value": { + "std": "bool" + }, + "span": { + "proc_macro2": "Span" + } + } + }, + { + "ident": "LitByte", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "LitByteStr", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "LitChar", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "LitFloat", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "LitInt", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "LitStr", + "features": { + "any": [ + "derive", + "full" + ] + } + }, + { + "ident": "Local", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "let_token": { + "token": "Let" + }, + "pat": { + "syn": "Pat" + }, + "init": { + "option": { + "tuple": [ + { + "token": "Eq" + }, + { + "box": { + "syn": "Expr" + } + } + ] + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "Macro", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "path": { + "syn": "Path" + }, + "bang_token": { + "token": "Bang" + }, + "delimiter": { + "syn": "MacroDelimiter" + }, + "tokens": { + "proc_macro2": "TokenStream" + } + } + }, + { + "ident": "MacroDelimiter", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Paren": [ + { + "group": "Paren" + } + ], + "Brace": [ + { + "group": "Brace" + } + ], + "Bracket": [ + { + "group": "Bracket" + } + ] + } + }, + { + "ident": "Member", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Named": [ + { + "proc_macro2": "Ident" + } + ], + "Unnamed": [ + { + "syn": "Index" + } + ] + } + }, + { + "ident": "Meta", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Path": [ + { + "syn": "Path" + } + ], + "List": [ + { + "syn": "MetaList" + } + ], + "NameValue": [ + { + "syn": "MetaNameValue" + } + ] + } + }, + { + "ident": "MetaList", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "path": { + "syn": "Path" + }, + "paren_token": { + "group": "Paren" + }, + "nested": { + "punctuated": { + "element": { + "syn": "NestedMeta" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "MetaNameValue", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "path": { + "syn": "Path" + }, + "eq_token": { + "token": "Eq" + }, + "lit": { + "syn": "Lit" + } + } + }, + { + "ident": "MethodTurbofish", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "colon2_token": { + "token": "Colon2" + }, + "lt_token": { + "token": "Lt" + }, + "args": { + "punctuated": { + "element": { + "syn": "GenericMethodArgument" + }, + "punct": "Comma" + } + }, + "gt_token": { + "token": "Gt" + } + } + }, + { + "ident": "NestedMeta", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Meta": [ + { + "syn": "Meta" + } + ], + "Lit": [ + { + "syn": "Lit" + } + ] + } + }, + { + "ident": "ParenthesizedGenericArguments", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "paren_token": { + "group": "Paren" + }, + "inputs": { + "punctuated": { + "element": { + "syn": "Type" + }, + "punct": "Comma" + } + }, + "output": { + "syn": "ReturnType" + } + } + }, + { + "ident": "Pat", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Box": [ + { + "syn": "PatBox" + } + ], + "Ident": [ + { + "syn": "PatIdent" + } + ], + "Lit": [ + { + "syn": "PatLit" + } + ], + "Macro": [ + { + "syn": "PatMacro" + } + ], + "Or": [ + { + "syn": "PatOr" + } + ], + "Path": [ + { + "syn": "PatPath" + } + ], + "Range": [ + { + "syn": "PatRange" + } + ], + "Reference": [ + { + "syn": "PatReference" + } + ], + "Rest": [ + { + "syn": "PatRest" + } + ], + "Slice": [ + { + "syn": "PatSlice" + } + ], + "Struct": [ + { + "syn": "PatStruct" + } + ], + "Tuple": [ + { + "syn": "PatTuple" + } + ], + "TupleStruct": [ + { + "syn": "PatTupleStruct" + } + ], + "Type": [ + { + "syn": "PatType" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ], + "Wild": [ + { + "syn": "PatWild" + } + ] + }, + "exhaustive": false + }, + { + "ident": "PatBox", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "box_token": { + "token": "Box" + }, + "pat": { + "box": { + "syn": "Pat" + } + } + } + }, + { + "ident": "PatIdent", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "by_ref": { + "option": { + "token": "Ref" + } + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "ident": { + "proc_macro2": "Ident" + }, + "subpat": { + "option": { + "tuple": [ + { + "token": "At" + }, + { + "box": { + "syn": "Pat" + } + } + ] + } + } + } + }, + { + "ident": "PatLit", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "expr": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "PatMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "mac": { + "syn": "Macro" + } + } + }, + { + "ident": "PatOr", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "leading_vert": { + "option": { + "token": "Or" + } + }, + "cases": { + "punctuated": { + "element": { + "syn": "Pat" + }, + "punct": "Or" + } + } + } + }, + { + "ident": "PatPath", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "qself": { + "option": { + "syn": "QSelf" + } + }, + "path": { + "syn": "Path" + } + } + }, + { + "ident": "PatRange", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "lo": { + "box": { + "syn": "Expr" + } + }, + "limits": { + "syn": "RangeLimits" + }, + "hi": { + "box": { + "syn": "Expr" + } + } + } + }, + { + "ident": "PatReference", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "and_token": { + "token": "And" + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "pat": { + "box": { + "syn": "Pat" + } + } + } + }, + { + "ident": "PatRest", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "dot2_token": { + "token": "Dot2" + } + } + }, + { + "ident": "PatSlice", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "bracket_token": { + "group": "Bracket" + }, + "elems": { + "punctuated": { + "element": { + "syn": "Pat" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "PatStruct", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "path": { + "syn": "Path" + }, + "brace_token": { + "group": "Brace" + }, + "fields": { + "punctuated": { + "element": { + "syn": "FieldPat" + }, + "punct": "Comma" + } + }, + "dot2_token": { + "option": { + "token": "Dot2" + } + } + } + }, + { + "ident": "PatTuple", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "paren_token": { + "group": "Paren" + }, + "elems": { + "punctuated": { + "element": { + "syn": "Pat" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "PatTupleStruct", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "path": { + "syn": "Path" + }, + "pat": { + "syn": "PatTuple" + } + } + }, + { + "ident": "PatType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "pat": { + "box": { + "syn": "Pat" + } + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "PatWild", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "underscore_token": { + "token": "Underscore" + } + } + }, + { + "ident": "Path", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "leading_colon": { + "option": { + "token": "Colon2" + } + }, + "segments": { + "punctuated": { + "element": { + "syn": "PathSegment" + }, + "punct": "Colon2" + } + } + } + }, + { + "ident": "PathArguments", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "None": [], + "AngleBracketed": [ + { + "syn": "AngleBracketedGenericArguments" + } + ], + "Parenthesized": [ + { + "syn": "ParenthesizedGenericArguments" + } + ] + } + }, + { + "ident": "PathSegment", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + }, + "arguments": { + "syn": "PathArguments" + } + } + }, + { + "ident": "PredicateEq", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lhs_ty": { + "syn": "Type" + }, + "eq_token": { + "token": "Eq" + }, + "rhs_ty": { + "syn": "Type" + } + } + }, + { + "ident": "PredicateLifetime", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lifetime": { + "syn": "Lifetime" + }, + "colon_token": { + "token": "Colon" + }, + "bounds": { + "punctuated": { + "element": { + "syn": "Lifetime" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "PredicateType", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lifetimes": { + "option": { + "syn": "BoundLifetimes" + } + }, + "bounded_ty": { + "syn": "Type" + }, + "colon_token": { + "token": "Colon" + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "QSelf", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lt_token": { + "token": "Lt" + }, + "ty": { + "box": { + "syn": "Type" + } + }, + "position": { + "std": "usize" + }, + "as_token": { + "option": { + "token": "As" + } + }, + "gt_token": { + "token": "Gt" + } + } + }, + { + "ident": "RangeLimits", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "HalfOpen": [ + { + "token": "Dot2" + } + ], + "Closed": [ + { + "token": "DotDotEq" + } + ] + } + }, + { + "ident": "Receiver", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "reference": { + "option": { + "tuple": [ + { + "token": "And" + }, + { + "option": { + "syn": "Lifetime" + } + } + ] + } + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "self_token": { + "token": "SelfValue" + } + } + }, + { + "ident": "ReturnType", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Default": [], + "Type": [ + { + "token": "RArrow" + }, + { + "box": { + "syn": "Type" + } + } + ] + } + }, + { + "ident": "Signature", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "constness": { + "option": { + "token": "Const" + } + }, + "asyncness": { + "option": { + "token": "Async" + } + }, + "unsafety": { + "option": { + "token": "Unsafe" + } + }, + "abi": { + "option": { + "syn": "Abi" + } + }, + "fn_token": { + "token": "Fn" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "paren_token": { + "group": "Paren" + }, + "inputs": { + "punctuated": { + "element": { + "syn": "FnArg" + }, + "punct": "Comma" + } + }, + "variadic": { + "option": { + "syn": "Variadic" + } + }, + "output": { + "syn": "ReturnType" + } + } + }, + { + "ident": "Stmt", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Local": [ + { + "syn": "Local" + } + ], + "Item": [ + { + "syn": "Item" + } + ], + "Expr": [ + { + "syn": "Expr" + } + ], + "Semi": [ + { + "syn": "Expr" + }, + { + "token": "Semi" + } + ] + } + }, + { + "ident": "TraitBound", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "paren_token": { + "option": { + "group": "Paren" + } + }, + "modifier": { + "syn": "TraitBoundModifier" + }, + "lifetimes": { + "option": { + "syn": "BoundLifetimes" + } + }, + "path": { + "syn": "Path" + } + } + }, + { + "ident": "TraitBoundModifier", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "None": [], + "Maybe": [ + { + "token": "Question" + } + ] + } + }, + { + "ident": "TraitItem", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Const": [ + { + "syn": "TraitItemConst" + } + ], + "Method": [ + { + "syn": "TraitItemMethod" + } + ], + "Type": [ + { + "syn": "TraitItemType" + } + ], + "Macro": [ + { + "syn": "TraitItemMacro" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ] + }, + "exhaustive": false + }, + { + "ident": "TraitItemConst", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "const_token": { + "token": "Const" + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "token": "Colon" + }, + "ty": { + "syn": "Type" + }, + "default": { + "option": { + "tuple": [ + { + "token": "Eq" + }, + { + "syn": "Expr" + } + ] + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "TraitItemMacro", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "mac": { + "syn": "Macro" + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "TraitItemMethod", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "sig": { + "syn": "Signature" + }, + "default": { + "option": { + "syn": "Block" + } + }, + "semi_token": { + "option": { + "token": "Semi" + } + } + } + }, + { + "ident": "TraitItemType", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "type_token": { + "token": "Type" + }, + "ident": { + "proc_macro2": "Ident" + }, + "generics": { + "syn": "Generics" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + }, + "default": { + "option": { + "tuple": [ + { + "token": "Eq" + }, + { + "syn": "Type" + } + ] + } + }, + "semi_token": { + "token": "Semi" + } + } + }, + { + "ident": "Type", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Array": [ + { + "syn": "TypeArray" + } + ], + "BareFn": [ + { + "syn": "TypeBareFn" + } + ], + "Group": [ + { + "syn": "TypeGroup" + } + ], + "ImplTrait": [ + { + "syn": "TypeImplTrait" + } + ], + "Infer": [ + { + "syn": "TypeInfer" + } + ], + "Macro": [ + { + "syn": "TypeMacro" + } + ], + "Never": [ + { + "syn": "TypeNever" + } + ], + "Paren": [ + { + "syn": "TypeParen" + } + ], + "Path": [ + { + "syn": "TypePath" + } + ], + "Ptr": [ + { + "syn": "TypePtr" + } + ], + "Reference": [ + { + "syn": "TypeReference" + } + ], + "Slice": [ + { + "syn": "TypeSlice" + } + ], + "TraitObject": [ + { + "syn": "TypeTraitObject" + } + ], + "Tuple": [ + { + "syn": "TypeTuple" + } + ], + "Verbatim": [ + { + "proc_macro2": "TokenStream" + } + ] + }, + "exhaustive": false + }, + { + "ident": "TypeArray", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "bracket_token": { + "group": "Bracket" + }, + "elem": { + "box": { + "syn": "Type" + } + }, + "semi_token": { + "token": "Semi" + }, + "len": { + "syn": "Expr" + } + } + }, + { + "ident": "TypeBareFn", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "lifetimes": { + "option": { + "syn": "BoundLifetimes" + } + }, + "unsafety": { + "option": { + "token": "Unsafe" + } + }, + "abi": { + "option": { + "syn": "Abi" + } + }, + "fn_token": { + "token": "Fn" + }, + "paren_token": { + "group": "Paren" + }, + "inputs": { + "punctuated": { + "element": { + "syn": "BareFnArg" + }, + "punct": "Comma" + } + }, + "variadic": { + "option": { + "syn": "Variadic" + } + }, + "output": { + "syn": "ReturnType" + } + } + }, + { + "ident": "TypeGroup", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "group_token": { + "group": "Group" + }, + "elem": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypeImplTrait", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "impl_token": { + "token": "Impl" + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "TypeInfer", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "underscore_token": { + "token": "Underscore" + } + } + }, + { + "ident": "TypeMacro", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "mac": { + "syn": "Macro" + } + } + }, + { + "ident": "TypeNever", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "bang_token": { + "token": "Bang" + } + } + }, + { + "ident": "TypeParam", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "ident": { + "proc_macro2": "Ident" + }, + "colon_token": { + "option": { + "token": "Colon" + } + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + }, + "eq_token": { + "option": { + "token": "Eq" + } + }, + "default": { + "option": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypeParamBound", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Trait": [ + { + "syn": "TraitBound" + } + ], + "Lifetime": [ + { + "syn": "Lifetime" + } + ] + } + }, + { + "ident": "TypeParen", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "paren_token": { + "group": "Paren" + }, + "elem": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypePath", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "qself": { + "option": { + "syn": "QSelf" + } + }, + "path": { + "syn": "Path" + } + } + }, + { + "ident": "TypePtr", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "star_token": { + "token": "Star" + }, + "const_token": { + "option": { + "token": "Const" + } + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "elem": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypeReference", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "and_token": { + "token": "And" + }, + "lifetime": { + "option": { + "syn": "Lifetime" + } + }, + "mutability": { + "option": { + "token": "Mut" + } + }, + "elem": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypeSlice", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "bracket_token": { + "group": "Bracket" + }, + "elem": { + "box": { + "syn": "Type" + } + } + } + }, + { + "ident": "TypeTraitObject", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "dyn_token": { + "option": { + "token": "Dyn" + } + }, + "bounds": { + "punctuated": { + "element": { + "syn": "TypeParamBound" + }, + "punct": "Add" + } + } + } + }, + { + "ident": "TypeTuple", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "paren_token": { + "group": "Paren" + }, + "elems": { + "punctuated": { + "element": { + "syn": "Type" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "UnOp", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Deref": [ + { + "token": "Star" + } + ], + "Not": [ + { + "token": "Bang" + } + ], + "Neg": [ + { + "token": "Sub" + } + ] + } + }, + { + "ident": "UseGlob", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "star_token": { + "token": "Star" + } + } + }, + { + "ident": "UseGroup", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "brace_token": { + "group": "Brace" + }, + "items": { + "punctuated": { + "element": { + "syn": "UseTree" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "UseName", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + } + } + }, + { + "ident": "UsePath", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + }, + "colon2_token": { + "token": "Colon2" + }, + "tree": { + "box": { + "syn": "UseTree" + } + } + } + }, + { + "ident": "UseRename", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "ident": { + "proc_macro2": "Ident" + }, + "as_token": { + "token": "As" + }, + "rename": { + "proc_macro2": "Ident" + } + } + }, + { + "ident": "UseTree", + "features": { + "any": [ + "full" + ] + }, + "variants": { + "Path": [ + { + "syn": "UsePath" + } + ], + "Name": [ + { + "syn": "UseName" + } + ], + "Rename": [ + { + "syn": "UseRename" + } + ], + "Glob": [ + { + "syn": "UseGlob" + } + ], + "Group": [ + { + "syn": "UseGroup" + } + ] + } + }, + { + "ident": "Variadic", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "dots": { + "token": "Dot3" + } + } + }, + { + "ident": "Variant", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "ident": { + "proc_macro2": "Ident" + }, + "fields": { + "syn": "Fields" + }, + "discriminant": { + "option": { + "tuple": [ + { + "token": "Eq" + }, + { + "syn": "Expr" + } + ] + } + } + } + }, + { + "ident": "VisCrate", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "crate_token": { + "token": "Crate" + } + } + }, + { + "ident": "VisPublic", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "pub_token": { + "token": "Pub" + } + } + }, + { + "ident": "VisRestricted", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "pub_token": { + "token": "Pub" + }, + "paren_token": { + "group": "Paren" + }, + "in_token": { + "option": { + "token": "In" + } + }, + "path": { + "box": { + "syn": "Path" + } + } + } + }, + { + "ident": "Visibility", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Public": [ + { + "syn": "VisPublic" + } + ], + "Crate": [ + { + "syn": "VisCrate" + } + ], + "Restricted": [ + { + "syn": "VisRestricted" + } + ], + "Inherited": [] + } + }, + { + "ident": "WhereClause", + "features": { + "any": [ + "derive", + "full" + ] + }, + "fields": { + "where_token": { + "token": "Where" + }, + "predicates": { + "punctuated": { + "element": { + "syn": "WherePredicate" + }, + "punct": "Comma" + } + } + } + }, + { + "ident": "WherePredicate", + "features": { + "any": [ + "derive", + "full" + ] + }, + "variants": { + "Type": [ + { + "syn": "PredicateType" + } + ], + "Lifetime": [ + { + "syn": "PredicateLifetime" + } + ], + "Eq": [ + { + "syn": "PredicateEq" + } + ] + } + } + ], + "tokens": { + "Abstract": "abstract", + "Add": "+", + "AddEq": "+=", + "And": "&", + "AndAnd": "&&", + "AndEq": "&=", + "As": "as", + "Async": "async", + "At": "@", + "Auto": "auto", + "Await": "await", + "Bang": "!", + "Become": "become", + "Box": "box", + "Break": "break", + "Caret": "^", + "CaretEq": "^=", + "Colon": ":", + "Colon2": "::", + "Comma": ",", + "Const": "const", + "Continue": "continue", + "Crate": "crate", + "Default": "default", + "Div": "/", + "DivEq": "/=", + "Do": "do", + "Dollar": "$", + "Dot": ".", + "Dot2": "..", + "Dot3": "...", + "DotDotEq": "..=", + "Dyn": "dyn", + "Else": "else", + "Enum": "enum", + "Eq": "=", + "EqEq": "==", + "Extern": "extern", + "FatArrow": "=>", + "Final": "final", + "Fn": "fn", + "For": "for", + "Ge": ">=", + "Gt": ">", + "If": "if", + "Impl": "impl", + "In": "in", + "LArrow": "<-", + "Le": "<=", + "Let": "let", + "Loop": "loop", + "Lt": "<", + "Macro": "macro", + "Match": "match", + "Mod": "mod", + "Move": "move", + "MulEq": "*=", + "Mut": "mut", + "Ne": "!=", + "Or": "|", + "OrEq": "|=", + "OrOr": "||", + "Override": "override", + "Pound": "#", + "Priv": "priv", + "Pub": "pub", + "Question": "?", + "RArrow": "->", + "Ref": "ref", + "Rem": "%", + "RemEq": "%=", + "Return": "return", + "SelfType": "Self", + "SelfValue": "self", + "Semi": ";", + "Shl": "<<", + "ShlEq": "<<=", + "Shr": ">>", + "ShrEq": ">>=", + "Star": "*", + "Static": "static", + "Struct": "struct", + "Sub": "-", + "SubEq": "-=", + "Super": "super", + "Tilde": "~", + "Trait": "trait", + "Try": "try", + "Type": "type", + "Typeof": "typeof", + "Underscore": "_", + "Union": "union", + "Unsafe": "unsafe", + "Unsized": "unsized", + "Use": "use", + "Virtual": "virtual", + "Where": "where", + "While": "while", + "Yield": "yield" + } +} diff --git a/syn/tests/common/eq.rs b/syn/tests/common/eq.rs new file mode 100644 index 0000000..098f833 --- /dev/null +++ b/syn/tests/common/eq.rs @@ -0,0 +1,459 @@ +extern crate rustc_data_structures; +extern crate rustc_span; +extern crate rustc_target; +extern crate syntax; + +use std::mem; + +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::thin_vec::ThinVec; +use rustc_span::{Span, SyntaxContext, DUMMY_SP}; +use syntax::ast::{ + AngleBracketedArgs, AnonConst, Arm, AsmDialect, AssocItem, AssocItemKind, AssocTyConstraint, + AssocTyConstraintKind, AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy, BinOpKind, + BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Constness, Crate, CrateSugar, + Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader, + FnSig, ForeignItem, ForeignItemKind, ForeignMod, FunctionRetTy, GenericArg, GenericArgs, + GenericBound, GenericParam, GenericParamKind, Generics, GlobalAsm, Ident, ImplPolarity, + InlineAsm, InlineAsmOutput, IntTy, IsAsync, IsAuto, Item, ItemKind, Label, Lifetime, Lit, + LitFloatType, LitIntType, LitKind, Local, Mac, MacArgs, MacDelimiter, MacStmtStyle, MacroDef, + Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind, Path, + PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrLit, + StrStyle, StructField, TraitBoundModifier, TraitObjectSyntax, TraitRef, Ty, TyKind, UintTy, + UnOp, UnsafeSource, Unsafety, UseTree, UseTreeKind, Variant, VariantData, VisibilityKind, + WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate, +}; +use syntax::ptr::P; +use syntax::source_map::Spanned; +use syntax::symbol::{sym, Symbol}; +use syntax::token::{self, DelimToken, Token, TokenKind}; +use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use syntax::util::comments; + +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!(DelimSpan); +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!(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 { .. } => {} + )* + } + #[allow(unreachable_patterns)] + 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 constraints); +spanless_eq_struct!(AnonConst; id value); +spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder); +spanless_eq_struct!(AssocItem; attrs id span vis ident defaultness generics kind !tokens); +spanless_eq_struct!(AssocTyConstraint; id ident kind span); +spanless_eq_struct!(AttrItem; path args); +spanless_eq_struct!(Attribute; kind id style span); +spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl); +spanless_eq_struct!(Block; stmts id rules span); +spanless_eq_struct!(Crate; module attrs span); +spanless_eq_struct!(EnumDef; variants); +spanless_eq_struct!(Expr; id kind span attrs); +spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder); +spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder); +spanless_eq_struct!(FnDecl; inputs output); +spanless_eq_struct!(FnHeader; constness asyncness unsafety ext); +spanless_eq_struct!(FnSig; header decl); +spanless_eq_struct!(ForeignItem; attrs id span vis ident kind tokens); +spanless_eq_struct!(ForeignMod; abi items); +spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind); +spanless_eq_struct!(Generics; params where_clause span); +spanless_eq_struct!(GlobalAsm; asm); +spanless_eq_struct!(InlineAsm; asm asm_str_style outputs inputs clobbers volatile alignstack dialect); +spanless_eq_struct!(InlineAsmOutput; constraint expr is_rw is_indirect); +spanless_eq_struct!(Item; attrs id span vis ident kind !tokens); +spanless_eq_struct!(Label; ident); +spanless_eq_struct!(Lifetime; id ident); +spanless_eq_struct!(Lit; token kind span); +spanless_eq_struct!(Local; pat ty init id span attrs); +spanless_eq_struct!(Mac; path args prior_type_ascription); +spanless_eq_struct!(MacroDef; body legacy); +spanless_eq_struct!(Mod; inner items inline); +spanless_eq_struct!(MutTy; ty mutbl); +spanless_eq_struct!(Param; attrs ty pat id span is_placeholder); +spanless_eq_struct!(ParenthesizedArgs; span inputs output); +spanless_eq_struct!(Pat; id kind span); +spanless_eq_struct!(Path; span segments); +spanless_eq_struct!(PathSegment; ident id args); +spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span); +spanless_eq_struct!(QSelf; ty path_span position); +spanless_eq_struct!(Stmt; id kind span); +spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped); +spanless_eq_struct!(StructField; attrs id span vis ident ty is_placeholder); +spanless_eq_struct!(Token; kind span); +spanless_eq_struct!(TraitRef; path ref_id); +spanless_eq_struct!(Ty; id kind span); +spanless_eq_struct!(UseTree; prefix kind span); +spanless_eq_struct!(Variant; attrs id span vis ident data disr_expr is_placeholder); +spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds); +spanless_eq_struct!(WhereClause; 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!(AssocItemKind; Const(0 1) Fn(0 1) TyAlias(0 1) Macro(0)); +spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds)); +spanless_eq_enum!(AttrKind; Normal(0) DocComment(0)); +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!(BorrowKind; Ref Raw); +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!(Extern; None Implicit Explicit(0)); +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) Const(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) Const(ty)); +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!(LitFloatType; Suffixed(0) Unsuffixed); +spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed); +spanless_eq_enum!(MacArgs; Empty Delimited(0 1 2) Eq(0 1)); +spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace); +spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces); +spanless_eq_enum!(Movability; Static Movable); +spanless_eq_enum!(Mutability; Mut Not); +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) Delimited(0 1 2)); +spanless_eq_enum!(TraitBoundModifier; None Maybe); +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) 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) Let(0 1) If(0 1 2) + While(0 1 2) 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) Await(0) TryBlock(0) Assign(0 1 2) AssignOp(0 1 2) + Field(0 1) Index(0 1) Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1) + Continue(0) Ret(0) InlineAsm(0) Mac(0) Struct(0 1 2) Repeat(0 1) Paren(0) + Try(0) Yield(0) Err); +spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1) + Fn(0 1 2) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(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) Bool(0) Err(0)); +spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1) + Or(0) Path(0 1) Tuple(0) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0) Rest + 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 CVarArgs); + +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 token::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 TokenKind { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TokenKind::Literal(this), TokenKind::Literal(other)) => SpanlessEq::eq(this, other), + (TokenKind::DotDotEq, _) | (TokenKind::DotDotDot, _) => match other { + TokenKind::DotDotEq | TokenKind::DotDotDot => true, + _ => false, + }, + _ => self == other, + } + } +} + +impl SpanlessEq for TokenStream { + fn eq(&self, other: &Self) -> bool { + SpanlessEq::eq(&expand_tts(self), &expand_tts(other)) + } +} + +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 { + kind: TokenKind::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(TokenKind::Pound, DUMMY_SP)); + if style == AttrStyle::Inner { + tokens.push(TokenTree::token(TokenKind::Not, DUMMY_SP)); + } + let lit = token::Lit { + kind: token::LitKind::Str, + symbol: Symbol::intern(&contents), + suffix: None, + }; + let tts = vec![ + TokenTree::token(TokenKind::Ident(sym::doc, false), DUMMY_SP), + TokenTree::token(TokenKind::Eq, DUMMY_SP), + TokenTree::token(TokenKind::Literal(lit), DUMMY_SP), + ]; + tokens.push(TokenTree::Delimited( + DelimSpan::dummy(), + DelimToken::Bracket, + tts.into_iter().collect::<TokenStream>().into(), + )); + } + tokens +} diff --git a/syn/tests/common/mod.rs b/syn/tests/common/mod.rs new file mode 100644 index 0000000..3dd2552 --- /dev/null +++ b/syn/tests/common/mod.rs @@ -0,0 +1,19 @@ +#![allow(dead_code)] + +use std::env; + +pub mod eq; +pub mod parse; + +/// 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(_) => usize::max_value(), + } +} + +/// Are we running in travis-ci.org. +pub fn travis_ci() -> bool { + env::var_os("TRAVIS").is_some() +} diff --git a/syn/tests/common/parse.rs b/syn/tests/common/parse.rs new file mode 100644 index 0000000..fc3bb96 --- /dev/null +++ b/syn/tests/common/parse.rs @@ -0,0 +1,49 @@ +extern crate rustc_expand; +extern crate rustc_parse as parse; +extern crate rustc_span; +extern crate syntax; + +use rustc_span::FileName; +use syntax::ast; +use syntax::ptr::P; +use syntax::sess::ParseSess; +use syntax::source_map::FilePathMapping; + +use std::panic; + +pub fn libsyntax_expr(input: &str) -> Option<P<ast::Expr>> { + match panic::catch_unwind(|| { + 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 + } + } +} diff --git a/syn/tests/debug/gen.rs b/syn/tests/debug/gen.rs new file mode 100644 index 0000000..8450c09 --- /dev/null +++ b/syn/tests/debug/gen.rs @@ -0,0 +1,5633 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +use super::{Lite, RefCast}; +use std::fmt::{self, Debug}; +impl Debug for Lite<syn::Abi> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Abi"); + if let Some(val) = &_val.name { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::LitStr); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("name", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::AngleBracketedGenericArguments> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("AngleBracketedGenericArguments"); + if let Some(val) = &_val.colon2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon2_token", Print::ref_cast(val)); + } + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Arm> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Arm"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + if let Some(val) = &_val.guard { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::If, Box<syn::Expr>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("guard", Print::ref_cast(val)); + } + formatter.field("body", Lite(&_val.body)); + if let Some(val) = &_val.comma { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Comma); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("comma", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::AttrStyle> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::AttrStyle::Outer => formatter.write_str("Outer"), + syn::AttrStyle::Inner(_val) => { + formatter.write_str("Inner")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Attribute> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Attribute"); + formatter.field("style", Lite(&_val.style)); + formatter.field("path", Lite(&_val.path)); + formatter.field("tokens", Lite(&_val.tokens)); + formatter.finish() + } +} +impl Debug for Lite<syn::BareFnArg> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("BareFnArg"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.name { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((proc_macro2::Ident, syn::token::Colon)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.0), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("name", Print::ref_cast(val)); + } + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::BinOp> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::BinOp::Add(_val) => { + formatter.write_str("Add")?; + Ok(()) + } + syn::BinOp::Sub(_val) => { + formatter.write_str("Sub")?; + Ok(()) + } + syn::BinOp::Mul(_val) => { + formatter.write_str("Mul")?; + Ok(()) + } + syn::BinOp::Div(_val) => { + formatter.write_str("Div")?; + Ok(()) + } + syn::BinOp::Rem(_val) => { + formatter.write_str("Rem")?; + Ok(()) + } + syn::BinOp::And(_val) => { + formatter.write_str("And")?; + Ok(()) + } + syn::BinOp::Or(_val) => { + formatter.write_str("Or")?; + Ok(()) + } + syn::BinOp::BitXor(_val) => { + formatter.write_str("BitXor")?; + Ok(()) + } + syn::BinOp::BitAnd(_val) => { + formatter.write_str("BitAnd")?; + Ok(()) + } + syn::BinOp::BitOr(_val) => { + formatter.write_str("BitOr")?; + Ok(()) + } + syn::BinOp::Shl(_val) => { + formatter.write_str("Shl")?; + Ok(()) + } + syn::BinOp::Shr(_val) => { + formatter.write_str("Shr")?; + Ok(()) + } + syn::BinOp::Eq(_val) => { + formatter.write_str("Eq")?; + Ok(()) + } + syn::BinOp::Lt(_val) => { + formatter.write_str("Lt")?; + Ok(()) + } + syn::BinOp::Le(_val) => { + formatter.write_str("Le")?; + Ok(()) + } + syn::BinOp::Ne(_val) => { + formatter.write_str("Ne")?; + Ok(()) + } + syn::BinOp::Ge(_val) => { + formatter.write_str("Ge")?; + Ok(()) + } + syn::BinOp::Gt(_val) => { + formatter.write_str("Gt")?; + Ok(()) + } + syn::BinOp::AddEq(_val) => { + formatter.write_str("AddEq")?; + Ok(()) + } + syn::BinOp::SubEq(_val) => { + formatter.write_str("SubEq")?; + Ok(()) + } + syn::BinOp::MulEq(_val) => { + formatter.write_str("MulEq")?; + Ok(()) + } + syn::BinOp::DivEq(_val) => { + formatter.write_str("DivEq")?; + Ok(()) + } + syn::BinOp::RemEq(_val) => { + formatter.write_str("RemEq")?; + Ok(()) + } + syn::BinOp::BitXorEq(_val) => { + formatter.write_str("BitXorEq")?; + Ok(()) + } + syn::BinOp::BitAndEq(_val) => { + formatter.write_str("BitAndEq")?; + Ok(()) + } + syn::BinOp::BitOrEq(_val) => { + formatter.write_str("BitOrEq")?; + Ok(()) + } + syn::BinOp::ShlEq(_val) => { + formatter.write_str("ShlEq")?; + Ok(()) + } + syn::BinOp::ShrEq(_val) => { + formatter.write_str("ShrEq")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Binding> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Binding"); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::Block> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Block"); + if !_val.stmts.is_empty() { + formatter.field("stmts", Lite(&_val.stmts)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::BoundLifetimes> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("BoundLifetimes"); + if !_val.lifetimes.is_empty() { + formatter.field("lifetimes", Lite(&_val.lifetimes)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ConstParam> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ConstParam"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + if let Some(val) = &_val.eq_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Eq); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("eq_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Expr); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Constraint> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Constraint"); + formatter.field("ident", Lite(&_val.ident)); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Data> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Data::Struct(_val) => { + let mut formatter = formatter.debug_struct("Data::Struct"); + formatter.field("fields", Lite(&_val.fields)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Data::Enum(_val) => { + let mut formatter = formatter.debug_struct("Data::Enum"); + if !_val.variants.is_empty() { + formatter.field("variants", Lite(&_val.variants)); + } + formatter.finish() + } + syn::Data::Union(_val) => { + let mut formatter = formatter.debug_struct("Data::Union"); + formatter.field("fields", Lite(&_val.fields)); + formatter.finish() + } + } + } +} +impl Debug for Lite<syn::DataEnum> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("DataEnum"); + if !_val.variants.is_empty() { + formatter.field("variants", Lite(&_val.variants)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::DataStruct> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("DataStruct"); + formatter.field("fields", Lite(&_val.fields)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::DataUnion> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("DataUnion"); + formatter.field("fields", Lite(&_val.fields)); + formatter.finish() + } +} +impl Debug for Lite<syn::DeriveInput> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("DeriveInput"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("data", Lite(&_val.data)); + formatter.finish() + } +} +impl Debug for Lite<syn::Expr> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Expr::Array(_val) => { + let mut formatter = formatter.debug_struct("Expr::Array"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } + syn::Expr::Assign(_val) => { + let mut formatter = formatter.debug_struct("Expr::Assign"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } + syn::Expr::AssignOp(_val) => { + let mut formatter = formatter.debug_struct("Expr::AssignOp"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("op", Lite(&_val.op)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } + syn::Expr::Async(_val) => { + let mut formatter = formatter.debug_struct("Expr::Async"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.capture { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Move); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("capture", Print::ref_cast(val)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::Expr::Await(_val) => { + let mut formatter = formatter.debug_struct("Expr::Await"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("base", Lite(&_val.base)); + formatter.finish() + } + syn::Expr::Binary(_val) => { + let mut formatter = formatter.debug_struct("Expr::Binary"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("op", Lite(&_val.op)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } + syn::Expr::Block(_val) => { + let mut formatter = formatter.debug_struct("Expr::Block"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::Expr::Box(_val) => { + let mut formatter = formatter.debug_struct("Expr::Box"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::Break(_val) => { + let mut formatter = formatter.debug_struct("Expr::Break"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Call(_val) => { + let mut formatter = formatter.debug_struct("Expr::Call"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("func", Lite(&_val.func)); + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } + syn::Expr::Cast(_val) => { + let mut formatter = formatter.debug_struct("Expr::Cast"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::Expr::Closure(_val) => { + let mut formatter = formatter.debug_struct("Expr::Closure"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.asyncness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Async); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("asyncness", Print::ref_cast(val)); + } + if let Some(val) = &_val.movability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Static); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("movability", Print::ref_cast(val)); + } + if let Some(val) = &_val.capture { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Move); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("capture", Print::ref_cast(val)); + } + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + formatter.field("output", Lite(&_val.output)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } + syn::Expr::Continue(_val) => { + let mut formatter = formatter.debug_struct("Expr::Continue"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Field(_val) => { + let mut formatter = formatter.debug_struct("Expr::Field"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("base", Lite(&_val.base)); + formatter.field("member", Lite(&_val.member)); + formatter.finish() + } + syn::Expr::ForLoop(_val) => { + let mut formatter = formatter.debug_struct("Expr::ForLoop"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("expr", Lite(&_val.expr)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } + syn::Expr::Group(_val) => { + let mut formatter = formatter.debug_struct("Expr::Group"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::If(_val) => { + let mut formatter = formatter.debug_struct("Expr::If"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("cond", Lite(&_val.cond)); + formatter.field("then_branch", Lite(&_val.then_branch)); + if let Some(val) = &_val.else_branch { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Else, Box<syn::Expr>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("else_branch", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Index(_val) => { + let mut formatter = formatter.debug_struct("Expr::Index"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("index", Lite(&_val.index)); + formatter.finish() + } + syn::Expr::Let(_val) => { + let mut formatter = formatter.debug_struct("Expr::Let"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::Lit(_val) => { + let mut formatter = formatter.debug_struct("Expr::Lit"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("lit", Lite(&_val.lit)); + formatter.finish() + } + syn::Expr::Loop(_val) => { + let mut formatter = formatter.debug_struct("Expr::Loop"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } + syn::Expr::Macro(_val) => { + let mut formatter = formatter.debug_struct("Expr::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } + syn::Expr::Match(_val) => { + let mut formatter = formatter.debug_struct("Expr::Match"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + if !_val.arms.is_empty() { + formatter.field("arms", Lite(&_val.arms)); + } + formatter.finish() + } + syn::Expr::MethodCall(_val) => { + let mut formatter = formatter.debug_struct("Expr::MethodCall"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("receiver", Lite(&_val.receiver)); + formatter.field("method", Lite(&_val.method)); + if let Some(val) = &_val.turbofish { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::MethodTurbofish); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("turbofish", Print::ref_cast(val)); + } + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } + syn::Expr::Paren(_val) => { + let mut formatter = formatter.debug_struct("Expr::Paren"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::Path(_val) => { + let mut formatter = formatter.debug_struct("Expr::Path"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } + syn::Expr::Range(_val) => { + let mut formatter = formatter.debug_struct("Expr::Range"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.from { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("from", Print::ref_cast(val)); + } + formatter.field("limits", Lite(&_val.limits)); + if let Some(val) = &_val.to { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("to", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Reference(_val) => { + let mut formatter = formatter.debug_struct("Expr::Reference"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::Repeat(_val) => { + let mut formatter = formatter.debug_struct("Expr::Repeat"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("len", Lite(&_val.len)); + formatter.finish() + } + syn::Expr::Return(_val) => { + let mut formatter = formatter.debug_struct("Expr::Return"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Struct(_val) => { + let mut formatter = formatter.debug_struct("Expr::Struct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + if !_val.fields.is_empty() { + formatter.field("fields", Lite(&_val.fields)); + } + if let Some(val) = &_val.dot2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dot2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dot2_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.rest { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("rest", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Expr::Try(_val) => { + let mut formatter = formatter.debug_struct("Expr::Try"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::TryBlock(_val) => { + let mut formatter = formatter.debug_struct("Expr::TryBlock"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::Expr::Tuple(_val) => { + let mut formatter = formatter.debug_struct("Expr::Tuple"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } + syn::Expr::Type(_val) => { + let mut formatter = formatter.debug_struct("Expr::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::Expr::Unary(_val) => { + let mut formatter = formatter.debug_struct("Expr::Unary"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("op", Lite(&_val.op)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Expr::Unsafe(_val) => { + let mut formatter = formatter.debug_struct("Expr::Unsafe"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::Expr::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Expr::While(_val) => { + let mut formatter = formatter.debug_struct("Expr::While"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("cond", Lite(&_val.cond)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } + syn::Expr::Yield(_val) => { + let mut formatter = formatter.debug_struct("Expr::Yield"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::ExprArray> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprArray"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprAssign> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprAssign"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprAssignOp> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprAssignOp"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("op", Lite(&_val.op)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprAsync> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprAsync"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.capture { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Move); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("capture", Print::ref_cast(val)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprAwait> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprAwait"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("base", Lite(&_val.base)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprBinary> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprBinary"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("left", Lite(&_val.left)); + formatter.field("op", Lite(&_val.op)); + formatter.field("right", Lite(&_val.right)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprBlock> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprBlock"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprBox> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprBox"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprBreak> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprBreak"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprCall> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprCall"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("func", Lite(&_val.func)); + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprCast> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprCast"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprClosure> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprClosure"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.asyncness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Async); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("asyncness", Print::ref_cast(val)); + } + if let Some(val) = &_val.movability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Static); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("movability", Print::ref_cast(val)); + } + if let Some(val) = &_val.capture { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Move); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("capture", Print::ref_cast(val)); + } + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + formatter.field("output", Lite(&_val.output)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprContinue> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprContinue"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprField> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprField"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("base", Lite(&_val.base)); + formatter.field("member", Lite(&_val.member)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprForLoop> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprForLoop"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("expr", Lite(&_val.expr)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprGroup> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprGroup"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprIf> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprIf"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("cond", Lite(&_val.cond)); + formatter.field("then_branch", Lite(&_val.then_branch)); + if let Some(val) = &_val.else_branch { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Else, Box<syn::Expr>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("else_branch", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprIndex> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprIndex"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("index", Lite(&_val.index)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprLet> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprLet"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprLit> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprLit"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("lit", Lite(&_val.lit)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprLoop> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprLoop"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprMatch> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprMatch"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + if !_val.arms.is_empty() { + formatter.field("arms", Lite(&_val.arms)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprMethodCall> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprMethodCall"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("receiver", Lite(&_val.receiver)); + formatter.field("method", Lite(&_val.method)); + if let Some(val) = &_val.turbofish { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::MethodTurbofish); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("turbofish", Print::ref_cast(val)); + } + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprParen> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprParen"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprPath> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprPath"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprRange> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprRange"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.from { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("from", Print::ref_cast(val)); + } + formatter.field("limits", Lite(&_val.limits)); + if let Some(val) = &_val.to { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("to", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprReference> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprReference"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprRepeat> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprRepeat"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("len", Lite(&_val.len)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprReturn> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprReturn"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprStruct> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprStruct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + if !_val.fields.is_empty() { + formatter.field("fields", Lite(&_val.fields)); + } + if let Some(val) = &_val.dot2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dot2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dot2_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.rest { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("rest", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprTry> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprTry"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprTryBlock> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprTryBlock"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprTuple> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprTuple"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ExprType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprUnary> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprUnary"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("op", Lite(&_val.op)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprUnsafe> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprUnsafe"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprWhile> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprWhile"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.label { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Label); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("label", Print::ref_cast(val)); + } + formatter.field("cond", Lite(&_val.cond)); + formatter.field("body", Lite(&_val.body)); + formatter.finish() + } +} +impl Debug for Lite<syn::ExprYield> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprYield"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.expr { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Box<syn::Expr>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("expr", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Field> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Field"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.ident { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(proc_macro2::Ident); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("ident", Print::ref_cast(val)); + } + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::FieldPat> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("FieldPat"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("member", Lite(&_val.member)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } +} +impl Debug for Lite<syn::FieldValue> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("FieldValue"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("member", Lite(&_val.member)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::Fields> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Fields::Named(_val) => { + let mut formatter = formatter.debug_struct("Fields::Named"); + if !_val.named.is_empty() { + formatter.field("named", Lite(&_val.named)); + } + formatter.finish() + } + syn::Fields::Unnamed(_val) => { + let mut formatter = formatter.debug_struct("Fields::Unnamed"); + if !_val.unnamed.is_empty() { + formatter.field("unnamed", Lite(&_val.unnamed)); + } + formatter.finish() + } + syn::Fields::Unit => formatter.write_str("Unit"), + } + } +} +impl Debug for Lite<syn::FieldsNamed> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("FieldsNamed"); + if !_val.named.is_empty() { + formatter.field("named", Lite(&_val.named)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::FieldsUnnamed> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("FieldsUnnamed"); + if !_val.unnamed.is_empty() { + formatter.field("unnamed", Lite(&_val.unnamed)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::File> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("File"); + if let Some(val) = &_val.shebang { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(String); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("shebang", Print::ref_cast(val)); + } + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::FnArg> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::FnArg::Receiver(_val) => { + formatter.write_str("Receiver")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::FnArg::Typed(_val) => { + formatter.write_str("Typed")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::ForeignItem> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::ForeignItem::Fn(_val) => { + let mut formatter = formatter.debug_struct("ForeignItem::Fn"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("sig", Lite(&_val.sig)); + formatter.finish() + } + syn::ForeignItem::Static(_val) => { + let mut formatter = formatter.debug_struct("ForeignItem::Static"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::ForeignItem::Type(_val) => { + let mut formatter = formatter.debug_struct("ForeignItem::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.finish() + } + syn::ForeignItem::Macro(_val) => { + let mut formatter = formatter.debug_struct("ForeignItem::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::ForeignItem::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::ForeignItemFn> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ForeignItemFn"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("sig", Lite(&_val.sig)); + formatter.finish() + } +} +impl Debug for Lite<syn::ForeignItemMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ForeignItemMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ForeignItemStatic> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ForeignItemStatic"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::ForeignItemType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ForeignItemType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.finish() + } +} +impl Debug for Lite<syn::GenericArgument> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::GenericArgument::Lifetime(_val) => { + formatter.write_str("Lifetime")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericArgument::Type(_val) => { + formatter.write_str("Type")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericArgument::Binding(_val) => { + formatter.write_str("Binding")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericArgument::Constraint(_val) => { + formatter.write_str("Constraint")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericArgument::Const(_val) => { + formatter.write_str("Const")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::GenericMethodArgument> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::GenericMethodArgument::Type(_val) => { + formatter.write_str("Type")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericMethodArgument::Const(_val) => { + formatter.write_str("Const")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::GenericParam> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::GenericParam::Type(_val) => { + formatter.write_str("Type")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericParam::Lifetime(_val) => { + formatter.write_str("Lifetime")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::GenericParam::Const(_val) => { + formatter.write_str("Const")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Generics> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Generics"); + if let Some(val) = &_val.lt_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Lt); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("lt_token", Print::ref_cast(val)); + } + if !_val.params.is_empty() { + formatter.field("params", Lite(&_val.params)); + } + if let Some(val) = &_val.gt_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Gt); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("gt_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.where_clause { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::WhereClause); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("where_clause", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ImplItem> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::ImplItem::Const(_val) => { + let mut formatter = formatter.debug_struct("ImplItem::Const"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::ImplItem::Method(_val) => { + let mut formatter = formatter.debug_struct("ImplItem::Method"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("sig", Lite(&_val.sig)); + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::ImplItem::Type(_val) => { + let mut formatter = formatter.debug_struct("ImplItem::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::ImplItem::Macro(_val) => { + let mut formatter = formatter.debug_struct("ImplItem::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::ImplItem::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::ImplItemConst> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ImplItemConst"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ImplItemMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ImplItemMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ImplItemMethod> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ImplItemMethod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("sig", Lite(&_val.sig)); + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ImplItemType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ImplItemType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::Index> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Index"); + formatter.field("index", Lite(&_val.index)); + formatter.finish() + } +} +impl Debug for Lite<syn::Item> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Item::Const(_val) => { + let mut formatter = formatter.debug_struct("Item::Const"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Item::Enum(_val) => { + let mut formatter = formatter.debug_struct("Item::Enum"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if !_val.variants.is_empty() { + formatter.field("variants", Lite(&_val.variants)); + } + formatter.finish() + } + syn::Item::ExternCrate(_val) => { + let mut formatter = formatter.debug_struct("Item::ExternCrate"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.rename { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::As, proc_macro2::Ident)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("rename", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Item::Fn(_val) => { + let mut formatter = formatter.debug_struct("Item::Fn"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("sig", Lite(&_val.sig)); + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } + syn::Item::ForeignMod(_val) => { + let mut formatter = formatter.debug_struct("Item::ForeignMod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("abi", Lite(&_val.abi)); + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } + syn::Item::Impl(_val) => { + let mut formatter = formatter.debug_struct("Item::Impl"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.trait_ { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((Option<syn::token::Bang>, syn::Path, syn::token::For)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt( + &( + { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Option<syn::token::Bang>); + impl Debug for Print { + fn fmt( + &self, + formatter: &mut fmt::Formatter, + ) -> fmt::Result + { + match &self.0 { + Some(_val) => { + formatter.write_str("Some")?; + Ok(()) + } + None => formatter.write_str("None"), + } + } + } + Print::ref_cast(&_val.0) + }, + Lite(&_val.1), + ), + formatter, + )?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("trait_", Print::ref_cast(val)); + } + formatter.field("self_ty", Lite(&_val.self_ty)); + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } + syn::Item::Macro(_val) => { + let mut formatter = formatter.debug_struct("Item::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.ident { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(proc_macro2::Ident); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("ident", Print::ref_cast(val)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Item::Macro2(_val) => { + let mut formatter = formatter.debug_struct("Item::Macro2"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("rules", Lite(&_val.rules)); + formatter.finish() + } + syn::Item::Mod(_val) => { + let mut formatter = formatter.debug_struct("Item::Mod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.content { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Brace, Vec<syn::Item>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("content", Print::ref_cast(val)); + } + if let Some(val) = &_val.semi { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Item::Static(_val) => { + let mut formatter = formatter.debug_struct("Item::Static"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Item::Struct(_val) => { + let mut formatter = formatter.debug_struct("Item::Struct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("fields", Lite(&_val.fields)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Item::Trait(_val) => { + let mut formatter = formatter.debug_struct("Item::Trait"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + if let Some(val) = &_val.auto_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Auto); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("auto_token", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.supertraits.is_empty() { + formatter.field("supertraits", Lite(&_val.supertraits)); + } + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } + syn::Item::TraitAlias(_val) => { + let mut formatter = formatter.debug_struct("Item::TraitAlias"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } + syn::Item::Type(_val) => { + let mut formatter = formatter.debug_struct("Item::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::Item::Union(_val) => { + let mut formatter = formatter.debug_struct("Item::Union"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("fields", Lite(&_val.fields)); + formatter.finish() + } + syn::Item::Use(_val) => { + let mut formatter = formatter.debug_struct("Item::Use"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.leading_colon { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("leading_colon", Print::ref_cast(val)); + } + formatter.field("tree", Lite(&_val.tree)); + formatter.finish() + } + syn::Item::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::ItemConst> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemConst"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemEnum> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemEnum"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if !_val.variants.is_empty() { + formatter.field("variants", Lite(&_val.variants)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemExternCrate> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemExternCrate"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.rename { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::As, proc_macro2::Ident)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("rename", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemFn> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemFn"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("sig", Lite(&_val.sig)); + formatter.field("block", Lite(&_val.block)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemForeignMod> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemForeignMod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("abi", Lite(&_val.abi)); + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemImpl> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemImpl"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.defaultness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Default); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("defaultness", Print::ref_cast(val)); + } + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.trait_ { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((Option<syn::token::Bang>, syn::Path, syn::token::For)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt( + &( + { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Option<syn::token::Bang>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match &self.0 { + Some(_val) => { + formatter.write_str("Some")?; + Ok(()) + } + None => formatter.write_str("None"), + } + } + } + Print::ref_cast(&_val.0) + }, + Lite(&_val.1), + ), + formatter, + )?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("trait_", Print::ref_cast(val)); + } + formatter.field("self_ty", Lite(&_val.self_ty)); + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.ident { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(proc_macro2::Ident); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("ident", Print::ref_cast(val)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemMacro2> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemMacro2"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("rules", Lite(&_val.rules)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemMod> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemMod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.content { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Brace, Vec<syn::Item>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("content", Print::ref_cast(val)); + } + if let Some(val) = &_val.semi { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemStatic> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemStatic"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemStruct> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemStruct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("fields", Lite(&_val.fields)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemTrait> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemTrait"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + if let Some(val) = &_val.auto_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Auto); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("auto_token", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.supertraits.is_empty() { + formatter.field("supertraits", Lite(&_val.supertraits)); + } + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemTraitAlias> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemTraitAlias"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ItemType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemUnion> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemUnion"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + formatter.field("fields", Lite(&_val.fields)); + formatter.finish() + } +} +impl Debug for Lite<syn::ItemUse> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ItemUse"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("vis", Lite(&_val.vis)); + if let Some(val) = &_val.leading_colon { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("leading_colon", Print::ref_cast(val)); + } + formatter.field("tree", Lite(&_val.tree)); + formatter.finish() + } +} +impl Debug for Lite<syn::Label> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Label"); + formatter.field("name", Lite(&_val.name)); + formatter.finish() + } +} +impl Debug for Lite<syn::Lifetime> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Lifetime"); + formatter.field("ident", Lite(&_val.ident)); + formatter.finish() + } +} +impl Debug for Lite<syn::LifetimeDef> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("LifetimeDef"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("lifetime", Lite(&_val.lifetime)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Lit> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Lit::Str(_val) => write!(formatter, "{:?}", _val.value()), + syn::Lit::ByteStr(_val) => write!(formatter, "{:?}", _val.value()), + syn::Lit::Byte(_val) => write!(formatter, "{:?}", _val.value()), + syn::Lit::Char(_val) => write!(formatter, "{:?}", _val.value()), + syn::Lit::Int(_val) => write!(formatter, "{}", _val), + syn::Lit::Float(_val) => write!(formatter, "{}", _val), + syn::Lit::Bool(_val) => { + let mut formatter = formatter.debug_struct("Lit::Bool"); + formatter.field("value", Lite(&_val.value)); + formatter.finish() + } + syn::Lit::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::LitBool> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("LitBool"); + formatter.field("value", Lite(&_val.value)); + formatter.finish() + } +} +impl Debug for Lite<syn::LitByte> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{:?}", _val.value()) + } +} +impl Debug for Lite<syn::LitByteStr> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{:?}", _val.value()) + } +} +impl Debug for Lite<syn::LitChar> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{:?}", _val.value()) + } +} +impl Debug for Lite<syn::LitFloat> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{}", _val) + } +} +impl Debug for Lite<syn::LitInt> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{}", _val) + } +} +impl Debug for Lite<syn::LitStr> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + write!(formatter, "{:?}", _val.value()) + } +} +impl Debug for Lite<syn::Local> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Local"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + if let Some(val) = &_val.init { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, Box<syn::Expr>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("init", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Macro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Macro"); + formatter.field("path", Lite(&_val.path)); + formatter.field("delimiter", Lite(&_val.delimiter)); + formatter.field("tokens", Lite(&_val.tokens)); + formatter.finish() + } +} +impl Debug for Lite<syn::MacroDelimiter> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::MacroDelimiter::Paren(_val) => { + formatter.write_str("Paren")?; + Ok(()) + } + syn::MacroDelimiter::Brace(_val) => { + formatter.write_str("Brace")?; + Ok(()) + } + syn::MacroDelimiter::Bracket(_val) => { + formatter.write_str("Bracket")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Member> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Member::Named(_val) => { + formatter.write_str("Named")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Member::Unnamed(_val) => { + formatter.write_str("Unnamed")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Meta> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Meta::Path(_val) => { + formatter.write_str("Path")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Meta::List(_val) => { + let mut formatter = formatter.debug_struct("Meta::List"); + formatter.field("path", Lite(&_val.path)); + if !_val.nested.is_empty() { + formatter.field("nested", Lite(&_val.nested)); + } + formatter.finish() + } + syn::Meta::NameValue(_val) => { + let mut formatter = formatter.debug_struct("Meta::NameValue"); + formatter.field("path", Lite(&_val.path)); + formatter.field("lit", Lite(&_val.lit)); + formatter.finish() + } + } + } +} +impl Debug for Lite<syn::MetaList> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("MetaList"); + formatter.field("path", Lite(&_val.path)); + if !_val.nested.is_empty() { + formatter.field("nested", Lite(&_val.nested)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::MetaNameValue> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("MetaNameValue"); + formatter.field("path", Lite(&_val.path)); + formatter.field("lit", Lite(&_val.lit)); + formatter.finish() + } +} +impl Debug for Lite<syn::MethodTurbofish> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("MethodTurbofish"); + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::NestedMeta> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::NestedMeta::Meta(_val) => { + formatter.write_str("Meta")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::NestedMeta::Lit(_val) => { + formatter.write_str("Lit")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::ParenthesizedGenericArguments> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ParenthesizedGenericArguments"); + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + formatter.field("output", Lite(&_val.output)); + formatter.finish() + } +} +impl Debug for Lite<syn::Pat> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Pat::Box(_val) => { + let mut formatter = formatter.debug_struct("Pat::Box"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } + syn::Pat::Ident(_val) => { + let mut formatter = formatter.debug_struct("Pat::Ident"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.by_ref { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Ref); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("by_ref", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.subpat { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::At, Box<syn::Pat>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("subpat", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Pat::Lit(_val) => { + let mut formatter = formatter.debug_struct("Pat::Lit"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } + syn::Pat::Macro(_val) => { + let mut formatter = formatter.debug_struct("Pat::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } + syn::Pat::Or(_val) => { + let mut formatter = formatter.debug_struct("Pat::Or"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.leading_vert { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Or); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("leading_vert", Print::ref_cast(val)); + } + if !_val.cases.is_empty() { + formatter.field("cases", Lite(&_val.cases)); + } + formatter.finish() + } + syn::Pat::Path(_val) => { + let mut formatter = formatter.debug_struct("Pat::Path"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } + syn::Pat::Range(_val) => { + let mut formatter = formatter.debug_struct("Pat::Range"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("lo", Lite(&_val.lo)); + formatter.field("limits", Lite(&_val.limits)); + formatter.field("hi", Lite(&_val.hi)); + formatter.finish() + } + syn::Pat::Reference(_val) => { + let mut formatter = formatter.debug_struct("Pat::Reference"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } + syn::Pat::Rest(_val) => { + let mut formatter = formatter.debug_struct("Pat::Rest"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } + syn::Pat::Slice(_val) => { + let mut formatter = formatter.debug_struct("Pat::Slice"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } + syn::Pat::Struct(_val) => { + let mut formatter = formatter.debug_struct("Pat::Struct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + if !_val.fields.is_empty() { + formatter.field("fields", Lite(&_val.fields)); + } + if let Some(val) = &_val.dot2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dot2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dot2_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::Pat::Tuple(_val) => { + let mut formatter = formatter.debug_struct("Pat::Tuple"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } + syn::Pat::TupleStruct(_val) => { + let mut formatter = formatter.debug_struct("Pat::TupleStruct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } + syn::Pat::Type(_val) => { + let mut formatter = formatter.debug_struct("Pat::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } + syn::Pat::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Pat::Wild(_val) => { + let mut formatter = formatter.debug_struct("Pat::Wild"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::PatBox> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatBox"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatIdent> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatIdent"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.by_ref { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Ref); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("by_ref", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.subpat { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::At, Box<syn::Pat>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("subpat", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatLit> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatLit"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("expr", Lite(&_val.expr)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatOr> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatOr"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.leading_vert { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Or); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("leading_vert", Print::ref_cast(val)); + } + if !_val.cases.is_empty() { + formatter.field("cases", Lite(&_val.cases)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatPath> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatPath"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatRange> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatRange"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("lo", Lite(&_val.lo)); + formatter.field("limits", Lite(&_val.limits)); + formatter.field("hi", Lite(&_val.hi)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatReference> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatReference"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatRest> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatRest"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatSlice> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatSlice"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatStruct> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatStruct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + if !_val.fields.is_empty() { + formatter.field("fields", Lite(&_val.fields)); + } + if let Some(val) = &_val.dot2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dot2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dot2_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatTuple> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatTuple"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PatTupleStruct> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatTupleStruct"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("path", Lite(&_val.path)); + formatter.field("pat", Lite(&_val.pat)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("pat", Lite(&_val.pat)); + formatter.field("ty", Lite(&_val.ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::PatWild> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PatWild"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Path> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Path"); + if let Some(val) = &_val.leading_colon { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("leading_colon", Print::ref_cast(val)); + } + if !_val.segments.is_empty() { + formatter.field("segments", Lite(&_val.segments)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PathArguments> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::PathArguments::None => formatter.write_str("None"), + syn::PathArguments::AngleBracketed(_val) => { + let mut formatter = formatter.debug_struct("PathArguments::AngleBracketed"); + if let Some(val) = &_val.colon2_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon2); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon2_token", Print::ref_cast(val)); + } + if !_val.args.is_empty() { + formatter.field("args", Lite(&_val.args)); + } + formatter.finish() + } + syn::PathArguments::Parenthesized(_val) => { + let mut formatter = formatter.debug_struct("PathArguments::Parenthesized"); + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + formatter.field("output", Lite(&_val.output)); + formatter.finish() + } + } + } +} +impl Debug for Lite<syn::PathSegment> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PathSegment"); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("arguments", Lite(&_val.arguments)); + formatter.finish() + } +} +impl Debug for Lite<syn::PredicateEq> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PredicateEq"); + formatter.field("lhs_ty", Lite(&_val.lhs_ty)); + formatter.field("rhs_ty", Lite(&_val.rhs_ty)); + formatter.finish() + } +} +impl Debug for Lite<syn::PredicateLifetime> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PredicateLifetime"); + formatter.field("lifetime", Lite(&_val.lifetime)); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::PredicateType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("PredicateType"); + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetimes", Print::ref_cast(val)); + } + formatter.field("bounded_ty", Lite(&_val.bounded_ty)); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::QSelf> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("QSelf"); + formatter.field("ty", Lite(&_val.ty)); + formatter.field("position", Lite(&_val.position)); + if let Some(val) = &_val.as_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::As); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("as_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::RangeLimits> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::RangeLimits::HalfOpen(_val) => { + formatter.write_str("HalfOpen")?; + Ok(()) + } + syn::RangeLimits::Closed(_val) => { + formatter.write_str("Closed")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Receiver> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Receiver"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + if let Some(val) = &_val.reference { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::And, Option<syn::Lifetime>)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt( + { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(Option<syn::Lifetime>); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match &self.0 { + Some(_val) => { + formatter.write_str("Some")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + None => formatter.write_str("None"), + } + } + } + Print::ref_cast(&_val.1) + }, + formatter, + )?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("reference", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::ReturnType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::ReturnType::Default => formatter.write_str("Default"), + syn::ReturnType::Type(_v0, _v1) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(Lite(_v1)); + formatter.finish() + } + } + } +} +impl Debug for Lite<syn::Signature> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Signature"); + if let Some(val) = &_val.constness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Const); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("constness", Print::ref_cast(val)); + } + if let Some(val) = &_val.asyncness { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Async); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("asyncness", Print::ref_cast(val)); + } + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + if let Some(val) = &_val.abi { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Abi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("abi", Print::ref_cast(val)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + if let Some(val) = &_val.variadic { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Variadic); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("variadic", Print::ref_cast(val)); + } + formatter.field("output", Lite(&_val.output)); + formatter.finish() + } +} +impl Debug for Lite<syn::Stmt> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Stmt::Local(_val) => { + formatter.write_str("Local")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Stmt::Item(_val) => { + formatter.write_str("Item")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Stmt::Expr(_val) => { + formatter.write_str("Expr")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::Stmt::Semi(_v0, _v1) => { + let mut formatter = formatter.debug_tuple("Semi"); + formatter.field(Lite(_v0)); + formatter.finish() + } + } + } +} +impl Debug for Lite<syn::TraitBound> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TraitBound"); + if let Some(val) = &_val.paren_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Paren); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("paren_token", Print::ref_cast(val)); + } + formatter.field("modifier", Lite(&_val.modifier)); + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetimes", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } +} +impl Debug for Lite<syn::TraitBoundModifier> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::TraitBoundModifier::None => formatter.write_str("None"), + syn::TraitBoundModifier::Maybe(_val) => { + formatter.write_str("Maybe")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::TraitItem> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::TraitItem::Const(_val) => { + let mut formatter = formatter.debug_struct("TraitItem::Const"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, syn::Expr)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } + syn::TraitItem::Method(_val) => { + let mut formatter = formatter.debug_struct("TraitItem::Method"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("sig", Lite(&_val.sig)); + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Block); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::TraitItem::Type(_val) => { + let mut formatter = formatter.debug_struct("TraitItem::Type"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, syn::Type)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } + syn::TraitItem::Macro(_val) => { + let mut formatter = formatter.debug_struct("TraitItem::Macro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } + syn::TraitItem::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::TraitItemConst> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TraitItemConst"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("ty", Lite(&_val.ty)); + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, syn::Expr)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TraitItemMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TraitItemMacro"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("mac", Lite(&_val.mac)); + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TraitItemMethod> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TraitItemMethod"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("sig", Lite(&_val.sig)); + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Block); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + if let Some(val) = &_val.semi_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Semi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("semi_token", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TraitItemType> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TraitItemType"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("generics", Lite(&_val.generics)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, syn::Type)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Type> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Type::Array(_val) => { + let mut formatter = formatter.debug_struct("Type::Array"); + formatter.field("elem", Lite(&_val.elem)); + formatter.field("len", Lite(&_val.len)); + formatter.finish() + } + syn::Type::BareFn(_val) => { + let mut formatter = formatter.debug_struct("Type::BareFn"); + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetimes", Print::ref_cast(val)); + } + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + if let Some(val) = &_val.abi { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Abi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("abi", Print::ref_cast(val)); + } + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + if let Some(val) = &_val.variadic { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Variadic); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("variadic", Print::ref_cast(val)); + } + formatter.field("output", Lite(&_val.output)); + formatter.finish() + } + syn::Type::Group(_val) => { + let mut formatter = formatter.debug_struct("Type::Group"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } + syn::Type::ImplTrait(_val) => { + let mut formatter = formatter.debug_struct("Type::ImplTrait"); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } + syn::Type::Infer(_val) => { + let mut formatter = formatter.debug_struct("Type::Infer"); + formatter.finish() + } + syn::Type::Macro(_val) => { + let mut formatter = formatter.debug_struct("Type::Macro"); + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } + syn::Type::Never(_val) => { + let mut formatter = formatter.debug_struct("Type::Never"); + formatter.finish() + } + syn::Type::Paren(_val) => { + let mut formatter = formatter.debug_struct("Type::Paren"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } + syn::Type::Path(_val) => { + let mut formatter = formatter.debug_struct("Type::Path"); + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } + syn::Type::Ptr(_val) => { + let mut formatter = formatter.debug_struct("Type::Ptr"); + if let Some(val) = &_val.const_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Const); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("const_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } + syn::Type::Reference(_val) => { + let mut formatter = formatter.debug_struct("Type::Reference"); + if let Some(val) = &_val.lifetime { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetime", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } + syn::Type::Slice(_val) => { + let mut formatter = formatter.debug_struct("Type::Slice"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } + syn::Type::TraitObject(_val) => { + let mut formatter = formatter.debug_struct("Type::TraitObject"); + if let Some(val) = &_val.dyn_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dyn); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dyn_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } + syn::Type::Tuple(_val) => { + let mut formatter = formatter.debug_struct("Type::Tuple"); + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } + syn::Type::Verbatim(_val) => { + formatter.write_str("Verbatim")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + _ => unreachable!(), + } + } +} +impl Debug for Lite<syn::TypeArray> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeArray"); + formatter.field("elem", Lite(&_val.elem)); + formatter.field("len", Lite(&_val.len)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeBareFn> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeBareFn"); + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetimes", Print::ref_cast(val)); + } + if let Some(val) = &_val.unsafety { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Unsafe); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("unsafety", Print::ref_cast(val)); + } + if let Some(val) = &_val.abi { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Abi); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("abi", Print::ref_cast(val)); + } + if !_val.inputs.is_empty() { + formatter.field("inputs", Lite(&_val.inputs)); + } + if let Some(val) = &_val.variadic { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Variadic); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("variadic", Print::ref_cast(val)); + } + formatter.field("output", Lite(&_val.output)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeGroup> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeGroup"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeImplTrait> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeImplTrait"); + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TypeInfer> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeInfer"); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeMacro> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeMacro"); + formatter.field("mac", Lite(&_val.mac)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeNever> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeNever"); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeParam> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeParam"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + if let Some(val) = &_val.colon_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Colon); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("colon_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + if let Some(val) = &_val.eq_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Eq); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("eq_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.default { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Type); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("default", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TypeParamBound> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::TypeParamBound::Trait(_val) => { + formatter.write_str("Trait")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::TypeParamBound::Lifetime(_val) => { + formatter.write_str("Lifetime")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::TypeParen> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeParen"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypePath> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypePath"); + if let Some(val) = &_val.qself { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::QSelf); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("qself", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypePtr> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypePtr"); + if let Some(val) = &_val.const_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Const); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("const_token", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeReference> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeReference"); + if let Some(val) = &_val.lifetime { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::Lifetime); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("lifetime", Print::ref_cast(val)); + } + if let Some(val) = &_val.mutability { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Mut); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("mutability", Print::ref_cast(val)); + } + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeSlice> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeSlice"); + formatter.field("elem", Lite(&_val.elem)); + formatter.finish() + } +} +impl Debug for Lite<syn::TypeTraitObject> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeTraitObject"); + if let Some(val) = &_val.dyn_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::Dyn); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("dyn_token", Print::ref_cast(val)); + } + if !_val.bounds.is_empty() { + formatter.field("bounds", Lite(&_val.bounds)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::TypeTuple> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("TypeTuple"); + if !_val.elems.is_empty() { + formatter.field("elems", Lite(&_val.elems)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::UnOp> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::UnOp::Deref(_val) => { + formatter.write_str("Deref")?; + Ok(()) + } + syn::UnOp::Not(_val) => { + formatter.write_str("Not")?; + Ok(()) + } + syn::UnOp::Neg(_val) => { + formatter.write_str("Neg")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::UseGlob> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("UseGlob"); + formatter.finish() + } +} +impl Debug for Lite<syn::UseGroup> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("UseGroup"); + if !_val.items.is_empty() { + formatter.field("items", Lite(&_val.items)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::UseName> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("UseName"); + formatter.field("ident", Lite(&_val.ident)); + formatter.finish() + } +} +impl Debug for Lite<syn::UsePath> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("UsePath"); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("tree", Lite(&_val.tree)); + formatter.finish() + } +} +impl Debug for Lite<syn::UseRename> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("UseRename"); + formatter.field("ident", Lite(&_val.ident)); + formatter.field("rename", Lite(&_val.rename)); + formatter.finish() + } +} +impl Debug for Lite<syn::UseTree> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::UseTree::Path(_val) => { + formatter.write_str("Path")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::UseTree::Name(_val) => { + formatter.write_str("Name")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::UseTree::Rename(_val) => { + formatter.write_str("Rename")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::UseTree::Glob(_val) => { + formatter.write_str("Glob")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::UseTree::Group(_val) => { + formatter.write_str("Group")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} +impl Debug for Lite<syn::Variadic> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Variadic"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::Variant> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("Variant"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.field("ident", Lite(&_val.ident)); + formatter.field("fields", Lite(&_val.fields)); + if let Some(val) = &_val.discriminant { + #[derive(RefCast)] + #[repr(transparent)] + struct Print((syn::token::Eq, syn::Expr)); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + let _val = &self.0; + formatter.write_str("(")?; + Debug::fmt(Lite(&_val.1), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + formatter.field("discriminant", Print::ref_cast(val)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::VisCrate> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("VisCrate"); + formatter.finish() + } +} +impl Debug for Lite<syn::VisPublic> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("VisPublic"); + formatter.finish() + } +} +impl Debug for Lite<syn::VisRestricted> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("VisRestricted"); + if let Some(val) = &_val.in_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::In); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("in_token", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } +} +impl Debug for Lite<syn::Visibility> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::Visibility::Public(_val) => { + let mut formatter = formatter.debug_struct("Visibility::Public"); + formatter.finish() + } + syn::Visibility::Crate(_val) => { + let mut formatter = formatter.debug_struct("Visibility::Crate"); + formatter.finish() + } + syn::Visibility::Restricted(_val) => { + let mut formatter = formatter.debug_struct("Visibility::Restricted"); + if let Some(val) = &_val.in_token { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::token::In); + impl Debug for Print { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Some")?; + Ok(()) + } + } + formatter.field("in_token", Print::ref_cast(val)); + } + formatter.field("path", Lite(&_val.path)); + formatter.finish() + } + syn::Visibility::Inherited => formatter.write_str("Inherited"), + } + } +} +impl Debug for Lite<syn::WhereClause> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("WhereClause"); + if !_val.predicates.is_empty() { + formatter.field("predicates", Lite(&_val.predicates)); + } + formatter.finish() + } +} +impl Debug for Lite<syn::WherePredicate> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + match _val { + syn::WherePredicate::Type(_val) => { + formatter.write_str("Type")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::WherePredicate::Lifetime(_val) => { + formatter.write_str("Lifetime")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + syn::WherePredicate::Eq(_val) => { + formatter.write_str("Eq")?; + formatter.write_str("(")?; + Debug::fmt(Lite(_val), formatter)?; + formatter.write_str(")")?; + Ok(()) + } + } + } +} diff --git a/syn/tests/debug/mod.rs b/syn/tests/debug/mod.rs new file mode 100644 index 0000000..9c80e2c --- /dev/null +++ b/syn/tests/debug/mod.rs @@ -0,0 +1,110 @@ +mod gen; + +use proc_macro2::{Ident, Literal, TokenStream}; +use ref_cast::RefCast; +use std::fmt::{self, Debug}; +use std::ops::Deref; +use syn::punctuated::Punctuated; + +#[derive(RefCast)] +#[repr(transparent)] +pub struct Lite<T: ?Sized> { + value: T, +} + +#[allow(non_snake_case)] +pub fn Lite<T: ?Sized>(value: &T) -> &Lite<T> { + Lite::ref_cast(value) +} + +impl<T: ?Sized> Deref for Lite<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl Debug for Lite<bool> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", self.value) + } +} + +impl Debug for Lite<u32> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", self.value) + } +} + +impl Debug for Lite<usize> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", self.value) + } +} + +impl Debug for Lite<String> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{:?}", self.value) + } +} + +impl Debug for Lite<Ident> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{:?}", self.value.to_string()) + } +} + +impl Debug for Lite<Literal> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{}", self.value) + } +} + +impl Debug for Lite<TokenStream> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "`{}`", self.value) + } +} + +impl<'a, T> Debug for Lite<&'a T> +where + Lite<T>: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(Lite(&*self.value), formatter) + } +} + +impl<T> Debug for Lite<Box<T>> +where + Lite<T>: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(Lite(&*self.value), formatter) + } +} + +impl<T> Debug for Lite<Vec<T>> +where + Lite<T>: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_list() + .entries(self.value.iter().map(Lite)) + .finish() + } +} + +impl<T, P> Debug for Lite<Punctuated<T, P>> +where + Lite<T>: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_list() + .entries(self.value.iter().map(Lite)) + .finish() + } +} diff --git a/syn/tests/features/error.rs b/syn/tests/features/error.rs new file mode 100644 index 0000000..10ac889 --- /dev/null +++ b/syn/tests/features/error.rs @@ -0,0 +1 @@ +"Hello! You want: cargo test --release --all-features" diff --git a/syn/tests/features/mod.rs b/syn/tests/features/mod.rs new file mode 100644 index 0000000..83fbe13 --- /dev/null +++ b/syn/tests/features/mod.rs @@ -0,0 +1,22 @@ +#[allow(unused_macros)] +macro_rules! hide_from_rustfmt { + ($mod:item) => { + $mod + }; +} + +#[cfg(not(all( + feature = "derive", + feature = "full", + feature = "parsing", + feature = "printing", + feature = "visit", + feature = "visit-mut", + feature = "fold", + feature = "clone-impls", + feature = "extra-traits", + feature = "proc-macro", +)))] +hide_from_rustfmt! { + mod error; +} diff --git a/syn/tests/macros/mod.rs b/syn/tests/macros/mod.rs new file mode 100644 index 0000000..3994615 --- /dev/null +++ b/syn/tests/macros/mod.rs @@ -0,0 +1,76 @@ +#[path = "../debug/mod.rs"] +pub mod debug; + +use syn; +use syn::parse::{Parse, Result}; + +#[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,)+) + }; +} + +#[macro_export] +macro_rules! snapshot { + ($($args:tt)*) => { + snapshot_impl!(() $($args)*) + }; +} + +#[macro_export] +macro_rules! snapshot_impl { + (($expr:ident) as $t:ty, @$snapshot:literal) => { + let $expr = crate::macros::Tokens::parse::<$t>($expr).unwrap(); + let debug = crate::macros::debug::Lite(&$expr); + insta::assert_debug_snapshot!(debug, @$snapshot); + }; + (($($expr:tt)*) as $t:ty, @$snapshot:literal) => {{ + let syntax_tree = crate::macros::Tokens::parse::<$t>($($expr)*).unwrap(); + let debug = crate::macros::debug::Lite(&syntax_tree); + insta::assert_debug_snapshot!(debug, @$snapshot); + syntax_tree + }}; + (($($expr:tt)*) , @$snapshot:literal) => {{ + let syntax_tree = $($expr)*; + let debug = crate::macros::debug::Lite(&syntax_tree); + insta::assert_debug_snapshot!(debug, @$snapshot); + syntax_tree + }}; + (($($expr:tt)*) $next:tt $($rest:tt)*) => { + snapshot_impl!(($($expr)* $next) $($rest)*) + }; +} + +pub trait Tokens { + fn parse<T: Parse>(self) -> Result<T>; +} + +impl<'a> Tokens for &'a str { + fn parse<T: Parse>(self) -> Result<T> { + syn::parse_str(self) + } +} + +impl Tokens for proc_macro2::TokenStream { + fn parse<T: Parse>(self) -> Result<T> { + syn::parse2(self) + } +} diff --git a/syn/tests/repo/mod.rs b/syn/tests/repo/mod.rs new file mode 100644 index 0000000..681615c --- /dev/null +++ b/syn/tests/repo/mod.rs @@ -0,0 +1,109 @@ +mod progress; + +use self::progress::Progress; +use crate::common; +use anyhow::Result; +use flate2::read::GzDecoder; +use std::fs; +use std::path::Path; +use tar::Archive; +use walkdir::DirEntry; + +const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d"; + +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/ui/obsolete-in-place/bad.rs" | + // Deprecated anonymous parameter syntax in traits + "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" | + "tests/rust/src/test/ui/issues/issue-13105.rs" | + "tests/rust/src/test/ui/issues/issue-13775.rs" | + "tests/rust/src/test/ui/issues/issue-34074.rs" | + // Deprecated await macro syntax + "tests/rust/src/test/ui/async-await/await-macro.rs" | + // 2015-style dyn that libsyntax rejects + "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" | + // not actually test cases + "tests/rust/src/test/ui/include-single-expr-helper.rs" | + "tests/rust/src/test/ui/include-single-expr-helper-1.rs" | + "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" | + "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" | + "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false, + _ => true, + } +} + +pub fn clone_rust() { + let needs_clone = match fs::read_to_string("tests/rust/COMMIT") { + Err(_) => true, + Ok(contents) => contents.trim() != REVISION, + }; + if needs_clone { + download_and_unpack().unwrap(); + } +} + +fn download_and_unpack() -> Result<()> { + let url = format!( + "https://github.com/rust-lang/rust/archive/{}.tar.gz", + REVISION + ); + let response = reqwest::blocking::get(&url)?.error_for_status()?; + let progress = Progress::new(response); + let decoder = GzDecoder::new(progress); + let mut archive = Archive::new(decoder); + let prefix = format!("rust-{}", REVISION); + + let tests_rust = Path::new("tests/rust"); + if tests_rust.exists() { + fs::remove_dir_all(tests_rust)?; + } + + for entry in archive.entries()? { + let mut entry = entry?; + let path = entry.path()?; + if path == Path::new("pax_global_header") { + continue; + } + let relative = path.strip_prefix(&prefix)?; + let out = tests_rust.join(relative); + entry.unpack(&out)?; + if common::travis_ci() { + // Something about this makes the travis build not deadlock... + errorf!("."); + } + } + + fs::write("tests/rust/COMMIT", REVISION)?; + Ok(()) +} diff --git a/syn/tests/repo/progress.rs b/syn/tests/repo/progress.rs new file mode 100644 index 0000000..28c8a44 --- /dev/null +++ b/syn/tests/repo/progress.rs @@ -0,0 +1,37 @@ +use std::io::{Read, Result}; +use std::time::{Duration, Instant}; + +pub struct Progress<R> { + bytes: usize, + tick: Instant, + stream: R, +} + +impl<R> Progress<R> { + pub fn new(stream: R) -> Self { + Progress { + bytes: 0, + tick: Instant::now() + Duration::from_millis(2000), + stream, + } + } +} + +impl<R: Read> Read for Progress<R> { + fn read(&mut self, buf: &mut [u8]) -> Result<usize> { + let num = self.stream.read(buf)?; + self.bytes += num; + let now = Instant::now(); + if now > self.tick { + self.tick = now + Duration::from_millis(500); + errorf!("downloading... {} bytes\n", self.bytes); + } + Ok(num) + } +} + +impl<R> Drop for Progress<R> { + fn drop(&mut self) { + errorf!("done ({} bytes)\n", self.bytes); + } +} diff --git a/syn/tests/test_asyncness.rs b/syn/tests/test_asyncness.rs new file mode 100644 index 0000000..e09e816 --- /dev/null +++ b/syn/tests/test_asyncness.rs @@ -0,0 +1,39 @@ +mod features; + +#[macro_use] +mod macros; + +use syn::{Expr, Item}; + +#[test] +fn test_async_fn() { + let input = "async fn process() {}"; + + snapshot!(input as Item, @r###" + Item::Fn { + vis: Inherited, + sig: Signature { + asyncness: Some, + ident: "process", + generics: Generics, + output: Default, + }, + block: Block, + } + "###); +} + +#[test] +fn test_async_closure() { + let input = "async || {}"; + + snapshot!(input as Expr, @r###" + Expr::Closure { + asyncness: Some, + output: Default, + body: Expr::Block { + block: Block, + }, + } + "###); +} diff --git a/syn/tests/test_attribute.rs b/syn/tests/test_attribute.rs new file mode 100644 index 0000000..d77c0c0 --- /dev/null +++ b/syn/tests/test_attribute.rs @@ -0,0 +1,296 @@ +mod features; + +#[macro_use] +mod macros; + +use syn::parse::Parser; +use syn::{Attribute, Meta}; + +#[test] +fn test_meta_item_word() { + let meta = test("#[foo]"); + + snapshot!(meta, @r###" + Path(Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }) + "###); +} + +#[test] +fn test_meta_item_name_value() { + let meta = test("#[foo = 5]"); + + snapshot!(meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); +} + +#[test] +fn test_meta_item_bool_value() { + let meta = test("#[foo = true]"); + + snapshot!(meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + lit: Lit::Bool { + value: true, + }, + } + "###); + + let meta = test("#[foo = false]"); + + snapshot!(meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + lit: Lit::Bool { + value: false, + }, + } + "###); +} + +#[test] +fn test_meta_item_list_lit() { + let meta = test("#[foo(5)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Lit(5), + ], + } + "###); +} + +#[test] +fn test_meta_item_list_word() { + let meta = test("#[foo(bar)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Path(Path { + segments: [ + PathSegment { + ident: "bar", + arguments: None, + }, + ], + })), + ], + } + "###); +} + +#[test] +fn test_meta_item_list_name_value() { + let meta = test("#[foo(bar = 5)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "bar", + arguments: None, + }, + ], + }, + lit: 5, + }), + ], + } + "###); +} + +#[test] +fn test_meta_item_list_bool_value() { + let meta = test("#[foo(bar = true)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "bar", + arguments: None, + }, + ], + }, + lit: Lit::Bool { + value: true, + }, + }), + ], + } + "###); +} + +#[test] +fn test_meta_item_multiple() { + let meta = test("#[foo(word, name = 5, list(name2 = 6), word2)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word", + arguments: None, + }, + ], + })), + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name", + arguments: None, + }, + ], + }, + lit: 5, + }), + Meta(Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "list", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name2", + arguments: None, + }, + ], + }, + lit: 6, + }), + ], + }), + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word2", + arguments: None, + }, + ], + })), + ], + } + "###); +} + +#[test] +fn test_bool_lit() { + let meta = test("#[foo(true)]"); + + snapshot!(meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Lit(Lit::Bool { + value: true, + }), + ], + } + "###); +} + +fn test(input: &str) -> Meta { + let attrs = Attribute::parse_outer.parse_str(input).unwrap(); + + assert_eq!(attrs.len(), 1); + let attr = attrs.into_iter().next().unwrap(); + + attr.parse_meta().unwrap() +} diff --git a/syn/tests/test_derive_input.rs b/syn/tests/test_derive_input.rs new file mode 100644 index 0000000..e3685ae --- /dev/null +++ b/syn/tests/test_derive_input.rs @@ -0,0 +1,894 @@ +mod features; + +#[macro_use] +mod macros; + +use quote::quote; +use syn::{Data, DeriveInput}; + +#[test] +fn test_unit() { + let input = quote! { + struct Unit; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "Unit", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_struct() { + let input = quote! { + #[derive(Debug, Clone)] + pub struct Item { + pub ident: Ident, + pub attrs: Vec<Attribute> + } + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + attrs: [ + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "derive", + arguments: None, + }, + ], + }, + tokens: `( Debug , Clone )`, + }, + ], + vis: Visibility::Public, + ident: "Item", + generics: Generics, + data: Data::Struct { + fields: Fields::Named { + named: [ + Field { + vis: Visibility::Public, + ident: Some("ident"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Ident", + arguments: None, + }, + ], + }, + }, + }, + Field { + vis: Visibility::Public, + ident: Some("attrs"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Attribute", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + ], + }, + }, + }, + ], + }, + }, + } + "###); + + snapshot!(input.attrs[0].parse_meta().unwrap(), @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "derive", + arguments: None, + }, + ], + }, + nested: [ + Meta(Path(Path { + segments: [ + PathSegment { + ident: "Debug", + arguments: None, + }, + ], + })), + Meta(Path(Path { + segments: [ + PathSegment { + ident: "Clone", + arguments: None, + }, + ], + })), + ], + } + "###); +} + +#[test] +fn test_union() { + let input = quote! { + union MaybeUninit<T> { + uninit: (), + value: T + } + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "MaybeUninit", + generics: Generics { + lt_token: Some, + params: [ + Type(TypeParam { + ident: "T", + }), + ], + gt_token: Some, + }, + data: Data::Union { + fields: FieldsNamed { + named: [ + Field { + vis: Inherited, + ident: Some("uninit"), + colon_token: Some, + ty: Type::Tuple, + }, + Field { + vis: Inherited, + ident: Some("value"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "T", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + }, + } + "###); +} + +#[test] +#[cfg(feature = "full")] +fn test_enum() { + let input = quote! { + /// 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 + } + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + attrs: [ + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "doc", + arguments: None, + }, + ], + }, + tokens: `= r" See the std::result module documentation for details."`, + }, + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "must_use", + arguments: None, + }, + ], + }, + tokens: ``, + }, + ], + vis: Visibility::Public, + ident: "Result", + generics: Generics { + lt_token: Some, + params: [ + Type(TypeParam { + ident: "T", + }), + Type(TypeParam { + ident: "E", + }), + ], + gt_token: Some, + }, + data: Data::Enum { + variants: [ + Variant { + ident: "Ok", + fields: Fields::Unnamed { + unnamed: [ + Field { + vis: Inherited, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "T", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + }, + Variant { + ident: "Err", + fields: Fields::Unnamed { + unnamed: [ + Field { + vis: Inherited, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "E", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + }, + Variant { + ident: "Surprise", + fields: Unit, + discriminant: Some(Expr::Lit { + lit: 0isize, + }), + }, + Variant { + ident: "ProcMacroHack", + fields: Unit, + discriminant: Some(Expr::Field { + base: Expr::Tuple { + elems: [ + Expr::Lit { + lit: 0, + }, + Expr::Lit { + lit: "data", + }, + ], + }, + member: Unnamed(Index { + index: 0, + }), + }), + }, + ], + }, + } + "###); + + let meta_items: Vec<_> = input + .attrs + .into_iter() + .map(|attr| attr.parse_meta().unwrap()) + .collect(); + + snapshot!(meta_items, @r###" + [ + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "doc", + arguments: None, + }, + ], + }, + lit: " See the std::result module documentation for details.", + }, + Path(Path { + segments: [ + PathSegment { + ident: "must_use", + arguments: None, + }, + ], + }), + ] + "###); +} + +#[test] +fn test_attr_with_path() { + let input = quote! { + #[::attr_args::identity + fn main() { assert_eq!(foo(), "Hello, world!"); }] + struct Dummy; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + attrs: [ + Attribute { + style: Outer, + path: Path { + leading_colon: Some, + segments: [ + PathSegment { + ident: "attr_args", + arguments: None, + }, + PathSegment { + ident: "identity", + arguments: None, + }, + ], + }, + tokens: `fn main ( ) { assert_eq ! ( foo ( ) , "Hello, world!" ) ; }`, + }, + ], + vis: Inherited, + ident: "Dummy", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); + + assert!(input.attrs[0].parse_meta().is_err()); +} + +#[test] +fn test_attr_with_non_mod_style_path() { + let input = quote! { + #[inert <T>] + struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + attrs: [ + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "inert", + arguments: None, + }, + ], + }, + tokens: `< T >`, + }, + ], + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); + + assert!(input.attrs[0].parse_meta().is_err()); +} + +#[test] +fn test_attr_with_mod_style_path_with_self() { + let input = quote! { + #[foo::self] + struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + attrs: [ + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + PathSegment { + ident: "self", + arguments: None, + }, + ], + }, + tokens: ``, + }, + ], + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); + + snapshot!(input.attrs[0].parse_meta().unwrap(), @r###" + Path(Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + PathSegment { + ident: "self", + arguments: None, + }, + ], + }) + "###); +} + +#[test] +fn test_pub_restricted() { + // Taken from tests/rust/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs + let input = quote! { + pub(in m) struct Z(pub(in m::n) u8); + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Visibility::Restricted { + in_token: Some, + path: Path { + segments: [ + PathSegment { + ident: "m", + arguments: None, + }, + ], + }, + }, + ident: "Z", + generics: Generics, + data: Data::Struct { + fields: Fields::Unnamed { + unnamed: [ + Field { + vis: Visibility::Restricted { + in_token: Some, + path: Path { + segments: [ + PathSegment { + ident: "m", + arguments: None, + }, + PathSegment { + ident: "n", + arguments: None, + }, + ], + }, + }, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_vis_crate() { + let input = quote! { + crate struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Visibility::Crate, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_pub_restricted_crate() { + let input = quote! { + pub(crate) struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Visibility::Restricted { + path: Path { + segments: [ + PathSegment { + ident: "crate", + arguments: None, + }, + ], + }, + }, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_pub_restricted_super() { + let input = quote! { + pub(super) struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Visibility::Restricted { + path: Path { + segments: [ + PathSegment { + ident: "super", + arguments: None, + }, + ], + }, + }, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_pub_restricted_in_super() { + let input = quote! { + pub(in super) struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Visibility::Restricted { + in_token: Some, + path: Path { + segments: [ + PathSegment { + ident: "super", + arguments: None, + }, + ], + }, + }, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); +} + +#[test] +fn test_fields_on_unit_struct() { + let input = quote! { + struct S; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); + + let data = match input.data { + Data::Struct(data) => data, + _ => panic!("expected a struct"), + }; + + assert_eq!(0, data.fields.iter().count()); +} + +#[test] +fn test_fields_on_named_struct() { + let input = quote! { + struct S { + foo: i32, + pub bar: String, + } + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Fields::Named { + named: [ + Field { + vis: Inherited, + ident: Some("foo"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "i32", + arguments: None, + }, + ], + }, + }, + }, + Field { + vis: Visibility::Public, + ident: Some("bar"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "String", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + }, + } + "###); + + let data = match input.data { + Data::Struct(data) => data, + _ => panic!("expected a struct"), + }; + + snapshot!(data.fields.into_iter().collect::<Vec<_>>(), @r###" + [ + Field { + vis: Inherited, + ident: Some("foo"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "i32", + arguments: None, + }, + ], + }, + }, + }, + Field { + vis: Visibility::Public, + ident: Some("bar"), + colon_token: Some, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "String", + arguments: None, + }, + ], + }, + }, + }, + ] + "###); +} + +#[test] +fn test_fields_on_tuple_struct() { + let input = quote! { + struct S(i32, pub String); + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Fields::Unnamed { + unnamed: [ + Field { + vis: Inherited, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "i32", + arguments: None, + }, + ], + }, + }, + }, + Field { + vis: Visibility::Public, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "String", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + semi_token: Some, + }, + } + "###); + + let data = match input.data { + Data::Struct(data) => data, + _ => panic!("expected a struct"), + }; + + snapshot!(data.fields.iter().collect::<Vec<_>>(), @r###" + [ + Field { + vis: Inherited, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "i32", + arguments: None, + }, + ], + }, + }, + }, + Field { + vis: Visibility::Public, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "String", + arguments: None, + }, + ], + }, + }, + }, + ] + "###); +} + +#[test] +fn test_ambiguous_crate() { + let input = quote! { + // The field type is `(crate::X)` not `crate (::X)`. + struct S(crate::X); + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "S", + generics: Generics, + data: Data::Struct { + fields: Fields::Unnamed { + unnamed: [ + Field { + vis: Inherited, + ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "crate", + arguments: None, + }, + PathSegment { + ident: "X", + arguments: None, + }, + ], + }, + }, + }, + ], + }, + semi_token: Some, + }, + } + "###); +} diff --git a/syn/tests/test_expr.rs b/syn/tests/test_expr.rs new file mode 100644 index 0000000..0edf6ce --- /dev/null +++ b/syn/tests/test_expr.rs @@ -0,0 +1,37 @@ +#[macro_use] +mod macros; + +use std::str::FromStr; + +use proc_macro2::TokenStream; +use syn::{Expr, ExprRange}; + +#[test] +fn test_expr_parse() { + let code = "..100u32"; + let tt = TokenStream::from_str(code).unwrap(); + let expr: Expr = syn::parse2(tt.clone()).unwrap(); + let expr_range: ExprRange = syn::parse2(tt).unwrap(); + assert_eq!(expr, Expr::Range(expr_range)); +} + +#[test] +fn test_await() { + // Must not parse as Expr::Field. + let expr = syn::parse_str::<Expr>("fut.await").unwrap(); + + snapshot!(expr, @r###" + Expr::Await { + base: Expr::Path { + path: Path { + segments: [ + PathSegment { + ident: "fut", + arguments: None, + }, + ], + }, + }, + } + "###); +} diff --git a/syn/tests/test_generics.rs b/syn/tests/test_generics.rs new file mode 100644 index 0000000..e863b77 --- /dev/null +++ b/syn/tests/test_generics.rs @@ -0,0 +1,285 @@ +mod features; + +#[macro_use] +mod macros; + +use quote::quote; +use syn::{DeriveInput, ItemFn, TypeParamBound, WhereClause, WherePredicate}; + +#[test] +fn test_split_for_impl() { + let input = quote! { + struct S<'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug; + }; + + snapshot!(input as DeriveInput, @r###" + DeriveInput { + vis: Inherited, + ident: "S", + generics: Generics { + lt_token: Some, + params: [ + Lifetime(LifetimeDef { + lifetime: Lifetime { + ident: "a", + }, + }), + Lifetime(LifetimeDef { + lifetime: Lifetime { + ident: "b", + }, + colon_token: Some, + bounds: [ + Lifetime { + ident: "a", + }, + ], + }), + Type(TypeParam { + attrs: [ + Attribute { + style: Outer, + path: Path { + segments: [ + PathSegment { + ident: "may_dangle", + arguments: None, + }, + ], + }, + tokens: ``, + }, + ], + ident: "T", + colon_token: Some, + bounds: [ + Lifetime(Lifetime { + ident: "a", + }), + ], + eq_token: Some, + default: Some(Type::Tuple), + }), + ], + gt_token: Some, + where_clause: Some(WhereClause { + predicates: [ + Type(PredicateType { + bounded_ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "T", + arguments: None, + }, + ], + }, + }, + bounds: [ + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "Debug", + arguments: None, + }, + ], + }, + }), + ], + }), + ], + }), + }, + data: Data::Struct { + fields: Unit, + semi_token: Some, + }, + } + "###); + + let generics = input.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let generated = quote! { + impl #impl_generics MyTrait for Test #ty_generics #where_clause {} + }; + let expected = quote! { + impl<'a, 'b: 'a, #[may_dangle] T: 'a> MyTrait + for Test<'a, 'b, T> + where + T: Debug + {} + }; + assert_eq!(generated.to_string(), expected.to_string()); + + let turbofish = ty_generics.as_turbofish(); + let generated = quote! { + Test #turbofish + }; + let expected = quote! { + Test::<'a, 'b, T> + }; + assert_eq!(generated.to_string(), expected.to_string()); +} + +#[test] +fn test_ty_param_bound() { + let tokens = quote!('a); + snapshot!(tokens as TypeParamBound, @r###" + Lifetime(Lifetime { + ident: "a", + }) + "###); + + let tokens = quote!('_); + snapshot!(tokens as TypeParamBound, @r###" + Lifetime(Lifetime { + ident: "_", + }) + "###); + + let tokens = quote!(Debug); + snapshot!(tokens as TypeParamBound, @r###" + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "Debug", + arguments: None, + }, + ], + }, + }) + "###); + + let tokens = quote!(?Sized); + snapshot!(tokens as TypeParamBound, @r###" + Trait(TraitBound { + modifier: Maybe, + path: Path { + segments: [ + PathSegment { + ident: "Sized", + arguments: None, + }, + ], + }, + }) + "###); +} + +#[test] +fn test_fn_precedence_in_where_clause() { + // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not + // `FnOnce() -> (i32 + Send)`. + let input = quote! { + fn f<G>() + where + G: FnOnce() -> i32 + Send, + { + } + }; + + snapshot!(input as ItemFn, @r###" + ItemFn { + vis: Inherited, + sig: Signature { + ident: "f", + generics: Generics { + lt_token: Some, + params: [ + Type(TypeParam { + ident: "G", + }), + ], + gt_token: Some, + where_clause: Some(WhereClause { + predicates: [ + Type(PredicateType { + bounded_ty: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "G", + arguments: None, + }, + ], + }, + }, + bounds: [ + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "FnOnce", + arguments: PathArguments::Parenthesized { + output: Type( + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "i32", + arguments: None, + }, + ], + }, + }, + ), + }, + }, + ], + }, + }), + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "Send", + arguments: None, + }, + ], + }, + }), + ], + }), + ], + }), + }, + output: Default, + }, + block: Block, + } + "###); + + let where_clause = input.sig.generics.where_clause.as_ref().unwrap(); + assert_eq!(where_clause.predicates.len(), 1); + + let predicate = match &where_clause.predicates[0] { + WherePredicate::Type(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"); +} + +#[test] +fn test_where_clause_at_end_of_input() { + let input = quote! { + where + }; + + snapshot!(input as WhereClause, @"WhereClause"); + + assert_eq!(input.predicates.len(), 0); +} diff --git a/syn/tests/test_grouping.rs b/syn/tests/test_grouping.rs new file mode 100644 index 0000000..4e43ab8 --- /dev/null +++ b/syn/tests/test_grouping.rs @@ -0,0 +1,55 @@ +mod features; + +#[macro_use] +mod macros; + +use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree}; +use syn::Expr; + +use std::iter::FromIterator; + +#[test] +fn test_grouping() { + let tokens: TokenStream = TokenStream::from_iter(vec![ + TokenTree::Literal(Literal::i32_suffixed(1)), + TokenTree::Punct(Punct::new('+', Spacing::Alone)), + TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_iter(vec![ + TokenTree::Literal(Literal::i32_suffixed(2)), + TokenTree::Punct(Punct::new('+', Spacing::Alone)), + TokenTree::Literal(Literal::i32_suffixed(3)), + ]), + )), + TokenTree::Punct(Punct::new('*', Spacing::Alone)), + TokenTree::Literal(Literal::i32_suffixed(4)), + ]); + + assert_eq!(tokens.to_string(), "1i32 + 2i32 + 3i32 * 4i32"); + + snapshot!(tokens as Expr, @r###" + Expr::Binary { + left: Expr::Lit { + lit: 1i32, + }, + op: Add, + right: Expr::Binary { + left: Expr::Group { + expr: Expr::Binary { + left: Expr::Lit { + lit: 2i32, + }, + op: Add, + right: Expr::Lit { + lit: 3i32, + }, + }, + }, + op: Mul, + right: Expr::Lit { + lit: 4i32, + }, + }, + } + "###); +} diff --git a/syn/tests/test_ident.rs b/syn/tests/test_ident.rs new file mode 100644 index 0000000..7578381 --- /dev/null +++ b/syn/tests/test_ident.rs @@ -0,0 +1,87 @@ +mod features; + +use proc_macro2::{Ident, Span, TokenStream}; +use std::str::FromStr; +use syn::Result; + +fn parse(s: &str) -> Result<Ident> { + 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/syn/tests/test_iterators.rs b/syn/tests/test_iterators.rs new file mode 100644 index 0000000..f107297 --- /dev/null +++ b/syn/tests/test_iterators.rs @@ -0,0 +1,51 @@ +use syn::punctuated::{Pair, Punctuated}; +use syn::Token; + +mod features; + +#[macro_use] +mod macros; + +macro_rules! check_exact_size_iterator { + ($iter:expr) => {{ + let iter = $iter; + let size_hint = iter.size_hint(); + let len = iter.len(); + let count = iter.count(); + assert_eq!(len, count); + assert_eq!(size_hint, (count, Some(count))); + }}; +} + +#[test] +fn pairs() { + let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); + + check_exact_size_iterator!(p.pairs()); + check_exact_size_iterator!(p.pairs_mut()); + check_exact_size_iterator!(p.into_pairs()); + + let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); + + assert_eq!(p.pairs().next_back().map(Pair::into_value), Some(&4)); + assert_eq!( + p.pairs_mut().next_back().map(Pair::into_value), + Some(&mut 4) + ); + assert_eq!(p.into_pairs().next_back().map(Pair::into_value), Some(4)); +} + +#[test] +fn iter() { + let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); + + check_exact_size_iterator!(p.iter()); + check_exact_size_iterator!(p.iter_mut()); + check_exact_size_iterator!(p.into_iter()); + + let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); + + assert_eq!(p.iter().next_back(), Some(&4)); + assert_eq!(p.iter_mut().next_back(), Some(&mut 4)); + assert_eq!(p.into_iter().next_back(), Some(4)); +} diff --git a/syn/tests/test_lit.rs b/syn/tests/test_lit.rs new file mode 100644 index 0000000..0b300c4 --- /dev/null +++ b/syn/tests/test_lit.rs @@ -0,0 +1,184 @@ +mod features; + +use proc_macro2::{TokenStream, TokenTree}; +use quote::ToTokens; +use std::str::FromStr; +use syn::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: &str) { + match lit(s) { + Lit::Int(lit) => { + assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), 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), + } + } + + test_int("5", 5, ""); + test_int("5u32", 5, "u32"); + test_int("5_0", 50, ""); + test_int("5_____0_____", 50, ""); + test_int("0x7f", 127, ""); + test_int("0x7F", 127, ""); + test_int("0b1001", 9, ""); + test_int("0o73", 59, ""); + test_int("0x7Fu8", 127, "u8"); + test_int("0b1001i8", 9, "i8"); + test_int("0o73u32", 59, "u32"); + test_int("0x__7___f_", 127, ""); + test_int("0x__7___F_", 127, ""); + test_int("0b_1_0__01", 9, ""); + test_int("0o_7__3", 59, ""); + 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: &str) { + match lit(s) { + Lit::Float(lit) => { + assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), 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), + } + } + + test_float("5.5", 5.5, ""); + test_float("5.5E12", 5.5e12, ""); + test_float("5.5e12", 5.5e12, ""); + test_float("1.0__3e-12", 1.03e-12, ""); + test_float("1.03e+12", 1.03e12, ""); +} diff --git a/syn/tests/test_meta.rs b/syn/tests/test_meta.rs new file mode 100644 index 0000000..618296e --- /dev/null +++ b/syn/tests/test_meta.rs @@ -0,0 +1,341 @@ +mod features; + +#[macro_use] +mod macros; + +use syn::{Meta, MetaList, MetaNameValue, NestedMeta}; + +#[test] +fn test_parse_meta_item_word() { + let input = "hello"; + + snapshot!(input as Meta, @r###" + Path(Path { + segments: [ + PathSegment { + ident: "hello", + arguments: None, + }, + ], + }) + "###); +} + +#[test] +fn test_parse_meta_name_value() { + let input = "foo = 5"; + let (inner, meta) = (input, input); + + snapshot!(inner as MetaNameValue, @r###" + MetaNameValue { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + snapshot!(meta as Meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + assert_eq!(meta, inner.into()); +} + +#[test] +fn test_parse_meta_name_value_with_keyword() { + let input = "static = 5"; + let (inner, meta) = (input, input); + + snapshot!(inner as MetaNameValue, @r###" + MetaNameValue { + path: Path { + segments: [ + PathSegment { + ident: "static", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + snapshot!(meta as Meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "static", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + assert_eq!(meta, inner.into()); +} + +#[test] +fn test_parse_meta_name_value_with_bool() { + let input = "true = 5"; + let (inner, meta) = (input, input); + + snapshot!(inner as MetaNameValue, @r###" + MetaNameValue { + path: Path { + segments: [ + PathSegment { + ident: "true", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + snapshot!(meta as Meta, @r###" + Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "true", + arguments: None, + }, + ], + }, + lit: 5, + } + "###); + + assert_eq!(meta, inner.into()); +} + +#[test] +fn test_parse_meta_item_list_lit() { + let input = "foo(5)"; + let (inner, meta) = (input, input); + + snapshot!(inner as MetaList, @r###" + MetaList { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Lit(5), + ], + } + "###); + + snapshot!(meta as Meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Lit(5), + ], + } + "###); + + assert_eq!(meta, inner.into()); +} + +#[test] +fn test_parse_meta_item_multiple() { + let input = "foo(word, name = 5, list(name2 = 6), word2)"; + let (inner, meta) = (input, input); + + snapshot!(inner as MetaList, @r###" + MetaList { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word", + arguments: None, + }, + ], + })), + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name", + arguments: None, + }, + ], + }, + lit: 5, + }), + Meta(Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "list", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name2", + arguments: None, + }, + ], + }, + lit: 6, + }), + ], + }), + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word2", + arguments: None, + }, + ], + })), + ], + } + "###); + + snapshot!(meta as Meta, @r###" + Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "foo", + arguments: None, + }, + ], + }, + nested: [ + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word", + arguments: None, + }, + ], + })), + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name", + arguments: None, + }, + ], + }, + lit: 5, + }), + Meta(Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "list", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name2", + arguments: None, + }, + ], + }, + lit: 6, + }), + ], + }), + Meta(Path(Path { + segments: [ + PathSegment { + ident: "word2", + arguments: None, + }, + ], + })), + ], + } + "###); + + assert_eq!(meta, inner.into()); +} + +#[test] +fn test_parse_nested_meta() { + let input = "5"; + snapshot!(input as NestedMeta, @"Lit(5)"); + + let input = "list(name2 = 6)"; + snapshot!(input as NestedMeta, @r###" + Meta(Meta::List { + path: Path { + segments: [ + PathSegment { + ident: "list", + arguments: None, + }, + ], + }, + nested: [ + Meta(Meta::NameValue { + path: Path { + segments: [ + PathSegment { + ident: "name2", + arguments: None, + }, + ], + }, + lit: 6, + }), + ], + }) + "###); +} diff --git a/syn/tests/test_parse_buffer.rs b/syn/tests/test_parse_buffer.rs new file mode 100644 index 0000000..d3f10c0 --- /dev/null +++ b/syn/tests/test_parse_buffer.rs @@ -0,0 +1,53 @@ +use syn::parenthesized; +use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result}; + +#[test] +#[should_panic(expected = "Fork was not derived from the advancing parse stream")] +fn smuggled_speculative_cursor_between_sources() { + struct BreakRules; + impl Parse for BreakRules { + fn parse(input1: ParseStream) -> Result<Self> { + let nested = |input2: ParseStream| { + input1.advance_to(&input2); + Ok(Self) + }; + nested.parse_str("") + } + } + + syn::parse_str::<BreakRules>("").unwrap(); +} + +#[test] +#[should_panic(expected = "Fork was not derived from the advancing parse stream")] +fn smuggled_speculative_cursor_between_brackets() { + struct BreakRules; + impl Parse for BreakRules { + fn parse(input: ParseStream) -> Result<Self> { + let a; + let b; + parenthesized!(a in input); + parenthesized!(b in input); + a.advance_to(&b); + Ok(Self) + } + } + + syn::parse_str::<BreakRules>("()()").unwrap(); +} + +#[test] +#[should_panic(expected = "Fork was not derived from the advancing parse stream")] +fn smuggled_speculative_cursor_into_brackets() { + struct BreakRules; + impl Parse for BreakRules { + fn parse(input: ParseStream) -> Result<Self> { + let a; + parenthesized!(a in input); + input.advance_to(&a); + Ok(Self) + } + } + + syn::parse_str::<BreakRules>("()").unwrap(); +} diff --git a/syn/tests/test_pat.rs b/syn/tests/test_pat.rs new file mode 100644 index 0000000..cce4b80 --- /dev/null +++ b/syn/tests/test_pat.rs @@ -0,0 +1,20 @@ +mod features; + +use quote::quote; +use syn::Pat; + +#[test] +fn test_pat_ident() { + match syn::parse2(quote!(self)).unwrap() { + Pat::Ident(_) => (), + value => panic!("expected PatIdent, got {:?}", value), + } +} + +#[test] +fn test_pat_path() { + match syn::parse2(quote!(self::CONST)).unwrap() { + Pat::Path(_) => (), + value => panic!("expected PatPath, got {:?}", value), + } +} diff --git a/syn/tests/test_precedence.rs b/syn/tests/test_precedence.rs new file mode 100644 index 0000000..3529c06 --- /dev/null +++ b/syn/tests/test_precedence.rs @@ -0,0 +1,394 @@ +#![cfg(not(syn_disable_nightly_tests))] +#![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. + +extern crate rustc_data_structures; +extern crate rustc_span; +extern crate syntax; + +mod features; + +use quote::quote; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use regex::Regex; +use rustc_span::edition::Edition; +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; + +mod repo; + +/// 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() { + repo::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(repo::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(Edition::Edition2018, || { + 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(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> { + use rustc_data_structures::thin_vec::ThinVec; + use rustc_span::DUMMY_SP; + use std::mem; + use syntax::ast::{Block, Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty}; + use syntax::mut_visit::MutVisitor; + use syntax::util::map_in_place::MapInPlace; + + struct BracketsVisitor { + failed: bool, + }; + + fn flat_map_field<T: MutVisitor>(mut f: Field, vis: &mut T) -> Vec<Field> { + if f.is_shorthand { + noop_visit_expr(&mut f.expr, vis); + } else { + vis.visit_expr(&mut f.expr); + } + vec![f] + } + + fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> { + let kind = match stmt.kind { + // Don't wrap toplevel expressions in statements. + StmtKind::Expr(mut e) => { + noop_visit_expr(&mut e, vis); + StmtKind::Expr(e) + } + StmtKind::Semi(mut e) => { + noop_visit_expr(&mut e, vis); + StmtKind::Semi(e) + } + s => s, + }; + + vec![Stmt { kind, ..stmt }] + } + + fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) { + use syntax::mut_visit::{noop_visit_expr, visit_opt, visit_thin_attrs}; + match &mut e.kind { + ExprKind::Struct(path, fields, expr) => { + vis.visit_path(path); + fields.flat_map_in_place(|field| flat_map_field(field, vis)); + visit_opt(expr, |expr| vis.visit_expr(expr)); + vis.visit_id(&mut e.id); + vis.visit_span(&mut e.span); + visit_thin_attrs(&mut e.attrs, vis); + } + _ => noop_visit_expr(e, vis), + } + } + + impl MutVisitor for BracketsVisitor { + fn visit_expr(&mut self, e: &mut P<Expr>) { + noop_visit_expr(e, self); + match e.kind { + ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {} + _ => { + let inner = mem::replace( + e, + P(Expr { + id: ast::DUMMY_NODE_ID, + kind: ExprKind::Err, + span: DUMMY_SP, + attrs: ThinVec::new(), + }), + ); + e.kind = ExprKind::Paren(inner); + } + } + } + + fn visit_block(&mut self, block: &mut P<Block>) { + self.visit_id(&mut block.id); + block + .stmts + .flat_map_in_place(|stmt| flat_map_stmt(stmt, self)); + self.visit_span(&mut block.span); + } + + // 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 visit_pat(&mut self, pat: &mut P<Pat>) { + let _ = pat; + } + + fn visit_ty(&mut self, ty: &mut P<Ty>) { + let _ = ty; + } + + fn visit_mac(&mut self, mac: &mut 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 visit_mac to just return the macro + // unchanged. + let _ = mac; + } + } + + let mut folder = BracketsVisitor { failed: false }; + folder.visit_expr(&mut libsyntax_expr); + if folder.failed { + None + } else { + Some(libsyntax_expr) + } +} + +/// 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::Let(..) => { + fold_expr(self, expr) + } + _ => Expr::Paren(ExprParen { + attrs: Vec::new(), + expr: Box::new(fold_expr(self, expr)), + 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 { + match expr { + Expr::Verbatim(tokens) if tokens.is_empty() => {} + _ => 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/syn/tests/test_receiver.rs b/syn/tests/test_receiver.rs new file mode 100644 index 0000000..168db8f --- /dev/null +++ b/syn/tests/test_receiver.rs @@ -0,0 +1,109 @@ +mod features; + +use syn::{FnArg, Receiver, TraitItemMethod}; + +#[test] +fn test_by_value() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_value(self: Self);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_by_mut_value() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_mut(mut self: Self);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_by_ref() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_ref(self: &Self);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_by_box() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_box(self: Box<Self>);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_by_pin() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn by_pin(self: Pin<Self>);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_explicit_type() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn explicit_type(self: Pin<MyType>);); + match sig.receiver() { + Some(FnArg::Typed(_)) => (), + value => panic!("expected FnArg::Typed, got {:?}", value), + } +} + +#[test] +fn test_value_shorthand() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn value_shorthand(self);); + match sig.receiver() { + Some(FnArg::Receiver(Receiver { + reference: None, + mutability: None, + .. + })) => (), + value => panic!("expected FnArg::Receiver without ref/mut, got {:?}", value), + } +} + +#[test] +fn test_mut_value_shorthand() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn mut_value_shorthand(mut self);); + match sig.receiver() { + Some(FnArg::Receiver(Receiver { + reference: None, + mutability: Some(_), + .. + })) => (), + value => panic!("expected FnArg::Receiver with mut, got {:?}", value), + } +} + +#[test] +fn test_ref_shorthand() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn ref_shorthand(&self);); + match sig.receiver() { + Some(FnArg::Receiver(Receiver { + reference: Some(_), + mutability: None, + .. + })) => (), + value => panic!("expected FnArg::Receiver with ref, got {:?}", value), + } +} + +#[test] +fn test_ref_mut_shorthand() { + let TraitItemMethod { sig, .. } = syn::parse_quote!(fn ref_mut_shorthand(&mut self);); + match sig.receiver() { + Some(FnArg::Receiver(Receiver { + reference: Some(_), + mutability: Some(_), + .. + })) => (), + value => panic!("expected FnArg::Receiver with ref+mut, got {:?}", value), + } +} diff --git a/syn/tests/test_round_trip.rs b/syn/tests/test_round_trip.rs new file mode 100644 index 0000000..435bd6a --- /dev/null +++ b/syn/tests/test_round_trip.rs @@ -0,0 +1,151 @@ +#![cfg(not(syn_disable_nightly_tests))] +#![recursion_limit = "1024"] +#![feature(rustc_private)] + +extern crate rustc_expand; +extern crate rustc_parse as parse; +extern crate rustc_span; +extern crate syntax; + +mod features; + +use quote::quote; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use rustc_span::edition::Edition; +use rustc_span::FileName; +use syntax::ast; +use syntax::errors::PResult; +use syntax::sess::ParseSess; +use syntax::source_map::FilePathMapping; +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; + +mod repo; + +use common::eq::SpanlessEq; + +#[test] +fn test_round_trip() { + repo::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(repo::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(Edition::Edition2018, || { + 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/syn/tests/test_should_parse.rs b/syn/tests/test_should_parse.rs new file mode 100644 index 0000000..d4f7ac3 --- /dev/null +++ b/syn/tests/test_should_parse.rs @@ -0,0 +1,47 @@ +mod features; + +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> {} + } +}); + +#[rustfmt::skip] +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/syn/tests/test_size.rs b/syn/tests/test_size.rs new file mode 100644 index 0000000..386d4df --- /dev/null +++ b/syn/tests/test_size.rs @@ -0,0 +1,31 @@ +#![cfg(target_pointer_width = "64")] + +mod features; + +use std::mem; +use syn::*; + +#[test] +fn test_expr_size() { + assert_eq!(mem::size_of::<Expr>(), 280); +} + +#[test] +fn test_item_size() { + assert_eq!(mem::size_of::<Item>(), 344); +} + +#[test] +fn test_type_size() { + assert_eq!(mem::size_of::<Type>(), 304); +} + +#[test] +fn test_pat_size() { + assert_eq!(mem::size_of::<Pat>(), 144); +} + +#[test] +fn test_lit_size() { + assert_eq!(mem::size_of::<Lit>(), 40); +} diff --git a/syn/tests/test_token_trees.rs b/syn/tests/test_token_trees.rs new file mode 100644 index 0000000..5d7610b --- /dev/null +++ b/syn/tests/test_token_trees.rs @@ -0,0 +1,28 @@ +mod features; + +#[macro_use] +mod macros; + +use proc_macro2::TokenStream; +use quote::quote; +use syn::Lit; + +#[test] +fn test_struct() { + let input = " + #[derive(Debug, Clone)] + pub struct Item { + pub ident: Ident, + pub attrs: Vec<Attribute>, + } + "; + + snapshot!(input as TokenStream, @"`# [ derive ( Debug , Clone ) ] pub struct Item { pub ident : Ident , pub attrs : Vec < Attribute >, }`"); +} + +#[test] +fn test_literal_mangling() { + let code = "0_4"; + let parsed: Lit = syn::parse_str(code).unwrap(); + assert_eq!(code, quote!(#parsed).to_string()); +} diff --git a/syn/tests/test_visibility.rs b/syn/tests/test_visibility.rs new file mode 100644 index 0000000..21c49c9 --- /dev/null +++ b/syn/tests/test_visibility.rs @@ -0,0 +1,99 @@ +mod features; + +use proc_macro2::TokenStream; +use syn::parse::{Parse, ParseStream}; +use syn::{Result, Visibility}; + +#[derive(Debug)] +struct VisRest { + vis: Visibility, + rest: TokenStream, +} + +impl Parse for VisRest { + fn parse(input: ParseStream) -> Result<Self> { + Ok(VisRest { + vis: input.parse()?, + rest: input.parse()?, + }) + } +} + +macro_rules! assert_vis_parse { + ($input:expr, Ok($p:pat)) => { + assert_vis_parse!($input, Ok($p) + ""); + }; + + ($input:expr, Ok($p:pat) + $rest:expr) => { + let expected = $rest.parse::<TokenStream>().unwrap(); + let parse: VisRest = syn::parse_str($input).unwrap(); + + match parse.vis { + $p => {} + _ => panic!("Expected {}, got {:?}", stringify!($p), parse.vis), + } + + // NOTE: Round-trips through `to_string` to avoid potential whitespace + // diffs. + assert_eq!(parse.rest.to_string(), expected.to_string()); + }; + + ($input:expr, Err) => { + syn::parse2::<VisRest>($input.parse().unwrap()).unwrap_err(); + }; +} + +#[test] +fn test_pub() { + assert_vis_parse!("pub", Ok(Visibility::Public(_))); +} + +#[test] +fn test_crate() { + assert_vis_parse!("crate", Ok(Visibility::Crate(_))); +} + +#[test] +fn test_inherited() { + assert_vis_parse!("", Ok(Visibility::Inherited)); +} + +#[test] +fn test_in() { + assert_vis_parse!("pub(in foo::bar)", Ok(Visibility::Restricted(_))); +} + +#[test] +fn test_pub_crate() { + assert_vis_parse!("pub(crate)", Ok(Visibility::Restricted(_))); +} + +#[test] +fn test_pub_self() { + assert_vis_parse!("pub(self)", Ok(Visibility::Restricted(_))); +} + +#[test] +fn test_pub_super() { + assert_vis_parse!("pub(super)", Ok(Visibility::Restricted(_))); +} + +#[test] +fn test_missing_in() { + assert_vis_parse!("pub(foo::bar)", Ok(Visibility::Public(_)) + "(foo::bar)"); +} + +#[test] +fn test_missing_in_path() { + assert_vis_parse!("pub(in)", Err); +} + +#[test] +fn test_crate_path() { + assert_vis_parse!("pub(crate::A, crate::B)", Ok(Visibility::Public(_)) + "(crate::A, crate::B)"); +} + +#[test] +fn test_junk_after_in() { + assert_vis_parse!("pub(in some::path @@garbage)", Err); +} diff --git a/syn/tests/zzz_stable.rs b/syn/tests/zzz_stable.rs new file mode 100644 index 0000000..6c768f2 --- /dev/null +++ b/syn/tests/zzz_stable.rs @@ -0,0 +1,33 @@ +#![cfg(syn_disable_nightly_tests)] + +use std::io::{self, Write}; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +const MSG: &str = "\ +‖ +‖ WARNING: +‖ This is not a nightly compiler so not all tests were able to +‖ run. Syn includes tests that compare Syn's parser against the +‖ compiler's parser, which requires access to unstable libsyntax +‖ data structures and a nightly compiler. +‖ +"; + +#[test] +fn notice() -> io::Result<()> { + let header = "WARNING"; + let index_of_header = MSG.find(header).unwrap(); + let before = &MSG[..index_of_header]; + let after = &MSG[index_of_header + header.len()..]; + + let mut stderr = StandardStream::stderr(ColorChoice::Auto); + stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(&mut stderr, "{}", before)?; + stderr.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; + write!(&mut stderr, "{}", header)?; + stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; + write!(&mut stderr, "{}", after)?; + stderr.reset()?; + + Ok(()) +} |