Skip to content

Commit b436933

Browse files
Germanascjones
German
andauthored
Upgrade to syn v2 (#1731)
* syn 2.0 * TraitItemMethod -> TraitItemFn * Token bang * ImplItemMethod -> ImplItemFn * Token![pub] * Remove ItemMacro2 * WIP fix Attribute Span * WIP updates * WIP updates * Method to Fn * Handle remaining attributes * Temp fix for extracting cfg attrs * Fix some other errors * Add test for wildcard selector (doesn't work :() * WIP impl parse for AttributeFrag * Fmt * Import skeleton parse impl * WIP * Copy across parse impl * Parse terminated * WIP fix attr parsing * WIP fix attr parsing * Remove attr property * Utilize attr_args meta for parsing * Format error messages * Extract selector parsing to TryFrom * Handle parsing wildcard selector * Factor out namesapce parsing * Introduce helper methods * suggestions * fix parsing of cfg attrs * remove expand.rs * add error message * start working on more detailed errors * fix tests * rework docs parsing * changelog entry * some refactoring * fmt --------- Co-authored-by: Andrew Jones <[email protected]>
1 parent 3f11e0e commit b436933

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+596
-521
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Changed
10+
- Upgraded `syn` to version `2` - [#1731](https://github.com/paritytech/ink/pull/1731)
11+
912
## Version 4.1.0
1013

1114
### Added

crates/e2e/macro/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ derive_more = "0.99.17"
2626
env_logger = "0.10.0"
2727
log = "0.4.17"
2828
serde_json = "1.0.89"
29-
syn = "1"
29+
syn = "2"
3030
proc-macro2 = "1"
3131
quote = "1"
3232
which = "4.4.0"

crates/ink/codegen/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ name = "ink_codegen"
2121
ink_primitives = { version = "4.1.0", path = "../../primitives" }
2222
ir = { version = "4.1.0", package = "ink_ir", path = "../ir", default-features = false }
2323
quote = "1"
24-
syn = { version = "1.0", features = ["parsing", "full", "extra-traits"] }
24+
syn = { version = "2.0", features = ["parsing", "full", "extra-traits"] }
2525
proc-macro2 = "1.0"
2626
derive_more = { version = "0.99", default-features = false, features = ["from"] }
2727
itertools = "0.10"

crates/ink/ir/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ name = "ink_ir"
1919

2020
[dependencies]
2121
quote = "1"
22-
syn = { version = "1.0", features = ["parsing", "full", "visit", "extra-traits"] }
22+
syn = { version = "2.0", features = ["parsing", "full", "visit", "extra-traits"] }
2323
proc-macro2 = "1.0"
2424
itertools = { version = "0.10", default-features = false }
2525
either = { version = "1.5", default-features = false }

crates/ink/ir/src/ast/attr_args.rs

+2-110
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,13 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use proc_macro2::{
16-
Ident,
17-
TokenStream as TokenStream2,
18-
};
19-
use quote::ToTokens;
15+
use super::MetaNameValue;
2016
use syn::{
21-
ext::IdentExt as _,
2217
parse::{
2318
Parse,
2419
ParseStream,
2520
},
2621
punctuated::Punctuated,
27-
spanned::Spanned,
2822
Token,
2923
};
3024

@@ -37,24 +31,6 @@ pub struct AttributeArgs {
3731
args: Punctuated<MetaNameValue, Token![,]>,
3832
}
3933

40-
/// A name-value pair within an attribute, like `feature = "nightly"`.
41-
///
42-
/// The only difference from `syn::MetaNameValue` is that this additionally
43-
/// allows the `value` to be a plain identifier or path.
44-
#[derive(Debug, PartialEq, Eq)]
45-
pub struct MetaNameValue {
46-
pub name: syn::Path,
47-
pub eq_token: syn::token::Eq,
48-
pub value: PathOrLit,
49-
}
50-
51-
/// Either a path or a literal.
52-
#[derive(Debug, PartialEq, Eq)]
53-
pub enum PathOrLit {
54-
Path(syn::Path),
55-
Lit(syn::Lit),
56-
}
57-
5834
impl IntoIterator for AttributeArgs {
5935
type Item = MetaNameValue;
6036
type IntoIter = syn::punctuated::IntoIter<MetaNameValue>;
@@ -72,94 +48,10 @@ impl Parse for AttributeArgs {
7248
}
7349
}
7450

75-
impl Parse for MetaNameValue {
76-
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
77-
let path = input.call(Self::parse_meta_path)?;
78-
Self::parse_meta_name_value_after_path(path, input)
79-
}
80-
}
81-
82-
impl ToTokens for PathOrLit {
83-
fn to_tokens(&self, tokens: &mut TokenStream2) {
84-
match self {
85-
Self::Lit(lit) => lit.to_tokens(tokens),
86-
Self::Path(path) => path.to_tokens(tokens),
87-
}
88-
}
89-
}
90-
91-
impl ToTokens for MetaNameValue {
92-
fn to_tokens(&self, tokens: &mut TokenStream2) {
93-
self.name.to_tokens(tokens);
94-
self.eq_token.to_tokens(tokens);
95-
self.value.to_tokens(tokens);
96-
}
97-
}
98-
99-
impl MetaNameValue {
100-
/// Like [`syn::Path::parse_mod_style`] but accepts keywords in the path.
101-
///
102-
/// # Note
103-
///
104-
/// This code was taken from the `syn` implementation for a very similar
105-
/// syntactical pattern.
106-
fn parse_meta_path(input: ParseStream) -> Result<syn::Path, syn::Error> {
107-
Ok(syn::Path {
108-
leading_colon: input.parse()?,
109-
segments: {
110-
let mut segments = Punctuated::new();
111-
while input.peek(Ident::peek_any) {
112-
let ident = Ident::parse_any(input)?;
113-
segments.push_value(syn::PathSegment::from(ident));
114-
if !input.peek(syn::Token![::]) {
115-
break
116-
}
117-
let punct = input.parse()?;
118-
segments.push_punct(punct);
119-
}
120-
if segments.is_empty() {
121-
return Err(input.error("expected path"))
122-
} else if segments.trailing_punct() {
123-
return Err(input.error("expected path segment"))
124-
}
125-
segments
126-
},
127-
})
128-
}
129-
130-
fn parse_meta_name_value_after_path(
131-
name: syn::Path,
132-
input: ParseStream,
133-
) -> Result<MetaNameValue, syn::Error> {
134-
let span = name.span();
135-
Ok(MetaNameValue {
136-
name,
137-
eq_token: input.parse().map_err(|_error| {
138-
format_err!(
139-
span,
140-
"ink! config options require an argument separated by '='",
141-
)
142-
})?,
143-
value: input.parse()?,
144-
})
145-
}
146-
}
147-
148-
impl Parse for PathOrLit {
149-
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
150-
if input.fork().peek(syn::Lit) {
151-
return input.parse::<syn::Lit>().map(PathOrLit::Lit)
152-
}
153-
if input.fork().peek(Ident::peek_any) || input.fork().peek(Token![::]) {
154-
return input.parse::<syn::Path>().map(PathOrLit::Path)
155-
}
156-
Err(input.error("cannot parse into either literal or path"))
157-
}
158-
}
159-
16051
#[cfg(test)]
16152
mod tests {
16253
use super::*;
54+
use crate::ast::PathOrLit;
16355
use quote::quote;
16456

16557
impl AttributeArgs {

crates/ink/ir/src/ast/meta.rs

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Copyright 2018-2022 Parity Technologies (UK) Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use proc_macro2::{
16+
Ident,
17+
TokenStream as TokenStream2,
18+
};
19+
use quote::ToTokens;
20+
use syn::{
21+
ext::IdentExt as _,
22+
parse::{
23+
Parse,
24+
ParseStream,
25+
},
26+
punctuated::Punctuated,
27+
spanned::Spanned,
28+
LitInt,
29+
Token,
30+
};
31+
32+
/// Content of a compile-time structured attribute.
33+
///
34+
/// This is a subset of `syn::Meta` that allows the `value` of a name-value pair
35+
/// to be a plain identifier or path.
36+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37+
pub enum Meta {
38+
/// A path, like `message`.
39+
Path(syn::Path),
40+
/// A name-value pair, like `feature = "nightly"`.
41+
NameValue(MetaNameValue),
42+
}
43+
44+
impl Parse for Meta {
45+
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
46+
let path = input.call(parse_meta_path)?;
47+
if input.peek(Token![=]) {
48+
MetaNameValue::parse_meta_name_value_after_path(path, input)
49+
.map(Meta::NameValue)
50+
} else {
51+
Ok(Meta::Path(path))
52+
}
53+
}
54+
}
55+
56+
impl ToTokens for Meta {
57+
fn to_tokens(&self, tokens: &mut TokenStream2) {
58+
match self {
59+
Self::Path(path) => path.to_tokens(tokens),
60+
Self::NameValue(name_value) => name_value.to_tokens(tokens),
61+
}
62+
}
63+
}
64+
65+
/// A name-value pair within an attribute, like `feature = "nightly"`.
66+
///
67+
/// The only difference from `syn::MetaNameValue` is that this additionally
68+
/// allows the `value` to be a plain identifier or path.
69+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
70+
pub struct MetaNameValue {
71+
pub name: syn::Path,
72+
pub eq_token: syn::token::Eq,
73+
pub value: PathOrLit,
74+
}
75+
76+
impl Parse for MetaNameValue {
77+
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
78+
let path = input.call(parse_meta_path)?;
79+
Self::parse_meta_name_value_after_path(path, input)
80+
}
81+
}
82+
83+
impl ToTokens for MetaNameValue {
84+
fn to_tokens(&self, tokens: &mut TokenStream2) {
85+
self.name.to_tokens(tokens);
86+
self.eq_token.to_tokens(tokens);
87+
self.value.to_tokens(tokens);
88+
}
89+
}
90+
91+
impl MetaNameValue {
92+
fn parse_meta_name_value_after_path(
93+
name: syn::Path,
94+
input: ParseStream,
95+
) -> Result<MetaNameValue, syn::Error> {
96+
let span = name.span();
97+
Ok(MetaNameValue {
98+
name,
99+
eq_token: input.parse().map_err(|_error| {
100+
format_err!(
101+
span,
102+
"ink! config options require an argument separated by '='",
103+
)
104+
})?,
105+
value: input.parse()?,
106+
})
107+
}
108+
}
109+
110+
/// Either a path or a literal.
111+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
112+
pub enum PathOrLit {
113+
Path(syn::Path),
114+
Lit(syn::Lit),
115+
}
116+
117+
impl Parse for PathOrLit {
118+
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
119+
if input.fork().peek(syn::Lit) {
120+
return input.parse::<syn::Lit>().map(PathOrLit::Lit)
121+
}
122+
if input.fork().peek(Ident::peek_any) || input.fork().peek(Token![::]) {
123+
return input.call(parse_meta_path).map(PathOrLit::Path)
124+
}
125+
Err(input.error("cannot parse into either literal or path"))
126+
}
127+
}
128+
129+
impl ToTokens for PathOrLit {
130+
fn to_tokens(&self, tokens: &mut TokenStream2) {
131+
match self {
132+
Self::Lit(lit) => lit.to_tokens(tokens),
133+
Self::Path(path) => path.to_tokens(tokens),
134+
}
135+
}
136+
}
137+
138+
impl PathOrLit {
139+
/// Returns the value of the literal if it is a boolean literal.
140+
pub fn as_bool(&self) -> Option<bool> {
141+
match self {
142+
Self::Lit(syn::Lit::Bool(lit_bool)) => Some(lit_bool.value),
143+
_ => None,
144+
}
145+
}
146+
147+
/// Returns the value of the literal if it is a string literal.
148+
pub fn as_string(&self) -> Option<String> {
149+
match self {
150+
Self::Lit(syn::Lit::Str(lit_str)) => Some(lit_str.value()),
151+
_ => None,
152+
}
153+
}
154+
155+
/// Returns the the literal if it is an integer literal.
156+
pub fn as_lit_int(&self) -> Option<&LitInt> {
157+
match self {
158+
Self::Lit(syn::Lit::Int(lit_int)) => Some(lit_int),
159+
_ => None,
160+
}
161+
}
162+
}
163+
164+
/// Like [`syn::Path::parse_mod_style`] but accepts keywords in the path.
165+
///
166+
/// # Note
167+
///
168+
/// This code was taken from the `syn` implementation for a very similar
169+
/// syntactical pattern.
170+
fn parse_meta_path(input: ParseStream) -> Result<syn::Path, syn::Error> {
171+
Ok(syn::Path {
172+
leading_colon: input.parse()?,
173+
segments: {
174+
let mut segments = Punctuated::new();
175+
while input.peek(Ident::peek_any) {
176+
let ident = Ident::parse_any(input)?;
177+
segments.push_value(syn::PathSegment::from(ident));
178+
if !input.peek(syn::Token![::]) {
179+
break
180+
}
181+
let punct = input.parse()?;
182+
segments.push_punct(punct);
183+
}
184+
if segments.is_empty() {
185+
return Err(input.error("expected path"))
186+
} else if segments.trailing_punct() {
187+
return Err(input.error("expected path segment"))
188+
}
189+
segments
190+
},
191+
})
192+
}
193+
194+
#[cfg(test)]
195+
mod tests {
196+
use super::*;
197+
use crate::ast::PathOrLit;
198+
use quote::quote;
199+
200+
#[test]
201+
fn underscore_token_works() {
202+
assert_eq!(
203+
syn::parse2::<Meta>(quote! { selector = _ }).unwrap(),
204+
Meta::NameValue(MetaNameValue {
205+
name: syn::parse_quote! { selector },
206+
eq_token: syn::parse_quote! { = },
207+
value: PathOrLit::Path(syn::Path::from(quote::format_ident!("_"))),
208+
})
209+
)
210+
}
211+
}

0 commit comments

Comments
 (0)