Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use name-only syntax for anonymous ink! event item configuration argument #2140

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Changed
- Use name-only syntax for `anonymous` ink! event item configuration argument - [#2140](https://github.com/paritytech/ink/pull/2140)
- Restrict syntax for setting default ink! e2e test runtime-only emulator - [#2143](https://github.com/paritytech/ink/pull/2143)

## Version 5.0.0-rc.2
Expand Down
69 changes: 41 additions & 28 deletions crates/ink/ir/src/ast/attr_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use super::MetaNameValue;
use super::Meta;
use syn::{
parse::{
Parse,
Expand All @@ -28,7 +28,7 @@ use syn::{
/// in `#[ink::contract(env = ::my::env::Environment)]`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AttributeArgs {
args: Punctuated<MetaNameValue, Token![,]>,
args: Punctuated<Meta, Token![,]>,
}

impl quote::ToTokens for AttributeArgs {
Expand All @@ -38,8 +38,8 @@ impl quote::ToTokens for AttributeArgs {
}

impl IntoIterator for AttributeArgs {
type Item = MetaNameValue;
type IntoIter = syn::punctuated::IntoIter<MetaNameValue>;
type Item = Meta;
type IntoIter = syn::punctuated::IntoIter<Meta>;

fn into_iter(self) -> Self::IntoIter {
self.args.into_iter()
Expand All @@ -57,14 +57,17 @@ impl Parse for AttributeArgs {
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::MetaValue;
use crate::ast::{
MetaNameValue,
MetaValue,
};
use quote::quote;

impl AttributeArgs {
/// Creates a new attribute argument list from the given arguments.
pub fn new<I>(args: I) -> Self
where
I: IntoIterator<Item = MetaNameValue>,
I: IntoIterator<Item = Meta>,
{
Self {
args: args.into_iter().collect(),
Expand All @@ -80,51 +83,59 @@ mod tests {
)
}

#[test]
fn flag_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { flag }).unwrap(),
AttributeArgs::new(vec![Meta::Path(syn::parse_quote! { flag })])
)
}

#[test]
fn literal_bool_value_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = true }).unwrap(),
AttributeArgs::new(vec![MetaNameValue {
AttributeArgs::new(vec![Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { true }),
}])
})])
)
}

#[test]
fn literal_str_value_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = "string literal" }).unwrap(),
AttributeArgs::new(vec![MetaNameValue {
AttributeArgs::new(vec![Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { "string literal" }),
}])
})])
)
}

#[test]
fn ident_value_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = MyIdentifier }).unwrap(),
AttributeArgs::new(vec![MetaNameValue {
AttributeArgs::new(vec![Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Path(syn::parse_quote! { MyIdentifier }),
}])
})])
)
}

#[test]
fn root_path_value_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = ::this::is::my::Path }).unwrap(),
AttributeArgs::new(vec![MetaNameValue {
AttributeArgs::new(vec![Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Path(syn::parse_quote! { ::this::is::my::Path }),
}])
})])
)
}

Expand All @@ -133,24 +144,24 @@ mod tests {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = this::is::my::relative::Path })
.unwrap(),
AttributeArgs::new(vec![MetaNameValue {
AttributeArgs::new(vec![Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Path(
syn::parse_quote! { this::is::my::relative::Path }
),
}])
})])
)
}

#[test]
fn trailing_comma_works() {
let mut expected_args = Punctuated::new();
expected_args.push_value(MetaNameValue {
expected_args.push_value(Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name },
eq_token: syn::parse_quote! { = },
value: MetaValue::Path(syn::parse_quote! { value }),
});
}));
expected_args.push_punct(<Token![,]>::default());
assert_eq!(
syn::parse2::<AttributeArgs>(quote! { name = value, }).unwrap(),
Expand All @@ -164,6 +175,7 @@ mod tests {
fn many_mixed_works() {
assert_eq!(
syn::parse2::<AttributeArgs>(quote! {
flag,
name1 = ::root::Path,
name2 = false,
name3 = "string literal",
Expand All @@ -172,31 +184,32 @@ mod tests {
})
.unwrap(),
AttributeArgs::new(vec![
MetaNameValue {
Meta::Path(syn::parse_quote! { flag }),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name1 },
eq_token: syn::parse_quote! { = },
value: MetaValue::Path(syn::parse_quote! { ::root::Path }),
},
MetaNameValue {
}),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name2 },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { false }),
},
MetaNameValue {
}),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name3 },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { "string literal" }),
},
MetaNameValue {
}),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name4 },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { 42 }),
},
MetaNameValue {
}),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { name5 },
eq_token: syn::parse_quote! { = },
value: MetaValue::Lit(syn::parse_quote! { 7.7 }),
},
}),
])
)
}
Expand Down
66 changes: 65 additions & 1 deletion crates/ink/ir/src/ast/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ use syn::{
},
punctuated::Punctuated,
spanned::Spanned,
LitBool,
LitInt,
LitStr,
Token,
};

