mirror of
https://github.com/openharmony/third_party_rust_syn.git
synced 2026-06-30 20:48:03 -04:00
+3
-3
@@ -1,3 +1,3 @@
|
||||
src/gen/** linguist-generated
|
||||
syn.json linguist-generated
|
||||
tests/debug/gen.rs linguist-generated
|
||||
/src/gen/** linguist-generated
|
||||
/syn.json linguist-generated
|
||||
/tests/debug/gen.rs linguist-generated
|
||||
|
||||
+27
-14
@@ -23,11 +23,17 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: llvm-tools, rustc-dev
|
||||
- run: cargo test --all-features --release --tests
|
||||
- uses: actions/upload-artifact@v6
|
||||
if: always()
|
||||
with:
|
||||
name: Cargo.lock
|
||||
path: Cargo.lock
|
||||
continue-on-error: true
|
||||
|
||||
build:
|
||||
name: ${{matrix.name || format('Rust {0}', matrix.rust)}}
|
||||
@@ -37,7 +43,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [stable, beta, 1.56.0]
|
||||
rust: [stable, beta, 1.82.0, 1.68.0]
|
||||
include:
|
||||
- rust: nightly
|
||||
components: rustc-dev
|
||||
@@ -45,8 +51,11 @@ jobs:
|
||||
name: WebAssembly
|
||||
target: wasm32-unknown-unknown
|
||||
- rust: nightly
|
||||
name: WASI
|
||||
target: wasm32-wasi
|
||||
name: WASI preview1
|
||||
target: wasm32-wasip1
|
||||
- rust: nightly
|
||||
name: WASI preview2
|
||||
target: wasm32-wasip2
|
||||
- rust: nightly
|
||||
name: Windows
|
||||
os: windows
|
||||
@@ -54,7 +63,7 @@ jobs:
|
||||
target: ${{matrix.target && format('--target={0}', matrix.target)}}
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
@@ -77,6 +86,8 @@ jobs:
|
||||
- run: cargo check ${{env.target}} --no-default-features --features 'full fold visit visit-mut parsing printing'
|
||||
- if: matrix.components == 'rustc-dev'
|
||||
run: cargo check --benches --all-features --release
|
||||
- if: matrix.rust != '1.68.0'
|
||||
run: cargo check ${{env.target}} --manifest-path json/Cargo.toml --no-default-features
|
||||
|
||||
examples:
|
||||
name: Examples
|
||||
@@ -85,7 +96,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- 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
|
||||
@@ -101,7 +112,7 @@ jobs:
|
||||
env:
|
||||
RUSTDOCFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-docs-rs
|
||||
- run: cargo docs-rs
|
||||
@@ -115,7 +126,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo run --manifest-path codegen/Cargo.toml
|
||||
- run: git diff --exit-code
|
||||
@@ -127,7 +138,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo generate-lockfile -Z minimal-versions
|
||||
- run: cargo check --all-features --locked
|
||||
@@ -139,7 +150,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-fuzz
|
||||
- run: cargo fuzz check
|
||||
@@ -151,10 +162,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@miri
|
||||
- run: cargo miri setup
|
||||
- run: cargo miri test --all-features
|
||||
- run: cargo miri test --all-features ${{github.event_name == 'pull_request' && '--tests' || ''}}
|
||||
env:
|
||||
MIRIFLAGS: -Zmiri-strict-provenance
|
||||
|
||||
@@ -164,7 +175,7 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: clippy,rustc-dev
|
||||
@@ -177,7 +188,9 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/install@cargo-outdated
|
||||
- run: cargo outdated --workspace --exit-code 1
|
||||
- run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1
|
||||
- run: cargo outdated --manifest-path codegen/Cargo.toml --exit-code 1
|
||||
|
||||
@@ -20,7 +20,7 @@ ohos_cargo_crate("lib") {
|
||||
|
||||
sources = [ "src/lib.rs" ]
|
||||
edition = "2021"
|
||||
cargo_pkg_version = "2.0.48"
|
||||
cargo_pkg_version = "2.0.114"
|
||||
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
|
||||
cargo_pkg_name = "syn"
|
||||
cargo_pkg_description = "Parser for Rust source code"
|
||||
|
||||
+20
-13
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "syn"
|
||||
version = "2.0.48" # don't forget to update html_root_url and syn.json
|
||||
version = "2.0.114"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
categories = ["development-tools::procedural-macro-helpers", "parser-implementations"]
|
||||
description = "Parser for Rust source code"
|
||||
@@ -18,43 +18,42 @@ include = [
|
||||
keywords = ["macros", "syn"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/syn"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.68"
|
||||
|
||||
[features]
|
||||
default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"]
|
||||
derive = []
|
||||
full = []
|
||||
parsing = []
|
||||
printing = ["quote"]
|
||||
printing = ["dep:quote"]
|
||||
visit = []
|
||||
visit-mut = []
|
||||
fold = []
|
||||
clone-impls = []
|
||||
extra-traits = []
|
||||
proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]
|
||||
proc-macro = ["proc-macro2/proc-macro", "quote?/proc-macro"]
|
||||
test = ["syn-test-suite/all-features"]
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "1.0.75", default-features = false }
|
||||
proc-macro2 = { version = "1.0.91", default-features = false }
|
||||
quote = { version = "1.0.35", optional = true, default-features = false }
|
||||
unicode-ident = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
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"
|
||||
walkdir = "2.3.2"
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
[target.'cfg(not(miri))'.dev-dependencies]
|
||||
flate2 = "1"
|
||||
rayon = "1"
|
||||
reqwest = { version = "0.13", features = ["blocking"] }
|
||||
tar = "0.4.16"
|
||||
walkdir = "2.3.2"
|
||||
|
||||
[[bench]]
|
||||
name = "rust"
|
||||
@@ -68,7 +67,15 @@ required-features = ["full", "parsing"]
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"]
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extend-css=src/gen/token.css",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["full", "visit", "visit-mut", "fold", "extra-traits"]
|
||||
|
||||
+7
-2
@@ -3,9 +3,14 @@
|
||||
"Name": "syn",
|
||||
"License": "Apache License V2.0, MIT",
|
||||
"License File": "LICENSE-APACHE, LICENSE-MIT",
|
||||
"Version Number": "2.0.48",
|
||||
"Version Number": "2.0.114",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/dtolnay/syn",
|
||||
"Description": "A Rust library that provides support for parsing Rust code."
|
||||
"Description": "A Rust library that provides support for parsing Rust code.",
|
||||
"Dependencies": [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -46,8 +46,6 @@ contains some APIs that may be useful more generally.
|
||||
[`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.56 and up.*
|
||||
|
||||
[*Release notes*](https://github.com/dtolnay/syn/releases)
|
||||
|
||||
<br>
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#![feature(rustc_private, test)]
|
||||
#![recursion_limit = "1024"]
|
||||
#![allow(
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::items_after_statements,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::must_use_candidate,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
|
||||
+41
-29
@@ -8,9 +8,11 @@
|
||||
#![allow(
|
||||
clippy::arc_with_non_send_sync,
|
||||
clippy::cast_lossless,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnecessary_wraps
|
||||
)]
|
||||
@@ -24,20 +26,24 @@ mod macros;
|
||||
mod repo;
|
||||
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(not(syn_only))]
|
||||
mod tokenstream_parse {
|
||||
use proc_macro2::TokenStream;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn bench(content: &str) -> Result<(), ()> {
|
||||
pub fn bench(_path: &Path, content: &str) -> Result<(), ()> {
|
||||
TokenStream::from_str(content).map(drop).map_err(drop)
|
||||
}
|
||||
}
|
||||
|
||||
mod syn_parse {
|
||||
pub fn bench(content: &str) -> Result<(), ()> {
|
||||
use std::path::Path;
|
||||
|
||||
pub fn bench(_path: &Path, content: &str) -> Result<(), ()> {
|
||||
syn::parse_file(content).map(drop).map_err(drop)
|
||||
}
|
||||
}
|
||||
@@ -52,45 +58,49 @@ mod librustc_parse {
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_messages::FluentBundle;
|
||||
use rustc_errors::{emitter::Emitter, translation::Translate, DiagCtxt, Diagnostic};
|
||||
use crate::repo;
|
||||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::registry::Registry;
|
||||
use rustc_errors::translation::Translator;
|
||||
use rustc_errors::{DiagCtxt, DiagInner};
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use rustc_span::{edition::Edition, FileName};
|
||||
use rustc_span::FileName;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn bench(content: &str) -> Result<(), ()> {
|
||||
pub fn bench(path: &Path, content: &str) -> Result<(), ()> {
|
||||
struct SilentEmitter;
|
||||
|
||||
impl Emitter for SilentEmitter {
|
||||
fn emit_diagnostic(&mut self, _diag: &Diagnostic) {}
|
||||
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
|
||||
fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) {}
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Translate for SilentEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
|
||||
None
|
||||
}
|
||||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||
fn translator(&self) -> &Translator {
|
||||
panic!("silent emitter attempted to translate a diagnostic");
|
||||
}
|
||||
}
|
||||
|
||||
rustc_span::create_session_if_not_set_then(Edition::Edition2018, |_| {
|
||||
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let edition = repo::edition(path).parse().unwrap();
|
||||
rustc_span::create_session_if_not_set_then(edition, |_| {
|
||||
let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let emitter = Box::new(SilentEmitter);
|
||||
let handler = DiagCtxt::with_emitter(emitter);
|
||||
let handler = DiagCtxt::new(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(),
|
||||
let name = FileName::Custom("bench".to_owned());
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(
|
||||
&sess,
|
||||
) {
|
||||
name,
|
||||
content.to_owned(),
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(diagnostic) = parser.parse_crate_mod() {
|
||||
diagnostic.cancel();
|
||||
return Err(());
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -98,13 +108,15 @@ mod librustc_parse {
|
||||
|
||||
#[cfg(not(syn_only))]
|
||||
mod read_from_disk {
|
||||
pub fn bench(content: &str) -> Result<(), ()> {
|
||||
use std::path::Path;
|
||||
|
||||
pub fn bench(_path: &Path, content: &str) -> Result<(), ()> {
|
||||
let _ = content;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
|
||||
fn exec(mut codepath: impl FnMut(&Path, &str) -> Result<(), ()>) -> Duration {
|
||||
let begin = Instant::now();
|
||||
let mut success = 0;
|
||||
let mut total = 0;
|
||||
@@ -123,7 +135,7 @@ fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration {
|
||||
return;
|
||||
}
|
||||
let content = fs::read_to_string(path).unwrap();
|
||||
let ok = codepath(&content).is_ok();
|
||||
let ok = codepath(path, &content).is_ok();
|
||||
success += ok as usize;
|
||||
total += 1;
|
||||
if !ok {
|
||||
@@ -143,7 +155,7 @@ fn main() {
|
||||
[
|
||||
$(
|
||||
$(#[$cfg])*
|
||||
(stringify!($name), $name::bench as fn(&str) -> Result<(), ()>),
|
||||
(stringify!($name), $name::bench as fn(&Path, &str) -> Result<(), ()>),
|
||||
)*
|
||||
]
|
||||
};
|
||||
@@ -153,7 +165,7 @@ fn main() {
|
||||
{
|
||||
let mut lines = 0;
|
||||
let mut files = 0;
|
||||
exec(|content| {
|
||||
exec(|_path, content| {
|
||||
lines += content.lines().count();
|
||||
files += 1;
|
||||
Ok(())
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::iter;
|
||||
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() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
// Note: add "/build.rs" to package.include in Cargo.toml if adding any
|
||||
// conditional compilation within the library.
|
||||
|
||||
println!("cargo:rustc-cfg=check_cfg");
|
||||
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
|
||||
println!("cargo:rustc-check-cfg=cfg(fuzzing)");
|
||||
println!("cargo:rustc-check-cfg=cfg(syn_disable_nightly_tests)");
|
||||
println!("cargo:rustc-check-cfg=cfg(syn_only)");
|
||||
|
||||
if !unstable() {
|
||||
println!("cargo:rustc-cfg=syn_disable_nightly_tests");
|
||||
}
|
||||
@@ -18,16 +24,15 @@ fn main() {
|
||||
|
||||
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)
|
||||
};
|
||||
let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty());
|
||||
let rustc_workspace_wrapper =
|
||||
env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty());
|
||||
let mut rustc = rustc_wrapper
|
||||
.into_iter()
|
||||
.chain(rustc_workspace_wrapper)
|
||||
.chain(iter::once(rustc));
|
||||
let mut cmd = Command::new(rustc.next().unwrap());
|
||||
cmd.args(rustc);
|
||||
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stdout(Stdio::null());
|
||||
|
||||
+8
-7
@@ -6,23 +6,24 @@ edition = "2021"
|
||||
|
||||
publish = false # this is an internal crate which should never be published
|
||||
|
||||
[features]
|
||||
default = ["json"]
|
||||
json = ["syn-codegen/serde"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
color-backtrace = "0.4"
|
||||
color-backtrace = "0.7"
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
indoc = "2"
|
||||
inflections = "1.1"
|
||||
prettyplease = "0.2.3"
|
||||
proc-macro2 = { version = "1.0.20", features = ["span-locations"] }
|
||||
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" }
|
||||
thiserror = "1"
|
||||
toml = "0.5"
|
||||
syn-codegen = { path = "../json", default-features = false }
|
||||
toml = { version = "0.9", default-features = false, features = ["parse", "serde"] }
|
||||
|
||||
[workspace]
|
||||
[patch.crates-io]
|
||||
syn = { path = ".." }
|
||||
|
||||
+24
-12
@@ -2,28 +2,40 @@ use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn_codegen::Features;
|
||||
|
||||
pub fn features<'a>(
|
||||
features: &Features,
|
||||
overriding_cfg: impl Into<Option<&'a str>>,
|
||||
) -> TokenStream {
|
||||
pub enum DocCfg {
|
||||
Ordinary,
|
||||
Override(&'static str),
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<&'static str> for DocCfg {
|
||||
fn from(overriding_cfg: &'static str) -> Self {
|
||||
DocCfg::Override(overriding_cfg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn features(features: &Features, doc_cfg: impl Into<DocCfg>) -> TokenStream {
|
||||
let features = &features.any;
|
||||
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! {
|
||||
match (cfg, doc_cfg.into()) {
|
||||
(Some(cfg), DocCfg::Ordinary) => quote! {
|
||||
#[#cfg]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = #overriding_cfg)))]
|
||||
#[cfg_attr(docsrs, doc(#cfg))]
|
||||
},
|
||||
(Some(cfg), None) => quote! {
|
||||
(Some(cfg), DocCfg::Override(overriding_cfg)) => quote! {
|
||||
#[#cfg]
|
||||
#[cfg_attr(doc_cfg, doc(#cfg))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = #overriding_cfg)))]
|
||||
},
|
||||
(None, Some(overriding_cfg)) => quote! {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = #overriding_cfg)))]
|
||||
(Some(cfg), DocCfg::None) => quote! {
|
||||
#[#cfg]
|
||||
},
|
||||
(None, None) => TokenStream::new(),
|
||||
(None, DocCfg::Override(overriding_cfg)) => quote! {
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = #overriding_cfg)))]
|
||||
},
|
||||
(None, DocCfg::Ordinary | DocCfg::None) => TokenStream::new(),
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
use crate::{cfg, file, lookup};
|
||||
use crate::{cfg, file, full, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@@ -13,11 +13,12 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let mixed_derive_full = full::is_mixed_derive_full_enum(defs, node);
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
#ident::#variant => #ident::#variant,
|
||||
crate::#ident::#variant => crate::#ident::#variant,
|
||||
}
|
||||
} else {
|
||||
let mut pats = Vec::new();
|
||||
@@ -28,20 +29,21 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
pats.push(pat);
|
||||
}
|
||||
let mut cfg = None;
|
||||
if node.ident == "Expr" {
|
||||
if mixed_derive_full {
|
||||
if let Type::Syn(ty) = &fields[0] {
|
||||
if !lookup::node(defs, ty).features.any.contains("derive") {
|
||||
let features = &lookup::node(defs, ty).features;
|
||||
if features.any.contains("full") && !features.any.contains("derive") {
|
||||
cfg = Some(quote!(#[cfg(feature = "full")]));
|
||||
}
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(#(#pats),*) => #ident::#variant(#(#clones),*),
|
||||
crate::#ident::#variant(#(#pats),*) => crate::#ident::#variant(#(#clones),*),
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
let nonexhaustive = if mixed_derive_full {
|
||||
Some(quote! {
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
@@ -63,7 +65,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
#ident: self.#ident.clone(),
|
||||
}
|
||||
});
|
||||
quote!(#ident { #(#fields)* })
|
||||
quote!(crate::#ident { #(#fields)* })
|
||||
}
|
||||
Data::Private => unreachable!(),
|
||||
}
|
||||
@@ -86,9 +88,9 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
if copy {
|
||||
return quote! {
|
||||
#cfg_features
|
||||
impl Copy for #ident {}
|
||||
impl Copy for crate::#ident {}
|
||||
#cfg_features
|
||||
impl Clone for #ident {
|
||||
impl Clone for crate::#ident {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
@@ -100,7 +102,7 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
impl Clone for #ident {
|
||||
impl Clone for crate::#ident {
|
||||
fn clone(&self) -> Self {
|
||||
#body
|
||||
}
|
||||
@@ -119,8 +121,6 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
quote! {
|
||||
#![allow(clippy::clone_on_copy, clippy::expl_impl_clone_on_copy)]
|
||||
|
||||
use crate::*;
|
||||
|
||||
#impls
|
||||
},
|
||||
)?;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
use crate::workspace_path;
|
||||
use anyhow::Result;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
use syn_codegen::Definitions;
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
let mut styles = String::new();
|
||||
for ty in defs.tokens.keys() {
|
||||
styles += &format!("a.struct[title=\"struct syn::token::{ty}\"],\n");
|
||||
}
|
||||
styles.truncate(styles.len() - 2);
|
||||
styles += indoc! {"
|
||||
{
|
||||
\tdisplay: inline-block;
|
||||
\tcolor: transparent;
|
||||
\twhite-space: nowrap;
|
||||
}
|
||||
"};
|
||||
styles.push('\n');
|
||||
for ty in defs.tokens.keys() {
|
||||
styles += &format!("a.struct[title=\"struct syn::token::{ty}\"]::before,\n");
|
||||
}
|
||||
styles.truncate(styles.len() - 2);
|
||||
styles += indoc! {"
|
||||
{
|
||||
\tdisplay: inline-block;
|
||||
\tcolor: var(--type-link-color);
|
||||
\twidth: 0;
|
||||
}
|
||||
"};
|
||||
let mut shrink = BTreeMap::new();
|
||||
let mut grow = BTreeMap::new();
|
||||
for (ty, repr) in &defs.tokens {
|
||||
let macro_len = "Token![]".len() + repr.len();
|
||||
let ty_len = ty.len();
|
||||
styles.push('\n');
|
||||
styles += &match Ord::cmp(¯o_len, &ty_len) {
|
||||
Ordering::Less => {
|
||||
shrink
|
||||
.entry((macro_len, ty_len))
|
||||
.or_insert_with(Vec::new)
|
||||
.push(ty);
|
||||
formatdoc! {"
|
||||
a.struct[title=\"struct syn::token::{ty}\"]::before {{
|
||||
\tcontent: \"Token![{repr}]\";
|
||||
\tfont-size: calc(100% * {ty_len} / {macro_len});
|
||||
}}
|
||||
"}
|
||||
}
|
||||
Ordering::Equal => unreachable!(),
|
||||
Ordering::Greater => {
|
||||
let padding = macro_len.saturating_sub(ty.len());
|
||||
grow.entry(padding).or_insert_with(Vec::new).push(ty);
|
||||
formatdoc! {"
|
||||
a.struct[title=\"struct syn::token::{ty}\"]::before {{
|
||||
\tcontent: \"Token![{repr}]\";
|
||||
}}
|
||||
"}
|
||||
}
|
||||
};
|
||||
}
|
||||
for ((macro_len, ty_len), types) in shrink {
|
||||
for ty in types {
|
||||
styles += &format!("\na.struct[title=\"struct syn::token::{ty}\"],");
|
||||
}
|
||||
styles.truncate(styles.len() - 1);
|
||||
styles += &formatdoc! {"
|
||||
{{
|
||||
\tfont-size: calc(100% * {macro_len} / {ty_len});
|
||||
}}
|
||||
"};
|
||||
}
|
||||
for (padding, types) in grow {
|
||||
for ty in types {
|
||||
styles += &format!("\na.struct[title=\"struct syn::token::{ty}\"]::after,");
|
||||
}
|
||||
styles.truncate(styles.len() - 1);
|
||||
let padding = ".".repeat(padding);
|
||||
styles += &formatdoc! {"
|
||||
{{
|
||||
\tcontent: \"{padding}\";
|
||||
}}
|
||||
"};
|
||||
}
|
||||
|
||||
let css_path = workspace_path::get("src/gen/token.css");
|
||||
fs::write(css_path, styles)?;
|
||||
Ok(())
|
||||
}
|
||||
+41
-29
@@ -1,4 +1,5 @@
|
||||
use crate::{cfg, file, lookup};
|
||||
use crate::cfg::{self, DocCfg};
|
||||
use crate::{file, full, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@@ -49,21 +50,23 @@ fn expand_impl_body(
|
||||
let ident = Ident::new(type_name, Span::call_site());
|
||||
let is_syntax_tree_variant = syntax_tree_variants.contains(type_name.as_str());
|
||||
|
||||
let body = match &node.data {
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
assert!(!is_syntax_tree_variant);
|
||||
let mixed_derive_full = full::is_mixed_derive_full_enum(defs, node);
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
#ident::#variant => formatter.write_str(#variant_name),
|
||||
crate::#ident::#variant => formatter.write_str(#variant_name),
|
||||
}
|
||||
} else {
|
||||
let mut cfg = None;
|
||||
if node.ident == "Expr" {
|
||||
if mixed_derive_full {
|
||||
if let Type::Syn(ty) = &fields[0] {
|
||||
if !lookup::node(defs, ty).features.any.contains("derive") {
|
||||
let features = &lookup::node(defs, ty).features;
|
||||
if features.any.contains("full") && !features.any.contains("derive") {
|
||||
cfg = Some(quote!(#[cfg(feature = "full")]));
|
||||
}
|
||||
}
|
||||
@@ -71,7 +74,7 @@ fn expand_impl_body(
|
||||
if syntax_tree_enum(type_name, variant_name, fields).is_some() {
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(v0) => v0.debug(formatter, #variant_name),
|
||||
crate::#ident::#variant(v0) => v0.debug(formatter, #variant_name),
|
||||
}
|
||||
} else {
|
||||
let pats = (0..fields.len())
|
||||
@@ -79,7 +82,7 @@ fn expand_impl_body(
|
||||
.collect::<Vec<_>>();
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(#(#pats),*) => {
|
||||
crate::#ident::#variant(#(#pats),*) => {
|
||||
let mut formatter = formatter.debug_tuple(#variant_name);
|
||||
#(formatter.field(#pats);)*
|
||||
formatter.finish()
|
||||
@@ -88,7 +91,7 @@ fn expand_impl_body(
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
let nonexhaustive = if mixed_derive_full {
|
||||
Some(quote! {
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
@@ -124,19 +127,6 @@ fn expand_impl_body(
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +136,10 @@ fn expand_impl(defs: &Definitions, node: &Node, syntax_tree_variants: &Set<&str>
|
||||
return TokenStream::new();
|
||||
}
|
||||
|
||||
let ident = Ident::new(&node.ident, Span::call_site());
|
||||
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());
|
||||
|
||||
let cfg_features = cfg::features(&node.features, "extra-traits");
|
||||
let body = expand_impl_body(defs, node, syntax_tree_variants);
|
||||
let formatter = match &node.data {
|
||||
@@ -154,11 +147,29 @@ fn expand_impl(defs: &Definitions, node: &Node, syntax_tree_variants: &Set<&str>
|
||||
_ => quote!(formatter),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
impl Debug for #ident {
|
||||
fn fmt(&self, #formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
#body
|
||||
if is_syntax_tree_variant {
|
||||
let inherent_cfg_features = cfg::features(&node.features, DocCfg::None);
|
||||
quote! {
|
||||
#cfg_features
|
||||
impl Debug for crate::#ident {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.debug(formatter, #type_name)
|
||||
}
|
||||
}
|
||||
#inherent_cfg_features
|
||||
impl crate::#ident {
|
||||
fn debug(&self, #formatter: &mut fmt::Formatter, name: &str) -> fmt::Result {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#cfg_features
|
||||
impl Debug for crate::#ident {
|
||||
fn fmt(&self, #formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,8 +196,9 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
file::write(
|
||||
DEBUG_SRC,
|
||||
quote! {
|
||||
use crate::*;
|
||||
use std::fmt::{self, Debug};
|
||||
#![allow(unknown_lints, non_local_definitions)]
|
||||
|
||||
use core::fmt::{self, Debug};
|
||||
|
||||
#impls
|
||||
},
|
||||
|
||||
+11
-8
@@ -1,4 +1,4 @@
|
||||
use crate::{cfg, file, lookup};
|
||||
use crate::{cfg, file, full, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@@ -23,11 +23,12 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let mixed_derive_full = full::is_mixed_derive_full_enum(defs, node);
|
||||
let arms = variants.iter().map(|(variant_name, fields)| {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
(#ident::#variant, #ident::#variant) => true,
|
||||
(crate::#ident::#variant, crate::#ident::#variant) => true,
|
||||
}
|
||||
} else {
|
||||
let mut this_pats = Vec::new();
|
||||
@@ -57,16 +58,17 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
comparisons.push(quote!(true));
|
||||
}
|
||||
let mut cfg = None;
|
||||
if node.ident == "Expr" {
|
||||
if mixed_derive_full {
|
||||
if let Type::Syn(ty) = &fields[0] {
|
||||
if !lookup::node(defs, ty).features.any.contains("derive") {
|
||||
let features = &lookup::node(defs, ty).features;
|
||||
if features.any.contains("full") && !features.any.contains("derive") {
|
||||
cfg = Some(quote!(#[cfg(feature = "full")]));
|
||||
}
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
#cfg
|
||||
(#ident::#variant(#(#this_pats),*), #ident::#variant(#(#other_pats),*)) => {
|
||||
(crate::#ident::#variant(#(#this_pats),*), crate::#ident::#variant(#(#other_pats),*)) => {
|
||||
#(#comparisons)&&*
|
||||
}
|
||||
}
|
||||
@@ -118,7 +120,7 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
|
||||
let eq = quote! {
|
||||
#cfg_features
|
||||
impl Eq for #ident {}
|
||||
impl Eq for crate::#ident {}
|
||||
};
|
||||
|
||||
let manual_partial_eq = node.data == Data::Private;
|
||||
@@ -137,7 +139,7 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
#eq
|
||||
|
||||
#cfg_features
|
||||
impl PartialEq for #ident {
|
||||
impl PartialEq for crate::#ident {
|
||||
fn eq(&self, #other: &Self) -> bool {
|
||||
#body
|
||||
}
|
||||
@@ -156,7 +158,8 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
quote! {
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use crate::tt::TokenStreamHelper;
|
||||
use crate::*;
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use alloc::string::ToString;
|
||||
|
||||
#impls
|
||||
},
|
||||
|
||||
+73
-31
@@ -1,3 +1,4 @@
|
||||
use crate::cfg::{self, DocCfg};
|
||||
use crate::{file, full, gen};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
@@ -7,12 +8,14 @@ use syn_codegen::{Data, Definitions, Features, Node, Type};
|
||||
|
||||
const FOLD_SRC: &str = "src/gen/fold.rs";
|
||||
|
||||
fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
|
||||
fn method_name(item: &str) -> Ident {
|
||||
let ident = gen::under_name(item);
|
||||
let method = format_ident!("fold_{}", ident);
|
||||
quote! {
|
||||
f.#method(#name)
|
||||
}
|
||||
format_ident!("fold_{}", ident)
|
||||
}
|
||||
|
||||
fn simple_fold(item: &str, name: &TokenStream) -> TokenStream {
|
||||
let method = method_name(item);
|
||||
quote! { f.#method(#name) }
|
||||
}
|
||||
|
||||
fn visit(
|
||||
@@ -29,17 +32,24 @@ fn visit(
|
||||
})
|
||||
}
|
||||
Type::Vec(t) => {
|
||||
let operand = quote!(it);
|
||||
let val = visit(t, features, defs, &operand)?;
|
||||
Some(quote! {
|
||||
FoldHelper::lift(#name, |it| #val)
|
||||
})
|
||||
let Type::Syn(t) = &**t else { unimplemented!() };
|
||||
if t == "Attribute" {
|
||||
Some(quote! {
|
||||
f.fold_attributes(#name)
|
||||
})
|
||||
} else {
|
||||
let method = method_name(t);
|
||||
Some(quote! {
|
||||
fold_vec(#name, f, F::#method)
|
||||
})
|
||||
}
|
||||
}
|
||||
Type::Punctuated(p) => {
|
||||
let operand = quote!(it);
|
||||
let val = visit(&p.element, features, defs, &operand)?;
|
||||
let t = &*p.element;
|
||||
let Type::Syn(t) = t else { unimplemented!() };
|
||||
let method = method_name(t);
|
||||
Some(quote! {
|
||||
FoldHelper::lift(#name, |it| #val)
|
||||
crate::punctuated::fold(#name, f, F::#method)
|
||||
})
|
||||
}
|
||||
Type::Option(t) => {
|
||||
@@ -66,21 +76,26 @@ fn visit(
|
||||
fn requires_full(features: &Features) -> bool {
|
||||
features.any.contains("full") && features.any.len() == 1
|
||||
}
|
||||
let mut res = simple_visit(t, name);
|
||||
let mut res = simple_fold(t, name);
|
||||
let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
|
||||
if requires_full(&target.features) && !requires_full(features) {
|
||||
res = quote!(full!(#res));
|
||||
}
|
||||
Some(res)
|
||||
}
|
||||
Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
|
||||
Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_fold(t, name)),
|
||||
Type::Ext(_) | Type::Std(_) | Type::Token(_) | Type::Group(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
|
||||
let under_name = gen::under_name(&s.ident);
|
||||
let ty = Ident::new(&s.ident, Span::call_site());
|
||||
let ident = Ident::new(&s.ident, Span::call_site());
|
||||
let ty = if gen::TERMINAL_TYPES.contains(&s.ident.as_str()) {
|
||||
quote!(proc_macro2::#ident)
|
||||
} else {
|
||||
quote!(crate::#ident)
|
||||
};
|
||||
let fold_fn = format_ident!("fold_{}", under_name);
|
||||
|
||||
let mut fold_impl = TokenStream::new();
|
||||
@@ -149,7 +164,7 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
|
||||
if fields.is_empty() {
|
||||
if ty == "Ident" {
|
||||
if s.ident == "Ident" {
|
||||
fold_impl.extend(quote! {
|
||||
let mut node = node;
|
||||
let span = f.fold_span(node.span());
|
||||
@@ -168,7 +183,7 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
Data::Private => {
|
||||
if ty == "Ident" {
|
||||
if s.ident == "Ident" {
|
||||
fold_impl.extend(quote! {
|
||||
let mut node = node;
|
||||
let span = f.fold_span(node.span());
|
||||
@@ -192,20 +207,38 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
};
|
||||
}
|
||||
|
||||
let traits_body = if s.ident == "Span" || s.ident == "TokenStream" {
|
||||
quote!(i)
|
||||
} else {
|
||||
quote!(#fold_fn(self, i))
|
||||
};
|
||||
|
||||
traits.extend(quote! {
|
||||
fn #fold_fn(&mut self, i: #ty) -> #ty {
|
||||
#fold_fn(self, i)
|
||||
#traits_body
|
||||
}
|
||||
});
|
||||
|
||||
impls.extend(quote! {
|
||||
pub fn #fold_fn<F>(f: &mut F, node: #ty) -> #ty
|
||||
where
|
||||
F: Fold + ?Sized,
|
||||
{
|
||||
#fold_impl
|
||||
}
|
||||
});
|
||||
if s.ident != "TokenStream" {
|
||||
impls.extend(quote! {
|
||||
pub fn #fold_fn<F>(f: &mut F, node: #ty) -> #ty
|
||||
where
|
||||
F: Fold + ?Sized,
|
||||
{
|
||||
#fold_impl
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if s.ident == "Attribute" {
|
||||
let features = cfg::features(&s.features, DocCfg::Ordinary);
|
||||
traits.extend(quote! {
|
||||
#features
|
||||
fn fold_attributes(&mut self, i: Vec<crate::Attribute>) -> Vec<crate::Attribute> {
|
||||
fold_vec(i, self, Self::fold_attribute)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
@@ -222,10 +255,10 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
clippy::needless_pass_by_ref_mut,
|
||||
)]
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::gen::helper::fold::*;
|
||||
use crate::*;
|
||||
use proc_macro2::Span;
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#full_macro
|
||||
|
||||
@@ -239,6 +272,15 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
}
|
||||
|
||||
#impls
|
||||
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
fn fold_vec<T, V, F>(vec: Vec<T>, fold: &mut V, mut f: F) -> Vec<T>
|
||||
where
|
||||
V: ?Sized,
|
||||
F: FnMut(&mut V, T) -> T,
|
||||
{
|
||||
vec.into_iter().map(|it| f(fold, it)).collect()
|
||||
}
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::lookup;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn_codegen::{Data, Definitions, Node, Type};
|
||||
|
||||
pub fn get_macro() -> TokenStream {
|
||||
quote! {
|
||||
@@ -18,3 +20,71 @@ pub fn get_macro() -> TokenStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Syntax tree enum that has some variants enabled in "derive" mode and the
|
||||
/// rest enabled in "full" mode.
|
||||
pub fn is_mixed_derive_full_enum(defs: &Definitions, node: &Node) -> bool {
|
||||
if !(node.features.any.contains("derive") && node.features.any.contains("full")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let variants = match &node.data {
|
||||
Data::Enum(variants) => variants,
|
||||
Data::Private | Data::Struct(_) => return false,
|
||||
};
|
||||
|
||||
let mut has_derive = false;
|
||||
let mut has_full = false;
|
||||
for fields in variants.values() {
|
||||
match classify_variant(defs, fields) {
|
||||
VariantAvailability::Derive => has_derive = true,
|
||||
VariantAvailability::Full => has_full = true,
|
||||
VariantAvailability::Other => {}
|
||||
}
|
||||
}
|
||||
has_derive && has_full
|
||||
}
|
||||
|
||||
enum VariantAvailability {
|
||||
Derive,
|
||||
Full,
|
||||
Other,
|
||||
}
|
||||
|
||||
fn classify_variant(defs: &Definitions, fields: &[Type]) -> VariantAvailability {
|
||||
let mut has_derive = false;
|
||||
let mut has_full = false;
|
||||
for field in fields {
|
||||
for_each_syn_type(field, &mut |ty| {
|
||||
let node = lookup::node(defs, ty);
|
||||
let derive = node.features.any.contains("derive");
|
||||
let full = node.features.any.contains("full");
|
||||
match (derive, full) {
|
||||
(false, false) => {}
|
||||
(false, true) => has_full = true,
|
||||
(true, false | true) => has_derive = true,
|
||||
}
|
||||
});
|
||||
}
|
||||
if has_full {
|
||||
VariantAvailability::Full
|
||||
} else if has_derive {
|
||||
VariantAvailability::Derive
|
||||
} else {
|
||||
VariantAvailability::Other
|
||||
}
|
||||
}
|
||||
|
||||
fn for_each_syn_type(ty: &Type, f: &mut dyn FnMut(&str)) {
|
||||
match ty {
|
||||
Type::Syn(ty) => f(ty),
|
||||
Type::Std(_) | Type::Ext(_) | Type::Token(_) | Type::Group(_) => {}
|
||||
Type::Punctuated(punctuated) => for_each_syn_type(&punctuated.element, f),
|
||||
Type::Option(ty) | Type::Box(ty) | Type::Vec(ty) => for_each_syn_type(ty, f),
|
||||
Type::Tuple(elements) => {
|
||||
for ty in elements {
|
||||
for_each_syn_type(ty, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
use crate::cfg;
|
||||
use crate::cfg::{self, DocCfg};
|
||||
use inflections::Inflect;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use syn_codegen::{Data, Definitions, Features, Node};
|
||||
|
||||
pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
|
||||
pub const TERMINAL_TYPES: [&str; 3] = ["Ident", "Span", "TokenStream"];
|
||||
|
||||
pub fn under_name(name: &str) -> Ident {
|
||||
Ident::new(&name.to_snake_case(), Span::call_site())
|
||||
@@ -14,7 +14,7 @@ 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_owned(),
|
||||
features: Features::default(),
|
||||
@@ -27,7 +27,7 @@ pub fn traverse(
|
||||
let mut traits = TokenStream::new();
|
||||
let mut impls = TokenStream::new();
|
||||
for s in types {
|
||||
let features = cfg::features(&s.features, None);
|
||||
let features = cfg::features(&s.features, DocCfg::Ordinary);
|
||||
traits.extend(features.clone());
|
||||
impls.extend(features);
|
||||
node(&mut traits, &mut impls, &s, defs);
|
||||
|
||||
+13
-9
@@ -1,4 +1,4 @@
|
||||
use crate::{cfg, file, lookup};
|
||||
use crate::{cfg, file, full, lookup};
|
||||
use anyhow::Result;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
@@ -23,6 +23,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
match &node.data {
|
||||
Data::Enum(variants) if variants.is_empty() => quote!(match *self {}),
|
||||
Data::Enum(variants) => {
|
||||
let mixed_derive_full = full::is_mixed_derive_full_enum(defs, node);
|
||||
let arms = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
@@ -31,7 +32,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
let variant = Ident::new(variant_name, Span::call_site());
|
||||
if fields.is_empty() {
|
||||
quote! {
|
||||
#ident::#variant => {
|
||||
crate::#ident::#variant => {
|
||||
state.write_u8(#i);
|
||||
}
|
||||
}
|
||||
@@ -60,23 +61,25 @@ fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
pats.push(var);
|
||||
}
|
||||
let mut cfg = None;
|
||||
if node.ident == "Expr" {
|
||||
if mixed_derive_full {
|
||||
if let Type::Syn(ty) = &fields[0] {
|
||||
if !lookup::node(defs, ty).features.any.contains("derive") {
|
||||
let features = &lookup::node(defs, ty).features;
|
||||
if features.any.contains("full") && !features.any.contains("derive")
|
||||
{
|
||||
cfg = Some(quote!(#[cfg(feature = "full")]));
|
||||
}
|
||||
}
|
||||
}
|
||||
quote! {
|
||||
#cfg
|
||||
#ident::#variant(#(#pats),*) => {
|
||||
crate::#ident::#variant(#(#pats),*) => {
|
||||
state.write_u8(#i);
|
||||
#(#hashes)*
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let nonexhaustive = if node.ident == "Expr" {
|
||||
let nonexhaustive = if mixed_derive_full {
|
||||
Some(quote! {
|
||||
#[cfg(not(feature = "full"))]
|
||||
_ => unreachable!(),
|
||||
@@ -135,7 +138,7 @@ fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
|
||||
|
||||
quote! {
|
||||
#cfg_features
|
||||
impl Hash for #ident {
|
||||
impl Hash for crate::#ident {
|
||||
fn hash<H>(&self, #hasher: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
@@ -157,8 +160,9 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
quote! {
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use crate::tt::TokenStreamHelper;
|
||||
use crate::*;
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use alloc::string::ToString;
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
#impls
|
||||
},
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
// programmatically from the syntax tree description.
|
||||
|
||||
#![allow(
|
||||
clippy::format_push_string,
|
||||
clippy::items_after_statements,
|
||||
clippy::manual_let_else,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines,
|
||||
clippy::uninlined_format_args
|
||||
@@ -20,6 +22,7 @@
|
||||
|
||||
mod cfg;
|
||||
mod clone;
|
||||
mod css;
|
||||
mod debug;
|
||||
mod eq;
|
||||
mod file;
|
||||
@@ -27,6 +30,7 @@ mod fold;
|
||||
mod full;
|
||||
mod gen;
|
||||
mod hash;
|
||||
#[cfg(feature = "json")]
|
||||
mod json;
|
||||
mod lookup;
|
||||
mod operand;
|
||||
@@ -44,10 +48,12 @@ fn main() -> anyhow::Result<()> {
|
||||
debug::generate(&defs)?;
|
||||
eq::generate(&defs)?;
|
||||
hash::generate(&defs)?;
|
||||
#[cfg(feature = "json")]
|
||||
json::generate(&defs)?;
|
||||
fold::generate(&defs)?;
|
||||
visit::generate(&defs)?;
|
||||
visit_mut::generate(&defs)?;
|
||||
snapshot::generate(&defs)?;
|
||||
css::generate(&defs)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ pub enum Operand {
|
||||
Owned(TokenStream),
|
||||
}
|
||||
|
||||
pub use self::Operand::*;
|
||||
pub use self::Operand::{Borrowed, Owned};
|
||||
|
||||
impl Operand {
|
||||
pub fn tokens(&self) -> &TokenStream {
|
||||
|
||||
+40
-31
@@ -3,6 +3,7 @@ use anyhow::{bail, Result};
|
||||
use indexmap::IndexMap;
|
||||
use quote::quote;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{self, Display};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use syn::parse::{Error, Parser};
|
||||
@@ -11,7 +12,6 @@ use syn::{
|
||||
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";
|
||||
@@ -86,9 +86,9 @@ fn introspect_item(item: &AstItem, lookup: &Lookup) -> types::Node {
|
||||
types::Data::Private
|
||||
}
|
||||
},
|
||||
exhaustive: true,
|
||||
exhaustive: !is_non_exhaustive(&item.ast.attrs),
|
||||
},
|
||||
Data::Union(..) => panic!("Union not supported"),
|
||||
Data::Union(..) => panic!("union not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ fn introspect_enum(item: &DataEnum, lookup: &Lookup) -> types::Variants {
|
||||
.map(|field| introspect_type(&field.ty, lookup))
|
||||
.collect(),
|
||||
Fields::Unit => vec![],
|
||||
Fields::Named(_) => panic!("Enum representation not supported"),
|
||||
Fields::Named(_) => panic!("enum representation not supported"),
|
||||
};
|
||||
Some((variant.ident.to_string(), fields))
|
||||
})
|
||||
@@ -126,7 +126,7 @@ fn introspect_struct(item: &DataStruct, lookup: &Lookup) -> types::Fields {
|
||||
})
|
||||
.collect(),
|
||||
Fields::Unit => IndexMap::new(),
|
||||
Fields::Unnamed(_) => panic!("Struct representation not supported"),
|
||||
Fields::Unnamed(_) => panic!("struct representation not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ fn introspect_type(item: &syn::Type, lookup: &Lookup) -> types::Type {
|
||||
while let Some(alias) = lookup.aliases.get(resolved) {
|
||||
resolved = alias;
|
||||
}
|
||||
if lookup.items.get(resolved).is_some() {
|
||||
if lookup.items.contains_key(resolved) {
|
||||
types::Type::Syn(resolved.to_string())
|
||||
} else {
|
||||
unimplemented!("{}", resolved);
|
||||
@@ -185,7 +185,7 @@ fn introspect_type(item: &syn::Type, lookup: &Lookup) -> types::Type {
|
||||
if mac.path.segments.last().unwrap().ident == "Token" =>
|
||||
{
|
||||
let content = mac.tokens.to_string();
|
||||
let ty = lookup.tokens.get(&content).unwrap().to_string();
|
||||
let ty = lookup.tokens.get(&content).unwrap().clone();
|
||||
|
||||
types::Type::Token(ty)
|
||||
}
|
||||
@@ -244,32 +244,32 @@ fn is_doc_hidden(attrs: &[Attribute]) -> bool {
|
||||
fn first_arg(params: &PathArguments) -> &syn::Type {
|
||||
let data = match params {
|
||||
PathArguments::AngleBracketed(data) => data,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
_ => panic!("expected at least 1 type argument here"),
|
||||
};
|
||||
|
||||
match data
|
||||
.args
|
||||
.first()
|
||||
.expect("Expected at least 1 type argument here")
|
||||
.expect("expected at least 1 type argument here")
|
||||
{
|
||||
GenericArgument::Type(ty) => ty,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
_ => panic!("expected at least 1 type argument here"),
|
||||
}
|
||||
}
|
||||
|
||||
fn last_arg(params: &PathArguments) -> &syn::Type {
|
||||
let data = match params {
|
||||
PathArguments::AngleBracketed(data) => data,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
_ => panic!("expected at least 1 type argument here"),
|
||||
};
|
||||
|
||||
match data
|
||||
.args
|
||||
.last()
|
||||
.expect("Expected at least 1 type argument here")
|
||||
.expect("expected at least 1 type argument here")
|
||||
{
|
||||
GenericArgument::Type(ty) => ty,
|
||||
_ => panic!("Expected at least 1 type argument here"),
|
||||
_ => panic!("expected at least 1 type argument here"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,27 +306,22 @@ mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
// Parses a simple AstStruct without the `pub struct` prefix.
|
||||
fn ast_struct_inner(input: ParseStream) -> Result<AstItem> {
|
||||
pub fn ast_struct(input: ParseStream) -> Result<AstItem> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
input.parse::<Token![pub]>()?;
|
||||
input.parse::<Token![struct]>()?;
|
||||
let ident: Ident = input.parse()?;
|
||||
let features = full(input);
|
||||
let rest: TokenStream = input.parse()?;
|
||||
Ok(AstItem {
|
||||
ast: syn::parse2(quote! {
|
||||
#(#attrs)*
|
||||
pub struct #ident #rest
|
||||
})?,
|
||||
features,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ast_struct(input: ParseStream) -> Result<AstItem> {
|
||||
input.call(Attribute::parse_outer)?;
|
||||
input.parse::<Token![pub]>()?;
|
||||
input.parse::<Token![struct]>()?;
|
||||
let res = input.call(ast_struct_inner)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn ast_enum(input: ParseStream) -> Result<AstItem> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
input.parse::<Token![pub]>()?;
|
||||
@@ -422,7 +417,7 @@ mod parsing {
|
||||
expansion.parse::<Token![$]>()?;
|
||||
let path: Path = expansion.parse()?;
|
||||
let ty = path.segments.last().unwrap().ident.to_string();
|
||||
tokens.insert(token, ty.to_string());
|
||||
tokens.insert(token, ty.clone());
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
@@ -495,8 +490,7 @@ fn get_features(attrs: &[Attribute], base: &[Attribute]) -> Vec<Attribute> {
|
||||
ret
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{path}:{line}:{column}: {error}")]
|
||||
#[derive(Debug)]
|
||||
struct LoadFileError {
|
||||
path: PathBuf,
|
||||
line: usize,
|
||||
@@ -504,6 +498,21 @@ struct LoadFileError {
|
||||
error: Error,
|
||||
}
|
||||
|
||||
impl std::error::Error for LoadFileError {}
|
||||
|
||||
impl Display for LoadFileError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
formatter,
|
||||
"{path}:{line}:{column}: {error}",
|
||||
path = self.path.display(),
|
||||
line = self.line,
|
||||
column = self.column,
|
||||
error = self.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_file(
|
||||
relative_to_workspace_root: impl AsRef<Path>,
|
||||
features: &[Attribute],
|
||||
@@ -581,13 +590,13 @@ fn do_load_file(
|
||||
let features = get_features(&item.attrs, features);
|
||||
|
||||
// Try to parse the AstItem declaration out of the item.
|
||||
let tts = item.mac.tokens.clone();
|
||||
let tokens = item.mac.tokens.clone();
|
||||
let mut found = if item.mac.path.is_ident("ast_struct") {
|
||||
parsing::ast_struct.parse2(tts)
|
||||
parsing::ast_struct.parse2(tokens)
|
||||
} else if item.mac.path.is_ident("ast_enum") {
|
||||
parsing::ast_enum.parse2(tts)
|
||||
parsing::ast_enum.parse2(tokens)
|
||||
} else if item.mac.path.is_ident("ast_enum_of_structs") {
|
||||
parsing::ast_enum_of_structs.parse2(tts)
|
||||
parsing::ast_enum_of_structs.parse2(tokens)
|
||||
} else {
|
||||
continue;
|
||||
}?;
|
||||
@@ -619,7 +628,7 @@ fn do_load_file(
|
||||
}
|
||||
}
|
||||
Item::Use(item)
|
||||
if relative_to_workspace_root == Path::new(SYN_CRATE_ROOT)
|
||||
if relative_to_workspace_root == Path::new("src/pat.rs")
|
||||
&& matches!(item.vis, Visibility::Public(_)) =>
|
||||
{
|
||||
load_aliases(item.tree, lookup);
|
||||
|
||||
@@ -275,7 +275,7 @@ fn expand_impl_body(defs: &Definitions, node: &Node, name: &str, val: &Operand)
|
||||
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) {
|
||||
if variants.get("None").is_some_and(Vec::is_empty) {
|
||||
let ty = rust_type(ty);
|
||||
call = quote! {
|
||||
match #val.#ident {
|
||||
@@ -356,14 +356,14 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
file::write(
|
||||
TESTS_DEBUG_SRC,
|
||||
quote! {
|
||||
// False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
|
||||
#![allow(repr_transparent_external_private_fields)]
|
||||
// False positive: https://github.com/rust-lang/rust/issues/115922
|
||||
#![allow(repr_transparent_non_zst_fields)]
|
||||
|
||||
#![allow(clippy::match_wildcard_for_single_variants)]
|
||||
|
||||
use super::{Lite, Present};
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use ref_cast::RefCast;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
#impls
|
||||
},
|
||||
|
||||
+12
-15
@@ -1,22 +1,19 @@
|
||||
use crate::workspace_path;
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context as _, Result};
|
||||
use semver::Version;
|
||||
use serde_derive::Deserialize;
|
||||
use std::fs;
|
||||
use toml::Table;
|
||||
|
||||
pub fn get() -> Result<Version> {
|
||||
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)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Manifest {
|
||||
package: Package,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Package {
|
||||
version: Version,
|
||||
let content = fs::read_to_string(syn_cargo_toml)?;
|
||||
let manifest: Table = toml::from_str(&content)?;
|
||||
manifest
|
||||
.get("package")
|
||||
.context("[package] not found in Cargo.toml")?
|
||||
.get("version")
|
||||
.and_then(toml::Value::as_str)
|
||||
.context("package version not found in Cargo.toml")?
|
||||
.parse()
|
||||
.context("failed to parse package version")
|
||||
}
|
||||
|
||||
+26
-13
@@ -96,7 +96,12 @@ fn visit(
|
||||
|
||||
fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
|
||||
let under_name = gen::under_name(&s.ident);
|
||||
let ty = Ident::new(&s.ident, Span::call_site());
|
||||
let ident = Ident::new(&s.ident, Span::call_site());
|
||||
let ty = if gen::TERMINAL_TYPES.contains(&s.ident.as_str()) {
|
||||
quote!(proc_macro2::#ident)
|
||||
} else {
|
||||
quote!(crate::#ident)
|
||||
};
|
||||
let visit_fn = format_ident!("visit_{}", under_name);
|
||||
|
||||
let mut visit_impl = TokenStream::new();
|
||||
@@ -164,7 +169,7 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
Data::Private => {
|
||||
if ty == "Ident" {
|
||||
if s.ident == "Ident" {
|
||||
visit_impl.extend(quote! {
|
||||
v.visit_span(&node.span());
|
||||
});
|
||||
@@ -178,20 +183,30 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
Some(quote!('ast))
|
||||
};
|
||||
|
||||
let traits_body = if s.ident == "Span" || s.ident == "TokenStream" {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#visit_fn(self, i);
|
||||
})
|
||||
};
|
||||
|
||||
traits.extend(quote! {
|
||||
fn #visit_fn(&mut self, i: &#ast_lifetime #ty) {
|
||||
#visit_fn(self, i);
|
||||
#traits_body
|
||||
}
|
||||
});
|
||||
|
||||
impls.extend(quote! {
|
||||
pub fn #visit_fn<'ast, V>(v: &mut V, node: &#ast_lifetime #ty)
|
||||
where
|
||||
V: Visit<'ast> + ?Sized,
|
||||
{
|
||||
#visit_impl
|
||||
}
|
||||
});
|
||||
if s.ident != "TokenStream" {
|
||||
impls.extend(quote! {
|
||||
pub fn #visit_fn<'ast, V>(v: &mut V, node: &#ast_lifetime #ty)
|
||||
where
|
||||
V: Visit<'ast> + ?Sized,
|
||||
{
|
||||
#visit_impl
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
@@ -205,8 +220,6 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::*;
|
||||
use proc_macro2::Span;
|
||||
|
||||
#full_macro
|
||||
|
||||
|
||||
+54
-20
@@ -1,3 +1,4 @@
|
||||
use crate::cfg::{self, DocCfg};
|
||||
use crate::operand::{Borrowed, Operand, Owned};
|
||||
use crate::{file, full, gen};
|
||||
use anyhow::Result;
|
||||
@@ -36,14 +37,20 @@ fn visit(
|
||||
visit(t, features, defs, &Owned(quote!(*#name)))
|
||||
}
|
||||
Type::Vec(t) => {
|
||||
let operand = Borrowed(quote!(it));
|
||||
let val = visit(t, features, defs, &operand)?;
|
||||
let name = name.ref_mut_tokens();
|
||||
Some(quote! {
|
||||
for it in #name {
|
||||
#val;
|
||||
}
|
||||
})
|
||||
if matches!(&**t, Type::Syn(t) if t == "Attribute") {
|
||||
Some(quote! {
|
||||
v.visit_attributes_mut(#name);
|
||||
})
|
||||
} else {
|
||||
let operand = Borrowed(quote!(it));
|
||||
let val = visit(t, features, defs, &operand)?;
|
||||
Some(quote! {
|
||||
for it in #name {
|
||||
#val;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Type::Punctuated(p) => {
|
||||
let operand = Borrowed(quote!(it));
|
||||
@@ -96,7 +103,12 @@ fn visit(
|
||||
|
||||
fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Definitions) {
|
||||
let under_name = gen::under_name(&s.ident);
|
||||
let ty = Ident::new(&s.ident, Span::call_site());
|
||||
let ident = Ident::new(&s.ident, Span::call_site());
|
||||
let ty = if gen::TERMINAL_TYPES.contains(&s.ident.as_str()) {
|
||||
quote!(proc_macro2::#ident)
|
||||
} else {
|
||||
quote!(crate::#ident)
|
||||
};
|
||||
let visit_mut_fn = format_ident!("visit_{}_mut", under_name);
|
||||
|
||||
let mut visit_mut_impl = TokenStream::new();
|
||||
@@ -164,7 +176,7 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
Data::Private => {
|
||||
if ty == "Ident" {
|
||||
if s.ident == "Ident" {
|
||||
visit_mut_impl.extend(quote! {
|
||||
let mut span = node.span();
|
||||
v.visit_span_mut(&mut span);
|
||||
@@ -174,20 +186,42 @@ fn node(traits: &mut TokenStream, impls: &mut TokenStream, s: &Node, defs: &Defi
|
||||
}
|
||||
}
|
||||
|
||||
let traits_body = if s.ident == "Span" || s.ident == "TokenStream" {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
#visit_mut_fn(self, i);
|
||||
})
|
||||
};
|
||||
|
||||
traits.extend(quote! {
|
||||
fn #visit_mut_fn(&mut self, i: &mut #ty) {
|
||||
#visit_mut_fn(self, i);
|
||||
#traits_body
|
||||
}
|
||||
});
|
||||
|
||||
impls.extend(quote! {
|
||||
pub fn #visit_mut_fn<V>(v: &mut V, node: &mut #ty)
|
||||
where
|
||||
V: VisitMut + ?Sized,
|
||||
{
|
||||
#visit_mut_impl
|
||||
}
|
||||
});
|
||||
if s.ident != "TokenStream" {
|
||||
impls.extend(quote! {
|
||||
pub fn #visit_mut_fn<V>(v: &mut V, node: &mut #ty)
|
||||
where
|
||||
V: VisitMut + ?Sized,
|
||||
{
|
||||
#visit_mut_impl
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if s.ident == "Attribute" {
|
||||
let features = cfg::features(&s.features, DocCfg::Ordinary);
|
||||
traits.extend(quote! {
|
||||
#features
|
||||
fn visit_attributes_mut(&mut self, i: &mut Vec<crate::Attribute>) {
|
||||
for attr in i {
|
||||
self.visit_attribute_mut(attr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
@@ -201,8 +235,8 @@ pub fn generate(defs: &Definitions) -> Result<()> {
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::*;
|
||||
use proc_macro2::Span;
|
||||
#[cfg(any(feature = "derive", feature = "full"))]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#full_macro
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "Usage: dev/import.sh tests/rust/path/to/mod.rs" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -eu
|
||||
|
||||
main=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)/main.rs
|
||||
echo -n "syn_dev::r#mod! {" > "$main"
|
||||
cat "$1" >> "$main"
|
||||
echo "}" >> "$main"
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
colored = "2"
|
||||
colored = "3"
|
||||
proc-macro2 = { version = "1", features = ["span-locations"] }
|
||||
|
||||
[dependencies.syn]
|
||||
|
||||
@@ -39,12 +39,10 @@ enum Error {
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::Error::*;
|
||||
|
||||
match self {
|
||||
IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
|
||||
ReadFile(error) => write!(f, "Unable to read file: {}", error),
|
||||
ParseFile {
|
||||
Error::IncorrectUsage => write!(f, "Usage: dump-syntax path/to/filename.rs"),
|
||||
Error::ReadFile(error) => write!(f, "Unable to read file: {}", error),
|
||||
Error::ParseFile {
|
||||
error,
|
||||
filepath,
|
||||
source_code,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::mem;
|
||||
|
||||
pub use heapsize_derive::*;
|
||||
pub use heapsize_derive::HeapSize;
|
||||
|
||||
pub trait HeapSize {
|
||||
/// Total number of bytes of heap memory owned by `self`.
|
||||
|
||||
+5
-4
@@ -1,4 +1,5 @@
|
||||
artifacts/
|
||||
corpus/
|
||||
coverage/
|
||||
target/
|
||||
/artifacts/
|
||||
/corpus/
|
||||
/coverage/
|
||||
/target/
|
||||
/Cargo.lock
|
||||
|
||||
@@ -28,4 +28,10 @@ path = "fuzz_targets/parse_file.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "parse_literal"
|
||||
path = "fuzz_targets/parse_literal.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use std::str;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if data.len() < 24 {
|
||||
if let Ok(string) = str::from_utf8(data) {
|
||||
let _ = syn::Lit::from_str_for_fuzzing(string);
|
||||
}
|
||||
}
|
||||
});
|
||||
+17
-9
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "syn-codegen"
|
||||
version = "0.4.1" # also update html_root_url
|
||||
version = "0.4.2" # 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"
|
||||
@@ -9,21 +9,29 @@ edition = "2021"
|
||||
keywords = ["syn"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/syn"
|
||||
rust-version = "1.82"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
serde = ["dep:serde", "dep:serde_derive", "indexmap/serde", "semver/serde"]
|
||||
|
||||
[dependencies]
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
semver = { version = "1", features = ["serde"] }
|
||||
serde = "1.0.88"
|
||||
serde_derive = "1.0.88"
|
||||
indexmap = "2"
|
||||
semver = "1"
|
||||
serde = { version = "1.0.88", optional = true }
|
||||
serde_derive = { version = "1.0.88", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
[workspace]
|
||||
|
||||
+37
-16
@@ -44,16 +44,19 @@
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/syn-codegen/0.4.1")]
|
||||
#![doc(html_root_url = "https://docs.rs/syn-codegen/0.4.2")]
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use semver::Version;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
/// Top-level content of the syntax tree description.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Definitions {
|
||||
/// The Syn version whose syntax tree is described by this data.
|
||||
pub version: Version,
|
||||
@@ -72,7 +75,8 @@ pub struct Definitions {
|
||||
}
|
||||
|
||||
/// Syntax tree type defined by Syn.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Node {
|
||||
/// Name of the type.
|
||||
///
|
||||
@@ -83,29 +87,36 @@ pub struct Node {
|
||||
pub features: Features,
|
||||
|
||||
/// Content of the data structure.
|
||||
#[serde(
|
||||
flatten,
|
||||
skip_serializing_if = "is_private",
|
||||
deserialize_with = "private_if_absent"
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
flatten,
|
||||
skip_serializing_if = "is_private",
|
||||
deserialize_with = "private_if_absent"
|
||||
)
|
||||
)]
|
||||
pub data: Data,
|
||||
|
||||
#[serde(skip_serializing_if = "is_true", default = "bool_true")]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(skip_serializing_if = "is_true", default = "bool_true")
|
||||
)]
|
||||
pub exhaustive: bool,
|
||||
}
|
||||
|
||||
/// Content of a syntax tree data structure.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Data {
|
||||
/// This is an opaque type with no publicly accessible structure.
|
||||
Private,
|
||||
|
||||
/// This type is a braced struct with named fields.
|
||||
#[serde(rename = "fields")]
|
||||
#[cfg_attr(feature = "serde", serde(rename = "fields"))]
|
||||
Struct(Fields),
|
||||
|
||||
/// This type is an enum.
|
||||
#[serde(rename = "variants")]
|
||||
#[cfg_attr(feature = "serde", serde(rename = "variants"))]
|
||||
Enum(Variants),
|
||||
}
|
||||
|
||||
@@ -123,8 +134,12 @@ pub type Fields = IndexMap<String, Type>;
|
||||
pub type Variants = IndexMap<String, Vec<Type>>;
|
||||
|
||||
/// Type of a struct field or tuple variant field in the syntax tree.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(Serialize, Deserialize),
|
||||
serde(rename_all = "lowercase")
|
||||
)]
|
||||
pub enum Type {
|
||||
/// Syntax tree type defined by Syn.
|
||||
///
|
||||
@@ -141,7 +156,7 @@ pub enum Type {
|
||||
///
|
||||
/// The type is accessible in the proc-macro2 public API as
|
||||
/// `proc_macro2::#name`.
|
||||
#[serde(rename = "proc_macro2")]
|
||||
#[cfg_attr(feature = "serde", serde(rename = "proc_macro2"))]
|
||||
Ext(String),
|
||||
|
||||
/// Keyword or punctuation token type defined by Syn.
|
||||
@@ -178,20 +193,23 @@ pub enum Type {
|
||||
/// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
|
||||
///
|
||||
/// The punct string will match one of the keys in the `tokens` map.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Punctuated {
|
||||
pub element: Box<Type>,
|
||||
pub punct: String,
|
||||
}
|
||||
|
||||
/// Features behind which a syntax tree type is cfg gated.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Features {
|
||||
/// Type is accessible if at least one of these features is enabled against
|
||||
/// the Syn dependency.
|
||||
pub any: BTreeSet<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn is_private(data: &Data) -> bool {
|
||||
match data {
|
||||
Data::Private => true,
|
||||
@@ -199,6 +217,7 @@ fn is_private(data: &Data) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
@@ -207,10 +226,12 @@ where
|
||||
Ok(option.unwrap_or(Data::Private))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn is_true(b: &bool) -> bool {
|
||||
*b
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn bool_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
+109
-44
@@ -1,12 +1,24 @@
|
||||
use super::*;
|
||||
use proc_macro2::TokenStream;
|
||||
use std::iter;
|
||||
use std::slice;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::error::Error;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::error::Result;
|
||||
use crate::expr::Expr;
|
||||
use crate::mac::MacroDelimiter;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::meta::{self, ParseNestedMeta};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream, Parser, Result};
|
||||
use crate::parse::{Parse, ParseStream, Parser};
|
||||
use crate::path::Path;
|
||||
use crate::token;
|
||||
#[cfg(feature = "parsing")]
|
||||
use alloc::format;
|
||||
#[cfg(feature = "parsing")]
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "printing")]
|
||||
use core::iter;
|
||||
#[cfg(feature = "printing")]
|
||||
use core::slice;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
ast_struct! {
|
||||
/// An attribute, like `#[repr(transparent)]`.
|
||||
@@ -77,9 +89,9 @@ ast_struct! {
|
||||
/// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on
|
||||
/// which you intend to parse.
|
||||
///
|
||||
/// [`Parse`]: parse::Parse
|
||||
/// [`ParseStream::parse`]: parse::ParseBuffer::parse
|
||||
/// [`ParseStream::call`]: parse::ParseBuffer::call
|
||||
/// [`Parse`]: crate::parse::Parse
|
||||
/// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse
|
||||
/// [`ParseStream::call`]: crate::parse::ParseBuffer::call
|
||||
///
|
||||
/// ```
|
||||
/// use syn::{Attribute, Ident, Result, Token};
|
||||
@@ -161,7 +173,7 @@ ast_struct! {
|
||||
/// };
|
||||
/// assert_eq!(doc, attr);
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Attribute {
|
||||
pub pound_token: Token![#],
|
||||
pub style: AttrStyle,
|
||||
@@ -210,7 +222,7 @@ impl Attribute {
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args<T: Parse>(&self) -> Result<T> {
|
||||
self.parse_args_with(T::parse)
|
||||
}
|
||||
@@ -233,7 +245,7 @@ impl Attribute {
|
||||
/// # anyhow::Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
||||
match &self.meta {
|
||||
Meta::Path(path) => Err(crate::error::new2(
|
||||
@@ -379,7 +391,7 @@ impl Attribute {
|
||||
/// # Ok(())
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_nested_meta(
|
||||
&self,
|
||||
logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
@@ -394,7 +406,7 @@ impl Attribute {
|
||||
/// See
|
||||
/// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
|
||||
let mut attrs = Vec::new();
|
||||
while input.peek(Token![#]) {
|
||||
@@ -410,7 +422,7 @@ impl Attribute {
|
||||
/// See
|
||||
/// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
|
||||
let mut attrs = Vec::new();
|
||||
parsing::parse_inner(input, &mut attrs)?;
|
||||
@@ -433,14 +445,14 @@ ast_enum! {
|
||||
/// - `#![feature(proc_macro)]`
|
||||
/// - `//! # Example`
|
||||
/// - `/*! Please file an issue */`
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum AttrStyle {
|
||||
Outer,
|
||||
Inner(Token![!]),
|
||||
}
|
||||
}
|
||||
|
||||
ast_enum_of_structs! {
|
||||
ast_enum! {
|
||||
/// Content of a compile-time structured attribute.
|
||||
///
|
||||
/// ## Path
|
||||
@@ -460,8 +472,8 @@ ast_enum_of_structs! {
|
||||
///
|
||||
/// 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"))))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum Meta {
|
||||
Path(Path),
|
||||
|
||||
@@ -475,7 +487,7 @@ ast_enum_of_structs! {
|
||||
|
||||
ast_struct! {
|
||||
/// A structured list within an attribute, like `derive(Copy, Clone)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct MetaList {
|
||||
pub path: Path,
|
||||
pub delimiter: MacroDelimiter,
|
||||
@@ -485,7 +497,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A name-value pair within an attribute, like `feature = "nightly"`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct MetaNameValue {
|
||||
pub path: Path,
|
||||
pub eq_token: Token![=],
|
||||
@@ -508,7 +520,7 @@ impl Meta {
|
||||
|
||||
/// Error if this is a `Meta::List` or `Meta::NameValue`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_path_only(&self) -> Result<&Path> {
|
||||
let error_span = match self {
|
||||
Meta::Path(path) => return Ok(path),
|
||||
@@ -520,7 +532,7 @@ impl Meta {
|
||||
|
||||
/// Error if this is a `Meta::Path` or `Meta::NameValue`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_list(&self) -> Result<&MetaList> {
|
||||
match self {
|
||||
Meta::List(meta) => Ok(meta),
|
||||
@@ -538,7 +550,7 @@ impl Meta {
|
||||
|
||||
/// Error if this is a `Meta::Path` or `Meta::List`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_name_value(&self) -> Result<&MetaNameValue> {
|
||||
match self {
|
||||
Meta::NameValue(meta) => Ok(meta),
|
||||
@@ -558,14 +570,14 @@ impl Meta {
|
||||
impl MetaList {
|
||||
/// See [`Attribute::parse_args`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_args<T: Parse>(&self) -> Result<T> {
|
||||
self.parse_args_with(T::parse)
|
||||
}
|
||||
|
||||
/// See [`Attribute::parse_args_with`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, 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())
|
||||
@@ -573,7 +585,7 @@ impl MetaList {
|
||||
|
||||
/// See [`Attribute::parse_nested_meta`].
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_nested_meta(
|
||||
&self,
|
||||
logic: impl FnMut(ParseNestedMeta) -> Result<()>,
|
||||
@@ -582,13 +594,16 @@ impl MetaList {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
pub(crate) trait FilterAttrs<'a> {
|
||||
type Ret: Iterator<Item = &'a Attribute>;
|
||||
|
||||
fn outer(self) -> Self::Ret;
|
||||
#[cfg(feature = "full")]
|
||||
fn inner(self) -> Self::Ret;
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
impl<'a> FilterAttrs<'a> for &'a [Attribute] {
|
||||
type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>;
|
||||
|
||||
@@ -602,6 +617,7 @@ impl<'a> FilterAttrs<'a> for &'a [Attribute] {
|
||||
self.iter().filter(is_outer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
fn inner(self) -> Self::Ret {
|
||||
fn is_inner(attr: &&Attribute) -> bool {
|
||||
match attr.style {
|
||||
@@ -613,16 +629,41 @@ impl<'a> FilterAttrs<'a> for &'a [Attribute] {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Path> for Meta {
|
||||
fn from(meta: Path) -> Meta {
|
||||
Meta::Path(meta)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MetaList> for Meta {
|
||||
fn from(meta: MetaList) -> Meta {
|
||||
Meta::List(meta)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MetaNameValue> for Meta {
|
||||
fn from(meta: MetaNameValue) -> Meta {
|
||||
Meta::NameValue(meta)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
|
||||
use crate::error::Result;
|
||||
use crate::expr::{Expr, ExprLit};
|
||||
use crate::lit::Lit;
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use std::fmt::{self, Display};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::path::Path;
|
||||
use crate::{mac, token};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Display};
|
||||
use proc_macro2::Ident;
|
||||
|
||||
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)?);
|
||||
attrs.push(input.call(single_parse_inner)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -647,34 +688,45 @@ pub(crate) mod parsing {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Meta {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
let path = parse_outermost_meta_path(input)?;
|
||||
parse_meta_after_path(path, input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for MetaList {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
let path = parse_outermost_meta_path(input)?;
|
||||
parse_meta_list_after_path(path, input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for MetaNameValue {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let path = input.call(Path::parse_mod_style)?;
|
||||
let path = parse_outermost_meta_path(input)?;
|
||||
parse_meta_name_value_after_path(path, input)
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike meta::parse_meta_path which accepts arbitrary keywords in the path,
|
||||
// only the `unsafe` keyword is accepted as an attribute's outermost path.
|
||||
fn parse_outermost_meta_path(input: ParseStream) -> Result<Path> {
|
||||
if input.peek(Token![unsafe]) {
|
||||
let unsafe_token: Token![unsafe] = input.parse()?;
|
||||
Ok(Path::from(Ident::new("unsafe", unsafe_token.span)))
|
||||
} else {
|
||||
Path::parse_mod_style(input)
|
||||
}
|
||||
}
|
||||
|
||||
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![=]) {
|
||||
} else if input.peek(Token![=]) && !input.peek(Token![==]) && !input.peek(Token![=>]) {
|
||||
parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
|
||||
} else {
|
||||
Ok(Meta::Path(path))
|
||||
@@ -740,11 +792,13 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
|
||||
use crate::path;
|
||||
use crate::path::printing::PathStyle;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Attribute {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.pound_token.to_tokens(tokens);
|
||||
@@ -757,18 +811,29 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Meta {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod),
|
||||
Meta::List(meta_list) => meta_list.to_tokens(tokens),
|
||||
Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for MetaList {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.path.to_tokens(tokens);
|
||||
path::printing::print_path(tokens, &self.path, PathStyle::Mod);
|
||||
self.delimiter.surround(tokens, self.tokens.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for MetaNameValue {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.path.to_tokens(tokens);
|
||||
path::printing::print_path(tokens, &self.path, PathStyle::Mod);
|
||||
self.eq_token.to_tokens(tokens);
|
||||
self.value.to_tokens(tokens);
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
use std::ops::{AddAssign, MulAssign};
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::{AddAssign, MulAssign};
|
||||
|
||||
// For implementing base10_digits() accessor on LitInt.
|
||||
pub(crate) struct BigInt {
|
||||
|
||||
+105
-100
@@ -5,11 +5,15 @@
|
||||
// Syn, and caution should be used when editing it. The public-facing interface
|
||||
// is 100% safe but the implementation is fragile internally.
|
||||
|
||||
use crate::ext::TokenStreamExt as _;
|
||||
use crate::Lifetime;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::Ordering;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
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;
|
||||
|
||||
/// Internal type which is used instead of `TokenTree` to represent a token tree
|
||||
/// within a `TokenBuffer`.
|
||||
@@ -20,8 +24,9 @@ enum Entry {
|
||||
Ident(Ident),
|
||||
Punct(Punct),
|
||||
Literal(Literal),
|
||||
// End entries contain the offset (negative) to the start of the buffer.
|
||||
End(isize),
|
||||
// End entries contain the offset (negative) to the start of the buffer, and
|
||||
// offset (negative) to the matching Group entry.
|
||||
End(isize, isize),
|
||||
}
|
||||
|
||||
/// A buffer that can be efficiently traversed multiple times, unlike
|
||||
@@ -42,12 +47,15 @@ impl TokenBuffer {
|
||||
TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)),
|
||||
TokenTree::Group(group) => {
|
||||
let group_start_index = entries.len();
|
||||
entries.push(Entry::End(0)); // we replace this below
|
||||
entries.push(Entry::End(0, 0)); // we replace this below
|
||||
Self::recursive_new(entries, group.stream());
|
||||
let group_end_index = entries.len();
|
||||
entries.push(Entry::End(-(group_end_index as isize)));
|
||||
let group_end_offset = group_end_index - group_start_index;
|
||||
entries[group_start_index] = Entry::Group(group, group_end_offset);
|
||||
let group_offset = group_end_index - group_start_index;
|
||||
entries.push(Entry::End(
|
||||
-(group_end_index as isize),
|
||||
-(group_offset as isize),
|
||||
));
|
||||
entries[group_start_index] = Entry::Group(group, group_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +64,7 @@ impl TokenBuffer {
|
||||
/// Creates a `TokenBuffer` containing all the tokens from the input
|
||||
/// `proc_macro::TokenStream`.
|
||||
#[cfg(feature = "proc-macro")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))]
|
||||
pub fn new(stream: proc_macro::TokenStream) -> Self {
|
||||
Self::new2(stream.into())
|
||||
}
|
||||
@@ -66,7 +74,7 @@ impl TokenBuffer {
|
||||
pub fn new2(stream: TokenStream) -> Self {
|
||||
let mut entries = Vec::new();
|
||||
Self::recursive_new(&mut entries, stream);
|
||||
entries.push(Entry::End(-(entries.len() as isize)));
|
||||
entries.push(Entry::End(-(entries.len() as isize), 0));
|
||||
Self {
|
||||
entries: entries.into_boxed_slice(),
|
||||
}
|
||||
@@ -111,7 +119,7 @@ impl<'a> Cursor<'a> {
|
||||
// object in global storage.
|
||||
struct UnsafeSyncEntry(Entry);
|
||||
unsafe impl Sync for UnsafeSyncEntry {}
|
||||
static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0));
|
||||
static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0, 0));
|
||||
|
||||
Cursor {
|
||||
ptr: &EMPTY_ENTRY.0,
|
||||
@@ -128,8 +136,8 @@ 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(_) = unsafe { &*ptr } {
|
||||
if ptr == scope {
|
||||
while let Entry::End(..) = unsafe { &*ptr } {
|
||||
if ptr::eq(ptr, scope) {
|
||||
break;
|
||||
}
|
||||
ptr = unsafe { ptr.add(1) };
|
||||
@@ -154,7 +162,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> {
|
||||
unsafe { Cursor::create(self.ptr.offset(1), self.scope) }
|
||||
unsafe { Cursor::create(self.ptr.add(1), self.scope) }
|
||||
}
|
||||
|
||||
/// While the cursor is looking at a `None`-delimited group, move it to look
|
||||
@@ -176,53 +184,7 @@ impl<'a> Cursor<'a> {
|
||||
/// scope.
|
||||
pub fn eof(self) -> bool {
|
||||
// We're at eof if we're at the end of our scope.
|
||||
self.ptr == self.scope
|
||||
}
|
||||
|
||||
/// If the cursor is pointing at a `Group` with the given delimiter, returns
|
||||
/// a cursor into that group and one pointing to the next `TokenTree`.
|
||||
pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, 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.
|
||||
if delim != Delimiter::None {
|
||||
self.ignore_none();
|
||||
}
|
||||
|
||||
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, 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
|
||||
ptr::eq(self.ptr, self.scope)
|
||||
}
|
||||
|
||||
/// If the cursor is pointing at a `Ident`, returns it along with a cursor
|
||||
@@ -275,16 +237,64 @@ 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>, 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.
|
||||
if delim != Delimiter::None {
|
||||
self.ignore_none();
|
||||
}
|
||||
|
||||
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, span, after_group));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// If the cursor is pointing at a `Group`, returns a cursor into the group
|
||||
/// and one pointing to the next `TokenTree`.
|
||||
pub 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
|
||||
}
|
||||
|
||||
/// Copies all remaining tokens visible from this cursor into a
|
||||
/// `TokenStream`.
|
||||
pub fn token_stream(self) -> TokenStream {
|
||||
let mut tts = Vec::new();
|
||||
let mut tokens = TokenStream::new();
|
||||
let mut cursor = self;
|
||||
while let Some((tt, rest)) = cursor.token_tree() {
|
||||
tts.push(tt);
|
||||
tokens.append(tt);
|
||||
cursor = rest;
|
||||
}
|
||||
tts.into_iter().collect()
|
||||
tokens
|
||||
}
|
||||
|
||||
/// If the cursor is pointing at a `TokenTree`, returns it along with a
|
||||
@@ -300,7 +310,7 @@ impl<'a> Cursor<'a> {
|
||||
Entry::Literal(literal) => (literal.clone().into(), 1),
|
||||
Entry::Ident(ident) => (ident.clone().into(), 1),
|
||||
Entry::Punct(punct) => (punct.clone().into(), 1),
|
||||
Entry::End(_) => return None,
|
||||
Entry::End(..) => return None,
|
||||
};
|
||||
|
||||
let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) };
|
||||
@@ -309,13 +319,20 @@ impl<'a> Cursor<'a> {
|
||||
|
||||
/// Returns the `Span` of the current token, or `Span::call_site()` if this
|
||||
/// cursor points to eof.
|
||||
pub fn span(self) -> Span {
|
||||
pub fn span(mut self) -> Span {
|
||||
match self.entry() {
|
||||
Entry::Group(group, _) => group.span(),
|
||||
Entry::Literal(literal) => literal.span(),
|
||||
Entry::Ident(ident) => ident.span(),
|
||||
Entry::Punct(punct) => punct.span(),
|
||||
Entry::End(_) => Span::call_site(),
|
||||
Entry::End(_, offset) => {
|
||||
self.ptr = unsafe { self.ptr.offset(*offset) };
|
||||
if let Entry::Group(group, _) = self.entry() {
|
||||
group.span_close()
|
||||
} else {
|
||||
Span::call_site()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,35 +341,20 @@ impl<'a> Cursor<'a> {
|
||||
#[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.ptr = unsafe { self.ptr.sub(1) };
|
||||
}
|
||||
self.span()
|
||||
}
|
||||
|
||||
/// Skip over the next token without cloning it. Returns `None` if this
|
||||
/// cursor points to eof.
|
||||
/// Skip over the next token that is not a None-delimited group, without
|
||||
/// cloning it. Returns `None` if this cursor points to eof.
|
||||
///
|
||||
/// This method treats `'lifetimes` as a single token.
|
||||
pub(crate) fn skip(self) -> Option<Cursor<'a>> {
|
||||
pub(crate) fn skip(mut self) -> Option<Cursor<'a>> {
|
||||
self.ignore_none();
|
||||
|
||||
let len = match self.entry() {
|
||||
Entry::End(_) => return None,
|
||||
Entry::End(..) => return None,
|
||||
|
||||
// Treat lifetimes as a single tt for the purposes of 'skip'.
|
||||
Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => {
|
||||
@@ -368,6 +370,16 @@ impl<'a> Cursor<'a> {
|
||||
|
||||
Some(unsafe { Cursor::create(self.ptr.add(len), self.scope) })
|
||||
}
|
||||
|
||||
pub(crate) fn scope_delimiter(self) -> Delimiter {
|
||||
match unsafe { &*self.scope } {
|
||||
Entry::End(_, offset) => match unsafe { &*self.scope.offset(*offset) } {
|
||||
Entry::Group(group, _) => group.delimiter(),
|
||||
_ => Delimiter::None,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Copy for Cursor<'a> {}
|
||||
@@ -382,7 +394,7 @@ impl<'a> Eq for Cursor<'a> {}
|
||||
|
||||
impl<'a> PartialEq for Cursor<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.ptr == other.ptr
|
||||
ptr::eq(self.ptr, other.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,17 +409,17 @@ impl<'a> PartialOrd for Cursor<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool {
|
||||
a.scope == b.scope
|
||||
ptr::eq(a.scope, b.scope)
|
||||
}
|
||||
|
||||
pub(crate) fn same_buffer(a: Cursor, b: Cursor) -> bool {
|
||||
start_of_buffer(a) == start_of_buffer(b)
|
||||
ptr::eq(start_of_buffer(a), start_of_buffer(b))
|
||||
}
|
||||
|
||||
fn start_of_buffer(cursor: Cursor) -> *const Entry {
|
||||
unsafe {
|
||||
match &*cursor.scope {
|
||||
Entry::End(offset) => cursor.scope.offset(*offset),
|
||||
Entry::End(offset, _) => cursor.scope.offset(*offset),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -423,10 +435,3 @@ pub(crate) fn open_span_of_group(cursor: Cursor) -> Span {
|
||||
_ => cursor.span(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn close_span_of_group(cursor: Cursor) -> Span {
|
||||
match cursor.entry() {
|
||||
Entry::Group(group, _) => group.span_close(),
|
||||
_ => cursor.span(),
|
||||
}
|
||||
}
|
||||
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
#[cfg(feature = "full")]
|
||||
use crate::expr::Expr;
|
||||
#[cfg(any(feature = "printing", feature = "full"))]
|
||||
use crate::generics::TypeParamBound;
|
||||
#[cfg(any(feature = "printing", feature = "full"))]
|
||||
use crate::path::{Path, PathArguments};
|
||||
#[cfg(any(feature = "printing", feature = "full"))]
|
||||
use crate::punctuated::Punctuated;
|
||||
#[cfg(any(feature = "printing", feature = "full"))]
|
||||
use crate::ty::{ReturnType, Type};
|
||||
#[cfg(any(feature = "printing", feature = "full"))]
|
||||
use core::ops::ControlFlow;
|
||||
#[cfg(feature = "full")]
|
||||
use proc_macro2::{Delimiter, TokenStream, TokenTree};
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Macro(expr) => !expr.mac.delimiter.is_brace(),
|
||||
_ => requires_comma_to_be_match_arm(expr),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::If(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc
|
||||
| Expr::While(_)
|
||||
| Expr::Loop(_)
|
||||
| Expr::ForLoop(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Const(_) => false,
|
||||
|
||||
Expr::Array(_)
|
||||
| Expr::Assign(_)
|
||||
| Expr::Async(_)
|
||||
| Expr::Await(_)
|
||||
| Expr::Binary(_)
|
||||
| Expr::Break(_)
|
||||
| Expr::Call(_)
|
||||
| Expr::Cast(_)
|
||||
| Expr::Closure(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Field(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::Index(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Let(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::Macro(_)
|
||||
| Expr::MethodCall(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Range(_)
|
||||
| Expr::RawAddr(_)
|
||||
| Expr::Reference(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Return(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::Try(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::Unary(_)
|
||||
| Expr::Yield(_)
|
||||
| Expr::Verbatim(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool {
|
||||
loop {
|
||||
match ty {
|
||||
Type::BareFn(t) => match &t.output {
|
||||
ReturnType::Default => return false,
|
||||
ReturnType::Type(_, ret) => ty = ret,
|
||||
},
|
||||
Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
|
||||
ControlFlow::Break(trailing_path) => return trailing_path,
|
||||
ControlFlow::Continue(t) => ty = t,
|
||||
},
|
||||
Type::Path(t) => match last_type_in_path(&t.path) {
|
||||
ControlFlow::Break(trailing_path) => return trailing_path,
|
||||
ControlFlow::Continue(t) => ty = t,
|
||||
},
|
||||
Type::Ptr(t) => ty = &t.elem,
|
||||
Type::Reference(t) => ty = &t.elem,
|
||||
Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
|
||||
ControlFlow::Break(trailing_path) => return trailing_path,
|
||||
ControlFlow::Continue(t) => ty = t,
|
||||
},
|
||||
|
||||
Type::Array(_)
|
||||
| Type::Group(_)
|
||||
| Type::Infer(_)
|
||||
| Type::Macro(_)
|
||||
| Type::Never(_)
|
||||
| Type::Paren(_)
|
||||
| Type::Slice(_)
|
||||
| Type::Tuple(_)
|
||||
| Type::Verbatim(_) => return false,
|
||||
}
|
||||
}
|
||||
|
||||
fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> {
|
||||
match &path.segments.last().unwrap().arguments {
|
||||
PathArguments::None => ControlFlow::Break(true),
|
||||
PathArguments::AngleBracketed(_) => ControlFlow::Break(false),
|
||||
PathArguments::Parenthesized(arg) => match &arg.output {
|
||||
ReturnType::Default => ControlFlow::Break(false),
|
||||
ReturnType::Type(_, ret) => ControlFlow::Continue(ret),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn last_type_in_bounds(
|
||||
bounds: &Punctuated<TypeParamBound, Token![+]>,
|
||||
) -> ControlFlow<bool, &Type> {
|
||||
match bounds.last().unwrap() {
|
||||
TypeParamBound::Trait(t) => last_type_in_path(&t.path),
|
||||
TypeParamBound::Lifetime(_)
|
||||
| TypeParamBound::PreciseCapture(_)
|
||||
| TypeParamBound::Verbatim(_) => ControlFlow::Break(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the expression's first token is the label of a loop/block.
|
||||
#[cfg(all(feature = "printing", feature = "full"))]
|
||||
pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool {
|
||||
loop {
|
||||
match expr {
|
||||
Expr::Block(e) => return e.label.is_some(),
|
||||
Expr::ForLoop(e) => return e.label.is_some(),
|
||||
Expr::Loop(e) => return e.label.is_some(),
|
||||
Expr::While(e) => return e.label.is_some(),
|
||||
|
||||
Expr::Assign(e) => expr = &e.left,
|
||||
Expr::Await(e) => expr = &e.base,
|
||||
Expr::Binary(e) => expr = &e.left,
|
||||
Expr::Call(e) => expr = &e.func,
|
||||
Expr::Cast(e) => expr = &e.expr,
|
||||
Expr::Field(e) => expr = &e.base,
|
||||
Expr::Index(e) => expr = &e.expr,
|
||||
Expr::MethodCall(e) => expr = &e.receiver,
|
||||
Expr::Range(e) => match &e.start {
|
||||
Some(start) => expr = start,
|
||||
None => return false,
|
||||
},
|
||||
Expr::Try(e) => expr = &e.expr,
|
||||
|
||||
Expr::Array(_)
|
||||
| Expr::Async(_)
|
||||
| Expr::Break(_)
|
||||
| Expr::Closure(_)
|
||||
| Expr::Const(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::If(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Let(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::Macro(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::RawAddr(_)
|
||||
| Expr::Reference(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Return(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::Unary(_)
|
||||
| Expr::Unsafe(_)
|
||||
| Expr::Verbatim(_)
|
||||
| Expr::Yield(_) => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the expression's last token is `}`.
|
||||
#[cfg(feature = "full")]
|
||||
pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
|
||||
loop {
|
||||
match expr {
|
||||
Expr::Async(_)
|
||||
| Expr::Block(_)
|
||||
| Expr::Const(_)
|
||||
| Expr::ForLoop(_)
|
||||
| Expr::If(_)
|
||||
| Expr::Loop(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Unsafe(_)
|
||||
| Expr::While(_) => return true,
|
||||
|
||||
Expr::Assign(e) => expr = &e.right,
|
||||
Expr::Binary(e) => expr = &e.right,
|
||||
Expr::Break(e) => match &e.expr {
|
||||
Some(e) => expr = e,
|
||||
None => return false,
|
||||
},
|
||||
Expr::Cast(e) => return type_trailing_brace(&e.ty),
|
||||
Expr::Closure(e) => expr = &e.body,
|
||||
Expr::Let(e) => expr = &e.expr,
|
||||
Expr::Macro(e) => return e.mac.delimiter.is_brace(),
|
||||
Expr::Range(e) => match &e.end {
|
||||
Some(end) => expr = end,
|
||||
None => return false,
|
||||
},
|
||||
Expr::RawAddr(e) => expr = &e.expr,
|
||||
Expr::Reference(e) => expr = &e.expr,
|
||||
Expr::Return(e) => match &e.expr {
|
||||
Some(e) => expr = e,
|
||||
None => return false,
|
||||
},
|
||||
Expr::Unary(e) => expr = &e.expr,
|
||||
Expr::Verbatim(e) => return tokens_trailing_brace(e),
|
||||
Expr::Yield(e) => match &e.expr {
|
||||
Some(e) => expr = e,
|
||||
None => return false,
|
||||
},
|
||||
|
||||
Expr::Array(_)
|
||||
| Expr::Await(_)
|
||||
| Expr::Call(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Field(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::Index(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::MethodCall(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Try(_)
|
||||
| Expr::Tuple(_) => return false,
|
||||
}
|
||||
}
|
||||
|
||||
fn type_trailing_brace(mut ty: &Type) -> bool {
|
||||
loop {
|
||||
match ty {
|
||||
Type::BareFn(t) => match &t.output {
|
||||
ReturnType::Default => return false,
|
||||
ReturnType::Type(_, ret) => ty = ret,
|
||||
},
|
||||
Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
|
||||
ControlFlow::Break(trailing_brace) => return trailing_brace,
|
||||
ControlFlow::Continue(t) => ty = t,
|
||||
},
|
||||
Type::Macro(t) => return t.mac.delimiter.is_brace(),
|
||||
Type::Path(t) => match last_type_in_path(&t.path) {
|
||||
Some(t) => ty = t,
|
||||
None => return false,
|
||||
},
|
||||
Type::Ptr(t) => ty = &t.elem,
|
||||
Type::Reference(t) => ty = &t.elem,
|
||||
Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
|
||||
ControlFlow::Break(trailing_brace) => return trailing_brace,
|
||||
ControlFlow::Continue(t) => ty = t,
|
||||
},
|
||||
Type::Verbatim(t) => return tokens_trailing_brace(t),
|
||||
|
||||
Type::Array(_)
|
||||
| Type::Group(_)
|
||||
| Type::Infer(_)
|
||||
| Type::Never(_)
|
||||
| Type::Paren(_)
|
||||
| Type::Slice(_)
|
||||
| Type::Tuple(_) => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn last_type_in_path(path: &Path) -> Option<&Type> {
|
||||
match &path.segments.last().unwrap().arguments {
|
||||
PathArguments::None | PathArguments::AngleBracketed(_) => None,
|
||||
PathArguments::Parenthesized(arg) => match &arg.output {
|
||||
ReturnType::Default => None,
|
||||
ReturnType::Type(_, ret) => Some(ret),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn last_type_in_bounds(
|
||||
bounds: &Punctuated<TypeParamBound, Token![+]>,
|
||||
) -> ControlFlow<bool, &Type> {
|
||||
match bounds.last().unwrap() {
|
||||
TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
|
||||
Some(t) => ControlFlow::Continue(t),
|
||||
None => ControlFlow::Break(false),
|
||||
},
|
||||
TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => {
|
||||
ControlFlow::Break(false)
|
||||
}
|
||||
TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
|
||||
}
|
||||
}
|
||||
|
||||
fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
|
||||
if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
|
||||
last.delimiter() == Delimiter::Brace
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,7 @@ macro_rules! custom_keyword {
|
||||
($ident:ident) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct $ident {
|
||||
#[allow(dead_code)]
|
||||
pub span: $crate::__private::Span,
|
||||
}
|
||||
|
||||
|
||||
+17
-14
@@ -30,6 +30,7 @@
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use core::iter;
|
||||
/// use proc_macro2::{TokenStream, TokenTree};
|
||||
/// use syn::parse::{Parse, ParseStream, Peek, Result};
|
||||
/// use syn::punctuated::Punctuated;
|
||||
@@ -64,7 +65,7 @@
|
||||
/// let mut tokens = TokenStream::new();
|
||||
/// while !input.is_empty() && !input.peek(end) {
|
||||
/// let next: TokenTree = input.parse()?;
|
||||
/// tokens.extend(Some(next));
|
||||
/// tokens.extend(iter::once(next));
|
||||
/// }
|
||||
/// Ok(tokens)
|
||||
/// }
|
||||
@@ -78,6 +79,7 @@
|
||||
macro_rules! custom_punctuation {
|
||||
($ident:ident, $($tt:tt)+) => {
|
||||
pub struct $ident {
|
||||
#[allow(dead_code)]
|
||||
pub spans: $crate::custom_punctuation_repr!($($tt)+),
|
||||
}
|
||||
|
||||
@@ -236,50 +238,51 @@ macro_rules! custom_punctuation_repr {
|
||||
#[macro_export]
|
||||
#[rustfmt::skip]
|
||||
macro_rules! custom_punctuation_len {
|
||||
($mode:ident, +) => { 1 };
|
||||
($mode:ident, +=) => { 2 };
|
||||
($mode:ident, &) => { 1 };
|
||||
($mode:ident, &&) => { 2 };
|
||||
($mode:ident, &=) => { 2 };
|
||||
($mode:ident, @) => { 1 };
|
||||
($mode:ident, !) => { 1 };
|
||||
($mode:ident, ^) => { 1 };
|
||||
($mode:ident, ^=) => { 2 };
|
||||
($mode:ident, :) => { 1 };
|
||||
($mode:ident, ::) => { 2 };
|
||||
($mode:ident, ,) => { 1 };
|
||||
($mode:ident, /) => { 1 };
|
||||
($mode:ident, /=) => { 2 };
|
||||
($mode:ident, $) => { 1 };
|
||||
($mode:ident, .) => { 1 };
|
||||
($mode:ident, ..) => { 2 };
|
||||
($mode:ident, ...) => { 3 };
|
||||
($mode:ident, ..=) => { 3 };
|
||||
($mode:ident, =) => { 1 };
|
||||
($mode:ident, ==) => { 2 };
|
||||
($mode:ident, =>) => { 2 };
|
||||
($mode:ident, >=) => { 2 };
|
||||
($mode:ident, >) => { 1 };
|
||||
($mode:ident, <-) => { 2 };
|
||||
($mode:ident, <=) => { 2 };
|
||||
($mode:ident, <) => { 1 };
|
||||
($mode:ident, *=) => { 2 };
|
||||
($mode:ident, -) => { 1 };
|
||||
($mode:ident, -=) => { 2 };
|
||||
($mode:ident, !=) => { 2 };
|
||||
($mode:ident, !) => { 1 };
|
||||
($mode:ident, |) => { 1 };
|
||||
($mode:ident, |=) => { 2 };
|
||||
($mode:ident, ||) => { 2 };
|
||||
($mode:ident, ::) => { 2 };
|
||||
($mode:ident, %) => { 1 };
|
||||
($mode:ident, %=) => { 2 };
|
||||
($mode:ident, +) => { 1 };
|
||||
($mode:ident, +=) => { 2 };
|
||||
($mode:ident, #) => { 1 };
|
||||
($mode:ident, ?) => { 1 };
|
||||
($mode:ident, ->) => { 2 };
|
||||
($mode:ident, <-) => { 2 };
|
||||
($mode:ident, %) => { 1 };
|
||||
($mode:ident, %=) => { 2 };
|
||||
($mode:ident, =>) => { 2 };
|
||||
($mode:ident, ;) => { 1 };
|
||||
($mode:ident, <<) => { 2 };
|
||||
($mode:ident, <<=) => { 3 };
|
||||
($mode:ident, >>) => { 2 };
|
||||
($mode:ident, >>=) => { 3 };
|
||||
($mode:ident, /) => { 1 };
|
||||
($mode:ident, /=) => { 2 };
|
||||
($mode:ident, *) => { 1 };
|
||||
($mode:ident, -) => { 1 };
|
||||
($mode:ident, -=) => { 2 };
|
||||
($mode:ident, *=) => { 2 };
|
||||
($mode:ident, ~) => { 1 };
|
||||
(lenient, $tt:tt) => { 0 };
|
||||
(strict, $tt:tt) => {{ $crate::custom_punctuation_unexpected!($tt); 0 }};
|
||||
|
||||
+116
-95
@@ -1,9 +1,15 @@
|
||||
use super::*;
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::attr::Attribute;
|
||||
use crate::expr::{Expr, Index, Member};
|
||||
use crate::ident::Ident;
|
||||
use crate::punctuated::{self, Punctuated};
|
||||
use crate::restriction::{FieldMutability, Visibility};
|
||||
use crate::token;
|
||||
use crate::ty::Type;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
ast_struct! {
|
||||
/// An enum variant.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Variant {
|
||||
pub attrs: Vec<Attribute>,
|
||||
|
||||
@@ -25,8 +31,8 @@ ast_enum_of_structs! {
|
||||
///
|
||||
/// 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"))))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum Fields {
|
||||
/// Named fields of a struct or struct variant such as `Point { x: f64,
|
||||
/// y: f64 }`.
|
||||
@@ -43,7 +49,7 @@ ast_enum_of_structs! {
|
||||
ast_struct! {
|
||||
/// Named fields of a struct or struct variant such as `Point { x: f64,
|
||||
/// y: f64 }`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct FieldsNamed {
|
||||
pub brace_token: token::Brace,
|
||||
pub named: Punctuated<Field, Token![,]>,
|
||||
@@ -52,7 +58,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct FieldsUnnamed {
|
||||
pub paren_token: token::Paren,
|
||||
pub unnamed: Punctuated<Field, Token![,]>,
|
||||
@@ -99,6 +105,47 @@ impl Fields {
|
||||
Fields::Unnamed(f) => f.unnamed.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
return_impl_trait! {
|
||||
/// Get an iterator over the fields of a struct or variant as [`Member`]s.
|
||||
/// This iterator can be used to iterate over a named or unnamed struct or
|
||||
/// variant's fields uniformly.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// The following is a simplistic [`Clone`] derive for structs. (A more
|
||||
/// complete implementation would additionally want to infer trait bounds on
|
||||
/// the generic type parameters.)
|
||||
///
|
||||
/// ```
|
||||
/// # use quote::quote;
|
||||
/// #
|
||||
/// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
|
||||
/// let ident = &input.ident;
|
||||
/// let members = input.fields.members();
|
||||
/// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
/// quote! {
|
||||
/// impl #impl_generics Clone for #ident #ty_generics #where_clause {
|
||||
/// fn clone(&self) -> Self {
|
||||
/// Self {
|
||||
/// #(#members: self.#members.clone()),*
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// For structs with named fields, it produces an expression like `Self { a:
|
||||
/// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
|
||||
/// self.0.clone() }`. And for unit structs, `Self {}`.
|
||||
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] {
|
||||
Members {
|
||||
fields: self.iter(),
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Fields {
|
||||
@@ -134,7 +181,7 @@ impl<'a> IntoIterator for &'a mut Fields {
|
||||
|
||||
ast_struct! {
|
||||
/// A field of a struct or enum variant.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Field {
|
||||
pub attrs: Vec<Attribute>,
|
||||
|
||||
@@ -153,15 +200,62 @@ ast_struct! {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Members<'a> {
|
||||
fields: punctuated::Iter<'a, Field>,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Members<'a> {
|
||||
type Item = Member;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let field = self.fields.next()?;
|
||||
let member = match &field.ident {
|
||||
Some(ident) => Member::Named(ident.clone()),
|
||||
None => {
|
||||
#[cfg(all(feature = "parsing", feature = "printing"))]
|
||||
let span = crate::spanned::Spanned::span(&field.ty);
|
||||
#[cfg(not(all(feature = "parsing", feature = "printing")))]
|
||||
let span = proc_macro2::Span::call_site();
|
||||
Member::Unnamed(Index {
|
||||
index: self.index,
|
||||
span,
|
||||
})
|
||||
}
|
||||
};
|
||||
self.index += 1;
|
||||
Some(member)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Clone for Members<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Members {
|
||||
fields: self.fields.clone(),
|
||||
index: self.index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};
|
||||
use crate::error::Result;
|
||||
use crate::expr::Expr;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::ident::Ident;
|
||||
#[cfg(not(feature = "full"))]
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::restriction::{FieldMutability, Visibility};
|
||||
#[cfg(not(feature = "full"))]
|
||||
use crate::scan_expr::scan_expr;
|
||||
use crate::token;
|
||||
use crate::ty::Type;
|
||||
use crate::verbatim;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Variant {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
@@ -185,7 +279,7 @@ pub(crate) mod parsing {
|
||||
let mut discriminant: Result<Expr> = ahead.parse();
|
||||
if discriminant.is_ok() {
|
||||
input.advance_to(&ahead);
|
||||
} else if scan_lenient_discriminant(input).is_ok() {
|
||||
} else if scan_expr(input).is_ok() {
|
||||
discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input)));
|
||||
}
|
||||
discriminant?
|
||||
@@ -203,80 +297,7 @@ pub(crate) 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for FieldsNamed {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -287,7 +308,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for FieldsUnnamed {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -300,7 +321,7 @@ pub(crate) mod parsing {
|
||||
|
||||
impl Field {
|
||||
/// Parses a named (braced struct) field.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_named(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let vis: Visibility = input.parse()?;
|
||||
@@ -337,7 +358,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
/// Parses an unnamed (tuple struct) field.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
|
||||
Ok(Field {
|
||||
attrs: input.call(Attribute::parse_outer)?,
|
||||
@@ -353,12 +374,12 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant};
|
||||
use crate::print::TokensOrDefault;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Variant {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(&self.attrs);
|
||||
@@ -371,7 +392,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for FieldsNamed {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.brace_token.surround(tokens, |tokens| {
|
||||
@@ -380,7 +401,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for FieldsUnnamed {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
@@ -389,7 +410,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Field {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(&self.attrs);
|
||||
|
||||
+27
-12
@@ -1,9 +1,15 @@
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::data::{Fields, FieldsNamed, Variant};
|
||||
use crate::generics::Generics;
|
||||
use crate::ident::Ident;
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::restriction::Visibility;
|
||||
use crate::token;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
ast_struct! {
|
||||
/// Data structure sent to a `proc_macro_derive` macro.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub struct DeriveInput {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub vis: Visibility,
|
||||
@@ -20,8 +26,8 @@ ast_enum! {
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub enum Data {
|
||||
Struct(DataStruct),
|
||||
Enum(DataEnum),
|
||||
@@ -31,7 +37,7 @@ ast_enum! {
|
||||
|
||||
ast_struct! {
|
||||
/// A struct input to a `proc_macro_derive` macro.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub struct DataStruct {
|
||||
pub struct_token: Token![struct],
|
||||
pub fields: Fields,
|
||||
@@ -41,7 +47,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An enum input to a `proc_macro_derive` macro.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub struct DataEnum {
|
||||
pub enum_token: Token![enum],
|
||||
pub brace_token: token::Brace,
|
||||
@@ -51,7 +57,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An untagged union input to a `proc_macro_derive` macro.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub struct DataUnion {
|
||||
pub union_token: Token![union],
|
||||
pub fields: FieldsNamed,
|
||||
@@ -60,10 +66,18 @@ ast_struct! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::attr::Attribute;
|
||||
use crate::data::{Fields, FieldsNamed, Variant};
|
||||
use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
|
||||
use crate::error::Result;
|
||||
use crate::generics::{Generics, WhereClause};
|
||||
use crate::ident::Ident;
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::restriction::Visibility;
|
||||
use crate::token;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for DeriveInput {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
@@ -193,13 +207,14 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::attr::FilterAttrs;
|
||||
use crate::data::Fields;
|
||||
use crate::derive::{Data, DeriveInput};
|
||||
use crate::print::TokensOrDefault;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for DeriveInput {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
for attr in self.attrs.outer() {
|
||||
|
||||
+13
-7
@@ -1,7 +1,13 @@
|
||||
//! Extensions to the parsing API with niche applicability.
|
||||
|
||||
use super::*;
|
||||
use crate::buffer::Cursor;
|
||||
use crate::error::Result;
|
||||
use crate::parse::{inner_unexpected, ParseBuffer, Unexpected};
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::Cell;
|
||||
use core::mem;
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Delimiter;
|
||||
|
||||
/// Extensions to the `ParseStream` API to support speculative parsing.
|
||||
pub trait Speculative {
|
||||
@@ -161,7 +167,7 @@ pub trait Speculative {
|
||||
impl<'a> Speculative for ParseBuffer<'a> {
|
||||
fn advance_to(&self, fork: &Self) {
|
||||
if !crate::buffer::same_scope(self.cursor(), fork.cursor()) {
|
||||
panic!("Fork was not derived from the advancing parse stream");
|
||||
panic!("fork was not derived from the advancing parse stream");
|
||||
}
|
||||
|
||||
let (self_unexp, self_sp) = inner_unexpected(self);
|
||||
@@ -169,17 +175,17 @@ impl<'a> Speculative for ParseBuffer<'a> {
|
||||
if !Rc::ptr_eq(&self_unexp, &fork_unexp) {
|
||||
match (fork_sp, self_sp) {
|
||||
// Unexpected set on the fork, but not on `self`, copy it over.
|
||||
(Some(span), None) => {
|
||||
self_unexp.set(Unexpected::Some(span));
|
||||
(Some((span, delimiter)), None) => {
|
||||
self_unexp.set(Unexpected::Some(span, delimiter));
|
||||
}
|
||||
// Unexpected unset. Use chain to propagate errors from fork.
|
||||
(None, None) => {
|
||||
fork_unexp.set(Unexpected::Chain(self_unexp));
|
||||
|
||||
// Ensure toplevel 'unexpected' tokens from the fork don't
|
||||
// bubble up the chain by replacing the root `unexpected`
|
||||
// propagate up the chain by replacing the root `unexpected`
|
||||
// pointer, only 'unexpected' tokens from existing group
|
||||
// parsers should bubble.
|
||||
// parsers should propagate.
|
||||
fork.unexpected
|
||||
.set(Some(Rc::new(Cell::new(Unexpected::None))));
|
||||
}
|
||||
@@ -206,7 +212,7 @@ 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 scope = span.close();
|
||||
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);
|
||||
|
||||
+10
-10
@@ -1,8 +1,8 @@
|
||||
use std::iter;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::option;
|
||||
use std::slice;
|
||||
use core::iter;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::option;
|
||||
use core::slice;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct NoDrop<T: ?Sized>(ManuallyDrop<T>);
|
||||
@@ -32,14 +32,14 @@ impl<T: ?Sized> DerefMut for NoDrop<T> {
|
||||
pub(crate) trait TrivialDrop {}
|
||||
|
||||
impl<T> TrivialDrop for iter::Empty<T> {}
|
||||
impl<'a, T> TrivialDrop for slice::Iter<'a, T> {}
|
||||
impl<'a, T> TrivialDrop for slice::IterMut<'a, T> {}
|
||||
impl<'a, T> TrivialDrop for option::IntoIter<&'a T> {}
|
||||
impl<'a, T> TrivialDrop for option::IntoIter<&'a mut T> {}
|
||||
impl<T> TrivialDrop for slice::Iter<'_, T> {}
|
||||
impl<T> TrivialDrop for slice::IterMut<'_, T> {}
|
||||
impl<T> TrivialDrop for option::IntoIter<&T> {}
|
||||
impl<T> TrivialDrop for option::IntoIter<&mut T> {}
|
||||
|
||||
#[test]
|
||||
fn test_needs_drop() {
|
||||
use std::mem::needs_drop;
|
||||
use core::mem::needs_drop;
|
||||
|
||||
struct NeedsDrop;
|
||||
|
||||
|
||||
+60
-54
@@ -1,17 +1,22 @@
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::buffer::Cursor;
|
||||
use crate::ext::{PunctExt as _, TokenStreamExt as _};
|
||||
use crate::thread::ThreadBound;
|
||||
#[cfg(feature = "parsing")]
|
||||
use alloc::format;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::slice;
|
||||
use proc_macro2::{
|
||||
Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree,
|
||||
};
|
||||
#[cfg(feature = "printing")]
|
||||
use quote::ToTokens;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::slice;
|
||||
use std::vec;
|
||||
|
||||
/// The result of a Syn parser.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
/// Error returned when a Syn parser cannot parse the input tokens.
|
||||
///
|
||||
@@ -22,7 +27,7 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||
/// [`compile_error!`] in the generated code. This produces a better diagnostic
|
||||
/// message than simply panicking the macro.
|
||||
///
|
||||
/// [`compile_error!`]: std::compile_error!
|
||||
/// [`compile_error!`]: core::compile_error!
|
||||
///
|
||||
/// When parsing macro input, the [`parse_macro_input!`] macro handles the
|
||||
/// conversion to `compile_error!` automatically.
|
||||
@@ -111,7 +116,7 @@ struct ErrorMessage {
|
||||
message: String,
|
||||
}
|
||||
|
||||
// Cannot use std::ops::Range<Span> because that does not implement Copy,
|
||||
// Cannot use core::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 {
|
||||
@@ -185,7 +190,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")))]
|
||||
#[cfg_attr(docsrs, 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());
|
||||
|
||||
@@ -220,18 +225,19 @@ impl Error {
|
||||
/// The [`parse_macro_input!`] macro provides a convenient way to invoke
|
||||
/// this method correctly in a procedural macro.
|
||||
///
|
||||
/// [`compile_error!`]: std::compile_error!
|
||||
/// [`compile_error!`]: core::compile_error!
|
||||
/// [`parse_macro_input!`]: crate::parse_macro_input!
|
||||
pub fn to_compile_error(&self) -> TokenStream {
|
||||
self.messages
|
||||
.iter()
|
||||
.map(ErrorMessage::to_compile_error)
|
||||
.collect()
|
||||
let mut tokens = TokenStream::new();
|
||||
for msg in &self.messages {
|
||||
ErrorMessage::to_compile_error(msg, &mut tokens);
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
/// Render the error as an invocation of [`compile_error!`].
|
||||
///
|
||||
/// [`compile_error!`]: std::compile_error!
|
||||
/// [`compile_error!`]: core::compile_error!
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -273,53 +279,52 @@ impl Error {
|
||||
}
|
||||
|
||||
impl ErrorMessage {
|
||||
fn to_compile_error(&self) -> TokenStream {
|
||||
fn to_compile_error(&self, tokens: &mut TokenStream) {
|
||||
let (start, end) = match self.span.get() {
|
||||
Some(range) => (range.start, range.end),
|
||||
None => (Span::call_site(), Span::call_site()),
|
||||
};
|
||||
|
||||
// ::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);
|
||||
punct.set_span(start);
|
||||
punct
|
||||
}),
|
||||
TokenTree::Group({
|
||||
let mut group = Group::new(Delimiter::Brace, {
|
||||
TokenStream::from_iter(vec![TokenTree::Literal({
|
||||
let mut string = Literal::string(&self.message);
|
||||
string.set_span(end);
|
||||
string
|
||||
})])
|
||||
});
|
||||
group.set_span(end);
|
||||
group
|
||||
}),
|
||||
])
|
||||
tokens.append(TokenTree::Punct(Punct::new_spanned(
|
||||
':',
|
||||
Spacing::Joint,
|
||||
start,
|
||||
)));
|
||||
tokens.append(TokenTree::Punct(Punct::new_spanned(
|
||||
':',
|
||||
Spacing::Alone,
|
||||
start,
|
||||
)));
|
||||
tokens.append(TokenTree::Ident(Ident::new("core", start)));
|
||||
tokens.append(TokenTree::Punct(Punct::new_spanned(
|
||||
':',
|
||||
Spacing::Joint,
|
||||
start,
|
||||
)));
|
||||
tokens.append(TokenTree::Punct(Punct::new_spanned(
|
||||
':',
|
||||
Spacing::Alone,
|
||||
start,
|
||||
)));
|
||||
tokens.append(TokenTree::Ident(Ident::new("compile_error", start)));
|
||||
tokens.append(TokenTree::Punct(Punct::new_spanned(
|
||||
'!',
|
||||
Spacing::Alone,
|
||||
start,
|
||||
)));
|
||||
tokens.append(TokenTree::Group({
|
||||
let mut group = Group::new(
|
||||
Delimiter::Brace,
|
||||
TokenStream::from({
|
||||
let mut string = Literal::string(&self.message);
|
||||
string.set_span(end);
|
||||
TokenTree::Literal(string)
|
||||
}),
|
||||
);
|
||||
group.set_span(end);
|
||||
group
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +405,7 @@ impl Clone for SpanRange {
|
||||
|
||||
impl Copy for SpanRange {}
|
||||
|
||||
// TODO: impl core::error::Error (requires Rust 1.81+)
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl From<LexError> for Error {
|
||||
|
||||
+14
-14
@@ -1,33 +1,33 @@
|
||||
#[doc(hidden)]
|
||||
pub use std::clone::Clone;
|
||||
pub use core::clone::Clone;
|
||||
#[doc(hidden)]
|
||||
pub use std::cmp::{Eq, PartialEq};
|
||||
pub use core::cmp::{Eq, PartialEq};
|
||||
#[doc(hidden)]
|
||||
pub use std::concat;
|
||||
pub use core::concat;
|
||||
#[doc(hidden)]
|
||||
pub use std::default::Default;
|
||||
pub use core::default::Default;
|
||||
#[doc(hidden)]
|
||||
pub use std::fmt::Debug;
|
||||
pub use core::fmt::Debug;
|
||||
#[doc(hidden)]
|
||||
pub use std::hash::{Hash, Hasher};
|
||||
pub use core::hash::{Hash, Hasher};
|
||||
#[doc(hidden)]
|
||||
pub use std::marker::Copy;
|
||||
pub use core::marker::Copy;
|
||||
#[doc(hidden)]
|
||||
pub use std::option::Option::{None, Some};
|
||||
pub use core::option::Option::{None, Some};
|
||||
#[doc(hidden)]
|
||||
pub use std::result::Result::{Err, Ok};
|
||||
pub use core::result::Result::{Err, Ok};
|
||||
#[doc(hidden)]
|
||||
pub use std::stringify;
|
||||
pub use core::stringify;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type Formatter<'a> = std::fmt::Formatter<'a>;
|
||||
pub type Formatter<'a> = core::fmt::Formatter<'a>;
|
||||
#[doc(hidden)]
|
||||
pub type FmtResult = std::fmt::Result;
|
||||
pub type FmtResult = core::fmt::Result;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type bool = std::primitive::bool;
|
||||
pub type bool = core::primitive::bool;
|
||||
#[doc(hidden)]
|
||||
pub type str = std::primitive::str;
|
||||
pub type str = core::primitive::str;
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[doc(hidden)]
|
||||
|
||||
+1422
-749
File diff suppressed because it is too large
Load Diff
+47
-2
@@ -1,11 +1,20 @@
|
||||
//! Extension traits to provide parsing methods on foreign types.
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::buffer::Cursor;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::error::Result;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::ParseStream;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::Peek;
|
||||
use crate::parse::{ParseStream, Result};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::sealed::lookahead;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::token::CustomToken;
|
||||
use proc_macro2::Ident;
|
||||
use alloc::string::ToString;
|
||||
use core::iter;
|
||||
use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream, TokenTree};
|
||||
|
||||
/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
|
||||
///
|
||||
@@ -42,6 +51,8 @@ pub trait IdentExt: Sized + private::Sealed {
|
||||
/// Ok(name)
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
fn parse_any(input: ParseStream) -> Result<Self>;
|
||||
|
||||
/// Peeks any identifier including keywords. Usage:
|
||||
@@ -49,6 +60,8 @@ pub trait IdentExt: Sized + private::Sealed {
|
||||
///
|
||||
/// This is different from `input.peek(Ident)` which only returns true in
|
||||
/// the case of an ident which is not a Rust keyword.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
#[allow(non_upper_case_globals)]
|
||||
const peek_any: private::PeekFn = private::PeekFn;
|
||||
|
||||
@@ -83,6 +96,7 @@ pub trait IdentExt: Sized + private::Sealed {
|
||||
}
|
||||
|
||||
impl IdentExt for Ident {
|
||||
#[cfg(feature = "parsing")]
|
||||
fn parse_any(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| match cursor.ident() {
|
||||
Some((ident, rest)) => Ok((ident, rest)),
|
||||
@@ -100,10 +114,12 @@ impl IdentExt for Ident {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Peek for private::PeekFn {
|
||||
type Token = private::IdentAny;
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl CustomToken for private::IdentAny {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
cursor.ident().is_some()
|
||||
@@ -114,8 +130,31 @@ impl CustomToken for private::IdentAny {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl lookahead::Sealed for private::PeekFn {}
|
||||
|
||||
pub(crate) trait TokenStreamExt {
|
||||
fn append(&mut self, token: TokenTree);
|
||||
}
|
||||
|
||||
impl TokenStreamExt for TokenStream {
|
||||
fn append(&mut self, token: TokenTree) {
|
||||
self.extend(iter::once(token));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait PunctExt {
|
||||
fn new_spanned(ch: char, spacing: Spacing, span: Span) -> Self;
|
||||
}
|
||||
|
||||
impl PunctExt for Punct {
|
||||
fn new_spanned(ch: char, spacing: Spacing, span: Span) -> Self {
|
||||
let mut punct = Punct::new(ch, spacing);
|
||||
punct.set_span(span);
|
||||
punct
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
use proc_macro2::Ident;
|
||||
|
||||
@@ -123,10 +162,16 @@ mod private {
|
||||
|
||||
impl Sealed for Ident {}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub struct PeekFn;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub struct IdentAny;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Copy for PeekFn {}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Clone for PeekFn {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
|
||||
+19
-16
@@ -1,10 +1,15 @@
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::item::Item;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
ast_struct! {
|
||||
/// A complete file of Rust source code.
|
||||
///
|
||||
/// Typically `File` objects are created with [`parse_file`].
|
||||
///
|
||||
/// [`parse_file`]: crate::parse_file
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Parse a Rust source file into a `syn::File` and print out a debug
|
||||
@@ -12,8 +17,7 @@ ast_struct! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::env;
|
||||
/// use std::fs::File;
|
||||
/// use std::io::Read;
|
||||
/// use std::fs;
|
||||
/// use std::process;
|
||||
///
|
||||
/// fn main() {
|
||||
@@ -31,12 +35,8 @@ ast_struct! {
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// let mut file = File::open(&filename).expect("Unable to open file");
|
||||
///
|
||||
/// let mut src = String::new();
|
||||
/// file.read_to_string(&mut src).expect("Unable to read file");
|
||||
///
|
||||
/// let syntax = syn::parse_file(&src).expect("Unable to parse file");
|
||||
/// let src = fs::read_to_string(&filename).expect("unable to read file");
|
||||
/// let syntax = syn::parse_file(&src).expect("unable to parse file");
|
||||
///
|
||||
/// // Debug impl is available if Syn is built with "extra-traits" feature.
|
||||
/// println!("{:#?}", syntax);
|
||||
@@ -77,7 +77,7 @@ ast_struct! {
|
||||
/// ),
|
||||
/// ...
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct File {
|
||||
pub shebang: Option<String>,
|
||||
pub attrs: Vec<Attribute>,
|
||||
@@ -87,10 +87,13 @@ ast_struct! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::attr::Attribute;
|
||||
use crate::error::Result;
|
||||
use crate::file::File;
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for File {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(File {
|
||||
@@ -110,12 +113,12 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::attr::FilterAttrs;
|
||||
use crate::file::File;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for File {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.inner());
|
||||
|
||||
+773
@@ -0,0 +1,773 @@
|
||||
use crate::classify;
|
||||
use crate::expr::Expr;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::expr::{
|
||||
ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield,
|
||||
};
|
||||
use crate::precedence::Precedence;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::ty::ReturnType;
|
||||
|
||||
pub(crate) struct FixupContext {
|
||||
#[cfg(feature = "full")]
|
||||
previous_operator: Precedence,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator: Precedence,
|
||||
|
||||
// Print expression such that it can be parsed back as a statement
|
||||
// consisting of the original expression.
|
||||
//
|
||||
// The effect of this is for binary operators in statement position to set
|
||||
// `leftmost_subexpression_in_stmt` when printing their left-hand operand.
|
||||
//
|
||||
// (match x {}) - 1; // match needs parens when LHS of binary operator
|
||||
//
|
||||
// match x {}; // not when its own statement
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
stmt: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// (match x {}) - 1; // subexpression needs parens
|
||||
//
|
||||
// let _ = match x {} - 1; // no parens
|
||||
//
|
||||
// There are 3 distinguishable contexts in which `print_expr` might be
|
||||
// called with the expression `$match` as its argument, where `$match`
|
||||
// represents an expression of kind `ExprKind::Match`:
|
||||
//
|
||||
// - stmt=false leftmost_subexpression_in_stmt=false
|
||||
//
|
||||
// Example: `let _ = $match - 1;`
|
||||
//
|
||||
// No parentheses required.
|
||||
//
|
||||
// - stmt=false leftmost_subexpression_in_stmt=true
|
||||
//
|
||||
// Example: `$match - 1;`
|
||||
//
|
||||
// Must parenthesize `($match)`, otherwise parsing back the output as a
|
||||
// statement would terminate the statement after the closing brace of
|
||||
// the match, parsing `-1;` as a separate statement.
|
||||
//
|
||||
// - stmt=true leftmost_subexpression_in_stmt=false
|
||||
//
|
||||
// Example: `$match;`
|
||||
//
|
||||
// No parentheses required.
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_stmt: bool,
|
||||
|
||||
// Print expression such that it can be parsed as a match arm.
|
||||
//
|
||||
// This is almost equivalent to `stmt`, but the grammar diverges a tiny bit
|
||||
// between statements and match arms when it comes to braced macro calls.
|
||||
// Macro calls with brace delimiter terminate a statement without a
|
||||
// semicolon, but do not terminate a match-arm without comma.
|
||||
//
|
||||
// m! {} - 1; // two statements: a macro call followed by -1 literal
|
||||
//
|
||||
// match () {
|
||||
// _ => m! {} - 1, // binary subtraction operator
|
||||
// }
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
match_arm: bool,
|
||||
|
||||
// This is almost equivalent to `leftmost_subexpression_in_stmt`, other than
|
||||
// for braced macro calls.
|
||||
//
|
||||
// If we have `m! {} - 1` as an expression, the leftmost subexpression
|
||||
// `m! {}` will need to be parenthesized in the statement case but not the
|
||||
// match-arm case.
|
||||
//
|
||||
// (m! {}) - 1; // subexpression needs parens
|
||||
//
|
||||
// match () {
|
||||
// _ => m! {} - 1, // no parens
|
||||
// }
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_match_arm: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// if let _ = (Struct {}) {} // needs parens
|
||||
//
|
||||
// match () {
|
||||
// () if let _ = Struct {} => {} // no parens
|
||||
// }
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
condition: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// if break Struct {} == (break) {} // needs parens
|
||||
//
|
||||
// if break break == Struct {} {} // no parens
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
rightmost_subexpression_in_condition: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// if break ({ x }).field + 1 {} needs parens
|
||||
//
|
||||
// if break 1 + { x }.field {} // no parens
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_optional_operand: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// let _ = (return) - 1; // without paren, this would return -1
|
||||
//
|
||||
// let _ = return + 1; // no paren because '+' cannot begin expr
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_begin_expr: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// let _ = 1 + return 1; // no parens if rightmost subexpression
|
||||
//
|
||||
// let _ = 1 + (return 1) + 1; // needs parens
|
||||
//
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_continue_expr: bool,
|
||||
|
||||
// This is the difference between:
|
||||
//
|
||||
// let _ = x as u8 + T;
|
||||
//
|
||||
// let _ = (x as u8) < T;
|
||||
//
|
||||
// Without parens, the latter would want to parse `u8<T...` as a type.
|
||||
next_operator_can_begin_generics: bool,
|
||||
}
|
||||
|
||||
impl FixupContext {
|
||||
/// The default amount of fixing is minimal fixing. Fixups should be turned
|
||||
/// on in a targeted fashion where needed.
|
||||
pub const NONE: Self = FixupContext {
|
||||
#[cfg(feature = "full")]
|
||||
previous_operator: Precedence::MIN,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator: Precedence::MIN,
|
||||
#[cfg(feature = "full")]
|
||||
stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
condition: false,
|
||||
#[cfg(feature = "full")]
|
||||
rightmost_subexpression_in_condition: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_optional_operand: false,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_begin_expr: false,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_continue_expr: false,
|
||||
next_operator_can_begin_generics: false,
|
||||
};
|
||||
|
||||
/// Create the initial fixup for printing an expression in statement
|
||||
/// position.
|
||||
#[cfg(feature = "full")]
|
||||
pub fn new_stmt() -> Self {
|
||||
FixupContext {
|
||||
stmt: true,
|
||||
..FixupContext::NONE
|
||||
}
|
||||
}
|
||||
|
||||
/// Create the initial fixup for printing an expression as the right-hand
|
||||
/// side of a match arm.
|
||||
#[cfg(feature = "full")]
|
||||
pub fn new_match_arm() -> Self {
|
||||
FixupContext {
|
||||
match_arm: true,
|
||||
..FixupContext::NONE
|
||||
}
|
||||
}
|
||||
|
||||
/// Create the initial fixup for printing an expression as the "condition"
|
||||
/// of an `if` or `while`. There are a few other positions which are
|
||||
/// grammatically equivalent and also use this, such as the iterator
|
||||
/// expression in `for` and the scrutinee in `match`.
|
||||
#[cfg(feature = "full")]
|
||||
pub fn new_condition() -> Self {
|
||||
FixupContext {
|
||||
condition: true,
|
||||
rightmost_subexpression_in_condition: true,
|
||||
..FixupContext::NONE
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing the
|
||||
/// leftmost subexpression of the current expression.
|
||||
///
|
||||
/// The leftmost subexpression is any subexpression that has the same first
|
||||
/// token as the current expression, but has a different last token.
|
||||
///
|
||||
/// For example in `$a + $b` and `$a.method()`, the subexpression `$a` is a
|
||||
/// leftmost subexpression.
|
||||
///
|
||||
/// Not every expression has a leftmost subexpression. For example neither
|
||||
/// `-$a` nor `[$a]` have one.
|
||||
pub fn leftmost_subexpression_with_operator(
|
||||
self,
|
||||
expr: &Expr,
|
||||
#[cfg(feature = "full")] next_operator_can_begin_expr: bool,
|
||||
next_operator_can_begin_generics: bool,
|
||||
#[cfg(feature = "full")] precedence: Precedence,
|
||||
) -> (Precedence, Self) {
|
||||
let fixup = FixupContext {
|
||||
#[cfg(feature = "full")]
|
||||
next_operator: precedence,
|
||||
#[cfg(feature = "full")]
|
||||
stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
|
||||
#[cfg(feature = "full")]
|
||||
match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_match_arm: self.match_arm
|
||||
|| self.leftmost_subexpression_in_match_arm,
|
||||
#[cfg(feature = "full")]
|
||||
rightmost_subexpression_in_condition: false,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_begin_expr,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_continue_expr: true,
|
||||
next_operator_can_begin_generics,
|
||||
..self
|
||||
};
|
||||
|
||||
(fixup.leftmost_subexpression_precedence(expr), fixup)
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing a
|
||||
/// leftmost subexpression followed by a `.` or `?` token, which confer
|
||||
/// different statement boundary rules compared to other leftmost
|
||||
/// subexpressions.
|
||||
pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) {
|
||||
let fixup = FixupContext {
|
||||
#[cfg(feature = "full")]
|
||||
next_operator: Precedence::Unambiguous,
|
||||
#[cfg(feature = "full")]
|
||||
stmt: self.stmt || self.leftmost_subexpression_in_stmt,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
rightmost_subexpression_in_condition: false,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_begin_expr: false,
|
||||
#[cfg(feature = "full")]
|
||||
next_operator_can_continue_expr: true,
|
||||
next_operator_can_begin_generics: false,
|
||||
..self
|
||||
};
|
||||
|
||||
(fixup.leftmost_subexpression_precedence(expr), fixup)
|
||||
}
|
||||
|
||||
fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
|
||||
#[cfg(feature = "full")]
|
||||
if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range {
|
||||
if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) {
|
||||
if scan_left(expr, self) {
|
||||
return Precedence::Unambiguous;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.precedence(expr)
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing the
|
||||
/// rightmost subexpression of the current expression.
|
||||
///
|
||||
/// The rightmost subexpression is any subexpression that has a different
|
||||
/// first token than the current expression, but has the same last token.
|
||||
///
|
||||
/// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
|
||||
/// rightmost subexpression.
|
||||
///
|
||||
/// Not every expression has a rightmost subexpression. For example neither
|
||||
/// `[$b]` nor `$a.f($b)` have one.
|
||||
pub fn rightmost_subexpression(
|
||||
self,
|
||||
expr: &Expr,
|
||||
#[cfg(feature = "full")] precedence: Precedence,
|
||||
) -> (Precedence, Self) {
|
||||
let fixup = self.rightmost_subexpression_fixup(
|
||||
#[cfg(feature = "full")]
|
||||
false,
|
||||
#[cfg(feature = "full")]
|
||||
false,
|
||||
#[cfg(feature = "full")]
|
||||
precedence,
|
||||
);
|
||||
(fixup.rightmost_subexpression_precedence(expr), fixup)
|
||||
}
|
||||
|
||||
pub fn rightmost_subexpression_fixup(
|
||||
self,
|
||||
#[cfg(feature = "full")] reset_allow_struct: bool,
|
||||
#[cfg(feature = "full")] optional_operand: bool,
|
||||
#[cfg(feature = "full")] precedence: Precedence,
|
||||
) -> Self {
|
||||
FixupContext {
|
||||
#[cfg(feature = "full")]
|
||||
previous_operator: precedence,
|
||||
#[cfg(feature = "full")]
|
||||
stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
#[cfg(feature = "full")]
|
||||
match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
#[cfg(feature = "full")]
|
||||
condition: self.condition && !reset_allow_struct,
|
||||
#[cfg(feature = "full")]
|
||||
leftmost_subexpression_in_optional_operand: self.condition && optional_operand,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence {
|
||||
let default_prec = self.precedence(expr);
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
if match self.previous_operator {
|
||||
Precedence::Assign | Precedence::Let | Precedence::Prefix => {
|
||||
default_prec < self.previous_operator
|
||||
}
|
||||
_ => default_prec <= self.previous_operator,
|
||||
} && match self.next_operator {
|
||||
Precedence::Range | Precedence::Or | Precedence::And => true,
|
||||
_ => !self.next_operator_can_begin_expr,
|
||||
} {
|
||||
if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0)
|
||||
{
|
||||
if scan_left(expr, self) {
|
||||
return Precedence::Prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default_prec
|
||||
}
|
||||
|
||||
/// Determine whether parentheses are needed around the given expression to
|
||||
/// head off the early termination of a statement or condition.
|
||||
#[cfg(feature = "full")]
|
||||
pub fn parenthesize(self, expr: &Expr) -> bool {
|
||||
(self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr))
|
||||
|| ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_)))
|
||||
|| (self.leftmost_subexpression_in_match_arm
|
||||
&& !classify::requires_comma_to_be_match_arm(expr))
|
||||
|| (self.condition && matches!(expr, Expr::Struct(_)))
|
||||
|| (self.rightmost_subexpression_in_condition
|
||||
&& matches!(
|
||||
expr,
|
||||
Expr::Return(ExprReturn { expr: None, .. })
|
||||
| Expr::Yield(ExprYield { expr: None, .. })
|
||||
))
|
||||
|| (self.rightmost_subexpression_in_condition
|
||||
&& !self.condition
|
||||
&& matches!(
|
||||
expr,
|
||||
Expr::Break(ExprBreak { expr: None, .. })
|
||||
| Expr::Path(_)
|
||||
| Expr::Range(ExprRange { end: None, .. })
|
||||
))
|
||||
|| (self.leftmost_subexpression_in_optional_operand
|
||||
&& matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none()))
|
||||
}
|
||||
|
||||
/// Determines the effective precedence of a subexpression. Some expressions
|
||||
/// have higher or lower precedence when adjacent to particular operators.
|
||||
fn precedence(self, expr: &Expr) -> Precedence {
|
||||
#[cfg(feature = "full")]
|
||||
if self.next_operator_can_begin_expr {
|
||||
// Decrease precedence of value-less jumps when followed by an
|
||||
// operator that would otherwise get interpreted as beginning a
|
||||
// value for the jump.
|
||||
if let Expr::Break(ExprBreak { expr: None, .. })
|
||||
| Expr::Return(ExprReturn { expr: None, .. })
|
||||
| Expr::Yield(ExprYield { expr: None, .. }) = expr
|
||||
{
|
||||
return Precedence::Jump;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
if !self.next_operator_can_continue_expr {
|
||||
match expr {
|
||||
// Increase precedence of expressions that extend to the end of
|
||||
// current statement or group.
|
||||
Expr::Break(_)
|
||||
| Expr::Closure(_)
|
||||
| Expr::Let(_)
|
||||
| Expr::Return(_)
|
||||
| Expr::Yield(_) => {
|
||||
return Precedence::Prefix;
|
||||
}
|
||||
Expr::Range(e) if e.start.is_none() => return Precedence::Prefix,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.next_operator_can_begin_generics {
|
||||
if let Expr::Cast(cast) = expr {
|
||||
if classify::trailing_unparameterized_path(&cast.ty) {
|
||||
return Precedence::MIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Precedence::of(expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for FixupContext {}
|
||||
|
||||
impl Clone for FixupContext {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
enum Scan {
|
||||
Fail,
|
||||
Bailout,
|
||||
Consume,
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl Copy for Scan {}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl Clone for Scan {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl PartialEq for Scan {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as u8 == *other as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
fn scan_left(expr: &Expr, fixup: FixupContext) -> bool {
|
||||
match expr {
|
||||
Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign,
|
||||
Expr::Binary(e) => match Precedence::of_binop(&e.op) {
|
||||
Precedence::Assign => fixup.previous_operator <= Precedence::Assign,
|
||||
binop_prec => fixup.previous_operator < binop_prec,
|
||||
},
|
||||
Expr::Cast(_) => fixup.previous_operator < Precedence::Cast,
|
||||
Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
fn scan_right(
|
||||
expr: &Expr,
|
||||
fixup: FixupContext,
|
||||
precedence: Precedence,
|
||||
fail_offset: u8,
|
||||
bailout_offset: u8,
|
||||
) -> Scan {
|
||||
let consume_by_precedence = if match precedence {
|
||||
Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator,
|
||||
_ => precedence < fixup.next_operator,
|
||||
} || fixup.next_operator == Precedence::MIN
|
||||
{
|
||||
Scan::Consume
|
||||
} else {
|
||||
Scan::Bailout
|
||||
};
|
||||
if fixup.parenthesize(expr) {
|
||||
return consume_by_precedence;
|
||||
}
|
||||
match expr {
|
||||
Expr::Assign(e) if e.attrs.is_empty() => {
|
||||
if match fixup.next_operator {
|
||||
Precedence::Unambiguous => fail_offset >= 2,
|
||||
_ => bailout_offset >= 1,
|
||||
} {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign);
|
||||
let scan = scan_right(
|
||||
&e.right,
|
||||
right_fixup,
|
||||
Precedence::Assign,
|
||||
match fixup.next_operator {
|
||||
Precedence::Unambiguous => fail_offset,
|
||||
_ => 1,
|
||||
},
|
||||
1,
|
||||
);
|
||||
if let Scan::Bailout | Scan::Consume = scan {
|
||||
Scan::Consume
|
||||
} else if let Precedence::Unambiguous = fixup.next_operator {
|
||||
Scan::Fail
|
||||
} else {
|
||||
Scan::Bailout
|
||||
}
|
||||
}
|
||||
Expr::Binary(e) if e.attrs.is_empty() => {
|
||||
if match fixup.next_operator {
|
||||
Precedence::Unambiguous => {
|
||||
fail_offset >= 2
|
||||
&& (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
|
||||
}
|
||||
_ => bailout_offset >= 1,
|
||||
} {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let binop_prec = Precedence::of_binop(&e.op);
|
||||
if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec);
|
||||
let scan = scan_right(
|
||||
&e.right,
|
||||
right_fixup,
|
||||
binop_prec,
|
||||
match fixup.next_operator {
|
||||
Precedence::Unambiguous => fail_offset,
|
||||
_ => 1,
|
||||
},
|
||||
consume_by_precedence as u8 - Scan::Bailout as u8,
|
||||
);
|
||||
match scan {
|
||||
Scan::Fail => {}
|
||||
Scan::Bailout => return consume_by_precedence,
|
||||
Scan::Consume => return Scan::Consume,
|
||||
}
|
||||
let right_needs_group = binop_prec != Precedence::Assign
|
||||
&& right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec;
|
||||
if right_needs_group {
|
||||
consume_by_precedence
|
||||
} else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
|
||||
Scan::Fail
|
||||
} else {
|
||||
Scan::Bailout
|
||||
}
|
||||
}
|
||||
Expr::RawAddr(ExprRawAddr { expr, .. })
|
||||
| Expr::Reference(ExprReference { expr, .. })
|
||||
| Expr::Unary(ExprUnary { expr, .. }) => {
|
||||
if match fixup.next_operator {
|
||||
Precedence::Unambiguous => {
|
||||
fail_offset >= 2
|
||||
&& (consume_by_precedence == Scan::Consume || bailout_offset >= 1)
|
||||
}
|
||||
_ => bailout_offset >= 1,
|
||||
} {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix);
|
||||
let scan = scan_right(
|
||||
expr,
|
||||
right_fixup,
|
||||
precedence,
|
||||
match fixup.next_operator {
|
||||
Precedence::Unambiguous => fail_offset,
|
||||
_ => 1,
|
||||
},
|
||||
consume_by_precedence as u8 - Scan::Bailout as u8,
|
||||
);
|
||||
match scan {
|
||||
Scan::Fail => {}
|
||||
Scan::Bailout => return consume_by_precedence,
|
||||
Scan::Consume => return Scan::Consume,
|
||||
}
|
||||
if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix {
|
||||
consume_by_precedence
|
||||
} else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) {
|
||||
Scan::Fail
|
||||
} else {
|
||||
Scan::Bailout
|
||||
}
|
||||
}
|
||||
Expr::Range(e) if e.attrs.is_empty() => match &e.end {
|
||||
Some(end) => {
|
||||
if fail_offset >= 2 {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup =
|
||||
fixup.rightmost_subexpression_fixup(false, true, Precedence::Range);
|
||||
let scan = scan_right(
|
||||
end,
|
||||
right_fixup,
|
||||
Precedence::Range,
|
||||
fail_offset,
|
||||
match fixup.next_operator {
|
||||
Precedence::Assign | Precedence::Range => 0,
|
||||
_ => 1,
|
||||
},
|
||||
);
|
||||
if match (scan, fixup.next_operator) {
|
||||
(Scan::Fail, _) => false,
|
||||
(Scan::Bailout, Precedence::Assign | Precedence::Range) => false,
|
||||
(Scan::Bailout | Scan::Consume, _) => true,
|
||||
} {
|
||||
return Scan::Consume;
|
||||
}
|
||||
if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range {
|
||||
Scan::Consume
|
||||
} else {
|
||||
Scan::Fail
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if fixup.next_operator_can_begin_expr {
|
||||
Scan::Consume
|
||||
} else {
|
||||
Scan::Fail
|
||||
}
|
||||
}
|
||||
},
|
||||
Expr::Break(e) => match &e.expr {
|
||||
Some(value) => {
|
||||
if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump);
|
||||
match scan_right(value, right_fixup, Precedence::Jump, 1, 1) {
|
||||
Scan::Fail => Scan::Bailout,
|
||||
Scan::Bailout | Scan::Consume => Scan::Consume,
|
||||
}
|
||||
}
|
||||
None => match fixup.next_operator {
|
||||
Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
|
||||
_ => Scan::Consume,
|
||||
},
|
||||
},
|
||||
Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr {
|
||||
Some(e) => {
|
||||
if bailout_offset >= 1 {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup =
|
||||
fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump);
|
||||
match scan_right(e, right_fixup, Precedence::Jump, 1, 1) {
|
||||
Scan::Fail => Scan::Bailout,
|
||||
Scan::Bailout | Scan::Consume => Scan::Consume,
|
||||
}
|
||||
}
|
||||
None => match fixup.next_operator {
|
||||
Precedence::Assign if precedence > Precedence::Assign => Scan::Fail,
|
||||
_ => Scan::Consume,
|
||||
},
|
||||
},
|
||||
Expr::Closure(e) => {
|
||||
if matches!(e.output, ReturnType::Default)
|
||||
|| matches!(&*e.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none())
|
||||
{
|
||||
if bailout_offset >= 1 {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup =
|
||||
fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump);
|
||||
match scan_right(&e.body, right_fixup, Precedence::Jump, 1, 1) {
|
||||
Scan::Fail => Scan::Bailout,
|
||||
Scan::Bailout | Scan::Consume => Scan::Consume,
|
||||
}
|
||||
} else {
|
||||
Scan::Consume
|
||||
}
|
||||
}
|
||||
Expr::Let(e) => {
|
||||
if bailout_offset >= 1 {
|
||||
return Scan::Consume;
|
||||
}
|
||||
let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let);
|
||||
let scan = scan_right(
|
||||
&e.expr,
|
||||
right_fixup,
|
||||
Precedence::Let,
|
||||
1,
|
||||
if fixup.next_operator < Precedence::Let {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
},
|
||||
);
|
||||
match scan {
|
||||
Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => {
|
||||
return Scan::Bailout;
|
||||
}
|
||||
Scan::Consume => return Scan::Consume,
|
||||
_ => {}
|
||||
}
|
||||
if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let {
|
||||
Scan::Consume
|
||||
} else if let Scan::Fail = scan {
|
||||
Scan::Bailout
|
||||
} else {
|
||||
Scan::Consume
|
||||
}
|
||||
}
|
||||
Expr::Array(_)
|
||||
| Expr::Assign(_)
|
||||
| Expr::Async(_)
|
||||
| Expr::Await(_)
|
||||
| Expr::Binary(_)
|
||||
| Expr::Block(_)
|
||||
| Expr::Call(_)
|
||||
| Expr::Cast(_)
|
||||
| Expr::Const(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Field(_)
|
||||
| Expr::ForLoop(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::If(_)
|
||||
| Expr::Index(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::Loop(_)
|
||||
| Expr::Macro(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::MethodCall(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Range(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::Try(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::Unsafe(_)
|
||||
| Expr::Verbatim(_)
|
||||
| Expr::While(_) => match fixup.next_operator {
|
||||
Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail,
|
||||
_ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => {
|
||||
Scan::Fail
|
||||
}
|
||||
_ => consume_by_precedence,
|
||||
},
|
||||
}
|
||||
}
|
||||
Generated
+750
-664
File diff suppressed because it is too large
Load Diff
Generated
+1830
-1644
File diff suppressed because it is too large
Load Diff
Generated
+1093
-933
File diff suppressed because it is too large
Load Diff
Generated
+1714
-1267
File diff suppressed because it is too large
Load Diff
Generated
+619
-545
File diff suppressed because it is too large
Load Diff
Generated
+737
@@ -0,0 +1,737 @@
|
||||
a.struct[title="struct syn::token::Abstract"],
|
||||
a.struct[title="struct syn::token::And"],
|
||||
a.struct[title="struct syn::token::AndAnd"],
|
||||
a.struct[title="struct syn::token::AndEq"],
|
||||
a.struct[title="struct syn::token::As"],
|
||||
a.struct[title="struct syn::token::Async"],
|
||||
a.struct[title="struct syn::token::At"],
|
||||
a.struct[title="struct syn::token::Auto"],
|
||||
a.struct[title="struct syn::token::Await"],
|
||||
a.struct[title="struct syn::token::Become"],
|
||||
a.struct[title="struct syn::token::Box"],
|
||||
a.struct[title="struct syn::token::Break"],
|
||||
a.struct[title="struct syn::token::Caret"],
|
||||
a.struct[title="struct syn::token::CaretEq"],
|
||||
a.struct[title="struct syn::token::Colon"],
|
||||
a.struct[title="struct syn::token::Comma"],
|
||||
a.struct[title="struct syn::token::Const"],
|
||||
a.struct[title="struct syn::token::Continue"],
|
||||
a.struct[title="struct syn::token::Crate"],
|
||||
a.struct[title="struct syn::token::Default"],
|
||||
a.struct[title="struct syn::token::Do"],
|
||||
a.struct[title="struct syn::token::Dollar"],
|
||||
a.struct[title="struct syn::token::Dot"],
|
||||
a.struct[title="struct syn::token::DotDot"],
|
||||
a.struct[title="struct syn::token::DotDotDot"],
|
||||
a.struct[title="struct syn::token::DotDotEq"],
|
||||
a.struct[title="struct syn::token::Dyn"],
|
||||
a.struct[title="struct syn::token::Else"],
|
||||
a.struct[title="struct syn::token::Enum"],
|
||||
a.struct[title="struct syn::token::Eq"],
|
||||
a.struct[title="struct syn::token::EqEq"],
|
||||
a.struct[title="struct syn::token::Extern"],
|
||||
a.struct[title="struct syn::token::FatArrow"],
|
||||
a.struct[title="struct syn::token::Final"],
|
||||
a.struct[title="struct syn::token::Fn"],
|
||||
a.struct[title="struct syn::token::For"],
|
||||
a.struct[title="struct syn::token::Ge"],
|
||||
a.struct[title="struct syn::token::Gt"],
|
||||
a.struct[title="struct syn::token::If"],
|
||||
a.struct[title="struct syn::token::Impl"],
|
||||
a.struct[title="struct syn::token::In"],
|
||||
a.struct[title="struct syn::token::LArrow"],
|
||||
a.struct[title="struct syn::token::Le"],
|
||||
a.struct[title="struct syn::token::Let"],
|
||||
a.struct[title="struct syn::token::Loop"],
|
||||
a.struct[title="struct syn::token::Lt"],
|
||||
a.struct[title="struct syn::token::Macro"],
|
||||
a.struct[title="struct syn::token::Match"],
|
||||
a.struct[title="struct syn::token::Minus"],
|
||||
a.struct[title="struct syn::token::MinusEq"],
|
||||
a.struct[title="struct syn::token::Mod"],
|
||||
a.struct[title="struct syn::token::Move"],
|
||||
a.struct[title="struct syn::token::Mut"],
|
||||
a.struct[title="struct syn::token::Ne"],
|
||||
a.struct[title="struct syn::token::Not"],
|
||||
a.struct[title="struct syn::token::Or"],
|
||||
a.struct[title="struct syn::token::OrEq"],
|
||||
a.struct[title="struct syn::token::OrOr"],
|
||||
a.struct[title="struct syn::token::Override"],
|
||||
a.struct[title="struct syn::token::PathSep"],
|
||||
a.struct[title="struct syn::token::Percent"],
|
||||
a.struct[title="struct syn::token::PercentEq"],
|
||||
a.struct[title="struct syn::token::Plus"],
|
||||
a.struct[title="struct syn::token::PlusEq"],
|
||||
a.struct[title="struct syn::token::Pound"],
|
||||
a.struct[title="struct syn::token::Priv"],
|
||||
a.struct[title="struct syn::token::Pub"],
|
||||
a.struct[title="struct syn::token::Question"],
|
||||
a.struct[title="struct syn::token::RArrow"],
|
||||
a.struct[title="struct syn::token::Raw"],
|
||||
a.struct[title="struct syn::token::Ref"],
|
||||
a.struct[title="struct syn::token::Return"],
|
||||
a.struct[title="struct syn::token::SelfType"],
|
||||
a.struct[title="struct syn::token::SelfValue"],
|
||||
a.struct[title="struct syn::token::Semi"],
|
||||
a.struct[title="struct syn::token::Shl"],
|
||||
a.struct[title="struct syn::token::ShlEq"],
|
||||
a.struct[title="struct syn::token::Shr"],
|
||||
a.struct[title="struct syn::token::ShrEq"],
|
||||
a.struct[title="struct syn::token::Slash"],
|
||||
a.struct[title="struct syn::token::SlashEq"],
|
||||
a.struct[title="struct syn::token::Star"],
|
||||
a.struct[title="struct syn::token::StarEq"],
|
||||
a.struct[title="struct syn::token::Static"],
|
||||
a.struct[title="struct syn::token::Struct"],
|
||||
a.struct[title="struct syn::token::Super"],
|
||||
a.struct[title="struct syn::token::Tilde"],
|
||||
a.struct[title="struct syn::token::Trait"],
|
||||
a.struct[title="struct syn::token::Try"],
|
||||
a.struct[title="struct syn::token::Type"],
|
||||
a.struct[title="struct syn::token::Typeof"],
|
||||
a.struct[title="struct syn::token::Underscore"],
|
||||
a.struct[title="struct syn::token::Union"],
|
||||
a.struct[title="struct syn::token::Unsafe"],
|
||||
a.struct[title="struct syn::token::Unsized"],
|
||||
a.struct[title="struct syn::token::Use"],
|
||||
a.struct[title="struct syn::token::Virtual"],
|
||||
a.struct[title="struct syn::token::Where"],
|
||||
a.struct[title="struct syn::token::While"],
|
||||
a.struct[title="struct syn::token::Yield"] {
|
||||
display: inline-block;
|
||||
color: transparent;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Abstract"]::before,
|
||||
a.struct[title="struct syn::token::And"]::before,
|
||||
a.struct[title="struct syn::token::AndAnd"]::before,
|
||||
a.struct[title="struct syn::token::AndEq"]::before,
|
||||
a.struct[title="struct syn::token::As"]::before,
|
||||
a.struct[title="struct syn::token::Async"]::before,
|
||||
a.struct[title="struct syn::token::At"]::before,
|
||||
a.struct[title="struct syn::token::Auto"]::before,
|
||||
a.struct[title="struct syn::token::Await"]::before,
|
||||
a.struct[title="struct syn::token::Become"]::before,
|
||||
a.struct[title="struct syn::token::Box"]::before,
|
||||
a.struct[title="struct syn::token::Break"]::before,
|
||||
a.struct[title="struct syn::token::Caret"]::before,
|
||||
a.struct[title="struct syn::token::CaretEq"]::before,
|
||||
a.struct[title="struct syn::token::Colon"]::before,
|
||||
a.struct[title="struct syn::token::Comma"]::before,
|
||||
a.struct[title="struct syn::token::Const"]::before,
|
||||
a.struct[title="struct syn::token::Continue"]::before,
|
||||
a.struct[title="struct syn::token::Crate"]::before,
|
||||
a.struct[title="struct syn::token::Default"]::before,
|
||||
a.struct[title="struct syn::token::Do"]::before,
|
||||
a.struct[title="struct syn::token::Dollar"]::before,
|
||||
a.struct[title="struct syn::token::Dot"]::before,
|
||||
a.struct[title="struct syn::token::DotDot"]::before,
|
||||
a.struct[title="struct syn::token::DotDotDot"]::before,
|
||||
a.struct[title="struct syn::token::DotDotEq"]::before,
|
||||
a.struct[title="struct syn::token::Dyn"]::before,
|
||||
a.struct[title="struct syn::token::Else"]::before,
|
||||
a.struct[title="struct syn::token::Enum"]::before,
|
||||
a.struct[title="struct syn::token::Eq"]::before,
|
||||
a.struct[title="struct syn::token::EqEq"]::before,
|
||||
a.struct[title="struct syn::token::Extern"]::before,
|
||||
a.struct[title="struct syn::token::FatArrow"]::before,
|
||||
a.struct[title="struct syn::token::Final"]::before,
|
||||
a.struct[title="struct syn::token::Fn"]::before,
|
||||
a.struct[title="struct syn::token::For"]::before,
|
||||
a.struct[title="struct syn::token::Ge"]::before,
|
||||
a.struct[title="struct syn::token::Gt"]::before,
|
||||
a.struct[title="struct syn::token::If"]::before,
|
||||
a.struct[title="struct syn::token::Impl"]::before,
|
||||
a.struct[title="struct syn::token::In"]::before,
|
||||
a.struct[title="struct syn::token::LArrow"]::before,
|
||||
a.struct[title="struct syn::token::Le"]::before,
|
||||
a.struct[title="struct syn::token::Let"]::before,
|
||||
a.struct[title="struct syn::token::Loop"]::before,
|
||||
a.struct[title="struct syn::token::Lt"]::before,
|
||||
a.struct[title="struct syn::token::Macro"]::before,
|
||||
a.struct[title="struct syn::token::Match"]::before,
|
||||
a.struct[title="struct syn::token::Minus"]::before,
|
||||
a.struct[title="struct syn::token::MinusEq"]::before,
|
||||
a.struct[title="struct syn::token::Mod"]::before,
|
||||
a.struct[title="struct syn::token::Move"]::before,
|
||||
a.struct[title="struct syn::token::Mut"]::before,
|
||||
a.struct[title="struct syn::token::Ne"]::before,
|
||||
a.struct[title="struct syn::token::Not"]::before,
|
||||
a.struct[title="struct syn::token::Or"]::before,
|
||||
a.struct[title="struct syn::token::OrEq"]::before,
|
||||
a.struct[title="struct syn::token::OrOr"]::before,
|
||||
a.struct[title="struct syn::token::Override"]::before,
|
||||
a.struct[title="struct syn::token::PathSep"]::before,
|
||||
a.struct[title="struct syn::token::Percent"]::before,
|
||||
a.struct[title="struct syn::token::PercentEq"]::before,
|
||||
a.struct[title="struct syn::token::Plus"]::before,
|
||||
a.struct[title="struct syn::token::PlusEq"]::before,
|
||||
a.struct[title="struct syn::token::Pound"]::before,
|
||||
a.struct[title="struct syn::token::Priv"]::before,
|
||||
a.struct[title="struct syn::token::Pub"]::before,
|
||||
a.struct[title="struct syn::token::Question"]::before,
|
||||
a.struct[title="struct syn::token::RArrow"]::before,
|
||||
a.struct[title="struct syn::token::Raw"]::before,
|
||||
a.struct[title="struct syn::token::Ref"]::before,
|
||||
a.struct[title="struct syn::token::Return"]::before,
|
||||
a.struct[title="struct syn::token::SelfType"]::before,
|
||||
a.struct[title="struct syn::token::SelfValue"]::before,
|
||||
a.struct[title="struct syn::token::Semi"]::before,
|
||||
a.struct[title="struct syn::token::Shl"]::before,
|
||||
a.struct[title="struct syn::token::ShlEq"]::before,
|
||||
a.struct[title="struct syn::token::Shr"]::before,
|
||||
a.struct[title="struct syn::token::ShrEq"]::before,
|
||||
a.struct[title="struct syn::token::Slash"]::before,
|
||||
a.struct[title="struct syn::token::SlashEq"]::before,
|
||||
a.struct[title="struct syn::token::Star"]::before,
|
||||
a.struct[title="struct syn::token::StarEq"]::before,
|
||||
a.struct[title="struct syn::token::Static"]::before,
|
||||
a.struct[title="struct syn::token::Struct"]::before,
|
||||
a.struct[title="struct syn::token::Super"]::before,
|
||||
a.struct[title="struct syn::token::Tilde"]::before,
|
||||
a.struct[title="struct syn::token::Trait"]::before,
|
||||
a.struct[title="struct syn::token::Try"]::before,
|
||||
a.struct[title="struct syn::token::Type"]::before,
|
||||
a.struct[title="struct syn::token::Typeof"]::before,
|
||||
a.struct[title="struct syn::token::Underscore"]::before,
|
||||
a.struct[title="struct syn::token::Union"]::before,
|
||||
a.struct[title="struct syn::token::Unsafe"]::before,
|
||||
a.struct[title="struct syn::token::Unsized"]::before,
|
||||
a.struct[title="struct syn::token::Use"]::before,
|
||||
a.struct[title="struct syn::token::Virtual"]::before,
|
||||
a.struct[title="struct syn::token::Where"]::before,
|
||||
a.struct[title="struct syn::token::While"]::before,
|
||||
a.struct[title="struct syn::token::Yield"]::before {
|
||||
display: inline-block;
|
||||
color: var(--type-link-color);
|
||||
width: 0;
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Abstract"]::before {
|
||||
content: "Token![abstract]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::And"]::before {
|
||||
content: "Token![&]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::AndAnd"]::before {
|
||||
content: "Token![&&]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::AndEq"]::before {
|
||||
content: "Token![&=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::As"]::before {
|
||||
content: "Token![as]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Async"]::before {
|
||||
content: "Token![async]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::At"]::before {
|
||||
content: "Token![@]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Auto"]::before {
|
||||
content: "Token![auto]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Await"]::before {
|
||||
content: "Token![await]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Become"]::before {
|
||||
content: "Token![become]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Box"]::before {
|
||||
content: "Token![box]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Break"]::before {
|
||||
content: "Token![break]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Caret"]::before {
|
||||
content: "Token![^]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::CaretEq"]::before {
|
||||
content: "Token![^=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Colon"]::before {
|
||||
content: "Token![:]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Comma"]::before {
|
||||
content: "Token![,]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Const"]::before {
|
||||
content: "Token![const]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Continue"]::before {
|
||||
content: "Token![continue]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Crate"]::before {
|
||||
content: "Token![crate]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Default"]::before {
|
||||
content: "Token![default]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Do"]::before {
|
||||
content: "Token![do]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Dollar"]::before {
|
||||
content: "Token![$]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Dot"]::before {
|
||||
content: "Token![.]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::DotDot"]::before {
|
||||
content: "Token![..]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::DotDotDot"]::before {
|
||||
content: "Token![...]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::DotDotEq"]::before {
|
||||
content: "Token![..=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Dyn"]::before {
|
||||
content: "Token![dyn]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Else"]::before {
|
||||
content: "Token![else]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Enum"]::before {
|
||||
content: "Token![enum]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Eq"]::before {
|
||||
content: "Token![=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::EqEq"]::before {
|
||||
content: "Token![==]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Extern"]::before {
|
||||
content: "Token![extern]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::FatArrow"]::before {
|
||||
content: "Token![=>]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Final"]::before {
|
||||
content: "Token![final]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Fn"]::before {
|
||||
content: "Token![fn]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::For"]::before {
|
||||
content: "Token![for]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Ge"]::before {
|
||||
content: "Token![>=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Gt"]::before {
|
||||
content: "Token![>]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::If"]::before {
|
||||
content: "Token![if]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Impl"]::before {
|
||||
content: "Token![impl]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::In"]::before {
|
||||
content: "Token![in]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::LArrow"]::before {
|
||||
content: "Token![<-]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Le"]::before {
|
||||
content: "Token![<=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Let"]::before {
|
||||
content: "Token![let]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Loop"]::before {
|
||||
content: "Token![loop]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Lt"]::before {
|
||||
content: "Token![<]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Macro"]::before {
|
||||
content: "Token![macro]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Match"]::before {
|
||||
content: "Token![match]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Minus"]::before {
|
||||
content: "Token![-]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::MinusEq"]::before {
|
||||
content: "Token![-=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Mod"]::before {
|
||||
content: "Token![mod]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Move"]::before {
|
||||
content: "Token![move]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Mut"]::before {
|
||||
content: "Token![mut]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Ne"]::before {
|
||||
content: "Token![!=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Not"]::before {
|
||||
content: "Token![!]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Or"]::before {
|
||||
content: "Token![|]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::OrEq"]::before {
|
||||
content: "Token![|=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::OrOr"]::before {
|
||||
content: "Token![||]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Override"]::before {
|
||||
content: "Token![override]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::PathSep"]::before {
|
||||
content: "Token![::]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Percent"]::before {
|
||||
content: "Token![%]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::PercentEq"]::before {
|
||||
content: "Token![%=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Plus"]::before {
|
||||
content: "Token![+]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::PlusEq"]::before {
|
||||
content: "Token![+=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Pound"]::before {
|
||||
content: "Token![#]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Priv"]::before {
|
||||
content: "Token![priv]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Pub"]::before {
|
||||
content: "Token![pub]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Question"]::before {
|
||||
content: "Token![?]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::RArrow"]::before {
|
||||
content: "Token![->]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Raw"]::before {
|
||||
content: "Token![raw]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Ref"]::before {
|
||||
content: "Token![ref]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Return"]::before {
|
||||
content: "Token![return]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::SelfType"]::before {
|
||||
content: "Token![Self]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::SelfValue"]::before {
|
||||
content: "Token![self]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Semi"]::before {
|
||||
content: "Token![;]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Shl"]::before {
|
||||
content: "Token![<<]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::ShlEq"]::before {
|
||||
content: "Token![<<=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Shr"]::before {
|
||||
content: "Token![>>]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::ShrEq"]::before {
|
||||
content: "Token![>>=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Slash"]::before {
|
||||
content: "Token![/]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::SlashEq"]::before {
|
||||
content: "Token![/=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Star"]::before {
|
||||
content: "Token![*]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::StarEq"]::before {
|
||||
content: "Token![*=]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Static"]::before {
|
||||
content: "Token![static]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Struct"]::before {
|
||||
content: "Token![struct]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Super"]::before {
|
||||
content: "Token![super]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Tilde"]::before {
|
||||
content: "Token![~]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Trait"]::before {
|
||||
content: "Token![trait]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Try"]::before {
|
||||
content: "Token![try]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Type"]::before {
|
||||
content: "Token![type]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Typeof"]::before {
|
||||
content: "Token![typeof]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Underscore"]::before {
|
||||
content: "Token![_]";
|
||||
font-size: calc(100% * 10 / 9);
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Union"]::before {
|
||||
content: "Token![union]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Unsafe"]::before {
|
||||
content: "Token![unsafe]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Unsized"]::before {
|
||||
content: "Token![unsized]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Use"]::before {
|
||||
content: "Token![use]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Virtual"]::before {
|
||||
content: "Token![virtual]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Where"]::before {
|
||||
content: "Token![where]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::While"]::before {
|
||||
content: "Token![while]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Yield"]::before {
|
||||
content: "Token![yield]";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Underscore"] {
|
||||
font-size: calc(100% * 9 / 10);
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::PercentEq"]::after,
|
||||
a.struct[title="struct syn::token::Question"]::after {
|
||||
content: ".";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::DotDotDot"]::after,
|
||||
a.struct[title="struct syn::token::FatArrow"]::after,
|
||||
a.struct[title="struct syn::token::Percent"]::after {
|
||||
content: "..";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::CaretEq"]::after,
|
||||
a.struct[title="struct syn::token::Dollar"]::after,
|
||||
a.struct[title="struct syn::token::DotDotEq"]::after,
|
||||
a.struct[title="struct syn::token::MinusEq"]::after,
|
||||
a.struct[title="struct syn::token::PathSep"]::after,
|
||||
a.struct[title="struct syn::token::SelfValue"]::after,
|
||||
a.struct[title="struct syn::token::SlashEq"]::after {
|
||||
content: "...";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::AndAnd"]::after,
|
||||
a.struct[title="struct syn::token::Caret"]::after,
|
||||
a.struct[title="struct syn::token::Colon"]::after,
|
||||
a.struct[title="struct syn::token::Comma"]::after,
|
||||
a.struct[title="struct syn::token::DotDot"]::after,
|
||||
a.struct[title="struct syn::token::LArrow"]::after,
|
||||
a.struct[title="struct syn::token::Minus"]::after,
|
||||
a.struct[title="struct syn::token::PlusEq"]::after,
|
||||
a.struct[title="struct syn::token::Pound"]::after,
|
||||
a.struct[title="struct syn::token::RArrow"]::after,
|
||||
a.struct[title="struct syn::token::SelfType"]::after,
|
||||
a.struct[title="struct syn::token::Slash"]::after,
|
||||
a.struct[title="struct syn::token::StarEq"]::after,
|
||||
a.struct[title="struct syn::token::Tilde"]::after {
|
||||
content: "....";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::AndEq"]::after,
|
||||
a.struct[title="struct syn::token::Plus"]::after,
|
||||
a.struct[title="struct syn::token::Semi"]::after,
|
||||
a.struct[title="struct syn::token::Star"]::after {
|
||||
content: ".....";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::And"]::after,
|
||||
a.struct[title="struct syn::token::Dot"]::after,
|
||||
a.struct[title="struct syn::token::EqEq"]::after,
|
||||
a.struct[title="struct syn::token::Not"]::after,
|
||||
a.struct[title="struct syn::token::OrEq"]::after,
|
||||
a.struct[title="struct syn::token::OrOr"]::after,
|
||||
a.struct[title="struct syn::token::ShlEq"]::after,
|
||||
a.struct[title="struct syn::token::ShrEq"]::after {
|
||||
content: "......";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::At"]::after,
|
||||
a.struct[title="struct syn::token::Eq"]::after,
|
||||
a.struct[title="struct syn::token::Gt"]::after,
|
||||
a.struct[title="struct syn::token::Lt"]::after,
|
||||
a.struct[title="struct syn::token::Or"]::after,
|
||||
a.struct[title="struct syn::token::Shl"]::after,
|
||||
a.struct[title="struct syn::token::Shr"]::after {
|
||||
content: ".......";
|
||||
}
|
||||
|
||||
a.struct[title="struct syn::token::Abstract"]::after,
|
||||
a.struct[title="struct syn::token::As"]::after,
|
||||
a.struct[title="struct syn::token::Async"]::after,
|
||||
a.struct[title="struct syn::token::Auto"]::after,
|
||||
a.struct[title="struct syn::token::Await"]::after,
|
||||
a.struct[title="struct syn::token::Become"]::after,
|
||||
a.struct[title="struct syn::token::Box"]::after,
|
||||
a.struct[title="struct syn::token::Break"]::after,
|
||||
a.struct[title="struct syn::token::Const"]::after,
|
||||
a.struct[title="struct syn::token::Continue"]::after,
|
||||
a.struct[title="struct syn::token::Crate"]::after,
|
||||
a.struct[title="struct syn::token::Default"]::after,
|
||||
a.struct[title="struct syn::token::Do"]::after,
|
||||
a.struct[title="struct syn::token::Dyn"]::after,
|
||||
a.struct[title="struct syn::token::Else"]::after,
|
||||
a.struct[title="struct syn::token::Enum"]::after,
|
||||
a.struct[title="struct syn::token::Extern"]::after,
|
||||
a.struct[title="struct syn::token::Final"]::after,
|
||||
a.struct[title="struct syn::token::Fn"]::after,
|
||||
a.struct[title="struct syn::token::For"]::after,
|
||||
a.struct[title="struct syn::token::Ge"]::after,
|
||||
a.struct[title="struct syn::token::If"]::after,
|
||||
a.struct[title="struct syn::token::Impl"]::after,
|
||||
a.struct[title="struct syn::token::In"]::after,
|
||||
a.struct[title="struct syn::token::Le"]::after,
|
||||
a.struct[title="struct syn::token::Let"]::after,
|
||||
a.struct[title="struct syn::token::Loop"]::after,
|
||||
a.struct[title="struct syn::token::Macro"]::after,
|
||||
a.struct[title="struct syn::token::Match"]::after,
|
||||
a.struct[title="struct syn::token::Mod"]::after,
|
||||
a.struct[title="struct syn::token::Move"]::after,
|
||||
a.struct[title="struct syn::token::Mut"]::after,
|
||||
a.struct[title="struct syn::token::Ne"]::after,
|
||||
a.struct[title="struct syn::token::Override"]::after,
|
||||
a.struct[title="struct syn::token::Priv"]::after,
|
||||
a.struct[title="struct syn::token::Pub"]::after,
|
||||
a.struct[title="struct syn::token::Raw"]::after,
|
||||
a.struct[title="struct syn::token::Ref"]::after,
|
||||
a.struct[title="struct syn::token::Return"]::after,
|
||||
a.struct[title="struct syn::token::Static"]::after,
|
||||
a.struct[title="struct syn::token::Struct"]::after,
|
||||
a.struct[title="struct syn::token::Super"]::after,
|
||||
a.struct[title="struct syn::token::Trait"]::after,
|
||||
a.struct[title="struct syn::token::Try"]::after,
|
||||
a.struct[title="struct syn::token::Type"]::after,
|
||||
a.struct[title="struct syn::token::Typeof"]::after,
|
||||
a.struct[title="struct syn::token::Union"]::after,
|
||||
a.struct[title="struct syn::token::Unsafe"]::after,
|
||||
a.struct[title="struct syn::token::Unsized"]::after,
|
||||
a.struct[title="struct syn::token::Use"]::after,
|
||||
a.struct[title="struct syn::token::Virtual"]::after,
|
||||
a.struct[title="struct syn::token::Where"]::after,
|
||||
a.struct[title="struct syn::token::While"]::after,
|
||||
a.struct[title="struct syn::token::Yield"]::after {
|
||||
content: "........";
|
||||
}
|
||||
Generated
+1017
-920
File diff suppressed because it is too large
Load Diff
Generated
+1111
-1197
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
||||
#[cfg(feature = "fold")]
|
||||
pub(crate) mod fold {
|
||||
use crate::punctuated::{Pair, Punctuated};
|
||||
|
||||
pub(crate) trait FoldHelper {
|
||||
type Item;
|
||||
fn lift<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnMut(Self::Item) -> Self::Item;
|
||||
}
|
||||
|
||||
impl<T> FoldHelper for Vec<T> {
|
||||
type Item = T;
|
||||
fn lift<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnMut(Self::Item) -> Self::Item,
|
||||
{
|
||||
self.into_iter().map(f).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> FoldHelper for Punctuated<T, U> {
|
||||
type Item = T;
|
||||
fn lift<F>(self, mut f: F) -> Self
|
||||
where
|
||||
F: FnMut(Self::Item) -> Self::Item,
|
||||
{
|
||||
self.into_pairs()
|
||||
.map(Pair::into_tuple)
|
||||
.map(|(t, u)| Pair::new(f(t), u))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
+543
-288
File diff suppressed because it is too large
Load Diff
+7
-4
@@ -82,7 +82,7 @@ fn parse_delimited<'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);
|
||||
let scope = span.close();
|
||||
let nested = crate::parse::advance_step_cursor(cursor, content);
|
||||
let unexpected = crate::parse::get_unexpected(input);
|
||||
let content = crate::parse::new_parse_buffer(scope, nested, unexpected);
|
||||
@@ -142,12 +142,13 @@ fn parse_delimited<'a>(
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
macro_rules! parenthesized {
|
||||
($content:ident in $cursor:expr) => {
|
||||
match $crate::__private::parse_parens(&$cursor) {
|
||||
$crate::__private::Ok(parens) => {
|
||||
$content = parens.content;
|
||||
_ = $content;
|
||||
parens.token
|
||||
}
|
||||
$crate::__private::Err(error) => {
|
||||
@@ -220,12 +221,13 @@ macro_rules! parenthesized {
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
macro_rules! braced {
|
||||
($content:ident in $cursor:expr) => {
|
||||
match $crate::__private::parse_braces(&$cursor) {
|
||||
$crate::__private::Ok(braces) => {
|
||||
$content = braces.content;
|
||||
_ = $content;
|
||||
braces.token
|
||||
}
|
||||
$crate::__private::Err(error) => {
|
||||
@@ -275,12 +277,13 @@ macro_rules! braced {
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
macro_rules! bracketed {
|
||||
($content:ident in $cursor:expr) => {
|
||||
match $crate::__private::parse_brackets(&$cursor) {
|
||||
$crate::__private::Ok(brackets) => {
|
||||
$content = brackets.content;
|
||||
_ = $content;
|
||||
brackets.token
|
||||
}
|
||||
$crate::__private::Err(error) => {
|
||||
|
||||
+4
-2
@@ -51,8 +51,10 @@ pub(crate) fn xid_ok(symbol: &str) -> bool {
|
||||
#[cfg(feature = "parsing")]
|
||||
mod parsing {
|
||||
use crate::buffer::Cursor;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::error::Result;
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::token::Token;
|
||||
use alloc::string::ToString;
|
||||
use proc_macro2::Ident;
|
||||
|
||||
fn accept_as_ident(ident: &Ident) -> bool {
|
||||
@@ -71,7 +73,7 @@ mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Ident {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| {
|
||||
|
||||
+285
-195
File diff suppressed because it is too large
Load Diff
+93
-88
@@ -248,11 +248,12 @@
|
||||
//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the
|
||||
//! dynamic library libproc_macro from rustc toolchain.
|
||||
|
||||
// Syn types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/syn/2.0.48")]
|
||||
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
||||
#![no_std]
|
||||
#![doc(html_root_url = "https://docs.rs/syn/2.0.114")]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg = false))]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||
#![allow(
|
||||
clippy::bool_to_int_with_if,
|
||||
clippy::cast_lossless,
|
||||
@@ -263,8 +264,11 @@
|
||||
clippy::derivable_impls,
|
||||
clippy::diverging_sub_expression,
|
||||
clippy::doc_markdown,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::enum_glob_use,
|
||||
clippy::expl_impl_clone_on_copy,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::fn_params_excessive_bools,
|
||||
clippy::if_not_else,
|
||||
clippy::inherent_to_string,
|
||||
clippy::into_iter_without_iter,
|
||||
@@ -273,8 +277,8 @@
|
||||
clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410
|
||||
clippy::manual_assert,
|
||||
clippy::manual_let_else,
|
||||
clippy::manual_map,
|
||||
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
|
||||
clippy::missing_errors_doc,
|
||||
@@ -282,16 +286,21 @@
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::needless_doctest_main,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::needless_update,
|
||||
clippy::never_loop,
|
||||
clippy::range_plus_one,
|
||||
clippy::redundant_else,
|
||||
clippy::ref_option,
|
||||
clippy::return_self_not_must_use,
|
||||
clippy::similar_names,
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_arguments,
|
||||
clippy::too_many_lines,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133
|
||||
clippy::uninhabited_references,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unnecessary_box_returns,
|
||||
@@ -299,6 +308,12 @@
|
||||
clippy::used_underscore_binding,
|
||||
clippy::wildcard_imports,
|
||||
)]
|
||||
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate std;
|
||||
|
||||
extern crate self as syn;
|
||||
|
||||
#[cfg(feature = "proc-macro")]
|
||||
extern crate proc_macro;
|
||||
@@ -316,15 +331,21 @@ pub mod token;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod attr;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub mod buffer;
|
||||
|
||||
#[cfg(any(
|
||||
all(feature = "parsing", feature = "full"),
|
||||
all(feature = "printing", any(feature = "full", feature = "derive")),
|
||||
))]
|
||||
mod classify;
|
||||
|
||||
mod custom_keyword;
|
||||
|
||||
mod custom_punctuation;
|
||||
@@ -332,13 +353,13 @@ mod custom_punctuation;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
mod data;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput};
|
||||
|
||||
mod drops;
|
||||
@@ -349,45 +370,49 @@ 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_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, 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")))]
|
||||
#[cfg_attr(docsrs, 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,
|
||||
ExprRange, ExprRawAddr, 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::file::File;
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
mod fixup;
|
||||
|
||||
#[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"))))]
|
||||
#[cfg_attr(docsrs, 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(feature = "full")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::generics::{CapturedParam, PreciseCapture};
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
#[cfg_attr(
|
||||
doc_cfg,
|
||||
docsrs,
|
||||
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
||||
)]
|
||||
pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics};
|
||||
@@ -399,7 +424,7 @@ pub use crate::ident::Ident;
|
||||
#[cfg(feature = "full")]
|
||||
mod item;
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::item::{
|
||||
FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType,
|
||||
ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item,
|
||||
@@ -417,7 +442,9 @@ 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};
|
||||
pub use crate::lit::{
|
||||
Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
mod lookahead;
|
||||
@@ -425,12 +452,12 @@ 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"))))]
|
||||
#[cfg_attr(docsrs, 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,
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive"))))
|
||||
)]
|
||||
pub mod meta;
|
||||
@@ -438,11 +465,11 @@ 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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::op::{BinOp, UnOp};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub mod parse;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "proc-macro"))]
|
||||
@@ -454,27 +481,27 @@ 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::pat::{
|
||||
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
|
||||
PatTupleStruct, PatType, PatWild,
|
||||
FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange,
|
||||
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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::path::{
|
||||
AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
|
||||
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
|
||||
};
|
||||
|
||||
#[cfg(all(
|
||||
any(feature = "full", feature = "derive"),
|
||||
any(feature = "parsing", feature = "printing")
|
||||
))]
|
||||
mod precedence;
|
||||
|
||||
#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))]
|
||||
mod print;
|
||||
|
||||
@@ -483,21 +510,24 @@ pub mod punctuated;
|
||||
#[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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub use crate::restriction::{FieldMutability, VisRestricted, Visibility};
|
||||
|
||||
mod sealed;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "derive", not(feature = "full")))]
|
||||
mod scan_expr;
|
||||
|
||||
mod span;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "printing"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[cfg_attr(docsrs, 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
|
||||
|
||||
mod thread;
|
||||
@@ -508,7 +538,7 @@ 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"))))]
|
||||
#[cfg_attr(docsrs, 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,
|
||||
@@ -521,6 +551,7 @@ mod verbatim;
|
||||
#[cfg(all(feature = "parsing", feature = "full"))]
|
||||
mod whitespace;
|
||||
|
||||
#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176
|
||||
mod gen {
|
||||
/// Syntax tree traversal to transform the nodes of an owned syntax tree.
|
||||
///
|
||||
@@ -603,7 +634,7 @@ mod gen {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "fold")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
|
||||
#[rustfmt::skip]
|
||||
pub mod fold;
|
||||
|
||||
@@ -722,7 +753,7 @@ mod gen {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "visit")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
|
||||
#[rustfmt::skip]
|
||||
pub mod visit;
|
||||
|
||||
@@ -816,7 +847,7 @@ mod gen {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "visit-mut")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit-mut")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
|
||||
#[rustfmt::skip]
|
||||
pub mod visit_mut;
|
||||
|
||||
@@ -835,22 +866,18 @@ mod gen {
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[rustfmt::skip]
|
||||
mod hash;
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
#[path = "../gen_helper.rs"]
|
||||
mod helper;
|
||||
}
|
||||
|
||||
#[cfg(feature = "fold")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "fold")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "fold")))]
|
||||
pub use crate::gen::fold;
|
||||
|
||||
#[cfg(feature = "visit")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "visit")))]
|
||||
pub use crate::gen::visit;
|
||||
|
||||
#[cfg(feature = "visit-mut")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "visit-mut")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))]
|
||||
pub use crate::gen::visit_mut;
|
||||
|
||||
// Not public API.
|
||||
@@ -858,6 +885,9 @@ pub use crate::gen::visit_mut;
|
||||
#[path = "export.rs"]
|
||||
pub mod __private;
|
||||
|
||||
#[cfg(all(feature = "parsing", feature = "full"))]
|
||||
use alloc::string::ToString;
|
||||
|
||||
/// Parse tokens of source code into the chosen syntax tree node.
|
||||
///
|
||||
/// This is preferred over parsing a string because tokens are able to preserve
|
||||
@@ -871,42 +901,16 @@ pub mod __private;
|
||||
///
|
||||
/// [`syn::parse2`]: parse2
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate proc_macro;
|
||||
/// #
|
||||
/// use proc_macro::TokenStream;
|
||||
/// use quote::quote;
|
||||
/// use syn::DeriveInput;
|
||||
///
|
||||
/// # const IGNORE_TOKENS: &str = stringify! {
|
||||
/// #[proc_macro_derive(MyMacro)]
|
||||
/// # };
|
||||
/// pub fn my_macro(input: TokenStream) -> TokenStream {
|
||||
/// // Parse the tokens into a syntax tree
|
||||
/// let ast: DeriveInput = syn::parse(input).unwrap();
|
||||
///
|
||||
/// // Build the output, possibly using quasi-quotation
|
||||
/// let expanded = quote! {
|
||||
/// /* ... */
|
||||
/// };
|
||||
///
|
||||
/// // Convert into a token stream and return it
|
||||
/// expanded.into()
|
||||
/// }
|
||||
/// ```
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the stream, an error is returned.
|
||||
#[cfg(all(feature = "parsing", feature = "proc-macro"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
|
||||
#[cfg_attr(docsrs, 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)
|
||||
}
|
||||
|
||||
/// Parse a proc-macro2 token stream into the chosen syntax tree node.
|
||||
///
|
||||
/// This function will check that the input is fully parsed. If there are
|
||||
/// any unparsed tokens at the end of the stream, an error is returned.
|
||||
///
|
||||
/// This function parses a `proc_macro2::TokenStream` which is commonly useful
|
||||
/// when the input comes from a node of the Syn syntax tree, for example the
|
||||
/// body tokens of a [`Macro`] node. When in a procedural macro parsing the
|
||||
@@ -914,14 +918,20 @@ pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> {
|
||||
/// instead.
|
||||
///
|
||||
/// [`syn::parse`]: parse()
|
||||
///
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the stream, an error is returned.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
|
||||
parse::Parser::parse2(T::parse, tokens)
|
||||
}
|
||||
|
||||
/// Parse a string of Rust code into the chosen syntax tree node.
|
||||
///
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the stream, an error is returned.
|
||||
///
|
||||
/// # Hygiene
|
||||
///
|
||||
/// Every span in the resulting syntax tree will be set to resolve at the macro
|
||||
@@ -942,13 +952,11 @@ pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> {
|
||||
/// # run().unwrap();
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
|
||||
parse::Parser::parse_str(T::parse, s)
|
||||
}
|
||||
|
||||
// FIXME the name parse_file makes it sound like you might pass in a path to a
|
||||
// file, rather than the content.
|
||||
/// Parse the content of a file of Rust code.
|
||||
///
|
||||
/// This is different from `syn::parse_str::<File>(content)` in two ways:
|
||||
@@ -962,14 +970,11 @@ pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::error::Error;
|
||||
/// use std::fs::File;
|
||||
/// use std::fs;
|
||||
/// use std::io::Read;
|
||||
///
|
||||
/// 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)?;
|
||||
///
|
||||
/// let content = fs::read_to_string("path/to/code.rs")?;
|
||||
/// let ast = syn::parse_file(&content)?;
|
||||
/// if let Some(shebang) = ast.shebang {
|
||||
/// println!("{}", shebang);
|
||||
@@ -982,7 +987,7 @@ pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> {
|
||||
/// # run().unwrap();
|
||||
/// ```
|
||||
#[cfg(all(feature = "parsing", feature = "full"))]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
|
||||
pub fn parse_file(mut content: &str) -> Result<File> {
|
||||
// Strip the BOM if it is present
|
||||
const BOM: &str = "\u{feff}";
|
||||
|
||||
+13
-14
@@ -1,10 +1,9 @@
|
||||
use proc_macro2::{Ident, Span};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Display};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::lookahead;
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt::{self, Display};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use proc_macro2::{Ident, Span};
|
||||
|
||||
/// A Rust lifetime: `'a`.
|
||||
///
|
||||
@@ -123,10 +122,11 @@ pub_if_not_doc! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::error::Result;
|
||||
use crate::lifetime::Lifetime;
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Lifetime {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| {
|
||||
@@ -140,16 +140,15 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::ext::PunctExt as _;
|
||||
use crate::lifetime::Lifetime;
|
||||
use proc_macro2::{Punct, Spacing, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Lifetime {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let mut apostrophe = Punct::new('\'', Spacing::Joint);
|
||||
apostrophe.set_span(self.apostrophe);
|
||||
tokens.append(apostrophe);
|
||||
tokens.append(Punct::new_spanned('\'', Spacing::Joint, self.apostrophe));
|
||||
self.ident.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
+519
-240
File diff suppressed because it is too large
Load Diff
+190
-9
@@ -2,9 +2,12 @@ use crate::buffer::Cursor;
|
||||
use crate::error::{self, Error};
|
||||
use crate::sealed::lookahead::Sealed;
|
||||
use crate::span::IntoSpans;
|
||||
use crate::token::Token;
|
||||
use crate::token::{CustomToken, Token};
|
||||
use alloc::format;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefCell;
|
||||
use core::fmt::{self, Display};
|
||||
use proc_macro2::{Delimiter, Span};
|
||||
use std::cell::RefCell;
|
||||
|
||||
/// Support for checking the next token in a stream to decide how to parse.
|
||||
///
|
||||
@@ -110,7 +113,18 @@ impl<'a> Lookahead1<'a> {
|
||||
/// The error message will identify all of the expected token types that
|
||||
/// have been peeked against this lookahead instance.
|
||||
pub fn error(self) -> Error {
|
||||
let comparisons = self.comparisons.borrow();
|
||||
let mut comparisons = self.comparisons.into_inner();
|
||||
comparisons.retain_mut(|display| {
|
||||
if *display == "`)`" {
|
||||
*display = match self.cursor.scope_delimiter() {
|
||||
Delimiter::Parenthesis => "`)`",
|
||||
Delimiter::Brace => "`}`",
|
||||
Delimiter::Bracket => "`]`",
|
||||
Delimiter::None => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
match comparisons.len() {
|
||||
0 => {
|
||||
if self.cursor.eof() {
|
||||
@@ -128,14 +142,29 @@ impl<'a> Lookahead1<'a> {
|
||||
error::new_at(self.scope, self.cursor, message)
|
||||
}
|
||||
_ => {
|
||||
let join = comparisons.join(", ");
|
||||
let message = format!("expected one of: {}", join);
|
||||
let message = format!("expected one of: {}", CommaSeparated(&comparisons));
|
||||
error::new_at(self.scope, self.cursor, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CommaSeparated<'a>(&'a [&'a str]);
|
||||
|
||||
impl<'a> Display for CommaSeparated<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut first = true;
|
||||
for &s in self.0 {
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str(s)?;
|
||||
first = false;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Types that can be parsed by looking at just one token.
|
||||
///
|
||||
/// Use [`ParseStream::peek`] to peek one of these types in a parse stream
|
||||
@@ -150,6 +179,160 @@ pub trait Peek: Sealed {
|
||||
type Token: Token;
|
||||
}
|
||||
|
||||
/// Pseudo-token used for peeking the end of a parse stream.
|
||||
///
|
||||
/// This type is only useful as an argument to one of the following functions:
|
||||
///
|
||||
/// - [`ParseStream::peek`][crate::parse::ParseBuffer::peek]
|
||||
/// - [`ParseStream::peek2`][crate::parse::ParseBuffer::peek2]
|
||||
/// - [`ParseStream::peek3`][crate::parse::ParseBuffer::peek3]
|
||||
/// - [`Lookahead1::peek`]
|
||||
///
|
||||
/// The peek will return `true` if there are no remaining tokens after that
|
||||
/// point in the parse stream.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Suppose we are parsing attributes containing core::fmt inspired formatting
|
||||
/// arguments:
|
||||
///
|
||||
/// - `#[fmt("simple example")]`
|
||||
/// - `#[fmt("interpolation e{}ample", self.x)]`
|
||||
/// - `#[fmt("interpolation e{x}ample")]`
|
||||
///
|
||||
/// and we want to recognize the cases where no interpolation occurs so that
|
||||
/// more efficient code can be generated.
|
||||
///
|
||||
/// The following implementation uses `input.peek(Token![,]) &&
|
||||
/// input.peek2(End)` to recognize the case of a trailing comma without
|
||||
/// consuming the comma from the parse stream, because if it isn't a trailing
|
||||
/// comma, that same comma needs to be parsed as part of `args`.
|
||||
///
|
||||
/// ```
|
||||
/// use proc_macro2::TokenStream;
|
||||
/// use quote::quote;
|
||||
/// use syn::parse::{End, Parse, ParseStream, Result};
|
||||
/// use syn::{parse_quote, Attribute, LitStr, Token};
|
||||
///
|
||||
/// struct FormatArgs {
|
||||
/// template: LitStr, // "...{}..."
|
||||
/// args: TokenStream, // , self.x
|
||||
/// }
|
||||
///
|
||||
/// impl Parse for FormatArgs {
|
||||
/// fn parse(input: ParseStream) -> Result<Self> {
|
||||
/// let template: LitStr = input.parse()?;
|
||||
///
|
||||
/// let args = if input.is_empty()
|
||||
/// || input.peek(Token![,]) && input.peek2(End)
|
||||
/// {
|
||||
/// input.parse::<Option<Token![,]>>()?;
|
||||
/// TokenStream::new()
|
||||
/// } else {
|
||||
/// input.parse()?
|
||||
/// };
|
||||
///
|
||||
/// Ok(FormatArgs {
|
||||
/// template,
|
||||
/// args,
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() -> Result<()> {
|
||||
/// let attrs: Vec<Attribute> = parse_quote! {
|
||||
/// #[fmt("simple example")]
|
||||
/// #[fmt("interpolation e{}ample", self.x)]
|
||||
/// #[fmt("interpolation e{x}ample")]
|
||||
/// };
|
||||
///
|
||||
/// for attr in &attrs {
|
||||
/// let FormatArgs { template, args } = attr.parse_args()?;
|
||||
/// let requires_fmt_machinery =
|
||||
/// !args.is_empty() || template.value().contains(['{', '}']);
|
||||
/// let out = if requires_fmt_machinery {
|
||||
/// quote! {
|
||||
/// ::core::write!(__formatter, #template #args)
|
||||
/// }
|
||||
/// } else {
|
||||
/// quote! {
|
||||
/// __formatter.write_str(#template)
|
||||
/// }
|
||||
/// };
|
||||
/// println!("{}", out);
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Implementing this parsing logic without `peek2(End)` is more clumsy because
|
||||
/// we'd need a parse stream actually advanced past the comma before being able
|
||||
/// to find out whether there is anything after it. It would look something
|
||||
/// like:
|
||||
///
|
||||
/// ```
|
||||
/// # use proc_macro2::TokenStream;
|
||||
/// # use syn::parse::{ParseStream, Result};
|
||||
/// # use syn::Token;
|
||||
/// #
|
||||
/// # fn parse(input: ParseStream) -> Result<()> {
|
||||
/// use syn::parse::discouraged::Speculative as _;
|
||||
///
|
||||
/// let ahead = input.fork();
|
||||
/// ahead.parse::<Option<Token![,]>>()?;
|
||||
/// let args = if ahead.is_empty() {
|
||||
/// input.advance_to(&ahead);
|
||||
/// TokenStream::new()
|
||||
/// } else {
|
||||
/// input.parse()?
|
||||
/// };
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// or:
|
||||
///
|
||||
/// ```
|
||||
/// # use proc_macro2::TokenStream;
|
||||
/// # use syn::parse::{ParseStream, Result};
|
||||
/// # use syn::Token;
|
||||
/// #
|
||||
/// # fn parse(input: ParseStream) -> Result<()> {
|
||||
/// use quote::ToTokens as _;
|
||||
///
|
||||
/// let comma: Option<Token![,]> = input.parse()?;
|
||||
/// let mut args = TokenStream::new();
|
||||
/// if !input.is_empty() {
|
||||
/// comma.to_tokens(&mut args);
|
||||
/// input.parse::<TokenStream>()?.to_tokens(&mut args);
|
||||
/// }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct End;
|
||||
|
||||
impl Copy for End {}
|
||||
|
||||
impl Clone for End {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Peek for End {
|
||||
type Token = Self;
|
||||
}
|
||||
|
||||
impl CustomToken for End {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
cursor.eof()
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
"`)`" // Lookahead1 error message will fill in the expected close delimiter
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F {
|
||||
type Token = T;
|
||||
}
|
||||
@@ -162,8 +345,6 @@ impl<S> IntoSpans<S> for TokenMarker {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool {
|
||||
cursor.group(delimiter).is_some()
|
||||
}
|
||||
|
||||
impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {}
|
||||
|
||||
impl Sealed for End {}
|
||||
|
||||
+30
-16
@@ -1,18 +1,19 @@
|
||||
use super::*;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::error::Result;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream, Parser};
|
||||
use crate::path::Path;
|
||||
use crate::token::{Brace, Bracket, Paren};
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
#[cfg(any(feature = "parsing", feature = "printing"))]
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::Delimiter;
|
||||
use proc_macro2::TokenStream;
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::TokenTree;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream, Parser, Result};
|
||||
|
||||
ast_struct! {
|
||||
/// A macro invocation: `println!("{}", mac)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Macro {
|
||||
pub path: Path,
|
||||
pub bang_token: Token![!],
|
||||
@@ -23,7 +24,7 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum MacroDelimiter {
|
||||
Paren(Paren),
|
||||
Brace(Brace),
|
||||
@@ -39,6 +40,14 @@ impl MacroDelimiter {
|
||||
MacroDelimiter::Bracket(token) => &token.span,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "full", any(feature = "parsing", feature = "printing")))]
|
||||
pub(crate) fn is_brace(&self) -> bool {
|
||||
match self {
|
||||
MacroDelimiter::Brace(_) => true,
|
||||
MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Macro {
|
||||
@@ -125,7 +134,7 @@ impl Macro {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_body<T: Parse>(&self) -> Result<T> {
|
||||
self.parse_body_with(T::parse)
|
||||
}
|
||||
@@ -133,7 +142,7 @@ impl Macro {
|
||||
/// Parse the tokens within the macro invocation's delimiters using the
|
||||
/// given parser.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
|
||||
let scope = self.delimiter.span().close();
|
||||
crate::parse::parse_scoped(parser, scope, self.tokens.clone())
|
||||
@@ -162,10 +171,12 @@ pub(crate) fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, Tok
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::error::Result;
|
||||
use crate::mac::{parse_delimiter, Macro};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::path::Path;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Macro {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let tokens;
|
||||
@@ -185,8 +196,11 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use proc_macro2::TokenStream;
|
||||
use crate::mac::{Macro, MacroDelimiter};
|
||||
use crate::path;
|
||||
use crate::path::printing::PathStyle;
|
||||
use crate::token;
|
||||
use proc_macro2::{Delimiter, TokenStream};
|
||||
use quote::ToTokens;
|
||||
|
||||
impl MacroDelimiter {
|
||||
@@ -200,10 +214,10 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Macro {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.path.to_tokens(tokens);
|
||||
path::printing::print_path(tokens, &self.path, PathStyle::Mod);
|
||||
self.bang_token.to_tokens(tokens);
|
||||
self.delimiter.surround(tokens, self.tokens.clone());
|
||||
}
|
||||
|
||||
+24
-18
@@ -15,7 +15,7 @@ macro_rules! ast_struct {
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
$(#[$attr])* $pub $struct $name {
|
||||
_noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>,
|
||||
_noconstruct: ::core::marker::PhantomData<::proc_macro2::Span>,
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "full"), feature = "printing"))]
|
||||
@@ -61,6 +61,9 @@ macro_rules! ast_enum_of_structs {
|
||||
$(#[$enum_attr])* $pub $enum $name $body
|
||||
|
||||
ast_enum_of_structs_impl!($name $body);
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
generate_to_tokens!(() tokens $name $body);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -70,26 +73,13 @@ macro_rules! ast_enum_of_structs_impl {
|
||||
$(
|
||||
$(#[cfg $cfg_attr:tt])*
|
||||
$(#[doc $($doc_attr:tt)*])*
|
||||
$variant:ident $( ($($member:ident)::+) )*,
|
||||
$variant:ident $( ($member:ident) )*,
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$($(
|
||||
ast_enum_from_struct!($name::$variant, $($member)::+);
|
||||
ast_enum_from_struct!($name::$variant, $member);
|
||||
)*)*
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
generate_to_tokens! {
|
||||
()
|
||||
tokens
|
||||
$name {
|
||||
$(
|
||||
$(#[cfg $cfg_attr])*
|
||||
$(#[doc $($doc_attr)*])*
|
||||
$variant $($($member)::+)*,
|
||||
)*
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,7 +116,7 @@ macro_rules! generate_to_tokens {
|
||||
($($arms:tt)*) $tokens:ident $name:ident {
|
||||
$(#[cfg $cfg_attr:tt])*
|
||||
$(#[doc $($doc_attr:tt)*])*
|
||||
$variant:ident $member:ident,
|
||||
$variant:ident($member:ident),
|
||||
$($next:tt)*
|
||||
}
|
||||
) => {
|
||||
@@ -137,7 +127,7 @@ macro_rules! generate_to_tokens {
|
||||
};
|
||||
|
||||
(($($arms:tt)*) $tokens:ident $name:ident {}) => {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ::quote::ToTokens for $name {
|
||||
fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
|
||||
match self {
|
||||
@@ -174,3 +164,19 @@ macro_rules! check_keyword_matches {
|
||||
(pub pub) => {};
|
||||
(struct struct) => {};
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
macro_rules! return_impl_trait {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$vis:vis fn $name:ident $args:tt -> $impl_trait:ty [$concrete:ty] $body:block
|
||||
) => {
|
||||
#[cfg(not(docsrs))]
|
||||
$(#[$attr])*
|
||||
$vis fn $name $args -> $concrete $body
|
||||
|
||||
#[cfg(docsrs)]
|
||||
$(#[$attr])*
|
||||
$vis fn $name $args -> $impl_trait $body
|
||||
};
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,12 +1,13 @@
|
||||
//! Facility for interpreting structured content inside of an `Attribute`.
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::lit::Lit;
|
||||
use crate::parse::{Error, ParseStream, Parser, Result};
|
||||
use crate::parse::{ParseStream, Parser};
|
||||
use crate::path::{Path, PathSegment};
|
||||
use crate::punctuated::Punctuated;
|
||||
use core::fmt::Display;
|
||||
use proc_macro2::Ident;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// Make a parser that is usable with `parse_macro_input!` in a
|
||||
/// `#[proc_macro_attribute]` macro.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ast_enum! {
|
||||
/// A binary operator: `+`, `+=`, `&`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum BinOp {
|
||||
/// The `+` operator (addition)
|
||||
@@ -64,7 +64,7 @@ ast_enum! {
|
||||
|
||||
ast_enum! {
|
||||
/// A unary operator: `*`, `!`, `-`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum UnOp {
|
||||
/// The `*` operator for dereferencing
|
||||
@@ -78,10 +78,11 @@ ast_enum! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::error::Result;
|
||||
use crate::op::{BinOp, UnOp};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for BinOp {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
if input.peek(Token![+=]) {
|
||||
@@ -146,7 +147,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for UnOp {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
@@ -165,11 +166,11 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::op::{BinOp, UnOp};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for BinOp {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
@@ -205,7 +206,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for UnOp {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
|
||||
+98
-64
@@ -103,7 +103,7 @@
|
||||
//! use syn::Type;
|
||||
//!
|
||||
//! # fn run_parser() -> syn::Result<()> {
|
||||
//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?;
|
||||
//! let t: Type = syn::parse_str("alloc::collections::HashMap<String, Value>")?;
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! #
|
||||
@@ -185,23 +185,25 @@ pub mod discouraged;
|
||||
use crate::buffer::{Cursor, TokenBuffer};
|
||||
use crate::error;
|
||||
use crate::lookahead;
|
||||
#[cfg(feature = "proc-macro")]
|
||||
use crate::proc_macro;
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token::Token;
|
||||
use proc_macro2::{self, Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree};
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::Cell;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ops::Deref;
|
||||
use core::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use core::str::FromStr;
|
||||
use proc_macro2::{Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree};
|
||||
#[cfg(feature = "printing")]
|
||||
use quote::ToTokens;
|
||||
|
||||
pub use crate::error::{Error, Result};
|
||||
pub use crate::lookahead::{Lookahead1, Peek};
|
||||
pub use crate::lookahead::{End, Lookahead1, Peek};
|
||||
|
||||
/// Parsing interface implemented by all types that can be parsed in a default
|
||||
/// way from a token stream.
|
||||
@@ -262,10 +264,11 @@ pub struct ParseBuffer<'a> {
|
||||
|
||||
impl<'a> Drop for ParseBuffer<'a> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(self.cursor()) {
|
||||
if let Some((unexpected_span, delimiter)) = span_of_unexpected_ignoring_nones(self.cursor())
|
||||
{
|
||||
let (inner, old_span) = inner_unexpected(self);
|
||||
if old_span.is_none() {
|
||||
inner.set(Unexpected::Some(unexpected_span));
|
||||
inner.set(Unexpected::Some(unexpected_span, delimiter));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,6 +286,9 @@ impl<'a> Debug for ParseBuffer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnwindSafe for ParseBuffer<'a> {}
|
||||
impl<'a> RefUnwindSafe for ParseBuffer<'a> {}
|
||||
|
||||
/// Cursor state associated with speculative parsing.
|
||||
///
|
||||
/// This type is the input of the closure provided to [`ParseStream::step`].
|
||||
@@ -393,7 +399,7 @@ pub(crate) fn new_parse_buffer(
|
||||
|
||||
pub(crate) enum Unexpected {
|
||||
None,
|
||||
Some(Span),
|
||||
Some(Span, Delimiter),
|
||||
Chain(Rc<Cell<Unexpected>>),
|
||||
}
|
||||
|
||||
@@ -407,7 +413,7 @@ impl Clone for Unexpected {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Unexpected::None => Unexpected::None,
|
||||
Unexpected::Some(span) => Unexpected::Some(*span),
|
||||
Unexpected::Some(span, delimiter) => Unexpected::Some(*span, *delimiter),
|
||||
Unexpected::Chain(next) => Unexpected::Chain(next.clone()),
|
||||
}
|
||||
}
|
||||
@@ -422,12 +428,12 @@ fn cell_clone<T: Default + Clone>(cell: &Cell<T>) -> T {
|
||||
ret
|
||||
}
|
||||
|
||||
fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<Span>) {
|
||||
fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<(Span, Delimiter)>) {
|
||||
let mut unexpected = get_unexpected(buffer);
|
||||
loop {
|
||||
match cell_clone(&unexpected) {
|
||||
Unexpected::None => return (unexpected, None),
|
||||
Unexpected::Some(span) => return (unexpected, Some(span)),
|
||||
Unexpected::Some(span, delimiter) => return (unexpected, Some((span, delimiter))),
|
||||
Unexpected::Chain(next) => unexpected = next,
|
||||
}
|
||||
}
|
||||
@@ -437,7 +443,7 @@ pub(crate) fn get_unexpected(buffer: &ParseBuffer) -> Rc<Cell<Unexpected>> {
|
||||
cell_clone(&buffer.unexpected).unwrap()
|
||||
}
|
||||
|
||||
fn span_of_unexpected_ignoring_nones(mut cursor: Cursor) -> Option<Span> {
|
||||
fn span_of_unexpected_ignoring_nones(mut cursor: Cursor) -> Option<(Span, Delimiter)> {
|
||||
if cursor.eof() {
|
||||
return None;
|
||||
}
|
||||
@@ -450,7 +456,7 @@ fn span_of_unexpected_ignoring_nones(mut cursor: Cursor) -> Option<Span> {
|
||||
if cursor.eof() {
|
||||
None
|
||||
} else {
|
||||
Some(cursor.span())
|
||||
Some((cursor.span(), cursor.scope_delimiter()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +503,7 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> {
|
||||
pub fn call<T>(&'a self, function: fn(ParseStream<'a>) -> Result<T>) -> Result<T> {
|
||||
function(self)
|
||||
}
|
||||
|
||||
@@ -614,11 +620,6 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// ```
|
||||
pub fn peek2<T: Peek>(&self, token: T) -> bool {
|
||||
fn peek2(buffer: &ParseBuffer, peek: fn(Cursor) -> bool) -> bool {
|
||||
if let Some(group) = buffer.cursor().group(Delimiter::None) {
|
||||
if group.0.skip().map_or(false, peek) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buffer.cursor().skip().map_or(false, peek)
|
||||
}
|
||||
|
||||
@@ -629,11 +630,6 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// Looks at the third-next token in the parse stream.
|
||||
pub fn peek3<T: Peek>(&self, token: T) -> bool {
|
||||
fn peek3(buffer: &ParseBuffer, peek: fn(Cursor) -> bool) -> bool {
|
||||
if let Some(group) = buffer.cursor().group(Delimiter::None) {
|
||||
if group.0.skip().and_then(Cursor::skip).map_or(false, peek) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buffer
|
||||
.cursor()
|
||||
.skip()
|
||||
@@ -737,8 +733,8 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn parse_terminated<T, P>(
|
||||
&self,
|
||||
parser: fn(ParseStream) -> Result<T>,
|
||||
&'a self,
|
||||
parser: fn(ParseStream<'a>) -> Result<T>,
|
||||
separator: P,
|
||||
) -> Result<Punctuated<T, P::Token>>
|
||||
where
|
||||
@@ -749,10 +745,17 @@ impl<'a> ParseBuffer<'a> {
|
||||
Punctuated::parse_terminated_with(self, parser)
|
||||
}
|
||||
|
||||
/// Returns whether there are tokens remaining in this stream.
|
||||
/// Returns whether there are no more tokens remaining to be parsed from
|
||||
/// this stream.
|
||||
///
|
||||
/// This method returns true at the end of the content of a set of
|
||||
/// delimiters, as well as at the very end of the complete macro input.
|
||||
/// This method returns true upon reaching the end of the content within a
|
||||
/// set of delimiters, as well as at the end of the tokens provided to the
|
||||
/// outermost parsing entry point.
|
||||
///
|
||||
/// This is equivalent to
|
||||
/// <code>.<a href="#method.peek">peek</a>(<a href="struct.End.html">syn::parse::End</a>)</code>.
|
||||
/// Use `.peek2(End)` or `.peek3(End)` to look for the end of a parse stream
|
||||
/// further ahead than the current position.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@@ -1125,7 +1128,7 @@ impl<'a> ParseBuffer<'a> {
|
||||
/// let mut tokens = TokenStream::new();
|
||||
/// while cursor < end {
|
||||
/// let (token, next) = cursor.token_tree().unwrap();
|
||||
/// tokens.extend(std::iter::once(token));
|
||||
/// tokens.extend(core::iter::once(token));
|
||||
/// cursor = next;
|
||||
/// }
|
||||
/// tokens
|
||||
@@ -1154,20 +1157,20 @@ impl<'a> ParseBuffer<'a> {
|
||||
|
||||
fn check_unexpected(&self) -> Result<()> {
|
||||
match inner_unexpected(self).1 {
|
||||
Some(span) => Err(Error::new(span, "unexpected token")),
|
||||
Some((span, delimiter)) => Err(err_unexpected_token(span, delimiter)),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl<T: Parse> Parse for Box<T> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.parse().map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl<T: Parse + Token> Parse for Option<T> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
if T::peek(input.cursor()) {
|
||||
@@ -1178,14 +1181,14 @@ impl<T: Parse + Token> Parse for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TokenStream {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| Ok((cursor.token_stream(), Cursor::empty())))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TokenTree {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| match cursor.token_tree() {
|
||||
@@ -1195,7 +1198,7 @@ impl Parse for TokenTree {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Group {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| {
|
||||
@@ -1209,7 +1212,7 @@ impl Parse for Group {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Punct {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| match cursor.punct() {
|
||||
@@ -1219,7 +1222,7 @@ impl Parse for Punct {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Literal {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| match cursor.literal() {
|
||||
@@ -1239,24 +1242,24 @@ pub trait Parser: Sized {
|
||||
|
||||
/// Parse a proc-macro2 token stream into the chosen syntax tree node.
|
||||
///
|
||||
/// This function will check that the input is fully parsed. If there are
|
||||
/// any unparsed tokens at the end of the stream, an error is returned.
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the stream, an error is returned.
|
||||
fn parse2(self, tokens: TokenStream) -> Result<Self::Output>;
|
||||
|
||||
/// Parse tokens of source code into the chosen syntax tree node.
|
||||
///
|
||||
/// This function will check that the input is fully parsed. If there are
|
||||
/// any unparsed tokens at the end of the stream, an error is returned.
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the stream, an error is returned.
|
||||
#[cfg(feature = "proc-macro")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "proc-macro")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))]
|
||||
fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> {
|
||||
self.parse2(proc_macro2::TokenStream::from(tokens))
|
||||
}
|
||||
|
||||
/// Parse a string of Rust code into the chosen syntax tree node.
|
||||
///
|
||||
/// This function will check that the input is fully parsed. If there are
|
||||
/// any unparsed tokens at the end of the string, an error is returned.
|
||||
/// This function enforces that the input is fully parsed. If there are any
|
||||
/// unparsed tokens at the end of the string, an error is returned.
|
||||
///
|
||||
/// # Hygiene
|
||||
///
|
||||
@@ -1268,7 +1271,6 @@ pub trait Parser: Sized {
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
|
||||
let _ = scope;
|
||||
self.parse2(tokens)
|
||||
@@ -1293,14 +1295,15 @@ where
|
||||
let state = tokens_to_parse_buffer(&buf);
|
||||
let node = self(&state)?;
|
||||
state.check_unexpected()?;
|
||||
if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(state.cursor()) {
|
||||
Err(Error::new(unexpected_span, "unexpected token"))
|
||||
if let Some((unexpected_span, delimiter)) =
|
||||
span_of_unexpected_ignoring_nones(state.cursor())
|
||||
{
|
||||
Err(err_unexpected_token(unexpected_span, delimiter))
|
||||
} else {
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> {
|
||||
let buf = TokenBuffer::new2(tokens);
|
||||
let cursor = buf.begin();
|
||||
@@ -1308,19 +1311,30 @@ where
|
||||
let state = new_parse_buffer(scope, cursor, unexpected);
|
||||
let node = self(&state)?;
|
||||
state.check_unexpected()?;
|
||||
if let Some(unexpected_span) = span_of_unexpected_ignoring_nones(state.cursor()) {
|
||||
Err(Error::new(unexpected_span, "unexpected token"))
|
||||
if let Some((unexpected_span, delimiter)) =
|
||||
span_of_unexpected_ignoring_nones(state.cursor())
|
||||
{
|
||||
Err(err_unexpected_token(unexpected_span, delimiter))
|
||||
} else {
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> {
|
||||
f.__parse_scoped(scope, tokens)
|
||||
}
|
||||
|
||||
fn err_unexpected_token(span: Span, delimiter: Delimiter) -> Error {
|
||||
let msg = match delimiter {
|
||||
Delimiter::Parenthesis => "unexpected token, expected `)`",
|
||||
Delimiter::Brace => "unexpected token, expected `}`",
|
||||
Delimiter::Bracket => "unexpected token, expected `]`",
|
||||
Delimiter::None => "unexpected token",
|
||||
};
|
||||
Error::new(span, msg)
|
||||
}
|
||||
|
||||
/// An empty syntax tree node that consumes no tokens when parsed.
|
||||
///
|
||||
/// This is useful for attribute macros that want to ensure they are not
|
||||
@@ -1359,8 +1373,28 @@ impl Parse for Nothing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Nothing {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let _ = tokens;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Nothing {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for Nothing {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for Nothing {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("Nothing")
|
||||
@@ -1368,11 +1402,11 @@ impl Debug for Nothing {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Eq for Nothing {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Nothing {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
@@ -1380,7 +1414,7 @@ impl PartialEq for Nothing {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for Nothing {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))]
|
||||
macro_rules! parse_macro_input {
|
||||
($tokenstream:ident as $ty:ty) => {
|
||||
match $crate::parse::<$ty>($tokenstream) {
|
||||
|
||||
+40
-5
@@ -53,18 +53,29 @@
|
||||
///
|
||||
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
|
||||
/// or inner like `#![...]`
|
||||
/// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
|
||||
/// any order
|
||||
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
|
||||
/// `P` with optional trailing punctuation
|
||||
/// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
|
||||
/// same grammar as the inside of a `match` expression
|
||||
/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
|
||||
/// - [`Pat`], [`Box<Pat>`] — parses the same as
|
||||
/// `Pat::parse_multi_with_leading_vert`
|
||||
/// - [`Field`] — parses a named or unnamed struct field
|
||||
///
|
||||
/// [`Vec<Attribute>`]: Attribute
|
||||
/// [`Vec<Arm>`]: Arm
|
||||
/// [`Vec<Stmt>`]: Block::parse_within
|
||||
/// [`Pat`]: Pat::parse_multi_with_leading_vert
|
||||
/// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the tokens fail to parse as the expected syntax tree type. The
|
||||
/// caller is responsible for ensuring that the input tokens are syntactically
|
||||
/// valid.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[macro_export]
|
||||
macro_rules! parse_quote {
|
||||
($($tt:tt)*) => {
|
||||
@@ -92,11 +103,11 @@ macro_rules! parse_quote {
|
||||
/// ReturnType::Type(_, ret) => quote!(#ret),
|
||||
/// };
|
||||
/// sig.output = parse_quote_spanned! {ret.span()=>
|
||||
/// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
|
||||
/// -> ::core::pin::Pin<::alloc::boxed::Box<dyn ::core::future::Future<Output = #ret>>>
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[macro_export]
|
||||
macro_rules! parse_quote_spanned {
|
||||
($span:expr=> $($tt:tt)*) => {
|
||||
@@ -107,11 +118,17 @@ macro_rules! parse_quote_spanned {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Can parse any type that implements Parse.
|
||||
|
||||
use crate::parse::{Parse, ParseStream, Parser, Result};
|
||||
use crate::error::Result;
|
||||
use crate::parse::{Parse, ParseStream, Parser};
|
||||
#[cfg(feature = "full")]
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
|
||||
let parser = T::parse;
|
||||
match parser.parse2(token_stream) {
|
||||
@@ -138,7 +155,7 @@ use crate::punctuated::Punctuated;
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::{Block, Pat, Stmt};
|
||||
use crate::{Arm, Block, Pat, Stmt};
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl ParseQuote for Attribute {
|
||||
@@ -151,6 +168,17 @@ impl ParseQuote for Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl ParseQuote for Vec<Attribute> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut attrs = Vec::new();
|
||||
while !input.is_empty() {
|
||||
attrs.push(ParseQuote::parse(input)?);
|
||||
}
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
impl ParseQuote for Field {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
@@ -207,3 +235,10 @@ impl ParseQuote for Vec<Stmt> {
|
||||
Block::parse_within(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl ParseQuote for Vec<Arm> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Arm::parse_multiple(input)
|
||||
}
|
||||
}
|
||||
|
||||
+80
-38
@@ -1,7 +1,19 @@
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::expr::Member;
|
||||
use crate::ident::Ident;
|
||||
use crate::path::{Path, QSelf};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token;
|
||||
use crate::ty::Type;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
pub use crate::expr::{
|
||||
ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
|
||||
ExprRange as PatRange,
|
||||
};
|
||||
|
||||
ast_enum_of_structs! {
|
||||
/// A pattern in a local binding, function signature, match expression, or
|
||||
/// various other places.
|
||||
@@ -10,8 +22,8 @@ ast_enum_of_structs! {
|
||||
///
|
||||
/// This type is a [syntax tree enum].
|
||||
///
|
||||
/// [syntax tree enum]: Expr#syntax-tree-enums
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
#[non_exhaustive]
|
||||
pub enum Pat {
|
||||
/// A const block: `const { ... }`.
|
||||
@@ -96,7 +108,7 @@ ast_struct! {
|
||||
///
|
||||
/// It may also be a unit struct or struct variant (e.g. `None`), or a
|
||||
/// constant; these cannot be distinguished syntactically.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatIdent {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub by_ref: Option<Token![ref]>,
|
||||
@@ -108,7 +120,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A pattern that matches any one of a set of cases.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatOr {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub leading_vert: Option<Token![|]>,
|
||||
@@ -118,7 +130,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A parenthesized pattern: `(A | B)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatParen {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub paren_token: token::Paren,
|
||||
@@ -128,7 +140,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A reference pattern: `&mut var`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatReference {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub and_token: Token![&],
|
||||
@@ -139,7 +151,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The dots in a tuple or slice pattern: `[0, 1, ..]`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatRest {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub dot2_token: Token![..],
|
||||
@@ -148,7 +160,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatSlice {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub bracket_token: token::Bracket,
|
||||
@@ -158,7 +170,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A struct or struct variant pattern: `Variant { x, y, .. }`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatStruct {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub qself: Option<QSelf>,
|
||||
@@ -171,7 +183,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A tuple pattern: `(a, b)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatTuple {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub paren_token: token::Paren,
|
||||
@@ -181,7 +193,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatTupleStruct {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub qself: Option<QSelf>,
|
||||
@@ -193,7 +205,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A type ascription pattern: `foo: f64`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatType {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub pat: Box<Pat>,
|
||||
@@ -204,7 +216,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A pattern that matches any value: `_`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct PatWild {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub underscore_token: Token![_],
|
||||
@@ -216,7 +228,7 @@ ast_struct! {
|
||||
///
|
||||
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated
|
||||
/// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct FieldPat {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub member: Member,
|
||||
@@ -227,12 +239,30 @@ ast_struct! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::error::{self, Result};
|
||||
use crate::expr::{
|
||||
Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits,
|
||||
};
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseBuffer, ParseStream, Result};
|
||||
use crate::path;
|
||||
use crate::ident::Ident;
|
||||
use crate::lit::Lit;
|
||||
use crate::mac::{self, Macro};
|
||||
use crate::parse::{Parse, ParseBuffer, ParseStream};
|
||||
use crate::pat::{
|
||||
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
|
||||
PatTuple, PatTupleStruct, PatType, PatWild,
|
||||
};
|
||||
use crate::path::{self, Path, QSelf};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::stmt::Block;
|
||||
use crate::token;
|
||||
use crate::verbatim;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Pat {
|
||||
/// Parse a pattern that does _not_ involve `|` at the top level.
|
||||
///
|
||||
@@ -356,7 +386,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for PatType {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(PatType {
|
||||
@@ -391,7 +421,8 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
|
||||
let (qself, path) = path::parsing::qpath(input, true)?;
|
||||
let expr_style = true;
|
||||
let (qself, path) = path::parsing::qpath(input, expr_style)?;
|
||||
|
||||
if qself.is_none()
|
||||
&& input.peek(Token![!])
|
||||
@@ -444,7 +475,13 @@ pub(crate) mod parsing {
|
||||
attrs: Vec::new(),
|
||||
by_ref: input.parse()?,
|
||||
mutability: input.parse()?,
|
||||
ident: input.call(Ident::parse_any)?,
|
||||
ident: {
|
||||
if input.peek(Token![self]) {
|
||||
input.call(Ident::parse_any)?
|
||||
} else {
|
||||
input.parse()?
|
||||
}
|
||||
},
|
||||
subpat: {
|
||||
if input.peek(Token![@]) {
|
||||
let at_token: Token![@] = input.parse()?;
|
||||
@@ -773,12 +810,17 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::attr::FilterAttrs;
|
||||
use crate::pat::{
|
||||
FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct,
|
||||
PatTuple, PatTupleStruct, PatType, PatWild,
|
||||
};
|
||||
use crate::path;
|
||||
use crate::path::printing::PathStyle;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatIdent {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -792,7 +834,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatOr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -801,7 +843,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatParen {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -811,7 +853,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatReference {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -821,7 +863,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatRest {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -829,7 +871,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatSlice {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -839,11 +881,11 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatStruct {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
path::printing::print_path(tokens, &self.qself, &self.path);
|
||||
path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
|
||||
self.brace_token.surround(tokens, |tokens| {
|
||||
self.fields.to_tokens(tokens);
|
||||
// NOTE: We need a comma before the dot2 token if it is present.
|
||||
@@ -855,7 +897,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatTuple {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -874,18 +916,18 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatTupleStruct {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
path::printing::print_path(tokens, &self.qself, &self.path);
|
||||
path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr);
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
self.elems.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -895,7 +937,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PatWild {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -903,7 +945,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for FieldPat {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
|
||||
+217
-125
@@ -1,9 +1,17 @@
|
||||
use super::*;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::error::Result;
|
||||
use crate::expr::Expr;
|
||||
use crate::generics::TypeParamBound;
|
||||
use crate::ident::Ident;
|
||||
use crate::lifetime::Lifetime;
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token;
|
||||
use crate::ty::{ReturnType, Type};
|
||||
use alloc::boxed::Box;
|
||||
|
||||
ast_struct! {
|
||||
/// A path at which a named item is exported (e.g. `std::collections::HashMap`).
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
/// A path at which a named item is exported (e.g. `alloc::collections::HashMap`).
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Path {
|
||||
pub leading_colon: Option<Token![::]>,
|
||||
pub segments: Punctuated<PathSegment, Token![::]>,
|
||||
@@ -85,7 +93,7 @@ impl Path {
|
||||
|
||||
/// 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn require_ident(&self) -> Result<&Ident> {
|
||||
self.get_ident().ok_or_else(|| {
|
||||
crate::error::new2(
|
||||
@@ -99,7 +107,7 @@ impl Path {
|
||||
|
||||
ast_struct! {
|
||||
/// A segment of a path together with any path arguments on that segment.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct PathSegment {
|
||||
pub ident: Ident,
|
||||
pub arguments: PathArguments,
|
||||
@@ -123,15 +131,15 @@ ast_enum! {
|
||||
///
|
||||
/// ## Angle bracketed
|
||||
///
|
||||
/// The `<'a, T>` in `std::slice::iter<'a, T>`.
|
||||
/// The `<'a, T>` in `core::slice::iter<'a, T>`.
|
||||
///
|
||||
/// ## Parenthesized
|
||||
///
|
||||
/// The `(A, B) -> C` in `Fn(A, B) -> C`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum PathArguments {
|
||||
None,
|
||||
/// The `<'a, T>` in `std::slice::iter<'a, T>`.
|
||||
/// The `<'a, T>` in `core::slice::iter<'a, T>`.
|
||||
AngleBracketed(AngleBracketedGenericArguments),
|
||||
/// The `(A, B) -> C` in `Fn(A, B) -> C`.
|
||||
Parenthesized(ParenthesizedGenericArguments),
|
||||
@@ -163,7 +171,7 @@ impl PathArguments {
|
||||
|
||||
ast_enum! {
|
||||
/// An individual generic argument, like `'a`, `T`, or `Item = T`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum GenericArgument {
|
||||
/// A lifetime argument.
|
||||
@@ -189,7 +197,7 @@ ast_enum! {
|
||||
ast_struct! {
|
||||
/// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
|
||||
/// V>`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct AngleBracketedGenericArguments {
|
||||
pub colon2_token: Option<Token![::]>,
|
||||
pub lt_token: Token![<],
|
||||
@@ -201,7 +209,7 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// 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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct AssocType {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
@@ -213,7 +221,7 @@ ast_struct! {
|
||||
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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct AssocConst {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
@@ -224,7 +232,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An associated type bound: `Iterator<Item: Display>`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Constraint {
|
||||
pub ident: Ident,
|
||||
pub generics: Option<AngleBracketedGenericArguments>,
|
||||
@@ -236,7 +244,7 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
|
||||
/// C`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct ParenthesizedGenericArguments {
|
||||
pub paren_token: token::Paren,
|
||||
/// `(A, B)`
|
||||
@@ -263,7 +271,7 @@ ast_struct! {
|
||||
/// ^~~~~~ ^
|
||||
/// ty position = 0
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct QSelf {
|
||||
pub lt_token: Token![<],
|
||||
pub ty: Box<Type>,
|
||||
@@ -275,19 +283,39 @@ ast_struct! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
|
||||
use crate::error::Result;
|
||||
#[cfg(feature = "full")]
|
||||
use crate::expr::ExprBlock;
|
||||
use crate::expr::{Expr, ExprPath};
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::generics::TypeParamBound;
|
||||
use crate::ident::Ident;
|
||||
use crate::lifetime::Lifetime;
|
||||
use crate::lit::Lit;
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::path::Constraint;
|
||||
use crate::path::{
|
||||
AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument,
|
||||
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
|
||||
};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token;
|
||||
use crate::ty::{ReturnType, Type};
|
||||
#[cfg(not(feature = "full"))]
|
||||
use crate::verbatim;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Path {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Self::parse_helper(input, false)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for GenericArgument {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
if input.peek(Lifetime) && !input.peek2(Token![+]) {
|
||||
@@ -352,8 +380,15 @@ pub(crate) mod parsing {
|
||||
if input.peek(Token![,]) || input.peek(Token![>]) {
|
||||
break;
|
||||
}
|
||||
let value: TypeParamBound = input.parse()?;
|
||||
bounds.push_value(value);
|
||||
bounds.push_value({
|
||||
let allow_precise_capture = false;
|
||||
let allow_const = true;
|
||||
TypeParamBound::parse_single(
|
||||
input,
|
||||
allow_precise_capture,
|
||||
allow_const,
|
||||
)?
|
||||
});
|
||||
if !input.peek(Token![+]) {
|
||||
break;
|
||||
}
|
||||
@@ -418,7 +453,7 @@ pub(crate) mod parsing {
|
||||
/// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments`
|
||||
/// parses optional leading `::`.
|
||||
#[cfg(feature = "full")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "full"))))]
|
||||
#[cfg_attr(docsrs, 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)
|
||||
@@ -452,7 +487,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for AngleBracketedGenericArguments {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let colon2_token: Option<Token![::]> = input.parse()?;
|
||||
@@ -460,7 +495,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for ParenthesizedGenericArguments {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -472,7 +507,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for PathSegment {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Self::parse_helper(input, false)
|
||||
@@ -496,7 +531,10 @@ pub(crate) mod parsing {
|
||||
input.parse()?
|
||||
};
|
||||
|
||||
if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
|
||||
if !expr_style
|
||||
&& input.peek(Token![<])
|
||||
&& !input.peek(Token![<=])
|
||||
&& !input.peek(Token![<<=])
|
||||
|| input.peek(Token![::]) && input.peek3(Token![<])
|
||||
{
|
||||
Ok(PathSegment {
|
||||
@@ -520,7 +558,7 @@ pub(crate) mod parsing {
|
||||
///
|
||||
/// // A simplified single `use` statement like:
|
||||
/// //
|
||||
/// // use std::collections::HashMap;
|
||||
/// // use alloc::collections::HashMap;
|
||||
/// //
|
||||
/// // Note that generic parameters are not allowed in a `use` statement
|
||||
/// // so the following must not be accepted.
|
||||
@@ -540,7 +578,7 @@ pub(crate) mod parsing {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
|
||||
Ok(Path {
|
||||
leading_colon: input.parse()?,
|
||||
@@ -663,77 +701,90 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
pub(crate) mod printing {
|
||||
use super::*;
|
||||
use crate::generics;
|
||||
use crate::path::{
|
||||
AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
|
||||
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
|
||||
};
|
||||
use crate::print::TokensOrDefault;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::spanned::Spanned;
|
||||
use core::cmp;
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::Span;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use std::cmp;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
pub(crate) enum PathStyle {
|
||||
Expr,
|
||||
Mod,
|
||||
AsWritten,
|
||||
}
|
||||
|
||||
impl Copy for PathStyle {}
|
||||
|
||||
impl Clone for PathStyle {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Path {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.leading_colon.to_tokens(tokens);
|
||||
self.segments.to_tokens(tokens);
|
||||
print_path(tokens, self, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
|
||||
path.leading_colon.to_tokens(tokens);
|
||||
for segment in path.segments.pairs() {
|
||||
print_path_segment(tokens, segment.value(), style);
|
||||
segment.punct().to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PathSegment {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
self.arguments.to_tokens(tokens);
|
||||
print_path_segment(tokens, self, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
|
||||
segment.ident.to_tokens(tokens);
|
||||
print_path_arguments(tokens, &segment.arguments, style);
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for PathArguments {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
PathArguments::None => {}
|
||||
PathArguments::AngleBracketed(arguments) => {
|
||||
arguments.to_tokens(tokens);
|
||||
}
|
||||
PathArguments::Parenthesized(arguments) => {
|
||||
arguments.to_tokens(tokens);
|
||||
}
|
||||
print_path_arguments(tokens, self, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
|
||||
match arguments {
|
||||
PathArguments::None => {}
|
||||
PathArguments::AngleBracketed(arguments) => {
|
||||
print_angle_bracketed_generic_arguments(tokens, arguments, style);
|
||||
}
|
||||
PathArguments::Parenthesized(arguments) => {
|
||||
print_parenthesized_generic_arguments(tokens, arguments, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for GenericArgument {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
|
||||
GenericArgument::Type(ty) => ty.to_tokens(tokens),
|
||||
GenericArgument::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);
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
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| {
|
||||
expr.to_tokens(tokens);
|
||||
}),
|
||||
},
|
||||
GenericArgument::Const(expr) => {
|
||||
generics::printing::print_const_argument(expr, tokens);
|
||||
}
|
||||
GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
|
||||
GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
|
||||
GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
|
||||
@@ -741,50 +792,62 @@ pub(crate) mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for AngleBracketedGenericArguments {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.colon2_token.to_tokens(tokens);
|
||||
self.lt_token.to_tokens(tokens);
|
||||
|
||||
// Print lifetimes before types/consts/bindings, regardless of their
|
||||
// order in self.args.
|
||||
let mut trailing_or_empty = true;
|
||||
for param in self.args.pairs() {
|
||||
match param.value() {
|
||||
GenericArgument::Lifetime(_) => {
|
||||
param.to_tokens(tokens);
|
||||
trailing_or_empty = param.punct().is_some();
|
||||
}
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {}
|
||||
}
|
||||
}
|
||||
for param in self.args.pairs() {
|
||||
match param.value() {
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {
|
||||
if !trailing_or_empty {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
}
|
||||
param.to_tokens(tokens);
|
||||
trailing_or_empty = param.punct().is_some();
|
||||
}
|
||||
GenericArgument::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.gt_token.to_tokens(tokens);
|
||||
print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
pub(crate) fn print_angle_bracketed_generic_arguments(
|
||||
tokens: &mut TokenStream,
|
||||
arguments: &AngleBracketedGenericArguments,
|
||||
style: PathStyle,
|
||||
) {
|
||||
if let PathStyle::Mod = style {
|
||||
return;
|
||||
}
|
||||
|
||||
conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
|
||||
arguments.lt_token.to_tokens(tokens);
|
||||
|
||||
// Print lifetimes before types/consts/bindings, regardless of their
|
||||
// order in args.
|
||||
let mut trailing_or_empty = true;
|
||||
for param in arguments.args.pairs() {
|
||||
match param.value() {
|
||||
GenericArgument::Lifetime(_) => {
|
||||
param.to_tokens(tokens);
|
||||
trailing_or_empty = param.punct().is_some();
|
||||
}
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {}
|
||||
}
|
||||
}
|
||||
for param in arguments.args.pairs() {
|
||||
match param.value() {
|
||||
GenericArgument::Type(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::AssocType(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {
|
||||
if !trailing_or_empty {
|
||||
<Token![,]>::default().to_tokens(tokens);
|
||||
}
|
||||
param.to_tokens(tokens);
|
||||
trailing_or_empty = param.punct().is_some();
|
||||
}
|
||||
GenericArgument::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
arguments.gt_token.to_tokens(tokens);
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for AssocType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
@@ -794,17 +857,17 @@ pub(crate) mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, 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);
|
||||
generics::printing::print_const_argument(&self.value, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Constraint {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.ident.to_tokens(tokens);
|
||||
@@ -814,21 +877,39 @@ pub(crate) mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for ParenthesizedGenericArguments {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
self.inputs.to_tokens(tokens);
|
||||
});
|
||||
self.output.to_tokens(tokens);
|
||||
print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
|
||||
fn print_parenthesized_generic_arguments(
|
||||
tokens: &mut TokenStream,
|
||||
arguments: &ParenthesizedGenericArguments,
|
||||
style: PathStyle,
|
||||
) {
|
||||
if let PathStyle::Mod = style {
|
||||
return;
|
||||
}
|
||||
|
||||
conditionally_print_turbofish(tokens, &None, style);
|
||||
arguments.paren_token.surround(tokens, |tokens| {
|
||||
arguments.inputs.to_tokens(tokens);
|
||||
});
|
||||
arguments.output.to_tokens(tokens);
|
||||
}
|
||||
|
||||
pub(crate) fn print_qpath(
|
||||
tokens: &mut TokenStream,
|
||||
qself: &Option<QSelf>,
|
||||
path: &Path,
|
||||
style: PathStyle,
|
||||
) {
|
||||
let qself = match qself {
|
||||
Some(qself) => qself,
|
||||
None => {
|
||||
path.to_tokens(tokens);
|
||||
print_path(tokens, path, style);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -841,25 +922,36 @@ pub(crate) mod printing {
|
||||
TokensOrDefault(&qself.as_token).to_tokens(tokens);
|
||||
path.leading_colon.to_tokens(tokens);
|
||||
for (i, segment) in segments.by_ref().take(pos).enumerate() {
|
||||
print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
|
||||
if i + 1 == pos {
|
||||
segment.value().to_tokens(tokens);
|
||||
qself.gt_token.to_tokens(tokens);
|
||||
segment.punct().to_tokens(tokens);
|
||||
} else {
|
||||
segment.to_tokens(tokens);
|
||||
}
|
||||
segment.punct().to_tokens(tokens);
|
||||
}
|
||||
} else {
|
||||
qself.gt_token.to_tokens(tokens);
|
||||
path.leading_colon.to_tokens(tokens);
|
||||
}
|
||||
for segment in segments {
|
||||
segment.to_tokens(tokens);
|
||||
print_path_segment(tokens, segment.value(), style);
|
||||
segment.punct().to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
fn conditionally_print_turbofish(
|
||||
tokens: &mut TokenStream,
|
||||
colon2_token: &Option<Token![::]>,
|
||||
style: PathStyle,
|
||||
) {
|
||||
match style {
|
||||
PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
|
||||
PathStyle::Mod => unreachable!(),
|
||||
PathStyle::AsWritten => colon2_token.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
|
||||
impl Spanned for QSelf {
|
||||
fn span(&self) -> Span {
|
||||
struct QSelfDelimiters<'a>(&'a QSelf);
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
#[cfg(all(feature = "printing", feature = "full"))]
|
||||
use crate::attr::{AttrStyle, Attribute};
|
||||
#[cfg(feature = "printing")]
|
||||
use crate::expr::Expr;
|
||||
#[cfg(all(feature = "printing", feature = "full"))]
|
||||
use crate::expr::{
|
||||
ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue,
|
||||
ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro,
|
||||
ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry,
|
||||
ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield,
|
||||
};
|
||||
use crate::op::BinOp;
|
||||
#[cfg(all(feature = "printing", feature = "full"))]
|
||||
use crate::ty::ReturnType;
|
||||
use core::cmp::Ordering;
|
||||
|
||||
// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence
|
||||
pub(crate) enum Precedence {
|
||||
// return, break, closures
|
||||
Jump,
|
||||
// = += -= *= /= %= &= |= ^= <<= >>=
|
||||
Assign,
|
||||
// .. ..=
|
||||
Range,
|
||||
// ||
|
||||
Or,
|
||||
// &&
|
||||
And,
|
||||
// let
|
||||
#[cfg(feature = "printing")]
|
||||
Let,
|
||||
// == != < > <= >=
|
||||
Compare,
|
||||
// |
|
||||
BitOr,
|
||||
// ^
|
||||
BitXor,
|
||||
// &
|
||||
BitAnd,
|
||||
// << >>
|
||||
Shift,
|
||||
// + -
|
||||
Sum,
|
||||
// * / %
|
||||
Product,
|
||||
// as
|
||||
Cast,
|
||||
// unary - * ! & &mut
|
||||
#[cfg(feature = "printing")]
|
||||
Prefix,
|
||||
// paths, loops, function calls, array indexing, field expressions, method calls
|
||||
#[cfg(feature = "printing")]
|
||||
Unambiguous,
|
||||
}
|
||||
|
||||
impl Precedence {
|
||||
pub(crate) const MIN: Self = Precedence::Jump;
|
||||
|
||||
pub(crate) fn of_binop(op: &BinOp) -> Self {
|
||||
match op {
|
||||
BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum,
|
||||
BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product,
|
||||
BinOp::And(_) => Precedence::And,
|
||||
BinOp::Or(_) => Precedence::Or,
|
||||
BinOp::BitXor(_) => Precedence::BitXor,
|
||||
BinOp::BitAnd(_) => Precedence::BitAnd,
|
||||
BinOp::BitOr(_) => Precedence::BitOr,
|
||||
BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift,
|
||||
|
||||
BinOp::Eq(_)
|
||||
| BinOp::Lt(_)
|
||||
| BinOp::Le(_)
|
||||
| BinOp::Ne(_)
|
||||
| BinOp::Ge(_)
|
||||
| BinOp::Gt(_) => Precedence::Compare,
|
||||
|
||||
BinOp::AddAssign(_)
|
||||
| BinOp::SubAssign(_)
|
||||
| BinOp::MulAssign(_)
|
||||
| BinOp::DivAssign(_)
|
||||
| BinOp::RemAssign(_)
|
||||
| BinOp::BitXorAssign(_)
|
||||
| BinOp::BitAndAssign(_)
|
||||
| BinOp::BitOrAssign(_)
|
||||
| BinOp::ShlAssign(_)
|
||||
| BinOp::ShrAssign(_) => Precedence::Assign,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
pub(crate) fn of(e: &Expr) -> Self {
|
||||
#[cfg(feature = "full")]
|
||||
fn prefix_attrs(attrs: &[Attribute]) -> Precedence {
|
||||
for attr in attrs {
|
||||
if let AttrStyle::Outer = attr.style {
|
||||
return Precedence::Prefix;
|
||||
}
|
||||
}
|
||||
Precedence::Unambiguous
|
||||
}
|
||||
|
||||
match e {
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Closure(e) => match e.output {
|
||||
ReturnType::Default => Precedence::Jump,
|
||||
ReturnType::Type(..) => prefix_attrs(&e.attrs),
|
||||
},
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Break(ExprBreak { expr, .. })
|
||||
| Expr::Return(ExprReturn { expr, .. })
|
||||
| Expr::Yield(ExprYield { expr, .. }) => match expr {
|
||||
Some(_) => Precedence::Jump,
|
||||
None => Precedence::Unambiguous,
|
||||
},
|
||||
|
||||
Expr::Assign(_) => Precedence::Assign,
|
||||
Expr::Range(_) => Precedence::Range,
|
||||
Expr::Binary(e) => Precedence::of_binop(&e.op),
|
||||
Expr::Let(_) => Precedence::Let,
|
||||
Expr::Cast(_) => Precedence::Cast,
|
||||
Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix,
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
Expr::Array(ExprArray { attrs, .. })
|
||||
| Expr::Async(ExprAsync { attrs, .. })
|
||||
| Expr::Await(ExprAwait { attrs, .. })
|
||||
| Expr::Block(ExprBlock { attrs, .. })
|
||||
| Expr::Call(ExprCall { attrs, .. })
|
||||
| Expr::Const(ExprConst { attrs, .. })
|
||||
| Expr::Continue(ExprContinue { attrs, .. })
|
||||
| Expr::Field(ExprField { attrs, .. })
|
||||
| Expr::ForLoop(ExprForLoop { attrs, .. })
|
||||
| Expr::Group(ExprGroup { attrs, .. })
|
||||
| Expr::If(ExprIf { attrs, .. })
|
||||
| Expr::Index(ExprIndex { attrs, .. })
|
||||
| Expr::Infer(ExprInfer { attrs, .. })
|
||||
| Expr::Lit(ExprLit { attrs, .. })
|
||||
| Expr::Loop(ExprLoop { attrs, .. })
|
||||
| Expr::Macro(ExprMacro { attrs, .. })
|
||||
| Expr::Match(ExprMatch { attrs, .. })
|
||||
| Expr::MethodCall(ExprMethodCall { attrs, .. })
|
||||
| Expr::Paren(ExprParen { attrs, .. })
|
||||
| Expr::Path(ExprPath { attrs, .. })
|
||||
| Expr::Repeat(ExprRepeat { attrs, .. })
|
||||
| Expr::Struct(ExprStruct { attrs, .. })
|
||||
| Expr::Try(ExprTry { attrs, .. })
|
||||
| Expr::TryBlock(ExprTryBlock { attrs, .. })
|
||||
| Expr::Tuple(ExprTuple { attrs, .. })
|
||||
| Expr::Unsafe(ExprUnsafe { attrs, .. })
|
||||
| Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs),
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
Expr::Array(_)
|
||||
| Expr::Async(_)
|
||||
| Expr::Await(_)
|
||||
| Expr::Block(_)
|
||||
| Expr::Call(_)
|
||||
| Expr::Const(_)
|
||||
| Expr::Continue(_)
|
||||
| Expr::Field(_)
|
||||
| Expr::ForLoop(_)
|
||||
| Expr::Group(_)
|
||||
| Expr::If(_)
|
||||
| Expr::Index(_)
|
||||
| Expr::Infer(_)
|
||||
| Expr::Lit(_)
|
||||
| Expr::Loop(_)
|
||||
| Expr::Macro(_)
|
||||
| Expr::Match(_)
|
||||
| Expr::MethodCall(_)
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Struct(_)
|
||||
| Expr::Try(_)
|
||||
| Expr::TryBlock(_)
|
||||
| Expr::Tuple(_)
|
||||
| Expr::Unsafe(_)
|
||||
| Expr::While(_) => Precedence::Unambiguous,
|
||||
|
||||
Expr::Verbatim(_) => Precedence::Unambiguous,
|
||||
|
||||
#[cfg(not(feature = "full"))]
|
||||
Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for Precedence {}
|
||||
|
||||
impl Clone for Precedence {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Precedence {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as u8 == *other as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Precedence {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
let this = *self as u8;
|
||||
let other = *other as u8;
|
||||
Some(this.cmp(&other))
|
||||
}
|
||||
}
|
||||
+101
-39
@@ -20,22 +20,26 @@
|
||||
//! ~~~~^ ~~~~^ ~~~~
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::fmt::{self, Debug};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use std::iter;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::option;
|
||||
use std::slice;
|
||||
use std::vec;
|
||||
|
||||
use crate::drops::{NoDrop, TrivialDrop};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::error::Result;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::token::Token;
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(all(feature = "fold", any(feature = "full", feature = "derive")))]
|
||||
use alloc::collections::VecDeque;
|
||||
use alloc::vec::{self, Vec};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use core::fmt::{self, Debug};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use core::hash::{Hash, Hasher};
|
||||
#[cfg(any(feature = "full", feature = "derive"))]
|
||||
use core::iter;
|
||||
use core::ops::{Index, IndexMut};
|
||||
use core::option;
|
||||
use core::slice;
|
||||
|
||||
/// **A punctuated sequence of syntax tree nodes of type `T` separated by
|
||||
/// punctuation of type `P`.**
|
||||
@@ -91,6 +95,29 @@ impl<T, P> Punctuated<T, P> {
|
||||
self.iter_mut().next_back()
|
||||
}
|
||||
|
||||
/// Borrows the element at the given index.
|
||||
pub fn get(&self, index: usize) -> Option<&T> {
|
||||
if let Some((value, _punct)) = self.inner.get(index) {
|
||||
Some(value)
|
||||
} else if index == self.inner.len() {
|
||||
self.last.as_deref()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutably borrows the element at the given index.
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
||||
let inner_len = self.inner.len();
|
||||
if let Some((value, _punct)) = self.inner.get_mut(index) {
|
||||
Some(value)
|
||||
} else if index == inner_len {
|
||||
self.last.as_deref_mut()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over borrowed syntax tree nodes of type `&T`.
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter {
|
||||
@@ -262,7 +289,7 @@ 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`.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_terminated(input: ParseStream) -> Result<Self>
|
||||
where
|
||||
T: Parse,
|
||||
@@ -280,10 +307,10 @@ impl<T, P> Punctuated<T, P> {
|
||||
///
|
||||
/// [`parse_terminated`]: Punctuated::parse_terminated
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_terminated_with(
|
||||
input: ParseStream,
|
||||
parser: fn(ParseStream) -> Result<T>,
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_terminated_with<'a>(
|
||||
input: ParseStream<'a>,
|
||||
parser: fn(ParseStream<'a>) -> Result<T>,
|
||||
) -> Result<Self>
|
||||
where
|
||||
P: Parse,
|
||||
@@ -314,7 +341,7 @@ impl<T, P> Punctuated<T, P> {
|
||||
/// is not followed by a `P`, even if there are remaining tokens in the
|
||||
/// stream.
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self>
|
||||
where
|
||||
T: Parse,
|
||||
@@ -332,10 +359,10 @@ impl<T, P> Punctuated<T, P> {
|
||||
///
|
||||
/// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_separated_nonempty_with(
|
||||
input: ParseStream,
|
||||
parser: fn(ParseStream) -> Result<T>,
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_separated_nonempty_with<'a>(
|
||||
input: ParseStream<'a>,
|
||||
parser: fn(ParseStream<'a>) -> Result<T>,
|
||||
) -> Result<Self>
|
||||
where
|
||||
P: Token + Parse,
|
||||
@@ -357,7 +384,7 @@ impl<T, P> Punctuated<T, P> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Clone for Punctuated<T, P>
|
||||
where
|
||||
T: Clone,
|
||||
@@ -377,7 +404,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl<T, P> Eq for Punctuated<T, P>
|
||||
where
|
||||
T: Eq,
|
||||
@@ -386,7 +413,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl<T, P> PartialEq for Punctuated<T, P>
|
||||
where
|
||||
T: PartialEq,
|
||||
@@ -399,7 +426,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl<T, P> Hash for Punctuated<T, P>
|
||||
where
|
||||
T: Hash,
|
||||
@@ -413,7 +440,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl<T: Debug, P: Debug> Debug for Punctuated<T, P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut list = f.debug_list();
|
||||
@@ -477,7 +504,7 @@ where
|
||||
let mut nomore = false;
|
||||
for pair in i {
|
||||
if nomore {
|
||||
panic!("Punctuated extended with items after a Pair::End");
|
||||
panic!("punctuated extended with items after a Pair::End");
|
||||
}
|
||||
match pair {
|
||||
Pair::Punctuated(a, b) => punctuated.inner.push((a, b)),
|
||||
@@ -495,8 +522,13 @@ impl<T, P> IntoIterator for Punctuated<T, P> {
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let mut elements = Vec::with_capacity(self.len());
|
||||
elements.extend(self.inner.into_iter().map(|pair| pair.0));
|
||||
elements.extend(self.last.map(|t| *t));
|
||||
|
||||
for (t, _) in self.inner {
|
||||
elements.push(t);
|
||||
}
|
||||
if let Some(t) = self.last {
|
||||
elements.push(*t);
|
||||
}
|
||||
|
||||
IntoIter {
|
||||
inner: elements.into_iter(),
|
||||
@@ -1006,7 +1038,7 @@ impl<T, P> Pair<T, P> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Pair<&T, &P> {
|
||||
pub fn cloned(self) -> Pair<T, P>
|
||||
where
|
||||
@@ -1021,7 +1053,7 @@ impl<T, P> Pair<&T, &P> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Clone for Pair<T, P>
|
||||
where
|
||||
T: Clone,
|
||||
@@ -1036,7 +1068,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl<T, P> Copy for Pair<T, P>
|
||||
where
|
||||
T: Copy,
|
||||
@@ -1048,7 +1080,7 @@ impl<T, P> Index<usize> for Punctuated<T, P> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
if index == self.len() - 1 {
|
||||
if index.checked_add(1) == Some(self.len()) {
|
||||
match &self.last {
|
||||
Some(t) => t,
|
||||
None => &self.inner[index].0,
|
||||
@@ -1061,7 +1093,7 @@ impl<T, P> Index<usize> for Punctuated<T, P> {
|
||||
|
||||
impl<T, P> IndexMut<usize> for Punctuated<T, P> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
if index == self.len() - 1 {
|
||||
if index.checked_add(1) == Some(self.len()) {
|
||||
match &mut self.last {
|
||||
Some(t) => t,
|
||||
None => &mut self.inner[index].0,
|
||||
@@ -1072,13 +1104,43 @@ impl<T, P> IndexMut<usize> for Punctuated<T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "fold", any(feature = "full", feature = "derive")))]
|
||||
pub(crate) fn fold<T, P, V, F>(
|
||||
punctuated: Punctuated<T, P>,
|
||||
fold: &mut V,
|
||||
mut f: F,
|
||||
) -> Punctuated<T, P>
|
||||
where
|
||||
V: ?Sized,
|
||||
F: FnMut(&mut V, T) -> T,
|
||||
{
|
||||
let Punctuated { inner, last } = punctuated;
|
||||
|
||||
// Convert into VecDeque to prevent needing to allocate a new Vec<(T, P)>
|
||||
// for the folded elements.
|
||||
let mut inner = VecDeque::from(inner);
|
||||
for _ in 0..inner.len() {
|
||||
if let Some((t, p)) = inner.pop_front() {
|
||||
inner.push_back((f(fold, t), p));
|
||||
}
|
||||
}
|
||||
|
||||
Punctuated {
|
||||
inner: Vec::from(inner),
|
||||
last: match last {
|
||||
Some(t) => Some(Box::new(f(fold, *t))),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::punctuated::{Pair, Punctuated};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl<T, P> ToTokens for Punctuated<T, P>
|
||||
where
|
||||
T: ToTokens,
|
||||
@@ -1089,7 +1151,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl<T, P> ToTokens for Pair<T, P>
|
||||
where
|
||||
T: ToTokens,
|
||||
|
||||
+21
-12
@@ -1,4 +1,6 @@
|
||||
use super::*;
|
||||
use crate::path::Path;
|
||||
use crate::token;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
ast_enum! {
|
||||
/// The visibility level of an item: inherited or `pub` or
|
||||
@@ -8,8 +10,8 @@ ast_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"))))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum Visibility {
|
||||
/// A public visibility level: `pub`.
|
||||
Public(Token![pub]),
|
||||
@@ -26,7 +28,7 @@ ast_enum! {
|
||||
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"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct VisRestricted {
|
||||
pub pub_token: Token![pub],
|
||||
pub paren_token: token::Paren,
|
||||
@@ -37,7 +39,7 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// Unused, but reserved for RFC 3323 restrictions.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum FieldMutability {
|
||||
None,
|
||||
@@ -57,12 +59,17 @@ ast_enum! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::error::Result;
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::ident::Ident;
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::path::Path;
|
||||
use crate::restriction::{VisRestricted, Visibility};
|
||||
use crate::token;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, 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
|
||||
@@ -141,11 +148,13 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::path;
|
||||
use crate::path::printing::PathStyle;
|
||||
use crate::restriction::{VisRestricted, Visibility};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Visibility {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
@@ -156,7 +165,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for VisRestricted {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.pub_token.to_tokens(tokens);
|
||||
@@ -164,7 +173,7 @@ mod printing {
|
||||
// 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);
|
||||
path::printing::print_path(tokens, &self.path, PathStyle::Mod);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
use self::{Action::*, Input::*};
|
||||
use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
|
||||
use syn::parse::{ParseStream, Result};
|
||||
#[allow(unused_imports)]
|
||||
//#[cfg_attr(not(test), expect(unused_imports))] // Rust 1.81+
|
||||
use syn::Token;
|
||||
use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Type};
|
||||
|
||||
enum Input {
|
||||
Keyword(&'static str),
|
||||
Punct(&'static str),
|
||||
ConsumeAny,
|
||||
ConsumeBinOp,
|
||||
ConsumeBrace,
|
||||
ConsumeDelimiter,
|
||||
ConsumeIdent,
|
||||
ConsumeLifetime,
|
||||
ConsumeLiteral,
|
||||
ConsumeNestedBrace,
|
||||
ExpectPath,
|
||||
ExpectTurbofish,
|
||||
ExpectType,
|
||||
CanBeginExpr,
|
||||
Otherwise,
|
||||
Empty,
|
||||
}
|
||||
|
||||
enum Action {
|
||||
SetState(&'static [(Input, Action)]),
|
||||
IncDepth,
|
||||
DecDepth,
|
||||
Finish,
|
||||
}
|
||||
|
||||
static INIT: [(Input, Action); 28] = [
|
||||
(ConsumeDelimiter, SetState(&POSTFIX)),
|
||||
(Keyword("async"), SetState(&ASYNC)),
|
||||
(Keyword("break"), SetState(&BREAK_LABEL)),
|
||||
(Keyword("const"), SetState(&CONST)),
|
||||
(Keyword("continue"), SetState(&CONTINUE)),
|
||||
(Keyword("for"), SetState(&FOR)),
|
||||
(Keyword("if"), IncDepth),
|
||||
(Keyword("let"), SetState(&PATTERN)),
|
||||
(Keyword("loop"), SetState(&BLOCK)),
|
||||
(Keyword("match"), IncDepth),
|
||||
(Keyword("move"), SetState(&CLOSURE)),
|
||||
(Keyword("return"), SetState(&RETURN)),
|
||||
(Keyword("static"), SetState(&CLOSURE)),
|
||||
(Keyword("unsafe"), SetState(&BLOCK)),
|
||||
(Keyword("while"), IncDepth),
|
||||
(Keyword("yield"), SetState(&RETURN)),
|
||||
(Keyword("_"), SetState(&POSTFIX)),
|
||||
(Punct("!"), SetState(&INIT)),
|
||||
(Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])),
|
||||
(Punct("&"), SetState(&REFERENCE)),
|
||||
(Punct("*"), SetState(&INIT)),
|
||||
(Punct("-"), SetState(&INIT)),
|
||||
(Punct("..="), SetState(&INIT)),
|
||||
(Punct(".."), SetState(&RANGE)),
|
||||
(Punct("|"), SetState(&CLOSURE_ARGS)),
|
||||
(ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])),
|
||||
(ConsumeLiteral, SetState(&POSTFIX)),
|
||||
(ExpectPath, SetState(&PATH)),
|
||||
];
|
||||
|
||||
static POSTFIX: [(Input, Action); 10] = [
|
||||
(Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])),
|
||||
(Punct("..="), SetState(&INIT)),
|
||||
(Punct(".."), SetState(&RANGE)),
|
||||
(Punct("."), SetState(&DOT)),
|
||||
(Punct("?"), SetState(&POSTFIX)),
|
||||
(ConsumeBinOp, SetState(&INIT)),
|
||||
(Punct("="), SetState(&INIT)),
|
||||
(ConsumeNestedBrace, SetState(&IF_THEN)),
|
||||
(ConsumeDelimiter, SetState(&POSTFIX)),
|
||||
(Empty, Finish),
|
||||
];
|
||||
|
||||
static ASYNC: [(Input, Action); 3] = [
|
||||
(Keyword("move"), SetState(&ASYNC)),
|
||||
(Punct("|"), SetState(&CLOSURE_ARGS)),
|
||||
(ConsumeBrace, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))];
|
||||
|
||||
static BREAK_LABEL: [(Input, Action); 2] = [
|
||||
(ConsumeLifetime, SetState(&BREAK_VALUE)),
|
||||
(Otherwise, SetState(&BREAK_VALUE)),
|
||||
];
|
||||
|
||||
static BREAK_VALUE: [(Input, Action); 3] = [
|
||||
(ConsumeNestedBrace, SetState(&IF_THEN)),
|
||||
(CanBeginExpr, SetState(&INIT)),
|
||||
(Otherwise, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static CLOSURE: [(Input, Action); 7] = [
|
||||
(Keyword("async"), SetState(&CLOSURE)),
|
||||
(Keyword("move"), SetState(&CLOSURE)),
|
||||
(Punct(","), SetState(&CLOSURE)),
|
||||
(Punct(">"), SetState(&CLOSURE)),
|
||||
(Punct("|"), SetState(&CLOSURE_ARGS)),
|
||||
(ConsumeLifetime, SetState(&CLOSURE)),
|
||||
(ConsumeIdent, SetState(&CLOSURE)),
|
||||
];
|
||||
|
||||
static CLOSURE_ARGS: [(Input, Action); 2] = [
|
||||
(Punct("|"), SetState(&CLOSURE_RET)),
|
||||
(ConsumeAny, SetState(&CLOSURE_ARGS)),
|
||||
];
|
||||
|
||||
static CLOSURE_RET: [(Input, Action); 2] = [
|
||||
(Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),
|
||||
(Otherwise, SetState(&INIT)),
|
||||
];
|
||||
|
||||
static CONST: [(Input, Action); 2] = [
|
||||
(Punct("|"), SetState(&CLOSURE_ARGS)),
|
||||
(ConsumeBrace, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static CONTINUE: [(Input, Action); 2] = [
|
||||
(ConsumeLifetime, SetState(&POSTFIX)),
|
||||
(Otherwise, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static DOT: [(Input, Action); 3] = [
|
||||
(Keyword("await"), SetState(&POSTFIX)),
|
||||
(ConsumeIdent, SetState(&METHOD)),
|
||||
(ConsumeLiteral, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static FOR: [(Input, Action); 2] = [
|
||||
(Punct("<"), SetState(&CLOSURE)),
|
||||
(Otherwise, SetState(&PATTERN)),
|
||||
];
|
||||
|
||||
static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];
|
||||
static IF_THEN: [(Input, Action); 2] =
|
||||
[(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)];
|
||||
|
||||
static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))];
|
||||
|
||||
static PATH: [(Input, Action); 4] = [
|
||||
(Punct("!="), SetState(&INIT)),
|
||||
(Punct("!"), SetState(&INIT)),
|
||||
(ConsumeNestedBrace, SetState(&IF_THEN)),
|
||||
(Otherwise, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static PATTERN: [(Input, Action); 15] = [
|
||||
(ConsumeDelimiter, SetState(&PATTERN)),
|
||||
(Keyword("box"), SetState(&PATTERN)),
|
||||
(Keyword("in"), IncDepth),
|
||||
(Keyword("mut"), SetState(&PATTERN)),
|
||||
(Keyword("ref"), SetState(&PATTERN)),
|
||||
(Keyword("_"), SetState(&PATTERN)),
|
||||
(Punct("!"), SetState(&PATTERN)),
|
||||
(Punct("&"), SetState(&PATTERN)),
|
||||
(Punct("..="), SetState(&PATTERN)),
|
||||
(Punct(".."), SetState(&PATTERN)),
|
||||
(Punct("="), SetState(&INIT)),
|
||||
(Punct("@"), SetState(&PATTERN)),
|
||||
(Punct("|"), SetState(&PATTERN)),
|
||||
(ConsumeLiteral, SetState(&PATTERN)),
|
||||
(ExpectPath, SetState(&PATTERN)),
|
||||
];
|
||||
|
||||
static RANGE: [(Input, Action); 6] = [
|
||||
(Punct("..="), SetState(&INIT)),
|
||||
(Punct(".."), SetState(&RANGE)),
|
||||
(Punct("."), SetState(&DOT)),
|
||||
(ConsumeNestedBrace, SetState(&IF_THEN)),
|
||||
(Empty, Finish),
|
||||
(Otherwise, SetState(&INIT)),
|
||||
];
|
||||
|
||||
static RAW: [(Input, Action); 3] = [
|
||||
(Keyword("const"), SetState(&INIT)),
|
||||
(Keyword("mut"), SetState(&INIT)),
|
||||
(Otherwise, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
static REFERENCE: [(Input, Action); 3] = [
|
||||
(Keyword("mut"), SetState(&INIT)),
|
||||
(Keyword("raw"), SetState(&RAW)),
|
||||
(Otherwise, SetState(&INIT)),
|
||||
];
|
||||
|
||||
static RETURN: [(Input, Action); 2] = [
|
||||
(CanBeginExpr, SetState(&INIT)),
|
||||
(Otherwise, SetState(&POSTFIX)),
|
||||
];
|
||||
|
||||
pub(crate) fn scan_expr(input: ParseStream) -> Result<()> {
|
||||
let mut state = INIT.as_slice();
|
||||
let mut depth = 0usize;
|
||||
'table: loop {
|
||||
for rule in state {
|
||||
if match rule.0 {
|
||||
Input::Keyword(expected) => input.step(|cursor| match cursor.ident() {
|
||||
Some((ident, rest)) if ident == expected => Ok((true, rest)),
|
||||
_ => Ok((false, *cursor)),
|
||||
})?,
|
||||
Input::Punct(expected) => input.step(|cursor| {
|
||||
let begin = *cursor;
|
||||
let mut cursor = begin;
|
||||
for (i, ch) in expected.chars().enumerate() {
|
||||
match cursor.punct() {
|
||||
Some((punct, _)) if punct.as_char() != ch => break,
|
||||
Some((_, rest)) if i == expected.len() - 1 => {
|
||||
return Ok((true, rest));
|
||||
}
|
||||
Some((punct, rest)) if punct.spacing() == Spacing::Joint => {
|
||||
cursor = rest;
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Ok((false, begin))
|
||||
})?,
|
||||
Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(),
|
||||
Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(),
|
||||
Input::ConsumeBrace | Input::ConsumeNestedBrace => {
|
||||
(matches!(rule.0, Input::ConsumeBrace) || depth > 0)
|
||||
&& input.step(|cursor| match cursor.group(Delimiter::Brace) {
|
||||
Some((_inside, _span, rest)) => Ok((true, rest)),
|
||||
None => Ok((false, *cursor)),
|
||||
})?
|
||||
}
|
||||
Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() {
|
||||
Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)),
|
||||
None => Ok((false, *cursor)),
|
||||
})?,
|
||||
Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(),
|
||||
Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(),
|
||||
Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(),
|
||||
Input::ExpectPath => {
|
||||
input.parse::<ExprPath>()?;
|
||||
true
|
||||
}
|
||||
Input::ExpectTurbofish => {
|
||||
if input.peek(Token![::]) {
|
||||
input.parse::<AngleBracketedGenericArguments>()?;
|
||||
}
|
||||
true
|
||||
}
|
||||
Input::ExpectType => {
|
||||
Type::without_plus(input)?;
|
||||
true
|
||||
}
|
||||
Input::CanBeginExpr => Expr::peek(input),
|
||||
Input::Otherwise => true,
|
||||
Input::Empty => input.is_empty() || input.peek(Token![,]),
|
||||
} {
|
||||
state = match rule.1 {
|
||||
Action::SetState(next) => next,
|
||||
Action::IncDepth => (depth += 1, &INIT).1,
|
||||
Action::DecDepth => (depth -= 1, &POSTFIX).1,
|
||||
Action::Finish => return if depth == 0 { Ok(()) } else { break },
|
||||
};
|
||||
continue 'table;
|
||||
}
|
||||
}
|
||||
return Err(input.error("unsupported expression"));
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -11,7 +11,7 @@
|
||||
//! be able to pass a reference to one of those fields across threads.
|
||||
//!
|
||||
//! [`Type`]: crate::Type
|
||||
//! [`Sync`]: std::marker::Sync
|
||||
//! [`Sync`]: core::marker::Sync
|
||||
//!
|
||||
//! If the field type does *not* implement `Sync` as required, we want the
|
||||
//! compiler to report an error pointing out exactly which type it was.
|
||||
@@ -53,7 +53,7 @@
|
||||
//! `Sync`. The errors they would see look like the following.
|
||||
//!
|
||||
//! ```text
|
||||
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
|
||||
//! error[E0277]: the trait bound `*const i32: core::marker::Sync` is not satisfied
|
||||
//! --> src/main.rs:10:21
|
||||
//! |
|
||||
//! 10 | bad_field: *const i32,
|
||||
@@ -108,7 +108,7 @@ impl<T: ?Sized + ToTokens> Spanned for T {
|
||||
}
|
||||
|
||||
mod private {
|
||||
use super::*;
|
||||
use crate::spanned::ToTokens;
|
||||
|
||||
pub trait Sealed {}
|
||||
impl<T: ?Sized + ToTokens> Sealed for T {}
|
||||
|
||||
+64
-28
@@ -1,8 +1,15 @@
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::expr::Expr;
|
||||
use crate::item::Item;
|
||||
use crate::mac::Macro;
|
||||
use crate::pat::Pat;
|
||||
use crate::token;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
ast_struct! {
|
||||
/// A braced block containing Rust statements.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct Block {
|
||||
pub brace_token: token::Brace,
|
||||
/// Statements in a block
|
||||
@@ -12,7 +19,7 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// A statement, usually ending in a semicolon.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub enum Stmt {
|
||||
/// A local (let) binding.
|
||||
Local(Local),
|
||||
@@ -33,8 +40,8 @@ ast_enum! {
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A local `let` binding: `let x: u64 = s.parse()?`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "full")))]
|
||||
/// A local `let` binding: `let x: u64 = s.parse()?;`.
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct Local {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub let_token: Token![let],
|
||||
@@ -50,7 +57,7 @@ ast_struct! {
|
||||
///
|
||||
/// `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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct LocalInit {
|
||||
pub eq_token: Token![=],
|
||||
pub expr: Box<Expr>,
|
||||
@@ -64,7 +71,7 @@ ast_struct! {
|
||||
/// 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")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
|
||||
pub struct StmtMacro {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub mac: Macro,
|
||||
@@ -74,9 +81,22 @@ ast_struct! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::classify;
|
||||
use crate::error::Result;
|
||||
use crate::expr::{Expr, ExprBlock, ExprMacro};
|
||||
use crate::ident::Ident;
|
||||
use crate::item;
|
||||
use crate::mac::{self, Macro};
|
||||
use crate::parse::discouraged::Speculative as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::pat::{Pat, PatType};
|
||||
use crate::path::Path;
|
||||
use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
|
||||
use crate::token;
|
||||
use crate::ty::Type;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
struct AllowNoSemi(bool);
|
||||
@@ -131,7 +151,7 @@ pub(crate) mod parsing {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
|
||||
let mut stmts = Vec::new();
|
||||
loop {
|
||||
@@ -143,7 +163,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
let stmt = parse_stmt(input, AllowNoSemi(true))?;
|
||||
let requires_semicolon = match &stmt {
|
||||
Stmt::Expr(stmt, None) => expr::requires_terminator(stmt),
|
||||
Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt),
|
||||
Stmt::Macro(stmt) => {
|
||||
stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace()
|
||||
}
|
||||
@@ -160,7 +180,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Block {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -171,7 +191,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Stmt {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_nosemi = AllowNoSemi(false);
|
||||
@@ -192,7 +212,8 @@ pub(crate) mod parsing {
|
||||
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.peek3(Token![.]) && !ahead.peek3(Token![..])
|
||||
|| ahead.peek3(Token![?]))
|
||||
{
|
||||
input.advance_to(&ahead);
|
||||
return stmt_mac(input, attrs, path).map(Stmt::Macro);
|
||||
@@ -282,8 +303,8 @@ pub(crate) mod parsing {
|
||||
let eq_token: Token![=] = eq_token;
|
||||
let expr: Expr = input.parse()?;
|
||||
|
||||
let diverge = if let Some(else_token) = input.parse()? {
|
||||
let else_token: Token![else] = else_token;
|
||||
let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) {
|
||||
let else_token: Token![else] = input.parse()?;
|
||||
let diverge = ExprBlock {
|
||||
attrs: Vec::new(),
|
||||
label: None,
|
||||
@@ -319,7 +340,7 @@ pub(crate) mod parsing {
|
||||
allow_nosemi: AllowNoSemi,
|
||||
mut attrs: Vec<Attribute>,
|
||||
) -> Result<Stmt> {
|
||||
let mut e = expr::parsing::expr_early(input)?;
|
||||
let mut e = Expr::parse_with_earlier_boundary_rule(input)?;
|
||||
|
||||
let mut attr_target = &mut e;
|
||||
loop {
|
||||
@@ -351,6 +372,7 @@ pub(crate) mod parsing {
|
||||
| Expr::Paren(_)
|
||||
| Expr::Path(_)
|
||||
| Expr::Range(_)
|
||||
| Expr::RawAddr(_)
|
||||
| Expr::Reference(_)
|
||||
| Expr::Repeat(_)
|
||||
| Expr::Return(_)
|
||||
@@ -385,7 +407,7 @@ pub(crate) mod parsing {
|
||||
|
||||
if semi_token.is_some() {
|
||||
Ok(Stmt::Expr(e, semi_token))
|
||||
} else if allow_nosemi.0 || !expr::requires_terminator(&e) {
|
||||
} else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) {
|
||||
Ok(Stmt::Expr(e, None))
|
||||
} else {
|
||||
Err(input.error("expected semicolon"))
|
||||
@@ -394,12 +416,16 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
pub(crate) mod printing {
|
||||
use crate::classify;
|
||||
use crate::expr::{self, Expr};
|
||||
use crate::fixup::FixupContext;
|
||||
use crate::stmt::{Block, Local, Stmt, StmtMacro};
|
||||
use crate::token;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Block {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.brace_token.surround(tokens, |tokens| {
|
||||
@@ -408,14 +434,14 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Stmt {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
Stmt::Local(local) => local.to_tokens(tokens),
|
||||
Stmt::Item(item) => item.to_tokens(tokens),
|
||||
Stmt::Expr(expr, semi) => {
|
||||
expr.to_tokens(tokens);
|
||||
expr::printing::print_expr(expr, tokens, FixupContext::new_stmt());
|
||||
semi.to_tokens(tokens);
|
||||
}
|
||||
Stmt::Macro(mac) => mac.to_tokens(tokens),
|
||||
@@ -423,7 +449,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Local {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
|
||||
@@ -431,17 +457,27 @@ mod printing {
|
||||
self.pat.to_tokens(tokens);
|
||||
if let Some(init) = &self.init {
|
||||
init.eq_token.to_tokens(tokens);
|
||||
init.expr.to_tokens(tokens);
|
||||
expr::printing::print_subexpression(
|
||||
&init.expr,
|
||||
init.diverge.is_some() && classify::expr_trailing_brace(&init.expr),
|
||||
tokens,
|
||||
FixupContext::NONE,
|
||||
);
|
||||
if let Some((else_token, diverge)) = &init.diverge {
|
||||
else_token.to_tokens(tokens);
|
||||
diverge.to_tokens(tokens);
|
||||
match &**diverge {
|
||||
Expr::Block(diverge) => diverge.to_tokens(tokens),
|
||||
_ => token::Brace::default().surround(tokens, |tokens| {
|
||||
expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt());
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.semi_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for StmtMacro {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
use std::fmt::{self, Debug};
|
||||
use core::fmt::{self, Debug};
|
||||
use std::thread::{self, ThreadId};
|
||||
|
||||
/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value
|
||||
@@ -49,7 +49,7 @@ impl<T: Debug> Debug for ThreadBound<T> {
|
||||
//
|
||||
// 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
|
||||
// core::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> {}
|
||||
|
||||
|
||||
+62
-106
@@ -98,12 +98,15 @@ use crate::error::Result;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::lifetime::Lifetime;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr};
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::lookahead;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::span::IntoSpans;
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use core::cmp;
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use core::fmt::{self, Debug};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use proc_macro2::extra::DelimSpan;
|
||||
use proc_macro2::Span;
|
||||
#[cfg(feature = "printing")]
|
||||
@@ -113,14 +116,7 @@ use proc_macro2::{Delimiter, Ident};
|
||||
#[cfg(feature = "parsing")]
|
||||
use proc_macro2::{Literal, Punct, TokenTree};
|
||||
#[cfg(feature = "printing")]
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::cmp;
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::fmt::{self, Debug};
|
||||
#[cfg(feature = "extra-traits")]
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
/// Marker trait for types that represent single tokens.
|
||||
///
|
||||
@@ -147,7 +143,7 @@ pub(crate) mod private {
|
||||
/// Support writing `token.span` rather than `token.spans[0]` on tokens that
|
||||
/// hold a single span.
|
||||
#[repr(transparent)]
|
||||
#[allow(unknown_lints, repr_transparent_external_private_fields)] // False positive: https://github.com/rust-lang/rust/issues/78586#issuecomment-1722680482
|
||||
#[allow(unknown_lints, repr_transparent_non_zst_fields)] // False positive: https://github.com/rust-lang/rust/issues/115922
|
||||
pub struct WithSpan {
|
||||
pub span: Span,
|
||||
}
|
||||
@@ -164,54 +160,10 @@ pub(crate) mod private {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl private::Sealed for Ident {}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool {
|
||||
use crate::parse::Unexpected;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
let scope = Span::call_site();
|
||||
let unexpected = Rc::new(Cell::new(Unexpected::None));
|
||||
let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected);
|
||||
peek(&buffer)
|
||||
}
|
||||
|
||||
macro_rules! impl_token {
|
||||
($display:literal $name:ty) => {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for $name {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
fn peek(input: ParseStream) -> bool {
|
||||
<$name as Parse>::parse(input).is_ok()
|
||||
}
|
||||
peek_impl(cursor, peek)
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
$display
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl private::Sealed for $name {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_token!("lifetime" Lifetime);
|
||||
impl_token!("literal" Lit);
|
||||
impl_token!("string literal" LitStr);
|
||||
impl_token!("byte string literal" LitByteStr);
|
||||
impl_token!("byte literal" LitByte);
|
||||
impl_token!("character literal" LitChar);
|
||||
impl_token!("integer literal" LitInt);
|
||||
impl_token!("floating point literal" LitFloat);
|
||||
impl_token!("boolean literal" LitBool);
|
||||
impl_token!("group token" proc_macro2::Group);
|
||||
|
||||
macro_rules! impl_low_level_token {
|
||||
($display:literal $ty:ident $get:ident) => {
|
||||
($display:literal $($path:ident)::+ $get:ident) => {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for $ty {
|
||||
impl Token for $($path)::+ {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
cursor.$get().is_some()
|
||||
}
|
||||
@@ -222,13 +174,15 @@ macro_rules! impl_low_level_token {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl private::Sealed for $ty {}
|
||||
impl private::Sealed for $($path)::+ {}
|
||||
};
|
||||
}
|
||||
|
||||
impl_low_level_token!("punctuation token" Punct punct);
|
||||
impl_low_level_token!("literal" Literal literal);
|
||||
impl_low_level_token!("token" TokenTree token_tree);
|
||||
impl_low_level_token!("group token" proc_macro2::Group any_group);
|
||||
impl_low_level_token!("lifetime" Lifetime lifetime);
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl<T: CustomToken> private::Sealed for T {}
|
||||
@@ -265,7 +219,7 @@ macro_rules! define_keywords {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for $name {
|
||||
impl core::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
$name {
|
||||
span: Span::call_site(),
|
||||
@@ -274,11 +228,11 @@ macro_rules! define_keywords {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for $name {}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
@@ -286,7 +240,7 @@ macro_rules! define_keywords {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(stringify!($name))
|
||||
@@ -294,11 +248,11 @@ macro_rules! define_keywords {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl cmp::Eq for $name {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for $name {
|
||||
fn eq(&self, _other: &$name) -> bool {
|
||||
true
|
||||
@@ -306,13 +260,13 @@ macro_rules! define_keywords {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for $name {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for $name {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
printing::keyword($token, self.span, tokens);
|
||||
@@ -320,7 +274,7 @@ macro_rules! define_keywords {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for $name {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok($name {
|
||||
@@ -370,7 +324,7 @@ macro_rules! define_punctuation_structs {
|
||||
($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => {
|
||||
$(
|
||||
#[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
|
||||
#[allow(unknown_lints, repr_transparent_non_zst_fields)] // False positive: https://github.com/rust-lang/rust/issues/115922
|
||||
#[doc = concat!('`', $token, '`')]
|
||||
///
|
||||
/// Usage:
|
||||
@@ -392,7 +346,7 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for $name {
|
||||
impl core::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
$name {
|
||||
spans: [Span::call_site(); $len],
|
||||
@@ -401,11 +355,11 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for $name {}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
@@ -413,7 +367,7 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(stringify!($name))
|
||||
@@ -421,11 +375,11 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl cmp::Eq for $name {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for $name {
|
||||
fn eq(&self, _other: &$name) -> bool {
|
||||
true
|
||||
@@ -433,7 +387,7 @@ macro_rules! define_punctuation_structs {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for $name {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
@@ -451,7 +405,7 @@ macro_rules! define_punctuation {
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for $name {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
printing::punct($token, &self.spans, tokens);
|
||||
@@ -459,7 +413,7 @@ macro_rules! define_punctuation {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for $name {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok($name {
|
||||
@@ -501,18 +455,18 @@ macro_rules! define_delimiters {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for $name {
|
||||
impl core::default::Default for $name {
|
||||
fn default() -> Self {
|
||||
$name(Span::call_site())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for $name {}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
@@ -520,7 +474,7 @@ macro_rules! define_delimiters {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(stringify!($name))
|
||||
@@ -528,11 +482,11 @@ macro_rules! define_delimiters {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl cmp::Eq for $name {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for $name {
|
||||
fn eq(&self, _other: &$name) -> bool {
|
||||
true
|
||||
@@ -540,13 +494,14 @@ macro_rules! define_delimiters {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for $name {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
|
||||
where
|
||||
F: FnOnce(&mut TokenStream),
|
||||
@@ -568,7 +523,7 @@ define_punctuation_structs! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Underscore {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append(Ident::new("_", self.span));
|
||||
@@ -576,7 +531,7 @@ impl ToTokens for Underscore {
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Underscore {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
input.step(|cursor| {
|
||||
@@ -628,7 +583,7 @@ pub fn Group<S: IntoSpans<Span>>(span: S) -> Group {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for Group {
|
||||
impl core::default::Default for Group {
|
||||
fn default() -> Self {
|
||||
Group {
|
||||
span: Span::call_site(),
|
||||
@@ -637,11 +592,11 @@ impl std::default::Default for Group {
|
||||
}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Copy for Group {}
|
||||
|
||||
#[cfg(feature = "clone-impls")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))]
|
||||
impl Clone for Group {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
@@ -649,7 +604,7 @@ impl Clone for Group {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Debug for Group {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("Group")
|
||||
@@ -657,11 +612,11 @@ impl Debug for Group {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl cmp::Eq for Group {}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl PartialEq for Group {
|
||||
fn eq(&self, _other: &Group) -> bool {
|
||||
true
|
||||
@@ -669,13 +624,14 @@ impl PartialEq for Group {
|
||||
}
|
||||
|
||||
#[cfg(feature = "extra-traits")]
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))]
|
||||
impl Hash for Group {
|
||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
impl Group {
|
||||
#[cfg(feature = "printing")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
pub fn surround<F>(&self, tokens: &mut TokenStream, f: F)
|
||||
where
|
||||
F: FnOnce(&mut TokenStream),
|
||||
@@ -692,7 +648,7 @@ impl private::Sealed for Group {}
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for Paren {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
lookahead::is_delimiter(cursor, Delimiter::Parenthesis)
|
||||
cursor.group(Delimiter::Parenthesis).is_some()
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
@@ -703,7 +659,7 @@ impl Token for Paren {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for Brace {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
lookahead::is_delimiter(cursor, Delimiter::Brace)
|
||||
cursor.group(Delimiter::Brace).is_some()
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
@@ -714,7 +670,7 @@ impl Token for Brace {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for Bracket {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
lookahead::is_delimiter(cursor, Delimiter::Bracket)
|
||||
cursor.group(Delimiter::Bracket).is_some()
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
@@ -725,7 +681,7 @@ impl Token for Bracket {
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Token for Group {
|
||||
fn peek(cursor: Cursor) -> bool {
|
||||
lookahead::is_delimiter(cursor, Delimiter::None)
|
||||
cursor.group(Delimiter::None).is_some()
|
||||
}
|
||||
|
||||
fn display() -> &'static str {
|
||||
@@ -767,6 +723,7 @@ define_keywords! {
|
||||
"override" pub struct Override
|
||||
"priv" pub struct Priv
|
||||
"pub" pub struct Pub
|
||||
"raw" pub struct Raw
|
||||
"ref" pub struct Ref
|
||||
"return" pub struct Return
|
||||
"Self" pub struct SelfType
|
||||
@@ -945,6 +902,7 @@ macro_rules! Token {
|
||||
[override] => { $crate::token::Override };
|
||||
[priv] => { $crate::token::Priv };
|
||||
[pub] => { $crate::token::Pub };
|
||||
[raw] => { $crate::token::Raw };
|
||||
[ref] => { $crate::token::Ref };
|
||||
[return] => { $crate::token::Return };
|
||||
[Self] => { $crate::token::SelfType };
|
||||
@@ -1020,6 +978,7 @@ pub(crate) mod parsing {
|
||||
use crate::buffer::Cursor;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::parse::ParseStream;
|
||||
use alloc::format;
|
||||
use proc_macro2::{Spacing, Span};
|
||||
|
||||
pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> {
|
||||
@@ -1099,8 +1058,9 @@ pub(crate) mod parsing {
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "printing")]
|
||||
pub(crate) mod printing {
|
||||
use crate::ext::PunctExt as _;
|
||||
use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream};
|
||||
use quote::TokenStreamExt;
|
||||
use quote::TokenStreamExt as _;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) {
|
||||
@@ -1111,14 +1071,10 @@ pub(crate) mod printing {
|
||||
let ch = chars.next_back().unwrap();
|
||||
let span = spans.next_back().unwrap();
|
||||
for (ch, span) in chars.zip(spans) {
|
||||
let mut op = Punct::new(ch, Spacing::Joint);
|
||||
op.set_span(*span);
|
||||
tokens.append(op);
|
||||
tokens.append(Punct::new_spanned(ch, Spacing::Joint, *span));
|
||||
}
|
||||
|
||||
let mut op = Punct::new(ch, Spacing::Alone);
|
||||
op.set_span(*span);
|
||||
tokens.append(op);
|
||||
tokens.append(Punct::new_spanned(ch, Spacing::Alone, *span));
|
||||
}
|
||||
|
||||
pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use proc_macro2::{Delimiter, TokenStream, TokenTree};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use alloc::string::ToString;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use proc_macro2::{Delimiter, Spacing, TokenStream, TokenTree};
|
||||
|
||||
pub(crate) struct TokenTreeHelper<'a>(pub &'a TokenTree);
|
||||
|
||||
impl<'a> PartialEq for TokenTreeHelper<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use proc_macro2::Spacing;
|
||||
|
||||
match (self.0, other.0) {
|
||||
(TokenTree::Group(g1), TokenTree::Group(g2)) => {
|
||||
match (g1.delimiter(), g2.delimiter()) {
|
||||
@@ -17,19 +16,7 @@ impl<'a> PartialEq for TokenTreeHelper<'a> {
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
let s1 = g1.stream().into_iter();
|
||||
let mut s2 = g2.stream().into_iter();
|
||||
|
||||
for item1 in s1 {
|
||||
let item2 = match s2.next() {
|
||||
Some(item) => item,
|
||||
None => return false,
|
||||
};
|
||||
if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
s2.next().is_none()
|
||||
TokenStreamHelper(&g1.stream()) == TokenStreamHelper(&g2.stream())
|
||||
}
|
||||
(TokenTree::Punct(o1), TokenTree::Punct(o2)) => {
|
||||
o1.as_char() == o2.as_char()
|
||||
@@ -47,8 +34,6 @@ impl<'a> PartialEq for TokenTreeHelper<'a> {
|
||||
|
||||
impl<'a> Hash for TokenTreeHelper<'a> {
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
use proc_macro2::Spacing;
|
||||
|
||||
match self.0 {
|
||||
TokenTree::Group(g) => {
|
||||
0u8.hash(h);
|
||||
@@ -62,7 +47,7 @@ impl<'a> Hash for TokenTreeHelper<'a> {
|
||||
for item in g.stream() {
|
||||
TokenTreeHelper(&item).hash(h);
|
||||
}
|
||||
0xffu8.hash(h); // terminator w/ a variant we don't normally hash
|
||||
0xFFu8.hash(h); // terminator w/ a variant we don't normally hash
|
||||
}
|
||||
TokenTree::Punct(op) => {
|
||||
1u8.hash(h);
|
||||
@@ -82,25 +67,30 @@ pub(crate) struct TokenStreamHelper<'a>(pub &'a TokenStream);
|
||||
|
||||
impl<'a> PartialEq for TokenStreamHelper<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let left = self.0.clone().into_iter().collect::<Vec<_>>();
|
||||
let right = other.0.clone().into_iter().collect::<Vec<_>>();
|
||||
if left.len() != right.len() {
|
||||
return false;
|
||||
}
|
||||
for (a, b) in left.into_iter().zip(right) {
|
||||
if TokenTreeHelper(&a) != TokenTreeHelper(&b) {
|
||||
let left = self.0.clone().into_iter();
|
||||
let mut right = other.0.clone().into_iter();
|
||||
|
||||
for item1 in left {
|
||||
let item2 = match right.next() {
|
||||
Some(item) => item,
|
||||
None => return false,
|
||||
};
|
||||
if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
|
||||
right.next().is_none()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Hash for TokenStreamHelper<'a> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let tts = self.0.clone().into_iter().collect::<Vec<_>>();
|
||||
tts.len().hash(state);
|
||||
for tt in tts {
|
||||
let tokens = self.0.clone().into_iter();
|
||||
|
||||
tokens.clone().count().hash(state);
|
||||
|
||||
for tt in tokens {
|
||||
TokenTreeHelper(&tt).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::expr::Expr;
|
||||
use crate::generics::{BoundLifetimes, TypeParamBound};
|
||||
use crate::ident::Ident;
|
||||
use crate::lifetime::Lifetime;
|
||||
use crate::lit::LitStr;
|
||||
use crate::mac::Macro;
|
||||
use crate::path::{Path, QSelf};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
ast_enum_of_structs! {
|
||||
@@ -9,8 +19,8 @@ ast_enum_of_structs! {
|
||||
///
|
||||
/// 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"))))]
|
||||
/// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[non_exhaustive]
|
||||
pub enum Type {
|
||||
/// A fixed size array type: `[T; n]`.
|
||||
@@ -38,7 +48,7 @@ ast_enum_of_structs! {
|
||||
/// A parenthesized type equivalent to the inner type.
|
||||
Paren(TypeParen),
|
||||
|
||||
/// A path like `std::slice::Iter`, optionally qualified with a
|
||||
/// A path like `core::slice::Iter`, optionally qualified with a
|
||||
/// self-type as in `<Vec<T> as SomeTrait>::Associated`.
|
||||
Path(TypePath),
|
||||
|
||||
@@ -83,7 +93,7 @@ ast_enum_of_structs! {
|
||||
|
||||
ast_struct! {
|
||||
/// A fixed size array type: `[T; n]`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeArray {
|
||||
pub bracket_token: token::Bracket,
|
||||
pub elem: Box<Type>,
|
||||
@@ -94,7 +104,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A bare function type: `fn(usize) -> bool`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeBareFn {
|
||||
pub lifetimes: Option<BoundLifetimes>,
|
||||
pub unsafety: Option<Token![unsafe]>,
|
||||
@@ -109,7 +119,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A type contained within invisible delimiters.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeGroup {
|
||||
pub group_token: token::Group,
|
||||
pub elem: Box<Type>,
|
||||
@@ -119,7 +129,7 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
|
||||
/// a lifetime.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeImplTrait {
|
||||
pub impl_token: Token![impl],
|
||||
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
||||
@@ -128,7 +138,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// Indication that a type should be inferred by the compiler: `_`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeInfer {
|
||||
pub underscore_token: Token![_],
|
||||
}
|
||||
@@ -136,7 +146,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A macro in the type position.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeMacro {
|
||||
pub mac: Macro,
|
||||
}
|
||||
@@ -144,7 +154,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The never type: `!`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeNever {
|
||||
pub bang_token: Token![!],
|
||||
}
|
||||
@@ -152,7 +162,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A parenthesized type equivalent to the inner type.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeParen {
|
||||
pub paren_token: token::Paren,
|
||||
pub elem: Box<Type>,
|
||||
@@ -160,9 +170,9 @@ ast_struct! {
|
||||
}
|
||||
|
||||
ast_struct! {
|
||||
/// A path like `std::slice::Iter`, optionally qualified with a
|
||||
/// A path like `core::slice::Iter`, optionally qualified with a
|
||||
/// self-type as in `<Vec<T> as SomeTrait>::Associated`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypePath {
|
||||
pub qself: Option<QSelf>,
|
||||
pub path: Path,
|
||||
@@ -171,7 +181,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A raw pointer type: `*const T` or `*mut T`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypePtr {
|
||||
pub star_token: Token![*],
|
||||
pub const_token: Option<Token![const]>,
|
||||
@@ -182,7 +192,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A reference type: `&'a T` or `&'a mut T`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeReference {
|
||||
pub and_token: Token![&],
|
||||
pub lifetime: Option<Lifetime>,
|
||||
@@ -193,7 +203,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A dynamically sized slice type: `[T]`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeSlice {
|
||||
pub bracket_token: token::Bracket,
|
||||
pub elem: Box<Type>,
|
||||
@@ -203,7 +213,7 @@ ast_struct! {
|
||||
ast_struct! {
|
||||
/// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a
|
||||
/// trait or a lifetime.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeTraitObject {
|
||||
pub dyn_token: Option<Token![dyn]>,
|
||||
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
||||
@@ -212,7 +222,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// A tuple type: `(A, B, C, String)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct TypeTuple {
|
||||
pub paren_token: token::Paren,
|
||||
pub elems: Punctuated<Type, Token![,]>,
|
||||
@@ -221,7 +231,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The binary interface of a function: `extern "C"`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct Abi {
|
||||
pub extern_token: Token![extern],
|
||||
pub name: Option<LitStr>,
|
||||
@@ -230,7 +240,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// An argument in a function type: the `usize` in `fn(usize) -> bool`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct BareFnArg {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub name: Option<(Ident, Token![:])>,
|
||||
@@ -240,7 +250,7 @@ ast_struct! {
|
||||
|
||||
ast_struct! {
|
||||
/// The variadic argument of a function pointer like `fn(usize, ...)`.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub struct BareVariadic {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub name: Option<(Ident, Token![:])>,
|
||||
@@ -251,7 +261,7 @@ ast_struct! {
|
||||
|
||||
ast_enum! {
|
||||
/// Return type of a function signature.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
|
||||
pub enum ReturnType {
|
||||
/// Return type is not specified.
|
||||
///
|
||||
@@ -264,13 +274,29 @@ ast_enum! {
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
pub(crate) mod parsing {
|
||||
use super::*;
|
||||
use crate::attr::Attribute;
|
||||
use crate::error::{self, Result};
|
||||
use crate::ext::IdentExt as _;
|
||||
use crate::parse::{Parse, ParseStream, Result};
|
||||
use crate::generics::{BoundLifetimes, TraitBound, TraitBoundModifier, TypeParamBound};
|
||||
use crate::ident::Ident;
|
||||
use crate::lifetime::Lifetime;
|
||||
use crate::mac::{self, Macro};
|
||||
use crate::parse::{Parse, ParseStream};
|
||||
use crate::path;
|
||||
use crate::path::{Path, PathArguments, QSelf};
|
||||
use crate::punctuated::Punctuated;
|
||||
use crate::token;
|
||||
use crate::ty::{
|
||||
Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup,
|
||||
TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr,
|
||||
TypeReference, TypeSlice, TypeTraitObject, TypeTuple,
|
||||
};
|
||||
use crate::verbatim;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use proc_macro2::Span;
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Type {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = true;
|
||||
@@ -285,7 +311,7 @@ pub(crate) mod parsing {
|
||||
/// contain a `+` character.
|
||||
///
|
||||
/// This parser does not allow a `+`, while the default parser does.
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn without_plus(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = false;
|
||||
let allow_group_generic = true;
|
||||
@@ -328,7 +354,7 @@ pub(crate) mod parsing {
|
||||
Path::parse_rest(input, &mut ty.path, false)?;
|
||||
return Ok(Type::Path(ty));
|
||||
} else {
|
||||
group.elem = Box::new(Type::Path(ty));
|
||||
*group.elem = Type::Path(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,7 +406,15 @@ pub(crate) mod parsing {
|
||||
}));
|
||||
while let Some(plus) = input.parse()? {
|
||||
bounds.push_punct(plus);
|
||||
bounds.push_value(input.parse()?);
|
||||
bounds.push_value({
|
||||
let allow_precise_capture = false;
|
||||
let allow_const = false;
|
||||
TypeParamBound::parse_single(
|
||||
input,
|
||||
allow_precise_capture,
|
||||
allow_const,
|
||||
)?
|
||||
});
|
||||
}
|
||||
bounds
|
||||
},
|
||||
@@ -435,6 +469,7 @@ pub(crate) mod parsing {
|
||||
})
|
||||
}
|
||||
other @ (TypeParamBound::Lifetime(_)
|
||||
| TypeParamBound::PreciseCapture(_)
|
||||
| TypeParamBound::Verbatim(_)) => other,
|
||||
}
|
||||
}
|
||||
@@ -447,7 +482,15 @@ pub(crate) mod parsing {
|
||||
bounds.push_value(first);
|
||||
while let Some(plus) = input.parse()? {
|
||||
bounds.push_punct(plus);
|
||||
bounds.push_value(input.parse()?);
|
||||
bounds.push_value({
|
||||
let allow_precise_capture = false;
|
||||
let allow_const = false;
|
||||
TypeParamBound::parse_single(
|
||||
input,
|
||||
allow_precise_capture,
|
||||
allow_const,
|
||||
)?
|
||||
});
|
||||
}
|
||||
bounds
|
||||
},
|
||||
@@ -510,7 +553,11 @@ pub(crate) mod parsing {
|
||||
{
|
||||
break;
|
||||
}
|
||||
bounds.push_value(input.parse()?);
|
||||
bounds.push_value({
|
||||
let allow_precise_capture = false;
|
||||
let allow_const = false;
|
||||
TypeParamBound::parse_single(input, allow_precise_capture, allow_const)?
|
||||
});
|
||||
}
|
||||
}
|
||||
return Ok(Type::TraitObject(TypeTraitObject {
|
||||
@@ -525,14 +572,14 @@ pub(crate) mod parsing {
|
||||
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() {
|
||||
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);
|
||||
@@ -567,7 +614,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeSlice {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -578,7 +625,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeArray {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -591,7 +638,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypePtr {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let star_token: Token![*] = input.parse()?;
|
||||
@@ -614,7 +661,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeReference {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(TypeReference {
|
||||
@@ -627,7 +674,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeBareFn {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let args;
|
||||
@@ -647,7 +694,7 @@ pub(crate) mod parsing {
|
||||
|
||||
if inputs.empty_or_trailing()
|
||||
&& (args.peek(Token![...])
|
||||
|| args.peek(Ident)
|
||||
|| (args.peek(Ident) || args.peek(Token![_]))
|
||||
&& args.peek2(Token![:])
|
||||
&& args.peek3(Token![...]))
|
||||
{
|
||||
@@ -674,7 +721,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeNever {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(TypeNever {
|
||||
@@ -683,7 +730,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeInfer {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(TypeInfer {
|
||||
@@ -692,7 +739,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeTuple {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
@@ -725,7 +772,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeMacro {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(TypeMacro {
|
||||
@@ -734,7 +781,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypePath {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let expr_style = false;
|
||||
@@ -744,7 +791,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
impl ReturnType {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn without_plus(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = false;
|
||||
Self::parse(input, allow_plus)
|
||||
@@ -762,7 +809,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for ReturnType {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = true;
|
||||
@@ -770,7 +817,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeTraitObject {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = true;
|
||||
@@ -779,7 +826,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
impl TypeTraitObject {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn without_plus(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = false;
|
||||
Self::parse(input, allow_plus)
|
||||
@@ -801,18 +848,28 @@ pub(crate) mod parsing {
|
||||
input: ParseStream,
|
||||
allow_plus: bool,
|
||||
) -> Result<Punctuated<TypeParamBound, Token![+]>> {
|
||||
let bounds = TypeParamBound::parse_multiple(input, allow_plus)?;
|
||||
let allow_precise_capture = false;
|
||||
let allow_const = false;
|
||||
let bounds = TypeParamBound::parse_multiple(
|
||||
input,
|
||||
allow_plus,
|
||||
allow_precise_capture,
|
||||
allow_const,
|
||||
)?;
|
||||
let mut last_lifetime_span = None;
|
||||
let mut at_least_one_trait = false;
|
||||
for bound in &bounds {
|
||||
match bound {
|
||||
TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => {
|
||||
TypeParamBound::Trait(_) => {
|
||||
at_least_one_trait = true;
|
||||
break;
|
||||
}
|
||||
TypeParamBound::Lifetime(lifetime) => {
|
||||
last_lifetime_span = Some(lifetime.ident.span());
|
||||
}
|
||||
TypeParamBound::PreciseCapture(_) | TypeParamBound::Verbatim(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just lifetimes like `'a + 'b` is not a TraitObject.
|
||||
@@ -824,7 +881,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeImplTrait {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = true;
|
||||
@@ -833,7 +890,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
|
||||
impl TypeImplTrait {
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
pub fn without_plus(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = false;
|
||||
Self::parse(input, allow_plus)
|
||||
@@ -841,17 +898,40 @@ pub(crate) mod parsing {
|
||||
|
||||
pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> {
|
||||
let impl_token: Token![impl] = input.parse()?;
|
||||
let bounds = TypeParamBound::parse_multiple(input, allow_plus)?;
|
||||
let mut last_lifetime_span = None;
|
||||
let allow_precise_capture = true;
|
||||
let allow_const = true;
|
||||
let bounds = TypeParamBound::parse_multiple(
|
||||
input,
|
||||
allow_plus,
|
||||
allow_precise_capture,
|
||||
allow_const,
|
||||
)?;
|
||||
let mut last_nontrait_span = None;
|
||||
let mut at_least_one_trait = false;
|
||||
for bound in &bounds {
|
||||
match bound {
|
||||
TypeParamBound::Trait(_) | TypeParamBound::Verbatim(_) => {
|
||||
TypeParamBound::Trait(_) => {
|
||||
at_least_one_trait = true;
|
||||
break;
|
||||
}
|
||||
TypeParamBound::Lifetime(lifetime) => {
|
||||
last_lifetime_span = Some(lifetime.ident.span());
|
||||
last_nontrait_span = Some(lifetime.ident.span());
|
||||
}
|
||||
TypeParamBound::PreciseCapture(precise_capture) => {
|
||||
#[cfg(feature = "full")]
|
||||
{
|
||||
last_nontrait_span = Some(precise_capture.gt_token.span);
|
||||
}
|
||||
#[cfg(not(feature = "full"))]
|
||||
{
|
||||
_ = precise_capture;
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
TypeParamBound::Verbatim(_) => {
|
||||
// `[const] Trait`
|
||||
at_least_one_trait = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -859,7 +939,7 @@ pub(crate) mod parsing {
|
||||
let msg = "at least one trait must be specified";
|
||||
return Err(error::new2(
|
||||
impl_token.span,
|
||||
last_lifetime_span.unwrap(),
|
||||
last_nontrait_span.unwrap(),
|
||||
msg,
|
||||
));
|
||||
}
|
||||
@@ -867,7 +947,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeGroup {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let group = crate::group::parse_group(input)?;
|
||||
@@ -878,7 +958,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for TypeParen {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_plus = false;
|
||||
@@ -899,7 +979,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for BareFnArg {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let allow_self = false;
|
||||
@@ -970,7 +1050,7 @@ pub(crate) mod parsing {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Abi {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
Ok(Abi {
|
||||
@@ -980,7 +1060,7 @@ pub(crate) mod parsing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
|
||||
impl Parse for Option<Abi> {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
if input.peek(Token![extern]) {
|
||||
@@ -994,13 +1074,19 @@ pub(crate) mod parsing {
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
mod printing {
|
||||
use super::*;
|
||||
use crate::attr::FilterAttrs;
|
||||
use crate::path;
|
||||
use crate::path::printing::PathStyle;
|
||||
use crate::print::TokensOrDefault;
|
||||
use crate::ty::{
|
||||
Abi, BareFnArg, BareVariadic, ReturnType, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait,
|
||||
TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice,
|
||||
TypeTraitObject, TypeTuple,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeSlice {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.bracket_token.surround(tokens, |tokens| {
|
||||
@@ -1009,7 +1095,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeArray {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.bracket_token.surround(tokens, |tokens| {
|
||||
@@ -1020,7 +1106,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypePtr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.star_token.to_tokens(tokens);
|
||||
@@ -1034,7 +1120,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeReference {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.and_token.to_tokens(tokens);
|
||||
@@ -1044,7 +1130,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeBareFn {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.lifetimes.to_tokens(tokens);
|
||||
@@ -1065,14 +1151,14 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeNever {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.bang_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeTuple {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
@@ -1086,14 +1172,14 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypePath {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
path::printing::print_path(tokens, &self.qself, &self.path);
|
||||
path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::AsWritten);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeTraitObject {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.dyn_token.to_tokens(tokens);
|
||||
@@ -1101,7 +1187,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeImplTrait {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.impl_token.to_tokens(tokens);
|
||||
@@ -1109,7 +1195,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeGroup {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.group_token.surround(tokens, |tokens| {
|
||||
@@ -1118,7 +1204,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeParen {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.paren_token.surround(tokens, |tokens| {
|
||||
@@ -1127,21 +1213,21 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeInfer {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.underscore_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for TypeMacro {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.mac.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for ReturnType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
@@ -1154,7 +1240,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for BareFnArg {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -1166,7 +1252,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for BareVariadic {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append_all(self.attrs.outer());
|
||||
@@ -1179,7 +1265,7 @@ mod printing {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
|
||||
impl ToTokens for Abi {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.extern_token.to_tokens(tokens);
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
use crate::ext::TokenStreamExt as _;
|
||||
use crate::parse::ParseStream;
|
||||
use core::cmp::Ordering;
|
||||
use proc_macro2::{Delimiter, TokenStream};
|
||||
use std::cmp::Ordering;
|
||||
use std::iter;
|
||||
|
||||
pub(crate) fn between<'a>(begin: ParseStream<'a>, end: ParseStream<'a>) -> TokenStream {
|
||||
let end = end.cursor();
|
||||
@@ -26,7 +26,7 @@ pub(crate) fn between<'a>(begin: ParseStream<'a>, end: ParseStream<'a>) -> Token
|
||||
}
|
||||
}
|
||||
|
||||
tokens.extend(iter::once(tt));
|
||||
tokens.append(tt);
|
||||
cursor = next;
|
||||
}
|
||||
tokens
|
||||
|
||||
+2
-2
@@ -41,11 +41,11 @@ pub(crate) fn skip(mut s: &str) -> &str {
|
||||
}
|
||||
}
|
||||
match byte {
|
||||
b' ' | 0x09..=0x0d => {
|
||||
b' ' | 0x09..=0x0D => {
|
||||
s = &s[1..];
|
||||
continue;
|
||||
}
|
||||
b if b <= 0x7f => {}
|
||||
b if b <= 0x7F => {}
|
||||
_ => {
|
||||
let ch = s.chars().next().unwrap();
|
||||
if is_whitespace(ch) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.0.48",
|
||||
"version": "2.0.114",
|
||||
"types": [
|
||||
{
|
||||
"ident": "Abi",
|
||||
@@ -450,6 +450,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "CapturedParam",
|
||||
"features": {
|
||||
"any": [
|
||||
"full"
|
||||
]
|
||||
},
|
||||
"variants": {
|
||||
"Lifetime": [
|
||||
{
|
||||
"syn": "Lifetime"
|
||||
}
|
||||
],
|
||||
"Ident": [
|
||||
{
|
||||
"proc_macro2": "Ident"
|
||||
}
|
||||
]
|
||||
},
|
||||
"exhaustive": false
|
||||
},
|
||||
{
|
||||
"ident": "ConstParam",
|
||||
"features": {
|
||||
@@ -775,6 +796,11 @@
|
||||
"syn": "ExprRange"
|
||||
}
|
||||
],
|
||||
"RawAddr": [
|
||||
{
|
||||
"syn": "ExprRawAddr"
|
||||
}
|
||||
],
|
||||
"Reference": [
|
||||
{
|
||||
"syn": "ExprReference"
|
||||
@@ -1619,6 +1645,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "ExprRawAddr",
|
||||
"features": {
|
||||
"any": [
|
||||
"full"
|
||||
]
|
||||
},
|
||||
"fields": {
|
||||
"attrs": {
|
||||
"vec": {
|
||||
"syn": "Attribute"
|
||||
}
|
||||
},
|
||||
"and_token": {
|
||||
"token": "And"
|
||||
},
|
||||
"raw": {
|
||||
"token": "Raw"
|
||||
},
|
||||
"mutability": {
|
||||
"syn": "PointerMutability"
|
||||
},
|
||||
"expr": {
|
||||
"box": {
|
||||
"syn": "Expr"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "ExprReference",
|
||||
"features": {
|
||||
@@ -1799,6 +1854,7 @@
|
||||
"ident": "ExprTuple",
|
||||
"features": {
|
||||
"any": [
|
||||
"derive",
|
||||
"full"
|
||||
]
|
||||
},
|
||||
@@ -3366,6 +3422,11 @@
|
||||
"syn": "LitByteStr"
|
||||
}
|
||||
],
|
||||
"CStr": [
|
||||
{
|
||||
"syn": "LitCStr"
|
||||
}
|
||||
],
|
||||
"Byte": [
|
||||
{
|
||||
"syn": "LitByte"
|
||||
@@ -3425,6 +3486,12 @@
|
||||
"any": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "LitCStr",
|
||||
"features": {
|
||||
"any": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "LitChar",
|
||||
"features": {
|
||||
@@ -4140,6 +4207,53 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "PointerMutability",
|
||||
"features": {
|
||||
"any": [
|
||||
"full"
|
||||
]
|
||||
},
|
||||
"variants": {
|
||||
"Const": [
|
||||
{
|
||||
"token": "Const"
|
||||
}
|
||||
],
|
||||
"Mut": [
|
||||
{
|
||||
"token": "Mut"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "PreciseCapture",
|
||||
"features": {
|
||||
"any": [
|
||||
"full"
|
||||
]
|
||||
},
|
||||
"fields": {
|
||||
"use_token": {
|
||||
"token": "Use"
|
||||
},
|
||||
"lt_token": {
|
||||
"token": "Lt"
|
||||
},
|
||||
"params": {
|
||||
"punctuated": {
|
||||
"element": {
|
||||
"syn": "CapturedParam"
|
||||
},
|
||||
"punct": "Comma"
|
||||
}
|
||||
},
|
||||
"gt_token": {
|
||||
"token": "Gt"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ident": "PredicateLifetime",
|
||||
"features": {
|
||||
@@ -4979,6 +5093,11 @@
|
||||
"syn": "Lifetime"
|
||||
}
|
||||
],
|
||||
"PreciseCapture": [
|
||||
{
|
||||
"syn": "PreciseCapture"
|
||||
}
|
||||
],
|
||||
"Verbatim": [
|
||||
{
|
||||
"proc_macro2": "TokenStream"
|
||||
@@ -5532,6 +5651,7 @@
|
||||
"Pub": "pub",
|
||||
"Question": "?",
|
||||
"RArrow": "->",
|
||||
"Raw": "raw",
|
||||
"Ref": "ref",
|
||||
"Return": "return",
|
||||
"SelfType": "Self",
|
||||
|
||||
+159
-133
@@ -10,22 +10,23 @@ use rustc_ast::ast::AngleBracketedArg;
|
||||
use rustc_ast::ast::AngleBracketedArgs;
|
||||
use rustc_ast::ast::AnonConst;
|
||||
use rustc_ast::ast::Arm;
|
||||
use rustc_ast::ast::AssocConstraint;
|
||||
use rustc_ast::ast::AssocConstraintKind;
|
||||
use rustc_ast::ast::AsmMacro;
|
||||
use rustc_ast::ast::AssignOpKind;
|
||||
use rustc_ast::ast::AssocItemConstraint;
|
||||
use rustc_ast::ast::AssocItemConstraintKind;
|
||||
use rustc_ast::ast::AssocItemKind;
|
||||
use rustc_ast::ast::AttrArgs;
|
||||
use rustc_ast::ast::AttrArgsEq;
|
||||
use rustc_ast::ast::AttrId;
|
||||
use rustc_ast::ast::AttrItem;
|
||||
use rustc_ast::ast::AttrKind;
|
||||
use rustc_ast::ast::AttrStyle;
|
||||
use rustc_ast::ast::Attribute;
|
||||
use rustc_ast::ast::BareFnTy;
|
||||
use rustc_ast::ast::BinOpKind;
|
||||
use rustc_ast::ast::BindingAnnotation;
|
||||
use rustc_ast::ast::BindingMode;
|
||||
use rustc_ast::ast::Block;
|
||||
use rustc_ast::ast::BlockCheckMode;
|
||||
use rustc_ast::ast::BorrowKind;
|
||||
use rustc_ast::ast::BoundAsyncness;
|
||||
use rustc_ast::ast::BoundConstness;
|
||||
use rustc_ast::ast::BoundPolarity;
|
||||
use rustc_ast::ast::ByRef;
|
||||
@@ -34,10 +35,15 @@ use rustc_ast::ast::Closure;
|
||||
use rustc_ast::ast::ClosureBinder;
|
||||
use rustc_ast::ast::Const;
|
||||
use rustc_ast::ast::ConstItem;
|
||||
use rustc_ast::ast::ConstItemRhs;
|
||||
use rustc_ast::ast::CoroutineKind;
|
||||
use rustc_ast::ast::Crate;
|
||||
use rustc_ast::ast::Defaultness;
|
||||
use rustc_ast::ast::Delegation;
|
||||
use rustc_ast::ast::DelegationMac;
|
||||
use rustc_ast::ast::DelimArgs;
|
||||
use rustc_ast::ast::EiiExternTarget;
|
||||
use rustc_ast::ast::EiiImpl;
|
||||
use rustc_ast::ast::EnumDef;
|
||||
use rustc_ast::ast::Expr;
|
||||
use rustc_ast::ast::ExprField;
|
||||
@@ -46,8 +52,10 @@ use rustc_ast::ast::Extern;
|
||||
use rustc_ast::ast::FieldDef;
|
||||
use rustc_ast::ast::FloatTy;
|
||||
use rustc_ast::ast::Fn;
|
||||
use rustc_ast::ast::FnContract;
|
||||
use rustc_ast::ast::FnDecl;
|
||||
use rustc_ast::ast::FnHeader;
|
||||
use rustc_ast::ast::FnPtrTy;
|
||||
use rustc_ast::ast::FnRetTy;
|
||||
use rustc_ast::ast::FnSig;
|
||||
use rustc_ast::ast::ForLoopKind;
|
||||
@@ -98,8 +106,13 @@ use rustc_ast::ast::MacCall;
|
||||
use rustc_ast::ast::MacCallStmt;
|
||||
use rustc_ast::ast::MacStmtStyle;
|
||||
use rustc_ast::ast::MacroDef;
|
||||
use rustc_ast::ast::MatchKind;
|
||||
use rustc_ast::ast::MetaItem;
|
||||
use rustc_ast::ast::MetaItemInner;
|
||||
use rustc_ast::ast::MetaItemKind;
|
||||
use rustc_ast::ast::MetaItemLit;
|
||||
use rustc_ast::ast::MethodCall;
|
||||
use rustc_ast::ast::MgcaDisambiguation;
|
||||
use rustc_ast::ast::ModKind;
|
||||
use rustc_ast::ast::ModSpans;
|
||||
use rustc_ast::ast::Movability;
|
||||
@@ -108,6 +121,7 @@ use rustc_ast::ast::Mutability;
|
||||
use rustc_ast::ast::NodeId;
|
||||
use rustc_ast::ast::NormalAttr;
|
||||
use rustc_ast::ast::Param;
|
||||
use rustc_ast::ast::Parens;
|
||||
use rustc_ast::ast::ParenthesizedArgs;
|
||||
use rustc_ast::ast::Pat;
|
||||
use rustc_ast::ast::PatField;
|
||||
@@ -115,11 +129,15 @@ use rustc_ast::ast::PatFieldsRest;
|
||||
use rustc_ast::ast::PatKind;
|
||||
use rustc_ast::ast::Path;
|
||||
use rustc_ast::ast::PathSegment;
|
||||
use rustc_ast::ast::Pinnedness;
|
||||
use rustc_ast::ast::PolyTraitRef;
|
||||
use rustc_ast::ast::PreciseCapturingArg;
|
||||
use rustc_ast::ast::QSelf;
|
||||
use rustc_ast::ast::RangeEnd;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_ast::ast::RangeSyntax;
|
||||
use rustc_ast::ast::Recovered;
|
||||
use rustc_ast::ast::Safety;
|
||||
use rustc_ast::ast::StaticItem;
|
||||
use rustc_ast::ast::Stmt;
|
||||
use rustc_ast::ast::StmtKind;
|
||||
@@ -129,16 +147,20 @@ use rustc_ast::ast::StructExpr;
|
||||
use rustc_ast::ast::StructRest;
|
||||
use rustc_ast::ast::Term;
|
||||
use rustc_ast::ast::Trait;
|
||||
use rustc_ast::ast::TraitAlias;
|
||||
use rustc_ast::ast::TraitBoundModifiers;
|
||||
use rustc_ast::ast::TraitImplHeader;
|
||||
use rustc_ast::ast::TraitObjectSyntax;
|
||||
use rustc_ast::ast::TraitRef;
|
||||
use rustc_ast::ast::Ty;
|
||||
use rustc_ast::ast::TyAlias;
|
||||
use rustc_ast::ast::TyAliasWhereClause;
|
||||
use rustc_ast::ast::TyKind;
|
||||
use rustc_ast::ast::TyPat;
|
||||
use rustc_ast::ast::TyPatKind;
|
||||
use rustc_ast::ast::UintTy;
|
||||
use rustc_ast::ast::UnOp;
|
||||
use rustc_ast::ast::Unsafe;
|
||||
use rustc_ast::ast::UnsafeBinderCastKind;
|
||||
use rustc_ast::ast::UnsafeBinderTy;
|
||||
use rustc_ast::ast::UnsafeSource;
|
||||
use rustc_ast::ast::UseTree;
|
||||
use rustc_ast::ast::UseTreeKind;
|
||||
@@ -150,19 +172,22 @@ use rustc_ast::ast::WhereBoundPredicate;
|
||||
use rustc_ast::ast::WhereClause;
|
||||
use rustc_ast::ast::WhereEqPredicate;
|
||||
use rustc_ast::ast::WherePredicate;
|
||||
use rustc_ast::ast::WherePredicateKind;
|
||||
use rustc_ast::ast::WhereRegionPredicate;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, Lit, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::ast::YieldKind;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Lit, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{
|
||||
AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing, DelimSpan, LazyAttrTokenStream,
|
||||
AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream,
|
||||
Spacing, TokenStream, TokenTree,
|
||||
};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, SyntaxContext, DUMMY_SP};
|
||||
use rustc_span::symbol::{sym, ByteSymbol, Ident, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Span, SyntaxContext, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::{BuildHasher, Hash};
|
||||
use std::sync::Arc;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
pub trait SpanlessEq {
|
||||
@@ -175,13 +200,7 @@ impl<T: ?Sized + SpanlessEq> SpanlessEq for Box<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + SpanlessEq> SpanlessEq for P<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
SpanlessEq::eq(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + SpanlessEq> SpanlessEq for Lrc<T> {
|
||||
impl<T: ?Sized + SpanlessEq> SpanlessEq for Arc<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
SpanlessEq::eq(&**self, &**other)
|
||||
}
|
||||
@@ -240,6 +259,12 @@ impl<K: Eq + Hash, V: SpanlessEq, S: BuildHasher> SpanlessEq for HashMap<K, V, S
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + ToOwned + SpanlessEq> SpanlessEq for Cow<'a, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
<T as SpanlessEq>::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
SpanlessEq::eq(&self.node, &other.node)
|
||||
@@ -287,6 +312,7 @@ macro_rules! spanless_eq_partial_eq {
|
||||
};
|
||||
}
|
||||
|
||||
spanless_eq_partial_eq!(());
|
||||
spanless_eq_partial_eq!(bool);
|
||||
spanless_eq_partial_eq!(u8);
|
||||
spanless_eq_partial_eq!(u16);
|
||||
@@ -294,8 +320,11 @@ spanless_eq_partial_eq!(u32);
|
||||
spanless_eq_partial_eq!(u128);
|
||||
spanless_eq_partial_eq!(usize);
|
||||
spanless_eq_partial_eq!(char);
|
||||
spanless_eq_partial_eq!(str);
|
||||
spanless_eq_partial_eq!(String);
|
||||
spanless_eq_partial_eq!(Pu128);
|
||||
spanless_eq_partial_eq!(Symbol);
|
||||
spanless_eq_partial_eq!(ByteSymbol);
|
||||
spanless_eq_partial_eq!(CommentKind);
|
||||
spanless_eq_partial_eq!(Delimiter);
|
||||
spanless_eq_partial_eq!(InlineAsmOptions);
|
||||
@@ -450,48 +479,54 @@ macro_rules! spanless_eq_enum {
|
||||
}
|
||||
|
||||
spanless_eq_struct!(AngleBracketedArgs; span args);
|
||||
spanless_eq_struct!(AnonConst; id value);
|
||||
spanless_eq_struct!(AnonConst; id value !mgca_disambiguation);
|
||||
spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder);
|
||||
spanless_eq_struct!(AssocConstraint; id ident gen_args kind span);
|
||||
spanless_eq_struct!(AttrItem; path args tokens);
|
||||
spanless_eq_struct!(AssocItemConstraint; id ident gen_args kind span);
|
||||
spanless_eq_struct!(AttrItem; unsafety path args tokens);
|
||||
spanless_eq_struct!(AttrTokenStream; 0);
|
||||
spanless_eq_struct!(Attribute; kind id style span);
|
||||
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!(AttrsTarget; attrs tokens);
|
||||
spanless_eq_struct!(BindingMode; 0 1);
|
||||
spanless_eq_struct!(Block; stmts id rules span tokens);
|
||||
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!(ConstItem; defaultness ident generics ty rhs define_opaque);
|
||||
spanless_eq_struct!(Crate; attrs items spans id is_placeholder);
|
||||
spanless_eq_struct!(Delegation; id qself path ident rename body from_glob);
|
||||
spanless_eq_struct!(DelegationMac; qself prefix suffixes body);
|
||||
spanless_eq_struct!(DelimArgs; dspan delim tokens);
|
||||
spanless_eq_struct!(DelimSpacing; open close);
|
||||
spanless_eq_struct!(EiiExternTarget; extern_item_path impl_unsafe span);
|
||||
spanless_eq_struct!(EiiImpl; node_id eii_macro_path impl_safety span inner_span is_default);
|
||||
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!(Fn; defaultness generics sig body);
|
||||
spanless_eq_struct!(FieldDef; attrs id span vis safety ident ty default is_placeholder);
|
||||
spanless_eq_struct!(Fn; defaultness ident generics sig contract define_opaque body eii_impls);
|
||||
spanless_eq_struct!(FnContract; declarations requires ensures);
|
||||
spanless_eq_struct!(FnDecl; inputs output);
|
||||
spanless_eq_struct!(FnHeader; constness coroutine_kind unsafety ext);
|
||||
spanless_eq_struct!(FnHeader; constness coroutine_kind safety ext);
|
||||
spanless_eq_struct!(FnPtrTy; safety ext generic_params decl decl_span);
|
||||
spanless_eq_struct!(FnSig; header decl span);
|
||||
spanless_eq_struct!(ForeignMod; unsafety abi items);
|
||||
spanless_eq_struct!(ForeignMod; extern_span safety abi items);
|
||||
spanless_eq_struct!(FormatArgPosition; index kind span);
|
||||
spanless_eq_struct!(FormatArgs; span template arguments);
|
||||
spanless_eq_struct!(FormatArgs; span template arguments uncooked_fmt_str is_source_literal);
|
||||
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);
|
||||
spanless_eq_struct!(InlineAsm; template template_strs operands clobber_abis options line_spans);
|
||||
spanless_eq_struct!(Impl; generics constness of_trait self_ty items);
|
||||
spanless_eq_struct!(InlineAsm; asm_macro template template_strs operands clobber_abis options line_spans);
|
||||
spanless_eq_struct!(InlineAsmSym; id qself path);
|
||||
spanless_eq_struct!(Item<K>; attrs id span vis ident kind !tokens);
|
||||
spanless_eq_struct!(Item<K>; attrs id span vis kind !tokens);
|
||||
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!(Local; id super_ pat ty kind span colon_sp attrs !tokens);
|
||||
spanless_eq_struct!(MacCall; path args);
|
||||
spanless_eq_struct!(MacCallStmt; mac style attrs tokens);
|
||||
spanless_eq_struct!(MacroDef; body macro_rules);
|
||||
spanless_eq_struct!(MacroDef; body macro_rules eii_extern_target);
|
||||
spanless_eq_struct!(MetaItem; unsafety path 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);
|
||||
@@ -502,48 +537,54 @@ spanless_eq_struct!(Pat; id kind span tokens);
|
||||
spanless_eq_struct!(PatField; ident pat is_shorthand attrs id span is_placeholder);
|
||||
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!(PolyTraitRef; bound_generic_params modifiers trait_ref span parens);
|
||||
spanless_eq_struct!(QSelf; ty path_span position);
|
||||
spanless_eq_struct!(StaticItem; ty mutability expr);
|
||||
spanless_eq_struct!(StaticItem; ident ty safety mutability expr define_opaque);
|
||||
spanless_eq_struct!(Stmt; id kind span);
|
||||
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!(Trait; constness safety is_auto ident generics bounds items);
|
||||
spanless_eq_struct!(TraitAlias; constness ident generics bounds);
|
||||
spanless_eq_struct!(TraitBoundModifiers; constness asyncness polarity);
|
||||
spanless_eq_struct!(TraitImplHeader; defaultness safety polarity trait_ref);
|
||||
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);
|
||||
spanless_eq_struct!(TyAliasWhereClause; !0 1);
|
||||
spanless_eq_struct!(TyAlias; defaultness ident generics after_where_clause bounds ty);
|
||||
spanless_eq_struct!(TyPat; id kind span tokens);
|
||||
spanless_eq_struct!(UnsafeBinderTy; generic_params inner_ty);
|
||||
spanless_eq_struct!(UseTree; prefix kind span);
|
||||
spanless_eq_struct!(Variant; attrs id span !vis ident data disr_expr is_placeholder);
|
||||
spanless_eq_struct!(Visibility; kind span tokens);
|
||||
spanless_eq_struct!(WhereBoundPredicate; span bound_generic_params bounded_ty bounds);
|
||||
spanless_eq_struct!(WhereBoundPredicate; bound_generic_params bounded_ty bounds);
|
||||
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_struct!(WhereEqPredicate; lhs_ty rhs_ty);
|
||||
spanless_eq_struct!(WherePredicate; attrs kind id span is_placeholder);
|
||||
spanless_eq_struct!(WhereRegionPredicate; lifetime bounds);
|
||||
spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0));
|
||||
spanless_eq_enum!(AssocConstraintKind; Equality(term) Bound(bounds));
|
||||
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!(AsmMacro; Asm GlobalAsm NakedAsm);
|
||||
spanless_eq_enum!(AssocItemConstraintKind; Equality(term) Bound(bounds));
|
||||
spanless_eq_enum!(AssocItemKind; Const(0) Fn(0) Type(0) MacCall(0) Delegation(0) DelegationMac(0));
|
||||
spanless_eq_enum!(AttrArgs; Empty Delimited(0) Eq(eq_span expr));
|
||||
spanless_eq_enum!(AttrStyle; Outer Inner);
|
||||
spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) Attributes(0));
|
||||
spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) AttrsTarget(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!(BorrowKind; Ref Raw Pin);
|
||||
spanless_eq_enum!(BoundAsyncness; Normal Async(0));
|
||||
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(move_kw) Ref);
|
||||
spanless_eq_enum!(ByRef; Yes(0 1) No);
|
||||
spanless_eq_enum!(CaptureBy; Value(move_kw) Ref Use(use_kw));
|
||||
spanless_eq_enum!(ClosureBinder; NotPresent For(span generic_params));
|
||||
spanless_eq_enum!(Const; Yes(0) No);
|
||||
spanless_eq_enum!(ConstItemRhs; TypeConst(0) Body(0));
|
||||
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!(FloatTy; F16 F32 F64 F128);
|
||||
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!(ForeignItemKind; Static(0) 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));
|
||||
@@ -554,11 +595,11 @@ 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));
|
||||
spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span default));
|
||||
spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0) ParenthesizedElided(0));
|
||||
spanless_eq_enum!(GenericBound; Trait(0) Outlives(0) Use(0 1));
|
||||
spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty span default));
|
||||
spanless_eq_enum!(ImplPolarity; Positive Negative(0));
|
||||
spanless_eq_enum!(Inline; Yes No);
|
||||
spanless_eq_enum!(Inline; Yes No(had_parse_error));
|
||||
spanless_eq_enum!(InlineAsmRegOrRegClass; Reg(0) RegClass(0));
|
||||
spanless_eq_enum!(InlineAsmTemplatePiece; String(0) Placeholder(operand_idx modifier span));
|
||||
spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128);
|
||||
@@ -567,51 +608,68 @@ 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!(MacStmtStyle; Semicolon Braces NoBraces);
|
||||
spanless_eq_enum!(MatchKind; Prefix Postfix);
|
||||
spanless_eq_enum!(MetaItemInner; MetaItem(0) Lit(0));
|
||||
spanless_eq_enum!(MetaItemKind; Word List(0) NameValue(0));
|
||||
spanless_eq_enum!(MgcaDisambiguation; AnonConst Direct);
|
||||
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!(Parens; Yes No);
|
||||
spanless_eq_enum!(PatFieldsRest; Rest(0) Recovered(0) None);
|
||||
spanless_eq_enum!(Pinnedness; Not Pinned);
|
||||
spanless_eq_enum!(PreciseCapturingArg; Lifetime(0) Arg(0 1));
|
||||
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!(Recovered; No Yes(0));
|
||||
spanless_eq_enum!(Safety; Unsafe(0) Safe(0) Default);
|
||||
spanless_eq_enum!(StmtKind; Let(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 3));
|
||||
spanless_eq_enum!(TraitObjectSyntax; Dyn DynStar None);
|
||||
spanless_eq_enum!(TraitObjectSyntax; Dyn None);
|
||||
spanless_eq_enum!(TyPatKind; Range(0 1 2) NotNull Or(0) Err(0));
|
||||
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!(UnsafeBinderCastKind; Wrap Unwrap);
|
||||
spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided);
|
||||
spanless_eq_enum!(UseTreeKind; Simple(0) Nested(0) Glob);
|
||||
spanless_eq_enum!(UseTreeKind; Simple(0) Nested(items span) Glob);
|
||||
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!(WherePredicateKind; BoundPredicate(0) RegionPredicate(0) EqPredicate(0));
|
||||
spanless_eq_enum!(YieldKind; Prefix(0) Postfix(0));
|
||||
spanless_eq_enum!(AssignOpKind; AddAssign SubAssign MulAssign DivAssign
|
||||
RemAssign BitXorAssign BitAndAssign BitOrAssign ShlAssign ShrAssign);
|
||||
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);
|
||||
Match(0 1 2) Closure(0) Block(0 1) Gen(0 1 2 3) Await(0 1) Use(0 1)
|
||||
TryBlock(0 1) 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)
|
||||
UnsafeBinderCast(0 1 2) Err(0) Dummy);
|
||||
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) 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));
|
||||
Sym(sym) Label(block));
|
||||
spanless_eq_enum!(ItemKind; ExternCrate(0 1) Use(0) Static(0) Const(0) Fn(0)
|
||||
Mod(0 1 2) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1 2) Struct(0 1 2)
|
||||
Union(0 1 2) Trait(0) TraitAlias(0) Impl(0) MacCall(0) MacroDef(0 1)
|
||||
Delegation(0) DelegationMac(0));
|
||||
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
|
||||
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);
|
||||
Int(0 1) Float(0 1) Bool(0) Err(0));
|
||||
spanless_eq_enum!(PatKind; Missing Wild Ident(0 1 2) Struct(0 1 2 3)
|
||||
TupleStruct(0 1 2) Or(0) Path(0 1) Tuple(0) Box(0) Deref(0) Ref(0 1 2)
|
||||
Expr(0) Range(0 1 2) Slice(0) Rest Never Guard(0 1) Paren(0) MacCall(0)
|
||||
Err(0));
|
||||
spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Ref(0 1) PinnedRef(0 1)
|
||||
FnPtr(0) UnsafeBinder(0) Never Tup(0) Path(0 1) TraitObject(0 1)
|
||||
ImplTrait(0 1) Paren(0) Infer ImplicitSelf MacCall(0) CVarArgs Pat(0 1)
|
||||
Dummy Err(0));
|
||||
|
||||
impl SpanlessEq for Ident {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@@ -647,8 +705,8 @@ impl SpanlessEq for Param {
|
||||
} = other;
|
||||
SpanlessEq::eq(id, id2)
|
||||
&& SpanlessEq::eq(is_placeholder, is_placeholder2)
|
||||
&& (matches!(ty.kind, TyKind::Err)
|
||||
|| matches!(ty2.kind, TyKind::Err)
|
||||
&& (matches!(ty.kind, TyKind::Err(_))
|
||||
|| matches!(ty2.kind, TyKind::Err(_))
|
||||
|| SpanlessEq::eq(attrs, attrs2)
|
||||
&& SpanlessEq::eq(ty, ty2)
|
||||
&& SpanlessEq::eq(pat, pat2))
|
||||
@@ -663,17 +721,6 @@ impl SpanlessEq for TokenKind {
|
||||
TokenKind::DotDotEq | TokenKind::DotDotDot => true,
|
||||
_ => false,
|
||||
},
|
||||
(TokenKind::Interpolated(this), TokenKind::Interpolated(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,
|
||||
}
|
||||
}
|
||||
_ => self == other,
|
||||
}
|
||||
}
|
||||
@@ -681,16 +728,14 @@ impl SpanlessEq for TokenKind {
|
||||
|
||||
impl SpanlessEq for TokenStream {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let mut this_trees = self.trees();
|
||||
let mut other_trees = other.trees();
|
||||
let mut this_trees = self.iter();
|
||||
let mut other_trees = other.iter();
|
||||
loop {
|
||||
let this = match this_trees.next() {
|
||||
None => return other_trees.next().is_none(),
|
||||
Some(tree) => tree,
|
||||
let Some(this) = this_trees.next() else {
|
||||
return other_trees.next().is_none();
|
||||
};
|
||||
let other = match other_trees.next() {
|
||||
None => return false,
|
||||
Some(tree) => tree,
|
||||
let Some(other) = other_trees.next() else {
|
||||
return false;
|
||||
};
|
||||
if SpanlessEq::eq(this, other) {
|
||||
continue;
|
||||
@@ -728,7 +773,7 @@ fn doc_comment<'a>(
|
||||
match trees.next() {
|
||||
Some(TokenTree::Token(
|
||||
Token {
|
||||
kind: TokenKind::Not,
|
||||
kind: TokenKind::Bang,
|
||||
span: _,
|
||||
},
|
||||
_spacing,
|
||||
@@ -736,15 +781,15 @@ fn doc_comment<'a>(
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
let stream = match trees.next() {
|
||||
Some(TokenTree::Delimited(_span, _spacing, Delimiter::Bracket, stream)) => stream,
|
||||
_ => return false,
|
||||
let Some(TokenTree::Delimited(_span, _spacing, Delimiter::Bracket, stream)) = trees.next()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let mut trees = stream.trees();
|
||||
let mut trees = stream.iter();
|
||||
match trees.next() {
|
||||
Some(TokenTree::Token(
|
||||
Token {
|
||||
kind: TokenKind::Ident(symbol, false),
|
||||
kind: TokenKind::Ident(symbol, IdentIsRaw::No),
|
||||
span: _,
|
||||
},
|
||||
_spacing,
|
||||
@@ -778,30 +823,10 @@ fn is_escaped_literal_token(token: &Token, unescaped: Symbol) -> bool {
|
||||
Ok(lit) => is_escaped_literal_meta_item_lit(&lit, unescaped),
|
||||
Err(_) => false,
|
||||
},
|
||||
Token {
|
||||
kind: TokenKind::Interpolated(nonterminal),
|
||||
span: _,
|
||||
} => match &nonterminal.0 {
|
||||
Nonterminal::NtExpr(expr) => match &expr.kind {
|
||||
ExprKind::Lit(lit) => is_escaped_lit(lit, unescaped),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_escaped_literal_attr_args(value: &AttrArgsEq, unescaped: Symbol) -> bool {
|
||||
match value {
|
||||
AttrArgsEq::Ast(expr) => match &expr.kind {
|
||||
ExprKind::Lit(lit) => is_escaped_lit(lit, unescaped),
|
||||
_ => false,
|
||||
},
|
||||
AttrArgsEq::Hir(lit) => is_escaped_literal_meta_item_lit(lit, unescaped),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_escaped_literal_meta_item_lit(lit: &MetaItemLit, unescaped: Symbol) -> bool {
|
||||
match lit {
|
||||
MetaItemLit {
|
||||
@@ -862,9 +887,10 @@ impl SpanlessEq for AttrKind {
|
||||
SpanlessEq::eq(&path, &normal2.item.path)
|
||||
&& match &normal2.item.args {
|
||||
AttrArgs::Empty | AttrArgs::Delimited(_) => false,
|
||||
AttrArgs::Eq(_span, value) => {
|
||||
is_escaped_literal_attr_args(value, *unescaped)
|
||||
}
|
||||
AttrArgs::Eq { eq_span: _, expr } => match &expr.kind {
|
||||
ExprKind::Lit(lit) => is_escaped_lit(lit, *unescaped),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
(AttrKind::Normal(_), AttrKind::DocComment(..)) => SpanlessEq::eq(other, self),
|
||||
|
||||
+1
-23
@@ -1,28 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::module_name_repetitions, clippy::shadow_unrelated)]
|
||||
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use std::env;
|
||||
|
||||
pub mod eq;
|
||||
pub mod parse;
|
||||
|
||||
/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
|
||||
pub fn abort_after() -> usize {
|
||||
match env::var("ABORT_AFTER_FAILURE") {
|
||||
Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"),
|
||||
Err(_) => usize::max_value(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure Rayon threadpool.
|
||||
pub fn rayon_init() {
|
||||
let stack_size = match env::var("RUST_MIN_STACK") {
|
||||
Ok(s) => s.parse().expect("failed to parse RUST_MIN_STACK"),
|
||||
Err(_) => 20 * 1024 * 1024,
|
||||
};
|
||||
ThreadPoolBuilder::new()
|
||||
.stack_size(stack_size)
|
||||
.build_global()
|
||||
.unwrap();
|
||||
}
|
||||
pub mod visit;
|
||||
|
||||
+12
-11
@@ -1,31 +1,32 @@
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_expand;
|
||||
extern crate rustc_parse as parse;
|
||||
extern crate rustc_parse;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::FilePathMapping;
|
||||
use rustc_span::FileName;
|
||||
use std::panic;
|
||||
|
||||
pub fn librustc_expr(input: &str) -> Option<P<ast::Expr>> {
|
||||
pub fn librustc_expr(input: &str) -> Option<Box<ast::Expr>> {
|
||||
match panic::catch_unwind(|| {
|
||||
let locale_resources = rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec();
|
||||
let file_path_mapping = FilePathMapping::empty();
|
||||
let sess = ParseSess::new(locale_resources, file_path_mapping);
|
||||
let e = parse::new_parser_from_source_str(
|
||||
let sess = ParseSess::new(locale_resources);
|
||||
let name = FileName::Custom("test_precedence".to_string());
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(
|
||||
&sess,
|
||||
FileName::Custom("test_precedence".to_string()),
|
||||
name,
|
||||
input.to_string(),
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
)
|
||||
.parse_expr();
|
||||
match e {
|
||||
.unwrap();
|
||||
let presult = parser.parse_expr();
|
||||
match presult {
|
||||
Ok(expr) => Some(expr),
|
||||
Err(mut diagnostic) => {
|
||||
Err(diagnostic) => {
|
||||
diagnostic.emit();
|
||||
None
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
|
||||
use std::mem;
|
||||
use syn::visit_mut::{self, VisitMut};
|
||||
use syn::{Expr, File, Generics, LifetimeParam, MacroDelimiter, Stmt, StmtMacro, TypeParam};
|
||||
|
||||
pub struct FlattenParens {
|
||||
discard_paren_attrs: bool,
|
||||
}
|
||||
|
||||
impl FlattenParens {
|
||||
pub fn discard_attrs() -> Self {
|
||||
FlattenParens {
|
||||
discard_paren_attrs: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn combine_attrs() -> Self {
|
||||
FlattenParens {
|
||||
discard_paren_attrs: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_token_stream_mut(tokens: &mut TokenStream) {
|
||||
*tokens = mem::take(tokens)
|
||||
.into_iter()
|
||||
.flat_map(|tt| {
|
||||
if let TokenTree::Group(group) = tt {
|
||||
let delimiter = group.delimiter();
|
||||
let mut content = group.stream();
|
||||
Self::visit_token_stream_mut(&mut content);
|
||||
if let Delimiter::Parenthesis = delimiter {
|
||||
content
|
||||
} else {
|
||||
TokenStream::from(TokenTree::Group(Group::new(delimiter, content)))
|
||||
}
|
||||
} else {
|
||||
TokenStream::from(tt)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for FlattenParens {
|
||||
fn visit_expr_mut(&mut self, e: &mut Expr) {
|
||||
while let Expr::Paren(paren) = e {
|
||||
let paren_attrs = mem::take(&mut paren.attrs);
|
||||
*e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER);
|
||||
if !paren_attrs.is_empty() && !self.discard_paren_attrs {
|
||||
let nested_attrs = match e {
|
||||
Expr::Assign(e) => &mut e.attrs,
|
||||
Expr::Binary(e) => &mut e.attrs,
|
||||
Expr::Cast(e) => &mut e.attrs,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert!(nested_attrs.is_empty());
|
||||
*nested_attrs = paren_attrs;
|
||||
}
|
||||
}
|
||||
visit_mut::visit_expr_mut(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AsIfPrinted;
|
||||
|
||||
impl VisitMut for AsIfPrinted {
|
||||
fn visit_file_mut(&mut self, file: &mut File) {
|
||||
file.shebang = None;
|
||||
visit_mut::visit_file_mut(self, file);
|
||||
}
|
||||
|
||||
fn visit_generics_mut(&mut self, generics: &mut Generics) {
|
||||
if generics.params.is_empty() {
|
||||
generics.lt_token = None;
|
||||
generics.gt_token = None;
|
||||
}
|
||||
if let Some(where_clause) = &generics.where_clause {
|
||||
if where_clause.predicates.is_empty() {
|
||||
generics.where_clause = None;
|
||||
}
|
||||
}
|
||||
visit_mut::visit_generics_mut(self, generics);
|
||||
}
|
||||
|
||||
fn visit_lifetime_param_mut(&mut self, param: &mut LifetimeParam) {
|
||||
if param.bounds.is_empty() {
|
||||
param.colon_token = None;
|
||||
}
|
||||
visit_mut::visit_lifetime_param_mut(self, param);
|
||||
}
|
||||
|
||||
fn visit_stmt_mut(&mut self, stmt: &mut Stmt) {
|
||||
if let Stmt::Expr(expr, semi) = stmt {
|
||||
if let Expr::Macro(e) = expr {
|
||||
if match e.mac.delimiter {
|
||||
MacroDelimiter::Brace(_) => true,
|
||||
MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => semi.is_some(),
|
||||
} {
|
||||
let Expr::Macro(expr) = mem::replace(expr, Expr::PLACEHOLDER) else {
|
||||
unreachable!();
|
||||
};
|
||||
*stmt = Stmt::Macro(StmtMacro {
|
||||
attrs: expr.attrs,
|
||||
mac: expr.mac,
|
||||
semi_token: *semi,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
visit_mut::visit_stmt_mut(self, stmt);
|
||||
}
|
||||
|
||||
fn visit_type_param_mut(&mut self, param: &mut TypeParam) {
|
||||
if param.bounds.is_empty() {
|
||||
param.colon_token = None;
|
||||
}
|
||||
visit_mut::visit_type_param_mut(self, param);
|
||||
}
|
||||
}
|
||||
Generated
+84
-2
@@ -1,11 +1,11 @@
|
||||
// This file is @generated by syn-internal-codegen.
|
||||
// It is not intended for manual editing.
|
||||
|
||||
#![allow(repr_transparent_external_private_fields)]
|
||||
#![allow(repr_transparent_non_zst_fields)]
|
||||
#![allow(clippy::match_wildcard_for_single_variants)]
|
||||
use super::{Lite, Present};
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use ref_cast::RefCast;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
impl Debug for Lite<syn::Abi> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("Abi");
|
||||
@@ -314,6 +314,27 @@ impl Debug for Lite<syn::BoundLifetimes> {
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::CapturedParam> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.value {
|
||||
syn::CapturedParam::Lifetime(_val) => {
|
||||
formatter.write_str("CapturedParam::Lifetime")?;
|
||||
formatter.write_str("(")?;
|
||||
Debug::fmt(Lite(_val), formatter)?;
|
||||
formatter.write_str(")")?;
|
||||
Ok(())
|
||||
}
|
||||
syn::CapturedParam::Ident(_val) => {
|
||||
formatter.write_str("CapturedParam::Ident")?;
|
||||
formatter.write_str("(")?;
|
||||
Debug::fmt(Lite(_val), formatter)?;
|
||||
formatter.write_str(")")?;
|
||||
Ok(())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::ConstParam> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("ConstParam");
|
||||
@@ -856,6 +877,15 @@ impl Debug for Lite<syn::Expr> {
|
||||
}
|
||||
formatter.finish()
|
||||
}
|
||||
syn::Expr::RawAddr(_val) => {
|
||||
let mut formatter = formatter.debug_struct("Expr::RawAddr");
|
||||
if !_val.attrs.is_empty() {
|
||||
formatter.field("attrs", Lite(&_val.attrs));
|
||||
}
|
||||
formatter.field("mutability", Lite(&_val.mutability));
|
||||
formatter.field("expr", Lite(&_val.expr));
|
||||
formatter.finish()
|
||||
}
|
||||
syn::Expr::Reference(_val) => {
|
||||
let mut formatter = formatter.debug_struct("Expr::Reference");
|
||||
if !_val.attrs.is_empty() {
|
||||
@@ -1513,6 +1543,17 @@ impl Debug for Lite<syn::ExprRange> {
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::ExprRawAddr> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("ExprRawAddr");
|
||||
if !self.value.attrs.is_empty() {
|
||||
formatter.field("attrs", Lite(&self.value.attrs));
|
||||
}
|
||||
formatter.field("mutability", Lite(&self.value.mutability));
|
||||
formatter.field("expr", Lite(&self.value.expr));
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::ExprReference> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("ExprReference");
|
||||
@@ -2864,6 +2905,7 @@ impl Debug for Lite<syn::Lit> {
|
||||
match &self.value {
|
||||
syn::Lit::Str(_val) => write!(formatter, "{:?}", _val.value()),
|
||||
syn::Lit::ByteStr(_val) => write!(formatter, "{:?}", _val.value()),
|
||||
syn::Lit::CStr(_val) => write!(formatter, "{:?}", _val.value()),
|
||||
syn::Lit::Byte(_val) => write!(formatter, "{:?}", _val.value()),
|
||||
syn::Lit::Char(_val) => write!(formatter, "{:?}", _val.value()),
|
||||
syn::Lit::Int(_val) => write!(formatter, "{}", _val),
|
||||
@@ -2901,6 +2943,11 @@ impl Debug for Lite<syn::LitByteStr> {
|
||||
write!(formatter, "{:?}", self.value.value())
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::LitCStr> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{:?}", self.value.value())
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::LitChar> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{:?}", self.value.value())
|
||||
@@ -3526,6 +3573,29 @@ impl Debug for Lite<syn::PathSegment> {
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::PointerMutability> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.value {
|
||||
syn::PointerMutability::Const(_val) => {
|
||||
formatter.write_str("PointerMutability::Const")?;
|
||||
Ok(())
|
||||
}
|
||||
syn::PointerMutability::Mut(_val) => {
|
||||
formatter.write_str("PointerMutability::Mut")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::PreciseCapture> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("PreciseCapture");
|
||||
if !self.value.params.is_empty() {
|
||||
formatter.field("params", Lite(&self.value.params));
|
||||
}
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::PredicateLifetime> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut formatter = formatter.debug_struct("PredicateLifetime");
|
||||
@@ -4348,6 +4418,13 @@ impl Debug for Lite<syn::TypeParamBound> {
|
||||
formatter.field("ident", Lite(&_val.ident));
|
||||
formatter.finish()
|
||||
}
|
||||
syn::TypeParamBound::PreciseCapture(_val) => {
|
||||
formatter.write_str("TypeParamBound::PreciseCapture")?;
|
||||
formatter.write_str("(")?;
|
||||
Debug::fmt(Lite(_val), formatter)?;
|
||||
formatter.write_str(")")?;
|
||||
Ok(())
|
||||
}
|
||||
syn::TypeParamBound::Verbatim(_val) => {
|
||||
formatter.write_str("TypeParamBound::Verbatim")?;
|
||||
formatter.write_str("(`")?;
|
||||
@@ -5005,6 +5082,11 @@ impl Debug for Lite<syn::token::RArrow> {
|
||||
formatter.write_str("Token![->]")
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::token::Raw> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("Token![raw]")
|
||||
}
|
||||
}
|
||||
impl Debug for Lite<syn::token::Ref> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("Token![ref]")
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ impl Debug for Lite<TokenStream> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Debug for Lite<&'a T>
|
||||
impl<T> Debug for Lite<&T>
|
||||
where
|
||||
Lite<T>: Debug,
|
||||
{
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
#![allow(unused_macros, unused_macro_rules)]
|
||||
|
||||
#[path = "../debug/mod.rs"]
|
||||
pub mod debug;
|
||||
|
||||
use std::str::FromStr;
|
||||
use syn::parse::Result;
|
||||
|
||||
macro_rules! errorf {
|
||||
($($tt:tt)*) => {{
|
||||
use ::std::io::Write;
|
||||
@@ -13,80 +5,3 @@ macro_rules! errorf {
|
||||
write!(stderr.lock(), $($tt)*).unwrap();
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! punctuated {
|
||||
($($e:expr,)+) => {{
|
||||
let mut seq = ::syn::punctuated::Punctuated::new();
|
||||
$(
|
||||
seq.push($e);
|
||||
)+
|
||||
seq
|
||||
}};
|
||||
|
||||
($($e:expr),+) => {
|
||||
punctuated!($($e,)+)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! snapshot {
|
||||
($($args:tt)*) => {
|
||||
snapshot_impl!(() $($args)*)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! snapshot_impl {
|
||||
(($expr:ident) as $t:ty, @$snapshot:literal) => {
|
||||
let tokens = crate::macros::TryIntoTokens::try_into_tokens($expr).unwrap();
|
||||
let $expr: $t = syn::parse_quote!(#tokens);
|
||||
let debug = crate::macros::debug::Lite(&$expr);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)] // https://github.com/mitsuhiko/insta/issues/389
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
};
|
||||
(($($expr:tt)*) as $t:ty, @$snapshot:literal) => {{
|
||||
let tokens = crate::macros::TryIntoTokens::try_into_tokens($($expr)*).unwrap();
|
||||
let syntax_tree: $t = syn::parse_quote!(#tokens);
|
||||
let debug = crate::macros::debug::Lite(&syntax_tree);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)]
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
syntax_tree
|
||||
}};
|
||||
(($($expr:tt)*) , @$snapshot:literal) => {{
|
||||
let syntax_tree = $($expr)*;
|
||||
let debug = crate::macros::debug::Lite(&syntax_tree);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)]
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
syntax_tree
|
||||
}};
|
||||
(($($expr:tt)*) $next:tt $($rest:tt)*) => {
|
||||
snapshot_impl!(($($expr)* $next) $($rest)*)
|
||||
};
|
||||
}
|
||||
|
||||
pub trait TryIntoTokens {
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream>;
|
||||
}
|
||||
|
||||
impl<'a> TryIntoTokens for &'a str {
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> {
|
||||
let tokens = proc_macro2::TokenStream::from_str(self)?;
|
||||
Ok(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoTokens for proc_macro2::TokenStream {
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
+312
-57
@@ -6,62 +6,290 @@ use self::progress::Progress;
|
||||
use anyhow::Result;
|
||||
use flate2::read::GzDecoder;
|
||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use std::collections::BTreeSet;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use tar::Archive;
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
const REVISION: &str = "b10cfcd65fd7f7b1ab9beb34798b2108de003452";
|
||||
// nightly-2025-08-14
|
||||
const REVISION: &str = "3672a55b7cfd0a12e7097197b6242872473ffaa7";
|
||||
|
||||
#[rustfmt::skip]
|
||||
static EXCLUDE_FILES: &[&str] = &[
|
||||
// TODO: CStr literals: c"…", cr"…"
|
||||
// https://github.com/dtolnay/syn/issues/1502
|
||||
"src/tools/clippy/tests/ui/needless_raw_string.rs",
|
||||
"src/tools/clippy/tests/ui/needless_raw_string_hashes.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs",
|
||||
// TODO: const traits: `pub const trait Trait {}`
|
||||
// https://github.com/dtolnay/syn/issues/1887
|
||||
"src/tools/clippy/tests/ui/assign_ops.rs",
|
||||
"src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs",
|
||||
"src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs",
|
||||
"src/tools/rust-analyzer/crates/test-utils/src/minicore.rs",
|
||||
|
||||
// TODO: explicit tail calls: `become _g()`
|
||||
// https://github.com/dtolnay/syn/issues/1501
|
||||
"tests/ui/explicit-tail-calls/return-lifetime-sub.rs",
|
||||
// TODO: unsafe binders: `unsafe<'a> &'a T`
|
||||
// https://github.com/dtolnay/syn/issues/1791
|
||||
"src/tools/rustfmt/tests/source/unsafe-binders.rs",
|
||||
"src/tools/rustfmt/tests/target/unsafe-binders.rs",
|
||||
"tests/mir-opt/gvn_on_unsafe_binder.rs",
|
||||
"tests/rustdoc/auxiliary/unsafe-binder-dep.rs",
|
||||
"tests/rustdoc/unsafe-binder.rs",
|
||||
"tests/ui/unsafe-binders/cat-projection.rs",
|
||||
|
||||
// TODO: non-lifetime binders: `where for<'a, T> &'a Struct<T>: Trait`
|
||||
// https://github.com/dtolnay/syn/issues/1435
|
||||
"src/tools/rustfmt/tests/source/issue_5721.rs",
|
||||
"src/tools/rustfmt/tests/source/non-lifetime-binders.rs",
|
||||
"src/tools/rustfmt/tests/target/issue_5721.rs",
|
||||
"src/tools/rustfmt/tests/target/non-lifetime-binders.rs",
|
||||
"tests/rustdoc-json/non_lifetime_binders.rs",
|
||||
"tests/rustdoc/inline_cross/auxiliary/non_lifetime_binders.rs",
|
||||
"tests/rustdoc/non_lifetime_binders.rs",
|
||||
// TODO: unsafe fields: `struct S { unsafe field: T }`
|
||||
// https://github.com/dtolnay/syn/issues/1792
|
||||
"src/tools/clippy/tests/ui/derive.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_list.rs",
|
||||
"src/tools/rustfmt/tests/source/unsafe-field.rs",
|
||||
"src/tools/rustfmt/tests/target/unsafe-field.rs",
|
||||
"tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs",
|
||||
|
||||
// TODO: return type notation: `where T: Trait<method(): Send>`
|
||||
// TODO: guard patterns: `match expr { (A if f()) | (B if g()) => {} }`
|
||||
// https://github.com/dtolnay/syn/issues/1793
|
||||
"src/tools/rustfmt/tests/target/guard_patterns.rs",
|
||||
"tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs",
|
||||
|
||||
// TODO: struct field default: `struct S { field: i32 = 1 }`
|
||||
// https://github.com/dtolnay/syn/issues/1774
|
||||
"compiler/rustc_errors/src/markdown/parse.rs",
|
||||
"compiler/rustc_session/src/config.rs",
|
||||
"src/tools/clippy/tests/ui/exhaustive_items.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs",
|
||||
"src/tools/rustfmt/tests/source/default-field-values.rs",
|
||||
"src/tools/rustfmt/tests/target/default-field-values.rs",
|
||||
"tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs",
|
||||
"tests/ui/structs/default-field-values/const-trait-default-field-value.rs",
|
||||
"tests/ui/structs/default-field-values/field-references-param.rs",
|
||||
"tests/ui/structs/default-field-values/support.rs",
|
||||
"tests/ui/structs/default-field-values/use-normalized-ty-for-default-struct-value.rs",
|
||||
|
||||
// TODO: return type notation: `where T: Trait<method(): Send>` and `where T::method(..): Send`
|
||||
// https://github.com/dtolnay/syn/issues/1434
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs",
|
||||
"src/tools/rustfmt/tests/target/return-type-notation.rs",
|
||||
"tests/rustdoc-json/return-type-notation.rs",
|
||||
"tests/rustdoc/return-type-notation.rs",
|
||||
"tests/ui/associated-type-bounds/all-generics-lookup.rs",
|
||||
"tests/ui/associated-type-bounds/implied-from-self-where-clause.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/basic.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/path-works.rs",
|
||||
"tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs",
|
||||
"tests/ui/async-await/return-type-notation/issue-110963-late.rs",
|
||||
"tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs",
|
||||
"tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs",
|
||||
"tests/ui/async-await/return-type-notation/super-method-bound.rs",
|
||||
"tests/ui/async-await/return-type-notation/supertrait-bound.rs",
|
||||
"tests/ui/borrowck/alias-liveness/rtn-static.rs",
|
||||
"tests/ui/feature-gates/feature-gate-return_type_notation.rs",
|
||||
|
||||
// TODO: lazy type alias syntax with where-clause in trailing position
|
||||
// https://github.com/dtolnay/syn/issues/1525
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_item_where_clause.rs",
|
||||
"src/tools/rustfmt/tests/source/type-alias-where-clauses-with-comments.rs",
|
||||
"src/tools/rustfmt/tests/source/type-alias-where-clauses.rs",
|
||||
"src/tools/rustfmt/tests/target/type-alias-where-clauses-with-comments.rs",
|
||||
"src/tools/rustfmt/tests/target/type-alias-where-clauses.rs",
|
||||
"tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs",
|
||||
|
||||
// TODO: gen blocks and functions
|
||||
// https://github.com/dtolnay/syn/issues/1526
|
||||
"compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs",
|
||||
"compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs",
|
||||
"compiler/rustc_metadata/src/rmeta/decoder.rs",
|
||||
"compiler/rustc_middle/src/ty/closure.rs",
|
||||
"compiler/rustc_middle/src/ty/context.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/gen_blocks.rs",
|
||||
"tests/ui/async-await/async-drop/assign-incompatible-types.rs",
|
||||
"tests/ui/coroutine/async-gen-deduce-yield.rs",
|
||||
"tests/ui/coroutine/async-gen-yield-ty-is-unit.rs",
|
||||
"tests/ui/coroutine/async_gen_fn_iter.rs",
|
||||
"tests/ui/coroutine/gen_block_is_fused_iter.rs",
|
||||
"tests/ui/coroutine/gen_block_is_iter.rs",
|
||||
"tests/ui/coroutine/gen_block_iterate.rs",
|
||||
"tests/ui/coroutine/gen_fn_iter.rs",
|
||||
"tests/ui/coroutine/gen_fn_lifetime_capture.rs",
|
||||
"tests/ui/coroutine/other-attribute-on-gen.rs",
|
||||
"tests/ui/coroutine/return-types-diverge.rs",
|
||||
"tests/ui/higher-ranked/builtin-closure-like-bounds.rs",
|
||||
"tests/ui/sanitizer/cfi/coroutine.rs",
|
||||
|
||||
// TODO: struct literal in match guard
|
||||
// https://github.com/dtolnay/syn/issues/1527
|
||||
"tests/ui/parser/struct-literal-in-match-guard.rs",
|
||||
// TODO: postfix yield
|
||||
// https://github.com/dtolnay/syn/issues/1890
|
||||
"tests/pretty/postfix-yield.rs",
|
||||
"tests/ui/coroutine/postfix-yield.rs",
|
||||
|
||||
// Compile-fail expr parameter in const generic position: f::<1 + 2>()
|
||||
// TODO: `!` as a pattern
|
||||
// https://github.com/dtolnay/syn/issues/1546
|
||||
"tests/mir-opt/building/match/never_patterns.rs",
|
||||
"tests/pretty/never-pattern.rs",
|
||||
"tests/ui/rfcs/rfc-0000-never_patterns/always-read-in-closure-capture.rs",
|
||||
"tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs",
|
||||
"tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs",
|
||||
|
||||
// TODO: async trait bounds: `impl async Fn()`
|
||||
// https://github.com/dtolnay/syn/issues/1628
|
||||
"src/tools/miri/tests/pass/async-closure-captures.rs",
|
||||
"src/tools/miri/tests/pass/async-closure-drop.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs",
|
||||
"src/tools/rustfmt/tests/target/asyncness.rs",
|
||||
"tests/coverage/async_closure.rs",
|
||||
"tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs",
|
||||
"tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs",
|
||||
"tests/ui/async-await/async-closures/auxiliary/foreign.rs",
|
||||
"tests/ui/async-await/async-closures/body-check-on-non-fnmut.rs",
|
||||
"tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs",
|
||||
"tests/ui/async-await/async-closures/brand.rs",
|
||||
"tests/ui/async-await/async-closures/captures.rs",
|
||||
"tests/ui/async-await/async-closures/clone-closure.rs",
|
||||
"tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs",
|
||||
"tests/ui/async-await/async-closures/debuginfo-by-move-body.rs",
|
||||
"tests/ui/async-await/async-closures/drop.rs",
|
||||
"tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs",
|
||||
"tests/ui/async-await/async-closures/foreign.rs",
|
||||
"tests/ui/async-await/async-closures/inline-body.rs",
|
||||
"tests/ui/async-await/async-closures/mangle.rs",
|
||||
"tests/ui/async-await/async-closures/moro-example.rs",
|
||||
"tests/ui/async-await/async-closures/move-is-async-fn.rs",
|
||||
"tests/ui/async-await/async-closures/mut-ref-reborrow.rs",
|
||||
"tests/ui/async-await/async-closures/no-borrow-from-env.rs",
|
||||
"tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs",
|
||||
"tests/ui/async-await/async-closures/overlapping-projs.rs",
|
||||
"tests/ui/async-await/async-closures/precise-captures.rs",
|
||||
"tests/ui/async-await/async-closures/refd.rs",
|
||||
"tests/ui/async-await/async-closures/signature-deduction.rs",
|
||||
"tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs",
|
||||
"tests/ui/async-await/async-fn/higher-ranked-async-fn.rs",
|
||||
"tests/ui/async-await/async-fn/impl-trait.rs",
|
||||
"tests/ui/async-await/async-fn/project.rs",
|
||||
"tests/ui/async-await/async-fn/sugar.rs",
|
||||
|
||||
// TODO: mutable by-reference bindings (mut ref)
|
||||
// https://github.com/dtolnay/syn/issues/1629
|
||||
"src/tools/rustfmt/tests/source/mut_ref.rs",
|
||||
"src/tools/rustfmt/tests/target/mut_ref.rs",
|
||||
"tests/ui/mut/mut-ref.rs",
|
||||
|
||||
// TODO: postfix match
|
||||
// https://github.com/dtolnay/syn/issues/1630
|
||||
"src/tools/clippy/tests/ui/unnecessary_semicolon.rs",
|
||||
"src/tools/rustfmt/tests/source/postfix-match/pf-match.rs",
|
||||
"src/tools/rustfmt/tests/target/postfix-match/pf-match.rs",
|
||||
"tests/pretty/postfix-match/simple-matches.rs",
|
||||
"tests/ui/match/postfix-match/no-unused-parens.rs",
|
||||
"tests/ui/match/postfix-match/pf-match-chain.rs",
|
||||
"tests/ui/match/postfix-match/postfix-match.rs",
|
||||
|
||||
// TODO: delegation: `reuse Trait::bar { Box::new(self.0) }`
|
||||
// https://github.com/dtolnay/syn/issues/1580
|
||||
"tests/pretty/delegation.rs",
|
||||
"tests/pretty/hir-delegation.rs",
|
||||
"tests/ui/delegation/body-identity-glob.rs",
|
||||
"tests/ui/delegation/body-identity-list.rs",
|
||||
"tests/ui/delegation/explicit-paths-in-traits-pass.rs",
|
||||
"tests/ui/delegation/explicit-paths-pass.rs",
|
||||
"tests/ui/delegation/explicit-paths-signature-pass.rs",
|
||||
"tests/ui/delegation/fn-header.rs",
|
||||
"tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs",
|
||||
"tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs",
|
||||
"tests/ui/delegation/generics/impl-to-free-fn-pass.rs",
|
||||
"tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs",
|
||||
"tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs",
|
||||
"tests/ui/delegation/generics/trait-method-to-other-pass.rs",
|
||||
"tests/ui/delegation/glob-glob.rs",
|
||||
"tests/ui/delegation/glob-override.rs",
|
||||
"tests/ui/delegation/glob.rs",
|
||||
"tests/ui/delegation/impl-trait.rs",
|
||||
"tests/ui/delegation/list.rs",
|
||||
"tests/ui/delegation/macro-inside-glob.rs",
|
||||
"tests/ui/delegation/macro-inside-list.rs",
|
||||
"tests/ui/delegation/method-call-priority.rs",
|
||||
"tests/ui/delegation/parse.rs",
|
||||
"tests/ui/delegation/rename.rs",
|
||||
"tests/ui/delegation/self-coercion.rs",
|
||||
|
||||
// TODO: for await
|
||||
// https://github.com/dtolnay/syn/issues/1631
|
||||
"tests/ui/async-await/for-await-2015.rs",
|
||||
"tests/ui/async-await/for-await-passthrough.rs",
|
||||
"tests/ui/async-await/for-await.rs",
|
||||
|
||||
// TODO: unparenthesized half-open range pattern inside slice pattern: `[1..]`
|
||||
// https://github.com/dtolnay/syn/issues/1769
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/range_pat.rs",
|
||||
"tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs",
|
||||
|
||||
// TODO: pinned type sugar: `&pin const Self`
|
||||
// https://github.com/dtolnay/syn/issues/1770
|
||||
"src/tools/rustfmt/tests/source/pin_sugar.rs",
|
||||
"src/tools/rustfmt/tests/target/pin_sugar.rs",
|
||||
"tests/pretty/pin-ergonomics-hir.rs",
|
||||
"tests/pretty/pin-ergonomics.rs",
|
||||
"tests/ui/pin-ergonomics/borrow.rs",
|
||||
"tests/ui/pin-ergonomics/sugar-self.rs",
|
||||
"tests/ui/pin-ergonomics/sugar.rs",
|
||||
|
||||
// TODO: attributes on where-predicates
|
||||
// https://github.com/dtolnay/syn/issues/1705
|
||||
"src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs",
|
||||
|
||||
// TODO: super let
|
||||
// https://github.com/dtolnay/syn/issues/1889
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/let_stmt.rs",
|
||||
|
||||
// TODO: "ergonomic clones": `f(obj.use)`, `thread::spawn(use || f(obj))`, `async use`
|
||||
// https://github.com/dtolnay/syn/issues/1802
|
||||
"tests/codegen-llvm/ergonomic-clones/closure.rs",
|
||||
"tests/mir-opt/ergonomic-clones/closure.rs",
|
||||
"tests/ui/ergonomic-clones/async/basic.rs",
|
||||
"tests/ui/ergonomic-clones/closure/basic.rs",
|
||||
"tests/ui/ergonomic-clones/closure/const-closure.rs",
|
||||
"tests/ui/ergonomic-clones/closure/mutation.rs",
|
||||
"tests/ui/ergonomic-clones/closure/nested.rs",
|
||||
"tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs",
|
||||
"tests/ui/ergonomic-clones/closure/with-binders.rs",
|
||||
"tests/ui/ergonomic-clones/dotuse/basic.rs",
|
||||
"tests/ui/ergonomic-clones/dotuse/block.rs",
|
||||
|
||||
// TODO: contracts
|
||||
// https://github.com/dtolnay/syn/issues/1892
|
||||
"tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs",
|
||||
"tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs",
|
||||
"tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs",
|
||||
"tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs",
|
||||
|
||||
// TODO: frontmatter
|
||||
// https://github.com/dtolnay/syn/issues/1893
|
||||
"tests/ui/frontmatter/auxiliary/lib.rs",
|
||||
"tests/ui/frontmatter/dot-in-infostring-non-leading.rs",
|
||||
"tests/ui/frontmatter/escape.rs",
|
||||
"tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs",
|
||||
"tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs",
|
||||
"tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs",
|
||||
"tests/ui/frontmatter/frontmatter-whitespace-3.rs",
|
||||
"tests/ui/frontmatter/frontmatter-whitespace-4.rs",
|
||||
"tests/ui/frontmatter/shebang.rs",
|
||||
"tests/ui/unpretty/frontmatter.rs",
|
||||
|
||||
// TODO: `|| .. .method()`
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_range_method_call.rs",
|
||||
"src/tools/rustfmt/tests/source/issue-4808.rs",
|
||||
|
||||
// Negative inherent impl: `impl !Box<JoinHandle> {}`
|
||||
"src/tools/rustfmt/tests/source/negative-impl.rs",
|
||||
"src/tools/rustfmt/tests/target/negative-impl.rs",
|
||||
|
||||
// Compile-fail expr parameter in const generic position: `f::<1 + 2>()`
|
||||
"tests/ui/const-generics/early/closing-args-token.rs",
|
||||
"tests/ui/const-generics/early/const-expression-parameter.rs",
|
||||
|
||||
// Compile-fail variadics in not the last position of a function parameter list
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/fn_def_param.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_vararg.rs",
|
||||
"tests/ui/parser/variadic-ffi-syntactic-pass.rs",
|
||||
|
||||
// Need at least one trait in impl Trait, no such type as impl 'static
|
||||
@@ -69,20 +297,24 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
|
||||
// Negative polarity trait bound: `where T: !Copy`
|
||||
"src/tools/rustfmt/tests/target/negative-bounds.rs",
|
||||
|
||||
// Lifetime bound inside for<>: `T: ~const ?for<'a: 'b> Trait<'a>`
|
||||
"tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs",
|
||||
"tests/ui/traits/negative-bounds/supertrait.rs",
|
||||
|
||||
// Const impl that is not a trait impl: `impl ~const T {}`
|
||||
"tests/ui/rfcs/rfc-2632-const-trait-impl/syntax.rs",
|
||||
"tests/ui/traits/const-traits/syntax.rs",
|
||||
|
||||
// Lifetimes and types out of order in angle bracketed path arguments
|
||||
"tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs",
|
||||
|
||||
// Deprecated anonymous parameter syntax in traits
|
||||
"src/tools/rustfmt/tests/source/trait.rs",
|
||||
"src/tools/rustfmt/tests/target/trait.rs",
|
||||
"tests/ui/issues/issue-13105.rs",
|
||||
"tests/ui/issues/issue-13775.rs",
|
||||
"tests/pretty/hir-fn-params.rs",
|
||||
"tests/rustdoc/anon-fn-params.rs",
|
||||
"tests/rustdoc/auxiliary/ext-anon-fn-params.rs",
|
||||
"tests/ui/fn/anonymous-parameters-trait-13105.rs",
|
||||
"tests/ui/issues/issue-34074.rs",
|
||||
"tests/ui/proc-macro/trait-fn-args-2015.rs",
|
||||
"tests/ui/trait-bounds/anonymous-parameters-13775.rs",
|
||||
|
||||
// Deprecated where-clause location
|
||||
"src/tools/rustfmt/tests/source/issue_4257.rs",
|
||||
@@ -93,10 +325,8 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"tests/rustdoc/generic-associated-types/gats.rs",
|
||||
|
||||
// Deprecated trait object syntax with parenthesized generic arguments and no dyn keyword
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rs",
|
||||
"src/tools/rustfmt/tests/source/attrib.rs",
|
||||
"src/tools/rustfmt/tests/source/closure.rs",
|
||||
"src/tools/rustfmt/tests/source/existential_type.rs",
|
||||
@@ -121,25 +351,21 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"tests/pretty/closure-reform-pretty.rs",
|
||||
"tests/run-make/reproducible-build-2/reproducible-build.rs",
|
||||
"tests/run-make/reproducible-build/reproducible-build.rs",
|
||||
"tests/ui/auxiliary/typeid-intrinsic-aux1.rs",
|
||||
"tests/ui/auxiliary/typeid-intrinsic-aux2.rs",
|
||||
"tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs",
|
||||
"tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs",
|
||||
"tests/ui/lifetimes/bare-trait-object-borrowck.rs",
|
||||
"tests/ui/lifetimes/bare-trait-object.rs",
|
||||
"tests/ui/parser/bounds-obj-parens.rs",
|
||||
|
||||
// Invalid unparenthesized range pattern inside slice pattern: `[1..]`
|
||||
"tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs",
|
||||
|
||||
// Various extensions to Rust syntax made up by rust-analyzer
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_param_default_path.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/use_tree_abs_star.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs",
|
||||
@@ -149,19 +375,25 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0261_dangling_impl_undeclared_lifetime.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rs",
|
||||
|
||||
// Placeholder syntax for "throw expressions"
|
||||
"compiler/rustc_errors/src/translation.rs",
|
||||
"compiler/rustc_expand/src/module.rs",
|
||||
"compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs",
|
||||
"src/tools/clippy/tests/ui/needless_return.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0204_yeet_expr.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/yeet_expr.rs",
|
||||
"tests/pretty/yeet-expr.rs",
|
||||
"tests/ui/try-trait/yeet-for-option.rs",
|
||||
"tests/ui/try-trait/yeet-for-result.rs",
|
||||
|
||||
// Edition 2015 code using identifiers that are now keywords
|
||||
// TODO: some of these we should probably parse
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs",
|
||||
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs",
|
||||
"src/tools/rustfmt/tests/source/configs/indent_style/block_call.rs",
|
||||
"src/tools/rustfmt/tests/source/configs/use_try_shorthand/false.rs",
|
||||
"src/tools/rustfmt/tests/source/configs/use_try_shorthand/true.rs",
|
||||
@@ -174,6 +406,7 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"tests/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs",
|
||||
"tests/ui/editions/edition-keywords-2015-2015.rs",
|
||||
"tests/ui/editions/edition-keywords-2015-2018.rs",
|
||||
"tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs",
|
||||
"tests/ui/lint/lint_pre_expansion_extern_module_aux.rs",
|
||||
"tests/ui/macros/macro-comma-support-rpass.rs",
|
||||
"tests/ui/macros/try-macro.rs",
|
||||
@@ -184,9 +417,12 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"tests/ui/issues/issue-74564-if-expr-stack-overflow.rs",
|
||||
|
||||
// Testing tools on invalid syntax
|
||||
"src/tools/clippy/tests/ui/non_expressive_names_error_recovery.rs",
|
||||
"src/tools/rustfmt/tests/coverage/target/comments.rs",
|
||||
"src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
|
||||
"src/tools/rustfmt/tests/parser/issue_4418.rs",
|
||||
"src/tools/rustfmt/tests/parser/stashed-diag.rs",
|
||||
"src/tools/rustfmt/tests/parser/stashed-diag2.rs",
|
||||
"src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
|
||||
"src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
|
||||
"src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
|
||||
@@ -195,15 +431,13 @@ static EXCLUDE_FILES: &[&str] = &[
|
||||
"src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
|
||||
"src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
|
||||
"src/tools/rustfmt/tests/target/type.rs",
|
||||
"src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs",
|
||||
"tests/run-make/translation/test.rs",
|
||||
"tests/ui/generics/issue-94432-garbage-ice.rs",
|
||||
|
||||
// Generated file containing a top-level expression, used with `include!`
|
||||
"compiler/rustc_codegen_gcc/src/intrinsic/archs.rs",
|
||||
|
||||
// Clippy lint lists represented as expressions
|
||||
"src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
|
||||
|
||||
// Not actually test cases
|
||||
"tests/ui/lint/expansion-time-include.rs",
|
||||
"tests/ui/macros/auxiliary/macro-comma-support.rs",
|
||||
@@ -225,6 +459,9 @@ static EXCLUDE_DIRS: &[&str] = &[
|
||||
// Inputs that used to crash rust-analyzer, but aren't necessarily supposed to parse
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures",
|
||||
"src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures",
|
||||
|
||||
// Inputs that crash rustc, making no claim about whether they are valid Rust
|
||||
"tests/crashes",
|
||||
];
|
||||
|
||||
// Directories in which a .stderr implies the corresponding .rs is not expected
|
||||
@@ -294,10 +531,29 @@ pub fn edition(path: &Path) -> &'static str {
|
||||
if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
|
||||
"2015"
|
||||
} else {
|
||||
"2018"
|
||||
"2021"
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn abort_after() -> usize {
|
||||
match env::var("ABORT_AFTER_FAILURE") {
|
||||
Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"),
|
||||
Err(_) => usize::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rayon_init() {
|
||||
let stack_size = match env::var("RUST_MIN_STACK") {
|
||||
Ok(s) => s.parse().expect("failed to parse RUST_MIN_STACK"),
|
||||
Err(_) => 1024 * 1024 * if cfg!(debug_assertions) { 40 } else { 20 },
|
||||
};
|
||||
ThreadPoolBuilder::new()
|
||||
.stack_size(stack_size)
|
||||
.build_global()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn clone_rust() {
|
||||
let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
|
||||
Err(_) => true,
|
||||
@@ -344,10 +600,9 @@ pub fn clone_rust() {
|
||||
}
|
||||
|
||||
fn download_and_unpack() -> Result<()> {
|
||||
let url = format!(
|
||||
"https://github.com/rust-lang/rust/archive/{}.tar.gz",
|
||||
REVISION
|
||||
);
|
||||
let url = format!("https://github.com/rust-lang/rust/archive/{REVISION}.tar.gz");
|
||||
errorf!("downloading {url}\n");
|
||||
|
||||
let response = reqwest::blocking::get(url)?.error_for_status()?;
|
||||
let progress = Progress::new(response);
|
||||
let decoder = GzDecoder::new(progress);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#![allow(unused_macros, unused_macro_rules)]
|
||||
|
||||
use std::str::FromStr;
|
||||
use syn::parse::Result;
|
||||
|
||||
macro_rules! snapshot {
|
||||
($($args:tt)*) => {
|
||||
snapshot_impl!(() $($args)*)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! snapshot_impl {
|
||||
(($expr:ident) as $t:ty, @$snapshot:literal) => {
|
||||
let tokens = crate::snapshot::TryIntoTokens::try_into_tokens($expr).unwrap();
|
||||
let $expr: $t = syn::parse_quote!(#tokens);
|
||||
let debug = crate::debug::Lite(&$expr);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)] // https://github.com/mitsuhiko/insta/issues/389
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
};
|
||||
(($($expr:tt)*) as $t:ty, @$snapshot:literal) => {{
|
||||
let tokens = crate::snapshot::TryIntoTokens::try_into_tokens($($expr)*).unwrap();
|
||||
let syntax_tree: $t = syn::parse_quote!(#tokens);
|
||||
let debug = crate::debug::Lite(&syntax_tree);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)]
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
syntax_tree
|
||||
}};
|
||||
(($($expr:tt)*) , @$snapshot:literal) => {{
|
||||
let syntax_tree = $($expr)*;
|
||||
let debug = crate::debug::Lite(&syntax_tree);
|
||||
if !cfg!(miri) {
|
||||
#[allow(clippy::needless_raw_string_hashes)]
|
||||
{
|
||||
insta::assert_debug_snapshot!(debug, @$snapshot);
|
||||
}
|
||||
}
|
||||
syntax_tree
|
||||
}};
|
||||
(($($expr:tt)*) $next:tt $($rest:tt)*) => {
|
||||
snapshot_impl!(($($expr)* $next) $($rest)*)
|
||||
};
|
||||
}
|
||||
|
||||
pub trait TryIntoTokens {
|
||||
#[allow(dead_code)]
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream>;
|
||||
}
|
||||
|
||||
impl TryIntoTokens for &str {
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> {
|
||||
let tokens = proc_macro2::TokenStream::from_str(self)?;
|
||||
Ok(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryIntoTokens for proc_macro2::TokenStream {
|
||||
fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
+12
-6
@@ -1,7 +1,13 @@
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
#![allow(
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod snapshot;
|
||||
|
||||
mod debug;
|
||||
|
||||
use syn::{Expr, Item};
|
||||
|
||||
@@ -9,7 +15,7 @@ use syn::{Expr, Item};
|
||||
fn test_async_fn() {
|
||||
let input = "async fn process() {}";
|
||||
|
||||
snapshot!(input as Item, @r###"
|
||||
snapshot!(input as Item, @r#"
|
||||
Item::Fn {
|
||||
vis: Visibility::Inherited,
|
||||
sig: Signature {
|
||||
@@ -22,14 +28,14 @@ fn test_async_fn() {
|
||||
stmts: [],
|
||||
},
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_async_closure() {
|
||||
let input = "async || {}";
|
||||
|
||||
snapshot!(input as Expr, @r###"
|
||||
snapshot!(input as Expr, @r#"
|
||||
Expr::Closure {
|
||||
asyncness: Some,
|
||||
output: ReturnType::Default,
|
||||
@@ -39,5 +45,5 @@ fn test_async_closure() {
|
||||
},
|
||||
},
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user