mirror of
https://gitee.com/openharmony/third_party_rust_syn
synced 2024-11-26 17:31:44 +00:00
commit
e009bb939f
@ -1 +0,0 @@
|
||||
msrv = "1.31.0"
|
68
.github/workflows/ci.yml
vendored
68
.github/workflows/ci.yml
vendored
@ -3,6 +3,7 @@ name: CI
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule: [cron: "40 1 * * *"]
|
||||
|
||||
permissions:
|
||||
@ -12,24 +13,31 @@ env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
|
||||
jobs:
|
||||
pre_ci:
|
||||
uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
|
||||
|
||||
test:
|
||||
name: Tests
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: rustc-dev
|
||||
components: llvm-tools, rustc-dev
|
||||
- run: cargo test --all-features --release --tests
|
||||
|
||||
build:
|
||||
name: ${{matrix.name || format('Rust {0}', matrix.rust)}}
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ${{matrix.os || 'ubuntu'}}-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [stable, beta, 1.31.0]
|
||||
rust: [stable, beta, 1.56.0]
|
||||
include:
|
||||
- rust: nightly
|
||||
components: rustc-dev
|
||||
@ -46,7 +54,7 @@ jobs:
|
||||
target: ${{matrix.target && format('--target={0}', matrix.target)}}
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
@ -72,65 +80,80 @@ jobs:
|
||||
|
||||
examples:
|
||||
name: Examples
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo check --manifest-path examples/dump-syntax/Cargo.toml
|
||||
- run: cargo check --manifest-path examples/heapsize/example/Cargo.toml
|
||||
- run: cargo check --manifest-path examples/lazy-static/example/Cargo.toml
|
||||
- run: cargo check --manifest-path examples/trace-var/example/Cargo.toml
|
||||
|
||||
docs:
|
||||
name: Docs
|
||||
doc:
|
||||
name: Documentation
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTDOCFLAGS: --cfg=doc_cfg -Dbroken_intra_doc_links
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
RUSTDOCFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-docs-rs
|
||||
- run: cargo docs-rs
|
||||
- run: cargo docs-rs --manifest-path json/Cargo.toml
|
||||
- run: cargo test --all-features --doc
|
||||
- run: cargo doc --all-features
|
||||
|
||||
codegen:
|
||||
name: Codegen
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cd codegen && cargo run
|
||||
- run: cargo run --manifest-path codegen/Cargo.toml
|
||||
- run: git diff --exit-code
|
||||
|
||||
msrv:
|
||||
minimal:
|
||||
name: Minimal versions
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo update -Z minimal-versions
|
||||
- run: cargo check --all-features
|
||||
- run: cargo generate-lockfile -Z minimal-versions
|
||||
- run: cargo check --all-features --locked
|
||||
|
||||
fuzz:
|
||||
name: Fuzz
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-fuzz
|
||||
- run: cargo fuzz build -O
|
||||
- run: cargo fuzz check
|
||||
|
||||
miri:
|
||||
name: Miri
|
||||
needs: pre_ci
|
||||
if: needs.pre_ci.outputs.continue
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@miri
|
||||
- run: cargo miri setup
|
||||
- run: cargo miri test --all-features
|
||||
env:
|
||||
MIRIFLAGS: -Zmiri-strict-provenance
|
||||
@ -141,11 +164,12 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy,rustc-dev
|
||||
- run: cargo clippy --all-features --tests --benches -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cargo clippy --manifest-path codegen/Cargo.toml -- -Dclippy::all -Dclippy::pedantic
|
||||
|
||||
outdated:
|
||||
name: Outdated
|
||||
@ -153,7 +177,7 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/install@cargo-outdated
|
||||
- run: cargo outdated --workspace --exit-code 1
|
||||
- run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1
|
||||
|
4
BUILD.gn
4
BUILD.gn
@ -19,8 +19,8 @@ ohos_cargo_crate("lib") {
|
||||
crate_root = "src/lib.rs"
|
||||
|
||||
sources = [ "src/lib.rs" ]
|
||||
edition = "2018"
|
||||
cargo_pkg_version = "1.0.107"
|
||||
edition = "2021"
|
||||
cargo_pkg_version = "2.0.48"
|
||||
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
|
||||
cargo_pkg_name = "syn"
|
||||
cargo_pkg_description = "Parser for Rust source code"
|
||||
|
35
Cargo.toml
35
Cargo.toml
@ -1,14 +1,13 @@
|
||||
[package]
|
||||
name = "syn"
|
||||
version = "1.0.107" # don't forget to update html_root_url and syn.json
|
||||
version = "2.0.48" # don't forget to update html_root_url and syn.json
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
categories = ["development-tools::procedural-macro-helpers", "parser-implementations"]
|
||||
description = "Parser for Rust source code"
|
||||
documentation = "https://docs.rs/syn"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
include = [
|
||||
"/benches/**",
|
||||
"/build.rs",
|
||||
"/Cargo.toml",
|
||||
"/LICENSE-APACHE",
|
||||
"/LICENSE-MIT",
|
||||
@ -19,7 +18,7 @@ include = [
|
||||
keywords = ["macros", "syn"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/syn"
|
||||
rust-version = "1.31"
|
||||
rust-version = "1.56"
|
||||
|
||||
[features]
|
||||
default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"]
|
||||
@ -36,23 +35,23 @@ proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]
|
||||
test = ["syn-test-suite/all-features"]
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0.46", default-features = false }
|
||||
quote = { version = "1.0", optional = true, default-features = false }
|
||||
unicode-ident = "1.0"
|
||||
proc-macro2 = { version = "1.0.75", default-features = false }
|
||||
quote = { version = "1.0.35", optional = true, default-features = false }
|
||||
unicode-ident = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0"
|
||||
automod = "1.0"
|
||||
flate2 = "1.0"
|
||||
insta = "1.0"
|
||||
rayon = "1.0"
|
||||
ref-cast = "1.0"
|
||||
regex = "1.0"
|
||||
anyhow = "1"
|
||||
automod = "1"
|
||||
flate2 = "1"
|
||||
insta = "1"
|
||||
rayon = "1"
|
||||
ref-cast = "1"
|
||||
reqwest = { version = "0.11", features = ["blocking"] }
|
||||
rustversion = "1"
|
||||
syn-test-suite = { version = "0", path = "tests/features" }
|
||||
tar = "0.4.16"
|
||||
termcolor = "1.0"
|
||||
walkdir = "2.1"
|
||||
termcolor = "1"
|
||||
walkdir = "2.3.2"
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
@ -69,7 +68,7 @@ required-features = ["full", "parsing"]
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--cfg", "doc_cfg"]
|
||||
rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["full", "visit", "visit-mut", "fold", "extra-traits"]
|
||||
@ -85,7 +84,5 @@ members = [
|
||||
"examples/lazy-static/lazy-static",
|
||||
"examples/trace-var/example",
|
||||
"examples/trace-var/trace-var",
|
||||
"json",
|
||||
"tests/crates",
|
||||
"tests/features",
|
||||
]
|
||||
|
@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
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.
|
||||
|
@ -3,7 +3,7 @@
|
||||
"Name": "syn",
|
||||
"License": "Apache License V2.0, MIT",
|
||||
"License File": "LICENSE-APACHE, LICENSE-MIT",
|
||||
"Version Number": "1.0.107",
|
||||
"Version Number": "2.0.48",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/dtolnay/syn",
|
||||
"Description": "A Rust library that provides support for parsing Rust code."
|
||||
|
21
README.md
21
README.md
@ -39,14 +39,14 @@ contains some APIs that may be useful more generally.
|
||||
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
|
||||
[`syn::File`]: https://docs.rs/syn/2.0/syn/struct.File.html
|
||||
[`syn::Item`]: https://docs.rs/syn/2.0/syn/enum.Item.html
|
||||
[`syn::Expr`]: https://docs.rs/syn/2.0/syn/enum.Expr.html
|
||||
[`syn::Type`]: https://docs.rs/syn/2.0/syn/enum.Type.html
|
||||
[`syn::DeriveInput`]: https://docs.rs/syn/2.0/syn/struct.DeriveInput.html
|
||||
[parser functions]: https://docs.rs/syn/2.0/syn/parse/index.html
|
||||
|
||||
*Version requirement: Syn supports rustc 1.31 and up.*
|
||||
*Version requirement: Syn supports rustc 1.56 and up.*
|
||||
|
||||
[*Release notes*](https://github.com/dtolnay/syn/releases)
|
||||
|
||||
@ -76,7 +76,7 @@ tokens back to the compiler to compile into the user's crate.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
syn = "1.0"
|
||||
syn = "2.0"
|
||||
quote = "1.0"
|
||||
|
||||
[lib]
|
||||
@ -104,9 +104,8 @@ pub fn my_macro(input: TokenStream) -> TokenStream {
|
||||
```
|
||||
|
||||
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.
|
||||
derive macro. The example derives a `HeapSize` trait which computes an estimate
|
||||
of the amount of heap memory owned by a value.
|
||||
|
||||
[`heapsize`]: examples/heapsize
|
||||
|
||||
|
@ -4,8 +4,11 @@
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(
|
||||
clippy::items_after_statements,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::must_use_candidate
|
||||
clippy::must_use_candidate,
|
||||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
extern crate test;
|
||||
@ -14,10 +17,9 @@ extern crate test;
|
||||
#[path = "../tests/macros/mod.rs"]
|
||||
mod macros;
|
||||
|
||||
#[path = "../tests/common/mod.rs"]
|
||||
mod common;
|
||||
#[allow(dead_code)]
|
||||
#[path = "../tests/repo/mod.rs"]
|
||||
pub mod repo;
|
||||
mod repo;
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use std::fs;
|
||||
|
@ -5,14 +5,21 @@
|
||||
|
||||
#![cfg_attr(not(syn_only), feature(rustc_private))]
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(clippy::cast_lossless, clippy::unnecessary_wraps)]
|
||||
#![allow(
|
||||
clippy::arc_with_non_send_sync,
|
||||
clippy::cast_lossless,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnecessary_wraps
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
#[path = "../tests/macros/mod.rs"]
|
||||
mod macros;
|
||||
|
||||
#[path = "../tests/common/mod.rs"]
|
||||
mod common;
|
||||
#[allow(dead_code)]
|
||||
#[path = "../tests/repo/mod.rs"]
|
||||
mod repo;
|
||||
|
||||
@ -38,6 +45,7 @@ mod syn_parse {
|
||||
#[cfg(not(syn_only))]
|
||||
mod librustc_parse {
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_error_messages;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_parse;
|
||||
@ -46,7 +54,7 @@ mod librustc_parse {
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_messages::FluentBundle;
|
||||
use rustc_errors::{emitter::Emitter, translation::Translate, Diagnostic, Handler};
|
||||
use rustc_errors::{emitter::Emitter, translation::Translate, DiagCtxt, Diagnostic};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use rustc_span::{edition::Edition, FileName};
|
||||
@ -71,10 +79,10 @@ mod librustc_parse {
|
||||
}
|
||||
|
||||
rustc_span::create_session_if_not_set_then(Edition::Edition2018, |_| {
|
||||
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let source_map = 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);
|
||||
let handler = DiagCtxt::with_emitter(emitter);
|
||||
let sess = ParseSess::with_dcx(handler, source_map);
|
||||
if let Err(diagnostic) = rustc_parse::parse_crate_from_source_str(
|
||||
FileName::Custom("bench".to_owned()),
|
||||
content.to_owned(),
|
||||
@ -91,7 +99,7 @@ mod librustc_parse {
|
||||
#[cfg(not(syn_only))]
|
||||
mod read_from_disk {
|
||||
pub fn bench(content: &str) -> Result<(), ()> {
|
||||
_ = content;
|
||||
let _ = content;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -101,9 +109,13 @@ fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
|
||||
let mut success = 0;
|
||||
let mut total = 0;
|
||||
|
||||
walkdir::WalkDir::new("tests/rust/src")
|
||||
.into_iter()
|
||||
.filter_entry(repo::base_dir_filter)
|
||||
["tests/rust/compiler", "tests/rust/library"]
|
||||
.iter()
|
||||
.flat_map(|dir| {
|
||||
walkdir::WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_entry(repo::base_dir_filter)
|
||||
})
|
||||
.for_each(|entry| {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
|
102
build.rs
102
build.rs
@ -1,51 +1,81 @@
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
use std::ffi::OsString;
|
||||
use std::process::{self, Command, Stdio};
|
||||
|
||||
// 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,
|
||||
};
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
if compiler.minor < 36 {
|
||||
println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
|
||||
}
|
||||
// Note: add "/build.rs" to package.include in Cargo.toml if adding any
|
||||
// conditional compilation within the library.
|
||||
|
||||
if compiler.minor < 39 {
|
||||
println!("cargo:rustc-cfg=syn_no_const_vec_new");
|
||||
}
|
||||
|
||||
if compiler.minor < 40 {
|
||||
println!("cargo:rustc-cfg=syn_no_non_exhaustive");
|
||||
}
|
||||
|
||||
if compiler.minor < 56 {
|
||||
println!("cargo:rustc-cfg=syn_no_negative_literal_parse");
|
||||
}
|
||||
|
||||
if !compiler.nightly {
|
||||
if !unstable() {
|
||||
println!("cargo:rustc-cfg=syn_disable_nightly_tests");
|
||||
}
|
||||
}
|
||||
|
||||
struct Compiler {
|
||||
minor: u32,
|
||||
nightly: bool,
|
||||
fn unstable() -> bool {
|
||||
let rustc = cargo_env_var("RUSTC");
|
||||
|
||||
// Pick up Cargo rustc configuration.
|
||||
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
|
||||
let mut cmd = Command::new(wrapper);
|
||||
// The wrapper's first argument is supposed to be the path to rustc.
|
||||
cmd.arg(rustc);
|
||||
cmd
|
||||
} else {
|
||||
Command::new(rustc)
|
||||
};
|
||||
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stdout(Stdio::null());
|
||||
cmd.stderr(Stdio::null());
|
||||
cmd.arg("-");
|
||||
|
||||
// Find out whether this is a nightly or dev build.
|
||||
cmd.env_remove("RUSTC_BOOTSTRAP");
|
||||
cmd.arg("-Zcrate-attr=feature(rustc_private)");
|
||||
|
||||
// Pass `-Zunpretty` to terminate earlier without writing out any "emit"
|
||||
// files. Use `expanded` to proceed far enough to actually apply crate
|
||||
// attrs. With `unpretty=normal` or `--print`, not enough compilation
|
||||
// happens to recognize that the feature attribute is unstable.
|
||||
cmd.arg("-Zunpretty=expanded");
|
||||
|
||||
// Set #![no_std] to bypass loading libstd.rlib. This is a 7.5% speedup.
|
||||
cmd.arg("-Zcrate-attr=no_std");
|
||||
|
||||
cmd.arg("--crate-type=lib");
|
||||
cmd.arg("--edition=2021");
|
||||
|
||||
if let Some(target) = env::var_os("TARGET") {
|
||||
cmd.arg("--target").arg(target);
|
||||
}
|
||||
|
||||
// If Cargo wants to set RUSTFLAGS, use that.
|
||||
if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
|
||||
if !rustflags.is_empty() {
|
||||
for arg in rustflags.split('\x1f') {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This rustc invocation should take around 0.03 seconds.
|
||||
match cmd.status() {
|
||||
Ok(status) => status.success(),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_version() -> Option<Compiler> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
let minor = pieces.next()?.parse().ok()?;
|
||||
let nightly = version.contains("nightly") || version.ends_with("-dev");
|
||||
Some(Compiler { minor, nightly })
|
||||
fn cargo_env_var(key: &str) -> OsString {
|
||||
env::var_os(key).unwrap_or_else(|| {
|
||||
eprintln!(
|
||||
"Environment variable ${} is not set during execution of build script",
|
||||
key,
|
||||
);
|
||||
process::exit(1);
|
||||
})
|
||||
}
|
||||
|
@ -2,24 +2,25 @@
|
||||
name = "syn-internal-codegen"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>", "Nika Layzell <nika@thelayzells.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
publish = false # this is an internal crate which should never be published
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
anyhow = "1"
|
||||
color-backtrace = "0.4"
|
||||
indexmap = { version = "1.0", features = ["serde-1"] }
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
inflections = "1.1"
|
||||
prettyplease = "0.1"
|
||||
prettyplease = "0.2.3"
|
||||
proc-macro2 = { version = "1.0.20", features = ["span-locations"] }
|
||||
quote = "1.0"
|
||||
semver = { version = "1.0", features = ["serde"] }
|
||||
serde = { version = "1.0.88", features = ["derive"] }
|
||||
quote = "1"
|
||||
semver = { version = "1", features = ["serde"] }
|
||||
serde = "1.0.88"
|
||||
serde_derive = "1.0.88"
|
||||
serde_json = "1.0.38"
|
||||
syn = { version = "2", features = ["derive", "full", "parsing", "printing"], default-features = false }
|
||||
syn-codegen = { path = "../json" }
|
||||
syn = { version = "1.0", features = ["derive", "parsing", "printing", "full"], default-features = false }
|
||||
thiserror = "1.0"
|
||||
thiserror = "1"
|
||||
toml = "0.5"
|
||||
|
||||
[workspace]
|
||||
|
@ -2,11 +2,28 @@ use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn_codegen::Features;
|
||||
|
||||
pub fn features(features: &Features) -> TokenStream {
|
||||
pub fn features<'a>(
|
||||
features: &Features,
|
||||
overriding_cfg: impl Into<Option<&'a str>>,
|
||||
) -> TokenStream {
|
||||
let features = &features.any;
|
||||
match features.len() {
|
||||
0 => quote!(),
|
||||
1 => quote!(#[cfg(feature = #(#features)*)]),
|
||||
_ => quote!(#[cfg(any(#(feature = #features),*))]),
|
||||
let cfg = match features.len() {
|
||||
0 => None,
|
||||
1 => Some(quote! { cfg(feature = #(#features)*) }),
|
||||
_ => Some(quote! { cfg(any(#(feature = #features),*)) }),
|
||||
};
|
||||
match (cfg, overriding_cfg.into()) {
|
||||
(Some(cfg), Some(overriding_cfg)) => quote! {
|
||||
#[#cfg]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = #overriding_cfg)))]
|
||||
},
|
||||
(Some(cfg), None) => quote! {
|
||||
#[#cfg]
|
||||
#[cfg_attr(doc_cfg, doc(#cfg))]
|
||||
},
|
||||
(None, Some(overriding_cfg)) => quote! {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = #overriding_cfg)))]
|
||||
},
|
||||
(None, None) => TokenStream::new(),
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,14 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
const DEBUG_SRC: &str = "../src/gen/clone.rs";
|
||||
const CLONE_SRC: &str = "src/gen/clone.rs";
|
||||
|
||||
fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
let type_name = &node.ident;
|
||||
let ident = Ident::new(type_name, Span::call_site());
|
||||
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
@ -40,18 +41,13 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.exhaustive {
|
||||
None
|
||||
} else if node.ident == "Expr" {
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
Some(quote! {
|
||||
#[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
None
|
||||
};
|
||||
quote! {
|
||||
match self {
|
||||
@ -80,7 +76,7 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
let cfg_features = cfg::features(&node.features);
|
||||
let cfg_features = cfg::features(&node.features, "clone-impls");
|
||||
|
||||
let copy = node.ident == "AttrStyle"
|
||||
|| node.ident == "BinOp"
|
||||
@ -90,10 +86,8 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
if copy {
|
||||
return quote! {
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for #ident {}
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for #ident {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
@ -106,7 +100,6 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for #ident {
|
||||
fn clone(&self) -> Self {
|
||||
#body
|
||||
@ -122,7 +115,7 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
}
|
||||
|
||||
file::write(
|
||||
DEBUG_SRC,
|
||||
CLONE_SRC,
|
||||
quote! {
|
||||
#![allow(clippy::clone_on_copy, clippy::expl_impl_clone_on_copy)]
|
||||
|
||||
|
@ -2,16 +2,57 @@ use crate::{cfg, file, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use std::collections::BTreeSet as Set;
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
const DEBUG_SRC: &str = "../src/gen/debug.rs";
|
||||
const DEBUG_SRC: &str = "src/gen/debug.rs";
|
||||
|
||||
fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
fn syntax_tree_enum<'a>(
|
||||
enum_name: &str,
|
||||
variant_name: &str,
|
||||
fields: &'a [Type],
|
||||
) -> Option<&'a str> {
|
||||
if fields.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
const WHITELIST: &[(&str, &str)] = &[
|
||||
("Meta", "Path"),
|
||||
("Pat", "Const"),
|
||||
("Pat", "Lit"),
|
||||
("Pat", "Macro"),
|
||||
("Pat", "Path"),
|
||||
("Pat", "Range"),
|
||||
("PathArguments", "AngleBracketed"),
|
||||
("PathArguments", "Parenthesized"),
|
||||
("Stmt", "Local"),
|
||||
("TypeParamBound", "Lifetime"),
|
||||
("Visibility", "Public"),
|
||||
("Visibility", "Restricted"),
|
||||
];
|
||||
match &fields[0] {
|
||||
Type::Syn(ty)
|
||||
if WHITELIST.contains(&(enum_name, variant_name))
|
||||
|| enum_name.to_owned() + variant_name == *ty =>
|
||||
{
|
||||
Some(ty)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_impl_body(
|
||||
defs: &Definitions,
|
||||
node: &Node,
|
||||
syntax_tree_variants: &Set<&str>,
|
||||
) -> TokenStream {
|
||||
let type_name = &node.ident;
|
||||
let ident = Ident::new(type_name, Span::call_site());
|
||||
let is_syntax_tree_variant = syntax_tree_variants.contains(type_name.as_str());
|
||||
|
||||
match &node.data {
|
||||
let body = match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
assert!(!is_syntax_tree_variant);
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
@ -19,9 +60,6 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
#ident::#variant => formatter.write_str(#variant_name),
|
||||
}
|
||||
} else {
|
||||
let pats = (0..fields.len())
|
||||
.map(|i| format_ident!("v{}", i))
|
||||
.collect::<Vec<_>>();
|
||||
let mut cfg = None;
|
||||
if node.ident == "Expr" {
|
||||
if let Type::Syn(ty) = &fields[0] {
|
||||
@ -30,30 +68,37 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(#(#pats),*) => {
|
||||
let mut formatter = formatter.debug_tuple(#variant_name);
|
||||
#(formatter.field(#pats);)*
|
||||
formatter.finish()
|
||||
if syntax_tree_enum(type_name, variant_name, fields).is_some() {
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(v0) => v0.debug(formatter, #variant_name),
|
||||
}
|
||||
} else {
|
||||
let pats = (0..fields.len())
|
||||
.map(|i| format_ident!("v{}", i))
|
||||
.collect::<Vec<_>>();
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(#(#pats),*) => {
|
||||
let mut formatter = formatter.debug_tuple(#variant_name);
|
||||
#(formatter.field(#pats);)*
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.exhaustive {
|
||||
None
|
||||
} else if node.ident == "Expr" {
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
Some(quote! {
|
||||
#[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
None
|
||||
};
|
||||
let prefix = format!("{}::", type_name);
|
||||
quote! {
|
||||
formatter.write_str(#prefix)?;
|
||||
match self {
|
||||
#(#arms)*
|
||||
#nonexhaustive
|
||||
@ -61,6 +106,11 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
Data::Struct(fields) => {
|
||||
let type_name = if is_syntax_tree_variant {
|
||||
quote!(name)
|
||||
} else {
|
||||
quote!(#type_name)
|
||||
};
|
||||
let fields = fields.keys().map(|f| {
|
||||
let ident = Ident::new(f, Span::call_site());
|
||||
quote! {
|
||||
@ -74,24 +124,40 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
Data::Private => unreachable!(),
|
||||
};
|
||||
|
||||
if is_syntax_tree_variant {
|
||||
quote! {
|
||||
impl #ident {
|
||||
fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
||||
#body
|
||||
}
|
||||
}
|
||||
self.debug(formatter, #type_name)
|
||||
}
|
||||
} else {
|
||||
body
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
fn expand_impl(defs: &Definitions, node: &Node, syntax_tree_variants: &Set<&str>) -> TokenStream {
|
||||
let manual_debug = node.data == Data::Private || node.ident == "LitBool";
|
||||
if manual_debug {
|
||||
return TokenStream::new();
|
||||
}
|
||||
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
let cfg_features = cfg::features(&node.features);
|
||||
let body = expand_impl_body(defs, node);
|
||||
let cfg_features = cfg::features(&node.features, "extra-traits");
|
||||
let body = expand_impl_body(defs, node, syntax_tree_variants);
|
||||
let formatter = match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(_formatter),
|
||||
_ => quote!(formatter),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for #ident {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, #formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
#body
|
||||
}
|
||||
}
|
||||
@ -99,9 +165,21 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
let mut syntax_tree_variants = Set::new();
|
||||
for node in &defs.types {
|
||||
if let Data::Enum(variants) = &node.data {
|
||||
let enum_name = &node.ident;
|
||||
for (variant_name, fields) in variants {
|
||||
if let Some(inner) = syntax_tree_enum(enum_name, variant_name, fields) {
|
||||
syntax_tree_variants.insert(inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut impls = TokenStream::new();
|
||||
for node in &defs.types {
|
||||
impls.extend(expand_impl(defs, node));
|
||||
impls.extend(expand_impl(defs, node, &syntax_tree_variants));
|
||||
}
|
||||
|
||||
file::write(
|
||||
|
@ -4,11 +4,10 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
const DEBUG_SRC: &str = "../src/gen/eq.rs";
|
||||
const EQ_SRC: &str = "src/gen/eq.rs";
|
||||
|
||||
fn always_eq(field_type: &Type) -> bool {
|
||||
match field_type {
|
||||
Type::Syn(node) => node == "Reserved",
|
||||
Type::Ext(ty) => ty == "Span",
|
||||
Type::Token(_) | Type::Group(_) => true,
|
||||
Type::Box(inner) => always_eq(inner),
|
||||
@ -22,6 +21,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
let ident = Ident::new(type_name, Span::call_site());
|
||||
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
@ -72,10 +72,15 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
});
|
||||
let fallthrough = if variants.len() == 1 {
|
||||
None
|
||||
} else {
|
||||
Some(quote!(_ => false,))
|
||||
};
|
||||
quote! {
|
||||
match (self, other) {
|
||||
#(#arms)*
|
||||
_ => false,
|
||||
#fallthrough
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,11 +114,10 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
let cfg_features = cfg::features(&node.features);
|
||||
let cfg_features = cfg::features(&node.features, "extra-traits");
|
||||
|
||||
let eq = quote! {
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for #ident {}
|
||||
};
|
||||
|
||||
@ -123,17 +127,16 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
|
||||
let body = expand_impl_body(defs, node);
|
||||
let other = if body.to_string() == "true" {
|
||||
quote!(_other)
|
||||
} else {
|
||||
quote!(other)
|
||||
let other = match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(_other),
|
||||
Data::Struct(fields) if fields.values().all(always_eq) => quote!(_other),
|
||||
_ => quote!(other),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#eq
|
||||
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for #ident {
|
||||
fn eq(&self, #other: &Self) -> bool {
|
||||
#body
|
||||
@ -149,7 +152,7 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
}
|
||||
|
||||
file::write(
|
||||
DEBUG_SRC,
|
||||
EQ_SRC,
|
||||
quote! {
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use crate::tt::TokenStreamHelper;
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::workspace_path;
|
||||
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<()> {
|
||||
pub fn write(relative_to_workspace_root: impl AsRef<Path>, content: TokenStream) -> Result<()> {
|
||||
let mut formatted = Vec::new();
|
||||
writeln!(
|
||||
formatted,
|
||||
@ -17,7 +18,8 @@ pub fn write<P: AsRef<Path>>(path: P, content: TokenStream) -> Result<()> {
|
||||
let pretty = prettyplease::unparse(&syntax_tree);
|
||||
write!(formatted, "{}", pretty)?;
|
||||
|
||||
if path.as_ref().is_file() && fs::read(&path)? == formatted {
|
||||
let path = workspace_path::get(relative_to_workspace_root);
|
||||
if path.is_file() && fs::read(&path)? == formatted {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use quote::{format_ident, quote};
|
||||
use syn::Index;
|
||||
use syn_codegen::{Data, Definitions, Features, Node, Type};
|
||||
|
||||
const FOLD_SRC: &str = "../src/gen/fold.rs";
|
||||
const FOLD_SRC: &str = "src/gen/fold.rs";
|
||||
|
||||
fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
|
||||
let ident = gen::under_name(item);
|
||||
@ -62,29 +62,6 @@ fn visit(
|
||||
(#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
|
||||
@ -97,7 +74,7 @@ fn visit(
|
||||
Some(res)
|
||||
}
|
||||
Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
|
||||
Type::Ext(_) | Type::Std(_) => None,
|
||||
Type::Ext(_) | Type::Std(_) | Type::Token(_) | Type::Group(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,19 +128,9 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
|
||||
let nonexhaustive = if s.exhaustive {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
};
|
||||
|
||||
fold_impl.extend(quote! {
|
||||
match node {
|
||||
#fold_variants
|
||||
#nonexhaustive
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -171,32 +138,17 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
let mut fold_fields = TokenStream::new();
|
||||
|
||||
for (field, ty) in fields {
|
||||
let id = Ident::new(&field, Span::call_site());
|
||||
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);
|
||||
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 fields.is_empty() {
|
||||
if ty == "Ident" {
|
||||
fold_impl.extend(quote! {
|
||||
let mut node = node;
|
||||
@ -207,6 +159,12 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
fold_impl.extend(quote! {
|
||||
node
|
||||
});
|
||||
} else {
|
||||
fold_impl.extend(quote! {
|
||||
#ty {
|
||||
#fold_fields
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Data::Private => {
|
||||
@ -258,12 +216,14 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
quote! {
|
||||
// Unreachable code is generated sometimes without the full feature.
|
||||
#![allow(unreachable_code, unused_variables)]
|
||||
#![allow(clippy::match_wildcard_for_single_variants)]
|
||||
#![allow(
|
||||
clippy::match_wildcard_for_single_variants,
|
||||
clippy::needless_match,
|
||||
clippy::needless_pass_by_ref_mut,
|
||||
)]
|
||||
|
||||
#[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;
|
||||
|
||||
@ -274,8 +234,6 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
/// See the [module documentation] for details.
|
||||
///
|
||||
/// [module documentation]: self
|
||||
///
|
||||
/// *This trait is available only if Syn is built with the `"fold"` feature.*
|
||||
pub trait Fold {
|
||||
#traits
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ pub fn traverse(
|
||||
node: fn(&mut TokenStream, &mut TokenStream, &Node, &Definitions),
|
||||
) -> (TokenStream, TokenStream) {
|
||||
let mut types = defs.types.clone();
|
||||
for terminal in TERMINAL_TYPES {
|
||||
for &terminal in TERMINAL_TYPES {
|
||||
types.push(Node {
|
||||
ident: terminal.to_string(),
|
||||
ident: terminal.to_owned(),
|
||||
features: Features::default(),
|
||||
data: Data::Private,
|
||||
exhaustive: true,
|
||||
@ -27,10 +27,7 @@ pub fn traverse(
|
||||
let mut traits = TokenStream::new();
|
||||
let mut impls = TokenStream::new();
|
||||
for s in types {
|
||||
if s.ident == "Reserved" {
|
||||
continue;
|
||||
}
|
||||
let features = cfg::features(&s.features);
|
||||
let features = cfg::features(&s.features, None);
|
||||
traits.extend(features.clone());
|
||||
impls.extend(features);
|
||||
node(&mut traits, &mut impls, &s, defs);
|
||||
|
@ -4,11 +4,10 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
const DEBUG_SRC: &str = "../src/gen/hash.rs";
|
||||
const HASH_SRC: &str = "src/gen/hash.rs";
|
||||
|
||||
fn skip(field_type: &Type) -> bool {
|
||||
match field_type {
|
||||
Type::Syn(node) => node == "Reserved",
|
||||
Type::Ext(ty) => ty == "Span",
|
||||
Type::Token(_) | Type::Group(_) => true,
|
||||
Type::Box(inner) => skip(inner),
|
||||
@ -22,12 +21,13 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
let ident = Ident::new(type_name, Span::call_site());
|
||||
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let arms = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (variant_name, fields))| {
|
||||
let i = i as u8;
|
||||
let i = u8::try_from(i).unwrap();
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
@ -76,18 +76,13 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.exhaustive {
|
||||
None
|
||||
} else if node.ident == "Expr" {
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
Some(quote! {
|
||||
#[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
None
|
||||
};
|
||||
quote! {
|
||||
match self {
|
||||
@ -128,20 +123,20 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
}
|
||||
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
let cfg_features = cfg::features(&node.features);
|
||||
let cfg_features = cfg::features(&node.features, "extra-traits");
|
||||
|
||||
let body = expand_impl_body(defs, node);
|
||||
let state = if body.is_empty() {
|
||||
quote!(_state)
|
||||
} else {
|
||||
quote!(state)
|
||||
|
||||
let hasher = match &node.data {
|
||||
Data::Struct(_) if body.is_empty() => quote!(_state),
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(_state),
|
||||
_ => quote!(state),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for #ident {
|
||||
fn hash<H>(&self, #state: &mut H)
|
||||
fn hash<H>(&self, #hasher: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
@ -158,7 +153,7 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
}
|
||||
|
||||
file::write(
|
||||
DEBUG_SRC,
|
||||
HASH_SRC,
|
||||
quote! {
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use crate::tt::TokenStreamHelper;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::workspace_path;
|
||||
use anyhow::Result;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use syn_codegen::Definitions;
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
@ -10,8 +10,7 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
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");
|
||||
let json_path = workspace_path::get("syn.json");
|
||||
fs::write(json_path, j)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -9,7 +9,14 @@
|
||||
// Finally this crate generates the Visit, VisitMut, and Fold traits in Syn
|
||||
// programmatically from the syntax tree description.
|
||||
|
||||
#![allow(clippy::needless_pass_by_value)]
|
||||
#![allow(
|
||||
clippy::items_after_statements,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines,
|
||||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
mod cfg;
|
||||
mod clone;
|
||||
@ -28,6 +35,7 @@ mod snapshot;
|
||||
mod version;
|
||||
mod visit;
|
||||
mod visit_mut;
|
||||
mod workspace_path;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
color_backtrace::install();
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::version;
|
||||
use crate::{version, workspace_path};
|
||||
use anyhow::{bail, Result};
|
||||
use indexmap::IndexMap;
|
||||
use quote::quote;
|
||||
@ -8,35 +8,46 @@ use std::path::{Path, PathBuf};
|
||||
use syn::parse::{Error, Parser};
|
||||
use syn::{
|
||||
parse_quote, Attribute, Data, DataEnum, DataStruct, DeriveInput, Fields, GenericArgument,
|
||||
Ident, Item, PathArguments, TypeMacro, TypePath, TypeTuple, Visibility,
|
||||
Ident, Item, PathArguments, TypeMacro, TypePath, TypeTuple, UseTree, Visibility,
|
||||
};
|
||||
use syn_codegen as types;
|
||||
use thiserror::Error;
|
||||
|
||||
const SYN_CRATE_ROOT: &str = "../src/lib.rs";
|
||||
const TOKEN_SRC: &str = "../src/token.rs";
|
||||
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"];
|
||||
|
||||
// NOTE: BTreeMap is used here instead of HashMap to have deterministic output.
|
||||
type ItemLookup = BTreeMap<Ident, AstItem>;
|
||||
type TokenLookup = BTreeMap<String, String>;
|
||||
struct Lookup {
|
||||
items: BTreeMap<Ident, AstItem>,
|
||||
// "+" => "Add"
|
||||
tokens: BTreeMap<String, String>,
|
||||
// "PatLit" => "ExprLit"
|
||||
aliases: BTreeMap<Ident, Ident>,
|
||||
}
|
||||
|
||||
/// 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 tokens = load_token_file(TOKEN_SRC)?;
|
||||
|
||||
let token_lookup = load_token_file(TOKEN_SRC)?;
|
||||
let mut lookup = Lookup {
|
||||
items: BTreeMap::new(),
|
||||
tokens,
|
||||
aliases: BTreeMap::new(),
|
||||
};
|
||||
|
||||
load_file(SYN_CRATE_ROOT, &[], &mut lookup)?;
|
||||
|
||||
let version = version::get()?;
|
||||
|
||||
let types = item_lookup
|
||||
let types = lookup
|
||||
.items
|
||||
.values()
|
||||
.map(|item| introspect_item(item, &item_lookup, &token_lookup))
|
||||
.map(|item| introspect_item(item, &lookup))
|
||||
.collect();
|
||||
|
||||
let tokens = token_lookup
|
||||
let tokens = lookup
|
||||
.tokens
|
||||
.into_iter()
|
||||
.map(|(name, ty)| (ty, name))
|
||||
.collect();
|
||||
@ -54,22 +65,23 @@ pub struct AstItem {
|
||||
features: Vec<Attribute>,
|
||||
}
|
||||
|
||||
fn introspect_item(item: &AstItem, items: &ItemLookup, tokens: &TokenLookup) -> types::Node {
|
||||
fn introspect_item(item: &AstItem, lookup: &Lookup) -> types::Node {
|
||||
let features = introspect_features(&item.features);
|
||||
|
||||
match &item.ast.data {
|
||||
Data::Enum(ref data) => types::Node {
|
||||
Data::Enum(data) => types::Node {
|
||||
ident: item.ast.ident.to_string(),
|
||||
features,
|
||||
data: types::Data::Enum(introspect_enum(data, items, tokens)),
|
||||
exhaustive: !data.variants.iter().any(|v| is_doc_hidden(&v.attrs)),
|
||||
data: types::Data::Enum(introspect_enum(data, lookup)),
|
||||
exhaustive: !(is_non_exhaustive(&item.ast.attrs)
|
||||
|| data.variants.iter().any(|v| is_doc_hidden(&v.attrs))),
|
||||
},
|
||||
Data::Struct(ref data) => types::Node {
|
||||
Data::Struct(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))
|
||||
types::Data::Struct(introspect_struct(data, lookup))
|
||||
} else {
|
||||
types::Data::Private
|
||||
}
|
||||
@ -80,7 +92,7 @@ fn introspect_item(item: &AstItem, items: &ItemLookup, tokens: &TokenLookup) ->
|
||||
}
|
||||
}
|
||||
|
||||
fn introspect_enum(item: &DataEnum, items: &ItemLookup, tokens: &TokenLookup) -> types::Variants {
|
||||
fn introspect_enum(item: &DataEnum, lookup: &Lookup) -> types::Variants {
|
||||
item.variants
|
||||
.iter()
|
||||
.filter_map(|variant| {
|
||||
@ -91,17 +103,17 @@ fn introspect_enum(item: &DataEnum, items: &ItemLookup, tokens: &TokenLookup) ->
|
||||
Fields::Unnamed(fields) => fields
|
||||
.unnamed
|
||||
.iter()
|
||||
.map(|field| introspect_type(&field.ty, items, tokens))
|
||||
.map(|field| introspect_type(&field.ty, lookup))
|
||||
.collect(),
|
||||
Fields::Unit => vec![],
|
||||
_ => panic!("Enum representation not supported"),
|
||||
Fields::Named(_) => panic!("Enum representation not supported"),
|
||||
};
|
||||
Some((variant.ident.to_string(), fields))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn introspect_struct(item: &DataStruct, items: &ItemLookup, tokens: &TokenLookup) -> types::Fields {
|
||||
fn introspect_struct(item: &DataStruct, lookup: &Lookup) -> types::Fields {
|
||||
match &item.fields {
|
||||
Fields::Named(fields) => fields
|
||||
.named
|
||||
@ -109,74 +121,71 @@ fn introspect_struct(item: &DataStruct, items: &ItemLookup, tokens: &TokenLookup
|
||||
.map(|field| {
|
||||
(
|
||||
field.ident.as_ref().unwrap().to_string(),
|
||||
introspect_type(&field.ty, items, tokens),
|
||||
introspect_type(&field.ty, lookup),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
Fields::Unit => IndexMap::new(),
|
||||
_ => panic!("Struct representation not supported"),
|
||||
Fields::Unnamed(_) => panic!("Struct representation not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
fn introspect_type(item: &syn::Type, items: &ItemLookup, tokens: &TokenLookup) -> types::Type {
|
||||
fn introspect_type(item: &syn::Type, lookup: &Lookup) -> types::Type {
|
||||
match item {
|
||||
syn::Type::Path(TypePath {
|
||||
qself: None,
|
||||
ref path,
|
||||
}) => {
|
||||
syn::Type::Path(TypePath { qself: None, 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);
|
||||
let nested = introspect_type(first_arg(&last.arguments), lookup);
|
||||
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!(),
|
||||
let nested = introspect_type(first_arg(&last.arguments), lookup);
|
||||
let types::Type::Token(punct) =
|
||||
introspect_type(last_arg(&last.arguments), lookup)
|
||||
else {
|
||||
panic!()
|
||||
};
|
||||
|
||||
types::Type::Punctuated(types::Punctuated {
|
||||
element: Box::new(nested),
|
||||
punct,
|
||||
})
|
||||
}
|
||||
"Vec" => {
|
||||
let nested = introspect_type(first_arg(&last.arguments), items, tokens);
|
||||
let nested = introspect_type(first_arg(&last.arguments), lookup);
|
||||
types::Type::Vec(Box::new(nested))
|
||||
}
|
||||
"Box" => {
|
||||
let nested = introspect_type(first_arg(&last.arguments), items, tokens);
|
||||
let nested = introspect_type(first_arg(&last.arguments), lookup);
|
||||
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)
|
||||
let mut resolved = &last.ident;
|
||||
while let Some(alias) = lookup.aliases.get(resolved) {
|
||||
resolved = alias;
|
||||
}
|
||||
if lookup.items.get(resolved).is_some() {
|
||||
types::Type::Syn(resolved.to_string())
|
||||
} else {
|
||||
unimplemented!("{}", string);
|
||||
unimplemented!("{}", resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
syn::Type::Tuple(TypeTuple { ref elems, .. }) => {
|
||||
let tys = elems
|
||||
.iter()
|
||||
.map(|ty| introspect_type(&ty, items, tokens))
|
||||
.collect();
|
||||
syn::Type::Tuple(TypeTuple { elems, .. }) => {
|
||||
let tys = elems.iter().map(|ty| introspect_type(ty, lookup)).collect();
|
||||
types::Type::Tuple(tys)
|
||||
}
|
||||
syn::Type::Macro(TypeMacro { ref mac })
|
||||
syn::Type::Macro(TypeMacro { mac })
|
||||
if mac.path.segments.last().unwrap().ident == "Token" =>
|
||||
{
|
||||
let content = mac.tokens.to_string();
|
||||
let ty = tokens.get(&content).unwrap().to_string();
|
||||
let ty = lookup.tokens.get(&content).unwrap().to_string();
|
||||
|
||||
types::Type::Token(ty)
|
||||
}
|
||||
@ -188,11 +197,11 @@ fn introspect_features(attrs: &[Attribute]) -> types::Features {
|
||||
let mut ret = types::Features::default();
|
||||
|
||||
for attr in attrs {
|
||||
if !attr.path.is_ident("cfg") {
|
||||
if !attr.path().is_ident("cfg") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let features = parsing::parse_features.parse2(attr.tokens.clone()).unwrap();
|
||||
let features = attr.parse_args_with(parsing::parse_features).unwrap();
|
||||
|
||||
if ret.any.is_empty() {
|
||||
ret = features;
|
||||
@ -214,60 +223,65 @@ fn is_pub(vis: &Visibility) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_non_exhaustive(attrs: &[Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.path().is_ident("non_exhaustive") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_doc_hidden(attrs: &[Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("doc") {
|
||||
if parsing::parse_doc_hidden_attr
|
||||
.parse2(attr.tokens.clone())
|
||||
.is_ok()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if attr.path().is_ident("doc") && attr.parse_args::<parsing::kw::hidden>().is_ok() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn first_arg(params: &PathArguments) -> &syn::Type {
|
||||
let data = match *params {
|
||||
PathArguments::AngleBracketed(ref data) => data,
|
||||
let data = match params {
|
||||
PathArguments::AngleBracketed(data) => data,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
};
|
||||
|
||||
match *data
|
||||
match data
|
||||
.args
|
||||
.first()
|
||||
.expect("Expected at least 1 type argument here")
|
||||
{
|
||||
GenericArgument::Type(ref ty) => ty,
|
||||
GenericArgument::Type(ty) => ty,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
}
|
||||
}
|
||||
|
||||
fn last_arg(params: &PathArguments) -> &syn::Type {
|
||||
let data = match *params {
|
||||
PathArguments::AngleBracketed(ref data) => data,
|
||||
let data = match params {
|
||||
PathArguments::AngleBracketed(data) => data,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
};
|
||||
|
||||
match *data
|
||||
match data
|
||||
.args
|
||||
.last()
|
||||
.expect("Expected at least 1 type argument here")
|
||||
{
|
||||
GenericArgument::Type(ref ty) => ty,
|
||||
GenericArgument::Type(ty) => ty,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
}
|
||||
}
|
||||
|
||||
mod parsing {
|
||||
use super::{AstItem, TokenLookup};
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
use super::AstItem;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use syn::parse::{ParseStream, Parser, Result};
|
||||
use syn::parse::{ParseStream, Result};
|
||||
use syn::{
|
||||
braced, bracketed, parenthesized, parse_quote, token, Attribute, Ident, LitStr, Path, Token,
|
||||
braced, bracketed, parenthesized, parse_quote, token, Attribute, Expr, Ident, Lit, LitStr,
|
||||
Path, Token,
|
||||
};
|
||||
use syn_codegen as types;
|
||||
|
||||
@ -313,32 +327,18 @@ mod parsing {
|
||||
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)?;
|
||||
pub fn ast_enum(input: ParseStream) -> Result<AstItem> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
input.parse::<Token![pub]>()?;
|
||||
input.parse::<Token![enum]>()?;
|
||||
let ident: Ident = input.parse()?;
|
||||
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![],
|
||||
})
|
||||
Ok(AstItem {
|
||||
ast: syn::parse2(quote! {
|
||||
#(#attrs)*
|
||||
pub enum #ident #rest
|
||||
})?,
|
||||
features: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -368,7 +368,7 @@ mod parsing {
|
||||
}
|
||||
|
||||
pub fn ast_enum_of_structs(input: ParseStream) -> Result<AstItem> {
|
||||
input.call(Attribute::parse_outer)?;
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
input.parse::<Token![pub]>()?;
|
||||
input.parse::<Token![enum]>()?;
|
||||
let ident: Ident = input.parse()?;
|
||||
@ -380,20 +380,18 @@ mod parsing {
|
||||
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 attrs = &v.attrs;
|
||||
let name = &v.name;
|
||||
match v.member {
|
||||
Some(ref member) => quote!(#(#attrs)* #name(#member)),
|
||||
None => quote!(#(#attrs)* #name),
|
||||
if let Some(member) = &v.member {
|
||||
quote!(#(#attrs)* #name(#member))
|
||||
} else {
|
||||
quote!(#(#attrs)* #name)
|
||||
}
|
||||
});
|
||||
parse_quote! {
|
||||
#(#attrs)*
|
||||
pub enum #ident {
|
||||
#(#variants),*
|
||||
}
|
||||
@ -405,47 +403,26 @@ mod parsing {
|
||||
})
|
||||
}
|
||||
|
||||
mod kw {
|
||||
pub mod kw {
|
||||
syn::custom_keyword!(hidden);
|
||||
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![;]>()?;
|
||||
|
||||
pub fn parse_token_macro(input: ParseStream) -> Result<BTreeMap<String, String>> {
|
||||
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;
|
||||
bracketed!(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());
|
||||
}
|
||||
while !input.is_empty() {
|
||||
let pattern;
|
||||
bracketed!(pattern in input);
|
||||
let token = pattern.parse::<TokenStream>()?.to_string();
|
||||
input.parse::<Token![=>]>()?;
|
||||
let expansion;
|
||||
braced!(expansion in input);
|
||||
input.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)
|
||||
}
|
||||
@ -463,56 +440,43 @@ mod parsing {
|
||||
pub fn parse_features(input: ParseStream) -> Result<types::Features> {
|
||||
let mut features = BTreeSet::new();
|
||||
|
||||
let level_1;
|
||||
parenthesized!(level_1 in input);
|
||||
|
||||
let i: Ident = level_1.fork().parse()?;
|
||||
let i: Ident = input.fork().parse()?;
|
||||
|
||||
if i == "any" {
|
||||
level_1.parse::<Ident>()?;
|
||||
input.parse::<Ident>()?;
|
||||
|
||||
let level_2;
|
||||
parenthesized!(level_2 in level_1);
|
||||
let nested;
|
||||
parenthesized!(nested in input);
|
||||
|
||||
while !level_2.is_empty() {
|
||||
features.insert(parse_feature(&level_2)?);
|
||||
while !nested.is_empty() {
|
||||
features.insert(parse_feature(&nested)?);
|
||||
|
||||
if !level_2.is_empty() {
|
||||
level_2.parse::<Token![,]>()?;
|
||||
if !nested.is_empty() {
|
||||
nested.parse::<Token![,]>()?;
|
||||
}
|
||||
}
|
||||
} else if i == "feature" {
|
||||
features.insert(parse_feature(&level_1)?);
|
||||
assert!(level_1.is_empty());
|
||||
features.insert(parse_feature(input)?);
|
||||
assert!(input.is_empty());
|
||||
} else {
|
||||
panic!("{:?}", i);
|
||||
}
|
||||
|
||||
assert!(input.is_empty());
|
||||
|
||||
Ok(types::Features { any: features })
|
||||
}
|
||||
|
||||
pub fn path_attr(attrs: &[Attribute]) -> Result<Option<LitStr>> {
|
||||
pub fn path_attr(attrs: &[Attribute]) -> Result<Option<&LitStr>> {
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("path") {
|
||||
fn parser(input: ParseStream) -> Result<LitStr> {
|
||||
input.parse::<Token![=]>()?;
|
||||
input.parse()
|
||||
if attr.path().is_ident("path") {
|
||||
if let Expr::Lit(expr) = &attr.meta.require_name_value()?.value {
|
||||
if let Lit::Str(lit) = &expr.lit {
|
||||
return Ok(Some(lit));
|
||||
}
|
||||
}
|
||||
let filename = parser.parse2(attr.tokens.clone())?;
|
||||
return Ok(Some(filename));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn parse_doc_hidden_attr(input: ParseStream) -> Result<()> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
content.parse::<kw::hidden>()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_features(features: &[Attribute]) -> Vec<Attribute> {
|
||||
@ -523,7 +487,7 @@ fn get_features(attrs: &[Attribute], base: &[Attribute]) -> Vec<Attribute> {
|
||||
let mut ret = clone_features(base);
|
||||
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("cfg") {
|
||||
if attr.path().is_ident("cfg") {
|
||||
ret.push(parse_quote!(#attr));
|
||||
}
|
||||
}
|
||||
@ -540,12 +504,12 @@ struct LoadFileError {
|
||||
error: Error,
|
||||
}
|
||||
|
||||
fn load_file<P: AsRef<Path>>(
|
||||
name: P,
|
||||
fn load_file(
|
||||
relative_to_workspace_root: impl AsRef<Path>,
|
||||
features: &[Attribute],
|
||||
lookup: &mut ItemLookup,
|
||||
lookup: &mut Lookup,
|
||||
) -> Result<()> {
|
||||
let error = match do_load_file(&name, features, lookup).err() {
|
||||
let error = match do_load_file(&relative_to_workspace_root, features, lookup).err() {
|
||||
None => return Ok(()),
|
||||
Some(error) => error,
|
||||
};
|
||||
@ -554,23 +518,23 @@ fn load_file<P: AsRef<Path>>(
|
||||
let span = error.span().start();
|
||||
|
||||
bail!(LoadFileError {
|
||||
path: name.as_ref().to_owned(),
|
||||
path: relative_to_workspace_root.as_ref().to_owned(),
|
||||
line: span.line,
|
||||
column: span.column + 1,
|
||||
error,
|
||||
})
|
||||
}
|
||||
|
||||
fn do_load_file<P: AsRef<Path>>(
|
||||
name: P,
|
||||
fn do_load_file(
|
||||
relative_to_workspace_root: impl AsRef<Path>,
|
||||
features: &[Attribute],
|
||||
lookup: &mut ItemLookup,
|
||||
lookup: &mut Lookup,
|
||||
) -> Result<()> {
|
||||
let name = name.as_ref();
|
||||
let parent = name.parent().expect("no parent path");
|
||||
let relative_to_workspace_root = relative_to_workspace_root.as_ref();
|
||||
let parent = relative_to_workspace_root.parent().expect("no parent path");
|
||||
|
||||
// Parse the file
|
||||
let src = fs::read_to_string(name)?;
|
||||
let src = fs::read_to_string(workspace_path::get(relative_to_workspace_root))?;
|
||||
let file = syn::parse_file(&src)?;
|
||||
|
||||
// Collect all of the interesting AstItems declared in this file or submodules.
|
||||
@ -603,9 +567,10 @@ fn do_load_file<P: AsRef<Path>>(
|
||||
|
||||
// Look up the submodule file, and recursively parse it.
|
||||
// Only handles same-directory .rs file submodules for now.
|
||||
let filename = match parsing::path_attr(&item.attrs)? {
|
||||
Some(filename) => filename.value(),
|
||||
None => format!("{}.rs", item.ident),
|
||||
let filename = if let Some(filename) = parsing::path_attr(&item.attrs)? {
|
||||
filename.value()
|
||||
} else {
|
||||
format!("{}.rs", item.ident)
|
||||
};
|
||||
let path = parent.join(filename);
|
||||
load_file(path, &features, lookup)?;
|
||||
@ -617,28 +582,24 @@ fn do_load_file<P: AsRef<Path>>(
|
||||
|
||||
// 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)?)
|
||||
let mut found = if item.mac.path.is_ident("ast_struct") {
|
||||
parsing::ast_struct.parse2(tts)
|
||||
} else if item.mac.path.is_ident("ast_enum") {
|
||||
parsing::ast_enum.parse2(tts)?
|
||||
parsing::ast_enum.parse2(tts)
|
||||
} else if item.mac.path.is_ident("ast_enum_of_structs") {
|
||||
Some(parsing::ast_enum_of_structs.parse2(tts)?)
|
||||
parsing::ast_enum_of_structs.parse2(tts)
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
}?;
|
||||
|
||||
// Record our features on the parsed AstItems.
|
||||
if let Some(mut item) = found {
|
||||
if item.ast.ident != "Reserved" {
|
||||
item.features.extend(clone_features(&features));
|
||||
lookup.insert(item.ast.ident.clone(), item);
|
||||
}
|
||||
}
|
||||
found.features.extend(clone_features(&features));
|
||||
lookup.items.insert(found.ast.ident.clone(), found);
|
||||
}
|
||||
Item::Struct(item) => {
|
||||
let ident = item.ident;
|
||||
if EXTRA_TYPES.contains(&&ident.to_string()[..]) {
|
||||
lookup.insert(
|
||||
lookup.items.insert(
|
||||
ident.clone(),
|
||||
AstItem {
|
||||
ast: DeriveInput {
|
||||
@ -657,20 +618,43 @@ fn do_load_file<P: AsRef<Path>>(
|
||||
);
|
||||
}
|
||||
}
|
||||
Item::Use(item)
|
||||
if relative_to_workspace_root == Path::new(SYN_CRATE_ROOT)
|
||||
&& matches!(item.vis, Visibility::Public(_)) =>
|
||||
{
|
||||
load_aliases(item.tree, lookup);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_token_file<P: AsRef<Path>>(name: P) -> Result<TokenLookup> {
|
||||
let name = name.as_ref();
|
||||
let src = fs::read_to_string(name)?;
|
||||
fn load_aliases(use_tree: UseTree, lookup: &mut Lookup) {
|
||||
match use_tree {
|
||||
UseTree::Path(use_tree) => load_aliases(*use_tree.tree, lookup),
|
||||
UseTree::Rename(use_tree) => {
|
||||
lookup.aliases.insert(use_tree.rename, use_tree.ident);
|
||||
}
|
||||
UseTree::Group(use_tree) => {
|
||||
for use_tree in use_tree.items {
|
||||
load_aliases(use_tree, lookup);
|
||||
}
|
||||
}
|
||||
UseTree::Name(_) | UseTree::Glob(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_token_file(
|
||||
relative_to_workspace_root: impl AsRef<Path>,
|
||||
) -> Result<BTreeMap<String, String>> {
|
||||
let path = workspace_path::get(relative_to_workspace_root);
|
||||
let src = fs::read_to_string(path)?;
|
||||
let file = syn::parse_file(&src)?;
|
||||
for item in file.items {
|
||||
if let Item::Macro(item) = item {
|
||||
match item.ident {
|
||||
Some(ref i) if i == "export_token_macro" => {}
|
||||
Some(i) if i == "Token" => {}
|
||||
_ => continue,
|
||||
}
|
||||
let tokens = item.mac.parse_body_with(parsing::parse_token_macro)?;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::operand::{Borrowed, Operand, Owned};
|
||||
use crate::{file, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
@ -5,7 +6,7 @@ use quote::{format_ident, quote};
|
||||
use syn::Index;
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
const DEBUG_SRC: &str = "../tests/debug/gen.rs";
|
||||
const TESTS_DEBUG_SRC: &str = "tests/debug/gen.rs";
|
||||
|
||||
fn rust_type(ty: &Type) -> TokenStream {
|
||||
match ty {
|
||||
@ -55,44 +56,44 @@ fn is_printable(ty: &Type) -> bool {
|
||||
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,
|
||||
Type::Syn(_) | Type::Std(_) | Type::Punctuated(_) | Type::Option(_) | Type::Vec(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_field(val: &TokenStream, ty: &Type) -> Option<TokenStream> {
|
||||
fn format_field(val: &Operand, 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(())
|
||||
if let Some(format) = format_field(&Borrowed(quote!(_val)), ty) {
|
||||
let ty = rust_type(ty);
|
||||
let val = val.ref_tokens();
|
||||
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(_val) => {
|
||||
formatter.write_str("Some(")?;
|
||||
Debug::fmt(#format, formatter)?;
|
||||
formatter.write_str(")")?;
|
||||
Ok(())
|
||||
}
|
||||
None => formatter.write_str("None"),
|
||||
}
|
||||
None => formatter.write_str("None"),
|
||||
}
|
||||
}
|
||||
Print::ref_cast(#val)
|
||||
})
|
||||
} else {
|
||||
let val = val.tokens();
|
||||
quote! {
|
||||
&super::Option { present: #val.is_some() }
|
||||
}
|
||||
Print::ref_cast(#val)
|
||||
})
|
||||
}
|
||||
}
|
||||
Type::Tuple(ty) => {
|
||||
let printable: Vec<TokenStream> = ty
|
||||
@ -100,8 +101,9 @@ fn format_field(val: &TokenStream, ty: &Type) -> Option<TokenStream> {
|
||||
.enumerate()
|
||||
.filter_map(|(i, ty)| {
|
||||
let index = Index::from(i);
|
||||
let val = quote!(&#val.#index);
|
||||
format_field(&val, ty)
|
||||
let val = val.tokens();
|
||||
let inner = Owned(quote!(#val.#index));
|
||||
format_field(&inner, ty)
|
||||
})
|
||||
.collect();
|
||||
if printable.len() == 1 {
|
||||
@ -112,7 +114,10 @@ fn format_field(val: &TokenStream, ty: &Type) -> Option<TokenStream> {
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => quote! { Lite(#val) },
|
||||
_ => {
|
||||
let val = val.ref_tokens();
|
||||
quote! { Lite(#val) }
|
||||
}
|
||||
};
|
||||
Some(format)
|
||||
}
|
||||
@ -121,27 +126,43 @@ fn syntax_tree_enum<'a>(outer: &str, inner: &str, fields: &'a [Type]) -> Option<
|
||||
if fields.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
const WHITELIST: &[&str] = &["PathArguments", "Visibility"];
|
||||
const WHITELIST: &[(&str, &str)] = &[
|
||||
("Meta", "Path"),
|
||||
("PathArguments", "AngleBracketed"),
|
||||
("PathArguments", "Parenthesized"),
|
||||
("Stmt", "Local"),
|
||||
("TypeParamBound", "Lifetime"),
|
||||
("Visibility", "Public"),
|
||||
("Visibility", "Restricted"),
|
||||
];
|
||||
match &fields[0] {
|
||||
Type::Syn(ty) if WHITELIST.contains(&outer) || outer.to_owned() + inner == *ty => Some(ty),
|
||||
Type::Syn(ty) if WHITELIST.contains(&(outer, inner)) || outer.to_owned() + inner == *ty => {
|
||||
Some(ty)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream {
|
||||
fn expand_impl_body(defs: &Definitions, node: &Node, name: &str, val: &Operand) -> TokenStream {
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(unreachable!()),
|
||||
Data::Enum(variants) => {
|
||||
let arms = variants.iter().map(|(v, fields)| {
|
||||
let path = format!("{}::{}", name, v);
|
||||
let variant = Ident::new(v, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
syn::#ident::#variant => formatter.write_str(#v),
|
||||
syn::#ident::#variant => formatter.write_str(#path),
|
||||
}
|
||||
} else if let Some(inner) = syntax_tree_enum(name, v, fields) {
|
||||
let path = format!("{}::{}", name, v);
|
||||
let format = expand_impl_body(defs, lookup::node(defs, inner), &path);
|
||||
let format = expand_impl_body(
|
||||
defs,
|
||||
lookup::node(defs, inner),
|
||||
&path,
|
||||
&Borrowed(quote!(_val)),
|
||||
);
|
||||
quote! {
|
||||
syn::#ident::#variant(_val) => {
|
||||
#format
|
||||
@ -157,7 +178,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
})
|
||||
} else {
|
||||
let ty = &fields[0];
|
||||
format_field(&val, ty).map(|format| {
|
||||
format_field(&Borrowed(val), ty).map(|format| {
|
||||
quote! {
|
||||
formatter.write_str("(")?;
|
||||
Debug::fmt(#format, formatter)?;
|
||||
@ -167,7 +188,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
};
|
||||
quote! {
|
||||
syn::#ident::#variant(_val) => {
|
||||
formatter.write_str(#v)?;
|
||||
formatter.write_str(#path)?;
|
||||
#format
|
||||
Ok(())
|
||||
}
|
||||
@ -177,14 +198,14 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
let fields = fields.iter().enumerate().filter_map(|(i, ty)| {
|
||||
let index = format_ident!("_v{}", i);
|
||||
let val = quote!(#index);
|
||||
let format = format_field(&val, ty)?;
|
||||
let format = format_field(&Borrowed(val), ty)?;
|
||||
Some(quote! {
|
||||
formatter.field(#format);
|
||||
})
|
||||
});
|
||||
quote! {
|
||||
syn::#ident::#variant(#(#pats),*) => {
|
||||
let mut formatter = formatter.debug_tuple(#v);
|
||||
let mut formatter = formatter.debug_tuple(#path);
|
||||
#(#fields)*
|
||||
formatter.finish()
|
||||
}
|
||||
@ -196,8 +217,9 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
} else {
|
||||
Some(quote!(_ => unreachable!()))
|
||||
};
|
||||
let val = val.ref_tokens();
|
||||
quote! {
|
||||
match _val {
|
||||
match #val {
|
||||
#(#arms)*
|
||||
#nonexhaustive
|
||||
}
|
||||
@ -207,43 +229,65 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
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| {
|
||||
Some(if let Some(format) = format_field(&Owned(quote!(self.0)), ty) {
|
||||
let val = val.tokens();
|
||||
let ty = rust_type(ty);
|
||||
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(())
|
||||
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(")?;
|
||||
Debug::fmt(#format, formatter)?;
|
||||
formatter.write_str(")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
formatter.field(#f, Print::ref_cast(val));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let val = val.tokens();
|
||||
quote! {
|
||||
if #val.#ident.is_some() {
|
||||
formatter.field(#f, &Present);
|
||||
}
|
||||
formatter.field(#f, Print::ref_cast(val));
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let val = quote!(&_val.#ident);
|
||||
let format = format_field(&val, ty)?;
|
||||
let val = val.tokens();
|
||||
let inner = Owned(quote!(#val.#ident));
|
||||
let format = format_field(&inner, ty)?;
|
||||
let mut call = quote! {
|
||||
formatter.field(#f, #format);
|
||||
};
|
||||
if let Type::Vec(_) | Type::Punctuated(_) = ty {
|
||||
if node.ident == "Block" && f == "stmts" {
|
||||
// Format regardless of whether is_empty().
|
||||
} else if let Type::Vec(_) | Type::Punctuated(_) = ty {
|
||||
call = quote! {
|
||||
if !_val.#ident.is_empty() {
|
||||
if !#val.#ident.is_empty() {
|
||||
#call
|
||||
}
|
||||
};
|
||||
} else if let Type::Syn(inner) = ty {
|
||||
for node in &defs.types {
|
||||
if node.ident == *inner {
|
||||
if let Data::Enum(variants) = &node.data {
|
||||
if variants.get("None").map_or(false, Vec::is_empty) {
|
||||
let ty = rust_type(ty);
|
||||
call = quote! {
|
||||
match #val.#ident {
|
||||
#ty::None => {}
|
||||
_ => { #call }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(call)
|
||||
}
|
||||
@ -256,12 +300,14 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
}
|
||||
Data::Private => {
|
||||
if node.ident == "LitInt" || node.ident == "LitFloat" {
|
||||
let val = val.ref_tokens();
|
||||
quote! {
|
||||
write!(formatter, "{}", _val)
|
||||
write!(formatter, "{}", #val)
|
||||
}
|
||||
} else {
|
||||
let val = val.tokens();
|
||||
quote! {
|
||||
write!(formatter, "{:?}", _val.value())
|
||||
write!(formatter, "{:?}", #val.value())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,33 +315,54 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str) -> TokenStream
|
||||
}
|
||||
|
||||
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);
|
||||
let body = expand_impl_body(defs, node, &node.ident, &Owned(quote!(self.value)));
|
||||
let formatter = match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(_formatter),
|
||||
_ => quote!(formatter),
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl Debug for Lite<syn::#ident> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let _val = &self.value;
|
||||
fn fmt(&self, #formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_token_impl(name: &str, symbol: &str) -> TokenStream {
|
||||
let ident = Ident::new(name, Span::call_site());
|
||||
let repr = format!("Token![{}]", symbol);
|
||||
|
||||
quote! {
|
||||
impl Debug for Lite<syn::token::#ident> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(#repr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
let mut impls = TokenStream::new();
|
||||
for node in &defs.types {
|
||||
impls.extend(expand_impl(&defs, node));
|
||||
impls.extend(expand_impl(defs, node));
|
||||
}
|
||||
for (name, symbol) in &defs.tokens {
|
||||
impls.extend(expand_token_impl(name, symbol));
|
||||
}
|
||||
|
||||
file::write(
|
||||
DEBUG_SRC,
|
||||
TESTS_DEBUG_SRC,
|
||||
quote! {
|
||||
use super::{Lite, RefCast};
|
||||
// False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
|
||||
#![allow(repr_transparent_external_private_fields)]
|
||||
|
||||
#![allow(clippy::match_wildcard_for_single_variants)]
|
||||
|
||||
use super::{Lite, Present};
|
||||
use ref_cast::RefCast;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
#impls
|
||||
|
@ -1,12 +1,11 @@
|
||||
use crate::workspace_path;
|
||||
use anyhow::Result;
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
use serde_derive::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 syn_cargo_toml = workspace_path::get("Cargo.toml");
|
||||
let manifest = fs::read_to_string(syn_cargo_toml)?;
|
||||
let parsed: Manifest = toml::from_str(&manifest)?;
|
||||
Ok(parsed.package.version)
|
||||
|
@ -6,7 +6,7 @@ use quote::{format_ident, quote};
|
||||
use syn::Index;
|
||||
use syn_codegen::{Data, Definitions, Features, Node, Type};
|
||||
|
||||
const VISIT_SRC: &str = "../src/gen/visit.rs";
|
||||
const VISIT_SRC: &str = "src/gen/visit.rs";
|
||||
|
||||
fn simple_visit(item: &str, name: &Operand) -> TokenStream {
|
||||
let ident = gen::under_name(item);
|
||||
@ -51,20 +51,17 @@ fn visit(
|
||||
let name = name.ref_tokens();
|
||||
Some(quote! {
|
||||
for el in Punctuated::pairs(#name) {
|
||||
let (it, p) = el.into_tuple();
|
||||
let it = el.value();
|
||||
#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();
|
||||
let name = name.ref_tokens();
|
||||
Some(quote! {
|
||||
if let Some(it) = &#name {
|
||||
if let Some(it) = #name {
|
||||
#val;
|
||||
}
|
||||
})
|
||||
@ -81,25 +78,6 @@ fn visit(
|
||||
}
|
||||
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
|
||||
@ -112,7 +90,7 @@ fn visit(
|
||||
Some(res)
|
||||
}
|
||||
Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
|
||||
Type::Ext(_) | Type::Std(_) => None,
|
||||
Type::Ext(_) | Type::Std(_) | Type::Token(_) | Type::Group(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +102,11 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
let mut visit_impl = TokenStream::new();
|
||||
|
||||
match &s.data {
|
||||
Data::Enum(variants) if variants.is_empty() => {
|
||||
visit_impl.extend(quote! {
|
||||
match *node {}
|
||||
});
|
||||
}
|
||||
Data::Enum(variants) => {
|
||||
let mut visit_variants = TokenStream::new();
|
||||
|
||||
@ -163,33 +146,17 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
|
||||
let nonexhaustive = if s.exhaustive {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => 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 id = Ident::new(field, Span::call_site());
|
||||
let ref_toks = Owned(quote!(node.#id));
|
||||
let visit_field = visit(&ty, &s.features, defs, &ref_toks)
|
||||
let visit_field = visit(ty, &s.features, defs, &ref_toks)
|
||||
.unwrap_or_else(|| noop_visit(&ref_toks));
|
||||
visit_impl.extend(quote! {
|
||||
#visit_field;
|
||||
@ -234,9 +201,8 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
VISIT_SRC,
|
||||
quote! {
|
||||
#![allow(unused_variables)]
|
||||
#![allow(clippy::needless_pass_by_ref_mut)]
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::gen::helper::visit::*;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::*;
|
||||
@ -253,8 +219,6 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
/// See the [module documentation] for details.
|
||||
///
|
||||
/// [module documentation]: self
|
||||
///
|
||||
/// *This trait is available only if Syn is built with the `"visit"` feature.*
|
||||
pub trait Visit<'ast> {
|
||||
#traits
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use quote::{format_ident, quote};
|
||||
use syn::Index;
|
||||
use syn_codegen::{Data, Definitions, Features, Node, Type};
|
||||
|
||||
const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
|
||||
const VISIT_MUT_SRC: &str = "src/gen/visit_mut.rs";
|
||||
|
||||
fn simple_visit(item: &str, name: &Operand) -> TokenStream {
|
||||
let ident = gen::under_name(item);
|
||||
@ -50,21 +50,18 @@ fn visit(
|
||||
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();
|
||||
for mut el in Punctuated::pairs_mut(#name) {
|
||||
let it = el.value_mut();
|
||||
#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();
|
||||
let name = name.ref_mut_tokens();
|
||||
Some(quote! {
|
||||
if let Some(it) = &mut #name {
|
||||
if let Some(it) = #name {
|
||||
#val;
|
||||
}
|
||||
})
|
||||
@ -81,25 +78,6 @@ fn visit(
|
||||
}
|
||||
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
|
||||
@ -112,7 +90,7 @@ fn visit(
|
||||
Some(res)
|
||||
}
|
||||
Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
|
||||
Type::Ext(_) | Type::Std(_) => None,
|
||||
Type::Ext(_) | Type::Std(_) | Type::Token(_) | Type::Group(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +102,11 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
let mut visit_mut_impl = TokenStream::new();
|
||||
|
||||
match &s.data {
|
||||
Data::Enum(variants) if variants.is_empty() => {
|
||||
visit_mut_impl.extend(quote! {
|
||||
match *node {}
|
||||
});
|
||||
}
|
||||
Data::Enum(variants) => {
|
||||
let mut visit_mut_variants = TokenStream::new();
|
||||
|
||||
@ -163,33 +146,17 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
|
||||
let nonexhaustive = if s.exhaustive {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => 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 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)
|
||||
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;
|
||||
@ -230,9 +197,8 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
VISIT_MUT_SRC,
|
||||
quote! {
|
||||
#![allow(unused_variables)]
|
||||
#![allow(clippy::needless_pass_by_ref_mut)]
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::gen::helper::visit_mut::*;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::*;
|
||||
@ -250,8 +216,6 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
/// See the [module documentation] for details.
|
||||
///
|
||||
/// [module documentation]: self
|
||||
///
|
||||
/// *This trait is available only if Syn is built with the `"visit-mut"` feature.*
|
||||
pub trait VisitMut {
|
||||
#traits
|
||||
}
|
||||
|
8
codegen/src/workspace_path.rs
Normal file
8
codegen/src/workspace_path.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn get(relative_to_workspace_root: impl AsRef<Path>) -> PathBuf {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
assert!(path.pop());
|
||||
path.push(relative_to_workspace_root);
|
||||
path
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
name = "syn-dev"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
@ -14,9 +14,9 @@ path = "main.rs"
|
||||
name = "syn-dev"
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
quote = "1"
|
||||
|
||||
[dependencies.syn]
|
||||
path = ".."
|
||||
default-features = false
|
||||
features = ["parsing", "full", "extra-traits", "proc-macro"]
|
||||
features = ["extra-traits", "full", "parsing", "proc-macro"]
|
||||
path = ".."
|
||||
|
@ -2,14 +2,14 @@
|
||||
name = "dump-syntax"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
colored = "2"
|
||||
proc-macro2 = { version = "1.0", features = ["span-locations"] }
|
||||
proc-macro2 = { version = "1", features = ["span-locations"] }
|
||||
|
||||
[dependencies.syn]
|
||||
path = "../.."
|
||||
default-features = false
|
||||
features = ["parsing", "full", "extra-traits"]
|
||||
features = ["extra-traits", "full", "parsing"]
|
||||
path = "../.."
|
||||
|
@ -13,7 +13,7 @@
|
||||
//! attrs: [
|
||||
//! Attribute {
|
||||
//! pound_token: Pound,
|
||||
//! style: Inner(
|
||||
//! style: AttrStyle::Inner(
|
||||
//! ...
|
||||
//! }
|
||||
|
||||
@ -55,14 +55,14 @@ impl Display for Error {
|
||||
|
||||
fn main() {
|
||||
if let Err(error) = try_main() {
|
||||
_ = writeln!(io::stderr(), "{}", error);
|
||||
let _ = writeln!(io::stderr(), "{}", error);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_main() -> Result<(), Error> {
|
||||
let mut args = env::args_os();
|
||||
_ = args.next(); // executable name
|
||||
let _ = args.next(); // executable name
|
||||
|
||||
let filepath = match (args.next(), args.next()) {
|
||||
(Some(arg), None) => PathBuf::from(arg),
|
||||
@ -99,11 +99,7 @@ fn render_location(
|
||||
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) {
|
||||
let code_line = match start.line.checked_sub(1).and_then(|n| code.lines().nth(n)) {
|
||||
Some(line) => line,
|
||||
None => return render_fallback(formatter, err),
|
||||
};
|
||||
@ -138,7 +134,10 @@ fn render_location(
|
||||
label = start.line.to_string().blue().bold(),
|
||||
code = code_line.trim_end(),
|
||||
offset = " ".repeat(start.column),
|
||||
underline = "^".repeat(end.column - start.column).red().bold(),
|
||||
underline = "^"
|
||||
.repeat(end.column.saturating_sub(start.column).max(1))
|
||||
.red()
|
||||
.bold(),
|
||||
message = err.to_string().red(),
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "heapsize_example"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "heapsize"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
|
@ -2,13 +2,13 @@
|
||||
name = "heapsize_derive"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { path = "../../.." }
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "lazy-static-example"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
|
@ -2,13 +2,13 @@
|
||||
name = "lazy_static"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0", features = ["nightly"] }
|
||||
quote = "1.0"
|
||||
proc-macro2 = { version = "1", features = ["nightly"] }
|
||||
quote = "1"
|
||||
syn = { path = "../../../", features = ["full"] }
|
||||
|
@ -42,7 +42,7 @@ 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
|
||||
[`Fold`]: https://docs.rs/syn/2.0/syn/fold/trait.Fold.html
|
||||
|
||||
```rust
|
||||
// Before
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "trace-var-example"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
|
@ -2,13 +2,13 @@
|
||||
name = "trace-var"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0", features = ["nightly"] }
|
||||
quote = "1.0"
|
||||
syn = { path = "../../../", features = ["full", "fold"] }
|
||||
proc-macro2 = { version = "1", features = ["nightly"] }
|
||||
quote = "1"
|
||||
syn = { path = "../../../", features = ["fold", "full"] }
|
||||
|
@ -4,7 +4,7 @@ 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};
|
||||
use syn::{parse_macro_input, parse_quote, BinOp, Expr, Ident, ItemFn, Local, Pat, Stmt, Token};
|
||||
|
||||
/// Parses a list of variable names separated by commas.
|
||||
///
|
||||
@ -84,7 +84,7 @@ impl Args {
|
||||
/// 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 init = self.fold_expr(*init.unwrap().expr);
|
||||
let ident = match pat {
|
||||
Pat::Ident(ref p) => &p.ident,
|
||||
_ => unreachable!(),
|
||||
@ -122,11 +122,11 @@ impl Fold for Args {
|
||||
Expr::Assign(fold::fold_expr_assign(self, e))
|
||||
}
|
||||
}
|
||||
Expr::AssignOp(e) => {
|
||||
Expr::Binary(e) if is_assign_op(e.op) => {
|
||||
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))
|
||||
Expr::Binary(fold::fold_expr_binary(self, e))
|
||||
}
|
||||
}
|
||||
_ => fold::fold_expr(self, e),
|
||||
@ -147,6 +147,22 @@ impl Fold for Args {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_assign_op(op: BinOp) -> bool {
|
||||
match op {
|
||||
BinOp::AddAssign(_)
|
||||
| BinOp::SubAssign(_)
|
||||
| BinOp::MulAssign(_)
|
||||
| BinOp::DivAssign(_)
|
||||
| BinOp::RemAssign(_)
|
||||
| BinOp::BitXorAssign(_)
|
||||
| BinOp::BitAndAssign(_)
|
||||
| BinOp::BitOrAssign(_)
|
||||
| BinOp::ShlAssign(_)
|
||||
| BinOp::ShrAssign(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attribute to print the value of the given variables each time they are
|
||||
/// reassigned.
|
||||
///
|
||||
|
1
fuzz/.gitignore
vendored
1
fuzz/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
artifacts/
|
||||
corpus/
|
||||
coverage/
|
||||
target/
|
||||
|
@ -10,9 +10,12 @@ cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
proc-macro2 = "1"
|
||||
proc-macro2 = "1.0.52"
|
||||
syn = { path = "..", default-features = false, features = ["full", "parsing"] }
|
||||
|
||||
[features]
|
||||
span-locations = ["proc-macro2/span-locations"]
|
||||
|
||||
[[bin]]
|
||||
name = "create_token_buffer"
|
||||
path = "fuzz_targets/create_token_buffer.rs"
|
||||
|
@ -12,7 +12,7 @@ fn immediate_fail(_input: ParseStream) -> syn::Result<()> {
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if data.len() < 300 {
|
||||
if let Ok(string) = str::from_utf8(data) {
|
||||
_ = immediate_fail.parse_str(string);
|
||||
let _ = immediate_fail.parse_str(string);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ use std::str;
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if data.len() < 300 {
|
||||
if let Ok(string) = str::from_utf8(data) {
|
||||
_ = syn::parse_file(string);
|
||||
let _ = syn::parse_file(string);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,22 +1,29 @@
|
||||
[package]
|
||||
name = "syn-codegen"
|
||||
version = "0.3.0" # also update html_root_url
|
||||
version = "0.4.1" # also update html_root_url
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
categories = ["development-tools::procedural-macro-helpers"]
|
||||
description = "Syntax tree describing Syn's syntax tree"
|
||||
documentation = "https://docs.rs/syn-codegen"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
keywords = ["syn"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/syn"
|
||||
|
||||
[dependencies]
|
||||
indexmap = { version = "1.0", features = ["serde-1"] }
|
||||
semver = { version = "1.0", features = ["serde"] }
|
||||
serde = { version = "1.0.88", features = ["derive"] }
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
semver = { version = "1", features = ["serde"] }
|
||||
serde = "1.0.88"
|
||||
serde_derive = "1.0.88"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0"
|
||||
serde_json = "1"
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[workspace]
|
||||
|
@ -13,9 +13,9 @@
|
||||
//! 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
|
||||
//! [`visit`]: https://docs.rs/syn/2.0/syn/visit/index.html
|
||||
//! [`visit_mut`]: https://docs.rs/syn/2.0/syn/visit_mut/index.html
|
||||
//! [`fold`]: https://docs.rs/syn/2.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
|
||||
@ -44,11 +44,12 @@
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/syn-codegen/0.2.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/syn-codegen/0.4.1")]
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
/// Top-level content of the syntax tree description.
|
||||
@ -96,7 +97,7 @@ pub struct Node {
|
||||
/// 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.
|
||||
/// This is an opaque type with no publicly accessible structure.
|
||||
Private,
|
||||
|
||||
/// This type is a braced struct with named fields.
|
||||
|
654
src/attr.rs
654
src/attr.rs
@ -1,19 +1,15 @@
|
||||
use super::*;
|
||||
use crate::punctuated::Punctuated;
|
||||
use proc_macro2::TokenStream;
|
||||
use std::iter;
|
||||
use std::slice;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseBuffer, ParseStream, Parser, Result};
|
||||
use crate::meta::{self, ParseNestedMeta};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::punctuated::Pair;
|
||||
use crate::parse::{Parse, ParseStream, Parser, Result};
|
||||
|
||||
ast_struct! {
|
||||
/// An attribute like `#[repr(transparent)]`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
/// An attribute, like `#[repr(transparent)]`.
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
@ -23,27 +19,52 @@ ast_struct! {
|
||||
///
|
||||
/// - 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 */`.
|
||||
///
|
||||
/// - Outer one-line doc comments like `/// Example`.
|
||||
///
|
||||
/// - Inner one-line doc comments like `//! Please file an issue`.
|
||||
///
|
||||
/// - Outer documentation blocks `/** Example */`.
|
||||
///
|
||||
/// - Inner documentation blocks `/*! 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
|
||||
/// is outer or inner.
|
||||
///
|
||||
/// Every attribute has a `path` that indicates the intended interpretation
|
||||
/// of the rest of the attribute's contents. The path and the optional
|
||||
/// additional contents are represented together in the `meta` field of the
|
||||
/// attribute in three possible varieties:
|
||||
///
|
||||
/// - Meta::Path — attributes whose information content conveys just a
|
||||
/// path, for example the `#[test]` attribute.
|
||||
///
|
||||
/// - Meta::List — attributes that carry arbitrary tokens after the
|
||||
/// path, surrounded by a delimiter (parenthesis, bracket, or brace). For
|
||||
/// example `#[derive(Copy)]` or `#[precondition(x < 5)]`.
|
||||
///
|
||||
/// - Meta::NameValue — attributes with an `=` sign after the path,
|
||||
/// followed by a Rust expression. For example `#[path =
|
||||
/// "sys/windows.rs"]`.
|
||||
///
|
||||
/// All doc comments are represented in the NameValue style with a path of
|
||||
/// "doc", 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
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// ~~~~~~Path
|
||||
/// ^^^^^^^^^^^^^^^^^^^Meta::List
|
||||
///
|
||||
/// #[path = "sys/windows.rs"]
|
||||
/// ~~~~Path
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue
|
||||
///
|
||||
/// #[test]
|
||||
/// ^^^^Meta::Path
|
||||
/// ```
|
||||
///
|
||||
/// <br>
|
||||
@ -93,18 +114,13 @@ ast_struct! {
|
||||
///
|
||||
/// 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.
|
||||
/// `Meta::List` variety of 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. Use [`parse_args()`] to parse those tokens into the expected
|
||||
/// data structure.
|
||||
///
|
||||
/// 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>
|
||||
@ -150,65 +166,49 @@ ast_struct! {
|
||||
pub pound_token: Token![#],
|
||||
pub style: AttrStyle,
|
||||
pub bracket_token: token::Bracket,
|
||||
pub path: Path,
|
||||
pub tokens: TokenStream,
|
||||
pub meta: Meta,
|
||||
}
|
||||
}
|
||||
|
||||
impl Attribute {
|
||||
/// Parses the content of the attribute, consisting of the path and tokens,
|
||||
/// as a [`Meta`] if possible.
|
||||
/// Returns the path that identifies the interpretation of this attribute.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(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())
|
||||
/// 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 {
|
||||
self.meta.path()
|
||||
}
|
||||
|
||||
/// Parse the arguments to the attribute as a syntax tree.
|
||||
///
|
||||
/// This is similar to `syn::parse2::<T>(attr.tokens)` except that:
|
||||
/// This is similar to pulling out the `TokenStream` from `Meta::List` and
|
||||
/// doing `syn::parse2::<T>(meta_list.tokens)`, except that using
|
||||
/// `parse_args` the error message has a more useful span when `tokens` is
|
||||
/// empty.
|
||||
///
|
||||
/// - 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.
|
||||
/// The surrounding delimiters are *not* included in the input to the
|
||||
/// parser.
|
||||
///
|
||||
/// ```text
|
||||
/// #[my_attr(value < 5)]
|
||||
/// ^^^^^^^^^ what gets parsed
|
||||
/// ```
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parse_quote, Attribute, Expr};
|
||||
///
|
||||
/// let attr: Attribute = parse_quote! {
|
||||
/// #[precondition(value < 5)]
|
||||
/// };
|
||||
///
|
||||
/// if attr.path().is_ident("precondition") {
|
||||
/// let precondition: Expr = attr.parse_args()?;
|
||||
/// // ...
|
||||
/// }
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args<T: Parse>(&self) -> Result<T> {
|
||||
@ -217,22 +217,182 @@ impl Attribute {
|
||||
|
||||
/// Parse the arguments to the attribute using the given parser.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parse_quote, Attribute};
|
||||
///
|
||||
/// let attr: Attribute = parse_quote! {
|
||||
/// #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]
|
||||
/// };
|
||||
///
|
||||
/// let bwom = attr.parse_args_with(Attribute::parse_outer)?;
|
||||
///
|
||||
/// // Attribute does not have a Parse impl, so we couldn't directly do:
|
||||
/// // let bwom: Attribute = attr.parse_args()?;
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(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())
|
||||
match &self.meta {
|
||||
Meta::Path(path) => Err(crate::error::new2(
|
||||
path.segments.first().unwrap().ident.span(),
|
||||
path.segments.last().unwrap().ident.span(),
|
||||
format!(
|
||||
"expected attribute arguments in parentheses: {}[{}(...)]",
|
||||
parsing::DisplayAttrStyle(&self.style),
|
||||
parsing::DisplayPath(path),
|
||||
),
|
||||
)),
|
||||
Meta::NameValue(meta) => Err(Error::new(
|
||||
meta.eq_token.span,
|
||||
format_args!(
|
||||
"expected parentheses: {}[{}(...)]",
|
||||
parsing::DisplayAttrStyle(&self.style),
|
||||
parsing::DisplayPath(&meta.path),
|
||||
),
|
||||
)),
|
||||
Meta::List(meta) => meta.parse_args_with(parser),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the arguments to the attribute, expecting it to follow the
|
||||
/// conventional structure used by most of Rust's built-in attributes.
|
||||
///
|
||||
/// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference
|
||||
/// explains the convention in more detail. Not all attributes follow this
|
||||
/// convention, so [`parse_args()`][Self::parse_args] is available if you
|
||||
/// need to parse arbitrarily goofy attribute syntax.
|
||||
///
|
||||
/// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute
|
||||
/// syntax.
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};
|
||||
///
|
||||
/// let input: ItemStruct = parse_quote! {
|
||||
/// #[repr(C, align(4))]
|
||||
/// pub struct MyStruct(u16, u32);
|
||||
/// };
|
||||
///
|
||||
/// let mut repr_c = false;
|
||||
/// let mut repr_transparent = false;
|
||||
/// let mut repr_align = None::<usize>;
|
||||
/// let mut repr_packed = None::<usize>;
|
||||
/// for attr in &input.attrs {
|
||||
/// if attr.path().is_ident("repr") {
|
||||
/// attr.parse_nested_meta(|meta| {
|
||||
/// // #[repr(C)]
|
||||
/// if meta.path.is_ident("C") {
|
||||
/// repr_c = true;
|
||||
/// return Ok(());
|
||||
/// }
|
||||
///
|
||||
/// // #[repr(transparent)]
|
||||
/// if meta.path.is_ident("transparent") {
|
||||
/// repr_transparent = true;
|
||||
/// return Ok(());
|
||||
/// }
|
||||
///
|
||||
/// // #[repr(align(N))]
|
||||
/// if meta.path.is_ident("align") {
|
||||
/// let content;
|
||||
/// parenthesized!(content in meta.input);
|
||||
/// let lit: LitInt = content.parse()?;
|
||||
/// let n: usize = lit.base10_parse()?;
|
||||
/// repr_align = Some(n);
|
||||
/// return Ok(());
|
||||
/// }
|
||||
///
|
||||
/// // #[repr(packed)] or #[repr(packed(N))], omitted N means 1
|
||||
/// if meta.path.is_ident("packed") {
|
||||
/// if meta.input.peek(token::Paren) {
|
||||
/// let content;
|
||||
/// parenthesized!(content in meta.input);
|
||||
/// let lit: LitInt = content.parse()?;
|
||||
/// let n: usize = lit.base10_parse()?;
|
||||
/// repr_packed = Some(n);
|
||||
/// } else {
|
||||
/// repr_packed = Some(1);
|
||||
/// }
|
||||
/// return Ok(());
|
||||
/// }
|
||||
///
|
||||
/// Err(meta.error("unrecognized repr"))
|
||||
/// })?;
|
||||
/// }
|
||||
/// }
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
///
|
||||
/// # Alternatives
|
||||
///
|
||||
/// In some cases, for attributes which have nested layers of structured
|
||||
/// content, the following less flexible approach might be more convenient:
|
||||
///
|
||||
/// ```
|
||||
/// # use syn::{parse_quote, ItemStruct};
|
||||
/// #
|
||||
/// # let input: ItemStruct = parse_quote! {
|
||||
/// # #[repr(C, align(4))]
|
||||
/// # pub struct MyStruct(u16, u32);
|
||||
/// # };
|
||||
/// #
|
||||
/// use syn::punctuated::Punctuated;
|
||||
/// use syn::{parenthesized, token, Error, LitInt, Meta, Token};
|
||||
///
|
||||
/// let mut repr_c = false;
|
||||
/// let mut repr_transparent = false;
|
||||
/// let mut repr_align = None::<usize>;
|
||||
/// let mut repr_packed = None::<usize>;
|
||||
/// for attr in &input.attrs {
|
||||
/// if attr.path().is_ident("repr") {
|
||||
/// let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
|
||||
/// for meta in nested {
|
||||
/// match meta {
|
||||
/// // #[repr(C)]
|
||||
/// Meta::Path(path) if path.is_ident("C") => {
|
||||
/// repr_c = true;
|
||||
/// }
|
||||
///
|
||||
/// // #[repr(align(N))]
|
||||
/// Meta::List(meta) if meta.path.is_ident("align") => {
|
||||
/// let lit: LitInt = meta.parse_args()?;
|
||||
/// let n: usize = lit.base10_parse()?;
|
||||
/// repr_align = Some(n);
|
||||
/// }
|
||||
///
|
||||
/// /* ... */
|
||||
///
|
||||
/// _ => {
|
||||
/// return Err(Error::new_spanned(meta, "unrecognized repr"));
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_nested_meta(
|
||||
&self,
|
||||
logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.parse_args_with(meta::parser(logic))
|
||||
}
|
||||
|
||||
/// Parses zero or more outer attributes from the stream.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
/// # Example
|
||||
///
|
||||
/// See
|
||||
/// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
|
||||
@ -245,8 +405,10 @@ impl Attribute {
|
||||
|
||||
/// Parses zero or more inner attributes from the stream.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
/// # Example
|
||||
///
|
||||
/// See
|
||||
/// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
|
||||
@ -256,65 +418,10 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn expected_parentheses(attr: &Attribute) -> String {
|
||||
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();
|
||||
}
|
||||
|
||||
format!("{}[{}(...)]", style, path)
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn enter_args<'a>(attr: &Attribute, input: ParseStream<'a>) -> Result<ParseBuffer<'a>> {
|
||||
if input.is_empty() {
|
||||
let expected = expected_parentheses(attr);
|
||||
let msg = format!("expected attribute arguments in parentheses: {}", expected);
|
||||
return Err(crate::error::new2(
|
||||
attr.pound_token.span,
|
||||
attr.bracket_token.span,
|
||||
msg,
|
||||
));
|
||||
} else if input.peek(Token![=]) {
|
||||
let expected = expected_parentheses(attr);
|
||||
let msg = format!("expected parentheses: {}", expected);
|
||||
return Err(input.error(msg));
|
||||
};
|
||||
|
||||
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 only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Outer attributes
|
||||
///
|
||||
/// - `#[repr(transparent)]`
|
||||
@ -336,9 +443,6 @@ ast_enum! {
|
||||
ast_enum_of_structs! {
|
||||
/// Content of a compile-time structured attribute.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// ## Path
|
||||
///
|
||||
/// A meta path is like the `test` in `#[test]`.
|
||||
@ -371,32 +475,26 @@ ast_enum_of_structs! {
|
||||
|
||||
ast_struct! {
|
||||
/// A structured list within an attribute, like `derive(Copy, Clone)`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct MetaList {
|
||||
pub path: Path,
|
||||
pub paren_token: token::Paren,
|
||||
pub nested: Punctuated<NestedMeta, Token![,]>,
|
||||
pub delimiter: MacroDelimiter,
|
||||
pub tokens: TokenStream,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A name-value pair within an attribute, like `feature = "nightly"`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct MetaNameValue {
|
||||
pub path: Path,
|
||||
pub eq_token: Token![=],
|
||||
pub lit: Lit,
|
||||
pub value: Expr,
|
||||
}
|
||||
}
|
||||
|
||||
impl Meta {
|
||||
/// Returns the identifier that begins this structured meta item.
|
||||
/// Returns the path 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"]`.
|
||||
@ -407,63 +505,84 @@ impl Meta {
|
||||
Meta::NameValue(meta) => &meta.path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum_of_structs! {
|
||||
/// Element of a compile-time attribute list.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum NestedMeta {
|
||||
/// A structured meta item, like the `Copy` in `#[derive(Copy)]` which
|
||||
/// would be a nested `Meta::Path`.
|
||||
Meta(Meta),
|
||||
/// Error if this is a `Meta::List` or `Meta::NameValue`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_path_only(&self) -> Result<&Path> {
|
||||
let error_span = match self {
|
||||
Meta::Path(path) => return Ok(path),
|
||||
Meta::List(meta) => meta.delimiter.span().open(),
|
||||
Meta::NameValue(meta) => meta.eq_token.span,
|
||||
};
|
||||
Err(Error::new(error_span, "unexpected token in attribute"))
|
||||
}
|
||||
|
||||
/// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`.
|
||||
Lit(Lit),
|
||||
/// Error if this is a `Meta::Path` or `Meta::NameValue`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_list(&self) -> Result<&MetaList> {
|
||||
match self {
|
||||
Meta::List(meta) => Ok(meta),
|
||||
Meta::Path(path) => Err(crate::error::new2(
|
||||
path.segments.first().unwrap().ident.span(),
|
||||
path.segments.last().unwrap().ident.span(),
|
||||
format!(
|
||||
"expected attribute arguments in parentheses: `{}(...)`",
|
||||
parsing::DisplayPath(path),
|
||||
),
|
||||
)),
|
||||
Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Error if this is a `Meta::Path` or `Meta::List`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_name_value(&self) -> Result<&MetaNameValue> {
|
||||
match self {
|
||||
Meta::NameValue(meta) => Ok(meta),
|
||||
Meta::Path(path) => Err(crate::error::new2(
|
||||
path.segments.first().unwrap().ident.span(),
|
||||
path.segments.last().unwrap().ident.span(),
|
||||
format!(
|
||||
"expected a value for this attribute: `{} = ...`",
|
||||
parsing::DisplayPath(path),
|
||||
),
|
||||
)),
|
||||
Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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()
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub type AttributeArgs = Vec<NestedMeta>;
|
||||
impl MetaList {
|
||||
/// See [`Attribute::parse_args`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args<T: Parse>(&self) -> Result<T> {
|
||||
self.parse_args_with(T::parse)
|
||||
}
|
||||
|
||||
pub trait FilterAttrs<'a> {
|
||||
/// See [`Attribute::parse_args_with`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
||||
let scope = self.delimiter.span().close();
|
||||
crate::parse::parse_scoped(parser, scope, self.tokens.clone())
|
||||
}
|
||||
|
||||
/// See [`Attribute::parse_nested_meta`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_nested_meta(
|
||||
&self,
|
||||
logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.parse_args_with(meta::parser(logic))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait FilterAttrs<'a> {
|
||||
type Ret: Iterator<Item = &'a Attribute>;
|
||||
|
||||
fn outer(self) -> Self::Ret;
|
||||
@ -495,69 +614,43 @@ impl<'a> FilterAttrs<'a> for &'a [Attribute] {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::ext::IdentExt;
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
pub fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
|
||||
pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
|
||||
while input.peek(Token![#]) && input.peek2(Token![!]) {
|
||||
attrs.push(input.call(parsing::single_parse_inner)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
|
||||
pub(crate) 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()?,
|
||||
meta: content.parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
|
||||
pub(crate) 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()?,
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
},
|
||||
meta: content.parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Meta {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(parse_meta_path)?;
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
parse_meta_after_path(path, input)
|
||||
}
|
||||
}
|
||||
@ -565,7 +658,7 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for MetaList {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(parse_meta_path)?;
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
parse_meta_list_after_path(path, input)
|
||||
}
|
||||
}
|
||||
@ -573,28 +666,13 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for MetaNameValue {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(parse_meta_path)?;
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
parse_meta_name_value_after_path(path, input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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.peek(Token![::]) && input.peek3(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) {
|
||||
pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
|
||||
if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
|
||||
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)
|
||||
@ -604,21 +682,60 @@ pub mod parsing {
|
||||
}
|
||||
|
||||
fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
|
||||
let content;
|
||||
let (delimiter, tokens) = mac::parse_delimiter(input)?;
|
||||
Ok(MetaList {
|
||||
path,
|
||||
paren_token: parenthesized!(content in input),
|
||||
nested: content.parse_terminated(NestedMeta::parse)?,
|
||||
delimiter,
|
||||
tokens,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
|
||||
let eq_token: Token![=] = input.parse()?;
|
||||
let ahead = input.fork();
|
||||
let lit: Option<Lit> = ahead.parse()?;
|
||||
let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
|
||||
input.advance_to(&ahead);
|
||||
Expr::Lit(ExprLit {
|
||||
attrs: Vec::new(),
|
||||
lit,
|
||||
})
|
||||
} else if input.peek(Token![#]) && input.peek2(token::Bracket) {
|
||||
return Err(input.error("unexpected attribute inside of attribute"));
|
||||
} else {
|
||||
input.parse()?
|
||||
};
|
||||
Ok(MetaNameValue {
|
||||
path,
|
||||
eq_token: input.parse()?,
|
||||
lit: input.parse()?,
|
||||
eq_token,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
|
||||
|
||||
impl<'a> Display for DisplayAttrStyle<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(match self.0 {
|
||||
AttrStyle::Outer => "#",
|
||||
AttrStyle::Inner(_) => "#!",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct DisplayPath<'a>(pub &'a Path);
|
||||
|
||||
impl<'a> Display for DisplayPath<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (i, segment) in self.0.segments.iter().enumerate() {
|
||||
if i > 0 || self.0.leading_colon.is_some() {
|
||||
formatter.write_str("::")?;
|
||||
}
|
||||
write!(formatter, "{}", segment.ident)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
@ -635,8 +752,7 @@ mod printing {
|
||||
b.to_tokens(tokens);
|
||||
}
|
||||
self.bracket_token.surround(tokens, |tokens| {
|
||||
self.path.to_tokens(tokens);
|
||||
self.tokens.to_tokens(tokens);
|
||||
self.meta.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -645,9 +761,7 @@ mod printing {
|
||||
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);
|
||||
});
|
||||
self.delimiter.surround(tokens, self.tokens.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,7 +770,7 @@ mod printing {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.path.to_tokens(tokens);
|
||||
self.eq_token.to_tokens(tokens);
|
||||
self.lit.to_tokens(tokens);
|
||||
self.value.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
// See include!("await.rs") in token.rs.
|
||||
export_token_macro! {[await]}
|
@ -1,16 +1,16 @@
|
||||
use std::ops::{AddAssign, MulAssign};
|
||||
|
||||
// For implementing base10_digits() accessor on LitInt.
|
||||
pub struct BigInt {
|
||||
pub(crate) struct BigInt {
|
||||
digits: Vec<u8>,
|
||||
}
|
||||
|
||||
impl BigInt {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
BigInt { digits: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
pub(crate) fn to_string(&self) -> String {
|
||||
let mut repr = String::with_capacity(self.digits.len());
|
||||
|
||||
let mut has_nonzero = false;
|
||||
|
100
src/buffer.rs
100
src/buffer.rs
@ -1,18 +1,12 @@
|
||||
//! A stably addressed token buffer supporting efficient traversal based on a
|
||||
//! cheaply copyable cursor.
|
||||
//!
|
||||
//! *This module is available only 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 crate::Lifetime;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
|
||||
use std::cmp::Ordering;
|
||||
use std::marker::PhantomData;
|
||||
@ -33,8 +27,6 @@ enum 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 only if Syn is built with the `"parsing"` feature.*
|
||||
pub struct TokenBuffer {
|
||||
// NOTE: Do not implement clone on this - while the current design could be
|
||||
// cloned, other designs which could be desirable may not be cloneable.
|
||||
@ -63,14 +55,9 @@ impl TokenBuffer {
|
||||
|
||||
/// Creates a `TokenBuffer` containing all the tokens from the input
|
||||
/// `proc_macro::TokenStream`.
|
||||
///
|
||||
/// *This method is available only 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) -> Self {
|
||||
#[cfg(feature = "proc-macro")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
|
||||
pub fn new(stream: proc_macro::TokenStream) -> Self {
|
||||
Self::new2(stream.into())
|
||||
}
|
||||
|
||||
@ -101,11 +88,6 @@ impl TokenBuffer {
|
||||
///
|
||||
/// 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 only if Syn is built with the `"parsing"` feature.*
|
||||
pub struct Cursor<'a> {
|
||||
// The current entry which the `Cursor` is pointing at.
|
||||
ptr: *const Entry,
|
||||
@ -146,11 +128,11 @@ impl<'a> Cursor<'a> {
|
||||
// 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(_) = *ptr {
|
||||
while let Entry::End(_) = unsafe { &*ptr } {
|
||||
if ptr == scope {
|
||||
break;
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
ptr = unsafe { ptr.add(1) };
|
||||
}
|
||||
|
||||
Cursor {
|
||||
@ -172,7 +154,7 @@ impl<'a> Cursor<'a> {
|
||||
/// If the cursor is looking at an `Entry::Group`, the bumped cursor will
|
||||
/// point at the first token in the group (with the same scope end).
|
||||
unsafe fn bump_ignore_group(self) -> Cursor<'a> {
|
||||
Cursor::create(self.ptr.offset(1), self.scope)
|
||||
unsafe { Cursor::create(self.ptr.offset(1), self.scope) }
|
||||
}
|
||||
|
||||
/// While the cursor is looking at a `None`-delimited group, move it to look
|
||||
@ -199,7 +181,7 @@ impl<'a> Cursor<'a> {
|
||||
|
||||
/// 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>)> {
|
||||
pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, DelimSpan, 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.
|
||||
@ -209,16 +191,40 @@ impl<'a> Cursor<'a> {
|
||||
|
||||
if let Entry::Group(group, end_offset) = self.entry() {
|
||||
if group.delimiter() == delim {
|
||||
let span = group.delim_span();
|
||||
let end_of_group = unsafe { self.ptr.add(*end_offset) };
|
||||
let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) };
|
||||
let after_group = unsafe { Cursor::create(end_of_group, self.scope) };
|
||||
return Some((inside_of_group, group.span(), after_group));
|
||||
return Some((inside_of_group, span, after_group));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn any_group(self) -> Option<(Cursor<'a>, Delimiter, DelimSpan, Cursor<'a>)> {
|
||||
if let Entry::Group(group, end_offset) = self.entry() {
|
||||
let delimiter = group.delimiter();
|
||||
let span = group.delim_span();
|
||||
let end_of_group = unsafe { self.ptr.add(*end_offset) };
|
||||
let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) };
|
||||
let after_group = unsafe { Cursor::create(end_of_group, self.scope) };
|
||||
return Some((inside_of_group, delimiter, span, after_group));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn any_group_token(self) -> Option<(Group, Cursor<'a>)> {
|
||||
if let Entry::Group(group, end_offset) = self.entry() {
|
||||
let end_of_group = unsafe { self.ptr.add(*end_offset) };
|
||||
let after_group = unsafe { Cursor::create(end_of_group, self.scope) };
|
||||
return Some((group.clone(), after_group));
|
||||
}
|
||||
|
||||
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>)> {
|
||||
@ -313,6 +319,33 @@ impl<'a> Cursor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `Span` of the token immediately prior to the position of
|
||||
/// this cursor, or of the current token if there is no previous one.
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
pub(crate) fn prev_span(mut self) -> Span {
|
||||
if start_of_buffer(self) < self.ptr {
|
||||
self.ptr = unsafe { self.ptr.offset(-1) };
|
||||
if let Entry::End(_) = self.entry() {
|
||||
// Locate the matching Group begin token.
|
||||
let mut depth = 1;
|
||||
loop {
|
||||
self.ptr = unsafe { self.ptr.offset(-1) };
|
||||
match self.entry() {
|
||||
Entry::Group(group, _) => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
return group.span();
|
||||
}
|
||||
}
|
||||
Entry::End(_) => depth += 1,
|
||||
Entry::Literal(_) | Entry::Ident(_) | Entry::Punct(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.span()
|
||||
}
|
||||
|
||||
/// Skip over the next token without cloning it. Returns `None` if this
|
||||
/// cursor points to eof.
|
||||
///
|
||||
@ -356,7 +389,7 @@ impl<'a> PartialEq for Cursor<'a> {
|
||||
impl<'a> PartialOrd for Cursor<'a> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
if same_buffer(*self, *other) {
|
||||
Some(self.ptr.cmp(&other.ptr))
|
||||
Some(cmp_assuming_same_buffer(*self, *other))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -368,17 +401,18 @@ pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
|
||||
}
|
||||
|
||||
pub(crate) fn same_buffer(a: Cursor, b: Cursor) -> bool {
|
||||
start_of_buffer(a) == start_of_buffer(b)
|
||||
}
|
||||
|
||||
fn start_of_buffer(cursor: Cursor) -> *const Entry {
|
||||
unsafe {
|
||||
match (&*a.scope, &*b.scope) {
|
||||
(Entry::End(a_offset), Entry::End(b_offset)) => {
|
||||
a.scope.offset(*a_offset) == b.scope.offset(*b_offset)
|
||||
}
|
||||
match &*cursor.scope {
|
||||
Entry::End(offset) => cursor.scope.offset(*offset),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
pub(crate) fn cmp_assuming_same_buffer(a: Cursor, b: Cursor) -> Ordering {
|
||||
a.ptr.cmp(&b.ptr)
|
||||
}
|
||||
|
@ -96,26 +96,28 @@ macro_rules! custom_keyword {
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_snake_case)]
|
||||
pub fn $ident<__S: $crate::__private::IntoSpans<[$crate::__private::Span; 1]>>(
|
||||
pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>(
|
||||
span: __S,
|
||||
) -> $ident {
|
||||
$ident {
|
||||
span: $crate::__private::IntoSpans::into_spans(span)[0],
|
||||
span: $crate::__private::IntoSpans::into_spans(span),
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::__private::Default for $ident {
|
||||
fn default() -> Self {
|
||||
$ident {
|
||||
span: $crate::__private::Span::call_site(),
|
||||
const _: () = {
|
||||
impl $crate::__private::Default for $ident {
|
||||
fn default() -> Self {
|
||||
$ident {
|
||||
span: $crate::__private::Span::call_site(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$crate::impl_parse_for_custom_keyword!($ident);
|
||||
$crate::impl_to_tokens_for_custom_keyword!($ident);
|
||||
$crate::impl_clone_for_custom_keyword!($ident);
|
||||
$crate::impl_extra_traits_for_custom_keyword!($ident);
|
||||
$crate::impl_parse_for_custom_keyword!($ident);
|
||||
$crate::impl_to_tokens_for_custom_keyword!($ident);
|
||||
$crate::impl_clone_for_custom_keyword!($ident);
|
||||
$crate::impl_extra_traits_for_custom_keyword!($ident);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -126,17 +128,17 @@ macro_rules! custom_keyword {
|
||||
macro_rules! impl_parse_for_custom_keyword {
|
||||
($ident:ident) => {
|
||||
// For peek.
|
||||
impl $crate::token::CustomToken for $ident {
|
||||
impl $crate::__private::CustomToken for $ident {
|
||||
fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool {
|
||||
if let $crate::__private::Some((ident, _rest)) = cursor.ident() {
|
||||
ident == stringify!($ident)
|
||||
ident == $crate::__private::stringify!($ident)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn display() -> &'static $crate::__private::str {
|
||||
concat!("`", stringify!($ident), "`")
|
||||
$crate::__private::concat!("`", $crate::__private::stringify!($ident), "`")
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,14 +146,14 @@ macro_rules! impl_parse_for_custom_keyword {
|
||||
fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
|
||||
input.step(|cursor| {
|
||||
if let $crate::__private::Some((ident, rest)) = cursor.ident() {
|
||||
if ident == stringify!($ident) {
|
||||
if ident == $crate::__private::stringify!($ident) {
|
||||
return $crate::__private::Ok(($ident { span: ident.span() }, rest));
|
||||
}
|
||||
}
|
||||
$crate::__private::Err(cursor.error(concat!(
|
||||
$crate::__private::Err(cursor.error($crate::__private::concat!(
|
||||
"expected `",
|
||||
stringify!($ident),
|
||||
"`"
|
||||
$crate::__private::stringify!($ident),
|
||||
"`",
|
||||
)))
|
||||
})
|
||||
}
|
||||
@ -175,7 +177,7 @@ macro_rules! impl_to_tokens_for_custom_keyword {
|
||||
($ident:ident) => {
|
||||
impl $crate::__private::ToTokens for $ident {
|
||||
fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) {
|
||||
let ident = $crate::Ident::new(stringify!($ident), self.span);
|
||||
let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span);
|
||||
$crate::__private::TokenStreamExt::append(tokens, ident);
|
||||
}
|
||||
}
|
||||
@ -222,10 +224,14 @@ macro_rules! impl_clone_for_custom_keyword {
|
||||
macro_rules! impl_extra_traits_for_custom_keyword {
|
||||
($ident:ident) => {
|
||||
impl $crate::__private::Debug for $ident {
|
||||
fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::fmt::Result {
|
||||
fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult {
|
||||
$crate::__private::Formatter::write_str(
|
||||
f,
|
||||
concat!("Keyword [", stringify!($ident), "]"),
|
||||
$crate::__private::concat!(
|
||||
"Keyword [",
|
||||
$crate::__private::stringify!($ident),
|
||||
"]",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -92,16 +92,18 @@ macro_rules! custom_punctuation {
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::__private::Default for $ident {
|
||||
fn default() -> Self {
|
||||
$ident($crate::__private::Span::call_site())
|
||||
const _: () = {
|
||||
impl $crate::__private::Default for $ident {
|
||||
fn default() -> Self {
|
||||
$ident($crate::__private::Span::call_site())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$crate::impl_parse_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_clone_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_parse_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_clone_for_custom_punctuation!($ident, $($tt)+);
|
||||
$crate::impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@ -111,20 +113,20 @@ macro_rules! custom_punctuation {
|
||||
#[macro_export]
|
||||
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, $crate::stringify_punct!($($tt)+))
|
||||
impl $crate::__private::CustomToken for $ident {
|
||||
fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool {
|
||||
$crate::__private::peek_punct(cursor, $crate::stringify_punct!($($tt)+))
|
||||
}
|
||||
|
||||
fn display() -> &'static $crate::__private::str {
|
||||
concat!("`", $crate::stringify_punct!($($tt)+), "`")
|
||||
$crate::__private::concat!("`", $crate::stringify_punct!($($tt)+), "`")
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::parse::Parse for $ident {
|
||||
fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
|
||||
let spans: $crate::custom_punctuation_repr!($($tt)+) =
|
||||
$crate::token::parsing::punct(input, $crate::stringify_punct!($($tt)+))?;
|
||||
$crate::__private::parse_punct(input, $crate::stringify_punct!($($tt)+))?;
|
||||
Ok($ident(spans))
|
||||
}
|
||||
}
|
||||
@ -147,7 +149,7 @@ macro_rules! impl_to_tokens_for_custom_punctuation {
|
||||
($ident:ident, $($tt:tt)+) => {
|
||||
impl $crate::__private::ToTokens for $ident {
|
||||
fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) {
|
||||
$crate::token::printing::punct($crate::stringify_punct!($($tt)+), &self.spans, tokens)
|
||||
$crate::__private::print_punct($crate::stringify_punct!($($tt)+), &self.spans, tokens)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -193,8 +195,8 @@ macro_rules! impl_clone_for_custom_punctuation {
|
||||
macro_rules! impl_extra_traits_for_custom_punctuation {
|
||||
($ident:ident, $($tt:tt)+) => {
|
||||
impl $crate::__private::Debug for $ident {
|
||||
fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::fmt::Result {
|
||||
$crate::__private::Formatter::write_str(f, stringify!($ident))
|
||||
fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult {
|
||||
$crate::__private::Formatter::write_str(f, $crate::__private::stringify!($ident))
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +297,6 @@ macro_rules! custom_punctuation_unexpected {
|
||||
#[macro_export]
|
||||
macro_rules! stringify_punct {
|
||||
($($tt:tt)+) => {
|
||||
concat!($(stringify!($tt)),+)
|
||||
$crate::__private::concat!($($crate::__private::stringify!($tt)),+)
|
||||
};
|
||||
}
|
||||
|
339
src/data.rs
339
src/data.rs
@ -3,12 +3,8 @@ use crate::punctuated::Punctuated;
|
||||
|
||||
ast_struct! {
|
||||
/// An enum variant.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Variant {
|
||||
/// Attributes tagged on the variant.
|
||||
pub attrs: Vec<Attribute>,
|
||||
|
||||
/// Name of the variant.
|
||||
@ -25,9 +21,6 @@ ast_struct! {
|
||||
ast_enum_of_structs! {
|
||||
/// Data stored within an enum variant or struct.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
@ -50,9 +43,6 @@ ast_enum_of_structs! {
|
||||
ast_struct! {
|
||||
/// Named fields of a struct or struct variant such as `Point { x: f64,
|
||||
/// y: f64 }`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct FieldsNamed {
|
||||
pub brace_token: token::Brace,
|
||||
@ -62,9 +52,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct FieldsUnnamed {
|
||||
pub paren_token: token::Paren,
|
||||
@ -147,17 +134,14 @@ impl<'a> IntoIterator for &'a mut Fields {
|
||||
|
||||
ast_struct! {
|
||||
/// A field of a struct or enum variant.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Field {
|
||||
/// Attributes tagged on the field.
|
||||
pub attrs: Vec<Attribute>,
|
||||
|
||||
/// Visibility of the field.
|
||||
pub vis: Visibility,
|
||||
|
||||
pub mutability: FieldMutability,
|
||||
|
||||
/// Name of the field, if any.
|
||||
///
|
||||
/// Fields of tuple structs have no names.
|
||||
@ -165,82 +149,16 @@ ast_struct! {
|
||||
|
||||
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 only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct VisPublic {
|
||||
pub pub_token: Token![pub],
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A crate-level visibility: `crate`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
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 {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::ext::IdentExt;
|
||||
use crate::parse::discouraged::Speculative;
|
||||
use crate::ext::IdentExt as _;
|
||||
#[cfg(not(feature = "full"))]
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
@ -258,7 +176,20 @@ pub mod parsing {
|
||||
};
|
||||
let discriminant = if input.peek(Token![=]) {
|
||||
let eq_token: Token![=] = input.parse()?;
|
||||
#[cfg(feature = "full")]
|
||||
let discriminant: Expr = input.parse()?;
|
||||
#[cfg(not(feature = "full"))]
|
||||
let discriminant = {
|
||||
let begin = input.fork();
|
||||
let ahead = input.fork();
|
||||
let mut discriminant: Result<Expr> = ahead.parse();
|
||||
if discriminant.is_ok() {
|
||||
input.advance_to(&ahead);
|
||||
} else if scan_lenient_discriminant(input).is_ok() {
|
||||
discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input)));
|
||||
}
|
||||
discriminant?
|
||||
};
|
||||
Some((eq_token, discriminant))
|
||||
} else {
|
||||
None
|
||||
@ -272,13 +203,86 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
pub(crate) fn scan_lenient_discriminant(input: ParseStream) -> Result<()> {
|
||||
use proc_macro2::Delimiter::{self, Brace, Bracket, Parenthesis};
|
||||
|
||||
let consume = |delimiter: Delimiter| {
|
||||
Result::unwrap(input.step(|cursor| match cursor.group(delimiter) {
|
||||
Some((_inside, _span, rest)) => Ok((true, rest)),
|
||||
None => Ok((false, *cursor)),
|
||||
}))
|
||||
};
|
||||
|
||||
macro_rules! consume {
|
||||
[$token:tt] => {
|
||||
input.parse::<Option<Token![$token]>>().unwrap().is_some()
|
||||
};
|
||||
}
|
||||
|
||||
let mut initial = true;
|
||||
let mut depth = 0usize;
|
||||
loop {
|
||||
if initial {
|
||||
if consume![&] {
|
||||
input.parse::<Option<Token![mut]>>()?;
|
||||
} else if consume![if] || consume![match] || consume![while] {
|
||||
depth += 1;
|
||||
} else if input.parse::<Option<Lit>>()?.is_some()
|
||||
|| (consume(Brace) || consume(Bracket) || consume(Parenthesis))
|
||||
|| (consume![async] || consume![const] || consume![loop] || consume![unsafe])
|
||||
&& (consume(Brace) || break)
|
||||
{
|
||||
initial = false;
|
||||
} else if consume![let] {
|
||||
while !consume![=] {
|
||||
if !((consume![|] || consume![ref] || consume![mut] || consume![@])
|
||||
|| (consume![!] || input.parse::<Option<Lit>>()?.is_some())
|
||||
|| (consume![..=] || consume![..] || consume![&] || consume![_])
|
||||
|| (consume(Brace) || consume(Bracket) || consume(Parenthesis)))
|
||||
{
|
||||
path::parsing::qpath(input, true)?;
|
||||
}
|
||||
}
|
||||
} else if input.parse::<Option<Lifetime>>()?.is_some() && !consume![:] {
|
||||
break;
|
||||
} else if input.parse::<UnOp>().is_err() {
|
||||
path::parsing::qpath(input, true)?;
|
||||
initial = consume![!] || depth == 0 && input.peek(token::Brace);
|
||||
}
|
||||
} else if input.is_empty() || input.peek(Token![,]) {
|
||||
return Ok(());
|
||||
} else if depth > 0 && consume(Brace) {
|
||||
if consume![else] && !consume(Brace) {
|
||||
initial = consume![if] || break;
|
||||
} else {
|
||||
depth -= 1;
|
||||
}
|
||||
} else if input.parse::<BinOp>().is_ok() || (consume![..] | consume![=]) {
|
||||
initial = true;
|
||||
} else if consume![.] {
|
||||
if input.parse::<Option<LitFloat>>()?.is_none()
|
||||
&& (input.parse::<Member>()?.is_named() && consume![::])
|
||||
{
|
||||
AngleBracketedGenericArguments::do_parse(None, input)?;
|
||||
}
|
||||
} else if consume![as] {
|
||||
input.parse::<Type>()?;
|
||||
} else if !(consume(Brace) || consume(Bracket) || consume(Parenthesis)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Err(input.error("unsupported expression"))
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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)?,
|
||||
named: content.parse_terminated(Field::parse_named, Token![,])?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -289,7 +293,7 @@ pub mod parsing {
|
||||
let content;
|
||||
Ok(FieldsUnnamed {
|
||||
paren_token: parenthesized!(content in input),
|
||||
unnamed: content.parse_terminated(Field::parse_unnamed)?,
|
||||
unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -298,16 +302,37 @@ pub mod parsing {
|
||||
/// Parses a named (braced struct) field.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_named(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let vis: Visibility = input.parse()?;
|
||||
|
||||
let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]);
|
||||
let ident = if unnamed_field {
|
||||
input.call(Ident::parse_any)
|
||||
} else {
|
||||
input.parse()
|
||||
}?;
|
||||
|
||||
let colon_token: Token![:] = input.parse()?;
|
||||
|
||||
let ty: Type = if unnamed_field
|
||||
&& (input.peek(Token![struct])
|
||||
|| input.peek(Token![union]) && input.peek2(token::Brace))
|
||||
{
|
||||
let begin = input.fork();
|
||||
input.call(Ident::parse_any)?;
|
||||
input.parse::<FieldsNamed>()?;
|
||||
Type::Verbatim(verbatim::between(&begin, input))
|
||||
} else {
|
||||
input.parse()?
|
||||
};
|
||||
|
||||
Ok(Field {
|
||||
attrs: input.call(Attribute::parse_outer)?,
|
||||
vis: input.parse()?,
|
||||
ident: Some(if input.peek(Token![_]) {
|
||||
input.call(Ident::parse_any)
|
||||
} else {
|
||||
input.parse()
|
||||
}?),
|
||||
colon_token: Some(input.parse()?),
|
||||
ty: input.parse()?,
|
||||
attrs,
|
||||
vis,
|
||||
mutability: FieldMutability::None,
|
||||
ident: Some(ident),
|
||||
colon_token: Some(colon_token),
|
||||
ty,
|
||||
})
|
||||
}
|
||||
|
||||
@ -317,100 +342,13 @@ pub mod parsing {
|
||||
Ok(Field {
|
||||
attrs: input.call(Attribute::parse_outer)?,
|
||||
vis: input.parse()?,
|
||||
mutability: FieldMutability::None,
|
||||
ident: None,
|
||||
colon_token: None,
|
||||
ty: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Visibility {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
// Recognize an empty None-delimited group, as produced by a $:vis
|
||||
// matcher that matched no tokens.
|
||||
if input.peek(token::Group) {
|
||||
let ahead = input.fork();
|
||||
let group = crate::group::parse_group(&ahead)?;
|
||||
if group.content.is_empty() {
|
||||
input.advance_to(&ahead);
|
||||
return Ok(Visibility::Inherited);
|
||||
}
|
||||
}
|
||||
|
||||
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 = "full")]
|
||||
pub(crate) fn is_some(&self) -> bool {
|
||||
match self {
|
||||
Visibility::Inherited => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
@ -463,31 +401,4 @@ mod printing {
|
||||
self.ty.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for VisPublic {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.pub_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for VisCrate {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.crate_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,32 +3,19 @@ use crate::punctuated::Punctuated;
|
||||
|
||||
ast_struct! {
|
||||
/// Data structure sent to a `proc_macro_derive` macro.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
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! {
|
||||
ast_enum! {
|
||||
/// The storage of a struct, enum or union data structure.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
@ -36,24 +23,14 @@ ast_enum_of_structs! {
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
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 only if Syn is built with the `"derive"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
pub struct DataStruct {
|
||||
pub struct_token: Token![struct],
|
||||
@ -64,9 +41,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An enum input to a `proc_macro_derive` macro.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
pub struct DataEnum {
|
||||
pub enum_token: Token![enum],
|
||||
@ -77,9 +51,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An untagged union input to a `proc_macro_derive` macro.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
pub struct DataUnion {
|
||||
pub union_token: Token![union],
|
||||
@ -88,7 +59,7 @@ ast_struct! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
@ -161,7 +132,7 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_struct(
|
||||
pub(crate) fn data_struct(
|
||||
input: ParseStream,
|
||||
) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
|
||||
let mut lookahead = input.lookahead1();
|
||||
@ -197,7 +168,7 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_enum(
|
||||
pub(crate) fn data_enum(
|
||||
input: ParseStream,
|
||||
) -> Result<(
|
||||
Option<WhereClause>,
|
||||
@ -208,12 +179,12 @@ pub mod parsing {
|
||||
|
||||
let content;
|
||||
let brace = braced!(content in input);
|
||||
let variants = content.parse_terminated(Variant::parse)?;
|
||||
let variants = content.parse_terminated(Variant::parse, Token![,])?;
|
||||
|
||||
Ok((where_clause, brace, variants))
|
||||
}
|
||||
|
||||
pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
|
||||
pub(crate) fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
|
||||
let where_clause = input.parse()?;
|
||||
let fields = input.parse()?;
|
||||
Ok((where_clause, fields))
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Extensions to the parsing API with niche applicability.
|
||||
|
||||
use super::*;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
|
||||
/// Extensions to the `ParseStream` API to support speculative parsing.
|
||||
pub trait Speculative {
|
||||
@ -192,3 +193,27 @@ impl<'a> Speculative for ParseBuffer<'a> {
|
||||
.set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) });
|
||||
}
|
||||
}
|
||||
|
||||
/// Extensions to the `ParseStream` API to support manipulating invisible
|
||||
/// delimiters the same as if they were visible.
|
||||
pub trait AnyDelimiter {
|
||||
/// Returns the delimiter, the span of the delimiter token, and the nested
|
||||
/// contents for further parsing.
|
||||
fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)>;
|
||||
}
|
||||
|
||||
impl<'a> AnyDelimiter for ParseBuffer<'a> {
|
||||
fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)> {
|
||||
self.step(|cursor| {
|
||||
if let Some((content, delimiter, span, rest)) = cursor.any_group() {
|
||||
let scope = crate::buffer::close_span_of_group(*cursor);
|
||||
let nested = crate::parse::advance_step_cursor(cursor, content);
|
||||
let unexpected = crate::parse::get_unexpected(self);
|
||||
let content = crate::parse::new_parse_buffer(scope, nested, unexpected);
|
||||
Ok(((delimiter, span, content), rest))
|
||||
} else {
|
||||
Err(cursor.error("expected any delimiter"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
113
src/error.rs
113
src/error.rs
@ -7,7 +7,6 @@ use proc_macro2::{
|
||||
#[cfg(feature = "printing")]
|
||||
use quote::ToTokens;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::iter::FromIterator;
|
||||
use std::slice;
|
||||
use std::vec;
|
||||
|
||||
@ -34,18 +33,34 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||
/// # extern crate proc_macro;
|
||||
/// #
|
||||
/// use proc_macro::TokenStream;
|
||||
/// use syn::{parse_macro_input, AttributeArgs, ItemFn};
|
||||
/// use syn::parse::{Parse, ParseStream, Result};
|
||||
/// use syn::{parse_macro_input, 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 args = parse_macro_input!(args as MyAttrArgs);
|
||||
/// let input = parse_macro_input!(input as ItemFn);
|
||||
///
|
||||
/// /* ... */
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
///
|
||||
/// struct MyAttrArgs {
|
||||
/// # _k: [(); { stringify! {
|
||||
/// ...
|
||||
/// # }; 0 }]
|
||||
/// }
|
||||
///
|
||||
/// impl Parse for MyAttrArgs {
|
||||
/// fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// # stringify! {
|
||||
/// ...
|
||||
/// # };
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// For errors that arise later than the initial parsing stage, the
|
||||
@ -89,14 +104,21 @@ pub struct Error {
|
||||
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>,
|
||||
// errors to be Send and Sync to play nicely with ecosystem crates for error
|
||||
// handling, so pin the span we're given to its original thread and assume
|
||||
// it is Span::call_site if accessed from any other thread.
|
||||
span: ThreadBound<SpanRange>,
|
||||
message: String,
|
||||
}
|
||||
|
||||
// Cannot use std::ops::Range<Span> because that does not implement Copy,
|
||||
// whereas ThreadBound<T> requires a Copy impl as a way to ensure no Drop impls
|
||||
// are involved.
|
||||
struct SpanRange {
|
||||
start: Span,
|
||||
end: Span,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
struct _Test
|
||||
where
|
||||
@ -139,8 +161,10 @@ impl Error {
|
||||
fn new(span: Span, message: String) -> Error {
|
||||
Error {
|
||||
messages: vec![ErrorMessage {
|
||||
start_span: ThreadBound::new(span),
|
||||
end_span: ThreadBound::new(span),
|
||||
span: ThreadBound::new(SpanRange {
|
||||
start: span,
|
||||
end: span,
|
||||
}),
|
||||
message,
|
||||
}],
|
||||
}
|
||||
@ -161,6 +185,7 @@ impl Error {
|
||||
/// When in doubt it's recommended to stick to `Error::new` (or
|
||||
/// `ParseStream::error`)!
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self {
|
||||
return new_spanned(tokens.into_token_stream(), message.to_string());
|
||||
|
||||
@ -170,8 +195,7 @@ impl Error {
|
||||
let end = iter.last().map_or(start, |t| t.span());
|
||||
Error {
|
||||
messages: vec![ErrorMessage {
|
||||
start_span: ThreadBound::new(start),
|
||||
end_span: ThreadBound::new(end),
|
||||
span: ThreadBound::new(SpanRange { start, end }),
|
||||
message,
|
||||
}],
|
||||
}
|
||||
@ -184,11 +208,7 @@ impl Error {
|
||||
/// 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() {
|
||||
let SpanRange { start, end } = match self.messages[0].span.get() {
|
||||
Some(span) => *span,
|
||||
None => return Span::call_site(),
|
||||
};
|
||||
@ -254,15 +274,34 @@ impl Error {
|
||||
|
||||
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);
|
||||
let (start, end) = match self.span.get() {
|
||||
Some(range) => (range.start, range.end),
|
||||
None => (Span::call_site(), Span::call_site()),
|
||||
};
|
||||
|
||||
// compile_error!($message)
|
||||
// ::core::compile_error!($message)
|
||||
TokenStream::from_iter(vec![
|
||||
TokenTree::Punct({
|
||||
let mut punct = Punct::new(':', Spacing::Joint);
|
||||
punct.set_span(start);
|
||||
punct
|
||||
}),
|
||||
TokenTree::Punct({
|
||||
let mut punct = Punct::new(':', Spacing::Alone);
|
||||
punct.set_span(start);
|
||||
punct
|
||||
}),
|
||||
TokenTree::Ident(Ident::new("core", start)),
|
||||
TokenTree::Punct({
|
||||
let mut punct = Punct::new(':', Spacing::Joint);
|
||||
punct.set_span(start);
|
||||
punct
|
||||
}),
|
||||
TokenTree::Punct({
|
||||
let mut punct = Punct::new(':', Spacing::Alone);
|
||||
punct.set_span(start);
|
||||
punct
|
||||
}),
|
||||
TokenTree::Ident(Ident::new("compile_error", start)),
|
||||
TokenTree::Punct({
|
||||
let mut punct = Punct::new('!', Spacing::Alone);
|
||||
@ -285,7 +324,7 @@ impl ErrorMessage {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
|
||||
pub(crate) 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 {
|
||||
@ -295,14 +334,13 @@ pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error {
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
|
||||
pub fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
|
||||
pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error {
|
||||
return new2(start, end, message.to_string());
|
||||
|
||||
fn new2(start: Span, end: Span, message: String) -> Error {
|
||||
Error {
|
||||
messages: vec![ErrorMessage {
|
||||
start_span: ThreadBound::new(start),
|
||||
end_span: ThreadBound::new(end),
|
||||
span: ThreadBound::new(SpanRange { start, end }),
|
||||
message,
|
||||
}],
|
||||
}
|
||||
@ -347,25 +385,26 @@ impl Clone for Error {
|
||||
|
||||
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),
|
||||
span: self.span,
|
||||
message: self.message.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for SpanRange {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for SpanRange {}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl From<LexError> for Error {
|
||||
fn from(err: LexError) -> Self {
|
||||
Error::new(err.span(), "lex error")
|
||||
Error::new(err.span(), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,39 +1,73 @@
|
||||
#[doc(hidden)]
|
||||
pub use std::clone::Clone;
|
||||
#[doc(hidden)]
|
||||
pub use std::cmp::{Eq, PartialEq};
|
||||
#[doc(hidden)]
|
||||
pub use std::concat;
|
||||
#[doc(hidden)]
|
||||
pub use std::default::Default;
|
||||
pub use std::fmt::{self, Debug, Formatter};
|
||||
#[doc(hidden)]
|
||||
pub use std::fmt::Debug;
|
||||
#[doc(hidden)]
|
||||
pub use std::hash::{Hash, Hasher};
|
||||
#[doc(hidden)]
|
||||
pub use std::marker::Copy;
|
||||
#[doc(hidden)]
|
||||
pub use std::option::Option::{None, Some};
|
||||
#[doc(hidden)]
|
||||
pub use std::result::Result::{Err, Ok};
|
||||
#[doc(hidden)]
|
||||
pub use std::stringify;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type Formatter<'a> = std::fmt::Formatter<'a>;
|
||||
#[doc(hidden)]
|
||||
pub type FmtResult = std::fmt::Result;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type bool = std::primitive::bool;
|
||||
#[doc(hidden)]
|
||||
pub type str = std::primitive::str;
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
pub extern crate quote;
|
||||
#[doc(hidden)]
|
||||
pub use quote;
|
||||
|
||||
pub use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
#[doc(hidden)]
|
||||
pub type Span = proc_macro2::Span;
|
||||
#[doc(hidden)]
|
||||
pub type TokenStream2 = proc_macro2::TokenStream;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::group::{parse_braces, parse_brackets, parse_parens};
|
||||
|
||||
#[doc(hidden)]
|
||||
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(all(feature = "parsing", feature = "printing"))]
|
||||
#[doc(hidden)]
|
||||
pub use crate::parse_quote::parse as parse_quote;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::token::parsing::{peek_punct, punct as parse_punct};
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::token::printing::punct as print_punct;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::token::private::CustomToken;
|
||||
|
||||
#[cfg(feature = "proc-macro")]
|
||||
#[doc(hidden)]
|
||||
pub type TokenStream = proc_macro::TokenStream;
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[doc(hidden)]
|
||||
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;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct private(pub(crate) ());
|
||||
|
1972
src/expr.rs
1972
src/expr.rs
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,4 @@
|
||||
//! Extension traits to provide parsing methods on foreign types.
|
||||
//!
|
||||
//! *This module is available only if Syn is built with the `"parsing"` feature.*
|
||||
|
||||
use crate::buffer::Cursor;
|
||||
use crate::parse::Peek;
|
||||
@ -13,8 +11,6 @@ use proc_macro2::Ident;
|
||||
///
|
||||
/// 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 only if Syn is built with the `"parsing"` feature.*
|
||||
pub trait IdentExt: Sized + private::Sealed {
|
||||
/// Parses any identifier including keywords.
|
||||
///
|
||||
@ -96,8 +92,8 @@ impl IdentExt for Ident {
|
||||
|
||||
fn unraw(&self) -> Ident {
|
||||
let string = self.to_string();
|
||||
if string.starts_with("r#") {
|
||||
Ident::new(&string[2..], self.span())
|
||||
if let Some(string) = string.strip_prefix("r#") {
|
||||
Ident::new(string, self.span())
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use super::*;
|
||||
ast_struct! {
|
||||
/// A complete file of Rust source code.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"full"` feature.*
|
||||
/// Typically `File` objects are created with [`parse_file`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -86,7 +86,7 @@ ast_struct! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
|
432
src/gen/clone.rs
generated
432
src/gen/clone.rs
generated
@ -41,6 +41,30 @@ impl Clone for Arm {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for AssocConst {
|
||||
fn clone(&self) -> Self {
|
||||
AssocConst {
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
value: self.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for AssocType {
|
||||
fn clone(&self) -> Self {
|
||||
AssocType {
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for AttrStyle {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
@ -57,8 +81,7 @@ impl Clone for Attribute {
|
||||
pound_token: self.pound_token.clone(),
|
||||
style: self.style.clone(),
|
||||
bracket_token: self.bracket_token.clone(),
|
||||
path: self.path.clone(),
|
||||
tokens: self.tokens.clone(),
|
||||
meta: self.meta.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,6 +98,18 @@ impl Clone for BareFnArg {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for BareVariadic {
|
||||
fn clone(&self) -> Self {
|
||||
BareVariadic {
|
||||
attrs: self.attrs.clone(),
|
||||
name: self.name.clone(),
|
||||
dots: self.dots.clone(),
|
||||
comma: self.comma.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for BinOp {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
@ -83,17 +118,6 @@ impl Clone for BinOp {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Binding {
|
||||
fn clone(&self) -> Self {
|
||||
Binding {
|
||||
ident: self.ident.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Block {
|
||||
@ -137,6 +161,7 @@ impl Clone for Constraint {
|
||||
fn clone(&self) -> Self {
|
||||
Constraint {
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
bounds: self.bounds.clone(),
|
||||
}
|
||||
@ -208,8 +233,6 @@ impl Clone for Expr {
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Assign(v0) => Expr::Assign(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::AssignOp(v0) => Expr::AssignOp(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Async(v0) => Expr::Async(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Await(v0) => Expr::Await(v0.clone()),
|
||||
@ -217,45 +240,42 @@ impl Clone for Expr {
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Block(v0) => Expr::Block(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Box(v0) => Expr::Box(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Break(v0) => Expr::Break(v0.clone()),
|
||||
Expr::Call(v0) => Expr::Call(v0.clone()),
|
||||
Expr::Cast(v0) => Expr::Cast(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Closure(v0) => Expr::Closure(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Const(v0) => Expr::Const(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Continue(v0) => Expr::Continue(v0.clone()),
|
||||
Expr::Field(v0) => Expr::Field(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::ForLoop(v0) => Expr::ForLoop(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Group(v0) => Expr::Group(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::If(v0) => Expr::If(v0.clone()),
|
||||
Expr::Index(v0) => Expr::Index(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Infer(v0) => Expr::Infer(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Let(v0) => Expr::Let(v0.clone()),
|
||||
Expr::Lit(v0) => Expr::Lit(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Loop(v0) => Expr::Loop(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Macro(v0) => Expr::Macro(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Match(v0) => Expr::Match(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::MethodCall(v0) => Expr::MethodCall(v0.clone()),
|
||||
Expr::Paren(v0) => Expr::Paren(v0.clone()),
|
||||
Expr::Path(v0) => Expr::Path(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Range(v0) => Expr::Range(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Reference(v0) => Expr::Reference(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Repeat(v0) => Expr::Repeat(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Return(v0) => Expr::Return(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Struct(v0) => Expr::Struct(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Try(v0) => Expr::Try(v0.clone()),
|
||||
@ -263,8 +283,6 @@ impl Clone for Expr {
|
||||
Expr::TryBlock(v0) => Expr::TryBlock(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Tuple(v0) => Expr::Tuple(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Type(v0) => Expr::Type(v0.clone()),
|
||||
Expr::Unary(v0) => Expr::Unary(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Unsafe(v0) => Expr::Unsafe(v0.clone()),
|
||||
@ -273,7 +291,7 @@ impl Clone for Expr {
|
||||
Expr::While(v0) => Expr::While(v0.clone()),
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Yield(v0) => Expr::Yield(v0.clone()),
|
||||
#[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -303,18 +321,6 @@ impl Clone for ExprAssign {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprAssignOp {
|
||||
fn clone(&self) -> Self {
|
||||
ExprAssignOp {
|
||||
attrs: self.attrs.clone(),
|
||||
left: self.left.clone(),
|
||||
op: self.op.clone(),
|
||||
right: self.right.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprAsync {
|
||||
fn clone(&self) -> Self {
|
||||
ExprAsync {
|
||||
@ -362,17 +368,6 @@ impl Clone for ExprBlock {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprBox {
|
||||
fn clone(&self) -> Self {
|
||||
ExprBox {
|
||||
attrs: self.attrs.clone(),
|
||||
box_token: self.box_token.clone(),
|
||||
expr: self.expr.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprBreak {
|
||||
fn clone(&self) -> Self {
|
||||
ExprBreak {
|
||||
@ -413,6 +408,8 @@ impl Clone for ExprClosure {
|
||||
fn clone(&self) -> Self {
|
||||
ExprClosure {
|
||||
attrs: self.attrs.clone(),
|
||||
lifetimes: self.lifetimes.clone(),
|
||||
constness: self.constness.clone(),
|
||||
movability: self.movability.clone(),
|
||||
asyncness: self.asyncness.clone(),
|
||||
capture: self.capture.clone(),
|
||||
@ -426,6 +423,17 @@ impl Clone for ExprClosure {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprConst {
|
||||
fn clone(&self) -> Self {
|
||||
ExprConst {
|
||||
attrs: self.attrs.clone(),
|
||||
const_token: self.const_token.clone(),
|
||||
block: self.block.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprContinue {
|
||||
fn clone(&self) -> Self {
|
||||
ExprContinue {
|
||||
@ -462,7 +470,7 @@ impl Clone for ExprForLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprGroup {
|
||||
fn clone(&self) -> Self {
|
||||
@ -500,6 +508,16 @@ impl Clone for ExprIndex {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprInfer {
|
||||
fn clone(&self) -> Self {
|
||||
ExprInfer {
|
||||
attrs: self.attrs.clone(),
|
||||
underscore_token: self.underscore_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprLet {
|
||||
fn clone(&self) -> Self {
|
||||
ExprLet {
|
||||
@ -533,7 +551,7 @@ impl Clone for ExprLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprMacro {
|
||||
fn clone(&self) -> Self {
|
||||
@ -556,7 +574,7 @@ impl Clone for ExprMatch {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprMethodCall {
|
||||
fn clone(&self) -> Self {
|
||||
@ -599,20 +617,19 @@ impl Clone for ExprRange {
|
||||
fn clone(&self) -> Self {
|
||||
ExprRange {
|
||||
attrs: self.attrs.clone(),
|
||||
from: self.from.clone(),
|
||||
start: self.start.clone(),
|
||||
limits: self.limits.clone(),
|
||||
to: self.to.clone(),
|
||||
end: self.end.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprReference {
|
||||
fn clone(&self) -> Self {
|
||||
ExprReference {
|
||||
attrs: self.attrs.clone(),
|
||||
and_token: self.and_token.clone(),
|
||||
raw: self.raw.clone(),
|
||||
mutability: self.mutability.clone(),
|
||||
expr: self.expr.clone(),
|
||||
}
|
||||
@ -642,12 +659,13 @@ impl Clone for ExprReturn {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprStruct {
|
||||
fn clone(&self) -> Self {
|
||||
ExprStruct {
|
||||
attrs: self.attrs.clone(),
|
||||
qself: self.qself.clone(),
|
||||
path: self.path.clone(),
|
||||
brace_token: self.brace_token.clone(),
|
||||
fields: self.fields.clone(),
|
||||
@ -689,18 +707,6 @@ impl Clone for ExprTuple {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprType {
|
||||
fn clone(&self) -> Self {
|
||||
ExprType {
|
||||
attrs: self.attrs.clone(),
|
||||
expr: self.expr.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ExprUnary {
|
||||
@ -754,12 +760,22 @@ impl Clone for Field {
|
||||
Field {
|
||||
attrs: self.attrs.clone(),
|
||||
vis: self.vis.clone(),
|
||||
mutability: self.mutability.clone(),
|
||||
ident: self.ident.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for FieldMutability {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
FieldMutability::None => FieldMutability::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for FieldPat {
|
||||
@ -772,7 +788,7 @@ impl Clone for FieldPat {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for FieldValue {
|
||||
fn clone(&self) -> Self {
|
||||
@ -846,8 +862,6 @@ impl Clone for ForeignItem {
|
||||
ForeignItem::Type(v0) => ForeignItem::Type(v0.clone()),
|
||||
ForeignItem::Macro(v0) => ForeignItem::Macro(v0.clone()),
|
||||
ForeignItem::Verbatim(v0) => ForeignItem::Verbatim(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -899,6 +913,7 @@ impl Clone for ForeignItemType {
|
||||
vis: self.vis.clone(),
|
||||
type_token: self.type_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
semi_token: self.semi_token.clone(),
|
||||
}
|
||||
}
|
||||
@ -911,28 +926,19 @@ impl Clone for GenericArgument {
|
||||
GenericArgument::Lifetime(v0) => GenericArgument::Lifetime(v0.clone()),
|
||||
GenericArgument::Type(v0) => GenericArgument::Type(v0.clone()),
|
||||
GenericArgument::Const(v0) => GenericArgument::Const(v0.clone()),
|
||||
GenericArgument::Binding(v0) => GenericArgument::Binding(v0.clone()),
|
||||
GenericArgument::AssocType(v0) => GenericArgument::AssocType(v0.clone()),
|
||||
GenericArgument::AssocConst(v0) => GenericArgument::AssocConst(v0.clone()),
|
||||
GenericArgument::Constraint(v0) => GenericArgument::Constraint(v0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for GenericMethodArgument {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
GenericMethodArgument::Type(v0) => GenericMethodArgument::Type(v0.clone()),
|
||||
GenericMethodArgument::Const(v0) => GenericMethodArgument::Const(v0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for GenericParam {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
GenericParam::Type(v0) => GenericParam::Type(v0.clone()),
|
||||
GenericParam::Lifetime(v0) => GenericParam::Lifetime(v0.clone()),
|
||||
GenericParam::Type(v0) => GenericParam::Type(v0.clone()),
|
||||
GenericParam::Const(v0) => GenericParam::Const(v0.clone()),
|
||||
}
|
||||
}
|
||||
@ -955,12 +961,10 @@ impl Clone for ImplItem {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
ImplItem::Const(v0) => ImplItem::Const(v0.clone()),
|
||||
ImplItem::Method(v0) => ImplItem::Method(v0.clone()),
|
||||
ImplItem::Fn(v0) => ImplItem::Fn(v0.clone()),
|
||||
ImplItem::Type(v0) => ImplItem::Type(v0.clone()),
|
||||
ImplItem::Macro(v0) => ImplItem::Macro(v0.clone()),
|
||||
ImplItem::Verbatim(v0) => ImplItem::Verbatim(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -974,6 +978,7 @@ impl Clone for ImplItemConst {
|
||||
defaultness: self.defaultness.clone(),
|
||||
const_token: self.const_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
@ -984,6 +989,19 @@ impl Clone for ImplItemConst {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ImplItemFn {
|
||||
fn clone(&self) -> Self {
|
||||
ImplItemFn {
|
||||
attrs: self.attrs.clone(),
|
||||
vis: self.vis.clone(),
|
||||
defaultness: self.defaultness.clone(),
|
||||
sig: self.sig.clone(),
|
||||
block: self.block.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ImplItemMacro {
|
||||
fn clone(&self) -> Self {
|
||||
ImplItemMacro {
|
||||
@ -995,19 +1013,6 @@ impl Clone for ImplItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ImplItemMethod {
|
||||
fn clone(&self) -> Self {
|
||||
ImplItemMethod {
|
||||
attrs: self.attrs.clone(),
|
||||
vis: self.vis.clone(),
|
||||
defaultness: self.defaultness.clone(),
|
||||
sig: self.sig.clone(),
|
||||
block: self.block.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ImplItemType {
|
||||
fn clone(&self) -> Self {
|
||||
ImplItemType {
|
||||
@ -1023,6 +1028,13 @@ impl Clone for ImplItemType {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ImplRestriction {
|
||||
fn clone(&self) -> Self {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Index {
|
||||
@ -1045,7 +1057,6 @@ impl Clone for Item {
|
||||
Item::ForeignMod(v0) => Item::ForeignMod(v0.clone()),
|
||||
Item::Impl(v0) => Item::Impl(v0.clone()),
|
||||
Item::Macro(v0) => Item::Macro(v0.clone()),
|
||||
Item::Macro2(v0) => Item::Macro2(v0.clone()),
|
||||
Item::Mod(v0) => Item::Mod(v0.clone()),
|
||||
Item::Static(v0) => Item::Static(v0.clone()),
|
||||
Item::Struct(v0) => Item::Struct(v0.clone()),
|
||||
@ -1055,8 +1066,6 @@ impl Clone for Item {
|
||||
Item::Union(v0) => Item::Union(v0.clone()),
|
||||
Item::Use(v0) => Item::Use(v0.clone()),
|
||||
Item::Verbatim(v0) => Item::Verbatim(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1069,6 +1078,7 @@ impl Clone for ItemConst {
|
||||
vis: self.vis.clone(),
|
||||
const_token: self.const_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
@ -1125,6 +1135,7 @@ impl Clone for ItemForeignMod {
|
||||
fn clone(&self) -> Self {
|
||||
ItemForeignMod {
|
||||
attrs: self.attrs.clone(),
|
||||
unsafety: self.unsafety.clone(),
|
||||
abi: self.abi.clone(),
|
||||
brace_token: self.brace_token.clone(),
|
||||
items: self.items.clone(),
|
||||
@ -1162,24 +1173,12 @@ impl Clone for ItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ItemMacro2 {
|
||||
fn clone(&self) -> Self {
|
||||
ItemMacro2 {
|
||||
attrs: self.attrs.clone(),
|
||||
vis: self.vis.clone(),
|
||||
macro_token: self.macro_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
rules: self.rules.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for ItemMod {
|
||||
fn clone(&self) -> Self {
|
||||
ItemMod {
|
||||
attrs: self.attrs.clone(),
|
||||
vis: self.vis.clone(),
|
||||
unsafety: self.unsafety.clone(),
|
||||
mod_token: self.mod_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
content: self.content.clone(),
|
||||
@ -1229,6 +1228,7 @@ impl Clone for ItemTrait {
|
||||
vis: self.vis.clone(),
|
||||
unsafety: self.unsafety.clone(),
|
||||
auto_token: self.auto_token.clone(),
|
||||
restriction: self.restriction.clone(),
|
||||
trait_token: self.trait_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
@ -1311,9 +1311,9 @@ impl Clone for Label {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for LifetimeDef {
|
||||
impl Clone for LifetimeParam {
|
||||
fn clone(&self) -> Self {
|
||||
LifetimeDef {
|
||||
LifetimeParam {
|
||||
attrs: self.attrs.clone(),
|
||||
lifetime: self.lifetime.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
@ -1358,6 +1358,17 @@ impl Clone for Local {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for LocalInit {
|
||||
fn clone(&self) -> Self {
|
||||
LocalInit {
|
||||
eq_token: self.eq_token.clone(),
|
||||
expr: self.expr.clone(),
|
||||
diverge: self.diverge.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Macro {
|
||||
@ -1408,8 +1419,8 @@ impl Clone for MetaList {
|
||||
fn clone(&self) -> Self {
|
||||
MetaList {
|
||||
path: self.path.clone(),
|
||||
paren_token: self.paren_token.clone(),
|
||||
nested: self.nested.clone(),
|
||||
delimiter: self.delimiter.clone(),
|
||||
tokens: self.tokens.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1420,29 +1431,7 @@ impl Clone for MetaNameValue {
|
||||
MetaNameValue {
|
||||
path: self.path.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
lit: self.lit.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for MethodTurbofish {
|
||||
fn clone(&self) -> Self {
|
||||
MethodTurbofish {
|
||||
colon2_token: self.colon2_token.clone(),
|
||||
lt_token: self.lt_token.clone(),
|
||||
args: self.args.clone(),
|
||||
gt_token: self.gt_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for NestedMeta {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
NestedMeta::Meta(v0) => NestedMeta::Meta(v0.clone()),
|
||||
NestedMeta::Lit(v0) => NestedMeta::Lit(v0.clone()),
|
||||
value: self.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1462,11 +1451,12 @@ impl Clone for ParenthesizedGenericArguments {
|
||||
impl Clone for Pat {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Pat::Box(v0) => Pat::Box(v0.clone()),
|
||||
Pat::Const(v0) => Pat::Const(v0.clone()),
|
||||
Pat::Ident(v0) => Pat::Ident(v0.clone()),
|
||||
Pat::Lit(v0) => Pat::Lit(v0.clone()),
|
||||
Pat::Macro(v0) => Pat::Macro(v0.clone()),
|
||||
Pat::Or(v0) => Pat::Or(v0.clone()),
|
||||
Pat::Paren(v0) => Pat::Paren(v0.clone()),
|
||||
Pat::Path(v0) => Pat::Path(v0.clone()),
|
||||
Pat::Range(v0) => Pat::Range(v0.clone()),
|
||||
Pat::Reference(v0) => Pat::Reference(v0.clone()),
|
||||
@ -1478,19 +1468,6 @@ impl Clone for Pat {
|
||||
Pat::Type(v0) => Pat::Type(v0.clone()),
|
||||
Pat::Verbatim(v0) => Pat::Verbatim(v0.clone()),
|
||||
Pat::Wild(v0) => Pat::Wild(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatBox {
|
||||
fn clone(&self) -> Self {
|
||||
PatBox {
|
||||
attrs: self.attrs.clone(),
|
||||
box_token: self.box_token.clone(),
|
||||
pat: self.pat.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1509,26 +1486,6 @@ impl Clone for PatIdent {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatLit {
|
||||
fn clone(&self) -> Self {
|
||||
PatLit {
|
||||
attrs: self.attrs.clone(),
|
||||
expr: self.expr.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatMacro {
|
||||
fn clone(&self) -> Self {
|
||||
PatMacro {
|
||||
attrs: self.attrs.clone(),
|
||||
mac: self.mac.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatOr {
|
||||
fn clone(&self) -> Self {
|
||||
PatOr {
|
||||
@ -1540,24 +1497,12 @@ impl Clone for PatOr {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatPath {
|
||||
impl Clone for PatParen {
|
||||
fn clone(&self) -> Self {
|
||||
PatPath {
|
||||
PatParen {
|
||||
attrs: self.attrs.clone(),
|
||||
qself: self.qself.clone(),
|
||||
path: self.path.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PatRange {
|
||||
fn clone(&self) -> Self {
|
||||
PatRange {
|
||||
attrs: self.attrs.clone(),
|
||||
lo: self.lo.clone(),
|
||||
limits: self.limits.clone(),
|
||||
hi: self.hi.clone(),
|
||||
paren_token: self.paren_token.clone(),
|
||||
pat: self.pat.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1600,10 +1545,11 @@ impl Clone for PatStruct {
|
||||
fn clone(&self) -> Self {
|
||||
PatStruct {
|
||||
attrs: self.attrs.clone(),
|
||||
qself: self.qself.clone(),
|
||||
path: self.path.clone(),
|
||||
brace_token: self.brace_token.clone(),
|
||||
fields: self.fields.clone(),
|
||||
dot2_token: self.dot2_token.clone(),
|
||||
rest: self.rest.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1624,8 +1570,10 @@ impl Clone for PatTupleStruct {
|
||||
fn clone(&self) -> Self {
|
||||
PatTupleStruct {
|
||||
attrs: self.attrs.clone(),
|
||||
qself: self.qself.clone(),
|
||||
path: self.path.clone(),
|
||||
pat: self.pat.clone(),
|
||||
paren_token: self.paren_token.clone(),
|
||||
elems: self.elems.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1686,17 +1634,6 @@ impl Clone for PathSegment {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PredicateEq {
|
||||
fn clone(&self) -> Self {
|
||||
PredicateEq {
|
||||
lhs_ty: self.lhs_ty.clone(),
|
||||
eq_token: self.eq_token.clone(),
|
||||
rhs_ty: self.rhs_ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for PredicateLifetime {
|
||||
fn clone(&self) -> Self {
|
||||
PredicateLifetime {
|
||||
@ -1750,6 +1687,8 @@ impl Clone for Receiver {
|
||||
reference: self.reference.clone(),
|
||||
mutability: self.mutability.clone(),
|
||||
self_token: self.self_token.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1784,13 +1723,34 @@ impl Clone for Signature {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for StaticMutability {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
StaticMutability::Mut(v0) => StaticMutability::Mut(v0.clone()),
|
||||
StaticMutability::None => StaticMutability::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Stmt {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Stmt::Local(v0) => Stmt::Local(v0.clone()),
|
||||
Stmt::Item(v0) => Stmt::Item(v0.clone()),
|
||||
Stmt::Expr(v0) => Stmt::Expr(v0.clone()),
|
||||
Stmt::Semi(v0, v1) => Stmt::Semi(v0.clone(), v1.clone()),
|
||||
Stmt::Expr(v0, v1) => Stmt::Expr(v0.clone(), v1.clone()),
|
||||
Stmt::Macro(v0) => Stmt::Macro(v0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for StmtMacro {
|
||||
fn clone(&self) -> Self {
|
||||
StmtMacro {
|
||||
attrs: self.attrs.clone(),
|
||||
mac: self.mac.clone(),
|
||||
semi_token: self.semi_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1822,12 +1782,10 @@ impl Clone for TraitItem {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
TraitItem::Const(v0) => TraitItem::Const(v0.clone()),
|
||||
TraitItem::Method(v0) => TraitItem::Method(v0.clone()),
|
||||
TraitItem::Fn(v0) => TraitItem::Fn(v0.clone()),
|
||||
TraitItem::Type(v0) => TraitItem::Type(v0.clone()),
|
||||
TraitItem::Macro(v0) => TraitItem::Macro(v0.clone()),
|
||||
TraitItem::Verbatim(v0) => TraitItem::Verbatim(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1839,6 +1797,7 @@ impl Clone for TraitItemConst {
|
||||
attrs: self.attrs.clone(),
|
||||
const_token: self.const_token.clone(),
|
||||
ident: self.ident.clone(),
|
||||
generics: self.generics.clone(),
|
||||
colon_token: self.colon_token.clone(),
|
||||
ty: self.ty.clone(),
|
||||
default: self.default.clone(),
|
||||
@ -1848,6 +1807,18 @@ impl Clone for TraitItemConst {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for TraitItemFn {
|
||||
fn clone(&self) -> Self {
|
||||
TraitItemFn {
|
||||
attrs: self.attrs.clone(),
|
||||
sig: self.sig.clone(),
|
||||
default: self.default.clone(),
|
||||
semi_token: self.semi_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for TraitItemMacro {
|
||||
fn clone(&self) -> Self {
|
||||
TraitItemMacro {
|
||||
@ -1859,18 +1830,6 @@ impl Clone for TraitItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for TraitItemMethod {
|
||||
fn clone(&self) -> Self {
|
||||
TraitItemMethod {
|
||||
attrs: self.attrs.clone(),
|
||||
sig: self.sig.clone(),
|
||||
default: self.default.clone(),
|
||||
semi_token: self.semi_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for TraitItemType {
|
||||
fn clone(&self) -> Self {
|
||||
TraitItemType {
|
||||
@ -1905,8 +1864,6 @@ impl Clone for Type {
|
||||
Type::TraitObject(v0) => Type::TraitObject(v0.clone()),
|
||||
Type::Tuple(v0) => Type::Tuple(v0.clone()),
|
||||
Type::Verbatim(v0) => Type::Verbatim(v0.clone()),
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2004,6 +1961,7 @@ impl Clone for TypeParamBound {
|
||||
match self {
|
||||
TypeParamBound::Trait(v0) => TypeParamBound::Trait(v0.clone()),
|
||||
TypeParamBound::Lifetime(v0) => TypeParamBound::Lifetime(v0.clone()),
|
||||
TypeParamBound::Verbatim(v0) => TypeParamBound::Verbatim(v0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2154,13 +2112,15 @@ impl Clone for UseTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Variadic {
|
||||
fn clone(&self) -> Self {
|
||||
Variadic {
|
||||
attrs: self.attrs.clone(),
|
||||
pat: self.pat.clone(),
|
||||
dots: self.dots.clone(),
|
||||
comma: self.comma.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2178,24 +2138,6 @@ impl Clone for Variant {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for VisCrate {
|
||||
fn clone(&self) -> Self {
|
||||
VisCrate {
|
||||
crate_token: self.crate_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for VisPublic {
|
||||
fn clone(&self) -> Self {
|
||||
VisPublic {
|
||||
pub_token: self.pub_token.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for VisRestricted {
|
||||
fn clone(&self) -> Self {
|
||||
VisRestricted {
|
||||
@ -2212,7 +2154,6 @@ impl Clone for Visibility {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Visibility::Public(v0) => Visibility::Public(v0.clone()),
|
||||
Visibility::Crate(v0) => Visibility::Crate(v0.clone()),
|
||||
Visibility::Restricted(v0) => Visibility::Restricted(v0.clone()),
|
||||
Visibility::Inherited => Visibility::Inherited,
|
||||
}
|
||||
@ -2233,9 +2174,8 @@ impl Clone for WhereClause {
|
||||
impl Clone for WherePredicate {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
WherePredicate::Type(v0) => WherePredicate::Type(v0.clone()),
|
||||
WherePredicate::Lifetime(v0) => WherePredicate::Lifetime(v0.clone()),
|
||||
WherePredicate::Eq(v0) => WherePredicate::Eq(v0.clone()),
|
||||
WherePredicate::Type(v0) => WherePredicate::Type(v0.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2954
src/gen/debug.rs
generated
2954
src/gen/debug.rs
generated
File diff suppressed because it is too large
Load Diff
481
src/gen/eq.rs
generated
481
src/gen/eq.rs
generated
@ -37,6 +37,28 @@ impl PartialEq for Arm {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for AssocConst {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for AssocConst {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ident == other.ident && self.generics == other.generics
|
||||
&& self.value == other.value
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for AssocType {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for AssocType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ident == other.ident && self.generics == other.generics
|
||||
&& self.ty == other.ty
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for AttrStyle {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -56,8 +78,7 @@ impl Eq for Attribute {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Attribute {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.style == other.style && self.path == other.path
|
||||
&& TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
|
||||
self.style == other.style && self.meta == other.meta
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -72,6 +93,16 @@ impl PartialEq for BareFnArg {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for BareVariadic {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for BareVariadic {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.name == other.name && self.comma == other.comma
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for BinOp {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -96,30 +127,20 @@ impl PartialEq for BinOp {
|
||||
(BinOp::Ne(_), BinOp::Ne(_)) => true,
|
||||
(BinOp::Ge(_), BinOp::Ge(_)) => true,
|
||||
(BinOp::Gt(_), BinOp::Gt(_)) => true,
|
||||
(BinOp::AddEq(_), BinOp::AddEq(_)) => true,
|
||||
(BinOp::SubEq(_), BinOp::SubEq(_)) => true,
|
||||
(BinOp::MulEq(_), BinOp::MulEq(_)) => true,
|
||||
(BinOp::DivEq(_), BinOp::DivEq(_)) => true,
|
||||
(BinOp::RemEq(_), BinOp::RemEq(_)) => true,
|
||||
(BinOp::BitXorEq(_), BinOp::BitXorEq(_)) => true,
|
||||
(BinOp::BitAndEq(_), BinOp::BitAndEq(_)) => true,
|
||||
(BinOp::BitOrEq(_), BinOp::BitOrEq(_)) => true,
|
||||
(BinOp::ShlEq(_), BinOp::ShlEq(_)) => true,
|
||||
(BinOp::ShrEq(_), BinOp::ShrEq(_)) => true,
|
||||
(BinOp::AddAssign(_), BinOp::AddAssign(_)) => true,
|
||||
(BinOp::SubAssign(_), BinOp::SubAssign(_)) => true,
|
||||
(BinOp::MulAssign(_), BinOp::MulAssign(_)) => true,
|
||||
(BinOp::DivAssign(_), BinOp::DivAssign(_)) => true,
|
||||
(BinOp::RemAssign(_), BinOp::RemAssign(_)) => true,
|
||||
(BinOp::BitXorAssign(_), BinOp::BitXorAssign(_)) => true,
|
||||
(BinOp::BitAndAssign(_), BinOp::BitAndAssign(_)) => true,
|
||||
(BinOp::BitOrAssign(_), BinOp::BitOrAssign(_)) => true,
|
||||
(BinOp::ShlAssign(_), BinOp::ShlAssign(_)) => true,
|
||||
(BinOp::ShrAssign(_), BinOp::ShrAssign(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Binding {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Binding {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ident == other.ident && self.ty == other.ty
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Block {}
|
||||
@ -158,7 +179,8 @@ impl Eq for Constraint {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Constraint {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ident == other.ident && self.bounds == other.bounds
|
||||
self.ident == other.ident && self.generics == other.generics
|
||||
&& self.bounds == other.bounds
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "derive")]
|
||||
@ -230,8 +252,6 @@ impl PartialEq for Expr {
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Assign(self0), Expr::Assign(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::AssignOp(self0), Expr::AssignOp(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Async(self0), Expr::Async(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Await(self0), Expr::Await(other0)) => self0 == other0,
|
||||
@ -239,45 +259,42 @@ impl PartialEq for Expr {
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Block(self0), Expr::Block(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Box(self0), Expr::Box(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Break(self0), Expr::Break(other0)) => self0 == other0,
|
||||
(Expr::Call(self0), Expr::Call(other0)) => self0 == other0,
|
||||
(Expr::Cast(self0), Expr::Cast(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Closure(self0), Expr::Closure(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Const(self0), Expr::Const(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Continue(self0), Expr::Continue(other0)) => self0 == other0,
|
||||
(Expr::Field(self0), Expr::Field(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::ForLoop(self0), Expr::ForLoop(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Group(self0), Expr::Group(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::If(self0), Expr::If(other0)) => self0 == other0,
|
||||
(Expr::Index(self0), Expr::Index(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Infer(self0), Expr::Infer(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Let(self0), Expr::Let(other0)) => self0 == other0,
|
||||
(Expr::Lit(self0), Expr::Lit(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Loop(self0), Expr::Loop(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Macro(self0), Expr::Macro(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Match(self0), Expr::Match(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::MethodCall(self0), Expr::MethodCall(other0)) => self0 == other0,
|
||||
(Expr::Paren(self0), Expr::Paren(other0)) => self0 == other0,
|
||||
(Expr::Path(self0), Expr::Path(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Range(self0), Expr::Range(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Reference(self0), Expr::Reference(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Repeat(self0), Expr::Repeat(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Return(self0), Expr::Return(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Struct(self0), Expr::Struct(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Try(self0), Expr::Try(other0)) => self0 == other0,
|
||||
@ -285,8 +302,6 @@ impl PartialEq for Expr {
|
||||
(Expr::TryBlock(self0), Expr::TryBlock(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Tuple(self0), Expr::Tuple(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Type(self0), Expr::Type(other0)) => self0 == other0,
|
||||
(Expr::Unary(self0), Expr::Unary(other0)) => self0 == other0,
|
||||
#[cfg(feature = "full")]
|
||||
(Expr::Unsafe(self0), Expr::Unsafe(other0)) => self0 == other0,
|
||||
@ -323,17 +338,6 @@ impl PartialEq for ExprAssign {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprAssignOp {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprAssignOp {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.left == other.left && self.op == other.op
|
||||
&& self.right == other.right
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprAsync {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -377,16 +381,6 @@ impl PartialEq for ExprBlock {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprBox {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprBox {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.expr == other.expr
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprBreak {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -422,7 +416,8 @@ impl Eq for ExprClosure {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprClosure {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.movability == other.movability
|
||||
self.attrs == other.attrs && self.lifetimes == other.lifetimes
|
||||
&& self.constness == other.constness && self.movability == other.movability
|
||||
&& self.asyncness == other.asyncness && self.capture == other.capture
|
||||
&& self.inputs == other.inputs && self.output == other.output
|
||||
&& self.body == other.body
|
||||
@ -430,6 +425,16 @@ impl PartialEq for ExprClosure {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprConst {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprConst {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.block == other.block
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprContinue {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -460,10 +465,10 @@ impl PartialEq for ExprForLoop {
|
||||
&& self.expr == other.expr && self.body == other.body
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprGroup {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprGroup {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -494,6 +499,16 @@ impl PartialEq for ExprIndex {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprInfer {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprInfer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprLet {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -522,10 +537,10 @@ impl PartialEq for ExprLoop {
|
||||
self.attrs == other.attrs && self.label == other.label && self.body == other.body
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprMacro {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprMacro {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -542,10 +557,10 @@ impl PartialEq for ExprMatch {
|
||||
self.attrs == other.attrs && self.expr == other.expr && self.arms == other.arms
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprMethodCall {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprMethodCall {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -581,14 +596,14 @@ impl Eq for ExprRange {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprRange {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.from == other.from
|
||||
&& self.limits == other.limits && self.to == other.to
|
||||
self.attrs == other.attrs && self.start == other.start
|
||||
&& self.limits == other.limits && self.end == other.end
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprReference {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprReference {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -616,14 +631,14 @@ impl PartialEq for ExprReturn {
|
||||
self.attrs == other.attrs && self.expr == other.expr
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprStruct {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprStruct {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.path == other.path
|
||||
self.attrs == other.attrs && self.qself == other.qself && self.path == other.path
|
||||
&& self.fields == other.fields && self.dot2_token == other.dot2_token
|
||||
&& self.rest == other.rest
|
||||
}
|
||||
@ -658,16 +673,6 @@ impl PartialEq for ExprTuple {
|
||||
self.attrs == other.attrs && self.elems == other.elems
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprType {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ExprType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.expr == other.expr && self.ty == other.ty
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ExprUnary {}
|
||||
@ -716,10 +721,23 @@ impl Eq for Field {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Field {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.mutability == other.mutability && self.ident == other.ident
|
||||
&& self.colon_token == other.colon_token && self.ty == other.ty
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for FieldMutability {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for FieldMutability {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(FieldMutability::None, FieldMutability::None) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for FieldPat {}
|
||||
@ -731,10 +749,10 @@ impl PartialEq for FieldPat {
|
||||
&& self.colon_token == other.colon_token && self.pat == other.pat
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for FieldValue {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for FieldValue {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -862,6 +880,7 @@ impl Eq for ForeignItemType {}
|
||||
impl PartialEq for ForeignItemType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
|
||||
&& self.generics == other.generics
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -881,7 +900,10 @@ impl PartialEq for GenericArgument {
|
||||
(GenericArgument::Const(self0), GenericArgument::Const(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(GenericArgument::Binding(self0), GenericArgument::Binding(other0)) => {
|
||||
(GenericArgument::AssocType(self0), GenericArgument::AssocType(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(GenericArgument::AssocConst(self0), GenericArgument::AssocConst(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(GenericArgument::Constraint(self0), GenericArgument::Constraint(other0)) => {
|
||||
@ -891,25 +913,6 @@ impl PartialEq for GenericArgument {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for GenericMethodArgument {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for GenericMethodArgument {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(GenericMethodArgument::Type(self0), GenericMethodArgument::Type(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(
|
||||
GenericMethodArgument::Const(self0),
|
||||
GenericMethodArgument::Const(other0),
|
||||
) => self0 == other0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for GenericParam {}
|
||||
@ -918,10 +921,10 @@ impl Eq for GenericParam {}
|
||||
impl PartialEq for GenericParam {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(GenericParam::Type(self0), GenericParam::Type(other0)) => self0 == other0,
|
||||
(GenericParam::Lifetime(self0), GenericParam::Lifetime(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(GenericParam::Type(self0), GenericParam::Type(other0)) => self0 == other0,
|
||||
(GenericParam::Const(self0), GenericParam::Const(other0)) => self0 == other0,
|
||||
_ => false,
|
||||
}
|
||||
@ -947,7 +950,7 @@ impl PartialEq for ImplItem {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(ImplItem::Const(self0), ImplItem::Const(other0)) => self0 == other0,
|
||||
(ImplItem::Method(self0), ImplItem::Method(other0)) => self0 == other0,
|
||||
(ImplItem::Fn(self0), ImplItem::Fn(other0)) => self0 == other0,
|
||||
(ImplItem::Type(self0), ImplItem::Type(other0)) => self0 == other0,
|
||||
(ImplItem::Macro(self0), ImplItem::Macro(other0)) => self0 == other0,
|
||||
(ImplItem::Verbatim(self0), ImplItem::Verbatim(other0)) => {
|
||||
@ -966,7 +969,20 @@ impl PartialEq for ImplItemConst {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.defaultness == other.defaultness && self.ident == other.ident
|
||||
&& self.ty == other.ty && self.expr == other.expr
|
||||
&& self.generics == other.generics && self.ty == other.ty
|
||||
&& self.expr == other.expr
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ImplItemFn {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ImplItemFn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.defaultness == other.defaultness && self.sig == other.sig
|
||||
&& self.block == other.block
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -982,18 +998,6 @@ impl PartialEq for ImplItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ImplItemMethod {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ImplItemMethod {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.defaultness == other.defaultness && self.sig == other.sig
|
||||
&& self.block == other.block
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ImplItemType {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1006,6 +1010,16 @@ impl PartialEq for ImplItemType {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ImplRestriction {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ImplRestriction {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Item {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1019,7 +1033,6 @@ impl PartialEq for Item {
|
||||
(Item::ForeignMod(self0), Item::ForeignMod(other0)) => self0 == other0,
|
||||
(Item::Impl(self0), Item::Impl(other0)) => self0 == other0,
|
||||
(Item::Macro(self0), Item::Macro(other0)) => self0 == other0,
|
||||
(Item::Macro2(self0), Item::Macro2(other0)) => self0 == other0,
|
||||
(Item::Mod(self0), Item::Mod(other0)) => self0 == other0,
|
||||
(Item::Static(self0), Item::Static(other0)) => self0 == other0,
|
||||
(Item::Struct(self0), Item::Struct(other0)) => self0 == other0,
|
||||
@ -1043,7 +1056,8 @@ impl Eq for ItemConst {}
|
||||
impl PartialEq for ItemConst {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
|
||||
&& self.ty == other.ty && self.expr == other.expr
|
||||
&& self.generics == other.generics && self.ty == other.ty
|
||||
&& self.expr == other.expr
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -1086,7 +1100,8 @@ impl Eq for ItemForeignMod {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ItemForeignMod {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.abi == other.abi && self.items == other.items
|
||||
self.attrs == other.attrs && self.unsafety == other.unsafety
|
||||
&& self.abi == other.abi && self.items == other.items
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -1115,23 +1130,13 @@ impl PartialEq for ItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ItemMacro2 {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ItemMacro2 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
|
||||
&& TokenStreamHelper(&self.rules) == TokenStreamHelper(&other.rules)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for ItemMod {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for ItemMod {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.unsafety == other.unsafety && self.ident == other.ident
|
||||
&& self.content == other.content && self.semi == other.semi
|
||||
}
|
||||
}
|
||||
@ -1168,8 +1173,8 @@ impl PartialEq for ItemTrait {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.vis == other.vis
|
||||
&& self.unsafety == other.unsafety && self.auto_token == other.auto_token
|
||||
&& self.ident == other.ident && self.generics == other.generics
|
||||
&& self.colon_token == other.colon_token
|
||||
&& self.restriction == other.restriction && self.ident == other.ident
|
||||
&& self.generics == other.generics && self.colon_token == other.colon_token
|
||||
&& self.supertraits == other.supertraits && self.items == other.items
|
||||
}
|
||||
}
|
||||
@ -1229,10 +1234,10 @@ impl PartialEq for Label {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for LifetimeDef {}
|
||||
impl Eq for LifetimeParam {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for LifetimeDef {
|
||||
impl PartialEq for LifetimeParam {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.lifetime == other.lifetime
|
||||
&& self.colon_token == other.colon_token && self.bounds == other.bounds
|
||||
@ -1288,6 +1293,16 @@ impl PartialEq for Local {
|
||||
self.attrs == other.attrs && self.pat == other.pat && self.init == other.init
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for LocalInit {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for LocalInit {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.expr == other.expr && self.diverge == other.diverge
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Macro {}
|
||||
@ -1336,7 +1351,8 @@ impl Eq for MetaList {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for MetaList {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.path == other.path && self.nested == other.nested
|
||||
self.path == other.path && self.delimiter == other.delimiter
|
||||
&& TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -1346,31 +1362,7 @@ impl Eq for MetaNameValue {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for MetaNameValue {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.path == other.path && self.lit == other.lit
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for MethodTurbofish {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for MethodTurbofish {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.args == other.args
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for NestedMeta {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for NestedMeta {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(NestedMeta::Meta(self0), NestedMeta::Meta(other0)) => self0 == other0,
|
||||
(NestedMeta::Lit(self0), NestedMeta::Lit(other0)) => self0 == other0,
|
||||
_ => false,
|
||||
}
|
||||
self.path == other.path && self.value == other.value
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -1391,11 +1383,12 @@ impl Eq for Pat {}
|
||||
impl PartialEq for Pat {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Pat::Box(self0), Pat::Box(other0)) => self0 == other0,
|
||||
(Pat::Const(self0), Pat::Const(other0)) => self0 == other0,
|
||||
(Pat::Ident(self0), Pat::Ident(other0)) => self0 == other0,
|
||||
(Pat::Lit(self0), Pat::Lit(other0)) => self0 == other0,
|
||||
(Pat::Macro(self0), Pat::Macro(other0)) => self0 == other0,
|
||||
(Pat::Or(self0), Pat::Or(other0)) => self0 == other0,
|
||||
(Pat::Paren(self0), Pat::Paren(other0)) => self0 == other0,
|
||||
(Pat::Path(self0), Pat::Path(other0)) => self0 == other0,
|
||||
(Pat::Range(self0), Pat::Range(other0)) => self0 == other0,
|
||||
(Pat::Reference(self0), Pat::Reference(other0)) => self0 == other0,
|
||||
@ -1415,16 +1408,6 @@ impl PartialEq for Pat {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatBox {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatBox {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.pat == other.pat
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatIdent {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1437,26 +1420,6 @@ impl PartialEq for PatIdent {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatLit {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatLit {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.expr == other.expr
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatMacro {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatMacro {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.mac == other.mac
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatOr {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1468,23 +1431,12 @@ impl PartialEq for PatOr {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatPath {}
|
||||
impl Eq for PatParen {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatPath {
|
||||
impl PartialEq for PatParen {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.qself == other.qself && self.path == other.path
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PatRange {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatRange {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.lo == other.lo && self.limits == other.limits
|
||||
&& self.hi == other.hi
|
||||
self.attrs == other.attrs && self.pat == other.pat
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -1525,8 +1477,8 @@ impl Eq for PatStruct {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatStruct {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.path == other.path
|
||||
&& self.fields == other.fields && self.dot2_token == other.dot2_token
|
||||
self.attrs == other.attrs && self.qself == other.qself && self.path == other.path
|
||||
&& self.fields == other.fields && self.rest == other.rest
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -1546,7 +1498,8 @@ impl Eq for PatTupleStruct {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PatTupleStruct {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.path == other.path && self.pat == other.pat
|
||||
self.attrs == other.attrs && self.qself == other.qself && self.path == other.path
|
||||
&& self.elems == other.elems
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
@ -1612,16 +1565,6 @@ impl PartialEq for PathSegment {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PredicateEq {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for PredicateEq {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.lhs_ty == other.lhs_ty && self.rhs_ty == other.rhs_ty
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for PredicateLifetime {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1675,6 +1618,7 @@ impl PartialEq for Receiver {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.reference == other.reference
|
||||
&& self.mutability == other.mutability
|
||||
&& self.colon_token == other.colon_token && self.ty == other.ty
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -1707,6 +1651,20 @@ impl PartialEq for Signature {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for StaticMutability {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for StaticMutability {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(StaticMutability::Mut(_), StaticMutability::Mut(_)) => true,
|
||||
(StaticMutability::None, StaticMutability::None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Stmt {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1715,12 +1673,25 @@ impl PartialEq for Stmt {
|
||||
match (self, other) {
|
||||
(Stmt::Local(self0), Stmt::Local(other0)) => self0 == other0,
|
||||
(Stmt::Item(self0), Stmt::Item(other0)) => self0 == other0,
|
||||
(Stmt::Expr(self0), Stmt::Expr(other0)) => self0 == other0,
|
||||
(Stmt::Semi(self0, _), Stmt::Semi(other0, _)) => self0 == other0,
|
||||
(Stmt::Expr(self0, self1), Stmt::Expr(other0, other1)) => {
|
||||
self0 == other0 && self1 == other1
|
||||
}
|
||||
(Stmt::Macro(self0), Stmt::Macro(other0)) => self0 == other0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for StmtMacro {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for StmtMacro {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.mac == other.mac
|
||||
&& self.semi_token == other.semi_token
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for TraitBound {}
|
||||
@ -1755,7 +1726,7 @@ impl PartialEq for TraitItem {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(TraitItem::Const(self0), TraitItem::Const(other0)) => self0 == other0,
|
||||
(TraitItem::Method(self0), TraitItem::Method(other0)) => self0 == other0,
|
||||
(TraitItem::Fn(self0), TraitItem::Fn(other0)) => self0 == other0,
|
||||
(TraitItem::Type(self0), TraitItem::Type(other0)) => self0 == other0,
|
||||
(TraitItem::Macro(self0), TraitItem::Macro(other0)) => self0 == other0,
|
||||
(TraitItem::Verbatim(self0), TraitItem::Verbatim(other0)) => {
|
||||
@ -1772,12 +1743,24 @@ impl Eq for TraitItemConst {}
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for TraitItemConst {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.ident == other.ident && self.ty == other.ty
|
||||
self.attrs == other.attrs && self.ident == other.ident
|
||||
&& self.generics == other.generics && self.ty == other.ty
|
||||
&& self.default == other.default
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for TraitItemFn {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for TraitItemFn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.sig == other.sig
|
||||
&& self.default == other.default && self.semi_token == other.semi_token
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for TraitItemMacro {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1789,17 +1772,6 @@ impl PartialEq for TraitItemMacro {
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for TraitItemMethod {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for TraitItemMethod {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs && self.sig == other.sig
|
||||
&& self.default == other.default && self.semi_token == other.semi_token
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for TraitItemType {}
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -1937,6 +1909,9 @@ impl PartialEq for TypeParamBound {
|
||||
(TypeParamBound::Lifetime(self0), TypeParamBound::Lifetime(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(TypeParamBound::Verbatim(self0), TypeParamBound::Verbatim(other0)) => {
|
||||
TokenStreamHelper(self0) == TokenStreamHelper(other0)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -2095,14 +2070,14 @@ impl PartialEq for UseTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Variadic {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Variadic {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.attrs == other.attrs
|
||||
self.attrs == other.attrs && self.pat == other.pat && self.comma == other.comma
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
@ -2118,26 +2093,6 @@ impl PartialEq for Variant {
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for VisCrate {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for VisCrate {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for VisPublic {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for VisPublic {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for VisRestricted {}
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
@ -2154,8 +2109,7 @@ impl Eq for Visibility {}
|
||||
impl PartialEq for Visibility {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Visibility::Public(self0), Visibility::Public(other0)) => self0 == other0,
|
||||
(Visibility::Crate(self0), Visibility::Crate(other0)) => self0 == other0,
|
||||
(Visibility::Public(_), Visibility::Public(_)) => true,
|
||||
(Visibility::Restricted(self0), Visibility::Restricted(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
@ -2182,13 +2136,12 @@ impl Eq for WherePredicate {}
|
||||
impl PartialEq for WherePredicate {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(WherePredicate::Type(self0), WherePredicate::Type(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(WherePredicate::Lifetime(self0), WherePredicate::Lifetime(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
(WherePredicate::Eq(self0), WherePredicate::Eq(other0)) => self0 == other0,
|
||||
(WherePredicate::Type(self0), WherePredicate::Type(other0)) => {
|
||||
self0 == other0
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
1598
src/gen/fold.rs
generated
1598
src/gen/fold.rs
generated
File diff suppressed because it is too large
Load Diff
601
src/gen/hash.rs
generated
601
src/gen/hash.rs
generated
File diff suppressed because it is too large
Load Diff
1876
src/gen/visit.rs
generated
1876
src/gen/visit.rs
generated
File diff suppressed because it is too large
Load Diff
1939
src/gen/visit_mut.rs
generated
1939
src/gen/visit_mut.rs
generated
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,8 @@
|
||||
#[cfg(feature = "fold")]
|
||||
pub mod fold {
|
||||
use crate::fold::Fold;
|
||||
pub(crate) mod fold {
|
||||
use crate::punctuated::{Pair, Punctuated};
|
||||
use proc_macro2::Span;
|
||||
|
||||
pub trait FoldHelper {
|
||||
pub(crate) trait FoldHelper {
|
||||
type Item;
|
||||
fn lift<F>(self, f: F) -> Self
|
||||
where
|
||||
@ -33,122 +31,4 @@ pub mod fold {
|
||||
.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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
429
src/generics.rs
429
src/generics.rs
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use crate::punctuated::{Iter, IterMut, Punctuated};
|
||||
use proc_macro2::TokenStream;
|
||||
#[cfg(all(feature = "printing", feature = "extra-traits"))]
|
||||
use std::fmt::{self, Debug};
|
||||
#[cfg(all(feature = "printing", feature = "extra-traits"))]
|
||||
@ -9,8 +10,12 @@ ast_struct! {
|
||||
/// Lifetimes and type parameters attached to a declaration of a function,
|
||||
/// enum, trait, etc.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
/// This struct represents two distinct optional syntactic elements,
|
||||
/// [generic parameters] and [where clause]. In some locations of the
|
||||
/// grammar, there may be other tokens in between these two things.
|
||||
///
|
||||
/// [generic parameters]: https://doc.rust-lang.org/stable/reference/items/generics.html#generic-parameters
|
||||
/// [where clause]: https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Generics {
|
||||
pub lt_token: Option<Token![<]>,
|
||||
@ -24,9 +29,6 @@ ast_enum_of_structs! {
|
||||
/// A generic type parameter, lifetime, or const generic: `T: Into<String>`,
|
||||
/// `'a: 'b`, `const LEN: usize`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
@ -34,22 +36,30 @@ ast_enum_of_structs! {
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum GenericParam {
|
||||
/// A lifetime parameter: `'a: 'b + 'c + 'd`.
|
||||
Lifetime(LifetimeParam),
|
||||
|
||||
/// 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 lifetime definition: `'a: 'b + 'c + 'd`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct LifetimeParam {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub lifetime: Lifetime,
|
||||
pub colon_token: Option<Token![:]>,
|
||||
pub bounds: Punctuated<Lifetime, Token![+]>,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A generic type parameter: `T: Into<String>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeParam {
|
||||
pub attrs: Vec<Attribute>,
|
||||
@ -61,25 +71,8 @@ ast_struct! {
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A lifetime definition: `'a: 'b + 'c + 'd`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct ConstParam {
|
||||
pub attrs: Vec<Attribute>,
|
||||
@ -104,6 +97,28 @@ impl Default for Generics {
|
||||
}
|
||||
|
||||
impl Generics {
|
||||
/// Returns an
|
||||
/// <code
|
||||
/// style="padding-right:0;">Iterator<Item = &</code><a
|
||||
/// href="struct.LifetimeParam.html"><code
|
||||
/// style="padding-left:0;padding-right:0;">LifetimeParam</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.LifetimeParam.html"><code
|
||||
/// style="padding-left:0;padding-right:0;">LifetimeParam</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
|
||||
@ -126,28 +141,6 @@ impl Generics {
|
||||
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
|
||||
@ -179,6 +172,42 @@ impl Generics {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lifetimes<'a>(Iter<'a, GenericParam>);
|
||||
|
||||
impl<'a> Iterator for Lifetimes<'a> {
|
||||
type Item = &'a LifetimeParam;
|
||||
|
||||
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 LifetimeParam;
|
||||
|
||||
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 TypeParams<'a>(Iter<'a, GenericParam>);
|
||||
|
||||
impl<'a> Iterator for TypeParams<'a> {
|
||||
@ -215,42 +244,6 @@ impl<'a> Iterator for TypeParamsMut<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -288,9 +281,6 @@ impl<'a> Iterator for ConstParamsMut<'a> {
|
||||
}
|
||||
|
||||
/// Returned by `Generics::split_for_impl`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature and the `"printing"` feature.*
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
@ -299,9 +289,6 @@ impl<'a> Iterator for ConstParamsMut<'a> {
|
||||
pub struct ImplGenerics<'a>(&'a Generics);
|
||||
|
||||
/// Returned by `Generics::split_for_impl`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature and the `"printing"` feature.*
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
@ -310,9 +297,6 @@ pub struct ImplGenerics<'a>(&'a Generics);
|
||||
pub struct TypeGenerics<'a>(&'a Generics);
|
||||
|
||||
/// Returned by `TypeGenerics::as_turbofish`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature and the `"printing"` feature.*
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
@ -340,9 +324,6 @@ impl Generics {
|
||||
/// }
|
||||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// *This method is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature and the `"printing"` feature.*
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
||||
@ -410,9 +391,6 @@ generics_wrapper_impls!(Turbofish);
|
||||
#[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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature and the `"printing"` feature.*
|
||||
pub fn as_turbofish(&self) -> Turbofish {
|
||||
Turbofish(self.0)
|
||||
}
|
||||
@ -420,14 +398,11 @@ impl<'a> TypeGenerics<'a> {
|
||||
|
||||
ast_struct! {
|
||||
/// A set of bound lifetimes: `for<'a, 'b, 'c>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct BoundLifetimes {
|
||||
pub for_token: Token![for],
|
||||
pub lt_token: Token![<],
|
||||
pub lifetimes: Punctuated<LifetimeDef, Token![,]>,
|
||||
pub lifetimes: Punctuated<GenericParam, Token![,]>,
|
||||
pub gt_token: Token![>],
|
||||
}
|
||||
}
|
||||
@ -443,9 +418,9 @@ impl Default for BoundLifetimes {
|
||||
}
|
||||
}
|
||||
|
||||
impl LifetimeDef {
|
||||
impl LifetimeParam {
|
||||
pub fn new(lifetime: Lifetime) -> Self {
|
||||
LifetimeDef {
|
||||
LifetimeParam {
|
||||
attrs: Vec::new(),
|
||||
lifetime,
|
||||
colon_token: None,
|
||||
@ -469,21 +444,17 @@ impl From<Ident> for TypeParam {
|
||||
|
||||
ast_enum_of_structs! {
|
||||
/// A trait or lifetime used as a bound on a type parameter.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum TypeParamBound {
|
||||
Trait(TraitBound),
|
||||
Lifetime(Lifetime),
|
||||
Verbatim(TokenStream),
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A trait used as a bound on a type parameter.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TraitBound {
|
||||
pub paren_token: Option<token::Paren>,
|
||||
@ -498,9 +469,6 @@ ast_struct! {
|
||||
ast_enum! {
|
||||
/// A modifier on a trait bound, currently only used for the `?` in
|
||||
/// `?Sized`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
@ -511,9 +479,6 @@ ast_enum! {
|
||||
ast_struct! {
|
||||
/// A `where` clause in a definition: `where T: Deserialize<'de>, D:
|
||||
/// 'static`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct WhereClause {
|
||||
pub where_token: Token![where],
|
||||
@ -524,32 +489,34 @@ ast_struct! {
|
||||
ast_enum_of_structs! {
|
||||
/// A single predicate in a `where` clause: `T: Deserialize<'de>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
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),
|
||||
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
||||
Type(PredicateType),
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct PredicateLifetime {
|
||||
pub lifetime: Lifetime,
|
||||
pub colon_token: Token![:],
|
||||
pub bounds: Punctuated<Lifetime, Token![+]>,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct PredicateType {
|
||||
/// Any lifetimes from a `for` binding
|
||||
@ -562,36 +529,10 @@ ast_struct! {
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct PredicateEq {
|
||||
pub lhs_ty: Type,
|
||||
pub eq_token: Token![=],
|
||||
pub rhs_ty: Type,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::ext::IdentExt;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
@ -612,7 +553,7 @@ pub mod parsing {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(Lifetime) {
|
||||
params.push_value(GenericParam::Lifetime(LifetimeDef {
|
||||
params.push_value(GenericParam::Lifetime(LifetimeParam {
|
||||
attrs,
|
||||
..input.parse()?
|
||||
}));
|
||||
@ -669,7 +610,7 @@ pub mod parsing {
|
||||
..input.parse()?
|
||||
}))
|
||||
} else if lookahead.peek(Lifetime) {
|
||||
Ok(GenericParam::Lifetime(LifetimeDef {
|
||||
Ok(GenericParam::Lifetime(LifetimeParam {
|
||||
attrs,
|
||||
..input.parse()?
|
||||
}))
|
||||
@ -685,10 +626,10 @@ pub mod parsing {
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for LifetimeDef {
|
||||
impl Parse for LifetimeParam {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let has_colon;
|
||||
Ok(LifetimeDef {
|
||||
Ok(LifetimeParam {
|
||||
attrs: input.call(Attribute::parse_outer)?,
|
||||
lifetime: input.parse()?,
|
||||
colon_token: {
|
||||
@ -731,7 +672,14 @@ pub mod parsing {
|
||||
lifetimes: {
|
||||
let mut lifetimes = Punctuated::new();
|
||||
while !input.peek(Token![>]) {
|
||||
lifetimes.push_value(input.parse()?);
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let lifetime: Lifetime = input.parse()?;
|
||||
lifetimes.push_value(GenericParam::Lifetime(LifetimeParam {
|
||||
attrs,
|
||||
lifetime,
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
}));
|
||||
if input.peek(Token![>]) {
|
||||
break;
|
||||
}
|
||||
@ -762,19 +710,12 @@ pub mod parsing {
|
||||
let ident: Ident = input.parse()?;
|
||||
let colon_token: Option<Token![:]> = input.parse()?;
|
||||
|
||||
let begin_bound = input.fork();
|
||||
let mut is_maybe_const = false;
|
||||
let mut bounds = Punctuated::new();
|
||||
if colon_token.is_some() {
|
||||
loop {
|
||||
if input.peek(Token![,]) || input.peek(Token![>]) || input.peek(Token![=]) {
|
||||
break;
|
||||
}
|
||||
if input.peek(Token![~]) && input.peek2(Token![const]) {
|
||||
input.parse::<Token![~]>()?;
|
||||
input.parse::<Token![const]>()?;
|
||||
is_maybe_const = true;
|
||||
}
|
||||
let value: TypeParamBound = input.parse()?;
|
||||
bounds.push_value(value);
|
||||
if !input.peek(Token![+]) {
|
||||
@ -785,19 +726,13 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
let mut eq_token: Option<Token![=]> = input.parse()?;
|
||||
let mut default = if eq_token.is_some() {
|
||||
let eq_token: Option<Token![=]> = input.parse()?;
|
||||
let default = if eq_token.is_some() {
|
||||
Some(input.parse::<Type>()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if is_maybe_const {
|
||||
bounds.clear();
|
||||
eq_token = None;
|
||||
default = Some(Type::Verbatim(verbatim::between(begin_bound, input)));
|
||||
}
|
||||
|
||||
Ok(TypeParam {
|
||||
attrs,
|
||||
ident,
|
||||
@ -816,15 +751,30 @@ pub mod parsing {
|
||||
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));
|
||||
let begin = input.fork();
|
||||
|
||||
let content;
|
||||
let (paren_token, content) = if input.peek(token::Paren) {
|
||||
(Some(parenthesized!(content in input)), &content)
|
||||
} else {
|
||||
(None, input)
|
||||
};
|
||||
|
||||
let is_tilde_const =
|
||||
cfg!(feature = "full") && content.peek(Token![~]) && content.peek2(Token![const]);
|
||||
if is_tilde_const {
|
||||
content.parse::<Token![~]>()?;
|
||||
content.parse::<Token![const]>()?;
|
||||
}
|
||||
|
||||
input.parse().map(TypeParamBound::Trait)
|
||||
let mut bound: TraitBound = content.parse()?;
|
||||
bound.paren_token = paren_token;
|
||||
|
||||
if is_tilde_const {
|
||||
Ok(TypeParamBound::Verbatim(verbatim::between(&begin, input)))
|
||||
} else {
|
||||
Ok(TypeParamBound::Trait(bound))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -844,7 +794,8 @@ pub mod parsing {
|
||||
|| input.peek(Token![::])
|
||||
|| input.peek(Token![?])
|
||||
|| input.peek(Lifetime)
|
||||
|| input.peek(token::Paren))
|
||||
|| input.peek(token::Paren)
|
||||
|| input.peek(Token![~]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -856,15 +807,6 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TraitBound {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
#[cfg(feature = "full")]
|
||||
let tilde_const = if input.peek(Token![~]) && input.peek2(Token![const]) {
|
||||
let tilde_token = input.parse::<Token![~]>()?;
|
||||
let const_token = input.parse::<Token![const]>()?;
|
||||
Some((tilde_token, const_token))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let modifier: TraitBoundModifier = input.parse()?;
|
||||
let lifetimes: Option<BoundLifetimes> = input.parse()?;
|
||||
|
||||
@ -878,21 +820,6 @@ pub mod parsing {
|
||||
path.segments.last_mut().unwrap().arguments = parenthesized;
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
if let Some((tilde_token, const_token)) = tilde_const {
|
||||
path.segments.insert(
|
||||
0,
|
||||
PathSegment {
|
||||
ident: Ident::new("const", const_token.span),
|
||||
arguments: PathArguments::None,
|
||||
},
|
||||
);
|
||||
let (_const, punct) = path.segments.pairs_mut().next().unwrap().into_tuple();
|
||||
*punct.unwrap() = Token![::](tilde_token.span);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(TraitBound {
|
||||
paren_token: None,
|
||||
modifier,
|
||||
@ -1047,11 +974,7 @@ mod printing {
|
||||
use super::*;
|
||||
use crate::attr::FilterAttrs;
|
||||
use crate::print::TokensOrDefault;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::punctuated::Pair;
|
||||
use proc_macro2::TokenStream;
|
||||
#[cfg(feature = "full")]
|
||||
use proc_macro2::TokenTree;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
@ -1065,9 +988,6 @@ mod printing {
|
||||
|
||||
// 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() {
|
||||
@ -1076,7 +996,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
for param in self.params.pairs() {
|
||||
match **param.value() {
|
||||
match param.value() {
|
||||
GenericParam::Type(_) | GenericParam::Const(_) => {
|
||||
if !trailing_or_empty {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
@ -1102,9 +1022,6 @@ mod printing {
|
||||
|
||||
// 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() {
|
||||
@ -1120,7 +1037,7 @@ mod printing {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
trailing_or_empty = true;
|
||||
}
|
||||
match *param.value() {
|
||||
match param.value() {
|
||||
GenericParam::Lifetime(_) => unreachable!(),
|
||||
GenericParam::Type(param) => {
|
||||
// Leave off the type parameter defaults
|
||||
@ -1157,9 +1074,6 @@ mod printing {
|
||||
|
||||
// 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() {
|
||||
@ -1177,7 +1091,7 @@ mod printing {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
trailing_or_empty = true;
|
||||
}
|
||||
match *param.value() {
|
||||
match param.value() {
|
||||
GenericParam::Lifetime(_) => unreachable!(),
|
||||
GenericParam::Type(param) => {
|
||||
// Leave off the type parameter defaults
|
||||
@ -1215,7 +1129,7 @@ mod printing {
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for LifetimeDef {
|
||||
impl ToTokens for LifetimeParam {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
self.lifetime.to_tokens(tokens);
|
||||
@ -1236,29 +1150,6 @@ mod printing {
|
||||
self.bounds.to_tokens(tokens);
|
||||
}
|
||||
if let Some(default) = &self.default {
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
if self.eq_token.is_none() {
|
||||
if let Type::Verbatim(default) = default {
|
||||
let mut iter = default.clone().into_iter().peekable();
|
||||
while let Some(token) = iter.next() {
|
||||
if let TokenTree::Punct(q) = token {
|
||||
if q.as_char() == '~' {
|
||||
if let Some(TokenTree::Ident(c)) = iter.peek() {
|
||||
if c == "const" {
|
||||
if self.bounds.is_empty() {
|
||||
TokensOrDefault(&self.colon_token)
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
return default.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TokensOrDefault(&self.eq_token).to_tokens(tokens);
|
||||
default.to_tokens(tokens);
|
||||
}
|
||||
@ -1269,26 +1160,9 @@ mod printing {
|
||||
impl ToTokens for TraitBound {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let to_tokens = |tokens: &mut TokenStream| {
|
||||
#[cfg(feature = "full")]
|
||||
let skip = match self.path.segments.pairs().next() {
|
||||
Some(Pair::Punctuated(t, p)) if t.ident == "const" => {
|
||||
Token![~](p.spans[0]).to_tokens(tokens);
|
||||
t.to_tokens(tokens);
|
||||
1
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
self.modifier.to_tokens(tokens);
|
||||
self.lifetimes.to_tokens(tokens);
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
self.path.leading_colon.to_tokens(tokens);
|
||||
tokens.append_all(self.path.segments.pairs().skip(skip));
|
||||
}
|
||||
#[cfg(not(feature = "full"))]
|
||||
{
|
||||
self.path.to_tokens(tokens);
|
||||
}
|
||||
self.path.to_tokens(tokens);
|
||||
};
|
||||
match &self.paren_token {
|
||||
Some(paren) => paren.surround(tokens, to_tokens),
|
||||
@ -1332,16 +1206,6 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PredicateLifetime {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
@ -1352,11 +1216,12 @@ mod printing {
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PredicateEq {
|
||||
impl ToTokens for PredicateType {
|
||||
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);
|
||||
self.lifetimes.to_tokens(tokens);
|
||||
self.bounded_ty.to_tokens(tokens);
|
||||
self.colon_token.to_tokens(tokens);
|
||||
self.bounds.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
src/group.rs
19
src/group.rs
@ -1,26 +1,33 @@
|
||||
use crate::error::Result;
|
||||
use crate::parse::ParseBuffer;
|
||||
use crate::token;
|
||||
use proc_macro2::{Delimiter, Span};
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Delimiter;
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub struct Parens<'a> {
|
||||
#[doc(hidden)]
|
||||
pub token: token::Paren,
|
||||
#[doc(hidden)]
|
||||
pub content: ParseBuffer<'a>,
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub struct Braces<'a> {
|
||||
#[doc(hidden)]
|
||||
pub token: token::Brace,
|
||||
#[doc(hidden)]
|
||||
pub content: ParseBuffer<'a>,
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub struct Brackets<'a> {
|
||||
#[doc(hidden)]
|
||||
pub token: token::Bracket,
|
||||
#[doc(hidden)]
|
||||
pub content: ParseBuffer<'a>,
|
||||
}
|
||||
|
||||
@ -28,7 +35,9 @@ pub struct Brackets<'a> {
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[doc(hidden)]
|
||||
pub struct Group<'a> {
|
||||
#[doc(hidden)]
|
||||
pub token: token::Group,
|
||||
#[doc(hidden)]
|
||||
pub content: ParseBuffer<'a>,
|
||||
}
|
||||
|
||||
@ -62,7 +71,7 @@ pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> {
|
||||
#[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),
|
||||
token: token::Group(span.join()),
|
||||
content,
|
||||
})
|
||||
}
|
||||
@ -70,7 +79,7 @@ pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> {
|
||||
fn parse_delimited<'a>(
|
||||
input: &ParseBuffer<'a>,
|
||||
delimiter: Delimiter,
|
||||
) -> Result<(Span, ParseBuffer<'a>)> {
|
||||
) -> Result<(DelimSpan, ParseBuffer<'a>)> {
|
||||
input.step(|cursor| {
|
||||
if let Some((content, span, rest)) = cursor.group(delimiter) {
|
||||
let scope = crate::buffer::close_span_of_group(*cursor);
|
||||
@ -119,7 +128,7 @@ fn parse_delimited<'a>(
|
||||
/// struct_token: input.parse()?,
|
||||
/// ident: input.parse()?,
|
||||
/// paren_token: parenthesized!(content in input),
|
||||
/// fields: content.parse_terminated(Type::parse)?,
|
||||
/// fields: content.parse_terminated(Type::parse, Token![,])?,
|
||||
/// semi_token: input.parse()?,
|
||||
/// })
|
||||
/// }
|
||||
@ -185,7 +194,7 @@ macro_rules! parenthesized {
|
||||
/// struct_token: input.parse()?,
|
||||
/// ident: input.parse()?,
|
||||
/// brace_token: braced!(content in input),
|
||||
/// fields: content.parse_terminated(Field::parse)?,
|
||||
/// fields: content.parse_terminated(Field::parse, Token![,])?,
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
|
122
src/ident.rs
122
src/ident.rs
@ -1,66 +1,14 @@
|
||||
#[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;
|
||||
|
||||
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")]
|
||||
#[cfg_attr(doc_cfg, doc(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"
|
||||
pub_if_not_doc! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
|
||||
match marker {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +34,7 @@ impl From<Token![_]> for Ident {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn xid_ok(symbol: &str) -> bool {
|
||||
pub(crate) fn xid_ok(symbol: &str) -> bool {
|
||||
let mut chars = symbol.chars();
|
||||
let first = chars.next().unwrap();
|
||||
if !(first == '_' || unicode_ident::is_xid_start(first)) {
|
||||
@ -99,3 +47,61 @@ pub fn xid_ok(symbol: &str) -> bool {
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
mod parsing {
|
||||
use crate::buffer::Cursor;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::token::Token;
|
||||
use proc_macro2::Ident;
|
||||
|
||||
fn accept_as_ident(ident: &Ident) -> bool {
|
||||
match ident.to_string().as_str() {
|
||||
"_" |
|
||||
// Based on https://doc.rust-lang.org/1.65.0/reference/keywords.html
|
||||
"abstract" | "as" | "async" | "await" | "become" | "box" | "break" |
|
||||
"const" | "continue" | "crate" | "do" | "dyn" | "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" | "try" | "type" |
|
||||
"typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
|
||||
"while" | "yield" => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(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) {
|
||||
Ok((ident, rest))
|
||||
} else {
|
||||
Err(cursor.error(format_args!(
|
||||
"expected identifier, found keyword `{}`",
|
||||
ident,
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
Err(cursor.error("expected identifier"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1773
src/item.rs
1773
src/item.rs
File diff suppressed because it is too large
Load Diff
542
src/lib.rs
542
src/lib.rs
@ -62,7 +62,7 @@
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! syn = "1.0"
|
||||
//! syn = "2.0"
|
||||
//! quote = "1.0"
|
||||
//!
|
||||
//! [lib]
|
||||
@ -94,9 +94,8 @@
|
||||
//! ```
|
||||
//!
|
||||
//! 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.
|
||||
//! of a derive macro. 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
|
||||
//!
|
||||
@ -250,8 +249,9 @@
|
||||
//! 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.107")]
|
||||
#![doc(html_root_url = "https://docs.rs/syn/2.0.48")]
|
||||
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(
|
||||
clippy::bool_to_int_with_if,
|
||||
@ -260,14 +260,20 @@
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_ptr_alignment,
|
||||
clippy::default_trait_access,
|
||||
clippy::derivable_impls,
|
||||
clippy::diverging_sub_expression,
|
||||
clippy::doc_markdown,
|
||||
clippy::expl_impl_clone_on_copy,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::if_not_else,
|
||||
clippy::inherent_to_string,
|
||||
clippy::into_iter_without_iter,
|
||||
clippy::items_after_statements,
|
||||
clippy::large_enum_variant,
|
||||
clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410
|
||||
clippy::manual_assert,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::match_on_vec_items,
|
||||
clippy::match_same_arms,
|
||||
clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
|
||||
@ -278,6 +284,7 @@
|
||||
clippy::needless_doctest_main,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::never_loop,
|
||||
clippy::range_plus_one,
|
||||
clippy::redundant_else,
|
||||
clippy::return_self_not_must_use,
|
||||
clippy::similar_names,
|
||||
@ -285,20 +292,16 @@
|
||||
clippy::too_many_arguments,
|
||||
clippy::too_many_lines,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::uninhabited_references,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnecessary_box_returns,
|
||||
clippy::unnecessary_unwrap,
|
||||
clippy::used_underscore_binding,
|
||||
clippy::wildcard_imports
|
||||
clippy::wildcard_imports,
|
||||
)]
|
||||
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
|
||||
feature = "proc-macro"
|
||||
))]
|
||||
#[cfg(feature = "proc-macro")]
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
extern crate quote;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@ -310,155 +313,300 @@ 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_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
|
||||
|
||||
mod bigint;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod buffer;
|
||||
|
||||
mod custom_keyword;
|
||||
|
||||
mod custom_punctuation;
|
||||
|
||||
#[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;
|
||||
|
||||
mod lit;
|
||||
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_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod derive;
|
||||
#[cfg(feature = "derive")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
|
||||
|
||||
mod drops;
|
||||
|
||||
mod error;
|
||||
pub use crate::error::{Error, Result};
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod expr;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::expr::{Arm, Label, RangeLimits};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::expr::{
|
||||
Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall,
|
||||
ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member,
|
||||
};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::expr::{
|
||||
ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst,
|
||||
ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch,
|
||||
ExprRange, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile,
|
||||
ExprYield,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod ext;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
mod file;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::file::File;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod generics;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::generics::{
|
||||
BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
|
||||
PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
|
||||
WherePredicate,
|
||||
};
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
||||
)]
|
||||
pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};
|
||||
|
||||
mod ident;
|
||||
#[doc(inline)]
|
||||
pub use crate::ident::Ident;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
mod item;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::item::{
|
||||
FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,
|
||||
ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,
|
||||
ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod,
|
||||
ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver,
|
||||
Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro,
|
||||
TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic,
|
||||
};
|
||||
|
||||
mod lifetime;
|
||||
#[doc(inline)]
|
||||
pub use crate::lifetime::Lifetime;
|
||||
|
||||
mod lit;
|
||||
#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566
|
||||
pub use crate::lit::StrStyle;
|
||||
#[doc(inline)]
|
||||
pub use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
mod lookahead;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod mac;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::mac::{Macro, MacroDelimiter};
|
||||
|
||||
#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive"))))
|
||||
)]
|
||||
pub mod meta;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod op;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(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(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod parse;
|
||||
|
||||
#[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(all(feature = "parsing", feature = "proc-macro"))]
|
||||
mod parse_macro_input;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "printing"))]
|
||||
mod parse_quote;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
mod pat;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::expr::{
|
||||
ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
|
||||
ExprRange as PatRange,
|
||||
};
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::pat::{
|
||||
FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference,
|
||||
PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild,
|
||||
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
|
||||
PatTupleStruct, PatType, PatWild,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod path;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::path::{
|
||||
AngleBracketedGenericArguments, Binding, Constraint, GenericArgument,
|
||||
AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
|
||||
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod buffer;
|
||||
mod drops;
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod ext;
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
mod print;
|
||||
|
||||
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;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod restriction;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};
|
||||
|
||||
// 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;
|
||||
mod sealed;
|
||||
|
||||
mod span;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "printing"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
pub mod spanned;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
mod stmt;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
|
||||
|
||||
mod thread;
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))]
|
||||
mod tt;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod ty;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::ty::{
|
||||
Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
|
||||
TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference,
|
||||
TypeSlice, TypeTraitObject, TypeTuple,
|
||||
};
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
|
||||
mod verbatim;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "full"))]
|
||||
mod whitespace;
|
||||
|
||||
mod gen {
|
||||
/// 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)),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /* ... */
|
||||
/// ```
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This fold inserts parentheses to fully parenthesizes any expression.
|
||||
///
|
||||
/// ```
|
||||
/// // [dependencies]
|
||||
/// // quote = "1.0"
|
||||
/// // syn = { version = "2.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")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
|
||||
#[rustfmt::skip]
|
||||
pub mod fold;
|
||||
|
||||
/// 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
|
||||
@ -499,8 +647,6 @@ mod gen {
|
||||
/// /* ... */
|
||||
/// ```
|
||||
///
|
||||
/// *This module is available only if Syn is built with the `"visit"` feature.*
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// # Example
|
||||
@ -511,7 +657,7 @@ mod gen {
|
||||
/// ```
|
||||
/// // [dependencies]
|
||||
/// // quote = "1.0"
|
||||
/// // syn = { version = "1.0", features = ["full", "visit"] }
|
||||
/// // syn = { version = "2.0", features = ["full", "visit"] }
|
||||
///
|
||||
/// use quote::quote;
|
||||
/// use syn::visit::{self, Visit};
|
||||
@ -621,9 +767,6 @@ mod gen {
|
||||
/// /* ... */
|
||||
/// ```
|
||||
///
|
||||
/// *This module is available only if Syn is built with the `"visit-mut"`
|
||||
/// feature.*
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// # Example
|
||||
@ -634,7 +777,7 @@ mod gen {
|
||||
/// ```
|
||||
/// // [dependencies]
|
||||
/// // quote = "1.0"
|
||||
/// // syn = { version = "1.0", features = ["full", "visit-mut"] }
|
||||
/// // syn = { version = "2.0", features = ["full", "visit-mut"] }
|
||||
///
|
||||
/// use quote::quote;
|
||||
/// use syn::visit_mut::{self, VisitMut};
|
||||
@ -677,97 +820,14 @@ mod gen {
|
||||
#[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 only 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")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
|
||||
#[rustfmt::skip]
|
||||
pub mod fold;
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[rustfmt::skip]
|
||||
mod clone;
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[rustfmt::skip]
|
||||
mod debug;
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[rustfmt::skip]
|
||||
mod eq;
|
||||
@ -776,48 +836,28 @@ mod gen {
|
||||
#[rustfmt::skip]
|
||||
mod hash;
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[rustfmt::skip]
|
||||
mod debug;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[path = "../gen_helper.rs"]
|
||||
mod helper;
|
||||
}
|
||||
pub use crate::gen::*;
|
||||
|
||||
#[cfg(feature = "fold")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
|
||||
pub use crate::gen::fold;
|
||||
|
||||
#[cfg(feature = "visit")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit")))]
|
||||
pub use crate::gen::visit;
|
||||
|
||||
#[cfg(feature = "visit-mut")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit-mut")))]
|
||||
pub use crate::gen::visit_mut;
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[path = "export.rs"]
|
||||
pub mod __private;
|
||||
|
||||
mod custom_keyword;
|
||||
mod custom_punctuation;
|
||||
mod sealed;
|
||||
mod span;
|
||||
mod thread;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
mod lookahead;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub mod parse;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
mod reserved;
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))]
|
||||
mod verbatim;
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
mod print;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
@ -831,9 +871,6 @@ pub use crate::error::{Error, Result};
|
||||
///
|
||||
/// [`syn::parse2`]: parse2
|
||||
///
|
||||
/// *This function is available only if Syn is built with both the `"parsing"` and
|
||||
/// `"proc-macro"` features.*
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
@ -859,11 +896,7 @@ pub use crate::error::{Error, Result};
|
||||
/// expanded.into()
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
|
||||
feature = "parsing",
|
||||
feature = "proc-macro"
|
||||
))]
|
||||
#[cfg(all(feature = "parsing", feature = "proc-macro"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
|
||||
pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
|
||||
parse::Parser::parse(T::parse, tokens)
|
||||
@ -881,8 +914,6 @@ pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
|
||||
/// instead.
|
||||
///
|
||||
/// [`syn::parse`]: parse()
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"` feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
|
||||
@ -891,8 +922,6 @@ pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
|
||||
|
||||
/// Parse a string of Rust code into the chosen syntax tree node.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"` feature.*
|
||||
///
|
||||
/// # Hygiene
|
||||
///
|
||||
/// Every span in the resulting syntax tree will be set to resolve at the macro
|
||||
@ -929,9 +958,6 @@ pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
|
||||
///
|
||||
/// If present, either of these would be an error using `from_str`.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"` and
|
||||
/// `"full"` features.*
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
@ -939,7 +965,7 @@ pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
|
||||
/// use std::fs::File;
|
||||
/// use std::io::Read;
|
||||
///
|
||||
/// fn run() -> Result<(), Box<Error>> {
|
||||
/// fn run() -> Result<(), Box<dyn Error>> {
|
||||
/// let mut file = File::open("path/to/code.rs")?;
|
||||
/// let mut content = String::new();
|
||||
/// file.read_to_string(&mut content)?;
|
||||
|
@ -113,14 +113,16 @@ impl Hash for Lifetime {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
|
||||
match marker {}
|
||||
pub_if_not_doc! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
|
||||
match marker {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
|
325
src/lit.rs
325
src/lit.rs
@ -19,6 +19,7 @@ ast_enum_of_structs! {
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: crate::Expr#syntax-tree-enums
|
||||
#[non_exhaustive]
|
||||
pub enum Lit {
|
||||
/// A UTF-8 string literal: `"foo"`.
|
||||
Str(LitStr),
|
||||
@ -142,8 +143,7 @@ impl LitStr {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use proc_macro2::Span;
|
||||
/// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result};
|
||||
/// use syn::{Attribute, Error, Expr, Lit, Meta, Path, Result};
|
||||
///
|
||||
/// // Parses the path from an attribute that looks like:
|
||||
/// //
|
||||
@ -151,19 +151,20 @@ impl LitStr {
|
||||
/// //
|
||||
/// // or returns `None` if the input is some other attribute.
|
||||
/// fn get_path(attr: &Attribute) -> Result<Option<Path>> {
|
||||
/// if !attr.path.is_ident("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))
|
||||
/// if let Meta::NameValue(meta) = &attr.meta {
|
||||
/// if let Expr::Lit(expr) = &meta.value {
|
||||
/// if let Lit::Str(lit_str) = &expr.lit {
|
||||
/// return lit_str.parse().map(Some);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let message = "expected #[path = \"...\"]";
|
||||
/// Err(Error::new_spanned(attr, message))
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
@ -227,7 +228,17 @@ impl LitStr {
|
||||
let mut tokens = TokenStream::from_str(&self.value())?;
|
||||
tokens = respan_token_stream(tokens, self.span());
|
||||
|
||||
parser.parse2(tokens)
|
||||
let result = parser.parse2(tokens)?;
|
||||
|
||||
let suffix = self.suffix();
|
||||
if !suffix.is_empty() {
|
||||
return Err(Error::new(
|
||||
self.span(),
|
||||
format!("unexpected suffix `{}` on string literal", suffix),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
@ -359,11 +370,7 @@ impl LitInt {
|
||||
None => panic!("Not an integer literal: `{}`", repr),
|
||||
};
|
||||
|
||||
let mut token = match value::to_literal(repr, &digits, &suffix) {
|
||||
Some(token) => token,
|
||||
None => panic!("Unsupported integer literal: `{}`", repr),
|
||||
};
|
||||
|
||||
let mut token: Literal = repr.parse().unwrap();
|
||||
token.set_span(span);
|
||||
LitInt {
|
||||
repr: Box::new(LitIntRepr {
|
||||
@ -457,11 +464,7 @@ impl LitFloat {
|
||||
None => panic!("Not a float literal: `{}`", repr),
|
||||
};
|
||||
|
||||
let mut token = match value::to_literal(repr, &digits, &suffix) {
|
||||
Some(token) => token,
|
||||
None => panic!("Unsupported float literal: `{}`", repr),
|
||||
};
|
||||
|
||||
let mut token: Literal = repr.parse().unwrap();
|
||||
token.set_span(span);
|
||||
LitFloat {
|
||||
repr: Box::new(LitFloatRepr {
|
||||
@ -557,70 +560,133 @@ mod debug_impls {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
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 LitStr {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitStr")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for LitByteStr {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("LitByteStr")
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
impl LitByteStr {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitByteStr")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for LitByte {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("LitByte")
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
impl LitByte {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitByte")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for LitChar {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("LitChar")
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
impl LitChar {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitChar")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
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 LitInt {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitInt")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
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 LitFloat {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("token", &format_args!("{}", self.repr.token))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitFloat")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for LitBool {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct("LitBool")
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
impl LitBool {
|
||||
pub(crate) fn debug(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
name: &str,
|
||||
) -> fmt::Result {
|
||||
formatter
|
||||
.debug_struct(name)
|
||||
.field("value", &self.value)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
self.debug(formatter, "LitBool")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -692,10 +758,12 @@ macro_rules! lit_extra_traits {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
|
||||
match marker {}
|
||||
pub_if_not_doc! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $ty(marker: lookahead::TokenMarker) -> $ty {
|
||||
match marker {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -708,34 +776,37 @@ lit_extra_traits!(LitInt);
|
||||
lit_extra_traits!(LitFloat);
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
|
||||
match marker {}
|
||||
pub_if_not_doc! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool {
|
||||
match marker {}
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum! {
|
||||
/// The style of a string literal, either plain quoted or a raw string like
|
||||
/// `r##"data"##`.
|
||||
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),
|
||||
/// The style of a string literal, either plain quoted or a raw string like
|
||||
/// `r##"data"##`.
|
||||
#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566
|
||||
pub enum StrStyle {
|
||||
/// 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")]
|
||||
pub_if_not_doc! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
|
||||
match marker {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
|
||||
match marker {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::buffer::Cursor;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
@ -783,23 +854,22 @@ pub mod parsing {
|
||||
repr.insert(0, '-');
|
||||
|
||||
if let Some((digits, suffix)) = value::parse_lit_int(&repr) {
|
||||
if let Some(mut token) = value::to_literal(&repr, &digits, &suffix) {
|
||||
token.set_span(span);
|
||||
return Some((
|
||||
Lit::Int(LitInt {
|
||||
repr: Box::new(LitIntRepr {
|
||||
token,
|
||||
digits,
|
||||
suffix,
|
||||
}),
|
||||
let mut token: Literal = repr.parse().unwrap();
|
||||
token.set_span(span);
|
||||
return Some((
|
||||
Lit::Int(LitInt {
|
||||
repr: Box::new(LitIntRepr {
|
||||
token,
|
||||
digits,
|
||||
suffix,
|
||||
}),
|
||||
rest,
|
||||
));
|
||||
}
|
||||
}),
|
||||
rest,
|
||||
));
|
||||
}
|
||||
|
||||
let (digits, suffix) = value::parse_lit_float(&repr)?;
|
||||
let mut token = value::to_literal(&repr, &digits, &suffix)?;
|
||||
let mut token: Literal = repr.parse().unwrap();
|
||||
token.set_span(span);
|
||||
Some((
|
||||
Lit::Float(LitFloat {
|
||||
@ -959,6 +1029,7 @@ mod value {
|
||||
let repr = token.to_string();
|
||||
|
||||
match byte(&repr, 0) {
|
||||
// "...", r"...", r#"..."#
|
||||
b'"' | b'r' => {
|
||||
let (_, suffix) = parse_lit_str(&repr);
|
||||
return Lit::Str(LitStr {
|
||||
@ -966,12 +1037,14 @@ mod value {
|
||||
});
|
||||
}
|
||||
b'b' => match byte(&repr, 1) {
|
||||
// b"...", br"...", br#"...#"
|
||||
b'"' | b'r' => {
|
||||
let (_, suffix) = parse_lit_byte_str(&repr);
|
||||
return Lit::ByteStr(LitByteStr {
|
||||
repr: Box::new(LitRepr { token, suffix }),
|
||||
});
|
||||
}
|
||||
// b'...'
|
||||
b'\'' => {
|
||||
let (_, suffix) = parse_lit_byte(&repr);
|
||||
return Lit::Byte(LitByte {
|
||||
@ -980,6 +1053,7 @@ mod value {
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
// '...'
|
||||
b'\'' => {
|
||||
let (_, suffix) = parse_lit_char(&repr);
|
||||
return Lit::Char(LitChar {
|
||||
@ -987,6 +1061,7 @@ mod value {
|
||||
});
|
||||
}
|
||||
b'0'..=b'9' | b'-' => {
|
||||
// 0, 123, 0xFF, 0o77, 0b11
|
||||
if let Some((digits, suffix)) = parse_lit_int(&repr) {
|
||||
return Lit::Int(LitInt {
|
||||
repr: Box::new(LitIntRepr {
|
||||
@ -996,6 +1071,7 @@ mod value {
|
||||
}),
|
||||
});
|
||||
}
|
||||
// 1.0, 1e-1, 1e+1
|
||||
if let Some((digits, suffix)) = parse_lit_float(&repr) {
|
||||
return Lit::Float(LitFloat {
|
||||
repr: Box::new(LitFloatRepr {
|
||||
@ -1006,6 +1082,7 @@ mod value {
|
||||
});
|
||||
}
|
||||
}
|
||||
// true, false
|
||||
b't' | b'f' => {
|
||||
if repr == "true" || repr == "false" {
|
||||
return Lit::Bool(LitBool {
|
||||
@ -1014,6 +1091,10 @@ mod value {
|
||||
});
|
||||
}
|
||||
}
|
||||
// c"...", cr"...", cr#"..."#
|
||||
// TODO: add a Lit::CStr variant?
|
||||
b'c' => return Lit::Verbatim(token),
|
||||
b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -1061,7 +1142,7 @@ mod value {
|
||||
|
||||
/// 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 {
|
||||
pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 {
|
||||
let s = s.as_ref();
|
||||
if idx < s.len() {
|
||||
s[idx]
|
||||
@ -1075,7 +1156,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns (content, suffix).
|
||||
pub fn parse_lit_str(s: &str) -> (Box<str>, Box<str>) {
|
||||
pub(crate) 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),
|
||||
@ -1101,7 +1182,7 @@ mod value {
|
||||
b'x' => {
|
||||
let (byte, rest) = backslash_x(s);
|
||||
s = rest;
|
||||
assert!(byte <= 0x80, "Invalid \\x byte in string literal");
|
||||
assert!(byte <= 0x7F, "Invalid \\x byte in string literal");
|
||||
char::from_u32(u32::from(byte)).unwrap()
|
||||
}
|
||||
b'u' => {
|
||||
@ -1117,11 +1198,10 @@ mod value {
|
||||
b'\'' => '\'',
|
||||
b'"' => '"',
|
||||
b'\r' | b'\n' => loop {
|
||||
let ch = next_chr(s);
|
||||
if ch.is_whitespace() {
|
||||
s = &s[ch.len_utf8()..];
|
||||
} else {
|
||||
continue 'outer;
|
||||
let b = byte(s, 0);
|
||||
match b {
|
||||
b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..],
|
||||
_ => continue 'outer,
|
||||
}
|
||||
},
|
||||
b => panic!("unexpected byte {:?} after \\ character in byte literal", b),
|
||||
@ -1167,7 +1247,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns (content, suffix).
|
||||
pub fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
|
||||
pub(crate) fn parse_lit_byte_str(s: &str) -> (Vec<u8>, Box<str>) {
|
||||
assert_eq!(byte(s, 0), b'b');
|
||||
match byte(s, 1) {
|
||||
b'"' => parse_lit_byte_str_cooked(s),
|
||||
@ -1209,8 +1289,7 @@ mod value {
|
||||
b'"' => b'"',
|
||||
b'\r' | b'\n' => loop {
|
||||
let byte = byte(v, 0);
|
||||
let ch = char::from_u32(u32::from(byte)).unwrap();
|
||||
if ch.is_whitespace() {
|
||||
if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
|
||||
v = &v[1..];
|
||||
} else {
|
||||
continue 'outer;
|
||||
@ -1244,7 +1323,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns (value, suffix).
|
||||
pub fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
|
||||
pub(crate) fn parse_lit_byte(s: &str) -> (u8, Box<str>) {
|
||||
assert_eq!(byte(s, 0), b'b');
|
||||
assert_eq!(byte(s, 1), b'\'');
|
||||
|
||||
@ -1283,7 +1362,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns (value, suffix).
|
||||
pub fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
|
||||
pub(crate) fn parse_lit_char(mut s: &str) -> (char, Box<str>) {
|
||||
assert_eq!(byte(s, 0), b'\'');
|
||||
s = &s[1..];
|
||||
|
||||
@ -1388,7 +1467,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns base 10 digits and suffix.
|
||||
pub fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
|
||||
pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> {
|
||||
let negative = byte(s, 0) == b'-';
|
||||
if negative {
|
||||
s = &s[1..];
|
||||
@ -1412,6 +1491,7 @@ mod value {
|
||||
};
|
||||
|
||||
let mut value = BigInt::new();
|
||||
let mut has_digit = false;
|
||||
'outer: loop {
|
||||
let b = byte(s, 0);
|
||||
let digit = match b {
|
||||
@ -1455,11 +1535,16 @@ mod value {
|
||||
return None;
|
||||
}
|
||||
|
||||
has_digit = true;
|
||||
value *= base;
|
||||
value += digit;
|
||||
s = &s[1..];
|
||||
}
|
||||
|
||||
if !has_digit {
|
||||
return None;
|
||||
}
|
||||
|
||||
let suffix = s;
|
||||
if suffix.is_empty() || crate::ident::xid_ok(suffix) {
|
||||
let mut repr = value.to_string();
|
||||
@ -1473,7 +1558,7 @@ mod value {
|
||||
}
|
||||
|
||||
// Returns base 10 digits and suffix.
|
||||
pub fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> {
|
||||
pub(crate) 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.
|
||||
@ -1563,38 +1648,4 @@ mod value {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
pub fn to_literal(repr: &str, digits: &str, suffix: &str) -> Option<Literal> {
|
||||
#[cfg(syn_no_negative_literal_parse)]
|
||||
{
|
||||
// Rustc older than https://github.com/rust-lang/rust/pull/87262.
|
||||
if repr.starts_with('-') {
|
||||
let f64_parse_finite = || digits.parse().ok().filter(|x: &f64| x.is_finite());
|
||||
let f32_parse_finite = || digits.parse().ok().filter(|x: &f32| x.is_finite());
|
||||
return if suffix == "f64" {
|
||||
f64_parse_finite().map(Literal::f64_suffixed)
|
||||
} else if suffix == "f32" {
|
||||
f32_parse_finite().map(Literal::f32_suffixed)
|
||||
} else if suffix == "i64" {
|
||||
digits.parse().ok().map(Literal::i64_suffixed)
|
||||
} else if suffix == "i32" {
|
||||
digits.parse().ok().map(Literal::i32_suffixed)
|
||||
} else if suffix == "i16" {
|
||||
digits.parse().ok().map(Literal::i16_suffixed)
|
||||
} else if suffix == "i8" {
|
||||
digits.parse().ok().map(Literal::i8_suffixed)
|
||||
} else if !suffix.is_empty() {
|
||||
None
|
||||
} else if digits.contains('.') {
|
||||
f64_parse_finite().map(Literal::f64_unsuffixed)
|
||||
} else {
|
||||
digits.parse().ok().map(Literal::i64_unsuffixed)
|
||||
};
|
||||
}
|
||||
}
|
||||
let _ = digits;
|
||||
let _ = suffix;
|
||||
Some(repr.parse::<Literal>().unwrap())
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ use std::cell::RefCell;
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam};
|
||||
/// use syn::{ConstParam, Ident, Lifetime, LifetimeParam, Result, Token, TypeParam};
|
||||
/// use syn::parse::{Parse, ParseStream};
|
||||
///
|
||||
/// // A generic parameter, a single one of the comma-separated elements inside
|
||||
@ -40,7 +40,7 @@ use std::cell::RefCell;
|
||||
/// // | ^
|
||||
/// enum GenericParam {
|
||||
/// Type(TypeParam),
|
||||
/// Lifetime(LifetimeDef),
|
||||
/// Lifetime(LifetimeParam),
|
||||
/// Const(ConstParam),
|
||||
/// }
|
||||
///
|
||||
@ -65,7 +65,7 @@ pub struct Lookahead1<'a> {
|
||||
comparisons: RefCell<Vec<&'static str>>,
|
||||
}
|
||||
|
||||
pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 {
|
||||
pub(crate) fn new(scope: Span, cursor: Cursor) -> Lookahead1 {
|
||||
Lookahead1 {
|
||||
scope,
|
||||
cursor,
|
||||
@ -162,7 +162,7 @@ impl<S> IntoSpans<S> for TokenMarker {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool {
|
||||
pub(crate) fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool {
|
||||
cursor.group(delimiter).is_some()
|
||||
}
|
||||
|
||||
|
64
src/mac.rs
64
src/mac.rs
@ -1,17 +1,17 @@
|
||||
use super::*;
|
||||
use crate::token::{Brace, Bracket, Paren};
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
#[cfg(any(feature = "parsing", feature = "printing"))]
|
||||
use proc_macro2::Delimiter;
|
||||
use proc_macro2::TokenStream;
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::{Delimiter, Group, Span, TokenTree};
|
||||
use proc_macro2::TokenTree;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream, Parser, Result};
|
||||
|
||||
ast_struct! {
|
||||
/// A macro invocation: `println!("{}", mac)`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Macro {
|
||||
pub path: Path,
|
||||
@ -23,9 +23,6 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum MacroDelimiter {
|
||||
Paren(Paren),
|
||||
@ -34,20 +31,14 @@ ast_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span {
|
||||
let delimiter = match macro_delimiter {
|
||||
MacroDelimiter::Paren(_) => Delimiter::Parenthesis,
|
||||
MacroDelimiter::Brace(_) => Delimiter::Brace,
|
||||
MacroDelimiter::Bracket(_) => Delimiter::Bracket,
|
||||
};
|
||||
let mut group = Group::new(delimiter, TokenStream::new());
|
||||
group.set_span(match macro_delimiter {
|
||||
MacroDelimiter::Paren(token) => token.span,
|
||||
MacroDelimiter::Brace(token) => token.span,
|
||||
MacroDelimiter::Bracket(token) => token.span,
|
||||
});
|
||||
group.span_close()
|
||||
impl MacroDelimiter {
|
||||
pub fn span(&self) -> &DelimSpan {
|
||||
match self {
|
||||
MacroDelimiter::Paren(token) => &token.span,
|
||||
MacroDelimiter::Brace(token) => &token.span,
|
||||
MacroDelimiter::Bracket(token) => &token.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Macro {
|
||||
@ -144,16 +135,16 @@ impl Macro {
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
||||
let scope = delimiter_span_close(&self.delimiter);
|
||||
let scope = self.delimiter.span().close();
|
||||
crate::parse::parse_scoped(parser, scope, self.tokens.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
|
||||
pub(crate) 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 span = g.delim_span();
|
||||
let delimiter = match g.delimiter() {
|
||||
Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
|
||||
Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
|
||||
@ -170,7 +161,7 @@ pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStrea
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
@ -198,22 +189,23 @@ mod printing {
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
impl MacroDelimiter {
|
||||
pub(crate) fn surround(&self, tokens: &mut TokenStream, inner: TokenStream) {
|
||||
let (delim, span) = match self {
|
||||
MacroDelimiter::Paren(paren) => (Delimiter::Parenthesis, paren.span),
|
||||
MacroDelimiter::Brace(brace) => (Delimiter::Brace, brace.span),
|
||||
MacroDelimiter::Bracket(bracket) => (Delimiter::Bracket, bracket.span),
|
||||
};
|
||||
token::printing::delim(delim, span.join(), tokens, inner);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
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));
|
||||
}
|
||||
}
|
||||
self.delimiter.surround(tokens, self.tokens.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,17 @@
|
||||
)]
|
||||
macro_rules! ast_struct {
|
||||
(
|
||||
[$($attrs_pub:tt)*]
|
||||
struct $name:ident #full $($rest:tt)*
|
||||
$(#[$attr:meta])*
|
||||
$pub:ident $struct:ident $name:ident #full $body:tt
|
||||
) => {
|
||||
check_keyword_matches!(pub $pub);
|
||||
check_keyword_matches!(struct $struct);
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
$($attrs_pub)* struct $name $($rest)*
|
||||
$(#[$attr])* $pub $struct $name $body
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
$($attrs_pub)* struct $name {
|
||||
$(#[$attr])* $pub $struct $name {
|
||||
_noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>,
|
||||
}
|
||||
|
||||
@ -24,35 +27,26 @@ macro_rules! ast_struct {
|
||||
};
|
||||
|
||||
(
|
||||
[$($attrs_pub:tt)*]
|
||||
struct $name:ident $($rest:tt)*
|
||||
$(#[$attr:meta])*
|
||||
$pub:ident $struct:ident $name:ident $body:tt
|
||||
) => {
|
||||
$($attrs_pub)* struct $name $($rest)*
|
||||
};
|
||||
check_keyword_matches!(pub $pub);
|
||||
check_keyword_matches!(struct $struct);
|
||||
|
||||
($($t:tt)*) => {
|
||||
strip_attrs_pub!(ast_struct!($($t)*));
|
||||
$(#[$attr])* $pub $struct $name $body
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
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)*);
|
||||
);
|
||||
$(#[$enum_attr:meta])*
|
||||
$pub:ident $enum:ident $name:ident $body:tt
|
||||
) => {
|
||||
check_keyword_matches!(pub $pub);
|
||||
check_keyword_matches!(enum $enum);
|
||||
|
||||
(
|
||||
[$($attrs_pub:tt)*]
|
||||
enum $name:ident $($rest:tt)*
|
||||
) => (
|
||||
$($attrs_pub)* enum $name $($rest)*
|
||||
);
|
||||
|
||||
($($t:tt)*) => {
|
||||
strip_attrs_pub!(ast_enum!($($t)*));
|
||||
$(#[$enum_attr])* $pub $enum $name $body
|
||||
};
|
||||
}
|
||||
|
||||
@ -60,35 +54,32 @@ macro_rules! ast_enum_of_structs {
|
||||
(
|
||||
$(#[$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)*);
|
||||
check_keyword_matches!(pub $pub);
|
||||
check_keyword_matches!(enum $enum);
|
||||
|
||||
$(#[$enum_attr])* $pub $enum $name $body
|
||||
|
||||
ast_enum_of_structs_impl!($name $body);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! ast_enum_of_structs_impl {
|
||||
(
|
||||
$pub:ident $enum:ident $name:ident {
|
||||
$name:ident {
|
||||
$(
|
||||
$(#[cfg $cfg_attr:tt])*
|
||||
$(#[doc $($doc_attr:tt)*])*
|
||||
$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 {
|
||||
@ -116,13 +107,7 @@ macro_rules! ast_enum_from_struct {
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(
|
||||
not(any(feature = "full", feature = "derive")),
|
||||
allow(unknown_lints, unused_macro_rules)
|
||||
)]
|
||||
macro_rules! generate_to_tokens {
|
||||
(do_not_generate_to_tokens $($foo:tt)*) => ();
|
||||
|
||||
(
|
||||
($($arms:tt)*) $tokens:ident $name:ident {
|
||||
$(#[cfg $cfg_attr:tt])*
|
||||
@ -163,15 +148,29 @@ macro_rules! generate_to_tokens {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! strip_attrs_pub {
|
||||
($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
|
||||
// Rustdoc bug: does not respect the doc(hidden) on some items.
|
||||
#[cfg(all(doc, feature = "parsing"))]
|
||||
macro_rules! pub_if_not_doc {
|
||||
($(#[$m:meta])* $pub:ident $($item:tt)*) => {
|
||||
check_keyword_matches!(pub $pub);
|
||||
|
||||
$mac!([$(#[$m])* $pub] $($t)*);
|
||||
$(#[$m])*
|
||||
$pub(crate) $($item)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(all(not(doc), feature = "parsing"))]
|
||||
macro_rules! pub_if_not_doc {
|
||||
($(#[$m:meta])* $pub:ident $($item:tt)*) => {
|
||||
check_keyword_matches!(pub $pub);
|
||||
|
||||
$(#[$m])*
|
||||
$pub $($item)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! check_keyword_matches {
|
||||
(enum enum) => {};
|
||||
(pub pub) => {};
|
||||
(struct struct) => {};
|
||||
}
|
||||
|
426
src/meta.rs
Normal file
426
src/meta.rs
Normal file
@ -0,0 +1,426 @@
|
||||
//! Facility for interpreting structured content inside of an `Attribute`.
|
||||
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::lit::Lit;
|
||||
use crate::parse::{Error, ParseStream, Parser, Result};
|
||||
use crate::path::{Path, PathSegment};
|
||||
use crate::punctuated::Punctuated;
|
||||
use proc_macro2::Ident;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Make a parser that is usable with `parse_macro_input!` in a
|
||||
/// `#[proc_macro_attribute]` macro.
|
||||
///
|
||||
/// *Warning:* When parsing attribute args **other than** the
|
||||
/// `proc_macro::TokenStream` input of a `proc_macro_attribute`, you do **not**
|
||||
/// need this function. In several cases your callers will get worse error
|
||||
/// messages if you use this function, because the surrounding delimiter's span
|
||||
/// is concealed from attribute macros by rustc. Use
|
||||
/// [`Attribute::parse_nested_meta`] instead.
|
||||
///
|
||||
/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example implements an attribute macro whose invocations look like this:
|
||||
///
|
||||
/// ```
|
||||
/// # const IGNORE: &str = stringify! {
|
||||
/// #[tea(kind = "EarlGrey", hot)]
|
||||
/// struct Picard {...}
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// The "parameters" supported by the attribute are:
|
||||
///
|
||||
/// - `kind = "..."`
|
||||
/// - `hot`
|
||||
/// - `with(sugar, milk, ...)`, a comma-separated list of ingredients
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate proc_macro;
|
||||
/// #
|
||||
/// use proc_macro::TokenStream;
|
||||
/// use syn::{parse_macro_input, LitStr, Path};
|
||||
///
|
||||
/// # const IGNORE: &str = stringify! {
|
||||
/// #[proc_macro_attribute]
|
||||
/// # };
|
||||
/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
/// let mut kind: Option<LitStr> = None;
|
||||
/// let mut hot: bool = false;
|
||||
/// let mut with: Vec<Path> = Vec::new();
|
||||
/// let tea_parser = syn::meta::parser(|meta| {
|
||||
/// if meta.path.is_ident("kind") {
|
||||
/// kind = Some(meta.value()?.parse()?);
|
||||
/// Ok(())
|
||||
/// } else if meta.path.is_ident("hot") {
|
||||
/// hot = true;
|
||||
/// Ok(())
|
||||
/// } else if meta.path.is_ident("with") {
|
||||
/// meta.parse_nested_meta(|meta| {
|
||||
/// with.push(meta.path);
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported tea property"))
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// parse_macro_input!(args with tea_parser);
|
||||
/// eprintln!("kind={kind:?} hot={hot} with={with:?}");
|
||||
///
|
||||
/// /* ... */
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `syn::meta` library will take care of dealing with the commas including
|
||||
/// trailing commas, and producing sensible error messages on unexpected input.
|
||||
///
|
||||
/// ```console
|
||||
/// error: expected `,`
|
||||
/// --> src/main.rs:3:37
|
||||
/// |
|
||||
/// 3 | #[tea(kind = "EarlGrey", with(sugar = "lol", milk))]
|
||||
/// | ^
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Same as above but we factor out most of the logic into a separate function.
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate proc_macro;
|
||||
/// #
|
||||
/// use proc_macro::TokenStream;
|
||||
/// use syn::meta::ParseNestedMeta;
|
||||
/// use syn::parse::{Parser, Result};
|
||||
/// use syn::{parse_macro_input, LitStr, Path};
|
||||
///
|
||||
/// # const IGNORE: &str = stringify! {
|
||||
/// #[proc_macro_attribute]
|
||||
/// # };
|
||||
/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
/// let mut attrs = TeaAttributes::default();
|
||||
/// let tea_parser = syn::meta::parser(|meta| attrs.parse(meta));
|
||||
/// parse_macro_input!(args with tea_parser);
|
||||
///
|
||||
/// /* ... */
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// struct TeaAttributes {
|
||||
/// kind: Option<LitStr>,
|
||||
/// hot: bool,
|
||||
/// with: Vec<Path>,
|
||||
/// }
|
||||
///
|
||||
/// impl TeaAttributes {
|
||||
/// fn parse(&mut self, meta: ParseNestedMeta) -> Result<()> {
|
||||
/// if meta.path.is_ident("kind") {
|
||||
/// self.kind = Some(meta.value()?.parse()?);
|
||||
/// Ok(())
|
||||
/// } else /* just like in last example */
|
||||
/// # { unimplemented!() }
|
||||
///
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn parser(logic: impl FnMut(ParseNestedMeta) -> Result<()>) -> impl Parser<Output = ()> {
|
||||
|input: ParseStream| {
|
||||
if input.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
parse_nested_meta(input, logic)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for parsing a single property in the conventional syntax for
|
||||
/// structured attributes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Refer to usage examples on the following two entry-points:
|
||||
///
|
||||
/// - [`Attribute::parse_nested_meta`] if you have an entire `Attribute` to
|
||||
/// parse. Always use this if possible. Generally this is able to produce
|
||||
/// better error messages because `Attribute` holds span information for all
|
||||
/// of the delimiters therein.
|
||||
///
|
||||
/// - [`syn::meta::parser`] if you are implementing a `proc_macro_attribute`
|
||||
/// macro and parsing the arguments to the attribute macro, i.e. the ones
|
||||
/// written in the same attribute that dispatched the macro invocation. Rustc
|
||||
/// does not pass span information for the surrounding delimiters into the
|
||||
/// attribute macro invocation in this situation, so error messages might be
|
||||
/// less precise.
|
||||
///
|
||||
/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta
|
||||
/// [`syn::meta::parser`]: crate::meta::parser
|
||||
#[non_exhaustive]
|
||||
pub struct ParseNestedMeta<'a> {
|
||||
pub path: Path,
|
||||
pub input: ParseStream<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ParseNestedMeta<'a> {
|
||||
/// Used when parsing `key = "value"` syntax.
|
||||
///
|
||||
/// All it does is advance `meta.input` past the `=` sign in the input. You
|
||||
/// could accomplish the same effect by writing
|
||||
/// `meta.parse::<Token![=]>()?`, so at most it is a minor convenience to
|
||||
/// use `meta.value()?`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parse_quote, Attribute, LitStr};
|
||||
///
|
||||
/// let attr: Attribute = parse_quote! {
|
||||
/// #[tea(kind = "EarlGrey")]
|
||||
/// };
|
||||
/// // conceptually:
|
||||
/// if attr.path().is_ident("tea") { // this parses the `tea`
|
||||
/// attr.parse_nested_meta(|meta| { // this parses the `(`
|
||||
/// if meta.path.is_ident("kind") { // this parses the `kind`
|
||||
/// let value = meta.value()?; // this parses the `=`
|
||||
/// let s: LitStr = value.parse()?; // this parses `"EarlGrey"`
|
||||
/// if s.value() == "EarlGrey" {
|
||||
/// // ...
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported attribute"))
|
||||
/// }
|
||||
/// })?;
|
||||
/// }
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
pub fn value(&self) -> Result<ParseStream<'a>> {
|
||||
self.input.parse::<Token![=]>()?;
|
||||
Ok(self.input)
|
||||
}
|
||||
|
||||
/// Used when parsing `list(...)` syntax **if** the content inside the
|
||||
/// nested parentheses is also expected to conform to Rust's structured
|
||||
/// attribute convention.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parse_quote, Attribute};
|
||||
///
|
||||
/// let attr: Attribute = parse_quote! {
|
||||
/// #[tea(with(sugar, milk))]
|
||||
/// };
|
||||
///
|
||||
/// if attr.path().is_ident("tea") {
|
||||
/// attr.parse_nested_meta(|meta| {
|
||||
/// if meta.path.is_ident("with") {
|
||||
/// meta.parse_nested_meta(|meta| { // <---
|
||||
/// if meta.path.is_ident("sugar") {
|
||||
/// // Here we can go even deeper if needed.
|
||||
/// Ok(())
|
||||
/// } else if meta.path.is_ident("milk") {
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported ingredient"))
|
||||
/// }
|
||||
/// })
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported tea property"))
|
||||
/// }
|
||||
/// })?;
|
||||
/// }
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
///
|
||||
/// # Counterexample
|
||||
///
|
||||
/// If you don't need `parse_nested_meta`'s help in parsing the content
|
||||
/// written within the nested parentheses, keep in mind that you can always
|
||||
/// just parse it yourself from the exposed ParseStream. Rust syntax permits
|
||||
/// arbitrary tokens within those parentheses so for the crazier stuff,
|
||||
/// `parse_nested_meta` is not what you want.
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{parenthesized, parse_quote, Attribute, LitInt};
|
||||
///
|
||||
/// let attr: Attribute = parse_quote! {
|
||||
/// #[repr(align(32))]
|
||||
/// };
|
||||
///
|
||||
/// let mut align: Option<LitInt> = None;
|
||||
/// if attr.path().is_ident("repr") {
|
||||
/// attr.parse_nested_meta(|meta| {
|
||||
/// if meta.path.is_ident("align") {
|
||||
/// let content;
|
||||
/// parenthesized!(content in meta.input);
|
||||
/// align = Some(content.parse()?);
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported repr"))
|
||||
/// }
|
||||
/// })?;
|
||||
/// }
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
pub fn parse_nested_meta(
|
||||
&self,
|
||||
logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
let content;
|
||||
parenthesized!(content in self.input);
|
||||
parse_nested_meta(&content, logic)
|
||||
}
|
||||
|
||||
/// Report that the attribute's content did not conform to expectations.
|
||||
///
|
||||
/// The span of the resulting error will cover `meta.path` *and* everything
|
||||
/// that has been parsed so far since it.
|
||||
///
|
||||
/// There are 2 ways you might call this. First, if `meta.path` is not
|
||||
/// something you recognize:
|
||||
///
|
||||
/// ```
|
||||
/// # use syn::Attribute;
|
||||
/// #
|
||||
/// # fn example(attr: &Attribute) -> syn::Result<()> {
|
||||
/// attr.parse_nested_meta(|meta| {
|
||||
/// if meta.path.is_ident("kind") {
|
||||
/// // ...
|
||||
/// Ok(())
|
||||
/// } else {
|
||||
/// Err(meta.error("unsupported tea property"))
|
||||
/// }
|
||||
/// })?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// In this case, it behaves exactly like
|
||||
/// `syn::Error::new_spanned(&meta.path, "message...")`.
|
||||
///
|
||||
/// ```console
|
||||
/// error: unsupported tea property
|
||||
/// --> src/main.rs:3:26
|
||||
/// |
|
||||
/// 3 | #[tea(kind = "EarlGrey", wat = "foo")]
|
||||
/// | ^^^
|
||||
/// ```
|
||||
///
|
||||
/// More usefully, the second place is if you've already parsed a value but
|
||||
/// have decided not to accept the value:
|
||||
///
|
||||
/// ```
|
||||
/// # use syn::Attribute;
|
||||
/// #
|
||||
/// # fn example(attr: &Attribute) -> syn::Result<()> {
|
||||
/// use syn::Expr;
|
||||
///
|
||||
/// attr.parse_nested_meta(|meta| {
|
||||
/// if meta.path.is_ident("kind") {
|
||||
/// let expr: Expr = meta.value()?.parse()?;
|
||||
/// match expr {
|
||||
/// Expr::Lit(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// Expr::Path(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// Expr::Macro(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// _ => Err(meta.error("tea kind must be a string literal, path, or macro")),
|
||||
/// }
|
||||
/// } else /* as above */
|
||||
/// # { unimplemented!() }
|
||||
///
|
||||
/// })?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ```console
|
||||
/// error: tea kind must be a string literal, path, or macro
|
||||
/// --> src/main.rs:3:7
|
||||
/// |
|
||||
/// 3 | #[tea(kind = async { replicator.await })]
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// Often you may want to use `syn::Error::new_spanned` even in this
|
||||
/// situation. In the above code, that would be:
|
||||
///
|
||||
/// ```
|
||||
/// # use syn::{Error, Expr};
|
||||
/// #
|
||||
/// # fn example(expr: Expr) -> syn::Result<()> {
|
||||
/// match expr {
|
||||
/// Expr::Lit(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// Expr::Path(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// Expr::Macro(expr) => /* ... */
|
||||
/// # unimplemented!(),
|
||||
/// _ => Err(Error::new_spanned(expr, "unsupported expression type for `kind`")),
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// ```console
|
||||
/// error: unsupported expression type for `kind`
|
||||
/// --> src/main.rs:3:14
|
||||
/// |
|
||||
/// 3 | #[tea(kind = async { replicator.await })]
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
pub fn error(&self, msg: impl Display) -> Error {
|
||||
let start_span = self.path.segments[0].ident.span();
|
||||
let end_span = self.input.cursor().prev_span();
|
||||
crate::error::new2(start_span, end_span, msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_nested_meta(
|
||||
input: ParseStream,
|
||||
mut logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let path = input.call(parse_meta_path)?;
|
||||
logic(ParseNestedMeta { path, input })?;
|
||||
if input.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
input.parse::<Token![,]>()?;
|
||||
if input.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
if input.peek(Ident::peek_any) {
|
||||
let ident = Ident::parse_any(input)?;
|
||||
segments.push_value(PathSegment::from(ident));
|
||||
} else if input.is_empty() {
|
||||
return Err(input.error("expected nested attribute"));
|
||||
} else if input.peek(Lit) {
|
||||
return Err(input.error("unexpected literal in nested attribute, expected ident"));
|
||||
} else {
|
||||
return Err(input.error("unexpected token in nested attribute, expected ident"));
|
||||
}
|
||||
while input.peek(Token![::]) {
|
||||
let punct = input.parse()?;
|
||||
segments.push_punct(punct);
|
||||
let ident = Ident::parse_any(input)?;
|
||||
segments.push_value(PathSegment::from(ident));
|
||||
}
|
||||
segments
|
||||
},
|
||||
})
|
||||
}
|
156
src/op.rs
156
src/op.rs
@ -1,9 +1,7 @@
|
||||
ast_enum! {
|
||||
/// A binary operator: `+`, `+=`, `&`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum BinOp {
|
||||
/// The `+` operator (addition)
|
||||
Add(Token![+]),
|
||||
@ -42,34 +40,32 @@ ast_enum! {
|
||||
/// The `>` operator (greater than)
|
||||
Gt(Token![>]),
|
||||
/// The `+=` operator
|
||||
AddEq(Token![+=]),
|
||||
AddAssign(Token![+=]),
|
||||
/// The `-=` operator
|
||||
SubEq(Token![-=]),
|
||||
SubAssign(Token![-=]),
|
||||
/// The `*=` operator
|
||||
MulEq(Token![*=]),
|
||||
MulAssign(Token![*=]),
|
||||
/// The `/=` operator
|
||||
DivEq(Token![/=]),
|
||||
DivAssign(Token![/=]),
|
||||
/// The `%=` operator
|
||||
RemEq(Token![%=]),
|
||||
RemAssign(Token![%=]),
|
||||
/// The `^=` operator
|
||||
BitXorEq(Token![^=]),
|
||||
BitXorAssign(Token![^=]),
|
||||
/// The `&=` operator
|
||||
BitAndEq(Token![&=]),
|
||||
BitAndAssign(Token![&=]),
|
||||
/// The `|=` operator
|
||||
BitOrEq(Token![|=]),
|
||||
BitOrAssign(Token![|=]),
|
||||
/// The `<<=` operator
|
||||
ShlEq(Token![<<=]),
|
||||
ShlAssign(Token![<<=]),
|
||||
/// The `>>=` operator
|
||||
ShrEq(Token![>>=]),
|
||||
ShrAssign(Token![>>=]),
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum! {
|
||||
/// A unary operator: `*`, `!`, `-`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum UnOp {
|
||||
/// The `*` operator for dereferencing
|
||||
Deref(Token![*]),
|
||||
@ -81,83 +77,71 @@ ast_enum! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) 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"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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)
|
||||
input.parse().map(BinOp::AddAssign)
|
||||
} else if input.peek(Token![-=]) {
|
||||
input.parse().map(BinOp::SubEq)
|
||||
input.parse().map(BinOp::SubAssign)
|
||||
} else if input.peek(Token![*=]) {
|
||||
input.parse().map(BinOp::MulEq)
|
||||
input.parse().map(BinOp::MulAssign)
|
||||
} else if input.peek(Token![/=]) {
|
||||
input.parse().map(BinOp::DivEq)
|
||||
input.parse().map(BinOp::DivAssign)
|
||||
} else if input.peek(Token![%=]) {
|
||||
input.parse().map(BinOp::RemEq)
|
||||
input.parse().map(BinOp::RemAssign)
|
||||
} else if input.peek(Token![^=]) {
|
||||
input.parse().map(BinOp::BitXorEq)
|
||||
input.parse().map(BinOp::BitXorAssign)
|
||||
} else if input.peek(Token![&=]) {
|
||||
input.parse().map(BinOp::BitAndEq)
|
||||
input.parse().map(BinOp::BitAndAssign)
|
||||
} else if input.peek(Token![|=]) {
|
||||
input.parse().map(BinOp::BitOrEq)
|
||||
input.parse().map(BinOp::BitOrAssign)
|
||||
} else if input.peek(Token![<<=]) {
|
||||
input.parse().map(BinOp::ShlEq)
|
||||
input.parse().map(BinOp::ShlAssign)
|
||||
} else if input.peek(Token![>>=]) {
|
||||
input.parse().map(BinOp::ShrEq)
|
||||
input.parse().map(BinOp::ShrAssign)
|
||||
} else 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 {
|
||||
parse_binop(input)
|
||||
Err(input.error("expected binary operator"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,16 +191,16 @@ mod printing {
|
||||
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),
|
||||
BinOp::AddAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::SubAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::MulAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::DivAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::RemAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::BitXorAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::BitAndAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::BitOrAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::ShlAssign(t) => t.to_tokens(tokens),
|
||||
BinOp::ShrAssign(t) => t.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
168
src/parse.rs
168
src/parse.rs
@ -66,7 +66,7 @@
|
||||
//! struct_token: input.parse()?,
|
||||
//! ident: input.parse()?,
|
||||
//! brace_token: braced!(content in input),
|
||||
//! fields: content.parse_terminated(Field::parse_named)?,
|
||||
//! fields: content.parse_terminated(Field::parse_named, Token![,])?,
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
@ -84,7 +84,7 @@
|
||||
//! let input = parse_macro_input!(tokens as Item);
|
||||
//!
|
||||
//! /* ... */
|
||||
//! # "".parse().unwrap()
|
||||
//! # TokenStream::new()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
@ -178,10 +178,6 @@
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! *This module is available only if Syn is built with the `"parsing"` feature.*
|
||||
|
||||
#[path = "discouraged.rs"]
|
||||
pub mod discouraged;
|
||||
@ -189,10 +185,7 @@ pub mod discouraged;
|
||||
use crate::buffer::{Cursor, TokenBuffer};
|
||||
use crate::error;
|
||||
use crate::lookahead;
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "wasi"))),
|
||||
feature = "proc-macro"
|
||||
))]
|
||||
#[cfg(feature = "proc-macro")]
|
||||
use crate::proc_macro;
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token::Token;
|
||||
@ -520,8 +513,8 @@ impl<'a> ParseBuffer<'a> {
|
||||
///
|
||||
/// - `input.peek(Token![struct])`
|
||||
/// - `input.peek(Token![==])`
|
||||
/// - `input.peek(Ident)` *(does not accept keywords)*
|
||||
/// - `input.peek(Ident::peek_any)`
|
||||
/// - `input.peek(syn::Ident)` *(does not accept keywords)*
|
||||
/// - `input.peek(syn::Ident::peek_any)`
|
||||
/// - `input.peek(Lifetime)`
|
||||
/// - `input.peek(token::Brace)`
|
||||
///
|
||||
@ -685,7 +678,7 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// struct_token: input.parse()?,
|
||||
/// ident: input.parse()?,
|
||||
/// paren_token: parenthesized!(content in input),
|
||||
/// fields: content.parse_terminated(Type::parse)?,
|
||||
/// fields: content.parse_terminated(Type::parse, Token![,])?,
|
||||
/// semi_token: input.parse()?,
|
||||
/// })
|
||||
/// }
|
||||
@ -696,10 +689,63 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// # };
|
||||
/// # syn::parse2::<TupleStruct>(input).unwrap();
|
||||
/// ```
|
||||
pub fn parse_terminated<T, P: Parse>(
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// If your separator is anything more complicated than an invocation of the
|
||||
/// `Token!` macro, this method won't be applicable and you can instead
|
||||
/// directly use `Punctuated`'s parser functions: [`parse_terminated`],
|
||||
/// [`parse_separated_nonempty`] etc.
|
||||
///
|
||||
/// [`parse_terminated`]: Punctuated::parse_terminated
|
||||
/// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{custom_keyword, Expr, Result, Token};
|
||||
/// use syn::parse::{Parse, ParseStream};
|
||||
/// use syn::punctuated::Punctuated;
|
||||
///
|
||||
/// mod kw {
|
||||
/// syn::custom_keyword!(fin);
|
||||
/// }
|
||||
///
|
||||
/// struct Fin(kw::fin, Token![;]);
|
||||
///
|
||||
/// impl Parse for Fin {
|
||||
/// fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// Ok(Self(input.parse()?, input.parse()?))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// struct Thing {
|
||||
/// steps: Punctuated<Expr, Fin>,
|
||||
/// }
|
||||
///
|
||||
/// impl Parse for Thing {
|
||||
/// fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// # if true {
|
||||
/// Ok(Thing {
|
||||
/// steps: Punctuated::parse_terminated(input)?,
|
||||
/// })
|
||||
/// # } else {
|
||||
/// // or equivalently, this means the same thing:
|
||||
/// # Ok(Thing {
|
||||
/// steps: input.call(Punctuated::parse_terminated)?,
|
||||
/// # })
|
||||
/// # }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn parse_terminated<T, P>(
|
||||
&self,
|
||||
parser: fn(ParseStream) -> Result<T>,
|
||||
) -> Result<Punctuated<T, P>> {
|
||||
separator: P,
|
||||
) -> Result<Punctuated<T, P::Token>>
|
||||
where
|
||||
P: Peek,
|
||||
P::Token: Parse,
|
||||
{
|
||||
let _ = separator;
|
||||
Punctuated::parse_terminated_with(self, parser)
|
||||
}
|
||||
|
||||
@ -750,7 +796,7 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam};
|
||||
/// use syn::{ConstParam, Ident, Lifetime, LifetimeParam, Result, Token, TypeParam};
|
||||
/// use syn::parse::{Parse, ParseStream};
|
||||
///
|
||||
/// // A generic parameter, a single one of the comma-separated elements inside
|
||||
@ -766,7 +812,7 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// // | ^
|
||||
/// enum GenericParam {
|
||||
/// Type(TypeParam),
|
||||
/// Lifetime(LifetimeDef),
|
||||
/// Lifetime(LifetimeParam),
|
||||
/// Const(ConstParam),
|
||||
/// }
|
||||
///
|
||||
@ -1050,6 +1096,58 @@ impl<'a> ParseBuffer<'a> {
|
||||
///
|
||||
/// Cursors are immutable so no operations you perform against the cursor
|
||||
/// will affect the state of this parse stream.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use proc_macro2::TokenStream;
|
||||
/// use syn::buffer::Cursor;
|
||||
/// use syn::parse::{ParseStream, Result};
|
||||
///
|
||||
/// // Run a parser that returns T, but get its output as TokenStream instead of T.
|
||||
/// // This works without T needing to implement ToTokens.
|
||||
/// fn recognize_token_stream<T>(
|
||||
/// recognizer: fn(ParseStream) -> Result<T>,
|
||||
/// ) -> impl Fn(ParseStream) -> Result<TokenStream> {
|
||||
/// move |input| {
|
||||
/// let begin = input.cursor();
|
||||
/// recognizer(input)?;
|
||||
/// let end = input.cursor();
|
||||
/// Ok(tokens_between(begin, end))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Collect tokens between two cursors as a TokenStream.
|
||||
/// fn tokens_between(begin: Cursor, end: Cursor) -> TokenStream {
|
||||
/// assert!(begin <= end);
|
||||
///
|
||||
/// let mut cursor = begin;
|
||||
/// let mut tokens = TokenStream::new();
|
||||
/// while cursor < end {
|
||||
/// let (token, next) = cursor.token_tree().unwrap();
|
||||
/// tokens.extend(std::iter::once(token));
|
||||
/// cursor = next;
|
||||
/// }
|
||||
/// tokens
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// use quote::quote;
|
||||
/// use syn::parse::{Parse, Parser};
|
||||
/// use syn::Token;
|
||||
///
|
||||
/// // Parse syn::Type as a TokenStream, surrounded by angle brackets.
|
||||
/// fn example(input: ParseStream) -> Result<TokenStream> {
|
||||
/// let _langle: Token![<] = input.parse()?;
|
||||
/// let ty = recognize_token_stream(syn::Type::parse)(input)?;
|
||||
/// let _rangle: Token![>] = input.parse()?;
|
||||
/// Ok(ty)
|
||||
/// }
|
||||
///
|
||||
/// let tokens = quote! { <fn() -> u8> };
|
||||
/// println!("{}", example.parse2(tokens).unwrap());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn cursor(&self) -> Cursor<'a> {
|
||||
self.cell.get()
|
||||
}
|
||||
@ -1101,10 +1199,8 @@ impl Parse for TokenTree {
|
||||
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);
|
||||
if let Some((group, rest)) = cursor.any_group_token() {
|
||||
if group.delimiter() != Delimiter::None {
|
||||
return Ok((group, rest));
|
||||
}
|
||||
}
|
||||
@ -1138,8 +1234,6 @@ impl Parse for Literal {
|
||||
/// Refer to the [module documentation] for details about parsing in Syn.
|
||||
///
|
||||
/// [module documentation]: self
|
||||
///
|
||||
/// *This trait is available only if Syn is built with the `"parsing"` feature.*
|
||||
pub trait Parser: Sized {
|
||||
type Output;
|
||||
|
||||
@ -1153,13 +1247,8 @@ pub trait Parser: Sized {
|
||||
///
|
||||
/// 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 only 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"
|
||||
))]
|
||||
#[cfg(feature = "proc-macro")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
|
||||
fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> {
|
||||
self.parse2(proc_macro2::TokenStream::from(tokens))
|
||||
}
|
||||
@ -1184,13 +1273,6 @@ pub trait Parser: Sized {
|
||||
let _ = scope;
|
||||
self.parse2(tokens)
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
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 {
|
||||
@ -1232,11 +1314,6 @@ where
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
fn __parse_stream(self, input: ParseStream) -> Result<Self::Output> {
|
||||
self(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
@ -1244,11 +1321,6 @@ pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) ->
|
||||
f.__parse_scoped(scope, tokens)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
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
|
||||
@ -1268,7 +1340,7 @@ pub(crate) fn parse_stream<F: Parser>(f: F, input: ParseStream) -> Result<F::Out
|
||||
/// parse_macro_input!(args as Nothing);
|
||||
///
|
||||
/// /* ... */
|
||||
/// # "".parse().unwrap()
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
@ -40,7 +40,7 @@
|
||||
/// let input = parse_macro_input!(tokens as MyMacroInput);
|
||||
///
|
||||
/// /* ... */
|
||||
/// # "".parse().unwrap()
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
@ -76,7 +76,7 @@
|
||||
/// let input = parse_macro_input!(tokens with MyMacroInput::parse_alternate);
|
||||
///
|
||||
/// /* ... */
|
||||
/// # "".parse().unwrap()
|
||||
/// # TokenStream::new()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
@ -107,7 +107,7 @@
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
|
||||
macro_rules! parse_macro_input {
|
||||
($tokenstream:ident as $ty:ty) => {
|
||||
match $crate::parse_macro_input::parse::<$ty>($tokenstream) {
|
||||
match $crate::parse::<$ty>($tokenstream) {
|
||||
$crate::__private::Ok(data) => data,
|
||||
$crate::__private::Err(err) => {
|
||||
return $crate::__private::TokenStream::from(err.to_compile_error());
|
||||
@ -126,54 +126,3 @@ macro_rules! parse_macro_input {
|
||||
$crate::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)
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,8 @@
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// *This macro is available only 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.*
|
||||
/// *This macro is available only if Syn is built with both the `"parsing"` and
|
||||
/// `"printing"` features.*
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -69,7 +68,7 @@
|
||||
#[macro_export]
|
||||
macro_rules! parse_quote {
|
||||
($($tt:tt)*) => {
|
||||
$crate::parse_quote::parse($crate::__private::quote::quote!($($tt)*))
|
||||
$crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
|
||||
};
|
||||
}
|
||||
|
||||
@ -101,7 +100,7 @@ macro_rules! parse_quote {
|
||||
#[macro_export]
|
||||
macro_rules! parse_quote_spanned {
|
||||
($span:expr=> $($tt:tt)*) => {
|
||||
$crate::parse_quote::parse($crate::__private::quote::quote_spanned!($span=> $($tt)*))
|
||||
$crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
|
||||
};
|
||||
}
|
||||
|
||||
@ -121,7 +120,6 @@ pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub trait ParseQuote: Sized {
|
||||
fn parse(input: ParseStream) -> Result<Self>;
|
||||
@ -138,9 +136,9 @@ impl<T: Parse> ParseQuote for T {
|
||||
|
||||
use crate::punctuated::Punctuated;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::{attr, Attribute};
|
||||
use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::{Block, Stmt};
|
||||
use crate::{Block, Pat, Stmt};
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl ParseQuote for Attribute {
|
||||
@ -153,6 +151,50 @@ impl ParseQuote for Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl ParseQuote for Field {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let vis: Visibility = input.parse()?;
|
||||
|
||||
let ident: Option<Ident>;
|
||||
let colon_token: Option<Token![:]>;
|
||||
let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
|
||||
if is_named {
|
||||
ident = Some(input.parse()?);
|
||||
colon_token = Some(input.parse()?);
|
||||
} else {
|
||||
ident = None;
|
||||
colon_token = None;
|
||||
}
|
||||
|
||||
let ty: Type = input.parse()?;
|
||||
|
||||
Ok(Field {
|
||||
attrs,
|
||||
vis,
|
||||
mutability: FieldMutability::None,
|
||||
ident,
|
||||
colon_token,
|
||||
ty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl ParseQuote for Pat {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Pat::parse_multi_with_leading_vert(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl ParseQuote for Box<Pat> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
<Pat as ParseQuote>::parse(input).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Self::parse_terminated(input)
|
||||
|
756
src/pat.rs
756
src/pat.rs
File diff suppressed because it is too large
Load Diff
523
src/path.rs
523
src/path.rs
@ -3,9 +3,6 @@ use crate::punctuated::Punctuated;
|
||||
|
||||
ast_struct! {
|
||||
/// A path at which a named item is exported (e.g. `std::collections::HashMap`).
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Path {
|
||||
pub leading_colon: Option<Token![::]>,
|
||||
@ -27,11 +24,81 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
/// 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.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use proc_macro2::TokenStream;
|
||||
/// use syn::{Attribute, Error, Meta, Result};
|
||||
///
|
||||
/// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> {
|
||||
/// if attr.path().is_ident("serde") {
|
||||
/// match &attr.meta {
|
||||
/// Meta::List(meta) => Ok(Some(&meta.tokens)),
|
||||
/// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
|
||||
/// }
|
||||
/// } else {
|
||||
/// Ok(None)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn is_ident<I>(&self, ident: &I) -> bool
|
||||
where
|
||||
I: ?Sized,
|
||||
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.
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// An error if this path is not a single ident, as defined in `get_ident`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_ident(&self) -> Result<&Ident> {
|
||||
self.get_ident().ok_or_else(|| {
|
||||
crate::error::new2(
|
||||
self.segments.first().unwrap().ident.span(),
|
||||
self.segments.last().unwrap().ident.span(),
|
||||
"expected this path to be an identifier",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A segment of a path together with any path arguments on that segment.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct PathSegment {
|
||||
pub ident: Ident,
|
||||
@ -54,9 +121,6 @@ where
|
||||
ast_enum! {
|
||||
/// Angle bracketed or parenthesized arguments of a path segment.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// ## Angle bracketed
|
||||
///
|
||||
/// The `<'a, T>` in `std::slice::iter<'a, T>`.
|
||||
@ -99,10 +163,8 @@ impl PathArguments {
|
||||
|
||||
ast_enum! {
|
||||
/// An individual generic argument, like `'a`, `T`, or `Item = T`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum GenericArgument {
|
||||
/// A lifetime argument.
|
||||
Lifetime(Lifetime),
|
||||
@ -115,7 +177,10 @@ ast_enum! {
|
||||
Const(Expr),
|
||||
/// A binding (equality constraint) on an associated type: the `Item =
|
||||
/// u8` in `Iterator<Item = u8>`.
|
||||
Binding(Binding),
|
||||
AssocType(AssocType),
|
||||
/// An equality constraint on an associated constant: the `PANIC =
|
||||
/// false` in `Trait<PANIC = false>`.
|
||||
AssocConst(AssocConst),
|
||||
/// An associated type bound: `Iterator<Item: Display>`.
|
||||
Constraint(Constraint),
|
||||
}
|
||||
@ -124,9 +189,6 @@ ast_enum! {
|
||||
ast_struct! {
|
||||
/// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
|
||||
/// V>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct AngleBracketedGenericArguments {
|
||||
pub colon2_token: Option<Token![::]>,
|
||||
@ -137,26 +199,35 @@ ast_struct! {
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A binding (equality constraint) on an associated type: `Item = u8`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
/// A binding (equality constraint) on an associated type: the `Item = u8`
|
||||
/// in `Iterator<Item = u8>`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Binding {
|
||||
pub struct AssocType {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
pub eq_token: Token![=],
|
||||
pub ty: Type,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// An equality constraint on an associated constant: the `PANIC = false` in
|
||||
/// `Trait<PANIC = false>`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct AssocConst {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
pub eq_token: Token![=],
|
||||
pub value: Expr,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// An associated type bound: `Iterator<Item: Display>`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Constraint {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
pub colon_token: Token![:],
|
||||
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
||||
}
|
||||
@ -165,9 +236,6 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
|
||||
/// C`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct ParenthesizedGenericArguments {
|
||||
pub paren_token: token::Paren,
|
||||
@ -195,9 +263,6 @@ ast_struct! {
|
||||
/// ^~~~~~ ^
|
||||
/// ty position = 0
|
||||
/// ```
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct QSelf {
|
||||
pub lt_token: Token![<],
|
||||
@ -209,10 +274,10 @@ ast_struct! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
|
||||
use crate::ext::IdentExt;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
@ -229,92 +294,87 @@ pub mod parsing {
|
||||
return Ok(GenericArgument::Lifetime(input.parse()?));
|
||||
}
|
||||
|
||||
if input.peek(Ident) && input.peek2(Token![=]) {
|
||||
let ident: Ident = input.parse()?;
|
||||
let eq_token: Token![=] = input.parse()?;
|
||||
|
||||
let ty = if input.peek(Lit) {
|
||||
let begin = input.fork();
|
||||
input.parse::<Lit>()?;
|
||||
Type::Verbatim(verbatim::between(begin, input))
|
||||
} else if input.peek(token::Brace) {
|
||||
let begin = input.fork();
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
input.parse::<ExprBlock>()?;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
{
|
||||
let content;
|
||||
braced!(content in input);
|
||||
content.parse::<Expr>()?;
|
||||
}
|
||||
|
||||
Type::Verbatim(verbatim::between(begin, input))
|
||||
} else {
|
||||
input.parse()?
|
||||
};
|
||||
|
||||
return Ok(GenericArgument::Binding(Binding {
|
||||
ident,
|
||||
eq_token,
|
||||
ty,
|
||||
}));
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
|
||||
return Ok(GenericArgument::Constraint(input.parse()?));
|
||||
}
|
||||
}
|
||||
|
||||
if input.peek(Lit) || input.peek(token::Brace) {
|
||||
return const_argument(input).map(GenericArgument::Const);
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
let begin = input.fork();
|
||||
let mut argument: Type = input.parse()?;
|
||||
|
||||
let argument: Type = input.parse()?;
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
if match &argument {
|
||||
Type::Path(argument)
|
||||
if argument.qself.is_none()
|
||||
&& argument.path.leading_colon.is_none()
|
||||
&& argument.path.segments.len() == 1 =>
|
||||
{
|
||||
match argument.path.segments[0].arguments {
|
||||
PathArguments::AngleBracketed(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
match argument {
|
||||
Type::Path(mut ty)
|
||||
if ty.qself.is_none()
|
||||
&& ty.path.leading_colon.is_none()
|
||||
&& ty.path.segments.len() == 1
|
||||
&& match &ty.path.segments[0].arguments {
|
||||
PathArguments::None | PathArguments::AngleBracketed(_) => true,
|
||||
PathArguments::Parenthesized(_) => false,
|
||||
} =>
|
||||
{
|
||||
if let Some(eq_token) = input.parse::<Option<Token![=]>>()? {
|
||||
let segment = ty.path.segments.pop().unwrap().into_value();
|
||||
let ident = segment.ident;
|
||||
let generics = match segment.arguments {
|
||||
PathArguments::None => None,
|
||||
PathArguments::AngleBracketed(arguments) => Some(arguments),
|
||||
PathArguments::Parenthesized(_) => unreachable!(),
|
||||
};
|
||||
return if input.peek(Lit) || input.peek(token::Brace) {
|
||||
Ok(GenericArgument::AssocConst(AssocConst {
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
value: const_argument(input)?,
|
||||
}))
|
||||
} else {
|
||||
Ok(GenericArgument::AssocType(AssocType {
|
||||
ident,
|
||||
generics,
|
||||
eq_token,
|
||||
ty: input.parse()?,
|
||||
}))
|
||||
};
|
||||
}
|
||||
_ => false,
|
||||
} && if input.peek(Token![=]) {
|
||||
input.parse::<Token![=]>()?;
|
||||
input.parse::<Type>()?;
|
||||
true
|
||||
} else if input.peek(Token![:]) {
|
||||
input.parse::<Token![:]>()?;
|
||||
input.call(constraint_bounds)?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
} {
|
||||
let verbatim = verbatim::between(begin, input);
|
||||
return Ok(GenericArgument::Type(Type::Verbatim(verbatim)));
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
|
||||
let segment = ty.path.segments.pop().unwrap().into_value();
|
||||
return Ok(GenericArgument::Constraint(Constraint {
|
||||
ident: segment.ident,
|
||||
generics: match segment.arguments {
|
||||
PathArguments::None => None,
|
||||
PathArguments::AngleBracketed(arguments) => Some(arguments),
|
||||
PathArguments::Parenthesized(_) => unreachable!(),
|
||||
},
|
||||
colon_token,
|
||||
bounds: {
|
||||
let mut bounds = Punctuated::new();
|
||||
loop {
|
||||
if input.peek(Token![,]) || input.peek(Token![>]) {
|
||||
break;
|
||||
}
|
||||
let value: TypeParamBound = input.parse()?;
|
||||
bounds.push_value(value);
|
||||
if !input.peek(Token![+]) {
|
||||
break;
|
||||
}
|
||||
let punct: Token![+] = input.parse()?;
|
||||
bounds.push_punct(punct);
|
||||
}
|
||||
bounds
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
argument = Type::Path(ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(GenericArgument::Type(argument))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_argument(input: ParseStream) -> Result<Expr> {
|
||||
pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
|
||||
let lookahead = input.lookahead1();
|
||||
|
||||
if input.peek(Lit) {
|
||||
@ -322,16 +382,13 @@ pub mod parsing {
|
||||
return Ok(Expr::Lit(lit));
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
if input.peek(Ident) {
|
||||
let ident: Ident = input.parse()?;
|
||||
return Ok(Expr::Path(ExprPath {
|
||||
attrs: Vec::new(),
|
||||
qself: None,
|
||||
path: Path::from(ident),
|
||||
}));
|
||||
}
|
||||
if input.peek(Ident) {
|
||||
let ident: Ident = input.parse()?;
|
||||
return Ok(Expr::Path(ExprPath {
|
||||
attrs: Vec::new(),
|
||||
qself: None,
|
||||
path: Path::from(ident),
|
||||
}));
|
||||
}
|
||||
|
||||
if input.peek(token::Brace) {
|
||||
@ -347,7 +404,7 @@ pub mod parsing {
|
||||
let content;
|
||||
braced!(content in input);
|
||||
content.parse::<Expr>()?;
|
||||
let verbatim = verbatim::between(begin, input);
|
||||
let verbatim = verbatim::between(&begin, input);
|
||||
return Ok(Expr::Verbatim(verbatim));
|
||||
}
|
||||
}
|
||||
@ -355,11 +412,24 @@ pub mod parsing {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for AngleBracketedGenericArguments {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
impl AngleBracketedGenericArguments {
|
||||
/// Parse `::<…>` with mandatory leading `::`.
|
||||
///
|
||||
/// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`
|
||||
/// parses optional leading `::`.
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
|
||||
pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
|
||||
let colon2_token: Token![::] = input.parse()?;
|
||||
Self::do_parse(Some(colon2_token), input)
|
||||
}
|
||||
|
||||
pub(crate) fn do_parse(
|
||||
colon2_token: Option<Token![::]>,
|
||||
input: ParseStream,
|
||||
) -> Result<Self> {
|
||||
Ok(AngleBracketedGenericArguments {
|
||||
colon2_token: input.parse()?,
|
||||
colon2_token,
|
||||
lt_token: input.parse()?,
|
||||
args: {
|
||||
let mut args = Punctuated::new();
|
||||
@ -367,12 +437,12 @@ pub mod parsing {
|
||||
if input.peek(Token![>]) {
|
||||
break;
|
||||
}
|
||||
let value = input.parse()?;
|
||||
let value: GenericArgument = input.parse()?;
|
||||
args.push_value(value);
|
||||
if input.peek(Token![>]) {
|
||||
break;
|
||||
}
|
||||
let punct = input.parse()?;
|
||||
let punct: Token![,] = input.parse()?;
|
||||
args.push_punct(punct);
|
||||
}
|
||||
args
|
||||
@ -382,13 +452,21 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for AngleBracketedGenericArguments {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let colon2_token: Option<Token![::]> = input.parse()?;
|
||||
Self::do_parse(colon2_token, input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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)?,
|
||||
inputs: content.parse_terminated(Type::parse, Token![,])?,
|
||||
output: input.call(ReturnType::without_plus)?,
|
||||
})
|
||||
}
|
||||
@ -403,7 +481,11 @@ pub mod parsing {
|
||||
|
||||
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]) {
|
||||
if input.peek(Token![super])
|
||||
|| input.peek(Token![self])
|
||||
|| input.peek(Token![crate])
|
||||
|| cfg!(feature = "full") && input.peek(Token![try])
|
||||
{
|
||||
let ident = input.call(Ident::parse_any)?;
|
||||
return Ok(PathSegment::from(ident));
|
||||
}
|
||||
@ -427,53 +509,9 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Constraint {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(Constraint {
|
||||
ident: input.parse()?,
|
||||
colon_token: input.parse()?,
|
||||
bounds: constraint_bounds(input)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
|
||||
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);
|
||||
}
|
||||
Ok(bounds)
|
||||
}
|
||||
|
||||
impl Path {
|
||||
/// Parse a `Path` containing no path arguments on any of its segments.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -526,80 +564,15 @@ pub mod parsing {
|
||||
segments.push_punct(punct);
|
||||
}
|
||||
if segments.is_empty() {
|
||||
return Err(input.error("expected path"));
|
||||
return Err(input.parse::<Ident>().unwrap_err());
|
||||
} else if segments.trailing_punct() {
|
||||
return Err(input.error("expected path segment"));
|
||||
return Err(input.error("expected path segment after `::`"));
|
||||
}
|
||||
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 only 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())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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 only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
|
||||
let mut path = Path {
|
||||
leading_colon: input.parse()?,
|
||||
@ -627,9 +600,15 @@ pub mod parsing {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn is_mod_style(&self) -> bool {
|
||||
self.segments
|
||||
.iter()
|
||||
.all(|segment| segment.arguments.is_none())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
|
||||
pub(crate) 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()?;
|
||||
@ -686,6 +665,10 @@ pub mod parsing {
|
||||
pub(crate) mod printing {
|
||||
use super::*;
|
||||
use crate::print::TokensOrDefault;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::spanned::Spanned;
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::Span;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use std::cmp;
|
||||
@ -728,23 +711,32 @@ pub(crate) mod printing {
|
||||
match self {
|
||||
GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
|
||||
GenericArgument::Type(ty) => ty.to_tokens(tokens),
|
||||
GenericArgument::Const(e) => match *e {
|
||||
Expr::Lit(_) => e.to_tokens(tokens),
|
||||
GenericArgument::Const(expr) => match expr {
|
||||
Expr::Lit(expr) => expr.to_tokens(tokens),
|
||||
|
||||
Expr::Path(expr)
|
||||
if expr.attrs.is_empty()
|
||||
&& expr.qself.is_none()
|
||||
&& expr.path.get_ident().is_some() =>
|
||||
{
|
||||
expr.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),
|
||||
Expr::Block(expr) => expr.to_tokens(tokens),
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
Expr::Verbatim(expr) => expr.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);
|
||||
expr.to_tokens(tokens);
|
||||
}),
|
||||
},
|
||||
GenericArgument::Binding(tb) => tb.to_tokens(tokens),
|
||||
GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
|
||||
GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
|
||||
GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
|
||||
GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -759,22 +751,24 @@ pub(crate) mod printing {
|
||||
// order in self.args.
|
||||
let mut trailing_or_empty = true;
|
||||
for param in self.args.pairs() {
|
||||
match **param.value() {
|
||||
match param.value() {
|
||||
GenericArgument::Lifetime(_) => {
|
||||
param.to_tokens(tokens);
|
||||
trailing_or_empty = param.punct().is_some();
|
||||
}
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::Binding(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {}
|
||||
}
|
||||
}
|
||||
for param in self.args.pairs() {
|
||||
match **param.value() {
|
||||
match param.value() {
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::Binding(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {
|
||||
if !trailing_or_empty {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
@ -791,18 +785,30 @@ pub(crate) mod printing {
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Binding {
|
||||
impl ToTokens for AssocType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
self.eq_token.to_tokens(tokens);
|
||||
self.ty.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for AssocConst {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
self.eq_token.to_tokens(tokens);
|
||||
self.value.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Constraint {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
self.colon_token.to_tokens(tokens);
|
||||
self.bounds.to_tokens(tokens);
|
||||
}
|
||||
@ -851,4 +857,21 @@ pub(crate) mod printing {
|
||||
segment.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
impl Spanned for QSelf {
|
||||
fn span(&self) -> Span {
|
||||
struct QSelfDelimiters<'a>(&'a QSelf);
|
||||
|
||||
impl<'a> ToTokens for QSelfDelimiters<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.0.lt_token.to_tokens(tokens);
|
||||
self.0.gt_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
QSelfDelimiters(self).span()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
pub struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>);
|
||||
pub(crate) struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>);
|
||||
|
||||
impl<'a, T> ToTokens for TokensOrDefault<'a, T>
|
||||
where
|
||||
|
@ -26,7 +26,6 @@ use std::fmt::{self, Debug};
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use std::iter;
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::option;
|
||||
use std::slice;
|
||||
@ -38,8 +37,8 @@ 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`.
|
||||
/// **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.
|
||||
///
|
||||
@ -51,7 +50,6 @@ pub struct Punctuated<T, P> {
|
||||
|
||||
impl<T, P> Punctuated<T, P> {
|
||||
/// Creates an empty punctuated sequence.
|
||||
#[cfg(not(syn_no_const_vec_new))]
|
||||
pub const fn new() -> Self {
|
||||
Punctuated {
|
||||
inner: Vec::new(),
|
||||
@ -59,15 +57,6 @@ impl<T, P> Punctuated<T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an empty punctuated sequence.
|
||||
#[cfg(syn_no_const_vec_new)]
|
||||
pub fn new() -> Self {
|
||||
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 {
|
||||
@ -151,7 +140,7 @@ impl<T, P> Punctuated<T, P> {
|
||||
}
|
||||
|
||||
/// Appends a syntax tree node onto the end of this punctuated sequence. The
|
||||
/// sequence must previously have a trailing punctuation.
|
||||
/// sequence must already have a trailing punctuation, or be empty.
|
||||
///
|
||||
/// Use [`push`] instead if the punctuated sequence may or may not already
|
||||
/// have trailing punctuation.
|
||||
@ -160,8 +149,8 @@ impl<T, P> Punctuated<T, P> {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the sequence does not already have a trailing punctuation when
|
||||
/// this method is called.
|
||||
/// Panics if the sequence is nonempty and does not already have a trailing
|
||||
/// punctuation.
|
||||
pub fn push_value(&mut self, value: T) {
|
||||
assert!(
|
||||
self.empty_or_trailing(),
|
||||
@ -198,6 +187,18 @@ impl<T, P> Punctuated<T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the trailing punctuation from this punctuated sequence, or
|
||||
/// `None` if there isn't any.
|
||||
pub fn pop_punct(&mut self) -> Option<P> {
|
||||
if self.last.is_some() {
|
||||
None
|
||||
} else {
|
||||
let (t, p) = self.inner.pop()?;
|
||||
self.last = Some(Box::new(t));
|
||||
Some(p)
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines whether this punctuated sequence ends with a trailing
|
||||
/// punctuation.
|
||||
pub fn trailing_punct(&self) -> bool {
|
||||
@ -260,9 +261,6 @@ impl<T, P> Punctuated<T, P> {
|
||||
///
|
||||
/// 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 only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_terminated(input: ParseStream) -> Result<Self>
|
||||
@ -281,9 +279,6 @@ impl<T, P> Punctuated<T, P> {
|
||||
/// to be parsed.
|
||||
///
|
||||
/// [`parse_terminated`]: Punctuated::parse_terminated
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_terminated_with(
|
||||
@ -318,9 +313,6 @@ impl<T, P> Punctuated<T, P> {
|
||||
/// 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 only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self>
|
||||
@ -339,9 +331,6 @@ impl<T, P> Punctuated<T, P> {
|
||||
/// the entire content of this stream.
|
||||
///
|
||||
/// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_separated_nonempty_with(
|
||||
@ -380,6 +369,11 @@ where
|
||||
last: self.last.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, other: &Self) {
|
||||
self.inner.clone_from(&other.inner);
|
||||
self.last.clone_from(&other.last);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
@ -459,29 +453,37 @@ where
|
||||
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);
|
||||
do_extend(&mut ret, i.into_iter());
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P> {
|
||||
impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P>
|
||||
where
|
||||
P: Default,
|
||||
{
|
||||
fn extend<I: IntoIterator<Item = Pair<T, P>>>(&mut self, i: I) {
|
||||
assert!(
|
||||
self.empty_or_trailing(),
|
||||
"Punctuated::extend: Punctuated is not empty or does not have a trailing punctuation",
|
||||
);
|
||||
if !self.empty_or_trailing() {
|
||||
self.push_punct(P::default());
|
||||
}
|
||||
do_extend(self, i.into_iter());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
fn do_extend<T, P, I>(punctuated: &mut Punctuated<T, P>, i: I)
|
||||
where
|
||||
I: Iterator<Item = Pair<T, P>>,
|
||||
{
|
||||
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) => punctuated.inner.push((a, b)),
|
||||
Pair::End(a) => {
|
||||
punctuated.last = Some(Box::new(a));
|
||||
nomore = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -719,16 +721,11 @@ where
|
||||
///
|
||||
/// [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<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>>,
|
||||
inner: Box<NoDrop<dyn IterTrait<'a, T> + 'a>>,
|
||||
}
|
||||
|
||||
trait IterTrait<'a, T: 'a>:
|
||||
DoubleEndedIterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>
|
||||
{
|
||||
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>>;
|
||||
trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> + DoubleEndedIterator + ExactSizeIterator {
|
||||
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T> + 'a>>;
|
||||
}
|
||||
|
||||
struct PrivateIter<'a, T: 'a, P: 'a> {
|
||||
@ -827,7 +824,7 @@ where
|
||||
+ TrivialDrop
|
||||
+ 'a,
|
||||
{
|
||||
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T, Item = &'a T> + 'a>> {
|
||||
fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T> + 'a>> {
|
||||
Box::new(NoDrop::new(self.clone()))
|
||||
}
|
||||
}
|
||||
@ -1008,6 +1005,21 @@ impl<T, P> Pair<T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Pair<&T, &P> {
|
||||
pub fn cloned(self) -> Pair<T, P>
|
||||
where
|
||||
T: Clone,
|
||||
P: Clone,
|
||||
{
|
||||
match self {
|
||||
Pair::Punctuated(t, p) => Pair::Punctuated(t.clone(), p.clone()),
|
||||
Pair::End(t) => Pair::End(t.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Clone for Pair<T, P>
|
||||
@ -1023,6 +1035,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Copy for Pair<T, P>
|
||||
where
|
||||
T: Copy,
|
||||
P: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, P> Index<usize> for Punctuated<T, P> {
|
||||
type Output = T;
|
||||
|
||||
|
@ -1,44 +0,0 @@
|
||||
// Type for a syntax tree node that is reserved for future use.
|
||||
//
|
||||
// For example ExprReference contains a field `raw` of type Reserved. If `&raw
|
||||
// place` syntax becomes a thing as per https://github.com/rust-lang/rfcs/pull/2582,
|
||||
// we can backward compatibly change `raw`'s type to Option<Token![raw]> without
|
||||
// the possibility of breaking any code.
|
||||
|
||||
use proc_macro2::Span;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
ast_struct! {
|
||||
pub struct Reserved {
|
||||
_private: PhantomData<Span>,
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Reserved {
|
||||
fn default() -> Self {
|
||||
Reserved {
|
||||
_private: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Reserved {
|
||||
fn clone(&self) -> Self {
|
||||
Reserved {
|
||||
_private: self._private,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for Reserved {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.debug_struct("Reserved").finish()
|
||||
}
|
||||
}
|
171
src/restriction.rs
Normal file
171
src/restriction.rs
Normal file
@ -0,0 +1,171 @@
|
||||
use super::*;
|
||||
|
||||
ast_enum! {
|
||||
/// The visibility level of an item: inherited or `pub` or
|
||||
/// `pub(restricted)`.
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum Visibility {
|
||||
/// A public visibility level: `pub`.
|
||||
Public(Token![pub]),
|
||||
|
||||
/// 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 visibility level restricted to some path: `pub(self)` or
|
||||
/// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct VisRestricted {
|
||||
pub pub_token: Token![pub],
|
||||
pub paren_token: token::Paren,
|
||||
pub in_token: Option<Token![in]>,
|
||||
pub path: Box<Path>,
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum! {
|
||||
/// Unused, but reserved for RFC 3323 restrictions.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum FieldMutability {
|
||||
None,
|
||||
|
||||
// TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html
|
||||
//
|
||||
// FieldMutability::Restricted(MutRestricted)
|
||||
//
|
||||
// pub struct MutRestricted {
|
||||
// pub mut_token: Token![mut],
|
||||
// pub paren_token: token::Paren,
|
||||
// pub in_token: Option<Token![in]>,
|
||||
// pub path: Box<Path>,
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Visibility {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
// Recognize an empty None-delimited group, as produced by a $:vis
|
||||
// matcher that matched no tokens.
|
||||
if input.peek(token::Group) {
|
||||
let ahead = input.fork();
|
||||
let group = crate::group::parse_group(&ahead)?;
|
||||
if group.content.is_empty() {
|
||||
input.advance_to(&ahead);
|
||||
return Ok(Visibility::Inherited);
|
||||
}
|
||||
}
|
||||
|
||||
if input.peek(Token![pub]) {
|
||||
Self::parse_pub(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(pub_token))
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
pub(crate) fn is_some(&self) -> bool {
|
||||
match self {
|
||||
Visibility::Inherited => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Visibility {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
Visibility::Public(pub_token) => pub_token.to_tokens(tokens),
|
||||
Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens),
|
||||
Visibility::Inherited => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod lookahead {
|
||||
pub(crate) mod lookahead {
|
||||
pub trait Sealed: Copy {}
|
||||
}
|
||||
|
38
src/span.rs
38
src/span.rs
@ -1,9 +1,17 @@
|
||||
use proc_macro2::Span;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::{Delimiter, Group, Span, TokenStream};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait IntoSpans<S> {
|
||||
fn into_spans(self) -> S;
|
||||
}
|
||||
|
||||
impl IntoSpans<Span> for Span {
|
||||
fn into_spans(self) -> Span {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoSpans<[Span; 1]> for Span {
|
||||
fn into_spans(self) -> [Span; 1] {
|
||||
[self]
|
||||
@ -40,28 +48,16 @@ impl IntoSpans<[Span; 3]> for [Span; 3] {
|
||||
}
|
||||
}
|
||||
|
||||
#[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]]
|
||||
impl IntoSpans<DelimSpan> for Span {
|
||||
fn into_spans(self) -> DelimSpan {
|
||||
let mut group = Group::new(Delimiter::None, TokenStream::new());
|
||||
group.set_span(self);
|
||||
group.delim_span()
|
||||
}
|
||||
}
|
||||
|
||||
#[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]]
|
||||
impl IntoSpans<DelimSpan> for DelimSpan {
|
||||
fn into_spans(self) -> DelimSpan {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
//! A trait that can provide the `Span` of the complete contents of a syntax
|
||||
//! tree node.
|
||||
//!
|
||||
//! *This module is available only if Syn is built with both the `"parsing"` and
|
||||
//! `"printing"` features.*
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Example
|
||||
@ -96,10 +93,7 @@ use quote::spanned::Spanned as ToTokens;
|
||||
/// See the [module documentation] for an example.
|
||||
///
|
||||
/// [module documentation]: self
|
||||
///
|
||||
/// *This trait is available only if Syn is built with both the `"parsing"` and
|
||||
/// `"printing"` features.*
|
||||
pub trait Spanned {
|
||||
pub trait Spanned: private::Sealed {
|
||||
/// Returns a `Span` covering the complete contents of this syntax tree
|
||||
/// node, or [`Span::call_site()`] if this node is empty.
|
||||
///
|
||||
@ -112,3 +106,13 @@ impl<T: ?Sized + ToTokens> Spanned for T {
|
||||
self.__span()
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
use super::*;
|
||||
|
||||
pub trait Sealed {}
|
||||
impl<T: ?Sized + ToTokens> Sealed for T {}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl Sealed for crate::QSelf {}
|
||||
}
|
||||
|
253
src/stmt.rs
253
src/stmt.rs
@ -2,8 +2,6 @@ use super::*;
|
||||
|
||||
ast_struct! {
|
||||
/// A braced block containing Rust statements.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub struct Block {
|
||||
pub brace_token: token::Brace,
|
||||
@ -14,8 +12,6 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// A statement, usually ending in a semicolon.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub enum Stmt {
|
||||
/// A local (let) binding.
|
||||
@ -24,42 +20,71 @@ ast_enum! {
|
||||
/// An item definition.
|
||||
Item(Item),
|
||||
|
||||
/// Expr without trailing semicolon.
|
||||
Expr(Expr),
|
||||
/// Expression, with or without trailing semicolon.
|
||||
Expr(Expr, Option<Token![;]>),
|
||||
|
||||
/// Expression with trailing semicolon.
|
||||
Semi(Expr, Token![;]),
|
||||
/// A macro invocation in statement position.
|
||||
///
|
||||
/// Syntactically it's ambiguous which other kind of statement this
|
||||
/// macro would expand to. It can be any of local variable (`let`),
|
||||
/// item, or expression.
|
||||
Macro(StmtMacro),
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A local `let` binding: `let x: u64 = s.parse()?`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub struct Local {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub let_token: Token![let],
|
||||
pub pat: Pat,
|
||||
pub init: Option<(Token![=], Box<Expr>)>,
|
||||
pub init: Option<LocalInit>,
|
||||
pub semi_token: Token![;],
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// The expression assigned in a local `let` binding, including optional
|
||||
/// diverging `else` block.
|
||||
///
|
||||
/// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and
|
||||
/// `= r else { return }` in `let Ok(x) = r else { return }`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub struct LocalInit {
|
||||
pub eq_token: Token![=],
|
||||
pub expr: Box<Expr>,
|
||||
pub diverge: Option<(Token![else], Box<Expr>)>,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A macro invocation in statement position.
|
||||
///
|
||||
/// Syntactically it's ambiguous which other kind of statement this macro
|
||||
/// would expand to. It can be any of local variable (`let`), item, or
|
||||
/// expression.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
pub struct StmtMacro {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub mac: Macro,
|
||||
pub semi_token: Option<Token![;]>,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::discouraged::Speculative;
|
||||
use crate::parse::{Parse, ParseBuffer, ParseStream, Result};
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
struct AllowNoSemi(bool);
|
||||
|
||||
impl Block {
|
||||
/// Parse the body of a block as zero or more statements, possibly
|
||||
/// including one trailing expression.
|
||||
///
|
||||
/// *This function is available only if Syn is built with the `"parsing"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -110,23 +135,25 @@ pub mod parsing {
|
||||
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));
|
||||
while let semi @ Some(_) = input.parse()? {
|
||||
stmts.push(Stmt::Expr(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
|
||||
let stmt = parse_stmt(input, AllowNoSemi(true))?;
|
||||
let requires_semicolon = match &stmt {
|
||||
Stmt::Expr(stmt, None) => expr::requires_terminator(stmt),
|
||||
Stmt::Macro(stmt) => {
|
||||
stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace()
|
||||
}
|
||||
Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false,
|
||||
};
|
||||
stmts.push(s);
|
||||
stmts.push(stmt);
|
||||
if input.is_empty() {
|
||||
break;
|
||||
} else if requires_semicolon {
|
||||
return Err(input.error("unexpected token"));
|
||||
return Err(input.error("unexpected token, expected `;`"));
|
||||
}
|
||||
}
|
||||
Ok(stmts)
|
||||
@ -147,30 +174,34 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Stmt {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
parse_stmt(input, false)
|
||||
let allow_nosemi = AllowNoSemi(false);
|
||||
parse_stmt(input, allow_nosemi)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
|
||||
fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> {
|
||||
let begin = input.fork();
|
||||
let mut attrs = input.call(Attribute::parse_outer)?;
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
|
||||
// brace-style macros; paren and bracket macros get parsed as
|
||||
// expression statements.
|
||||
let ahead = input.fork();
|
||||
let mut is_item_macro = false;
|
||||
if let Ok(path) = ahead.call(Path::parse_mod_style) {
|
||||
if ahead.peek(Token![!])
|
||||
&& (ahead.peek2(token::Brace)
|
||||
if ahead.peek(Token![!]) {
|
||||
if ahead.peek2(Ident) || ahead.peek2(Token![try]) {
|
||||
is_item_macro = true;
|
||||
} else if ahead.peek2(token::Brace)
|
||||
&& !(ahead.peek3(Token![.]) || ahead.peek3(Token![?]))
|
||||
|| ahead.peek2(Ident))
|
||||
{
|
||||
input.advance_to(&ahead);
|
||||
return stmt_mac(input, attrs, path);
|
||||
{
|
||||
input.advance_to(&ahead);
|
||||
return stmt_mac(input, attrs, path).map(Stmt::Macro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if input.peek(Token![let]) {
|
||||
stmt_local(input, attrs, begin)
|
||||
if input.peek(Token![let]) && !input.peek(token::Group) {
|
||||
stmt_local(input, attrs).map(Stmt::Local)
|
||||
} else if input.peek(Token![pub])
|
||||
|| input.peek(Token![crate]) && !input.peek2(Token![::])
|
||||
|| input.peek(Token![extern])
|
||||
@ -180,7 +211,15 @@ pub mod parsing {
|
||||
|| input.peek2(Ident)
|
||||
&& !(input.peek2(Token![async])
|
||||
&& (input.peek3(Token![move]) || input.peek3(Token![|]))))
|
||||
|| input.peek(Token![const]) && !input.peek2(token::Brace)
|
||||
|| input.peek(Token![const])
|
||||
&& !(input.peek2(token::Brace)
|
||||
|| input.peek2(Token![static])
|
||||
|| input.peek2(Token![async])
|
||||
&& !(input.peek3(Token![unsafe])
|
||||
|| input.peek3(Token![extern])
|
||||
|| input.peek3(Token![fn]))
|
||||
|| input.peek2(Token![move])
|
||||
|| input.peek2(Token![|]))
|
||||
|| input.peek(Token![unsafe]) && !input.peek2(token::Brace)
|
||||
|| input.peek(Token![async])
|
||||
&& (input.peek2(Token![unsafe])
|
||||
@ -198,25 +237,22 @@ pub mod parsing {
|
||||
&& (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
|
||||
|| input.peek(Token![impl])
|
||||
|| input.peek(Token![macro])
|
||||
|| is_item_macro
|
||||
{
|
||||
let mut item: Item = input.parse()?;
|
||||
attrs.extend(item.replace_attrs(Vec::new()));
|
||||
item.replace_attrs(attrs);
|
||||
let item = item::parsing::parse_rest_of_item(begin, attrs, input)?;
|
||||
Ok(Stmt::Item(item))
|
||||
} else {
|
||||
stmt_expr(input, allow_nosemi, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<Stmt> {
|
||||
fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> {
|
||||
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 {
|
||||
Ok(StmtMacro {
|
||||
attrs,
|
||||
ident,
|
||||
mac: Macro {
|
||||
path,
|
||||
bang_token,
|
||||
@ -224,13 +260,13 @@ pub mod parsing {
|
||||
tokens,
|
||||
},
|
||||
semi_token,
|
||||
})))
|
||||
})
|
||||
}
|
||||
|
||||
fn stmt_local(input: ParseStream, attrs: Vec<Attribute>, begin: ParseBuffer) -> Result<Stmt> {
|
||||
fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
|
||||
let let_token: Token![let] = input.parse()?;
|
||||
|
||||
let mut pat: Pat = pat::parsing::multi_pat_with_leading_vert(input)?;
|
||||
let mut pat = Pat::parse_single(input)?;
|
||||
if input.peek(Token![:]) {
|
||||
let colon_token: Token![:] = input.parse()?;
|
||||
let ty: Type = input.parse()?;
|
||||
@ -242,39 +278,45 @@ pub mod parsing {
|
||||
});
|
||||
}
|
||||
|
||||
let init = if input.peek(Token![=]) {
|
||||
let eq_token: Token![=] = input.parse()?;
|
||||
let init: Expr = input.parse()?;
|
||||
let init = if let Some(eq_token) = input.parse()? {
|
||||
let eq_token: Token![=] = eq_token;
|
||||
let expr: Expr = input.parse()?;
|
||||
|
||||
if input.peek(Token![else]) {
|
||||
input.parse::<Token![else]>()?;
|
||||
let content;
|
||||
braced!(content in input);
|
||||
content.call(Block::parse_within)?;
|
||||
let verbatim = Expr::Verbatim(verbatim::between(begin, input));
|
||||
let semi_token: Token![;] = input.parse()?;
|
||||
return Ok(Stmt::Semi(verbatim, semi_token));
|
||||
}
|
||||
let diverge = if let Some(else_token) = input.parse()? {
|
||||
let else_token: Token![else] = else_token;
|
||||
let diverge = ExprBlock {
|
||||
attrs: Vec::new(),
|
||||
label: None,
|
||||
block: input.parse()?,
|
||||
};
|
||||
Some((else_token, Box::new(Expr::Block(diverge))))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Some((eq_token, Box::new(init)))
|
||||
Some(LocalInit {
|
||||
eq_token,
|
||||
expr: Box::new(expr),
|
||||
diverge,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let semi_token: Token![;] = input.parse()?;
|
||||
|
||||
Ok(Stmt::Local(Local {
|
||||
Ok(Local {
|
||||
attrs,
|
||||
let_token,
|
||||
pat,
|
||||
init,
|
||||
semi_token,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn stmt_expr(
|
||||
input: ParseStream,
|
||||
allow_nosemi: bool,
|
||||
allow_nosemi: AllowNoSemi,
|
||||
mut attrs: Vec<Attribute>,
|
||||
) -> Result<Stmt> {
|
||||
let mut e = expr::parsing::expr_early(input)?;
|
||||
@ -283,20 +325,68 @@ pub mod parsing {
|
||||
loop {
|
||||
attr_target = match attr_target {
|
||||
Expr::Assign(e) => &mut e.left,
|
||||
Expr::AssignOp(e) => &mut e.left,
|
||||
Expr::Binary(e) => &mut e.left,
|
||||
_ => break,
|
||||
Expr::Cast(e) => &mut e.expr,
|
||||
Expr::Array(_)
|
||||
| Expr::Async(_)
|
||||
| Expr::Await(_)
|
||||
| Expr::Block(_)
|
||||
| Expr::Break(_)
|
||||
| Expr::Call(_)
|
||||
| Expr::Closure(_)
|
||||
| Expr::Const(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Field(_)
|
||||
| Expr::ForLoop(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::If(_)
|
||||
| Expr::Index(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Let(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::Loop(_)
|
||||
| Expr::Macro(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::MethodCall(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Range(_)
|
||||
| Expr::Reference(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Return(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::Try(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::Unary(_)
|
||||
| Expr::Unsafe(_)
|
||||
| Expr::While(_)
|
||||
| Expr::Yield(_)
|
||||
| Expr::Verbatim(_) => break,
|
||||
};
|
||||
}
|
||||
attrs.extend(attr_target.replace_attrs(Vec::new()));
|
||||
attr_target.replace_attrs(attrs);
|
||||
|
||||
if input.peek(Token![;]) {
|
||||
return Ok(Stmt::Semi(e, input.parse()?));
|
||||
let semi_token: Option<Token![;]> = input.parse()?;
|
||||
|
||||
match e {
|
||||
Expr::Macro(ExprMacro { attrs, mac })
|
||||
if semi_token.is_some() || mac.delimiter.is_brace() =>
|
||||
{
|
||||
return Ok(Stmt::Macro(StmtMacro {
|
||||
attrs,
|
||||
mac,
|
||||
semi_token,
|
||||
}));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if allow_nosemi || !expr::requires_terminator(&e) {
|
||||
Ok(Stmt::Expr(e))
|
||||
if semi_token.is_some() {
|
||||
Ok(Stmt::Expr(e, semi_token))
|
||||
} else if allow_nosemi.0 || !expr::requires_terminator(&e) {
|
||||
Ok(Stmt::Expr(e, None))
|
||||
} else {
|
||||
Err(input.error("expected semicolon"))
|
||||
}
|
||||
@ -324,11 +414,11 @@ mod printing {
|
||||
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) => {
|
||||
Stmt::Expr(expr, semi) => {
|
||||
expr.to_tokens(tokens);
|
||||
semi.to_tokens(tokens);
|
||||
}
|
||||
Stmt::Macro(mac) => mac.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,11 +429,24 @@ mod printing {
|
||||
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);
|
||||
if let Some(init) = &self.init {
|
||||
init.eq_token.to_tokens(tokens);
|
||||
init.expr.to_tokens(tokens);
|
||||
if let Some((else_token, diverge)) = &init.diverge {
|
||||
else_token.to_tokens(tokens);
|
||||
diverge.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
self.semi_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for StmtMacro {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
|
||||
self.mac.to_tokens(tokens);
|
||||
self.semi_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ 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> {
|
||||
pub(crate) struct ThreadBound<T> {
|
||||
value: T,
|
||||
thread_id: ThreadId,
|
||||
}
|
||||
@ -12,17 +12,20 @@ pub struct ThreadBound<T> {
|
||||
unsafe impl<T> Sync for ThreadBound<T> {}
|
||||
|
||||
// Send bound requires Copy, as otherwise Drop could run in the wrong place.
|
||||
//
|
||||
// Today Copy and Drop are mutually exclusive so `T: Copy` implies `T: !Drop`.
|
||||
// This impl needs to be revisited if that restriction is relaxed in the future.
|
||||
unsafe impl<T: Copy> Send for ThreadBound<T> {}
|
||||
|
||||
impl<T> ThreadBound<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
pub(crate) fn new(value: T) -> Self {
|
||||
ThreadBound {
|
||||
value,
|
||||
thread_id: thread::current().id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Option<&T> {
|
||||
pub(crate) fn get(&self) -> Option<&T> {
|
||||
if thread::current().id() == self.thread_id {
|
||||
Some(&self.value)
|
||||
} else {
|
||||
@ -39,3 +42,19 @@ impl<T: Debug> Debug for ThreadBound<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the bytes of T, even if the currently running thread is the "wrong"
|
||||
// thread. This is fine as long as the original thread is not simultaneously
|
||||
// mutating this value via interior mutability, which would be a data race.
|
||||
//
|
||||
// Currently `T: Copy` is sufficient to guarantee that T contains no interior
|
||||
// mutability, because _all_ interior mutability in Rust is built on
|
||||
// std::cell::UnsafeCell, which has no Copy impl. This impl needs to be
|
||||
// revisited if that restriction is relaxed in the future.
|
||||
impl<T: Copy> Copy for ThreadBound<T> {}
|
||||
|
||||
impl<T: Copy> Clone for ThreadBound<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
691
src/token.rs
691
src/token.rs
@ -88,6 +88,8 @@
|
||||
//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html
|
||||
//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) use self::private::CustomToken;
|
||||
use self::private::WithSpan;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::buffer::Cursor;
|
||||
@ -102,13 +104,14 @@ use crate::lookahead;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::span::IntoSpans;
|
||||
#[cfg(any(feature = "parsing", feature = "printing"))]
|
||||
use proc_macro2::Ident;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Span;
|
||||
#[cfg(feature = "printing")]
|
||||
use proc_macro2::TokenStream;
|
||||
#[cfg(any(feature = "parsing", feature = "printing"))]
|
||||
use proc_macro2::{Delimiter, Ident};
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::{Delimiter, Literal, Punct, TokenTree};
|
||||
use proc_macro2::{Literal, Punct, TokenTree};
|
||||
#[cfg(feature = "printing")]
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
@ -133,7 +136,9 @@ pub trait Token: private::Sealed {
|
||||
fn display() -> &'static str;
|
||||
}
|
||||
|
||||
mod private {
|
||||
pub(crate) mod private {
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::buffer::Cursor;
|
||||
use proc_macro2::Span;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
@ -141,10 +146,19 @@ mod private {
|
||||
|
||||
/// Support writing `token.span` rather than `token.spans[0]` on tokens that
|
||||
/// hold a single span.
|
||||
#[repr(C)]
|
||||
#[repr(transparent)]
|
||||
#[allow(unknown_lints, repr_transparent_external_private_fields)] // False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
|
||||
pub struct WithSpan {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "parsing")]
|
||||
pub trait CustomToken {
|
||||
fn peek(cursor: Cursor) -> bool;
|
||||
fn display() -> &'static str;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
@ -163,7 +177,7 @@ fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
|
||||
}
|
||||
|
||||
macro_rules! impl_token {
|
||||
($display:tt $name:ty) => {
|
||||
($display:literal $name:ty) => {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for $name {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
@ -195,7 +209,7 @@ impl_token!("boolean literal" LitBool);
|
||||
impl_token!("group token" proc_macro2::Group);
|
||||
|
||||
macro_rules! impl_low_level_token {
|
||||
($display:tt $ty:ident $get:ident) => {
|
||||
($display:literal $ty:ident $get:ident) => {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for $ty {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
@ -216,14 +230,6 @@ impl_low_level_token!("punctuation token" Punct punct);
|
||||
impl_low_level_token!("literal" Literal literal);
|
||||
impl_low_level_token!("token" TokenTree token_tree);
|
||||
|
||||
// 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 {}
|
||||
|
||||
@ -239,9 +245,9 @@ impl<T: CustomToken> Token for T {
|
||||
}
|
||||
|
||||
macro_rules! define_keywords {
|
||||
($($token:tt pub struct $name:ident #[$doc:meta])*) => {
|
||||
($($token:literal pub struct $name:ident)*) => {
|
||||
$(
|
||||
#[$doc]
|
||||
#[doc = concat!('`', $token, '`')]
|
||||
///
|
||||
/// Don't try to remember the name of this type — use the
|
||||
/// [`Token!`] macro instead.
|
||||
@ -253,9 +259,9 @@ macro_rules! define_keywords {
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
|
||||
pub fn $name<S: IntoSpans<Span>>(span: S) -> $name {
|
||||
$name {
|
||||
span: span.into_spans()[0],
|
||||
span: span.into_spans(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,25 +352,29 @@ macro_rules! impl_deref_if_len_is_1 {
|
||||
type Target = WithSpan;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*(self as *const Self as *const WithSpan) }
|
||||
unsafe { &*(self as *const Self).cast::<WithSpan>() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for $name {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *(self as *mut Self as *mut WithSpan) }
|
||||
unsafe { &mut *(self as *mut Self).cast::<WithSpan>() }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($name:ident/$len:tt) => {};
|
||||
($name:ident/$len:literal) => {};
|
||||
}
|
||||
|
||||
macro_rules! define_punctuation_structs {
|
||||
($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
|
||||
($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
|
||||
$(
|
||||
#[repr(C)]
|
||||
#[$doc]
|
||||
#[cfg_attr(not(doc), repr(transparent))]
|
||||
#[allow(unknown_lints, repr_transparent_external_private_fields)] // False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
|
||||
#[doc = concat!('`', $token, '`')]
|
||||
///
|
||||
/// Usage:
|
||||
#[doc = concat!($usage, '.')]
|
||||
///
|
||||
/// Don't try to remember the name of this type — use the
|
||||
/// [`Token!`] macro instead.
|
||||
@ -434,10 +444,10 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
|
||||
macro_rules! define_punctuation {
|
||||
($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => {
|
||||
($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
|
||||
$(
|
||||
define_punctuation_structs! {
|
||||
$token pub struct $name/$len #[$doc]
|
||||
$token pub struct $name/$len #[doc = $usage]
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
@ -476,26 +486,24 @@ macro_rules! define_punctuation {
|
||||
}
|
||||
|
||||
macro_rules! define_delimiters {
|
||||
($($token:tt pub struct $name:ident #[$doc:meta])*) => {
|
||||
($($delim:ident pub struct $name:ident #[$doc:meta])*) => {
|
||||
$(
|
||||
#[$doc]
|
||||
pub struct $name {
|
||||
pub span: Span,
|
||||
pub span: DelimSpan,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name {
|
||||
pub fn $name<S: IntoSpans<DelimSpan>>(span: S) -> $name {
|
||||
$name {
|
||||
span: span.into_spans()[0],
|
||||
span: span.into_spans(),
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
$name {
|
||||
span: Span::call_site(),
|
||||
}
|
||||
$name(Span::call_site())
|
||||
}
|
||||
}
|
||||
|
||||
@ -543,7 +551,9 @@ macro_rules! define_delimiters {
|
||||
where
|
||||
F: FnOnce(&mut TokenStream),
|
||||
{
|
||||
printing::delim($token, self.span, tokens, f);
|
||||
let mut inner = TokenStream::new();
|
||||
f(&mut inner);
|
||||
printing::delim(Delimiter::$delim, self.span.join(), tokens, inner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,7 +564,7 @@ macro_rules! define_delimiters {
|
||||
}
|
||||
|
||||
define_punctuation_structs! {
|
||||
"_" pub struct Underscore/1 /// `_`
|
||||
"_" pub struct Underscore/1 /// wildcard patterns, inferred types, unnamed items in constants, extern crates, use declarations, and destructuring assignment
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
@ -605,6 +615,80 @@ impl Token for Underscore {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl private::Sealed for Underscore {}
|
||||
|
||||
/// None-delimited group
|
||||
pub struct Group {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Group<S: IntoSpans<Span>>(span: S) -> Group {
|
||||
Group {
|
||||
span: span.into_spans(),
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for Group {
|
||||
fn default() -> Self {
|
||||
Group {
|
||||
span: Span::call_site(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for Group {}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Group {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for Group {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("Group")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl cmp::Eq for Group {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Group {
|
||||
fn eq(&self, _other: &Group) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for Group {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
impl Group {
|
||||
#[cfg(feature = "printing")]
|
||||
pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
|
||||
where
|
||||
F: FnOnce(&mut TokenStream),
|
||||
{
|
||||
let mut inner = TokenStream::new();
|
||||
f(&mut inner);
|
||||
printing::delim(Delimiter::None, self.span, tokens, inner);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl private::Sealed for Group {}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for Paren {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
@ -650,250 +734,295 @@ impl Token for 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`
|
||||
"abstract" pub struct Abstract
|
||||
"as" pub struct As
|
||||
"async" pub struct Async
|
||||
"auto" pub struct Auto
|
||||
"await" pub struct Await
|
||||
"become" pub struct Become
|
||||
"box" pub struct Box
|
||||
"break" pub struct Break
|
||||
"const" pub struct Const
|
||||
"continue" pub struct Continue
|
||||
"crate" pub struct Crate
|
||||
"default" pub struct Default
|
||||
"do" pub struct Do
|
||||
"dyn" pub struct Dyn
|
||||
"else" pub struct Else
|
||||
"enum" pub struct Enum
|
||||
"extern" pub struct Extern
|
||||
"final" pub struct Final
|
||||
"fn" pub struct Fn
|
||||
"for" pub struct For
|
||||
"if" pub struct If
|
||||
"impl" pub struct Impl
|
||||
"in" pub struct In
|
||||
"let" pub struct Let
|
||||
"loop" pub struct Loop
|
||||
"macro" pub struct Macro
|
||||
"match" pub struct Match
|
||||
"mod" pub struct Mod
|
||||
"move" pub struct Move
|
||||
"mut" pub struct Mut
|
||||
"override" pub struct Override
|
||||
"priv" pub struct Priv
|
||||
"pub" pub struct Pub
|
||||
"ref" pub struct Ref
|
||||
"return" pub struct Return
|
||||
"Self" pub struct SelfType
|
||||
"self" pub struct SelfValue
|
||||
"static" pub struct Static
|
||||
"struct" pub struct Struct
|
||||
"super" pub struct Super
|
||||
"trait" pub struct Trait
|
||||
"try" pub struct Try
|
||||
"type" pub struct Type
|
||||
"typeof" pub struct Typeof
|
||||
"union" pub struct Union
|
||||
"unsafe" pub struct Unsafe
|
||||
"unsized" pub struct Unsized
|
||||
"use" pub struct Use
|
||||
"virtual" pub struct Virtual
|
||||
"where" pub struct Where
|
||||
"while" pub struct While
|
||||
"yield" pub struct 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 /// `~`
|
||||
"&" pub struct And/1 /// bitwise and logical AND, borrow, references, reference patterns
|
||||
"&&" pub struct AndAnd/2 /// lazy AND, borrow, references, reference patterns
|
||||
"&=" pub struct AndEq/2 /// bitwise AND assignment
|
||||
"@" pub struct At/1 /// subpattern binding
|
||||
"^" pub struct Caret/1 /// bitwise and logical XOR
|
||||
"^=" pub struct CaretEq/2 /// bitwise XOR assignment
|
||||
":" pub struct Colon/1 /// various separators
|
||||
"," pub struct Comma/1 /// various separators
|
||||
"$" pub struct Dollar/1 /// macros
|
||||
"." pub struct Dot/1 /// field access, tuple index
|
||||
".." pub struct DotDot/2 /// range, struct expressions, patterns, range patterns
|
||||
"..." pub struct DotDotDot/3 /// variadic functions, range patterns
|
||||
"..=" pub struct DotDotEq/3 /// inclusive range, range patterns
|
||||
"=" pub struct Eq/1 /// assignment, attributes, various type definitions
|
||||
"==" pub struct EqEq/2 /// equal
|
||||
"=>" pub struct FatArrow/2 /// match arms, macros
|
||||
">=" pub struct Ge/2 /// greater than or equal to, generics
|
||||
">" pub struct Gt/1 /// greater than, generics, paths
|
||||
"<-" pub struct LArrow/2 /// unused
|
||||
"<=" pub struct Le/2 /// less than or equal to
|
||||
"<" pub struct Lt/1 /// less than, generics, paths
|
||||
"-" pub struct Minus/1 /// subtraction, negation
|
||||
"-=" pub struct MinusEq/2 /// subtraction assignment
|
||||
"!=" pub struct Ne/2 /// not equal
|
||||
"!" pub struct Not/1 /// bitwise and logical NOT, macro calls, inner attributes, never type, negative impls
|
||||
"|" pub struct Or/1 /// bitwise and logical OR, closures, patterns in match, if let, and while let
|
||||
"|=" pub struct OrEq/2 /// bitwise OR assignment
|
||||
"||" pub struct OrOr/2 /// lazy OR, closures
|
||||
"::" pub struct PathSep/2 /// path separator
|
||||
"%" pub struct Percent/1 /// remainder
|
||||
"%=" pub struct PercentEq/2 /// remainder assignment
|
||||
"+" pub struct Plus/1 /// addition, trait bounds, macro Kleene matcher
|
||||
"+=" pub struct PlusEq/2 /// addition assignment
|
||||
"#" pub struct Pound/1 /// attributes
|
||||
"?" pub struct Question/1 /// question mark operator, questionably sized, macro Kleene matcher
|
||||
"->" pub struct RArrow/2 /// function return type, closure return type, function pointer type
|
||||
";" pub struct Semi/1 /// terminator for various items and statements, array types
|
||||
"<<" pub struct Shl/2 /// shift left, nested generics
|
||||
"<<=" pub struct ShlEq/3 /// shift left assignment
|
||||
">>" pub struct Shr/2 /// shift right, nested generics
|
||||
">>=" pub struct ShrEq/3 /// shift right assignment, nested generics
|
||||
"/" pub struct Slash/1 /// division
|
||||
"/=" pub struct SlashEq/2 /// division assignment
|
||||
"*" pub struct Star/1 /// multiplication, dereference, raw pointers, macro Kleene matcher, use wildcards
|
||||
"*=" pub struct StarEq/2 /// multiplication assignment
|
||||
"~" pub struct Tilde/1 /// unused since before Rust 1.0
|
||||
}
|
||||
|
||||
define_delimiters! {
|
||||
"{" pub struct Brace /// `{...}`
|
||||
"[" pub struct Bracket /// `[...]`
|
||||
"(" pub struct Paren /// `(...)`
|
||||
" " pub struct Group /// None-delimited group
|
||||
Brace pub struct Brace /// `{`…`}`
|
||||
Bracket pub struct Bracket /// `[`…`]`
|
||||
Parenthesis pub struct Paren /// `(`…`)`
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
};
|
||||
/// A type-macro that expands to the name of the Rust type representation of a
|
||||
/// given token.
|
||||
///
|
||||
/// As a type, `Token!` is commonly used in the type of struct fields, the type
|
||||
/// of a `let` statement, or in turbofish for a `parse` function.
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{Ident, Token};
|
||||
/// use syn::parse::{Parse, ParseStream, Result};
|
||||
///
|
||||
/// // `struct Foo;`
|
||||
/// pub struct UnitStruct {
|
||||
/// struct_token: Token![struct],
|
||||
/// ident: Ident,
|
||||
/// semi_token: Token![;],
|
||||
/// }
|
||||
///
|
||||
/// impl Parse for UnitStruct {
|
||||
/// fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// let struct_token: Token![struct] = input.parse()?;
|
||||
/// let ident: Ident = input.parse()?;
|
||||
/// let semi_token = input.parse::<Token![;]>()?;
|
||||
/// Ok(UnitStruct { struct_token, ident, semi_token })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// As an expression, `Token!` is used for peeking tokens or instantiating
|
||||
/// tokens from a span.
|
||||
///
|
||||
/// ```
|
||||
/// # use syn::{Ident, Token};
|
||||
/// # use syn::parse::{Parse, ParseStream, Result};
|
||||
/// #
|
||||
/// # struct UnitStruct {
|
||||
/// # struct_token: Token![struct],
|
||||
/// # ident: Ident,
|
||||
/// # semi_token: Token![;],
|
||||
/// # }
|
||||
/// #
|
||||
/// # impl Parse for UnitStruct {
|
||||
/// # fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// fn make_unit_struct(name: Ident) -> UnitStruct {
|
||||
/// let span = name.span();
|
||||
/// UnitStruct {
|
||||
/// struct_token: Token![struct](span),
|
||||
/// ident: name,
|
||||
/// semi_token: Token![;](span),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn parse(input: ParseStream) -> Result<()> {
|
||||
/// if input.peek(Token![struct]) {
|
||||
/// let unit_struct: UnitStruct = input.parse()?;
|
||||
/// /* ... */
|
||||
/// }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// See the [token module] documentation for details and examples.
|
||||
///
|
||||
/// [token module]: crate::token
|
||||
#[macro_export]
|
||||
macro_rules! Token {
|
||||
[abstract] => { $crate::token::Abstract };
|
||||
[as] => { $crate::token::As };
|
||||
[async] => { $crate::token::Async };
|
||||
[auto] => { $crate::token::Auto };
|
||||
[await] => { $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::And };
|
||||
[&&] => { $crate::token::AndAnd };
|
||||
[&=] => { $crate::token::AndEq };
|
||||
[@] => { $crate::token::At };
|
||||
[^] => { $crate::token::Caret };
|
||||
[^=] => { $crate::token::CaretEq };
|
||||
[:] => { $crate::token::Colon };
|
||||
[,] => { $crate::token::Comma };
|
||||
[$] => { $crate::token::Dollar };
|
||||
[.] => { $crate::token::Dot };
|
||||
[..] => { $crate::token::DotDot };
|
||||
[...] => { $crate::token::DotDotDot };
|
||||
[..=] => { $crate::token::DotDotEq };
|
||||
[=] => { $crate::token::Eq };
|
||||
[==] => { $crate::token::EqEq };
|
||||
[=>] => { $crate::token::FatArrow };
|
||||
[>=] => { $crate::token::Ge };
|
||||
[>] => { $crate::token::Gt };
|
||||
[<-] => { $crate::token::LArrow };
|
||||
[<=] => { $crate::token::Le };
|
||||
[<] => { $crate::token::Lt };
|
||||
[-] => { $crate::token::Minus };
|
||||
[-=] => { $crate::token::MinusEq };
|
||||
[!=] => { $crate::token::Ne };
|
||||
[!] => { $crate::token::Not };
|
||||
[|] => { $crate::token::Or };
|
||||
[|=] => { $crate::token::OrEq };
|
||||
[||] => { $crate::token::OrOr };
|
||||
[::] => { $crate::token::PathSep };
|
||||
[%] => { $crate::token::Percent };
|
||||
[%=] => { $crate::token::PercentEq };
|
||||
[+] => { $crate::token::Plus };
|
||||
[+=] => { $crate::token::PlusEq };
|
||||
[#] => { $crate::token::Pound };
|
||||
[?] => { $crate::token::Question };
|
||||
[->] => { $crate::token::RArrow };
|
||||
[;] => { $crate::token::Semi };
|
||||
[<<] => { $crate::token::Shl };
|
||||
[<<=] => { $crate::token::ShlEq };
|
||||
[>>] => { $crate::token::Shr };
|
||||
[>>=] => { $crate::token::ShrEq };
|
||||
[/] => { $crate::token::Slash };
|
||||
[/=] => { $crate::token::SlashEq };
|
||||
[*] => { $crate::token::Star };
|
||||
[*=] => { $crate::token::StarEq };
|
||||
[~] => { $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 {
|
||||
pub(crate) mod parsing {
|
||||
use crate::buffer::Cursor;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::parse::ParseStream;
|
||||
use crate::span::FromSpans;
|
||||
use proc_macro2::{Spacing, Span};
|
||||
|
||||
pub fn keyword(input: ParseStream, token: &str) -> Result<Span> {
|
||||
pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> {
|
||||
input.step(|cursor| {
|
||||
if let Some((ident, rest)) = cursor.ident() {
|
||||
if ident == token {
|
||||
@ -904,7 +1033,7 @@ pub mod parsing {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn peek_keyword(cursor: Cursor, token: &str) -> bool {
|
||||
pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool {
|
||||
if let Some((ident, _rest)) = cursor.ident() {
|
||||
ident == token
|
||||
} else {
|
||||
@ -912,16 +1041,17 @@ pub mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> {
|
||||
let mut spans = [input.span(); 3];
|
||||
#[doc(hidden)]
|
||||
pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> {
|
||||
let mut spans = [input.span(); N];
|
||||
punct_helper(input, token, &mut spans)?;
|
||||
Ok(S::from_spans(&spans))
|
||||
Ok(spans)
|
||||
}
|
||||
|
||||
fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> {
|
||||
fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> {
|
||||
input.step(|cursor| {
|
||||
let mut cursor = *cursor;
|
||||
assert!(token.len() <= spans.len());
|
||||
assert_eq!(token.len(), spans.len());
|
||||
|
||||
for (i, ch) in token.chars().enumerate() {
|
||||
match cursor.punct() {
|
||||
@ -944,6 +1074,7 @@ pub mod parsing {
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool {
|
||||
for (i, ch) in token.chars().enumerate() {
|
||||
match cursor.punct() {
|
||||
@ -967,10 +1098,11 @@ pub mod parsing {
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "printing")]
|
||||
pub mod printing {
|
||||
pub(crate) mod printing {
|
||||
use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
|
||||
use quote::TokenStreamExt;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
|
||||
assert_eq!(s.len(), spans.len());
|
||||
|
||||
@ -989,23 +1121,16 @@ pub mod printing {
|
||||
tokens.append(op);
|
||||
}
|
||||
|
||||
pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
|
||||
pub(crate) 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);
|
||||
pub(crate) fn delim(
|
||||
delim: Delimiter,
|
||||
span: Span,
|
||||
tokens: &mut TokenStream,
|
||||
inner: TokenStream,
|
||||
) {
|
||||
let mut g = Group::new(delim, inner);
|
||||
g.set_span(span);
|
||||
tokens.append(g);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use proc_macro2::{Delimiter, TokenStream, TokenTree};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
pub struct TokenTreeHelper<'a>(pub &'a TokenTree);
|
||||
pub(crate) struct TokenTreeHelper<'a>(pub &'a TokenTree);
|
||||
|
||||
impl<'a> PartialEq for TokenTreeHelper<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -78,7 +78,7 @@ impl<'a> Hash for TokenTreeHelper<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TokenStreamHelper<'a>(pub &'a TokenStream);
|
||||
pub(crate) struct TokenStreamHelper<'a>(pub &'a TokenStream);
|
||||
|
||||
impl<'a> PartialEq for TokenStreamHelper<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
|
409
src/ty.rs
409
src/ty.rs
@ -5,16 +5,13 @@ use proc_macro2::TokenStream;
|
||||
ast_enum_of_structs! {
|
||||
/// The possible types that a Rust value could have.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
///
|
||||
/// # Syntax tree enum
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)]
|
||||
#[non_exhaustive]
|
||||
pub enum Type {
|
||||
/// A fixed size array type: `[T; n]`.
|
||||
Array(TypeArray),
|
||||
@ -64,17 +61,16 @@ ast_enum_of_structs! {
|
||||
/// Tokens in type position not interpreted by Syn.
|
||||
Verbatim(TokenStream),
|
||||
|
||||
// Not public API.
|
||||
//
|
||||
// For testing exhaustiveness in downstream code, use the following idiom:
|
||||
//
|
||||
// match ty {
|
||||
// #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
|
||||
//
|
||||
// Type::Array(ty) => {...}
|
||||
// Type::BareFn(ty) => {...}
|
||||
// ...
|
||||
// Type::Verbatim(ty) => {...}
|
||||
//
|
||||
// #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))]
|
||||
// _ => { /* some sane fallback */ }
|
||||
// }
|
||||
//
|
||||
@ -82,17 +78,11 @@ ast_enum_of_structs! {
|
||||
// a variant. You will be notified by a test failure when a variant is
|
||||
// added, so that you can add code to handle it, but your library will
|
||||
// continue to compile and work for downstream users in the interim.
|
||||
#[cfg(syn_no_non_exhaustive)]
|
||||
#[doc(hidden)]
|
||||
__NonExhaustive,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A fixed size array type: `[T; n]`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeArray {
|
||||
pub bracket_token: token::Bracket,
|
||||
@ -104,9 +94,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A bare function type: `fn(usize) -> bool`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeBareFn {
|
||||
pub lifetimes: Option<BoundLifetimes>,
|
||||
@ -115,16 +102,13 @@ ast_struct! {
|
||||
pub fn_token: Token![fn],
|
||||
pub paren_token: token::Paren,
|
||||
pub inputs: Punctuated<BareFnArg, Token![,]>,
|
||||
pub variadic: Option<Variadic>,
|
||||
pub variadic: Option<BareVariadic>,
|
||||
pub output: ReturnType,
|
||||
}
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A type contained within invisible delimiters.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeGroup {
|
||||
pub group_token: token::Group,
|
||||
@ -135,9 +119,6 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
|
||||
/// a lifetime.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeImplTrait {
|
||||
pub impl_token: Token![impl],
|
||||
@ -147,9 +128,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// Indication that a type should be inferred by the compiler: `_`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeInfer {
|
||||
pub underscore_token: Token![_],
|
||||
@ -158,9 +136,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A macro in the type position.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeMacro {
|
||||
pub mac: Macro,
|
||||
@ -169,9 +144,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The never type: `!`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeNever {
|
||||
pub bang_token: Token![!],
|
||||
@ -180,9 +152,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A parenthesized type equivalent to the inner type.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeParen {
|
||||
pub paren_token: token::Paren,
|
||||
@ -193,9 +162,6 @@ ast_struct! {
|
||||
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 only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypePath {
|
||||
pub qself: Option<QSelf>,
|
||||
@ -205,9 +171,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A raw pointer type: `*const T` or `*mut T`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypePtr {
|
||||
pub star_token: Token![*],
|
||||
@ -219,9 +182,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A reference type: `&'a T` or `&'a mut T`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeReference {
|
||||
pub and_token: Token![&],
|
||||
@ -233,9 +193,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A dynamically sized slice type: `[T]`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeSlice {
|
||||
pub bracket_token: token::Bracket,
|
||||
@ -246,9 +203,6 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a
|
||||
/// trait or a lifetime.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeTraitObject {
|
||||
pub dyn_token: Option<Token![dyn]>,
|
||||
@ -258,9 +212,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A tuple type: `(A, B, C, String)`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or
|
||||
/// `"full"` feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeTuple {
|
||||
pub paren_token: token::Paren,
|
||||
@ -270,9 +221,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The binary interface of a function: `extern "C"`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Abi {
|
||||
pub extern_token: Token![extern],
|
||||
@ -282,9 +230,6 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An argument in a function type: the `usize` in `fn(usize) -> bool`.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct BareFnArg {
|
||||
pub attrs: Vec<Attribute>,
|
||||
@ -294,32 +239,18 @@ ast_struct! {
|
||||
}
|
||||
|
||||
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 only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
/// The variadic argument of a function pointer like `fn(usize, ...)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Variadic {
|
||||
pub struct BareVariadic {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub name: Option<(Ident, Token![:])>,
|
||||
pub dots: Token![...],
|
||||
pub comma: Option<Token![,]>,
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum! {
|
||||
/// Return type of a function signature.
|
||||
///
|
||||
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
||||
/// feature.*
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum ReturnType {
|
||||
/// Return type is not specified.
|
||||
@ -332,12 +263,12 @@ ast_enum! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing {
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::ext::IdentExt;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::path;
|
||||
use proc_macro2::{Punct, Spacing, Span, TokenTree};
|
||||
use proc_macro2::Span;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Type {
|
||||
@ -392,7 +323,7 @@ pub mod parsing {
|
||||
{
|
||||
if let Type::Path(mut ty) = *group.elem {
|
||||
let arguments = &mut ty.path.segments.last_mut().unwrap().arguments;
|
||||
if let PathArguments::None = arguments {
|
||||
if arguments.is_none() {
|
||||
*arguments = PathArguments::AngleBracketed(input.parse()?);
|
||||
Path::parse_rest(input, &mut ty.path, false)?;
|
||||
return Ok(Type::Path(ty));
|
||||
@ -503,7 +434,8 @@ pub mod parsing {
|
||||
..trait_bound
|
||||
})
|
||||
}
|
||||
other @ TypeParamBound::Lifetime(_) => other,
|
||||
other @ (TypeParamBound::Lifetime(_)
|
||||
| TypeParamBound::Verbatim(_)) => other,
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
@ -530,13 +462,9 @@ pub mod parsing {
|
||||
|| lookahead.peek(Token![unsafe])
|
||||
|| lookahead.peek(Token![extern])
|
||||
{
|
||||
let allow_mut_self = true;
|
||||
if let Some(mut bare_fn) = parse_bare_fn(input, allow_mut_self)? {
|
||||
bare_fn.lifetimes = lifetimes;
|
||||
Ok(Type::BareFn(bare_fn))
|
||||
} else {
|
||||
Ok(Type::Verbatim(verbatim::between(begin, input)))
|
||||
}
|
||||
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])
|
||||
@ -545,49 +473,22 @@ pub mod parsing {
|
||||
|| lookahead.peek(Token![::])
|
||||
|| lookahead.peek(Token![<])
|
||||
{
|
||||
let dyn_token: Option<Token![dyn]> = input.parse()?;
|
||||
if let Some(dyn_token) = dyn_token {
|
||||
let dyn_span = dyn_token.span;
|
||||
let star_token: Option<Token![*]> = input.parse()?;
|
||||
let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?;
|
||||
return Ok(if star_token.is_some() {
|
||||
Type::Verbatim(verbatim::between(begin, input))
|
||||
} else {
|
||||
Type::TraitObject(TypeTraitObject {
|
||||
dyn_token: Some(dyn_token),
|
||||
bounds,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
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 input.peek(Token![!]) && !input.peek(Token![!=]) && ty.path.is_mod_style() {
|
||||
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![+]) {
|
||||
@ -619,6 +520,19 @@ pub mod parsing {
|
||||
}
|
||||
|
||||
Ok(Type::Path(ty))
|
||||
} else if lookahead.peek(Token![dyn]) {
|
||||
let dyn_token: Token![dyn] = input.parse()?;
|
||||
let dyn_span = dyn_token.span;
|
||||
let star_token: Option<Token![*]> = input.parse()?;
|
||||
let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?;
|
||||
return Ok(if star_token.is_some() {
|
||||
Type::Verbatim(verbatim::between(&begin, input))
|
||||
} else {
|
||||
Type::TraitObject(TypeTraitObject {
|
||||
dyn_token: Some(dyn_token),
|
||||
bounds,
|
||||
})
|
||||
});
|
||||
} else if lookahead.peek(token::Bracket) {
|
||||
let content;
|
||||
let bracket_token = bracketed!(content in input);
|
||||
@ -716,61 +630,47 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeBareFn {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_mut_self = false;
|
||||
parse_bare_fn(input, allow_mut_self).map(Option::unwrap)
|
||||
}
|
||||
}
|
||||
let args;
|
||||
let mut variadic = None;
|
||||
|
||||
fn parse_bare_fn(input: ParseStream, allow_mut_self: bool) -> Result<Option<TypeBareFn>> {
|
||||
let args;
|
||||
let mut variadic = None;
|
||||
let mut has_mut_self = false;
|
||||
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();
|
||||
|
||||
let bare_fn = 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)?;
|
||||
|
||||
while !args.is_empty() {
|
||||
let attrs = args.call(Attribute::parse_outer)?;
|
||||
if inputs.empty_or_trailing()
|
||||
&& (args.peek(Token![...])
|
||||
|| args.peek(Ident)
|
||||
&& args.peek2(Token![:])
|
||||
&& args.peek3(Token![...]))
|
||||
{
|
||||
variadic = Some(parse_bare_variadic(&args, attrs)?);
|
||||
break;
|
||||
}
|
||||
|
||||
if inputs.empty_or_trailing() && args.peek(Token![...]) {
|
||||
variadic = Some(Variadic {
|
||||
attrs,
|
||||
dots: args.parse()?,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(arg) = parse_bare_fn_arg(&args, allow_mut_self)? {
|
||||
let allow_self = inputs.is_empty();
|
||||
let arg = parse_bare_fn_arg(&args, allow_self)?;
|
||||
inputs.push_value(BareFnArg { attrs, ..arg });
|
||||
} else {
|
||||
has_mut_self = true;
|
||||
}
|
||||
if args.is_empty() {
|
||||
break;
|
||||
}
|
||||
if args.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let comma = args.parse()?;
|
||||
if !has_mut_self {
|
||||
let comma = args.parse()?;
|
||||
inputs.push_punct(comma);
|
||||
}
|
||||
}
|
||||
|
||||
inputs
|
||||
},
|
||||
variadic,
|
||||
output: input.call(ReturnType::without_plus)?,
|
||||
};
|
||||
|
||||
if has_mut_self {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(bare_fn))
|
||||
inputs
|
||||
},
|
||||
variadic,
|
||||
output: input.call(ReturnType::without_plus)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -838,29 +738,7 @@ pub mod parsing {
|
||||
impl Parse for TypePath {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let expr_style = false;
|
||||
let (qself, mut path) = path::parsing::qpath(input, expr_style)?;
|
||||
|
||||
while path.segments.last().unwrap().arguments.is_empty()
|
||||
&& (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
|
||||
{
|
||||
input.parse::<Option<Token![::]>>()?;
|
||||
let args: ParenthesizedGenericArguments = input.parse()?;
|
||||
let allow_associated_type = cfg!(feature = "full")
|
||||
&& match &args.output {
|
||||
ReturnType::Default => true,
|
||||
ReturnType::Type(_, ty) => match **ty {
|
||||
// TODO: probably some of the other kinds allow this too.
|
||||
Type::Paren(_) => true,
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
let parenthesized = PathArguments::Parenthesized(args);
|
||||
path.segments.last_mut().unwrap().arguments = parenthesized;
|
||||
if allow_associated_type {
|
||||
Path::parse_rest(input, &mut path, expr_style)?;
|
||||
}
|
||||
}
|
||||
|
||||
let (qself, path) = path::parsing::qpath(input, expr_style)?;
|
||||
Ok(TypePath { qself, path })
|
||||
}
|
||||
}
|
||||
@ -928,7 +806,7 @@ pub mod parsing {
|
||||
let mut at_least_one_trait = false;
|
||||
for bound in &bounds {
|
||||
match bound {
|
||||
TypeParamBound::Trait(_) => {
|
||||
TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => {
|
||||
at_least_one_trait = true;
|
||||
break;
|
||||
}
|
||||
@ -968,7 +846,7 @@ pub mod parsing {
|
||||
let mut at_least_one_trait = false;
|
||||
for bound in &bounds {
|
||||
match bound {
|
||||
TypeParamBound::Trait(_) => {
|
||||
TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => {
|
||||
at_least_one_trait = true;
|
||||
break;
|
||||
}
|
||||
@ -1024,75 +902,72 @@ pub mod parsing {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for BareFnArg {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_mut_self = false;
|
||||
parse_bare_fn_arg(input, allow_mut_self).map(Option::unwrap)
|
||||
let allow_self = false;
|
||||
parse_bare_fn_arg(input, allow_self)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bare_fn_arg(
|
||||
input: ParseStream,
|
||||
mut allow_mut_self: bool,
|
||||
) -> Result<Option<BareFnArg>> {
|
||||
let mut has_mut_self = false;
|
||||
let arg = BareFnArg {
|
||||
attrs: input.call(Attribute::parse_outer)?,
|
||||
name: {
|
||||
if (input.peek(Ident) || input.peek(Token![_]) || input.peek(Token![self]))
|
||||
&& input.peek2(Token![:])
|
||||
&& !input.peek2(Token![::])
|
||||
{
|
||||
let name = input.call(Ident::parse_any)?;
|
||||
let colon: Token![:] = input.parse()?;
|
||||
Some((name, colon))
|
||||
} else if allow_mut_self
|
||||
&& input.peek(Token![mut])
|
||||
&& input.peek2(Token![self])
|
||||
&& input.peek3(Token![:])
|
||||
&& !input.peek3(Token![::])
|
||||
{
|
||||
has_mut_self = true;
|
||||
allow_mut_self = false;
|
||||
input.parse::<Token![mut]>()?;
|
||||
input.parse::<Token![self]>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
ty: if !has_mut_self && input.peek(Token![...]) {
|
||||
let dot3 = input.parse::<Token![...]>()?;
|
||||
let args = vec![
|
||||
TokenTree::Punct(Punct::new('.', Spacing::Joint)),
|
||||
TokenTree::Punct(Punct::new('.', Spacing::Joint)),
|
||||
TokenTree::Punct(Punct::new('.', Spacing::Alone)),
|
||||
];
|
||||
let tokens: TokenStream = args
|
||||
.into_iter()
|
||||
.zip(&dot3.spans)
|
||||
.map(|(mut arg, span)| {
|
||||
arg.set_span(*span);
|
||||
arg
|
||||
})
|
||||
.collect();
|
||||
Type::Verbatim(tokens)
|
||||
} else if allow_mut_self && input.peek(Token![mut]) && input.peek2(Token![self]) {
|
||||
has_mut_self = true;
|
||||
input.parse::<Token![mut]>()?;
|
||||
Type::Path(TypePath {
|
||||
qself: None,
|
||||
path: input.parse::<Token![self]>()?.into(),
|
||||
})
|
||||
} else {
|
||||
input.parse()?
|
||||
},
|
||||
fn parse_bare_fn_arg(input: ParseStream, allow_self: bool) -> Result<BareFnArg> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
|
||||
let begin = input.fork();
|
||||
|
||||
let has_mut_self = allow_self && input.peek(Token![mut]) && input.peek2(Token![self]);
|
||||
if has_mut_self {
|
||||
input.parse::<Token![mut]>()?;
|
||||
}
|
||||
|
||||
let mut has_self = false;
|
||||
let mut name = if (input.peek(Ident) || input.peek(Token![_]) || {
|
||||
has_self = allow_self && input.peek(Token![self]);
|
||||
has_self
|
||||
}) && input.peek2(Token![:])
|
||||
&& !input.peek2(Token![::])
|
||||
{
|
||||
let name = input.call(Ident::parse_any)?;
|
||||
let colon: Token![:] = input.parse()?;
|
||||
Some((name, colon))
|
||||
} else {
|
||||
has_self = false;
|
||||
None
|
||||
};
|
||||
|
||||
if has_mut_self {
|
||||
Ok(None)
|
||||
let ty = if allow_self && !has_self && input.peek(Token![mut]) && input.peek2(Token![self])
|
||||
{
|
||||
input.parse::<Token![mut]>()?;
|
||||
input.parse::<Token![self]>()?;
|
||||
None
|
||||
} else if has_mut_self && name.is_none() {
|
||||
input.parse::<Token![self]>()?;
|
||||
None
|
||||
} else {
|
||||
Ok(Some(arg))
|
||||
}
|
||||
Some(input.parse()?)
|
||||
};
|
||||
|
||||
let ty = match ty {
|
||||
Some(ty) if !has_mut_self => ty,
|
||||
_ => {
|
||||
name = None;
|
||||
Type::Verbatim(verbatim::between(&begin, input))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(BareFnArg { attrs, name, ty })
|
||||
}
|
||||
|
||||
fn parse_bare_variadic(input: ParseStream, attrs: Vec<Attribute>) -> Result<BareVariadic> {
|
||||
Ok(BareVariadic {
|
||||
attrs,
|
||||
name: if input.peek(Ident) || input.peek(Token![_]) {
|
||||
let name = input.call(Ident::parse_any)?;
|
||||
let colon: Token![:] = input.parse()?;
|
||||
Some((name, colon))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
dots: input.parse()?,
|
||||
comma: input.parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
@ -1202,6 +1077,11 @@ mod printing {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
self.elems.to_tokens(tokens);
|
||||
// If we only have one argument, we need a trailing comma to
|
||||
// distinguish TypeTuple from TypeParen.
|
||||
if self.elems.len() == 1 && !self.elems.trailing_punct() {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1287,10 +1167,15 @@ mod printing {
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Variadic {
|
||||
impl ToTokens for BareVariadic {
|
||||
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.dots.to_tokens(tokens);
|
||||
self.comma.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::parse::{ParseBuffer, ParseStream};
|
||||
use crate::parse::ParseStream;
|
||||
use proc_macro2::{Delimiter, TokenStream};
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
|
||||
pub fn between<'a>(begin: ParseBuffer<'a>, end: ParseStream<'a>) -> TokenStream {
|
||||
pub(crate) fn between<'a>(begin: ParseStream<'a>, end: ParseStream<'a>) -> TokenStream {
|
||||
let end = end.cursor();
|
||||
let mut cursor = begin.cursor();
|
||||
assert!(crate::buffer::same_buffer(end, cursor));
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub fn skip(mut s: &str) -> &str {
|
||||
pub(crate) fn skip(mut s: &str) -> &str {
|
||||
'skip: while !s.is_empty() {
|
||||
let byte = s.as_bytes()[0];
|
||||
if byte == b'/' {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_span;
|
||||
extern crate thin_vec;
|
||||
|
||||
@ -12,7 +13,6 @@ use rustc_ast::ast::Arm;
|
||||
use rustc_ast::ast::AssocConstraint;
|
||||
use rustc_ast::ast::AssocConstraintKind;
|
||||
use rustc_ast::ast::AssocItemKind;
|
||||
use rustc_ast::ast::Async;
|
||||
use rustc_ast::ast::AttrArgs;
|
||||
use rustc_ast::ast::AttrArgsEq;
|
||||
use rustc_ast::ast::AttrId;
|
||||
@ -26,11 +26,15 @@ use rustc_ast::ast::BindingAnnotation;
|
||||
use rustc_ast::ast::Block;
|
||||
use rustc_ast::ast::BlockCheckMode;
|
||||
use rustc_ast::ast::BorrowKind;
|
||||
use rustc_ast::ast::BoundConstness;
|
||||
use rustc_ast::ast::BoundPolarity;
|
||||
use rustc_ast::ast::ByRef;
|
||||
use rustc_ast::ast::CaptureBy;
|
||||
use rustc_ast::ast::Closure;
|
||||
use rustc_ast::ast::ClosureBinder;
|
||||
use rustc_ast::ast::Const;
|
||||
use rustc_ast::ast::ConstItem;
|
||||
use rustc_ast::ast::CoroutineKind;
|
||||
use rustc_ast::ast::Crate;
|
||||
use rustc_ast::ast::Defaultness;
|
||||
use rustc_ast::ast::DelimArgs;
|
||||
@ -46,8 +50,24 @@ use rustc_ast::ast::FnDecl;
|
||||
use rustc_ast::ast::FnHeader;
|
||||
use rustc_ast::ast::FnRetTy;
|
||||
use rustc_ast::ast::FnSig;
|
||||
use rustc_ast::ast::ForLoopKind;
|
||||
use rustc_ast::ast::ForeignItemKind;
|
||||
use rustc_ast::ast::ForeignMod;
|
||||
use rustc_ast::ast::FormatAlignment;
|
||||
use rustc_ast::ast::FormatArgPosition;
|
||||
use rustc_ast::ast::FormatArgPositionKind;
|
||||
use rustc_ast::ast::FormatArgs;
|
||||
use rustc_ast::ast::FormatArgsPiece;
|
||||
use rustc_ast::ast::FormatArgument;
|
||||
use rustc_ast::ast::FormatArgumentKind;
|
||||
use rustc_ast::ast::FormatArguments;
|
||||
use rustc_ast::ast::FormatCount;
|
||||
use rustc_ast::ast::FormatDebugHex;
|
||||
use rustc_ast::ast::FormatOptions;
|
||||
use rustc_ast::ast::FormatPlaceholder;
|
||||
use rustc_ast::ast::FormatSign;
|
||||
use rustc_ast::ast::FormatTrait;
|
||||
use rustc_ast::ast::GenBlockKind;
|
||||
use rustc_ast::ast::GenericArg;
|
||||
use rustc_ast::ast::GenericArgs;
|
||||
use rustc_ast::ast::GenericBound;
|
||||
@ -76,7 +96,6 @@ use rustc_ast::ast::Local;
|
||||
use rustc_ast::ast::LocalKind;
|
||||
use rustc_ast::ast::MacCall;
|
||||
use rustc_ast::ast::MacCallStmt;
|
||||
use rustc_ast::ast::MacDelimiter;
|
||||
use rustc_ast::ast::MacStmtStyle;
|
||||
use rustc_ast::ast::MacroDef;
|
||||
use rustc_ast::ast::MetaItemLit;
|
||||
@ -92,6 +111,7 @@ use rustc_ast::ast::Param;
|
||||
use rustc_ast::ast::ParenthesizedArgs;
|
||||
use rustc_ast::ast::Pat;
|
||||
use rustc_ast::ast::PatField;
|
||||
use rustc_ast::ast::PatFieldsRest;
|
||||
use rustc_ast::ast::PatKind;
|
||||
use rustc_ast::ast::Path;
|
||||
use rustc_ast::ast::PathSegment;
|
||||
@ -100,6 +120,7 @@ use rustc_ast::ast::QSelf;
|
||||
use rustc_ast::ast::RangeEnd;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_ast::ast::RangeSyntax;
|
||||
use rustc_ast::ast::StaticItem;
|
||||
use rustc_ast::ast::Stmt;
|
||||
use rustc_ast::ast::StmtKind;
|
||||
use rustc_ast::ast::StrLit;
|
||||
@ -108,7 +129,7 @@ use rustc_ast::ast::StructExpr;
|
||||
use rustc_ast::ast::StructRest;
|
||||
use rustc_ast::ast::Term;
|
||||
use rustc_ast::ast::Trait;
|
||||
use rustc_ast::ast::TraitBoundModifier;
|
||||
use rustc_ast::ast::TraitBoundModifiers;
|
||||
use rustc_ast::ast::TraitObjectSyntax;
|
||||
use rustc_ast::ast::TraitRef;
|
||||
use rustc_ast::ast::Ty;
|
||||
@ -133,13 +154,15 @@ use rustc_ast::ast::WhereRegionPredicate;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, Lit, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{
|
||||
AttrTokenStream, AttrTokenTree, AttributesData, DelimSpan, LazyAttrTokenStream, Spacing,
|
||||
TokenStream, TokenTree,
|
||||
AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing, DelimSpan, LazyAttrTokenStream,
|
||||
Spacing, TokenStream, TokenTree,
|
||||
};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{Span, Symbol, SyntaxContext, DUMMY_SP};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, SyntaxContext, DUMMY_SP};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
pub trait SpanlessEq {
|
||||
@ -174,6 +197,16 @@ impl<T: SpanlessEq> SpanlessEq for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SpanlessEq, E: SpanlessEq> SpanlessEq for Result<T, E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Ok(this), Ok(other)) => SpanlessEq::eq(this, other),
|
||||
(Err(this), Err(other)) => SpanlessEq::eq(this, other),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SpanlessEq> SpanlessEq for [T] {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b))
|
||||
@ -196,6 +229,17 @@ impl<T: SpanlessEq> SpanlessEq for ThinVec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: SpanlessEq, S: BuildHasher> SpanlessEq for HashMap<K, V, S> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len()
|
||||
&& self.iter().all(|(key, this_v)| {
|
||||
other
|
||||
.get(key)
|
||||
.map_or(false, |other_v| SpanlessEq::eq(this_v, other_v))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
SpanlessEq::eq(&self.node, &other.node)
|
||||
@ -246,6 +290,7 @@ macro_rules! spanless_eq_partial_eq {
|
||||
spanless_eq_partial_eq!(bool);
|
||||
spanless_eq_partial_eq!(u8);
|
||||
spanless_eq_partial_eq!(u16);
|
||||
spanless_eq_partial_eq!(u32);
|
||||
spanless_eq_partial_eq!(u128);
|
||||
spanless_eq_partial_eq!(usize);
|
||||
spanless_eq_partial_eq!(char);
|
||||
@ -255,6 +300,7 @@ spanless_eq_partial_eq!(CommentKind);
|
||||
spanless_eq_partial_eq!(Delimiter);
|
||||
spanless_eq_partial_eq!(InlineAsmOptions);
|
||||
spanless_eq_partial_eq!(token::LitKind);
|
||||
spanless_eq_partial_eq!(ErrorGuaranteed);
|
||||
|
||||
macro_rules! spanless_eq_struct {
|
||||
{
|
||||
@ -414,18 +460,25 @@ spanless_eq_struct!(AttributesData; attrs tokens);
|
||||
spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl decl_span);
|
||||
spanless_eq_struct!(BindingAnnotation; 0 1);
|
||||
spanless_eq_struct!(Block; stmts id rules span tokens could_be_bare_literal);
|
||||
spanless_eq_struct!(Closure; binder capture_clause asyncness movability fn_decl body !fn_decl_span);
|
||||
spanless_eq_struct!(Closure; binder capture_clause constness coroutine_kind movability fn_decl body !fn_decl_span !fn_arg_span);
|
||||
spanless_eq_struct!(ConstItem; defaultness generics ty expr);
|
||||
spanless_eq_struct!(Crate; attrs items spans id is_placeholder);
|
||||
spanless_eq_struct!(DelimArgs; dspan delim tokens);
|
||||
spanless_eq_struct!(DelimSpacing; open close);
|
||||
spanless_eq_struct!(EnumDef; variants);
|
||||
spanless_eq_struct!(Expr; id kind span attrs !tokens);
|
||||
spanless_eq_struct!(ExprField; attrs id span ident expr is_shorthand is_placeholder);
|
||||
spanless_eq_struct!(FieldDef; attrs id span vis ident ty is_placeholder);
|
||||
spanless_eq_struct!(FnDecl; inputs output);
|
||||
spanless_eq_struct!(FnHeader; constness asyncness unsafety ext);
|
||||
spanless_eq_struct!(Fn; defaultness generics sig body);
|
||||
spanless_eq_struct!(FnDecl; inputs output);
|
||||
spanless_eq_struct!(FnHeader; constness coroutine_kind unsafety ext);
|
||||
spanless_eq_struct!(FnSig; header decl span);
|
||||
spanless_eq_struct!(ForeignMod; unsafety abi items);
|
||||
spanless_eq_struct!(FormatArgPosition; index kind span);
|
||||
spanless_eq_struct!(FormatArgs; span template arguments);
|
||||
spanless_eq_struct!(FormatArgument; kind expr);
|
||||
spanless_eq_struct!(FormatOptions; width precision alignment fill sign alternate zero_pad debug_hex);
|
||||
spanless_eq_struct!(FormatPlaceholder; argument span format_trait format_options);
|
||||
spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind !colon_span);
|
||||
spanless_eq_struct!(Generics; params where_clause span);
|
||||
spanless_eq_struct!(Impl; defaultness unsafety generics constness polarity of_trait self_ty items);
|
||||
@ -436,10 +489,10 @@ spanless_eq_struct!(Label; ident);
|
||||
spanless_eq_struct!(Lifetime; id ident);
|
||||
spanless_eq_struct!(Lit; kind symbol suffix);
|
||||
spanless_eq_struct!(Local; pat ty kind id span attrs !tokens);
|
||||
spanless_eq_struct!(MacCall; path args prior_type_ascription);
|
||||
spanless_eq_struct!(MacCall; path args);
|
||||
spanless_eq_struct!(MacCallStmt; mac style attrs tokens);
|
||||
spanless_eq_struct!(MacroDef; body macro_rules);
|
||||
spanless_eq_struct!(MetaItemLit; token_lit kind span);
|
||||
spanless_eq_struct!(MetaItemLit; symbol suffix kind span);
|
||||
spanless_eq_struct!(MethodCall; seg receiver args !span);
|
||||
spanless_eq_struct!(ModSpans; !inner_span !inject_use_span);
|
||||
spanless_eq_struct!(MutTy; ty mutbl);
|
||||
@ -451,11 +504,13 @@ spanless_eq_struct!(Path; span segments tokens);
|
||||
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!(StaticItem; ty mutability expr);
|
||||
spanless_eq_struct!(Stmt; id kind span);
|
||||
spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped);
|
||||
spanless_eq_struct!(StrLit; symbol suffix symbol_unescaped style span);
|
||||
spanless_eq_struct!(StructExpr; qself path fields rest);
|
||||
spanless_eq_struct!(Token; kind span);
|
||||
spanless_eq_struct!(Trait; unsafety is_auto generics bounds items);
|
||||
spanless_eq_struct!(TraitBoundModifiers; constness polarity);
|
||||
spanless_eq_struct!(TraitRef; path ref_id);
|
||||
spanless_eq_struct!(Ty; id kind span tokens);
|
||||
spanless_eq_struct!(TyAlias; defaultness generics where_clauses !where_predicates_split bounds ty);
|
||||
@ -468,25 +523,36 @@ spanless_eq_struct!(WhereClause; has_where_token predicates span);
|
||||
spanless_eq_struct!(WhereEqPredicate; span lhs_ty rhs_ty);
|
||||
spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds);
|
||||
spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0));
|
||||
spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0) Type(0) MacCall(0));
|
||||
spanless_eq_enum!(AssocConstraintKind; Equality(term) Bound(bounds));
|
||||
spanless_eq_enum!(Async; Yes(span closure_id return_impl_trait_id) No);
|
||||
spanless_eq_enum!(AssocItemKind; Const(0) Fn(0) Type(0) MacCall(0));
|
||||
spanless_eq_enum!(AttrArgs; Empty Delimited(0) Eq(0 1));
|
||||
spanless_eq_enum!(AttrArgsEq; Ast(0) Hir(0));
|
||||
spanless_eq_enum!(AttrStyle; Outer Inner);
|
||||
spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2) Attributes(0));
|
||||
spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) Attributes(0));
|
||||
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!(BlockCheckMode; Default Unsafe(0));
|
||||
spanless_eq_enum!(BorrowKind; Ref Raw);
|
||||
spanless_eq_enum!(BoundConstness; Never Always(0) Maybe(0));
|
||||
spanless_eq_enum!(BoundPolarity; Positive Negative(0) Maybe(0));
|
||||
spanless_eq_enum!(ByRef; Yes No);
|
||||
spanless_eq_enum!(CaptureBy; Value Ref);
|
||||
spanless_eq_enum!(CaptureBy; Value(move_kw) Ref);
|
||||
spanless_eq_enum!(ClosureBinder; NotPresent For(span generic_params));
|
||||
spanless_eq_enum!(Const; Yes(0) No);
|
||||
spanless_eq_enum!(Defaultness; Default(0) Final);
|
||||
spanless_eq_enum!(Extern; None Implicit(0) Explicit(0 1));
|
||||
spanless_eq_enum!(FloatTy; F32 F64);
|
||||
spanless_eq_enum!(FnRetTy; Default(0) Ty(0));
|
||||
spanless_eq_enum!(ForLoopKind; For ForAwait);
|
||||
spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0) TyAlias(0) MacCall(0));
|
||||
spanless_eq_enum!(FormatAlignment; Left Right Center);
|
||||
spanless_eq_enum!(FormatArgPositionKind; Implicit Number Named);
|
||||
spanless_eq_enum!(FormatArgsPiece; Literal(0) Placeholder(0));
|
||||
spanless_eq_enum!(FormatArgumentKind; Normal Named(0) Captured(0));
|
||||
spanless_eq_enum!(FormatCount; Literal(0) Argument(0));
|
||||
spanless_eq_enum!(FormatDebugHex; Lower Upper);
|
||||
spanless_eq_enum!(FormatSign; Plus Minus);
|
||||
spanless_eq_enum!(FormatTrait; Display Debug LowerExp UpperExp Octal Pointer Binary LowerHex UpperHex);
|
||||
spanless_eq_enum!(GenBlockKind; Async Gen AsyncGen);
|
||||
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));
|
||||
@ -500,50 +566,52 @@ 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!(LocalKind; Decl Init(0) InitElse(0 1));
|
||||
spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace);
|
||||
spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces);
|
||||
spanless_eq_enum!(ModKind; Loaded(0 1 2) Unloaded);
|
||||
spanless_eq_enum!(Movability; Static Movable);
|
||||
spanless_eq_enum!(Mutability; Mut Not);
|
||||
spanless_eq_enum!(PatFieldsRest; Rest None);
|
||||
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) Empty MacCall(0));
|
||||
spanless_eq_enum!(StrStyle; Cooked Raw(0));
|
||||
spanless_eq_enum!(StructRest; Base(0) Rest(0) None);
|
||||
spanless_eq_enum!(Term; Ty(0) Const(0));
|
||||
spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1 2));
|
||||
spanless_eq_enum!(TraitBoundModifier; None Maybe MaybeConst MaybeConstMaybe);
|
||||
spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1 2 3));
|
||||
spanless_eq_enum!(TraitObjectSyntax; Dyn DynStar None);
|
||||
spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
|
||||
spanless_eq_enum!(UnOp; Deref Not Neg);
|
||||
spanless_eq_enum!(Unsafe; Yes(0) No);
|
||||
spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
|
||||
spanless_eq_enum!(UseTreeKind; Simple(0) Nested(0) Glob);
|
||||
spanless_eq_enum!(VariantData; Struct(0 1) Tuple(0 1) Unit(0));
|
||||
spanless_eq_enum!(VariantData; Struct(fields recovered) Tuple(0 1) Unit(0));
|
||||
spanless_eq_enum!(VisibilityKind; Public Restricted(path id shorthand) Inherited);
|
||||
spanless_eq_enum!(WherePredicate; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
|
||||
spanless_eq_enum!(ExprKind; Box(0) Array(0) ConstBlock(0) Call(0 1)
|
||||
MethodCall(0) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1)
|
||||
Let(0 1 2) If(0 1 2) While(0 1 2) ForLoop(0 1 2 3) Loop(0 1 2) Match(0 1)
|
||||
Closure(0) 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) Underscore Range(0 1 2) Path(0 1)
|
||||
AddrOf(0 1 2) Break(0 1) Continue(0) Ret(0) InlineAsm(0) MacCall(0)
|
||||
Struct(0) Repeat(0 1) Paren(0) Try(0) Yield(0) Yeet(0) IncludedBytes(0)
|
||||
Err);
|
||||
spanless_eq_enum!(CoroutineKind; Async(span closure_id return_impl_trait_id)
|
||||
Gen(span closure_id return_impl_trait_id)
|
||||
AsyncGen(span closure_id return_impl_trait_id));
|
||||
spanless_eq_enum!(ExprKind; Array(0) ConstBlock(0) Call(0 1) MethodCall(0)
|
||||
Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) Let(0 1 2 3)
|
||||
If(0 1 2) While(0 1 2) ForLoop(pat iter body label kind) Loop(0 1 2)
|
||||
Match(0 1) Closure(0) Block(0 1) Gen(0 1 2) Await(0 1) TryBlock(0)
|
||||
Assign(0 1 2) AssignOp(0 1 2) Field(0 1) Index(0 1 2) Underscore
|
||||
Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1) Continue(0) Ret(0)
|
||||
InlineAsm(0) OffsetOf(0 1) MacCall(0) Struct(0) Repeat(0 1) Paren(0) Try(0)
|
||||
Yield(0) Yeet(0) Become(0) IncludedBytes(0) FormatArgs(0) Err);
|
||||
spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr)
|
||||
InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(anon_const)
|
||||
Sym(sym));
|
||||
spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1 2)
|
||||
Fn(0) Mod(0 1) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1) Struct(0 1)
|
||||
spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0) Const(0) Fn(0)
|
||||
Mod(0 1) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1) Struct(0 1)
|
||||
Union(0 1) Trait(0) TraitAlias(0 1) Impl(0) MacCall(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);
|
||||
spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0 1) CStr(0 1) Byte(0) Char(0)
|
||||
Int(0 1) Float(0 1) Bool(0) Err);
|
||||
spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2 3) TupleStruct(0 1 2)
|
||||
Or(0) Path(0 1) Tuple(0) Box(0) Ref(0 1) Lit(0) Range(0 1 2) Slice(0) Rest
|
||||
Paren(0) MacCall(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 MacCall(0) Err CVarArgs);
|
||||
Never Paren(0) MacCall(0));
|
||||
spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Ref(0 1) BareFn(0) Never
|
||||
Tup(0) AnonStruct(0) AnonUnion(0) Path(0 1) TraitObject(0 1) ImplTrait(0 1)
|
||||
Paren(0) Typeof(0) Infer ImplicitSelf MacCall(0) Err CVarArgs);
|
||||
|
||||
impl SpanlessEq for Ident {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -591,17 +659,20 @@ 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, _) => match other {
|
||||
TokenKind::DotDotEq | TokenKind::DotDotDot => true,
|
||||
_ => false,
|
||||
},
|
||||
(TokenKind::Interpolated(this), TokenKind::Interpolated(other)) => {
|
||||
match (this.as_ref(), other.as_ref()) {
|
||||
(Nonterminal::NtExpr(this), Nonterminal::NtExpr(other)) => {
|
||||
SpanlessEq::eq(this, other)
|
||||
let (this, this_span) = this.as_ref();
|
||||
let (other, other_span) = other.as_ref();
|
||||
SpanlessEq::eq(this_span, other_span)
|
||||
&& match (this, other) {
|
||||
(Nonterminal::NtExpr(this), Nonterminal::NtExpr(other)) => {
|
||||
SpanlessEq::eq(this, other)
|
||||
}
|
||||
_ => this == other,
|
||||
}
|
||||
_ => this == other,
|
||||
}
|
||||
}
|
||||
_ => self == other,
|
||||
}
|
||||
@ -666,7 +737,7 @@ fn doc_comment<'a>(
|
||||
}
|
||||
}
|
||||
let stream = match trees.next() {
|
||||
Some(TokenTree::Delimited(_span, Delimiter::Bracket, stream)) => stream,
|
||||
Some(TokenTree::Delimited(_span, _spacing, Delimiter::Bracket, stream)) => stream,
|
||||
_ => return false,
|
||||
};
|
||||
let mut trees = stream.trees();
|
||||
@ -710,7 +781,7 @@ fn is_escaped_literal_token(token: &Token, unescaped: Symbol) -> bool {
|
||||
Token {
|
||||
kind: TokenKind::Interpolated(nonterminal),
|
||||
span: _,
|
||||
} => match nonterminal.as_ref() {
|
||||
} => match &nonterminal.0 {
|
||||
Nonterminal::NtExpr(expr) => match &expr.kind {
|
||||
ExprKind::Lit(lit) => is_escaped_lit(lit, unescaped),
|
||||
_ => false,
|
||||
@ -734,12 +805,8 @@ fn is_escaped_literal_attr_args(value: &AttrArgsEq, unescaped: Symbol) -> bool {
|
||||
fn is_escaped_literal_meta_item_lit(lit: &MetaItemLit, unescaped: Symbol) -> bool {
|
||||
match lit {
|
||||
MetaItemLit {
|
||||
token_lit:
|
||||
Lit {
|
||||
kind: token::LitKind::Str,
|
||||
symbol: _,
|
||||
suffix: None,
|
||||
},
|
||||
symbol: _,
|
||||
suffix: None,
|
||||
kind,
|
||||
span: _,
|
||||
} => is_escaped_lit_kind(kind, unescaped),
|
||||
@ -804,3 +871,9 @@ impl SpanlessEq for AttrKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpanlessEq for FormatArguments {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
SpanlessEq::eq(self.all_args(), other.all_args())
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user