Commit b9b9a9b3 authored by Robin Freyler's avatar Robin Freyler

[*] remove ink_lang and ink_model sub crates

parent fe093478
Pipeline #56436 failed with stages
in 24 seconds
......@@ -3,8 +3,6 @@
members = [
"utils",
"core",
"model",
"lang",
"lang2",
"cli",
"abi",
......
[package]
name = "ink_lang"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "MIT/Apache-2.0"
readme = "README.md"
# repository = "https://github.com/robbepop/substrate-contract"
# homepage = "https://github.com/robbepop/substrate-contract"
# documentation = "https://robbepop.github.io/pwasm-abi/substrate-contract/"
description = "[ink!] Rust based eDSL for writing smart contracts for Substrate"
keywords = ["wasm", "parity", "webassembly", "blockchain", "edsl"]
categories = ["no-std", "embedded"]
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
[dependencies]
ink_utils = { path = "../utils/", default-features = false }
ink_model = { path = "../model/", default-features = false }
scale = { package = "parity-scale-codec", version = "1.0", default-features = false, features = ["derive"] }
quote = "0.6"
syn = { version = "0.15", features = ["parsing", "full", "extra-traits"] }
proc-macro2 = "0.4"
heck = "0.3"
itertools = { version = "0.8", default-features = false }
either = { version = "1.5", default-features = false }
serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = "1.0"
[dev-dependencies]
pretty_assertions = "0.6.1"
[lib]
name = "ink_lang"
proc-macro = true
[features]
default = ["test-env"]
std = [
"ink_utils/std",
"ink_model/std",
"scale/std",
"itertools/use_std",
"either/use_std",
"serde/std",
]
test-env = [
"std",
"ink_model/test-env",
]
ink-generate-abi = [
"std",
]
../LICENSE
\ No newline at end of file
../README.md
\ No newline at end of file
This diff is collapsed.
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::TokenStream as TokenStream2;
use syn::Result;
#[cfg(feature = "ink-generate-abi")]
use crate::old_abi;
use crate::{
gen,
hir,
parser,
};
pub fn generate(input: TokenStream2) -> TokenStream2 {
match generate_or_err(input) {
Ok(tokens) => tokens,
Err(err) => err.to_compile_error(),
}
}
pub fn generate_or_err(input: TokenStream2) -> Result<TokenStream2> {
let ast_contract = parser::parse_contract(input)?;
let hir_contract = hir::Contract::from_ast(&ast_contract)?;
#[cfg(feature = "ink-generate-abi")]
old_abi::generate_old_abi(&hir_contract)?;
let tokens = gen::generate_code(&hir_contract);
Ok(tokens)
}
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
macro_rules! bail {
($($args:tt)*) => {
return Err(format_err!($($args)*).into())
}
}
macro_rules! format_err {
($tokens:expr, $($msg:tt)*) => {
match &$tokens {
t => {
syn::parse::Error::new_spanned(t, format_args!($($msg)*))
}
}
}
}
This diff is collapsed.
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
//! Code generation for smart contracts when they are compiled as a dependency of another smart contract
//! using the generally available `ink-as-dependency` crate feature.
//!
//! The code generated by this generally conflicts with other generated code since an ink! contract
//! that is compiled as dependency no longer requires any infrastructure to dispatch calls or instantiations.
//! However, it requires special treatment for all public messages since their bodies are completely
//! replaced by direct forwards to the remote call infrastructure going through SRML contracts.
use crate::{
ast,
gen::selector_to_expr,
hir,
};
use proc_macro2::TokenStream as TokenStream2;
use quote::{
quote,
quote_spanned,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Mutability {
Immutable,
Mutable,
}
pub fn generate_code(tokens: &mut TokenStream2, contract: &hir::Contract) {
let messages = generate_messages_as_dependency(contract);
let call_enhancer_messages =
generate_call_enhancer_messages(contract, Mutability::Immutable);
let call_enhancer_mut_messages =
generate_call_enhancer_messages(contract, Mutability::Mutable);
let state = generate_state_as_dependency(contract);
let contract_ident = &contract.name;
tokens.extend(quote! {
#[cfg(feature = "ink-as-dependency")]
mod as_dependency {
use super::*;
#state
impl #contract_ident {
#(#messages)*
}
impl<'a> CallEnhancer<'a> {
#(#call_enhancer_messages)*
}
impl<'a> CallEnhancerMut<'a> {
#(#call_enhancer_mut_messages)*
}
}
#[cfg(feature = "ink-as-dependency")]
pub use as_dependency::{
#contract_ident,
CallEnhancer,
CallEnhancerMut,
};
});
}
fn generate_state_as_dependency(contract: &hir::Contract) -> TokenStream2 {
let name = &contract.name;
let attrs = &contract.state.attrs;
let create = generate_create(contract);
quote! {
#( #attrs )*
#[derive(Clone, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))]
pub struct #name {
account_id: AccountId,
}
impl ink_core::storage::Flush for #name {
fn flush(&mut self) {}
}
/// Allows to enhance calls to `&self` contract messages.
pub struct CallEnhancer<'a> {
contract: &'a #name,
}
/// Allows to enhance calls to `&mut self` contract messages.
pub struct CallEnhancerMut<'a> {
contract: &'a mut #name,
}
impl ink_core::env::FromAccountId<Env> for #name {
fn from_account_id(account_id: AccountId) -> Self {
Self { account_id }
}
}
impl #name {
#create
/// Returns the internal account ID of the contract.
pub fn account_id(&self) -> AccountId {
self.account_id
}
/// Allows to enhance calls to `&self` contract messages.
pub fn call(&self) -> CallEnhancer {
CallEnhancer { contract: self }
}
/// Allows to enhance calls to `&mut self` contract messages.
pub fn call_mut(&mut self) -> CallEnhancerMut {
CallEnhancerMut { contract: self }
}
}
}
}
fn generate_create(contract: &hir::Contract) -> TokenStream2 {
let deploy_handler = &contract.on_deploy;
let attrs = &deploy_handler.attrs;
let args = deploy_handler.decl.inputs.iter().skip(1);
let inputs = deploy_handler
.decl
.inputs
.iter()
.filter_map(ast::FnArg::ident)
.map(|ident| quote! { #ident });
quote_spanned! { deploy_handler.decl.fn_tok.span =>
#(#attrs)*
pub fn new(
code_hash: Hash,
#(#args ,)*
) -> ink_core::env::CreateBuilder<Env, Self> {
ink_core::env::CreateBuilder::<Env, Self>::new(code_hash)
#(
.push_arg(&#inputs)
)*
}
}
}
fn generate_messages_as_dependency<'a>(
contract: &'a hir::Contract,
) -> impl Iterator<Item = TokenStream2> + 'a {
let contract_ident = &contract.name;
contract.messages.iter().map(move |message| {
let ident = &message.sig.ident;
let attrs = &message.attrs;
let args = message.sig.decl.inputs.iter().skip(1);
let (self_arg, call_fn) = if message.is_mut() {
(quote! { &mut self }, quote! { call_mut() })
} else {
(quote! { &self }, quote! { call() })
};
let inputs = message
.sig
.decl
.inputs
.iter()
.filter_map(ast::FnArg::ident)
.map(|ident| quote! { #ident });
let output = &message.sig.decl.output;
let (_impl_generics, type_generics, where_clause) =
message.sig.decl.generics.split_for_impl();
match output {
syn::ReturnType::Default => {
quote_spanned! { ident.span() =>
#(#attrs)*
pub fn #ident #type_generics (
#self_arg ,
#(#args ,)*
) #where_clause {
self.#call_fn.#ident( #(#inputs ,)* )
.fire()
.expect(concat!(
"invocation of ",
stringify!(#contract_ident), "::", stringify!(#ident),
" message was invalid"))
}
}
}
syn::ReturnType::Type(_, ty) => {
quote_spanned! { ident.span() =>
#(#attrs)*
pub fn #ident #type_generics (
#self_arg ,
#(#args ,)*
) -> #ty #where_clause {
self.#call_fn.#ident( #(#inputs ,)* )
.fire()
.expect(concat!(
"evaluation of ",
stringify!(#contract_ident), "::", stringify!(#ident),
" message was invalid"))
}
}
}
}
})
}
fn generate_call_enhancer_messages<'a>(
contract: &'a hir::Contract,
mutability: Mutability,
) -> impl Iterator<Item = TokenStream2> + 'a {
contract.messages
.iter()
.filter(move |message| {
if mutability == Mutability::Mutable {
message.is_mut()
} else {
!message.is_mut()
}
})
.map(|message| {
let ident = &message.sig.ident;
let attrs = &message.attrs;
let args = message.sig.decl.inputs.iter().skip(1);
let inputs = message.sig.decl.inputs
.iter()
.filter_map(ast::FnArg::ident)
.map(|ident| quote! { #ident });
let output = &message.sig.decl.output;
let (_impl_generics, type_generics, where_clause) = message.sig.decl.generics.split_for_impl();
let selector = selector_to_expr(message.selector());
match output {
syn::ReturnType::Default => quote_spanned! { ident.span() =>
#(#attrs)*
pub fn #ident #type_generics (
self,
#(#args ,)*
) -> ink_core::env::CallBuilder<Env, ()> #where_clause {
ink_core::env::CallBuilder::<Env, ()>::invoke(self.contract.account_id.clone(), #selector)
#(
.push_arg(&#inputs)
)*
}
},
syn::ReturnType::Type(_, ty) => quote_spanned! { ident.span() =>
#(#attrs)*
pub fn #ident #type_generics (
self,
#(#args ,)*
) -> ink_core::env::CallBuilder<Env, ink_core::env::ReturnType<#ty>> #where_clause {
ink_core::env::CallBuilder::eval(self.contract.account_id.clone(), #selector)
#(
.push_arg(&#inputs)
)*
}
}
}
})
}
This diff is collapsed.
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
//! Code generation for documentation generation of Wasm smart contracts.
//!
//! We use the special `#[cfg(rustdoc)]` that is set when `rustdoc` is
//! compiling a crate in order to generate special code that is only used
//! for documentation purposes.
use crate::hir;
use proc_macro2::TokenStream as TokenStream2;
pub fn generate_code(_tokens: &mut TokenStream2, _contract: &hir::Contract) {}
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
mod abi;
mod as_dependency;
mod build;
mod doc;
mod test;
use crate::hir;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{
parse_str,
Expr,
};
/// Generates code for the given contract.
///
/// # Note
///
/// This generates code for normal Wasm smart contract builds as
/// well as code for specialized `test` and `doc` targets.
pub fn generate_code(contract: &hir::Contract) -> TokenStream2 {
let mut tokens = quote! {};
build::generate_code(&mut tokens, contract);
doc::generate_code(&mut tokens, contract);
test::generate_code(&mut tokens, contract);
abi::generate_code(&mut tokens, contract);
as_dependency::generate_code(&mut tokens, contract);
tokens
}
/// The function is required because syn doesn't provide a
/// `ToTokens` implementation for `[u8; 4]`.
fn selector_to_expr(selector: [u8; 4]) -> Expr {
let selector = format!(
"[{}, {}, {}, {}]",
selector[0], selector[1], selector[2], selector[3]
);
parse_str::<syn::Expr>(&selector).expect("failed to parse selector")
}
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
//! Code generation for test generation of Wasm smart contracts.
//!
//! Test code is generated under the `#[cfg(test)]` compile flag.
use crate::{
ast,
hir,
ident_ext::IdentExt,
};
use proc_macro2::TokenStream as TokenStream2;
use quote::{
quote,
ToTokens,
};
use syn::{
self,
punctuated::Punctuated,
Token,
};
pub fn generate_code(tokens: &mut TokenStream2, contract: &hir::Contract) {
let test_mod_body = generate_test_mod_body(contract);
tokens.extend(quote! {
#[cfg(test)]
mod test {
use super::*;
#test_mod_body
}
})
}
fn generate_test_mod_body(contract: &hir::Contract) -> TokenStream2 {
let mut tokens = quote! {};
generate_test_struct(&mut tokens, contract);
generate_test_deploy(&mut tokens, contract);
generate_test_allocate_deploy_block(&mut tokens, contract);
generate_test_methods(&mut tokens, contract);
tokens
}
/// For a contract returns its testable type name.
///
/// # Example
///
/// For a contract called `Flipper` this returns `TestableFlipper`.
fn testable_contract_name(contract: &hir::Contract) -> proc_macro2::Ident {
proc_macro2::Ident::from_str(["Testable", &contract.name.to_string()].concat())
}
fn generate_test_struct(tokens: &mut TokenStream2, contract: &hir::Contract) {
let contract_name = &contract.name;
let env_types = &contract.env_types_type;
let testable_name = testable_contract_name(contract);
tokens.extend(quote! {
pub struct #testable_name {
env: ink_model::ExecutionEnv<#contract_name, ink_core::env::ContractEnv<#env_types>>,
}
})
}
fn generate_test_deploy(tokens: &mut TokenStream2, contract: &hir::Contract) {
let contract_name = &contract.name;
let testable_name = testable_contract_name(contract);
let deploy_fn_toks = {
let mut content = quote! {};
<Token![pub]>::default().to_tokens(&mut content);
<Token![fn]>::default().to_tokens(&mut content);
syn::Ident::from_str("deploy_mock").to_tokens(&mut content);
syn::token::Paren::default().surround(&mut content, |inner| {
contract
.on_deploy
.decl
.inputs_without_self()
.to_tokens(inner)
});
<Token![->]>::default().to_tokens(&mut content);
testable_name.to_tokens(&mut content);
syn::token::Brace::default().surround(&mut content, |inner| {
let inputs = {
let mut inputs: Punctuated<syn::Pat, Token![,]> = Default::default();
for input in &contract.on_deploy.decl.inputs {
if let ast::FnArg::Captured(captured) = input {
inputs.push(captured.pat.clone())
}
}
inputs
};
inner.extend(quote! {
let mut mock = #testable_name::allocate();
mock.deploy(#inputs);
mock
})
});
content
};
tokens.extend(quote! {
impl #contract_name {
/// Returns a testable version of the contract.
#deploy_fn_toks
}
})
}
fn generate_test_allocate_deploy_block(
tokens: &mut TokenStream2,
contract: &hir::Contract,
) {
let testable_name = testable_contract_name(contract);
let mut impl_body = quote! {};
generate_test_allocate_fn(&mut impl_body, contract);
generate_test_deploy_fn(&mut impl_body, contract);
tokens.extend(quote! {
impl #testable_name {
#impl_body
}
})
}
fn generate_test_allocate_fn(tokens: &mut TokenStream2, _contract: &hir::Contract) {
tokens.extend(quote! {
/// Allocates the testable contract storage.
fn allocate() -> Self {
use ink_core::storage::{
Key,
alloc::{
AllocateUsing as _,
Initialize as _,
BumpAlloc,
},
};
Self {
env: unsafe {
let mut alloc = BumpAlloc::from_raw_parts(Key([0x0; 32]));
ink_model::ExecutionEnv::allocate_using(&mut alloc).initialize_into(())
}
}
}
})
}
fn generate_test_deploy_fn(tokens: &mut TokenStream2, contract: &hir::Contract) {
let log_params = contract.on_deploy.decl.inputs_without_self();
let act_params = log_params.to_actual_params();
tokens.extend(quote! {
/// Deploys the testable contract by initializing it with the given values.
fn deploy(&mut self, #log_params) {
let (handler, state) = self.env.split_mut();
state.deploy(handler, #act_params)
}
})
}
fn generate_test_methods(tokens: &mut TokenStream2, contract: &hir::Contract) {
let impl_for = testable_contract_name(contract);
let mut impl_body = quote! {};
generate_test_method_fns(&mut impl_body, contract);
tokens.extend(quote! {
impl #impl_for {
#impl_body
}
})
}
fn generate_test_method_fns(tokens: &mut TokenStream2, contract: &hir::Contract) {
for msg in &contract.messages {
generate_test_method_fn(tokens, msg);
}
}
fn generate_test_method_fn(tokens: &mut TokenStream2, msg: &hir::Message) {
<Token![pub]>::default().to_tokens(tokens);
<Token![fn]>::default().to_tokens(tokens);
msg.sig.ident.to_tokens(tokens);
syn::token::Paren::default()
.surround(tokens, |inner| msg.sig.decl.inputs().to_tokens(inner));
msg.sig.decl.output.to_tokens(tokens);
syn::token::Brace::default().surround(tokens, |inner| {
let params = msg.sig.decl.inputs_without_self().to_actual_params();
let name = &msg.sig.ident;
let split_impl = if msg.is_mut() {
quote! { self.env.split_mut() }
} else {
quote! { self.env.split() }
};
inner.extend(quote! {
let (handler, state) = #split_impl;
state.#name(handler, #params)
})
});
}
This diff is collapsed.
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! is distributed in the hope that it will be useful,