1// This file is part of Substrate.
23// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
56// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
1718use super::helper;
19use frame_support_procedural_tools::get_doc_literals;
20use syn::spanned::Spanned;
2122/// List of additional token to be used for parsing.
23mod keyword {
24syn::custom_keyword!(DispatchResultWithPostInfo);
25syn::custom_keyword!(Call);
26syn::custom_keyword!(OriginFor);
27syn::custom_keyword!(weight);
28syn::custom_keyword!(compact);
29syn::custom_keyword!(T);
30syn::custom_keyword!(pallet);
31syn::custom_keyword!(constant_name);
32}
3334/// Definition of extra constants typically `impl<T: Config> Pallet<T> { ... }`
35pub struct ExtraConstantsDef {
36/// The where_clause used.
37pub where_clause: Option<syn::WhereClause>,
38/// A set of usage of instance, must be check for consistency with trait.
39pub instances: Vec<helper::InstanceUsage>,
40/// The extra constant defined.
41pub extra_constants: Vec<ExtraConstantDef>,
42}
4344/// Input definition for an constant in pallet.
45pub struct ExtraConstantDef {
46/// Name of the function
47pub ident: syn::Ident,
48/// The type returned by the function
49pub type_: syn::Type,
50/// The doc associated
51pub doc: Vec<syn::Expr>,
52/// Optional MetaData Name
53pub metadata_name: Option<syn::Ident>,
54/// Attributes
55pub attrs: Vec<syn::Attribute>,
56}
5758/// Attributes for functions in extra_constants impl block.
59/// Parse for `#[pallet::constant_name(ConstantName)]`
60pub struct ExtraConstAttr {
61 metadata_name: syn::Ident,
62}
6364impl syn::parse::Parse for ExtraConstAttr {
65fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
66 input.parse::<syn::Token![#]>()?;
67let content;
68syn::bracketed!(content in input);
69 content.parse::<keyword::pallet>()?;
70 content.parse::<syn::Token![::]>()?;
71 content.parse::<keyword::constant_name>()?;
7273let metadata_name;
74syn::parenthesized!(metadata_name in content);
75Ok(ExtraConstAttr { metadata_name: metadata_name.parse::<syn::Ident>()? })
76 }
77}
7879impl ExtraConstantsDef {
80pub fn try_from(item: &mut syn::Item) -> syn::Result<Self> {
81let item = if let syn::Item::Impl(item) = item {
82 item
83 } else {
84return Err(syn::Error::new(
85 item.span(),
86"Invalid pallet::extra_constants, expected item impl",
87 ));
88 };
8990let instances = vec![
91 helper::check_impl_gen(&item.generics, item.impl_token.span())?,
92 helper::check_pallet_struct_usage(&item.self_ty)?,
93 ];
9495if let Some((_, _, for_)) = item.trait_ {
96let msg = "Invalid pallet::call, expected no trait ident as in \
97 `impl<..> Pallet<..> { .. }`";
98return Err(syn::Error::new(for_.span(), msg));
99 }
100101let mut extra_constants = vec![];
102for impl_item in &mut item.items {
103let method = if let syn::ImplItem::Fn(method) = impl_item {
104 method
105 } else {
106let msg = "Invalid pallet::call, only method accepted";
107return Err(syn::Error::new(impl_item.span(), msg));
108 };
109110if !method.sig.inputs.is_empty() {
111let msg = "Invalid pallet::extra_constants, method must have 0 args";
112return Err(syn::Error::new(method.sig.span(), msg));
113 }
114115if !method.sig.generics.params.is_empty() {
116let msg = "Invalid pallet::extra_constants, method must have 0 generics";
117return Err(syn::Error::new(method.sig.generics.params[0].span(), msg));
118 }
119120if method.sig.generics.where_clause.is_some() {
121let msg = "Invalid pallet::extra_constants, method must have no where clause";
122return Err(syn::Error::new(method.sig.generics.where_clause.span(), msg));
123 }
124125let type_ = match &method.sig.output {
126 syn::ReturnType::Default => {
127let msg = "Invalid pallet::extra_constants, method must have a return type";
128return Err(syn::Error::new(method.span(), msg));
129 },
130 syn::ReturnType::Type(_, type_) => *type_.clone(),
131 };
132133// parse metadata_name
134let mut extra_constant_attrs: Vec<ExtraConstAttr> =
135 helper::take_item_pallet_attrs(method)?;
136137if extra_constant_attrs.len() > 1 {
138let msg =
139"Invalid attribute in pallet::constant_name, only one attribute is expected";
140return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg));
141 }
142143let metadata_name = extra_constant_attrs.pop().map(|attr| attr.metadata_name);
144145 extra_constants.push(ExtraConstantDef {
146 ident: method.sig.ident.clone(),
147 type_,
148 doc: get_doc_literals(&method.attrs),
149 metadata_name,
150 attrs: method.attrs.clone(),
151 });
152 }
153154Ok(Self { instances, where_clause: item.generics.where_clause.clone(), extra_constants })
155 }
156}