aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-11-17 00:14:03 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-11-17 00:14:03 +0000
commit10f5acc0f0b3f5d4dbd4f871af7ceb4e18a0aca5 (patch)
treeb5292124981f207ffbb2a12b3a78d6e5a65c0d77
parent129301cc8a06384523784f740016f0e251fe2fca (diff)
parentaf68bf99ca6c35f44c4ec225f7c5d37a20e2873b (diff)
downloadsyn-mid-android14-qpr2-s1-release.tar.gz
Change-Id: I5caebfa8e2b2ecb7898f9842cf2e2be5f9599cdb
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--.clippy.toml1
-rw-r--r--.editorconfig20
-rw-r--r--.gitattributes1
-rw-r--r--.rustfmt.toml34
-rw-r--r--Android.bp8
-rw-r--r--CHANGELOG.md20
-rw-r--r--Cargo.toml50
-rw-r--r--Cargo.toml.orig24
-rw-r--r--METADATA14
-rw-r--r--README.md28
-rw-r--r--cargo2android.json5
-rw-r--r--cargo_embargo.json9
-rw-r--r--patches/syn-2.patch50
-rw-r--r--src/func.rs297
-rw-r--r--src/lib.rs106
-rw-r--r--src/macros.rs15
-rw-r--r--src/pat.rs204
-rw-r--r--src/path.rs4
19 files changed, 523 insertions, 374 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index ea91f75..4d497af 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "6a4dcb4b7c3bcb2ad086745bc88515a6756e3edc"
- }
-}
+ "sha1": "4eebddd1dc907b1edb4deb1b497617698a086f12"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/.clippy.toml b/.clippy.toml
deleted file mode 100644
index 422beeb..0000000
--- a/.clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-msrv = "1.31"
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index a73a88d..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-# EditorConfig configuration
-# https://editorconfig.org
-
-root = true
-
-[*]
-charset = utf-8
-end_of_line = lf
-indent_size = 4
-indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.{json,yml,md}]
-indent_size = 2
-
-[*.sh]
-indent_size = 2
-binary_next_line = true
-switch_case_indent = true
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 6313b56..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto eol=lf
diff --git a/.rustfmt.toml b/.rustfmt.toml
deleted file mode 100644
index 6604f5c..0000000
--- a/.rustfmt.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-# Rustfmt configuration
-# https://github.com/rust-lang/rustfmt/blob/HEAD/Configurations.md
-
-# This is required for bug-fixes, which technically can't be made to the stable
-# first version.
-# This is unstable (tracking issue: https://github.com/rust-lang/rustfmt/issues/3383).
-version = "Two"
-# Rustfmt cannot format long lines inside macros, but this option detects this.
-# This is unstable (tracking issue: https://github.com/rust-lang/rustfmt/issues/3391)
-error_on_line_overflow = true
-
-# Override the default formatting style.
-# See https://internals.rust-lang.org/t/running-rustfmt-on-rust-lang-rust-and-other-rust-lang-repositories/8732/81.
-use_small_heuristics = "Max"
-# See https://github.com/rust-dev-tools/fmt-rfcs/issues/149.
-# This is unstable (tracking issue: https://github.com/rust-lang/rustfmt/issues/3370)
-overflow_delimited_expr = true
-
-# Apply rustfmt to more places.
-# This is unstable (tracking issue: https://github.com/rust-lang/rustfmt/issues/3362).
-merge_imports = true
-# This is unstable (tracking issue: https://github.com/rust-lang/rustfmt/issues/3348).
-format_code_in_doc_comments = true
-
-# Automatically fix deprecated style.
-use_field_init_shorthand = true
-use_try_shorthand = true
-
-# Set the default settings again to always apply the proper formatting without
-# being affected by the editor settings.
-edition = "2018"
-hard_tabs = false
-newline_style = "Unix"
-tab_spaces = 4
diff --git a/Android.bp b/Android.bp
index 5a487de..7da01bd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --config cargo2android.json.
+// This file is generated by cargo_embargo.
// Do not modify this file as changes will be overridden on upgrade.
package {
@@ -41,15 +41,13 @@ rust_library_host {
name: "libsyn_mid",
crate_name: "syn_mid",
cargo_env_compat: true,
- cargo_pkg_version: "0.5.3",
+ cargo_pkg_version: "0.6.0",
srcs: ["src/lib.rs"],
- edition: "2018",
+ edition: "2021",
rustlibs: [
"libproc_macro2",
"libquote",
"libsyn",
],
compile_multilib: "first",
- product_available: true,
- vendor_available: true,
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6eafa2e..82ee4b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,16 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
## [Unreleased]
+## [0.6.0] - 2023-09-30
+
+- Update to syn 2.0. ([#26](https://github.com/taiki-e/syn-mid/pull/26))
+
+## [0.5.4] - 2023-06-29
+
+- Increase the minimum supported Rust version from Rust 1.31 to Rust 1.56.
+
+- Update minimal version of `proc-macro2` to 1.0.60.
+
## [0.5.3] - 2021-01-05
- Exclude unneeded files from crates.io.
@@ -28,9 +38,7 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
## [0.5.0] - 2019-12-09
-- [Added `Signature` type.][13]
-
-[13]: https://github.com/taiki-e/syn-mid/pull/13
+- Added `Signature` type. ([#13](https://github.com/taiki-e/syn-mid/pull/13))
## [0.4.0] - 2019-08-15
@@ -62,11 +70,13 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
## [0.1.0] - 2019-02-14
-**Note: This release has been yanked.**
+**Note:** This release has been yanked.
Initial release
-[Unreleased]: https://github.com/taiki-e/syn-mid/compare/v0.5.3...HEAD
+[Unreleased]: https://github.com/taiki-e/syn-mid/compare/v0.6.0...HEAD
+[0.6.0]: https://github.com/taiki-e/syn-mid/compare/v0.5.4...v0.6.0
+[0.5.4]: https://github.com/taiki-e/syn-mid/compare/v0.5.3...v0.5.4
[0.5.3]: https://github.com/taiki-e/syn-mid/compare/v0.5.2...v0.5.3
[0.5.2]: https://github.com/taiki-e/syn-mid/compare/v0.5.1...v0.5.2
[0.5.1]: https://github.com/taiki-e/syn-mid/compare/v0.5.0...v0.5.1
diff --git a/Cargo.toml b/Cargo.toml
index 422755b..a646f02 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,31 +3,45 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.56"
name = "syn-mid"
-version = "0.5.3"
-authors = ["Taiki Endo <te316e89@gmail.com>"]
-exclude = ["/.github", "/scripts"]
-description = "Providing the features between \"full\" and \"derive\" of syn.\n"
-documentation = "https://docs.rs/syn-mid"
+version = "0.6.0"
+exclude = [
+ "/.*",
+ "/tools",
+]
+description = """
+Providing the features between \"full\" and \"derive\" of syn.
+"""
readme = "README.md"
-keywords = ["syn", "macros"]
-categories = ["development-tools::procedural-macro-helpers"]
+keywords = [
+ "syn",
+ "macros",
+]
+categories = [
+ "development-tools::procedural-macro-helpers",
+ "parser-implementations",
+]
license = "Apache-2.0 OR MIT"
repository = "https://github.com/taiki-e/syn-mid"
+
[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-unknown-linux-gnu"]
+
+[lib]
+doc-scrape-examples = false
+
[dependencies.proc-macro2]
-version = "1"
+version = "1.0.60"
default-features = false
[dependencies.quote]
@@ -35,8 +49,12 @@ version = "1"
default-features = false
[dependencies.syn]
-version = "1.0.44"
-features = ["parsing", "printing", "derive"]
+version = "2"
+features = [
+ "parsing",
+ "printing",
+ "derive",
+]
default-features = false
[features]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 965c63a..0c7caa0 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,15 +1,13 @@
[package]
name = "syn-mid"
-version = "0.5.3"
-authors = ["Taiki Endo <te316e89@gmail.com>"]
-edition = "2018"
+version = "0.6.0"
+edition = "2021"
+rust-version = "1.56"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/taiki-e/syn-mid"
-documentation = "https://docs.rs/syn-mid"
keywords = ["syn", "macros"]
-categories = ["development-tools::procedural-macro-helpers"]
-readme = "README.md"
-exclude = ["/.github", "/scripts"]
+categories = ["development-tools::procedural-macro-helpers", "parser-implementations"]
+exclude = ["/.*", "/tools"]
description = """
Providing the features between \"full\" and \"derive\" of syn.
"""
@@ -19,13 +17,17 @@ all-features = true
targets = ["x86_64-unknown-linux-gnu"]
[workspace]
-members = ["examples/const_fn", "examples/const_fn_test"]
+resolver = "2"
+members = ["examples/const_fn"]
+
+[lib]
+doc-scrape-examples = false
[features]
clone-impls = ["syn/clone-impls"]
-# NB: proc-macro2, quote, and syn are public dependencies.
+# Note: proc-macro2, quote, and syn are public dependencies.
[dependencies]
-proc-macro2 = { version = "1", default-features = false }
+proc-macro2 = { version = "1.0.60", default-features = false }
quote = { version = "1", default-features = false }
-syn = { version = "1.0.44", default-features = false, features = ["parsing", "printing", "derive"] }
+syn = { version = "2", default-features = false, features = ["parsing", "printing", "derive"] }
diff --git a/METADATA b/METADATA
index 540870e..df66819 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/syn-mid
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
name: "syn-mid"
description: "Providing the features between \"full\" and \"derive\" of syn."
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/syn-mid/syn-mid-0.5.3.crate"
+ value: "https://static.crates.io/crates/syn-mid/syn-mid-0.6.0.crate"
}
- version: "0.5.3"
+ version: "0.6.0"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 1
- day: 5
+ year: 2023
+ month: 11
+ day: 15
}
}
diff --git a/README.md b/README.md
index 87ce628..cfd6f7e 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,24 @@
# syn-mid
-[![crates.io](https://img.shields.io/crates/v/syn-mid.svg?style=flat-square&logo=rust)](https://crates.io/crates/syn-mid)
-[![docs.rs](https://img.shields.io/badge/docs.rs-syn--mid-blue?style=flat-square)](https://docs.rs/syn-mid)
-[![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg?style=flat-square)](#license)
-[![rustc](https://img.shields.io/badge/rustc-1.31+-blue.svg?style=flat-square)](https://www.rust-lang.org)
-[![build status](https://img.shields.io/github/workflow/status/taiki-e/syn-mid/CI/master?style=flat-square)](https://github.com/taiki-e/syn-mid/actions?query=workflow%3ACI+branch%3Amaster)
+[![crates.io](https://img.shields.io/crates/v/syn-mid?style=flat-square&logo=rust)](https://crates.io/crates/syn-mid)
+[![docs.rs](https://img.shields.io/badge/docs.rs-syn--mid-blue?style=flat-square&logo=docs.rs)](https://docs.rs/syn-mid)
+[![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue?style=flat-square)](#license)
+[![rustc](https://img.shields.io/badge/rustc-1.56+-blue?style=flat-square&logo=rust)](https://www.rust-lang.org)
+[![build status](https://img.shields.io/github/actions/workflow/status/taiki-e/syn-mid/ci.yml?branch=main&style=flat-square&logo=github)](https://github.com/taiki-e/syn-mid/actions)
+<!-- tidy:crate-doc:start -->
Providing the features between "full" and "derive" of syn.
This crate provides the following two unique data structures.
-- `syn_mid::ItemFn` -- A function whose body is not parsed.
+- [`syn_mid::ItemFn`] -- A function whose body is not parsed.
```text
fn process(n: usize) -> Result<()> { ... }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^
```
-- `syn_mid::Block` -- A block whose body is not parsed.
+- [`syn_mid::Block`] -- A block whose body is not parsed.
```text
{ ... }
@@ -28,8 +29,6 @@ Other data structures are the same as data structures of [syn]. These are
defined in this crate because they cannot be used in [syn] without "full"
feature.
-[syn]: https://github.com/dtolnay/syn
-
## Usage
Add this to your `Cargo.toml`:
@@ -39,14 +38,21 @@ Add this to your `Cargo.toml`:
syn-mid = "0.5"
```
-*Compiler support: requires rustc 1.31+*
+*Compiler support: requires rustc 1.56+*
-[**Examples**](examples)
+[**Examples**](https://github.com/taiki-e/syn-mid/tree/HEAD/examples)
## Optional features
- **`clone-impls`** — Clone impls for all syntax tree types.
+[syn]: https://github.com/dtolnay/syn
+
+<!-- tidy:crate-doc:end -->
+
+[`syn_mid::Block`]: https://docs.rs/syn-mid/latest/syn_mid/struct.Block.html
+[`syn_mid::ItemFn`]: https://docs.rs/syn-mid/latest/syn_mid/struct.ItemFn.html
+
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
diff --git a/cargo2android.json b/cargo2android.json
deleted file mode 100644
index b360f74..0000000
--- a/cargo2android.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "host-first-multilib": true,
- "run": true,
- "tests": true
-} \ No newline at end of file
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..b49e77c
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,9 @@
+{
+ "package": {
+ "syn-mid": {
+ "device_supported": false,
+ "host_first_multilib": true
+ }
+ },
+ "run_cargo": false
+}
diff --git a/patches/syn-2.patch b/patches/syn-2.patch
deleted file mode 100644
index a25bd0c..0000000
--- a/patches/syn-2.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-diff --git a/src/func.rs b/src/func.rs
-index a53e63b..384e80b 100644
---- a/src/func.rs
-+++ b/src/func.rs
-@@ -85,11 +85,12 @@ mod parsing {
-
- impl Parse for Signature {
- fn parse(input: ParseStream<'_>) -> Result<Self> {
-+ #[allow(clippy::trivially_copy_pass_by_ref)]
- fn get_variadic(input: &&FnArg) -> Option<Variadic> {
- if let FnArg::Typed(PatType { ty, .. }) = input {
- if let Type::Verbatim(tokens) = &**ty {
- if let Ok(dots) = parse2(tokens.clone()) {
-- return Some(Variadic { attrs: Vec::new(), dots });
-+ return Some(Variadic { attrs: Vec::new(), pat: None, comma: None, dots });
- }
- }
- }
-@@ -106,7 +107,7 @@ mod parsing {
-
- let content;
- let paren_token = parenthesized!(content in input);
-- let inputs = content.parse_terminated(FnArg::parse)?;
-+ let inputs = content.parse_terminated(FnArg::parse, Token![,])?;
- let variadic = inputs.last().as_ref().and_then(get_variadic);
-
- let output: ReturnType = input.parse()?;
-@@ -119,11 +120,11 @@ mod parsing {
- abi,
- fn_token,
- ident,
-+ generics,
- paren_token,
- inputs,
-- output,
- variadic,
-- generics,
-+ output,
- })
- }
- }
-@@ -210,7 +211,7 @@ mod printing {
- FnArg::Receiver(_) => return false,
- };
-
-- let tokens = match pat.ty.as_ref() {
-+ let tokens = match &*pat.ty {
- Type::Verbatim(tokens) => tokens,
- _ => return false,
- };
diff --git a/src/func.rs b/src/func.rs
index 384e80b..477841b 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -1,10 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+// Based on https://github.com/dtolnay/syn/blob/2.0.37/src/item.rs.
+
use proc_macro2::TokenStream;
use syn::{
punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, Lifetime, ReturnType, Token,
- Variadic, Visibility,
+ Type, Visibility,
};
-use super::PatType;
+use super::{Pat, PatType};
ast_struct! {
/// A free-standing function: `fn process(n: usize) -> Result<()> { ...
@@ -64,6 +68,18 @@ ast_struct! {
pub reference: Option<(Token![&], Option<Lifetime>)>,
pub mutability: Option<Token![mut]>,
pub self_token: Token![self],
+ pub colon_token: Option<Token![:]>,
+ pub ty: Box<Type>,
+ }
+}
+
+ast_struct! {
+ /// The variadic argument of a foreign function.
+ pub struct Variadic {
+ pub attrs: Vec<Attribute>,
+ pub pat: Option<(Box<Pat>, Token![:])>,
+ pub dots: Token![...],
+ pub comma: Option<Token![,]>,
}
}
@@ -71,10 +87,13 @@ mod parsing {
use syn::{
braced, parenthesized,
parse::{discouraged::Speculative, Parse, ParseStream, Result},
- parse2, Abi, Attribute, Generics, Ident, ReturnType, Token, Type, Variadic, Visibility,
+ punctuated::Punctuated,
+ Abi, Attribute, Error, Generics, Ident, Lifetime, Path, ReturnType, Token, Type, TypePath,
+ TypeReference, Visibility,
};
- use super::{Block, FnArg, ItemFn, PatType, Receiver, Signature};
+ use super::{Block, FnArg, ItemFn, Receiver, Signature, Variadic};
+ use crate::pat::{Pat, PatType, PatWild};
impl Parse for Block {
fn parse(input: ParseStream<'_>) -> Result<Self> {
@@ -85,18 +104,6 @@ mod parsing {
impl Parse for Signature {
fn parse(input: ParseStream<'_>) -> Result<Self> {
- #[allow(clippy::trivially_copy_pass_by_ref)]
- fn get_variadic(input: &&FnArg) -> Option<Variadic> {
- if let FnArg::Typed(PatType { ty, .. }) = input {
- if let Type::Verbatim(tokens) = &**ty {
- if let Ok(dots) = parse2(tokens.clone()) {
- return Some(Variadic { attrs: Vec::new(), pat: None, comma: None, dots });
- }
- }
- }
- None
- }
-
let constness: Option<Token![const]> = input.parse()?;
let asyncness: Option<Token![async]> = input.parse()?;
let unsafety: Option<Token![unsafe]> = input.parse()?;
@@ -107,8 +114,7 @@ mod parsing {
let content;
let paren_token = parenthesized!(content in input);
- let inputs = content.parse_terminated(FnArg::parse, Token![,])?;
- let variadic = inputs.last().as_ref().and_then(get_variadic);
+ let (inputs, variadic) = parse_fn_args(&content)?;
let output: ReturnType = input.parse()?;
generics.where_clause = input.parse()?;
@@ -133,7 +139,7 @@ mod parsing {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let vis: Visibility = input.parse()?;
- let sig = input.parse()?;
+ let sig: Signature = input.parse()?;
let block = input.parse()?;
Ok(Self { attrs, vis, sig, block: Box::new(block) })
}
@@ -141,56 +147,185 @@ mod parsing {
impl Parse for FnArg {
fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let allow_variadic = false;
let attrs = input.call(Attribute::parse_outer)?;
-
- let ahead = input.fork();
- if let Ok(mut receiver) = ahead.parse::<Receiver>() {
- if !ahead.peek(Token![:]) {
- input.advance_to(&ahead);
- receiver.attrs = attrs;
- return Ok(FnArg::Receiver(receiver));
- }
+ match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? {
+ FnArgOrVariadic::FnArg(arg) => Ok(arg),
+ FnArgOrVariadic::Variadic(_) => unreachable!(),
}
+ }
+ }
+
+ enum FnArgOrVariadic {
+ FnArg(FnArg),
+ Variadic(Variadic),
+ }
- let mut typed = input.call(fn_arg_typed)?;
- typed.attrs = attrs;
- Ok(FnArg::Typed(typed))
+ fn parse_fn_arg_or_variadic(
+ input: ParseStream<'_>,
+ attrs: Vec<Attribute>,
+ allow_variadic: bool,
+ ) -> Result<FnArgOrVariadic> {
+ let ahead = input.fork();
+ if let Ok(mut receiver) = ahead.parse::<Receiver>() {
+ input.advance_to(&ahead);
+ receiver.attrs = attrs;
+ return Ok(FnArgOrVariadic::FnArg(FnArg::Receiver(receiver)));
}
+
+ // Hack to parse pre-2018 syntax in
+ // test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs
+ // because the rest of the test case is valuable.
+ if input.peek(Ident) && input.peek2(Token![<]) {
+ let span = input.fork().parse::<Ident>()?.span();
+ return Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType {
+ attrs,
+ pat: Box::new(Pat::Wild(PatWild {
+ attrs: Vec::new(),
+ underscore_token: Token![_](span),
+ })),
+ colon_token: Token![:](span),
+ ty: input.parse()?,
+ })));
+ }
+
+ let pat = Box::new(Pat::parse_single(input)?);
+ let colon_token: Token![:] = input.parse()?;
+
+ if allow_variadic {
+ if let Some(dots) = input.parse::<Option<Token![...]>>()? {
+ return Ok(FnArgOrVariadic::Variadic(Variadic {
+ attrs,
+ pat: Some((pat, colon_token)),
+ dots,
+ comma: None,
+ }));
+ }
+ }
+
+ Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType {
+ attrs,
+ pat,
+ colon_token,
+ ty: input.parse()?,
+ })))
}
impl Parse for Receiver {
fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let reference = if input.peek(Token![&]) {
+ let ampersand: Token![&] = input.parse()?;
+ let lifetime: Option<Lifetime> = input.parse()?;
+ Some((ampersand, lifetime))
+ } else {
+ None
+ };
+ let mutability: Option<Token![mut]> = input.parse()?;
+ let self_token: Token![self] = input.parse()?;
+ let colon_token: Option<Token![:]> =
+ if reference.is_some() { None } else { input.parse()? };
+ let ty: Type = if colon_token.is_some() {
+ input.parse()?
+ } else {
+ let mut ty = Type::Path(TypePath {
+ qself: None,
+ path: Path::from(Ident::new("Self", self_token.span)),
+ });
+ if let Some((ampersand, lifetime)) = reference.as_ref() {
+ ty = Type::Reference(TypeReference {
+ and_token: Token![&](ampersand.span),
+ lifetime: lifetime.clone(),
+ mutability: mutability.as_ref().map(|m| Token![mut](m.span)),
+ elem: Box::new(ty),
+ });
+ }
+ ty
+ };
Ok(Self {
attrs: Vec::new(),
- reference: {
- if input.peek(Token![&]) {
- Some((input.parse()?, input.parse()?))
- } else {
- None
- }
- },
- mutability: input.parse()?,
- self_token: input.parse()?,
+ reference,
+ mutability,
+ self_token,
+ colon_token,
+ ty: Box::new(ty),
})
}
}
- fn fn_arg_typed(input: ParseStream<'_>) -> Result<PatType> {
- Ok(PatType {
- attrs: Vec::new(),
- pat: input.parse()?,
- colon_token: input.parse()?,
- ty: Box::new(input.parse()?),
- })
+ fn parse_fn_args(
+ input: ParseStream<'_>,
+ ) -> Result<(Punctuated<FnArg, Token![,]>, Option<Variadic>)> {
+ let mut args = Punctuated::new();
+ let mut variadic = None;
+ let mut has_receiver = false;
+
+ while !input.is_empty() {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ if let Some(dots) = input.parse::<Option<Token![...]>>()? {
+ variadic = Some(Variadic {
+ attrs,
+ pat: None,
+ dots,
+ comma: if input.is_empty() { None } else { Some(input.parse()?) },
+ });
+ break;
+ }
+
+ let allow_variadic = true;
+ let arg = match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? {
+ FnArgOrVariadic::FnArg(arg) => arg,
+ FnArgOrVariadic::Variadic(arg) => {
+ variadic = Some(Variadic {
+ comma: if input.is_empty() { None } else { Some(input.parse()?) },
+ ..arg
+ });
+ break;
+ }
+ };
+
+ match &arg {
+ FnArg::Receiver(receiver) if has_receiver => {
+ return Err(Error::new(
+ receiver.self_token.span,
+ "unexpected second method receiver",
+ ));
+ }
+ FnArg::Receiver(receiver) if !args.is_empty() => {
+ return Err(Error::new(receiver.self_token.span, "unexpected method receiver"));
+ }
+ FnArg::Receiver(_) => has_receiver = true,
+ FnArg::Typed(_) => {}
+ }
+ args.push_value(arg);
+
+ if input.is_empty() {
+ break;
+ }
+
+ let comma: Token![,] = input.parse()?;
+ args.push_punct(comma);
+ }
+
+ Ok((args, variadic))
}
}
mod printing {
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt};
- use syn::{punctuated::Punctuated, Token, Type};
+ use syn::{Token, Type};
- use super::{Block, FnArg, ItemFn, Receiver, Signature};
+ use super::{Block, ItemFn, Receiver, Signature, Variadic};
+
+ impl ToTokens for ItemFn {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.vis.to_tokens(tokens);
+ self.sig.to_tokens(tokens);
+ self.block.to_tokens(tokens);
+ }
+ }
impl ToTokens for Block {
fn to_tokens(&self, tokens: &mut TokenStream) {
@@ -200,25 +335,6 @@ mod printing {
}
}
- fn has_variadic(inputs: &Punctuated<FnArg, Token![,]>) -> bool {
- let last = match inputs.last() {
- Some(last) => last,
- None => return false,
- };
-
- let pat = match last {
- FnArg::Typed(pat) => pat,
- FnArg::Receiver(_) => return false,
- };
-
- let tokens = match &*pat.ty {
- Type::Verbatim(tokens) => tokens,
- _ => return false,
- };
-
- tokens.to_string() == "..."
- }
-
impl ToTokens for Signature {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.constness.to_tokens(tokens);
@@ -230,11 +346,11 @@ mod printing {
self.generics.to_tokens(tokens);
self.paren_token.surround(tokens, |tokens| {
self.inputs.to_tokens(tokens);
- if self.variadic.is_some() && !has_variadic(&self.inputs) {
+ if let Some(variadic) = &self.variadic {
if !self.inputs.empty_or_trailing() {
<Token![,]>::default().to_tokens(tokens);
}
- self.variadic.to_tokens(tokens);
+ variadic.to_tokens(tokens);
}
});
self.output.to_tokens(tokens);
@@ -242,17 +358,6 @@ mod printing {
}
}
- impl ToTokens for ItemFn {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- tokens.append_all(&self.attrs);
- self.vis.to_tokens(tokens);
- self.sig.to_tokens(tokens);
- self.block.brace_token.surround(tokens, |tokens| {
- tokens.append_all(self.block.stmts.clone());
- });
- }
- }
-
impl ToTokens for Receiver {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(&self.attrs);
@@ -262,6 +367,38 @@ mod printing {
}
self.mutability.to_tokens(tokens);
self.self_token.to_tokens(tokens);
+ if let Some(colon_token) = &self.colon_token {
+ colon_token.to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ } else {
+ let consistent = match (&self.reference, &self.mutability, &*self.ty) {
+ (Some(_), mutability, Type::Reference(ty)) => {
+ mutability.is_some() == ty.mutability.is_some()
+ && match &*ty.elem {
+ Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"),
+ _ => false,
+ }
+ }
+ (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"),
+ _ => false,
+ };
+ if !consistent {
+ <Token![:]>::default().to_tokens(tokens);
+ self.ty.to_tokens(tokens);
+ }
+ }
+ }
+ }
+
+ impl ToTokens for Variadic {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ if let Some((pat, colon)) = &self.pat {
+ pat.to_tokens(tokens);
+ colon.to_tokens(tokens);
+ }
+ self.dots.to_tokens(tokens);
+ self.comma.to_tokens(tokens);
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index ca490cf..ad0bf73 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,32 +1,50 @@
-//! Providing the features between "full" and "derive" of syn.
-//!
-//! This crate provides the following two unique data structures.
-//!
-//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
-//!
-//! ```text
-//! fn process(n: usize) -> Result<()> { ... }
-//! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^
-//! ```
-//!
-//! * [`syn_mid::Block`] -- A block whose body is not parsed.
-//!
-//! ```text
-//! { ... }
-//! ^ ^
-//! ```
-//!
-//! Other data structures are the same as data structures of [syn]. These are
-//! defined in this crate because they cannot be used in [syn] without "full"
-//! feature.
-//!
-//! # Optional features
-//!
-//! * **`clone-impls`** — Clone impls for all syntax tree types.
-//!
-//! [`syn_mid::ItemFn`]: ItemFn
-//! [`syn_mid::Block`]: Block
-//! [syn]: https://github.com/dtolnay/syn
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+/*!
+<!-- tidy:crate-doc:start -->
+Providing the features between "full" and "derive" of syn.
+
+This crate provides the following two unique data structures.
+
+- [`syn_mid::ItemFn`] -- A function whose body is not parsed.
+
+ ```text
+ fn process(n: usize) -> Result<()> { ... }
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^
+ ```
+
+- [`syn_mid::Block`] -- A block whose body is not parsed.
+
+ ```text
+ { ... }
+ ^ ^
+ ```
+
+Other data structures are the same as data structures of [syn]. These are
+defined in this crate because they cannot be used in [syn] without "full"
+feature.
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+syn-mid = "0.5"
+```
+
+*Compiler support: requires rustc 1.56+*
+
+[**Examples**](https://github.com/taiki-e/syn-mid/tree/HEAD/examples)
+
+## Optional features
+
+- **`clone-impls`** — Clone impls for all syntax tree types.
+
+[syn]: https://github.com/dtolnay/syn
+
+<!-- tidy:crate-doc:end -->
+*/
#![doc(test(
no_crate_inject,
@@ -36,12 +54,29 @@
)
))]
#![forbid(unsafe_code)]
-#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
-#![warn(clippy::all, clippy::default_trait_access)]
-#![allow(clippy::eval_order_dependence, clippy::large_enum_variant)]
+#![warn(
+ rust_2018_idioms,
+ single_use_lifetimes,
+ unreachable_pub,
+ clippy::pedantic,
+ // Lints that may help when writing public library.
+ // missing_debug_implementations,
+ // missing_docs,
+ clippy::alloc_instead_of_core,
+ // clippy::exhaustive_enums, // TODO
+ // clippy::exhaustive_structs, // TODO
+ clippy::impl_trait_in_params,
+ // clippy::missing_inline_in_public_items,
+ // clippy::std_instead_of_alloc,
+ clippy::std_instead_of_core,
+)]
+#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)]
// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.
+#[cfg(doc)]
+extern crate self as syn_mid;
+
#[macro_use]
mod macros;
@@ -49,10 +84,13 @@ mod func;
mod pat;
mod path;
+#[doc(no_inline)]
+pub use syn::ExprPath as PatPath;
+
pub use crate::{
- func::{Block, FnArg, ItemFn, Receiver, Signature},
+ func::{Block, FnArg, ItemFn, Receiver, Signature, Variadic},
pat::{
- FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
+ FieldPat, Pat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct,
PatType, PatWild,
},
};
diff --git a/src/macros.rs b/src/macros.rs
index 87be7b4..7ea574c 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
macro_rules! ast_struct {
(
[$($attrs_pub:tt)*]
@@ -7,8 +9,8 @@ macro_rules! ast_struct {
$($attrs_pub)* struct $name $($rest)*
};
- ($($t:tt)*) => {
- strip_attrs_pub!(ast_struct!($($t)*));
+ ($($tt:tt)*) => {
+ strip_attrs_pub!(ast_struct!($($tt)*));
};
}
@@ -21,8 +23,8 @@ macro_rules! ast_enum {
$($attrs_pub)* enum $name $($rest)*
);
- ($($t:tt)*) => {
- strip_attrs_pub!(ast_enum!($($t)*));
+ ($($tt:tt)*) => {
+ strip_attrs_pub!(ast_enum!($($tt)*));
};
}
@@ -93,15 +95,14 @@ macro_rules! generate_to_tokens {
}
macro_rules! strip_attrs_pub {
- ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
+ ($mac:ident!($(#[$m:meta])* $pub:ident $($tt:tt)*)) => {
check_keyword_matches!(pub $pub);
- $mac!([$(#[$m])* $pub] $($t)*);
+ $mac!([$(#[$m])* $pub] $($tt)*);
};
}
macro_rules! check_keyword_matches {
- (struct struct) => {};
(enum enum) => {};
(pub pub) => {};
}
diff --git a/src/pat.rs b/src/pat.rs
index 78bf890..7a193fb 100644
--- a/src/pat.rs
+++ b/src/pat.rs
@@ -1,14 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+// Based on https://github.com/dtolnay/syn/blob/2.0.37/src/item.rs.
+
use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token, Type};
+use super::PatPath;
+
ast_enum_of_structs! {
/// A pattern in a local binding, function signature, match expression, or
/// various other places.
- ///
- /// # Syntax tree enum
- ///
- /// This type is a [syntax tree enum].
- ///
- /// [syntax tree enum]: https://docs.rs/syn/1/syn/enum.Expr.html#syntax-tree-enums
+ #[non_exhaustive]
pub enum Pat {
/// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`.
Ident(PatIdent),
@@ -33,9 +34,6 @@ ast_enum_of_structs! {
/// A pattern that matches any value: `_`.
Wild(PatWild),
-
- #[doc(hidden)]
- __Nonexhaustive,
}
}
@@ -50,14 +48,6 @@ ast_struct! {
}
ast_struct! {
- /// A path pattern like `Color::Red`.
- pub struct PatPath {
- pub attrs: Vec<Attribute>,
- pub path: Path,
- }
-}
-
-ast_struct! {
/// A reference pattern: `&mut var`.
pub struct PatReference {
pub attrs: Vec<Attribute>,
@@ -68,13 +58,21 @@ ast_struct! {
}
ast_struct! {
+ /// The dots in a tuple pattern: `[0, 1, ..]`.
+ pub struct PatRest {
+ pub attrs: Vec<Attribute>,
+ pub dot2_token: Token![..],
+ }
+}
+
+ast_struct! {
/// A struct or struct variant pattern: `Variant { x, y, .. }`.
pub struct PatStruct {
pub attrs: Vec<Attribute>,
pub path: Path,
pub brace_token: token::Brace,
pub fields: Punctuated<FieldPat, Token![,]>,
- pub dot2_token: Option<Token![..]>,
+ pub rest: Option<PatRest>,
}
}
@@ -92,7 +90,8 @@ ast_struct! {
pub struct PatTupleStruct {
pub attrs: Vec<Attribute>,
pub path: Path,
- pub pat: PatTuple,
+ pub paren_token: token::Paren,
+ pub elems: Punctuated<Pat, Token![,]>,
}
}
@@ -132,34 +131,32 @@ mod parsing {
braced,
ext::IdentExt,
parenthesized,
- parse::{Parse, ParseStream, Result},
+ parse::{ParseStream, Result},
punctuated::Punctuated,
- token, Attribute, Ident, Member, Path, Token,
+ token, Attribute, ExprPath, Ident, Member, Path, Token,
};
use super::{
- FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
+ FieldPat, Pat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct,
PatWild,
};
use crate::path;
- impl Parse for Pat {
- fn parse(input: ParseStream<'_>) -> Result<Self> {
+ impl Pat {
+ /// Parse a pattern that does _not_ involve `|` at the top level.
+ pub fn parse_single(input: ParseStream<'_>) -> Result<Self> {
let lookahead = input.lookahead1();
- if {
- let ahead = input.fork();
- ahead.parse::<Option<Ident>>()?.is_some()
- && (ahead.peek(Token![::])
- || ahead.peek(token::Brace)
- || ahead.peek(token::Paren))
- } || {
- let ahead = input.fork();
- ahead.parse::<Option<Token![self]>>()?.is_some() && ahead.peek(Token![::])
- } || lookahead.peek(Token![::])
+ if lookahead.peek(Ident)
+ && (input.peek2(Token![::])
+ || input.peek2(Token![!])
+ || input.peek2(token::Brace)
+ || input.peek2(token::Paren)
+ || input.peek2(Token![..]))
+ || input.peek(Token![self]) && input.peek2(Token![::])
+ || lookahead.peek(Token![::])
|| lookahead.peek(Token![<])
|| input.peek(Token![Self])
|| input.peek(Token![super])
- || input.peek(Token![extern])
|| input.peek(Token![crate])
{
pat_path_or_struct(input)
@@ -174,7 +171,7 @@ mod parsing {
} else if lookahead.peek(Token![&]) {
input.call(pat_reference).map(Pat::Reference)
} else if lookahead.peek(token::Paren) {
- input.call(pat_tuple).map(Pat::Tuple)
+ input.call(pat_paren_or_tuple)
} else {
Err(lookahead.error())
}
@@ -189,7 +186,7 @@ mod parsing {
} else if input.peek(token::Paren) {
pat_tuple_struct(input, path).map(Pat::TupleStruct)
} else {
- Ok(Pat::Path(PatPath { attrs: Vec::new(), path }))
+ Ok(Pat::Path(ExprPath { attrs: Vec::new(), qself: None, path }))
}
}
@@ -207,7 +204,21 @@ mod parsing {
}
fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
- Ok(PatTupleStruct { attrs: Vec::new(), path, pat: input.call(pat_tuple)? })
+ let content;
+ let paren_token = parenthesized!(content in input);
+
+ let mut elems = Punctuated::new();
+ while !content.is_empty() {
+ let value = Pat::parse_single(&content)?;
+ elems.push_value(value);
+ if content.is_empty() {
+ break;
+ }
+ let punct = content.parse()?;
+ elems.push_punct(punct);
+ }
+
+ Ok(PatTupleStruct { attrs: Vec::new(), path, paren_token, elems })
}
fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
@@ -215,8 +226,15 @@ mod parsing {
let brace_token = braced!(content in input);
let mut fields = Punctuated::new();
- while !content.is_empty() && !content.peek(Token![..]) {
- let value = content.call(field_pat)?;
+ let mut rest = None;
+ while !content.is_empty() {
+ let attrs = content.call(Attribute::parse_outer)?;
+ if content.peek(Token![..]) {
+ rest = Some(PatRest { attrs, dot2_token: content.parse()? });
+ break;
+ }
+ let mut value = content.call(field_pat)?;
+ value.attrs = attrs;
fields.push_value(value);
if content.is_empty() {
break;
@@ -225,30 +243,28 @@ mod parsing {
fields.push_punct(punct);
}
- let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) {
- Some(content.parse()?)
- } else {
- None
- };
-
- Ok(PatStruct { attrs: Vec::new(), path, brace_token, fields, dot2_token })
+ Ok(PatStruct { attrs: Vec::new(), path, brace_token, fields, rest })
}
fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
- let attrs = input.call(Attribute::parse_outer)?;
let boxed: Option<Token![box]> = input.parse()?;
let by_ref: Option<Token![ref]> = input.parse()?;
let mutability: Option<Token![mut]> = input.parse()?;
- let member: Member = input.parse()?;
+
+ let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
+ input.parse().map(Member::Named)
+ } else {
+ input.parse()
+ }?;
if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
|| is_unnamed(&member)
{
return Ok(FieldPat {
- attrs,
+ attrs: Vec::new(),
member,
- colon_token: input.parse()?,
- pat: input.parse()?,
+ colon_token: Some(input.parse()?),
+ pat: Box::new(Pat::parse_single(input)?),
});
}
@@ -260,25 +276,31 @@ mod parsing {
let pat =
Pat::Ident(PatIdent { attrs: Vec::new(), by_ref, mutability, ident: ident.clone() });
- Ok(FieldPat { attrs, member: Member::Named(ident), colon_token: None, pat: Box::new(pat) })
+ Ok(FieldPat {
+ attrs: Vec::new(),
+ member: Member::Named(ident),
+ colon_token: None,
+ pat: Box::new(pat),
+ })
}
- fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> {
+ fn pat_paren_or_tuple(input: ParseStream<'_>) -> Result<Pat> {
let content;
let paren_token = parenthesized!(content in input);
let mut elems = Punctuated::new();
while !content.is_empty() {
- let value: Pat = content.parse()?;
- elems.push_value(value);
+ let value = Pat::parse_single(&content)?;
if content.is_empty() {
+ elems.push_value(value);
break;
}
+ elems.push_value(value);
let punct = content.parse()?;
elems.push_punct(punct);
}
- Ok(PatTuple { attrs: Vec::new(), paren_token, elems })
+ Ok(Pat::Tuple(PatTuple { attrs: Vec::new(), paren_token, elems }))
}
fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> {
@@ -286,7 +308,7 @@ mod parsing {
attrs: Vec::new(),
and_token: input.parse()?,
mutability: input.parse()?,
- pat: input.parse()?,
+ pat: Box::new(Pat::parse_single(input)?),
})
}
@@ -304,42 +326,66 @@ mod printing {
use syn::Token;
use super::{
- FieldPat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType,
+ FieldPat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct, PatType,
PatWild,
};
- impl ToTokens for PatWild {
+ impl ToTokens for PatIdent {
fn to_tokens(&self, tokens: &mut TokenStream) {
- self.underscore_token.to_tokens(tokens);
+ tokens.append_all(&self.attrs);
+ self.by_ref.to_tokens(tokens);
+ self.mutability.to_tokens(tokens);
+ self.ident.to_tokens(tokens);
}
}
- impl ToTokens for PatIdent {
+ impl ToTokens for PatReference {
fn to_tokens(&self, tokens: &mut TokenStream) {
- self.by_ref.to_tokens(tokens);
+ tokens.append_all(&self.attrs);
+ self.and_token.to_tokens(tokens);
self.mutability.to_tokens(tokens);
- self.ident.to_tokens(tokens);
+ self.pat.to_tokens(tokens);
+ }
+ }
+
+ impl ToTokens for PatRest {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.dot2_token.to_tokens(tokens);
}
}
impl ToTokens for PatStruct {
fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
self.path.to_tokens(tokens);
self.brace_token.surround(tokens, |tokens| {
self.fields.to_tokens(tokens);
- // NOTE: We need a comma before the dot2 token if it is present.
- if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+ // Note: We need a comma before the dot2 token if it is present.
+ if !self.fields.empty_or_trailing() && self.rest.is_some() {
<Token![,]>::default().to_tokens(tokens);
}
- self.dot2_token.to_tokens(tokens);
+ self.rest.to_tokens(tokens);
+ });
+ }
+ }
+
+ impl ToTokens for PatTuple {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
});
}
}
impl ToTokens for PatTupleStruct {
fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
self.path.to_tokens(tokens);
- self.pat.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.elems.to_tokens(tokens);
+ });
}
}
@@ -352,30 +398,16 @@ mod printing {
}
}
- impl ToTokens for PatPath {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.path.to_tokens(tokens)
- }
- }
-
- impl ToTokens for PatTuple {
- fn to_tokens(&self, tokens: &mut TokenStream) {
- self.paren_token.surround(tokens, |tokens| {
- self.elems.to_tokens(tokens);
- });
- }
- }
-
- impl ToTokens for PatReference {
+ impl ToTokens for PatWild {
fn to_tokens(&self, tokens: &mut TokenStream) {
- self.and_token.to_tokens(tokens);
- self.mutability.to_tokens(tokens);
- self.pat.to_tokens(tokens);
+ tokens.append_all(&self.attrs);
+ self.underscore_token.to_tokens(tokens);
}
}
impl ToTokens for FieldPat {
fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.append_all(&self.attrs);
if let Some(colon_token) = &self.colon_token {
self.member.to_tokens(tokens);
colon_token.to_tokens(tokens);
diff --git a/src/path.rs b/src/path.rs
index c58a0c1..a643b74 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+// Based on https://github.com/dtolnay/syn/blob/2.0.37/src/path.rs.
+
use syn::{
ext::IdentExt,
parse::{ParseStream, Result},