diff --git a/Cargo.lock b/Cargo.lock index 7a34d0f919f..d64cf722cf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3905,7 +3905,6 @@ dependencies = [ "blake2-rfc", "derive_more", "gear-core", - "gear-core-backend-codegen", "gear-core-errors", "gear-lazy-pages-common", "gear-sandbox", @@ -3916,15 +3915,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "gear-core-backend-codegen" -version = "1.0.1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.31", -] - [[package]] name = "gear-core-errors" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 48a31507c75..1f34048181c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ members = [ "common/codegen", "core", "core-backend", - "core-backend/codegen", "core-processor", "core-errors", "examples/async", @@ -196,7 +195,6 @@ gsys = { path = "gsys" } gtest = { path = "gtest" } gmeta = { path = "gmeta" } gear-authorship = { path = "node/authorship" } -gear-core-backend-codegen = { path = "core-backend/codegen" } gear-core-backend = { path = "core-backend", default-features = false } gear-call-gen = { path = "utils/call-gen" } gear-common = { path = "common", default-features = false } diff --git a/core-backend/Cargo.toml b/core-backend/Cargo.toml index 653b6412c6d..af71eb2c5d0 100644 --- a/core-backend/Cargo.toml +++ b/core-backend/Cargo.toml @@ -8,7 +8,6 @@ license.workspace = true [dependencies] gear-core.workspace = true gear-core-errors = { workspace = true, features = ["codec"] } -gear-core-backend-codegen.workspace = true gear-lazy-pages-common.workspace = true gsys = { workspace = true } diff --git a/core-backend/codegen/Cargo.toml b/core-backend/codegen/Cargo.toml deleted file mode 100644 index 8f7bb632556..00000000000 --- a/core-backend/codegen/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "gear-core-backend-codegen" -description = "Code generation library for gear-core-backend" -keywords = ["gear", "wasm", "codegen"] -categories = ["wasm"] -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[lib] -proc-macro = true - -[dependencies] -syn = { workspace = true, features = ["full", "fold"] } -quote.workspace = true -proc-macro2.workspace = true diff --git a/core-backend/codegen/src/host.rs b/core-backend/codegen/src/host.rs deleted file mode 100644 index 1b9ebeb774f..00000000000 --- a/core-backend/codegen/src/host.rs +++ /dev/null @@ -1,281 +0,0 @@ -// This file is part of Gear. -// -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use quote::{quote, ToTokens}; -use syn::{ - fold::Fold, parse::Parse, parse_quote, punctuated::Punctuated, Block, Expr, ExprCall, ExprPath, - FnArg, GenericArgument, ItemFn, Meta, Pat, PatType, Path, PathArguments, ReturnType, Signature, - Token, Type, -}; - -/// Host function builder. -pub struct HostFn { - item: ItemFn, - meta: HostFnMeta, -} - -impl HostFn { - /// Create a new host function builder. - pub fn new(meta: HostFnMeta, item: ItemFn) -> Self { - Self { item, meta } - } - - /// Build the host function. - pub fn build(mut self) -> TokenStream { - let maybe_wgas = self.meta.fold_item_fn(ItemFn { - attrs: self.item.attrs.clone(), - vis: self.item.vis.clone(), - sig: self.build_sig(), - block: self.build_block(), - }); - - if !self.meta.wgas { - return maybe_wgas.into_token_stream().into(); - } - - self.meta.wgas = false; - let without_gas = ItemFn { - attrs: self.item.attrs.clone(), - vis: self.item.vis.clone(), - sig: self.build_sig(), - block: self.build_block(), - }; - - quote! { - #without_gas - - #maybe_wgas - } - .into() - } - - /// Build inputs from the function signature. - fn build_inputs(&self) -> Vec { - let mut inputs = self.item.sig.inputs.iter().cloned().collect::>(); - - inputs.insert(1, parse_quote!(gas: u64)); - - if matches!(self.meta.call_type, CallType::Fallible) { - inputs.push(parse_quote!(err_mid_ptr: u32)); - } - - if !self.meta.wgas { - return inputs; - } - - let mut injected = false; - let mut new_inputs = vec![]; - inputs.into_iter().for_each(|a| { - if let FnArg::Typed(PatType { pat, .. }) = a.clone() { - if let Pat::Ident(ident) = pat.as_ref() { - // TODO #2722 - if !injected && (ident.ident == "value_ptr" || ident.ident == "delay") { - new_inputs.push(parse_quote!(gas_limit: u64)); - injected = true; - } - } - } - - new_inputs.push(a); - }); - - new_inputs - } - - /// Build the signature of the function. - fn build_sig(&self) -> Signature { - let name = self.item.sig.ident.clone(); - let inputs = self.build_inputs(); - - let mut output = self.item.sig.output.clone(); - if let ReturnType::Type(_rarrow, ty) = &mut output { - if let Type::Path(type_path) = ty.as_mut() { - let segment = type_path.path.segments.first_mut().unwrap(); - if let PathArguments::AngleBracketed(generic_args) = &mut segment.arguments { - let generic_arg = generic_args.args.first_mut().unwrap(); - if let GenericArgument::Type(ty) = generic_arg { - *ty = parse_quote! { (u64, #ty) }; - } - } - } - } - let output = output.clone().into_token_stream(); - - parse_quote! { - fn #name(#(#inputs),*) #output - } - } - - /// Build the function body. - fn build_block(&self) -> Box { - let mut name = self.item.sig.ident.clone().to_string(); - if self.meta.wgas { - name += "_wgas"; - } - - let cost = self.meta.runtime_costs.clone(); - let err = self.meta.err.clone(); - let inner_block = self.item.block.clone(); - let inputs = self.build_inputs(); - - let run: Expr = match self.meta.call_type { - CallType::Any => { - parse_quote! { - ctx.run_any(gas, #cost, |ctx| { - #inner_block - }) - } - } - CallType::Fallible => { - parse_quote! { - ctx.run_fallible::<_, _, #err>(gas, err_mid_ptr, #cost, |ctx| { - #inner_block - }) - } - } - }; - - let mut log_args: Vec = vec![parse_quote!(#name)]; - log_args.extend( - inputs - .into_iter() - .skip(1) - .filter_map(|a| match a { - FnArg::Typed(PatType { pat, .. }) => match pat.as_ref() { - Pat::Ident(ident) => Some(Expr::Path(ExprPath { - attrs: Default::default(), - qself: None, - path: Path::from(ident.clone().ident), - })), - _ => None, - }, - _ => None, - }) - .collect::>(), - ); - - parse_quote! ({ - syscall_trace!(#(#log_args),*); - - #run - }) - } -} - -impl From for TokenStream { - fn from(host_fn: HostFn) -> Self { - host_fn.build() - } -} - -/// Call type of the host function. -#[derive(Default)] -pub enum CallType { - #[default] - Any, - Fallible, -} - -/// Attribute meta of the host function. -pub struct HostFnMeta { - /// Call type of the host function. - pub call_type: CallType, - /// If the host function is wgas. - pub wgas: bool, - /// The runtime costs of the host function. - runtime_costs: Expr, - /// The length of the error. - pub err: Expr, -} - -impl Parse for HostFnMeta { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut call_type = Default::default(); - let mut wgas = false; - let mut runtime_costs = parse_quote!(RuntimeCosts::Null); - let mut err = parse_quote!(ErrorWithHash); - - let meta_list = Punctuated::::parse_terminated(input)?; - for meta in meta_list { - let ident = meta.path().get_ident().expect("Missing ident"); - match ident.to_string().as_ref() { - "fallible" => call_type = CallType::Fallible, - "wgas" => wgas = true, - "cost" => runtime_costs = meta.require_name_value()?.value.clone(), - "err" => err = meta.require_name_value()?.value.clone(), - _ => {} - } - } - - Ok(Self { - call_type, - wgas, - runtime_costs, - err, - }) - } -} - -impl Fold for HostFnMeta { - fn fold_item_fn(&mut self, mut item: ItemFn) -> ItemFn { - if !self.wgas { - return item; - } - - item.sig.ident = Ident::new( - &(item.sig.ident.to_token_stream().to_string() + "_wgas"), - Span::call_site(), - ); - - item.block = Box::new(self.fold_block(*item.block)); - item - } - - fn fold_expr_call(&mut self, mut expr: ExprCall) -> ExprCall { - if !self.wgas { - return expr; - } - - if let Expr::Path(ExprPath { - path: Path { segments, .. }, - .. - }) = &mut *expr.func - { - if segments - .first() - .map(|i| i.to_token_stream().to_string().ends_with("Packet")) - != Some(true) - { - return expr; - } - - if let Some(new) = segments.last_mut() { - new.ident = Ident::new("new_with_gas", Span::call_site()); - } - } - - if let Some(value) = expr.args.pop() { - expr.args.push(parse_quote!(gas_limit)); - expr.args.push(value.value().clone()); - } - - expr - } -} diff --git a/core-backend/codegen/src/lib.rs b/core-backend/codegen/src/lib.rs deleted file mode 100644 index 427ff085416..00000000000 --- a/core-backend/codegen/src/lib.rs +++ /dev/null @@ -1,91 +0,0 @@ -// This file is part of Gear. -// -// Copyright (C) 2021-2023 Gear Technologies Inc. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use host::{HostFn, HostFnMeta}; -use proc_macro::TokenStream; -use syn::ItemFn; - -mod host; - -/// Apply host state wrapper to host functions. -/// -/// Supported meta attributes: -/// * `fallible` - if the host function executes fallible call. -/// * `wgas` - if the host function supports with-gas version. -/// * `cost` - RuntimeCosts definition, for example `#[host(cost = RuntimeCosts::Null)]` -/// * `err` - Structure definition with error code, for example `#[host(err = ErrorWithHash)]` -/// -/// # Example -/// -/// ```ignore -/// #[host(fallible, wgas, cost = RuntimeCosts::Reply(len))] -/// pub fn reply( -/// ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// value_ptr: u32, -/// delay: u32, -/// ) -> Result<(), R::Error> { -/// let read_payload = ctx.register_read(payload_ptr, len); -/// let value = ctx.register_and_read_value(value_ptr)?; -/// let payload = ctx.read(read_payload)?.try_into()?; -/// -/// let state = ctx.host_state_mut(); -/// state.ext.reply(ReplyPacket::new(payload, value), delay) -/// .map_err(Into::into) -/// } -/// ``` -/// -/// will generate -/// -/// ```ignore -/// pub fn reply(ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// value_ptr: u32, -/// delay: u32 -/// ) -> Result<(), R::Error> { -/// syscall_trace!("reply", payload_ptr, len, value_ptr, delay, err_mid_ptr); -/// -/// ctx.run_fallible::<_, _, ErrorWithHash>(err_mid_ptr, RuntimeCosts::Reply(len), |ctx| { -/// // ... -/// }) -/// } -/// -/// pub fn reply_wgas( -/// ctx: &mut R, -/// payload_ptr: u32, -/// len: u32, -/// gas_limit: u64, -/// value_ptr: u32, -/// delay: u32 -/// ) -> Result<(), R::Error> { -/// syscall_trace!("reply_wgas", payload_ptr, len, gas_limit, value_ptr, delay, err_mid_ptr); -/// -/// ctx.run_fallible::<_, _, ErrorWithHash>(err_mid_ptr, RuntimeCosts::ReplyWGas(len), |ctx| { -/// // ... -/// }) -/// } -/// ``` -#[proc_macro_attribute] -pub fn host(meta: TokenStream, item: TokenStream) -> TokenStream { - let meta: HostFnMeta = syn::parse_macro_input!(meta); - let item: ItemFn = syn::parse_macro_input!(item); - - HostFn::new(meta, item).into() -}