diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 0d09fdc8..ab203b7c 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,6 +1,6 @@ +pub(crate) mod add; pub(crate) mod build; pub(crate) mod call; pub(crate) mod new; -pub(crate) mod add; pub(crate) mod test; pub(crate) mod up; diff --git a/src/engines/pallet_engine/pallet_entry.rs b/src/engines/pallet_engine/pallet_entry.rs index a3fa7331..0fa381e4 100644 --- a/src/engines/pallet_engine/pallet_entry.rs +++ b/src/engines/pallet_engine/pallet_entry.rs @@ -4,40 +4,39 @@ use syn::Ident; /// Format containing necessary information for appending pallets #[derive(Debug)] pub(super) struct AddPalletEntry { - pub(super) index: Option, - pub(super) path: Ident, - pub(super) name: Ident, + pub(super) index: Option, + pub(super) path: Ident, + pub(super) name: Ident, } impl AddPalletEntry { - pub(super) fn new(index: Option, path: &str, name: &str) -> Self { - let path = Ident::new(path, proc_macro2::Span::call_site()); - let name = Ident::new(name, proc_macro2::Span::call_site()); - Self { index, path, name } - } + pub(super) fn new(index: Option, path: &str, name: &str) -> Self { + let path = Ident::new(path, proc_macro2::Span::call_site()); + let name = Ident::new(name, proc_macro2::Span::call_site()); + Self { index, path, name } + } } impl From for AddPalletEntry { - fn from(value: ReadPalletEntry) -> Self { - todo!("") - } + fn from(value: ReadPalletEntry) -> Self { + todo!("") + } } - /// All information that's needed to represent a pallet in a construct_runtime! invocation /// The processing must be based on the context i.e. the type of RuntimeDeclaration in the runtime pub(super) struct ReadPalletEntry { - /// Pallet identifier. "System" in `System: frame_system = 1` - pub(super) entry: String, - /// Stores a tuple of information (index, instance). For single instances, instance = 0 - pub(super) numbers: Numbers, + /// Pallet identifier. "System" in `System: frame_system = 1` + pub(super) entry: String, + /// Stores a tuple of information (index, instance). For single instances, instance = 0 + pub(super) numbers: Numbers, } #[derive(Default, Debug)] pub(super) struct Numbers { - /// Stores the first index as parsed from input file - pub(super) index: Option, - /// Counts the number of instances in runtime file - /// 0 means only 1 unique instance was found - /// 1 means the pallet is using instance syntax pallet:: - /// >1 means multiple pallet instances were found - pub(super) instance: u8, -} \ No newline at end of file + /// Stores the first index as parsed from input file + pub(super) index: Option, + /// Counts the number of instances in runtime file + /// 0 means only 1 unique instance was found + /// 1 means the pallet is using instance syntax pallet:: + /// >1 means multiple pallet instances were found + pub(super) instance: u8, +} diff --git a/src/engines/pallet_engine/parser.rs b/src/engines/pallet_engine/parser.rs index 7c57ada4..3a7f85f0 100644 --- a/src/engines/pallet_engine/parser.rs +++ b/src/engines/pallet_engine/parser.rs @@ -20,65 +20,59 @@ use frame_support_procedural_tools::syn_ext as ext; use proc_macro2::{Delimiter, Group, Punct, Spacing, Span, TokenStream}; use quote::{quote, ToTokens, TokenStreamExt}; use std::{ - collections::{HashMap, HashSet}, - str::FromStr, + collections::{HashMap, HashSet}, + str::FromStr, }; use syn::{ - ext::IdentExt, - parse::{Parse, ParseStream}, - parse_quote, - punctuated::Punctuated, - spanned::Spanned, - token, Attribute, Error, Ident, Path, Result, Token, + ext::IdentExt, + parse::{Parse, ParseStream}, + parse_quote, + punctuated::Punctuated, + spanned::Spanned, + token, Attribute, Error, Ident, Path, Result, Token, }; /// Span for delimiting tokens. macro_rules! bs_delim_span { - ($d:ident) => { - proc_macro2::Group::new(proc_macro2::Delimiter::$d, proc_macro2::TokenStream::new()) - .delim_span() - }; - ($d:ident, $group:tt) => { - proc_macro2::Group::new(proc_macro2::Delimiter::$d, $group).delim_span() - }; + ($d:ident) => { + proc_macro2::Group::new(proc_macro2::Delimiter::$d, proc_macro2::TokenStream::new()) + .delim_span() + }; + ($d:ident, $group:tt) => { + proc_macro2::Group::new(proc_macro2::Delimiter::$d, $group).delim_span() + }; } /// Tokens that delimit a group macro_rules! delim_token { - (Parenthesis, $group:tt) => { - syn::token::Paren { - span: bs_delim_span!(Parenthesis, $group), - } - }; - ($d:ident) => { - syn::token::$d { - span: bs_delim_span!($d), - } - }; - ($d:ident, $group:tt) => { - syn::token::$d { - span: bs_delim_span!($d, $group), - } - }; + (Parenthesis, $group:tt) => { + syn::token::Paren { span: bs_delim_span!(Parenthesis, $group) } + }; + ($d:ident) => { + syn::token::$d { span: bs_delim_span!($d) } + }; + ($d:ident, $group:tt) => { + syn::token::$d { span: bs_delim_span!($d, $group) } + }; } mod keyword { - syn::custom_keyword!(Block); - syn::custom_keyword!(NodeBlock); - syn::custom_keyword!(UncheckedExtrinsic); - syn::custom_keyword!(Pallet); - syn::custom_keyword!(Call); - syn::custom_keyword!(Storage); - syn::custom_keyword!(Event); - syn::custom_keyword!(Error); - syn::custom_keyword!(Config); - syn::custom_keyword!(Origin); - syn::custom_keyword!(Inherent); - syn::custom_keyword!(ValidateUnsigned); - syn::custom_keyword!(FreezeReason); - syn::custom_keyword!(HoldReason); - syn::custom_keyword!(LockId); - syn::custom_keyword!(SlashReason); - syn::custom_keyword!(exclude_parts); - syn::custom_keyword!(use_parts); - syn::custom_keyword!(expanded); + syn::custom_keyword!(Block); + syn::custom_keyword!(NodeBlock); + syn::custom_keyword!(UncheckedExtrinsic); + syn::custom_keyword!(Pallet); + syn::custom_keyword!(Call); + syn::custom_keyword!(Storage); + syn::custom_keyword!(Event); + syn::custom_keyword!(Error); + syn::custom_keyword!(Config); + syn::custom_keyword!(Origin); + syn::custom_keyword!(Inherent); + syn::custom_keyword!(ValidateUnsigned); + syn::custom_keyword!(FreezeReason); + syn::custom_keyword!(HoldReason); + syn::custom_keyword!(LockId); + syn::custom_keyword!(SlashReason); + syn::custom_keyword!(exclude_parts); + syn::custom_keyword!(use_parts); + syn::custom_keyword!(expanded); } /// Declaration of a runtime. @@ -88,359 +82,339 @@ mod keyword { /// implicit. #[derive(Debug)] pub enum RuntimeDeclaration { - Implicit(ImplicitRuntimeDeclaration), - Explicit(ExplicitRuntimeDeclaration), - ExplicitExpanded(ExplicitRuntimeDeclaration), + Implicit(ImplicitRuntimeDeclaration), + Explicit(ExplicitRuntimeDeclaration), + ExplicitExpanded(ExplicitRuntimeDeclaration), } impl ToTokens for RuntimeDeclaration { - fn to_tokens(&self, tokens: &mut TokenStream) { - let group = match self { - RuntimeDeclaration::Implicit(i) => i.to_token_stream(), - RuntimeDeclaration::Explicit(_) | RuntimeDeclaration::ExplicitExpanded(_) => { - unimplemented!() - } - }; - let crt = syn::Macro { - path: parse_quote!(construct_runtime), - bang_token: Token![!](Span::call_site()), - tokens: group.clone(), - delimiter: syn::MacroDelimiter::Paren(delim_token!(Parenthesis, group)), - }; - tokens.extend(crt.into_token_stream()); - } + fn to_tokens(&self, tokens: &mut TokenStream) { + let group = match self { + RuntimeDeclaration::Implicit(i) => i.to_token_stream(), + RuntimeDeclaration::Explicit(_) | RuntimeDeclaration::ExplicitExpanded(_) => { + unimplemented!() + }, + }; + let crt = syn::Macro { + path: parse_quote!(construct_runtime), + bang_token: Token![!](Span::call_site()), + tokens: group.clone(), + delimiter: syn::MacroDelimiter::Paren(delim_token!(Parenthesis, group)), + }; + tokens.extend(crt.into_token_stream()); + } } /// Declaration of a runtime with some pallet with implicit declaration of parts. #[derive(Debug)] pub struct ImplicitRuntimeDeclaration { - pub name: Ident, - pub where_section: Option, - pub pallets: Vec, + pub name: Ident, + pub where_section: Option, + pub pallets: Vec, } impl ToTokens for ImplicitRuntimeDeclaration { - fn to_tokens(&self, tokens: &mut TokenStream) { - let (name, where_section) = (&self.name, &self.where_section); - tokens.extend(quote!( + fn to_tokens(&self, tokens: &mut TokenStream) { + let (name, where_section) = (&self.name, &self.where_section); + tokens.extend(quote!( pub struct #name #where_section)); - let mut pallets = TokenStream::new(); - for p in &self.pallets { - pallets.extend(p.to_token_stream()); - } - tokens.append(Group::new(Delimiter::Brace, pallets)); - } + let mut pallets = TokenStream::new(); + for p in &self.pallets { + pallets.extend(p.to_token_stream()); + } + tokens.append(Group::new(Delimiter::Brace, pallets)); + } } /// Declaration of a runtime with all pallet having explicit declaration of parts. #[derive(Debug)] pub struct ExplicitRuntimeDeclaration { - pub name: Ident, - pub where_section: Option, - pub pallets: Vec, - pub pallets_token: token::Brace, + pub name: Ident, + pub where_section: Option, + pub pallets: Vec, + pub pallets_token: token::Brace, } impl Parse for RuntimeDeclaration { - fn parse(input: ParseStream) -> Result { - input.parse::()?; - - // Support either `enum` or `struct`. - if input.peek(Token![struct]) { - input.parse::()?; - } else { - input.parse::()?; - } - - let name = input.parse::()?; - let where_section = if input.peek(token::Where) { - Some(input.parse()?) - } else { - None - }; - let pallets = - input.parse::>>()?; - let pallets_token = pallets.token; - - match convert_pallets(pallets.content.inner.into_iter().collect())? { - PalletsConversion::Implicit(pallets) => { - Ok(RuntimeDeclaration::Implicit(ImplicitRuntimeDeclaration { - name, - where_section, - pallets, - })) - } - PalletsConversion::Explicit(pallets) => { - Ok(RuntimeDeclaration::Explicit(ExplicitRuntimeDeclaration { - name, - where_section, - pallets, - pallets_token, - })) - } - PalletsConversion::ExplicitExpanded(pallets) => Ok( - RuntimeDeclaration::ExplicitExpanded(ExplicitRuntimeDeclaration { - name, - where_section, - pallets, - pallets_token, - }), - ), - } - } + fn parse(input: ParseStream) -> Result { + input.parse::()?; + + // Support either `enum` or `struct`. + if input.peek(Token![struct]) { + input.parse::()?; + } else { + input.parse::()?; + } + + let name = input.parse::()?; + let where_section = if input.peek(token::Where) { Some(input.parse()?) } else { None }; + let pallets = + input.parse::>>()?; + let pallets_token = pallets.token; + + match convert_pallets(pallets.content.inner.into_iter().collect())? { + PalletsConversion::Implicit(pallets) => { + Ok(RuntimeDeclaration::Implicit(ImplicitRuntimeDeclaration { + name, + where_section, + pallets, + })) + }, + PalletsConversion::Explicit(pallets) => { + Ok(RuntimeDeclaration::Explicit(ExplicitRuntimeDeclaration { + name, + where_section, + pallets, + pallets_token, + })) + }, + PalletsConversion::ExplicitExpanded(pallets) => { + Ok(RuntimeDeclaration::ExplicitExpanded(ExplicitRuntimeDeclaration { + name, + where_section, + pallets, + pallets_token, + })) + }, + } + } } #[derive(Debug)] pub struct WhereSection { - pub span: Span, - pub block: syn::TypePath, - pub node_block: syn::TypePath, - pub unchecked_extrinsic: syn::TypePath, + pub span: Span, + pub block: syn::TypePath, + pub node_block: syn::TypePath, + pub unchecked_extrinsic: syn::TypePath, } impl ToTokens for WhereSection { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.extend(quote!()); - } + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(quote!()); + } } impl Parse for WhereSection { - fn parse(input: ParseStream) -> Result { - input.parse::()?; - - let mut definitions = Vec::new(); - while !input.peek(token::Brace) { - let definition: WhereDefinition = input.parse()?; - definitions.push(definition); - if !input.peek(Token![,]) { - if !input.peek(token::Brace) { - return Err(input.error("Expected `,` or `{`")); - } - break; - } - input.parse::()?; - } - let block = remove_kind(input, WhereKind::Block, &mut definitions)?.value; - let node_block = remove_kind(input, WhereKind::NodeBlock, &mut definitions)?.value; - let unchecked_extrinsic = - remove_kind(input, WhereKind::UncheckedExtrinsic, &mut definitions)?.value; - if let Some(WhereDefinition { - ref kind_span, - ref kind, - .. - }) = definitions.first() - { - let msg = format!( - "`{:?}` was declared above. Please use exactly one declaration for `{:?}`.", - kind, kind - ); - return Err(Error::new(*kind_span, msg)); - } - Ok(Self { - span: input.span(), - block, - node_block, - unchecked_extrinsic, - }) - } + fn parse(input: ParseStream) -> Result { + input.parse::()?; + + let mut definitions = Vec::new(); + while !input.peek(token::Brace) { + let definition: WhereDefinition = input.parse()?; + definitions.push(definition); + if !input.peek(Token![,]) { + if !input.peek(token::Brace) { + return Err(input.error("Expected `,` or `{`")); + } + break; + } + input.parse::()?; + } + let block = remove_kind(input, WhereKind::Block, &mut definitions)?.value; + let node_block = remove_kind(input, WhereKind::NodeBlock, &mut definitions)?.value; + let unchecked_extrinsic = + remove_kind(input, WhereKind::UncheckedExtrinsic, &mut definitions)?.value; + if let Some(WhereDefinition { ref kind_span, ref kind, .. }) = definitions.first() { + let msg = format!( + "`{:?}` was declared above. Please use exactly one declaration for `{:?}`.", + kind, kind + ); + return Err(Error::new(*kind_span, msg)); + } + Ok(Self { span: input.span(), block, node_block, unchecked_extrinsic }) + } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub enum WhereKind { - Block, - NodeBlock, - UncheckedExtrinsic, + Block, + NodeBlock, + UncheckedExtrinsic, } #[derive(Debug)] pub struct WhereDefinition { - pub kind_span: Span, - pub kind: WhereKind, - pub value: syn::TypePath, + pub kind_span: Span, + pub kind: WhereKind, + pub value: syn::TypePath, } impl Parse for WhereDefinition { - fn parse(input: ParseStream) -> Result { - let lookahead = input.lookahead1(); - let (kind_span, kind) = if lookahead.peek(keyword::Block) { - (input.parse::()?.span(), WhereKind::Block) - } else if lookahead.peek(keyword::NodeBlock) { - ( - input.parse::()?.span(), - WhereKind::NodeBlock, - ) - } else if lookahead.peek(keyword::UncheckedExtrinsic) { - ( - input.parse::()?.span(), - WhereKind::UncheckedExtrinsic, - ) - } else { - return Err(lookahead.error()); - }; - - Ok(Self { - kind_span, - kind, - value: { - let _: Token![=] = input.parse()?; - input.parse()? - }, - }) - } + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + let (kind_span, kind) = if lookahead.peek(keyword::Block) { + (input.parse::()?.span(), WhereKind::Block) + } else if lookahead.peek(keyword::NodeBlock) { + (input.parse::()?.span(), WhereKind::NodeBlock) + } else if lookahead.peek(keyword::UncheckedExtrinsic) { + (input.parse::()?.span(), WhereKind::UncheckedExtrinsic) + } else { + return Err(lookahead.error()); + }; + + Ok(Self { + kind_span, + kind, + value: { + let _: Token![=] = input.parse()?; + input.parse()? + }, + }) + } } /// The declaration of a pallet. #[derive(Debug, Clone)] pub struct PalletDeclaration { - /// Span for current pallet - pub span: Span, - /// Is this pallet fully expanded? - pub is_expanded: bool, - /// The name of the pallet, e.g.`System` in `System: frame_system`. - pub name: Ident, - /// Optional attributes tagged right above a pallet declaration. - pub attrs: Vec, - /// Optional fixed index, e.g. `MyPallet ... = 3,`. - pub index: Option, - /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. - pub path: PalletPath, - /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. - pub instance: Option, - /// The declared pallet parts, - /// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}` - /// or `None` for `System: system`. - pub pallet_parts: Option>, - /// The specified parts, either use_parts or exclude_parts. - pub specified_parts: SpecifiedParts, + /// Span for current pallet + pub span: Span, + /// Is this pallet fully expanded? + pub is_expanded: bool, + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Optional attributes tagged right above a pallet declaration. + pub attrs: Vec, + /// Optional fixed index, e.g. `MyPallet ... = 3,`. + pub index: Option, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, + /// The declared pallet parts, + /// e.g. `Some([Pallet, Call])` for `System: system::{Pallet, Call}` + /// or `None` for `System: system`. + pub pallet_parts: Option>, + /// The specified parts, either use_parts or exclude_parts. + pub specified_parts: SpecifiedParts, } impl ToTokens for PalletDeclaration { - fn to_tokens(&self, tokens: &mut TokenStream) { - let PalletDeclaration { name, path, .. } = self; - tokens.extend(quote!(#name )); - if let Some(instance) = &self.instance { - tokens.extend(quote!(: #path::<#instance>)); - } else { - tokens.extend(quote!(: #path)) - } - if let Some(idx) = self.index { - let idx = format!(" = {},", idx); - // This means no help from rustfmt - tokens.extend(TokenStream::from_str(&idx)); - // If we want rustfmt we would have to handroll our own solution or forgo indices - // (which is bad and probably not what the developer wants which is to delete code) - // tokens.extend(quote!(,)); - } else { - tokens.append(Punct::new(',', Spacing::Alone)); - } - } + fn to_tokens(&self, tokens: &mut TokenStream) { + let PalletDeclaration { name, path, .. } = self; + tokens.extend(quote!(#name )); + if let Some(instance) = &self.instance { + tokens.extend(quote!(: #path::<#instance>)); + } else { + tokens.extend(quote!(: #path)) + } + if let Some(idx) = self.index { + let idx = format!(" = {},", idx); + // This means no help from rustfmt + tokens.extend(TokenStream::from_str(&idx)); + // If we want rustfmt we would have to handroll our own solution or forgo indices + // (which is bad and probably not what the developer wants which is to delete code) + // tokens.extend(quote!(,)); + } else { + tokens.append(Punct::new(',', Spacing::Alone)); + } + } } /// The possible declaration of pallet parts to use. #[derive(Debug, Clone)] pub enum SpecifiedParts { - /// Use all the pallet parts except those specified. - Exclude(Vec), - /// Use only the specified pallet parts. - Use(Vec), - /// Use the all the pallet parts. - All, + /// Use all the pallet parts except those specified. + Exclude(Vec), + /// Use only the specified pallet parts. + Use(Vec), + /// Use the all the pallet parts. + All, } impl Parse for PalletDeclaration { - fn parse(input: ParseStream) -> Result { - let attrs = input.call(Attribute::parse_outer)?; - let span = input.span(); - let name = input.parse()?; - let _: Token![:] = input.parse()?; - let path = input.parse()?; - - // Parse for instance. - let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { - let _: Token![::] = input.parse()?; - let _: Token![<] = input.parse()?; - let res = Some(input.parse()?); - let _: Token![>] = input.parse()?; - res - } else if !(input.peek(Token![::]) && input.peek3(token::Brace)) - && !input.peek(keyword::expanded) - && !input.peek(keyword::exclude_parts) - && !input.peek(keyword::use_parts) - && !input.peek(Token![=]) - && !input.peek(Token![,]) - && !input.is_empty() - { - return Err(input.error( + fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let span = input.span(); + let name = input.parse()?; + let _: Token![:] = input.parse()?; + let path = input.parse()?; + + // Parse for instance. + let instance = if input.peek(Token![::]) && input.peek3(Token![<]) { + let _: Token![::] = input.parse()?; + let _: Token![<] = input.parse()?; + let res = Some(input.parse()?); + let _: Token![>] = input.parse()?; + res + } else if !(input.peek(Token![::]) && input.peek3(token::Brace)) + && !input.peek(keyword::expanded) + && !input.peek(keyword::exclude_parts) + && !input.peek(keyword::use_parts) + && !input.peek(Token![=]) + && !input.peek(Token![,]) + && !input.is_empty() + { + return Err(input.error( "Unexpected tokens, expected one of `::$ident` `::{`, `exclude_parts`, `use_parts`, `=`, `,`", )); - } else { - None - }; - - // Check if the pallet is fully expanded. - let (is_expanded, extra_parts) = if input.peek(keyword::expanded) { - let _: keyword::expanded = input.parse()?; - let _: Token![::] = input.parse()?; - (true, parse_pallet_parts(input)?) - } else { - (false, vec![]) - }; - - // Parse for explicit parts - let pallet_parts = if input.peek(Token![::]) && input.peek3(token::Brace) { - let _: Token![::] = input.parse()?; - let mut parts = parse_pallet_parts(input)?; - parts.extend(extra_parts.into_iter()); - Some(parts) - } else if !input.peek(keyword::exclude_parts) - && !input.peek(keyword::use_parts) - && !input.peek(Token![=]) - && !input.peek(Token![,]) - && !input.is_empty() - { - return Err(input.error( - "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", - )); - } else { - is_expanded.then_some(extra_parts) - }; - - // Parse for specified parts - let specified_parts = if input.peek(keyword::exclude_parts) { - let _: keyword::exclude_parts = input.parse()?; - SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?) - } else if input.peek(keyword::use_parts) { - let _: keyword::use_parts = input.parse()?; - SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) - } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { - return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")); - } else { - SpecifiedParts::All - }; - - // Parse for pallet index - let index = if input.peek(Token![=]) { - input.parse::()?; - let index = input.parse::()?; - let index = index.base10_parse::()?; - Some(index) - } else if !input.peek(Token![,]) && !input.is_empty() { - return Err(input.error("Unexpected tokens, expected one of `=`, `,`")); - } else { - None - }; - - Ok(Self { - span, - is_expanded, - attrs, - name, - path, - instance, - pallet_parts, - specified_parts, - index, - }) - } + } else { + None + }; + + // Check if the pallet is fully expanded. + let (is_expanded, extra_parts) = if input.peek(keyword::expanded) { + let _: keyword::expanded = input.parse()?; + let _: Token![::] = input.parse()?; + (true, parse_pallet_parts(input)?) + } else { + (false, vec![]) + }; + + // Parse for explicit parts + let pallet_parts = if input.peek(Token![::]) && input.peek3(token::Brace) { + let _: Token![::] = input.parse()?; + let mut parts = parse_pallet_parts(input)?; + parts.extend(extra_parts.into_iter()); + Some(parts) + } else if !input.peek(keyword::exclude_parts) + && !input.peek(keyword::use_parts) + && !input.peek(Token![=]) + && !input.peek(Token![,]) + && !input.is_empty() + { + return Err(input.error( + "Unexpected tokens, expected one of `::{`, `exclude_parts`, `use_parts`, `=`, `,`", + )); + } else { + is_expanded.then_some(extra_parts) + }; + + // Parse for specified parts + let specified_parts = if input.peek(keyword::exclude_parts) { + let _: keyword::exclude_parts = input.parse()?; + SpecifiedParts::Exclude(parse_pallet_parts_no_generic(input)?) + } else if input.peek(keyword::use_parts) { + let _: keyword::use_parts = input.parse()?; + SpecifiedParts::Use(parse_pallet_parts_no_generic(input)?) + } else if !input.peek(Token![=]) && !input.peek(Token![,]) && !input.is_empty() { + return Err(input.error("Unexpected tokens, expected one of `exclude_parts`, `=`, `,`")); + } else { + SpecifiedParts::All + }; + + // Parse for pallet index + let index = if input.peek(Token![=]) { + input.parse::()?; + let index = input.parse::()?; + let index = index.base10_parse::()?; + Some(index) + } else if !input.peek(Token![,]) && !input.is_empty() { + return Err(input.error("Unexpected tokens, expected one of `=`, `,`")); + } else { + None + }; + + Ok(Self { + span, + is_expanded, + attrs, + name, + path, + instance, + pallet_parts, + specified_parts, + index, + }) + } } /// A struct representing a path to a pallet. `PalletPath` is almost identical to the standard @@ -449,309 +423,300 @@ impl Parse for PalletDeclaration { /// - Path segments can only consist of identifers separated by colons #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct PalletPath { - pub inner: Path, + pub inner: Path, } impl PalletPath { - pub fn module_name(&self) -> String { - self.inner - .segments - .iter() - .fold(String::new(), |mut acc, segment| { - if !acc.is_empty() { - acc.push_str("::"); - } - acc.push_str(&segment.ident.to_string()); - acc - }) - } + pub fn module_name(&self) -> String { + self.inner.segments.iter().fold(String::new(), |mut acc, segment| { + if !acc.is_empty() { + acc.push_str("::"); + } + acc.push_str(&segment.ident.to_string()); + acc + }) + } } impl Parse for PalletPath { - fn parse(input: ParseStream) -> Result { - let mut res = PalletPath { - inner: Path { - leading_colon: None, - segments: Punctuated::new(), - }, - }; - - let lookahead = input.lookahead1(); - if lookahead.peek(Token![crate]) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Ident) - { - let ident = input.call(Ident::parse_any)?; - res.inner.segments.push(ident.into()); - } else { - return Err(lookahead.error()); - } - - while input.peek(Token![::]) && input.peek3(Ident) { - input.parse::()?; - let ident = input.parse::()?; - res.inner.segments.push(ident.into()); - } - Ok(res) - } + fn parse(input: ParseStream) -> Result { + let mut res = + PalletPath { inner: Path { leading_colon: None, segments: Punctuated::new() } }; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![crate]) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Ident) + { + let ident = input.call(Ident::parse_any)?; + res.inner.segments.push(ident.into()); + } else { + return Err(lookahead.error()); + } + + while input.peek(Token![::]) && input.peek3(Ident) { + input.parse::()?; + let ident = input.parse::()?; + res.inner.segments.push(ident.into()); + } + Ok(res) + } } impl quote::ToTokens for PalletPath { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.inner.to_tokens(tokens); - } + fn to_tokens(&self, tokens: &mut TokenStream) { + self.inner.to_tokens(tokens); + } } /// Parse [`PalletPart`]'s from a braces enclosed list that is split by commas, e.g. /// /// `{ Call, Event }` fn parse_pallet_parts(input: ParseStream) -> Result> { - let pallet_parts: ext::Braces> = input.parse()?; + let pallet_parts: ext::Braces> = input.parse()?; - let mut resolved = HashSet::new(); - for part in pallet_parts.content.inner.iter() { - if !resolved.insert(part.name()) { - let msg = format!( - "`{}` was already declared before. Please remove the duplicate declaration", - part.name(), - ); - return Err(Error::new(part.keyword.span(), msg)); - } - } + let mut resolved = HashSet::new(); + for part in pallet_parts.content.inner.iter() { + if !resolved.insert(part.name()) { + let msg = format!( + "`{}` was already declared before. Please remove the duplicate declaration", + part.name(), + ); + return Err(Error::new(part.keyword.span(), msg)); + } + } - Ok(pallet_parts.content.inner.into_iter().collect()) + Ok(pallet_parts.content.inner.into_iter().collect()) } #[derive(Debug, Clone)] pub enum PalletPartKeyword { - Pallet(keyword::Pallet), - Call(keyword::Call), - Storage(keyword::Storage), - Event(keyword::Event), - Error(keyword::Error), - Config(keyword::Config), - Origin(keyword::Origin), - Inherent(keyword::Inherent), - ValidateUnsigned(keyword::ValidateUnsigned), - FreezeReason(keyword::FreezeReason), - HoldReason(keyword::HoldReason), - LockId(keyword::LockId), - SlashReason(keyword::SlashReason), + Pallet(keyword::Pallet), + Call(keyword::Call), + Storage(keyword::Storage), + Event(keyword::Event), + Error(keyword::Error), + Config(keyword::Config), + Origin(keyword::Origin), + Inherent(keyword::Inherent), + ValidateUnsigned(keyword::ValidateUnsigned), + FreezeReason(keyword::FreezeReason), + HoldReason(keyword::HoldReason), + LockId(keyword::LockId), + SlashReason(keyword::SlashReason), } impl Parse for PalletPartKeyword { - fn parse(input: ParseStream) -> Result { - let lookahead = input.lookahead1(); - - if lookahead.peek(keyword::Pallet) { - Ok(Self::Pallet(input.parse()?)) - } else if lookahead.peek(keyword::Call) { - Ok(Self::Call(input.parse()?)) - } else if lookahead.peek(keyword::Storage) { - Ok(Self::Storage(input.parse()?)) - } else if lookahead.peek(keyword::Event) { - Ok(Self::Event(input.parse()?)) - } else if lookahead.peek(keyword::Error) { - Ok(Self::Error(input.parse()?)) - } else if lookahead.peek(keyword::Config) { - Ok(Self::Config(input.parse()?)) - } else if lookahead.peek(keyword::Origin) { - Ok(Self::Origin(input.parse()?)) - } else if lookahead.peek(keyword::Inherent) { - Ok(Self::Inherent(input.parse()?)) - } else if lookahead.peek(keyword::ValidateUnsigned) { - Ok(Self::ValidateUnsigned(input.parse()?)) - } else if lookahead.peek(keyword::FreezeReason) { - Ok(Self::FreezeReason(input.parse()?)) - } else if lookahead.peek(keyword::HoldReason) { - Ok(Self::HoldReason(input.parse()?)) - } else if lookahead.peek(keyword::LockId) { - Ok(Self::LockId(input.parse()?)) - } else if lookahead.peek(keyword::SlashReason) { - Ok(Self::SlashReason(input.parse()?)) - } else { - Err(lookahead.error()) - } - } + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::Pallet) { + Ok(Self::Pallet(input.parse()?)) + } else if lookahead.peek(keyword::Call) { + Ok(Self::Call(input.parse()?)) + } else if lookahead.peek(keyword::Storage) { + Ok(Self::Storage(input.parse()?)) + } else if lookahead.peek(keyword::Event) { + Ok(Self::Event(input.parse()?)) + } else if lookahead.peek(keyword::Error) { + Ok(Self::Error(input.parse()?)) + } else if lookahead.peek(keyword::Config) { + Ok(Self::Config(input.parse()?)) + } else if lookahead.peek(keyword::Origin) { + Ok(Self::Origin(input.parse()?)) + } else if lookahead.peek(keyword::Inherent) { + Ok(Self::Inherent(input.parse()?)) + } else if lookahead.peek(keyword::ValidateUnsigned) { + Ok(Self::ValidateUnsigned(input.parse()?)) + } else if lookahead.peek(keyword::FreezeReason) { + Ok(Self::FreezeReason(input.parse()?)) + } else if lookahead.peek(keyword::HoldReason) { + Ok(Self::HoldReason(input.parse()?)) + } else if lookahead.peek(keyword::LockId) { + Ok(Self::LockId(input.parse()?)) + } else if lookahead.peek(keyword::SlashReason) { + Ok(Self::SlashReason(input.parse()?)) + } else { + Err(lookahead.error()) + } + } } impl PalletPartKeyword { - /// Returns the name of `Self`. - fn name(&self) -> &'static str { - match self { - Self::Pallet(_) => "Pallet", - Self::Call(_) => "Call", - Self::Storage(_) => "Storage", - Self::Event(_) => "Event", - Self::Error(_) => "Error", - Self::Config(_) => "Config", - Self::Origin(_) => "Origin", - Self::Inherent(_) => "Inherent", - Self::ValidateUnsigned(_) => "ValidateUnsigned", - Self::FreezeReason(_) => "FreezeReason", - Self::HoldReason(_) => "HoldReason", - Self::LockId(_) => "LockId", - Self::SlashReason(_) => "SlashReason", - } - } - - /// Returns `true` if this pallet part is allowed to have generic arguments. - fn allows_generic(&self) -> bool { - Self::all_generic_arg().iter().any(|n| *n == self.name()) - } - - /// Returns the names of all pallet parts that allow to have a generic argument. - fn all_generic_arg() -> &'static [&'static str] { - &["Event", "Error", "Origin", "Config"] - } + /// Returns the name of `Self`. + fn name(&self) -> &'static str { + match self { + Self::Pallet(_) => "Pallet", + Self::Call(_) => "Call", + Self::Storage(_) => "Storage", + Self::Event(_) => "Event", + Self::Error(_) => "Error", + Self::Config(_) => "Config", + Self::Origin(_) => "Origin", + Self::Inherent(_) => "Inherent", + Self::ValidateUnsigned(_) => "ValidateUnsigned", + Self::FreezeReason(_) => "FreezeReason", + Self::HoldReason(_) => "HoldReason", + Self::LockId(_) => "LockId", + Self::SlashReason(_) => "SlashReason", + } + } + + /// Returns `true` if this pallet part is allowed to have generic arguments. + fn allows_generic(&self) -> bool { + Self::all_generic_arg().iter().any(|n| *n == self.name()) + } + + /// Returns the names of all pallet parts that allow to have a generic argument. + fn all_generic_arg() -> &'static [&'static str] { + &["Event", "Error", "Origin", "Config"] + } } impl ToTokens for PalletPartKeyword { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Self::Pallet(inner) => inner.to_tokens(tokens), - Self::Call(inner) => inner.to_tokens(tokens), - Self::Storage(inner) => inner.to_tokens(tokens), - Self::Event(inner) => inner.to_tokens(tokens), - Self::Error(inner) => inner.to_tokens(tokens), - Self::Config(inner) => inner.to_tokens(tokens), - Self::Origin(inner) => inner.to_tokens(tokens), - Self::Inherent(inner) => inner.to_tokens(tokens), - Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), - Self::FreezeReason(inner) => inner.to_tokens(tokens), - Self::HoldReason(inner) => inner.to_tokens(tokens), - Self::LockId(inner) => inner.to_tokens(tokens), - Self::SlashReason(inner) => inner.to_tokens(tokens), - } - } + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Pallet(inner) => inner.to_tokens(tokens), + Self::Call(inner) => inner.to_tokens(tokens), + Self::Storage(inner) => inner.to_tokens(tokens), + Self::Event(inner) => inner.to_tokens(tokens), + Self::Error(inner) => inner.to_tokens(tokens), + Self::Config(inner) => inner.to_tokens(tokens), + Self::Origin(inner) => inner.to_tokens(tokens), + Self::Inherent(inner) => inner.to_tokens(tokens), + Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), + Self::FreezeReason(inner) => inner.to_tokens(tokens), + Self::HoldReason(inner) => inner.to_tokens(tokens), + Self::LockId(inner) => inner.to_tokens(tokens), + Self::SlashReason(inner) => inner.to_tokens(tokens), + } + } } #[derive(Debug, Clone)] pub struct PalletPart { - pub keyword: PalletPartKeyword, - pub generics: syn::Generics, + pub keyword: PalletPartKeyword, + pub generics: syn::Generics, } impl Parse for PalletPart { - fn parse(input: ParseStream) -> Result { - let keyword: PalletPartKeyword = input.parse()?; - - let generics: syn::Generics = input.parse()?; - if !generics.params.is_empty() && !keyword.allows_generic() { - let valid_generics = PalletPart::format_names(PalletPartKeyword::all_generic_arg()); - let msg = format!( - "`{}` is not allowed to have generics. \ + fn parse(input: ParseStream) -> Result { + let keyword: PalletPartKeyword = input.parse()?; + + let generics: syn::Generics = input.parse()?; + if !generics.params.is_empty() && !keyword.allows_generic() { + let valid_generics = PalletPart::format_names(PalletPartKeyword::all_generic_arg()); + let msg = format!( + "`{}` is not allowed to have generics. \ Only the following pallets are allowed to have generics: {}.", - keyword.name(), - valid_generics, - ); - return Err(syn::Error::new(keyword.span(), msg)); - } + keyword.name(), + valid_generics, + ); + return Err(syn::Error::new(keyword.span(), msg)); + } - Ok(Self { keyword, generics }) - } + Ok(Self { keyword, generics }) + } } impl PalletPart { - pub fn format_names(names: &[&'static str]) -> String { - let res: Vec<_> = names.iter().map(|s| format!("`{}`", s)).collect(); - res.join(", ") - } + pub fn format_names(names: &[&'static str]) -> String { + let res: Vec<_> = names.iter().map(|s| format!("`{}`", s)).collect(); + res.join(", ") + } - /// The name of this pallet part. - pub fn name(&self) -> &'static str { - self.keyword.name() - } + /// The name of this pallet part. + pub fn name(&self) -> &'static str { + self.keyword.name() + } } fn remove_kind( - input: ParseStream, - kind: WhereKind, - definitions: &mut Vec, + input: ParseStream, + kind: WhereKind, + definitions: &mut Vec, ) -> Result { - if let Some(pos) = definitions.iter().position(|d| d.kind == kind) { - Ok(definitions.remove(pos)) - } else { - let msg = format!( - "Missing associated type for `{:?}`. Add `{:?}` = ... to where section.", - kind, kind - ); - Err(input.error(msg)) - } + if let Some(pos) = definitions.iter().position(|d| d.kind == kind) { + Ok(definitions.remove(pos)) + } else { + let msg = format!( + "Missing associated type for `{:?}`. Add `{:?}` = ... to where section.", + kind, kind + ); + Err(input.error(msg)) + } } /// The declaration of a part without its generics #[derive(Debug, Clone)] pub struct PalletPartNoGeneric { - keyword: PalletPartKeyword, + keyword: PalletPartKeyword, } impl Parse for PalletPartNoGeneric { - fn parse(input: ParseStream) -> Result { - Ok(Self { - keyword: input.parse()?, - }) - } + fn parse(input: ParseStream) -> Result { + Ok(Self { keyword: input.parse()? }) + } } /// Parse [`PalletPartNoGeneric`]'s from a braces enclosed list that is split by commas, e.g. /// /// `{ Call, Event }` fn parse_pallet_parts_no_generic(input: ParseStream) -> Result> { - let pallet_parts: ext::Braces> = - input.parse()?; + let pallet_parts: ext::Braces> = + input.parse()?; - let mut resolved = HashSet::new(); - for part in pallet_parts.content.inner.iter() { - if !resolved.insert(part.keyword.name()) { - let msg = format!( - "`{}` was already declared before. Please remove the duplicate declaration", - part.keyword.name(), - ); - return Err(Error::new(part.keyword.span(), msg)); - } - } + let mut resolved = HashSet::new(); + for part in pallet_parts.content.inner.iter() { + if !resolved.insert(part.keyword.name()) { + let msg = format!( + "`{}` was already declared before. Please remove the duplicate declaration", + part.keyword.name(), + ); + return Err(Error::new(part.keyword.span(), msg)); + } + } - Ok(pallet_parts.content.inner.into_iter().collect()) + Ok(pallet_parts.content.inner.into_iter().collect()) } /// The final definition of a pallet with the resulting fixed index and explicit parts. #[derive(Debug, Clone)] pub struct Pallet { - /// Span for current pallet - pub span: Span, - /// Is this pallet fully expanded? - pub is_expanded: bool, - /// The name of the pallet, e.g.`System` in `System: frame_system`. - pub name: Ident, - /// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`). - pub index: u8, - /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. - pub path: PalletPath, - /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. - pub instance: Option, - /// The pallet parts to use for the pallet. - pub pallet_parts: Vec, - /// Expressions specified inside of a #[cfg] attribute. - pub cfg_pattern: Vec, + /// Span for current pallet + pub span: Span, + /// Is this pallet fully expanded? + pub is_expanded: bool, + /// The name of the pallet, e.g.`System` in `System: frame_system`. + pub name: Ident, + /// Either automatically infered, or defined (e.g. `MyPallet ... = 3,`). + pub index: u8, + /// The path of the pallet, e.g. `frame_system` in `System: frame_system`. + pub path: PalletPath, + /// The instance of the pallet, e.g. `Instance1` in `Council: pallet_collective::`. + pub instance: Option, + /// The pallet parts to use for the pallet. + pub pallet_parts: Vec, + /// Expressions specified inside of a #[cfg] attribute. + pub cfg_pattern: Vec, } impl Pallet { - /// Get resolved pallet parts - pub fn pallet_parts(&self) -> &[PalletPart] { - &self.pallet_parts - } + /// Get resolved pallet parts + pub fn pallet_parts(&self) -> &[PalletPart] { + &self.pallet_parts + } - /// Find matching parts - pub fn find_part(&self, name: &str) -> Option<&PalletPart> { - self.pallet_parts.iter().find(|part| part.name() == name) - } + /// Find matching parts + pub fn find_part(&self, name: &str) -> Option<&PalletPart> { + self.pallet_parts.iter().find(|part| part.name() == name) + } - /// Return whether pallet contains part - pub fn exists_part(&self, name: &str) -> bool { - self.find_part(name).is_some() - } + /// Return whether pallet contains part + pub fn exists_part(&self, name: &str) -> bool { + self.find_part(name).is_some() + } } /// Result of a conversion of a declaration of pallets. @@ -764,26 +729,26 @@ impl Pallet { /// +----------+ +----------+ +------------------+ /// ``` enum PalletsConversion { - /// Pallets implicitely declare parts. - /// - /// `System: frame_system`. - Implicit(Vec), - /// Pallets explicitly declare parts. - /// - /// `System: frame_system::{Pallet, Call}` - /// - /// However, for backwards compatibility with Polkadot/Kusama - /// we must propagate some other parts to the pallet by default. - Explicit(Vec), - /// Pallets explicitly declare parts that are fully expanded. - /// - /// This is the end state that contains extra parts included by - /// default by Subtrate. - /// - /// `System: frame_system expanded::{Error} ::{Pallet, Call}` - /// - /// For this example, the `Pallet`, `Call` and `Error` parts are collected. - ExplicitExpanded(Vec), + /// Pallets implicitely declare parts. + /// + /// `System: frame_system`. + Implicit(Vec), + /// Pallets explicitly declare parts. + /// + /// `System: frame_system::{Pallet, Call}` + /// + /// However, for backwards compatibility with Polkadot/Kusama + /// we must propagate some other parts to the pallet by default. + Explicit(Vec), + /// Pallets explicitly declare parts that are fully expanded. + /// + /// This is the end state that contains extra parts included by + /// default by Subtrate. + /// + /// `System: frame_system expanded::{Error} ::{Pallet, Call}` + /// + /// For this example, the `Pallet`, `Call` and `Error` parts are collected. + ExplicitExpanded(Vec), } /// Convert from the parsed pallet declaration to their final information. @@ -792,168 +757,157 @@ enum PalletsConversion { /// pallet using same rules as rust for fieldless enum. I.e. implicit are assigned number /// incrementedly from last explicit or 0. fn convert_pallets(pallets: Vec) -> syn::Result { - if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { - return Ok(PalletsConversion::Implicit(pallets)); - } - - let mut indices = HashMap::new(); - let mut last_index: Option = None; - let mut names = HashMap::new(); - let mut is_expanded = true; - - let pallets = pallets - .into_iter() - .map(|pallet| { - let final_index = match pallet.index { - Some(i) => i, - None => last_index - .map_or(Some(0), |i| i.checked_add(1)) - .ok_or_else(|| { - let msg = "Pallet index doesn't fit into u8, index is 256"; - syn::Error::new(pallet.name.span(), msg) - })?, - }; - - last_index = Some(final_index); - - if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { - let msg = format!( - "Pallet indices are conflicting: Both pallets {} and {} are at index {}", - used_pallet, pallet.name, final_index, - ); - let mut err = syn::Error::new(used_pallet.span(), &msg); - err.combine(syn::Error::new(pallet.name.span(), msg)); - return Err(err); - } - - if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { - let msg = "Two pallets with the same name!"; - - let mut err = syn::Error::new(used_pallet, &msg); - err.combine(syn::Error::new(pallet.name.span(), &msg)); - return Err(err); - } - - let mut pallet_parts = pallet.pallet_parts.expect("Checked above"); - - let available_parts = pallet_parts - .iter() - .map(|part| part.keyword.name()) - .collect::>(); - - // Check parts are correctly specified - match &pallet.specified_parts { - SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) => { - for part in parts { - if !available_parts.contains(part.keyword.name()) { - let msg = format!( - "Invalid pallet part specified, the pallet `{}` doesn't have the \ + if pallets.iter().any(|pallet| pallet.pallet_parts.is_none()) { + return Ok(PalletsConversion::Implicit(pallets)); + } + + let mut indices = HashMap::new(); + let mut last_index: Option = None; + let mut names = HashMap::new(); + let mut is_expanded = true; + + let pallets = pallets + .into_iter() + .map(|pallet| { + let final_index = match pallet.index { + Some(i) => i, + None => last_index.map_or(Some(0), |i| i.checked_add(1)).ok_or_else(|| { + let msg = "Pallet index doesn't fit into u8, index is 256"; + syn::Error::new(pallet.name.span(), msg) + })?, + }; + + last_index = Some(final_index); + + if let Some(used_pallet) = indices.insert(final_index, pallet.name.clone()) { + let msg = format!( + "Pallet indices are conflicting: Both pallets {} and {} are at index {}", + used_pallet, pallet.name, final_index, + ); + let mut err = syn::Error::new(used_pallet.span(), &msg); + err.combine(syn::Error::new(pallet.name.span(), msg)); + return Err(err); + } + + if let Some(used_pallet) = names.insert(pallet.name.clone(), pallet.name.span()) { + let msg = "Two pallets with the same name!"; + + let mut err = syn::Error::new(used_pallet, &msg); + err.combine(syn::Error::new(pallet.name.span(), &msg)); + return Err(err); + } + + let mut pallet_parts = pallet.pallet_parts.expect("Checked above"); + + let available_parts = + pallet_parts.iter().map(|part| part.keyword.name()).collect::>(); + + // Check parts are correctly specified + match &pallet.specified_parts { + SpecifiedParts::Exclude(parts) | SpecifiedParts::Use(parts) => { + for part in parts { + if !available_parts.contains(part.keyword.name()) { + let msg = format!( + "Invalid pallet part specified, the pallet `{}` doesn't have the \ `{}` part. Available parts are: {}.", - pallet.name, - part.keyword.name(), - pallet_parts.iter().fold(String::new(), |fold, part| { - if fold.is_empty() { - format!("`{}`", part.keyword.name()) - } else { - format!("{}, `{}`", fold, part.keyword.name()) - } - }) - ); - return Err(syn::Error::new(part.keyword.span(), msg)); - } - } - } - SpecifiedParts::All => (), - } - - // Set only specified parts. - match pallet.specified_parts { - SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| { - !excluded_parts - .iter() - .any(|excluded_part| excluded_part.keyword.name() == part.keyword.name()) - }), - SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| { - used_parts - .iter() - .any(|use_part| use_part.keyword.name() == part.keyword.name()) - }), - SpecifiedParts::All => (), - } - - let cfg_pattern = pallet - .attrs - .iter() - .map(|attr| { - if attr - .path() - .segments - .first() - .map_or(false, |s| s.ident != "cfg") - { - let msg = "Unsupported attribute, only #[cfg] is supported on pallet \ + pallet.name, + part.keyword.name(), + pallet_parts.iter().fold(String::new(), |fold, part| { + if fold.is_empty() { + format!("`{}`", part.keyword.name()) + } else { + format!("{}, `{}`", fold, part.keyword.name()) + } + }) + ); + return Err(syn::Error::new(part.keyword.span(), msg)); + } + } + }, + SpecifiedParts::All => (), + } + + // Set only specified parts. + match pallet.specified_parts { + SpecifiedParts::Exclude(excluded_parts) => pallet_parts.retain(|part| { + !excluded_parts + .iter() + .any(|excluded_part| excluded_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::Use(used_parts) => pallet_parts.retain(|part| { + used_parts.iter().any(|use_part| use_part.keyword.name() == part.keyword.name()) + }), + SpecifiedParts::All => (), + } + + let cfg_pattern = pallet + .attrs + .iter() + .map(|attr| { + if attr.path().segments.first().map_or(false, |s| s.ident != "cfg") { + let msg = "Unsupported attribute, only #[cfg] is supported on pallet \ declarations in `construct_runtime`"; - return Err(syn::Error::new(attr.span(), msg)); - } - - attr.parse_args_with(|input: syn::parse::ParseStream| { - // Required, otherwise the parse stream doesn't advance and will result in - // an error. - let input = input.parse::()?; - cfg_expr::Expression::parse(&input.to_string()) - .map_err(|e| syn::Error::new(attr.span(), e.to_string())) - }) - }) - .collect::>>()?; - - is_expanded &= pallet.is_expanded; - - Ok(Pallet { - span: pallet.span, - is_expanded: pallet.is_expanded, - name: pallet.name, - index: final_index, - path: pallet.path, - instance: pallet.instance, - cfg_pattern, - pallet_parts, - }) - }) - .collect::>>()?; - - if is_expanded { - Ok(PalletsConversion::ExplicitExpanded(pallets)) - } else { - Ok(PalletsConversion::Explicit(pallets)) - } + return Err(syn::Error::new(attr.span(), msg)); + } + + attr.parse_args_with(|input: syn::parse::ParseStream| { + // Required, otherwise the parse stream doesn't advance and will result in + // an error. + let input = input.parse::()?; + cfg_expr::Expression::parse(&input.to_string()) + .map_err(|e| syn::Error::new(attr.span(), e.to_string())) + }) + }) + .collect::>>()?; + + is_expanded &= pallet.is_expanded; + + Ok(Pallet { + span: pallet.span, + is_expanded: pallet.is_expanded, + name: pallet.name, + index: final_index, + path: pallet.path, + instance: pallet.instance, + cfg_pattern, + pallet_parts, + }) + }) + .collect::>>()?; + + if is_expanded { + Ok(PalletsConversion::ExplicitExpanded(pallets)) + } else { + Ok(PalletsConversion::Explicit(pallets)) + } } pub fn check_pallet_number(input: proc_macro2::TokenStream, pallet_num: usize) -> Result<()> { - let max_pallet_num = { - if cfg!(feature = "tuples-96") { - 96 - } else if cfg!(feature = "tuples-128") { - 128 - } else { - 64 - } - }; - - if pallet_num > max_pallet_num { - let no_feature = max_pallet_num == 128; - return Err(syn::Error::new( - input.span(), - format!( - "{} To increase this limit, enable the tuples-{} feature of [frame_support]. {}", - "The number of pallets exceeds the maximum number of tuple elements.", - max_pallet_num + 32, - if no_feature { - "If the feature does not exist - it needs to be implemented." - } else { - "" - }, - ), - )); - } - - Ok(()) + let max_pallet_num = { + if cfg!(feature = "tuples-96") { + 96 + } else if cfg!(feature = "tuples-128") { + 128 + } else { + 64 + } + }; + + if pallet_num > max_pallet_num { + let no_feature = max_pallet_num == 128; + return Err(syn::Error::new( + input.span(), + format!( + "{} To increase this limit, enable the tuples-{} feature of [frame_support]. {}", + "The number of pallets exceeds the maximum number of tuple elements.", + max_pallet_num + 32, + if no_feature { + "If the feature does not exist - it needs to be implemented." + } else { + "" + }, + ), + )); + } + + Ok(()) } diff --git a/src/engines/pallet_engine/template.rs b/src/engines/pallet_engine/template.rs index 60b455e2..ff9d3b46 100644 --- a/src/engines/pallet_engine/template.rs +++ b/src/engines/pallet_engine/template.rs @@ -1,81 +1,74 @@ use crate::{ - engines::generator::PalletItem, - helpers::{resolve_pallet_path, sanitize}, + engines::generator::PalletItem, + helpers::{resolve_pallet_path, sanitize}, }; use std::{fs, path::PathBuf}; // use super::{pallet_entry::AddPalletEntry, PalletEngine}; pub fn create_pallet_template( - path: Option, - config: TemplatePalletConfig, + path: Option, + config: TemplatePalletConfig, ) -> anyhow::Result<()> { - let target = resolve_pallet_path(path); - // TODO : config.name might use `-` or use snake_case. We want to use pallet_template for the pallet dirs - // and PalletTemplate for the runtime macro - // TODO: this can be further polished (edge cases: no pallet prefix.) - let pallet_name = config.name.clone(); - let pallet_path = target.join(pallet_name.clone()); - sanitize(&pallet_path)?; - generate_pallet_structure(&target, &pallet_name)?; - // todo let pallet_module_name = ... ; - render_pallet(pallet_name, config, &pallet_path)?; - Ok(()) + let target = resolve_pallet_path(path); + // TODO : config.name might use `-` or use snake_case. We want to use pallet_template for the pallet dirs + // and PalletTemplate for the runtime macro + // TODO: this can be further polished (edge cases: no pallet prefix.) + let pallet_name = config.name.clone(); + let pallet_path = target.join(pallet_name.clone()); + sanitize(&pallet_path)?; + generate_pallet_structure(&target, &pallet_name)?; + // todo let pallet_module_name = ... ; + render_pallet(pallet_name, config, &pallet_path)?; + Ok(()) } #[derive(clap::Args, Clone)] pub struct TemplatePalletConfig { - #[arg(short, long, default_value_t = String::from("template"))] - pub name: String, - #[arg(short, long, default_value_t = String::from("author"))] - pub authors: String, - #[arg(short, long, default_value_t = String::from("description"))] - pub description: String, + #[arg(short, long, default_value_t = String::from("template"))] + pub name: String, + #[arg(short, long, default_value_t = String::from("author"))] + pub authors: String, + #[arg(short, long, default_value_t = String::from("description"))] + pub description: String, } /// Generate a pallet folder and file structure fn generate_pallet_structure(target: &PathBuf, pallet_name: &str) -> anyhow::Result<()> { - use fs::{create_dir, File}; - let (pallet, src) = ( - target.join(pallet_name), - target.join(pallet_name.to_string() + "/src"), - ); - // println!("source = > {}", src.display()); - create_dir(&pallet)?; - create_dir(&src)?; - File::create(format!("{}/Cargo.toml", pallet.display()))?; - File::create(format!("{}/lib.rs", src.display()))?; - File::create(format!("{}/benchmarking.rs", src.display()))?; - File::create(format!("{}/tests.rs", src.display()))?; - File::create(format!("{}/mock.rs", src.display()))?; - Ok(()) + use fs::{create_dir, File}; + let (pallet, src) = (target.join(pallet_name), target.join(pallet_name.to_string() + "/src")); + // println!("source = > {}", src.display()); + create_dir(&pallet)?; + create_dir(&src)?; + File::create(format!("{}/Cargo.toml", pallet.display()))?; + File::create(format!("{}/lib.rs", src.display()))?; + File::create(format!("{}/benchmarking.rs", src.display()))?; + File::create(format!("{}/tests.rs", src.display()))?; + File::create(format!("{}/mock.rs", src.display()))?; + Ok(()) } fn render_pallet( - pallet_name: String, - config: TemplatePalletConfig, - pallet_path: &PathBuf, + pallet_name: String, + config: TemplatePalletConfig, + pallet_path: &PathBuf, ) -> anyhow::Result<()> { - // let pallet_name = pallet_name.replace('-', "_"); - use crate::engines::generator::{ - PalletBenchmarking, PalletCargoToml, PalletLib, PalletMock, PalletTests, - }; - // Todo `module` must be of the form Template if pallet_name : `pallet_template` - let pallet: Vec> = vec![ - Box::new(PalletCargoToml { - name: pallet_name.clone(), - authors: config.authors, - description: config.description, - }), - Box::new(PalletLib {}), - Box::new(PalletBenchmarking {}), - Box::new(PalletMock { - module: pallet_name.clone(), - }), - Box::new(PalletTests { - module: pallet_name, - }), - ]; - for item in pallet { - item.execute(pallet_path)?; - } - Ok(()) + // let pallet_name = pallet_name.replace('-', "_"); + use crate::engines::generator::{ + PalletBenchmarking, PalletCargoToml, PalletLib, PalletMock, PalletTests, + }; + // Todo `module` must be of the form Template if pallet_name : `pallet_template` + let pallet: Vec> = vec![ + Box::new(PalletCargoToml { + name: pallet_name.clone(), + authors: config.authors, + description: config.description, + }), + Box::new(PalletLib {}), + Box::new(PalletBenchmarking {}), + Box::new(PalletMock { module: pallet_name.clone() }), + Box::new(PalletTests { module: pallet_name }), + ]; + for item in pallet { + item.execute(pallet_path)?; + } + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 0e3109d8..b9fc16d5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,8 +45,8 @@ enum Commands { #[clap(alias = "t")] Test(commands::test::TestArgs), #[clap(alias = "a")] - /// Add a pallet to the runtime - Add(commands::add::AddArgs), + /// Add a pallet to the runtime + Add(commands::add::AddArgs), } #[tokio::main] @@ -81,7 +81,7 @@ async fn main() -> Result<()> { #[cfg(feature = "contract")] commands::test::TestCommands::Contract(cmd) => cmd.execute(), }, - Commands::Add(args) => args.execute(), + Commands::Add(args) => args.execute(), } }