288 lines
8.6 KiB
Rust
288 lines
8.6 KiB
Rust
// This file is part of Bizinikiwi.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
pub mod helper;
|
|
pub mod pezpallet;
|
|
pub mod pezpallet_decl;
|
|
pub mod runtime_struct;
|
|
pub mod runtime_types;
|
|
|
|
use crate::construct_runtime::parse::Pezpallet;
|
|
use pezpallet_decl::PalletDeclaration;
|
|
use proc_macro2::TokenStream as TokenStream2;
|
|
use quote::ToTokens;
|
|
use std::collections::HashMap;
|
|
use syn::{spanned::Spanned, Ident, Token};
|
|
|
|
use pezframe_support_procedural_tools::syn_ext as ext;
|
|
use runtime_types::RuntimeType;
|
|
|
|
mod keyword {
|
|
use syn::custom_keyword;
|
|
|
|
custom_keyword!(runtime);
|
|
custom_keyword!(derive);
|
|
custom_keyword!(pezpallet_index);
|
|
custom_keyword!(disable_call);
|
|
custom_keyword!(disable_unsigned);
|
|
}
|
|
|
|
enum RuntimeAttr {
|
|
Runtime(proc_macro2::Span),
|
|
Derive(proc_macro2::Span, Vec<RuntimeType>),
|
|
PalletIndex(proc_macro2::Span, u8),
|
|
DisableCall(proc_macro2::Span),
|
|
DisableUnsigned(proc_macro2::Span),
|
|
}
|
|
|
|
impl RuntimeAttr {
|
|
fn span(&self) -> proc_macro2::Span {
|
|
match self {
|
|
Self::Runtime(span) => *span,
|
|
Self::Derive(span, _) => *span,
|
|
Self::PalletIndex(span, _) => *span,
|
|
Self::DisableCall(span) => *span,
|
|
Self::DisableUnsigned(span) => *span,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl syn::parse::Parse for RuntimeAttr {
|
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
|
input.parse::<syn::Token![#]>()?;
|
|
let content;
|
|
syn::bracketed!(content in input);
|
|
content.parse::<keyword::runtime>()?;
|
|
content.parse::<syn::Token![::]>()?;
|
|
|
|
let lookahead = content.lookahead1();
|
|
if lookahead.peek(keyword::runtime) {
|
|
Ok(RuntimeAttr::Runtime(content.parse::<keyword::runtime>()?.span()))
|
|
} else if lookahead.peek(keyword::derive) {
|
|
let _ = content.parse::<keyword::derive>();
|
|
let derive_content;
|
|
syn::parenthesized!(derive_content in content);
|
|
let runtime_types =
|
|
derive_content.parse::<ext::Punctuated<RuntimeType, Token![,]>>()?;
|
|
let runtime_types = runtime_types.inner.into_iter().collect();
|
|
Ok(RuntimeAttr::Derive(derive_content.span(), runtime_types))
|
|
} else if lookahead.peek(keyword::pezpallet_index) {
|
|
let _ = content.parse::<keyword::pezpallet_index>();
|
|
let pezpallet_index_content;
|
|
syn::parenthesized!(pezpallet_index_content in content);
|
|
let pezpallet_index = pezpallet_index_content.parse::<syn::LitInt>()?;
|
|
if !pezpallet_index.suffix().is_empty() {
|
|
let msg = "Number literal must not have a suffix";
|
|
return Err(syn::Error::new(pezpallet_index.span(), msg));
|
|
}
|
|
Ok(RuntimeAttr::PalletIndex(pezpallet_index.span(), pezpallet_index.base10_parse()?))
|
|
} else if lookahead.peek(keyword::disable_call) {
|
|
Ok(RuntimeAttr::DisableCall(content.parse::<keyword::disable_call>()?.span()))
|
|
} else if lookahead.peek(keyword::disable_unsigned) {
|
|
Ok(RuntimeAttr::DisableUnsigned(content.parse::<keyword::disable_unsigned>()?.span()))
|
|
} else {
|
|
Err(lookahead.error())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum AllPalletsDeclaration {
|
|
Implicit(ImplicitAllPalletsDeclaration),
|
|
Explicit(ExplicitAllPalletsDeclaration),
|
|
}
|
|
|
|
/// Declaration of a runtime with some pezpallet with implicit declaration of parts.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ImplicitAllPalletsDeclaration {
|
|
pub pezpallet_decls: Vec<PalletDeclaration>,
|
|
pub pezpallet_count: usize,
|
|
}
|
|
|
|
/// Declaration of a runtime with all pezpallet having explicit declaration of parts.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ExplicitAllPalletsDeclaration {
|
|
pub name: Ident,
|
|
pub pallets: Vec<Pezpallet>,
|
|
}
|
|
|
|
pub struct Def {
|
|
pub input: TokenStream2,
|
|
pub runtime_struct: runtime_struct::RuntimeStructDef,
|
|
pub pallets: AllPalletsDeclaration,
|
|
pub runtime_types: Vec<RuntimeType>,
|
|
}
|
|
|
|
impl Def {
|
|
pub fn try_from(mut item: syn::ItemMod) -> syn::Result<Self> {
|
|
let input: TokenStream2 = item.to_token_stream().into();
|
|
let item_span = item.span();
|
|
let items = &mut item
|
|
.content
|
|
.as_mut()
|
|
.ok_or_else(|| {
|
|
let msg = "Invalid runtime definition, expected mod to be inlined.";
|
|
syn::Error::new(item_span, msg)
|
|
})?
|
|
.1;
|
|
|
|
let mut runtime_struct = None;
|
|
let mut runtime_types = None;
|
|
|
|
let mut indices = HashMap::new();
|
|
let mut names = HashMap::new();
|
|
|
|
let mut pezpallet_decls = vec![];
|
|
let mut pallets = vec![];
|
|
|
|
for item in items.iter_mut() {
|
|
let mut pezpallet_index_and_item = None;
|
|
|
|
let mut disable_call = false;
|
|
let mut disable_unsigned = false;
|
|
|
|
while let Some(runtime_attr) =
|
|
helper::take_first_item_runtime_attr::<RuntimeAttr>(item)?
|
|
{
|
|
match runtime_attr {
|
|
RuntimeAttr::Runtime(_) if runtime_struct.is_none() => {
|
|
let p = runtime_struct::RuntimeStructDef::try_from(item)?;
|
|
runtime_struct = Some(p);
|
|
},
|
|
RuntimeAttr::Derive(_, types) if runtime_types.is_none() => {
|
|
runtime_types = Some(types);
|
|
},
|
|
RuntimeAttr::PalletIndex(span, index) => {
|
|
pezpallet_index_and_item = if let syn::Item::Type(item) = item {
|
|
Some((index, item.clone()))
|
|
} else {
|
|
let msg = "Invalid runtime::pezpallet_index, expected type definition";
|
|
return Err(syn::Error::new(span, msg));
|
|
};
|
|
},
|
|
RuntimeAttr::DisableCall(_) => disable_call = true,
|
|
RuntimeAttr::DisableUnsigned(_) => disable_unsigned = true,
|
|
attr => {
|
|
let msg = "Invalid duplicated attribute";
|
|
return Err(syn::Error::new(attr.span(), msg));
|
|
},
|
|
}
|
|
}
|
|
|
|
if let Some((pezpallet_index, pezpallet_item)) = pezpallet_index_and_item {
|
|
match *pezpallet_item.ty.clone() {
|
|
syn::Type::Path(ref path) => {
|
|
let pezpallet_decl =
|
|
PalletDeclaration::try_from(item.span(), &pezpallet_item, &path.path)?;
|
|
|
|
if let Some(used_pallet) =
|
|
names.insert(pezpallet_decl.name.clone(), pezpallet_decl.name.span())
|
|
{
|
|
let msg = "Two pallets with the same name!";
|
|
|
|
let mut err = syn::Error::new(used_pallet, &msg);
|
|
err.combine(syn::Error::new(pezpallet_decl.name.span(), &msg));
|
|
return Err(err);
|
|
}
|
|
|
|
pezpallet_decls.push(pezpallet_decl);
|
|
},
|
|
syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) => {
|
|
let pezpallet = Pezpallet::try_from(
|
|
item.span(),
|
|
&pezpallet_item,
|
|
pezpallet_index,
|
|
disable_call,
|
|
disable_unsigned,
|
|
&bounds,
|
|
)?;
|
|
|
|
if let Some(used_pallet) =
|
|
indices.insert(pezpallet.index, pezpallet.name.clone())
|
|
{
|
|
let msg = format!(
|
|
"Pezpallet indices are conflicting: Both pallets {} and {} are at index {}",
|
|
used_pallet, pezpallet.name, pezpallet.index,
|
|
);
|
|
let mut err = syn::Error::new(used_pallet.span(), &msg);
|
|
err.combine(syn::Error::new(pezpallet.name.span(), msg));
|
|
return Err(err);
|
|
}
|
|
|
|
pallets.push(pezpallet);
|
|
},
|
|
_ => continue,
|
|
}
|
|
} else {
|
|
if let syn::Item::Type(item) = item {
|
|
let msg = "Missing pezpallet index for pezpallet declaration. Please add `#[runtime::pezpallet_index(...)]`";
|
|
return Err(syn::Error::new(item.span(), &msg));
|
|
}
|
|
}
|
|
}
|
|
|
|
let name = item.ident.clone();
|
|
let decl_count = pezpallet_decls.len();
|
|
let pallets = if decl_count > 0 {
|
|
AllPalletsDeclaration::Implicit(ImplicitAllPalletsDeclaration {
|
|
pezpallet_decls,
|
|
pezpallet_count: decl_count.saturating_add(pallets.len()),
|
|
})
|
|
} else {
|
|
AllPalletsDeclaration::Explicit(ExplicitAllPalletsDeclaration { name, pallets })
|
|
};
|
|
|
|
let def = Def {
|
|
input,
|
|
runtime_struct: runtime_struct.ok_or_else(|| {
|
|
syn::Error::new(item_span,
|
|
"Missing Runtime. Please add a struct inside the module and annotate it with `#[runtime::runtime]`"
|
|
)
|
|
})?,
|
|
pallets,
|
|
runtime_types: runtime_types.ok_or_else(|| {
|
|
syn::Error::new(item_span,
|
|
"Missing Runtime Types. Please annotate the runtime struct with `#[runtime::derive]`"
|
|
)
|
|
})?,
|
|
};
|
|
|
|
Ok(def)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn runtime_parsing_works() {
|
|
let def = Def::try_from(syn::parse_quote! {
|
|
#[runtime::runtime]
|
|
mod runtime {
|
|
#[runtime::derive(RuntimeCall, RuntimeEvent)]
|
|
#[runtime::runtime]
|
|
pub struct Runtime;
|
|
|
|
#[runtime::pezpallet_index(0)]
|
|
pub type System = pezframe_system::Pezpallet<Runtime>;
|
|
|
|
#[runtime::pezpallet_index(1)]
|
|
pub type Pallet1 = pallet1<Instance1>;
|
|
}
|
|
})
|
|
.expect("Failed to parse runtime definition");
|
|
|
|
assert_eq!(def.runtime_struct.ident, "Runtime");
|
|
}
|