Expand Down Expand Up @@ -62,6 +64,32 @@ impl ToTokens for Meta {
}
}

impl Meta {
/// Returns the meta-item name.
pub fn name(&self) -> &syn::Path {
match self {
Meta::Path(path) => path,
Meta::NameValue(name_value) => &name_value.name,
}
}

/// Returns the meta-item value (if any).
pub fn value(&self) -> Option<&MetaValue> {
match self {
Meta::Path(_) => None,
Meta::NameValue(name_value) => Some(&name_value.value),
}
}

/// Returns the `NameValue` variant (if any).
pub fn name_value(&self) -> Option<&MetaNameValue> {
match self {
Meta::NameValue(name_value) => Some(name_value),
Meta::Path(_) => None,
}
}
}

/// A name-value pair within an attribute, like `feature = "nightly"`.
///
/// The only difference from `syn::MetaNameValue` is that this additionally
Expand Down Expand Up @@ -157,13 +185,37 @@ impl MetaValue {
}
}

/// Returns the the literal if it is an integer literal.
/// Returns the literal if it is an integer literal.
pub fn as_lit_int(&self) -> Option<&LitInt> {
match self {
Self::Lit(syn::Lit::Int(lit_int)) => Some(lit_int),
_ => None,
}
}

/// Returns the literal if it is a boolean literal.
pub fn as_lit_bool(&self) -> Option<&LitBool> {
match self {
Self::Lit(syn::Lit::Bool(lit_bool)) => Some(lit_bool),
_ => None,
}
}

/// Returns the literal if it is a string literal.
pub fn as_lit_string(&self) -> Option<&LitStr> {
match self {
Self::Lit(syn::Lit::Str(lit_str)) => Some(lit_str),
_ => None,
}
}

/// Returns the path (if the value is a path).
pub fn as_path(&self) -> Option<&syn::Path> {
match self {
Self::Path(path) => Some(path),
_ => None,
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -243,4 +295,16 @@ mod tests {
})
)
}

#[test]
fn at_token_works() {
assert_eq!(
syn::parse2::<Meta>(quote! { selector = @ }).unwrap(),
Meta::NameValue(MetaNameValue {
name: syn::parse_quote! { selector },
eq_token: syn::parse_quote! { = },
value: MetaValue::Symbol(Symbol::AtSign(syn::parse_quote! { @ })),
})
)
}
}
15 changes: 15 additions & 0 deletions crates/ink/ir/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ macro_rules! format_err_spanned {
}
}

/// Creates a [`syn::Error`] with the format message and infers the
/// [`Span`](`proc_macro2::Span`) using the [`ToTokens`](`quote::ToTokens`) implementation
/// for the [`MetaValue`][crate::ast::MetaValue] (if possible).
///
/// See [`format_err_spanned`] for more details.
macro_rules! format_err_spanned_value {
($arg:expr, $($msg:tt)*) => {
if let Some(value) = $arg.value() {
format_err_spanned!(value, $($msg)*)
} else {
format_err_spanned!($arg, $($msg)*)
}
};
}

/// Creates a [`syn::Error`] with the format message and infers the
/// [`Span`](`proc_macro2::Span`) using [`Spanned`](`syn::spanned::Spanned`).
///
Expand Down
18 changes: 9 additions & 9 deletions crates/ink/ir/src/ir/chain_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ impl TryFrom<ast::AttributeArgs> for Config {
let mut ext_id: Option<ExtensionId> = None;

for arg in args.clone().into_iter() {
if arg.name.is_ident("extension") {
if arg.name().is_ident("extension") {
if ext_id.is_some() {
return Err(format_err_spanned!(
arg.value,
return Err(format_err_spanned_value!(
arg,
"encountered duplicate ink! contract `extension` configuration argument",
))
));
}

if let Some(lit_int) = arg.value.as_lit_int() {
if let Some(lit_int) = arg.value().and_then(ast::MetaValue::as_lit_int) {
let id = lit_int.base10_parse::<u16>()
.map_err(|error| {
format_err_spanned!(
Expand All @@ -98,16 +98,16 @@ impl TryFrom<ast::AttributeArgs> for Config {
})?;
ext_id = Some(ExtensionId::from_u16(id));
} else {
return Err(format_err_spanned!(
arg.value,
return Err(format_err_spanned_value!(
arg,
"expected `u16` integer type for `N` in `extension = N`",
))
));
}
} else {
return Err(format_err_spanned!(
arg,
"encountered unknown or unsupported chain extension configuration argument",
))
));
}
}

Expand Down
Loading