Skip to content

Commit

Permalink
feat(dan): basic template macro (#4358)
Browse files Browse the repository at this point in the history
Description
---
* New engine package to encapsulate the macro logic. In the future we may consider extracting it to a separate project or repo.
* The user template code handling is encapsulated into the `ast` module.
* Each section of the generated template code is split into different modules:
    * **definition**: generates a verbatim module of the user code, needed for the template macro to compile properly.
    * **abi**: generates the ABI section of the contract wasm, needed in the engine to know the contract function signatures.
    * **dispatcher**: executes a call invocation, by deciding which user-defined code to call and encoding the result.
    * **dependencies**: helper functions that need to be included into the wasm, as well as the `tari_engine` import signature.
* Current limitations:
    * The function arguments are not yet processed and encoded, so at the moment it only supports user-defined functions with no parameters. But return values are handled.
    * Struct fields and `self` is not handled yet
    * Calls to the tari engine import are not being done

Motivation and Context
---
Template developers need an ergonomic way of writing contract code. This PR aims to provide a new macro `template!` to allow easy development of new _basic_  contracts. And for _basic_ I mean no struct fields, no resource access and no composability, only stateless functions. Those features will be added in future PRs.

With this PR, the existing "Hello World" example is rewritten as:
```
use tari_template_macros::template;

template! {
    struct HelloWorld {}

    impl HelloWorld { 
        pub fn greet() -> String {
            "Hello World!".to_string()
        }
    }
}
```

How Has This Been Tested?
---
* The unit test for the "Hello World" contract example now is written using the new macro. It compiles and runs in our engine successfully
* New unit tests for some complex sections of the macro
  • Loading branch information
mrnaveira authored Jul 29, 2022
1 parent 2ca0672 commit 594ca0e
Show file tree
Hide file tree
Showing 13 changed files with 809 additions and 32 deletions.
15 changes: 13 additions & 2 deletions dan_layer/engine/tests/hello_world/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dan_layer/engine/tests/hello_world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"

[dependencies]
tari_template_abi = { path = "../../../template_abi" }
tari_template_macros = { path = "../macros" }
common = { path = "../common" }

[profile.release]
Expand Down
37 changes: 8 additions & 29 deletions dan_layer/engine/tests/hello_world/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,14 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// TODO: we should only use stdlib if the template dev needs to include it e.g. use core::mem when stdlib is not
// available
use tari_template_macros::template;

use common::{generate_abi, generate_main, TemplateImpl};
use tari_template_abi::{encode_with_len, FunctionDef, Type};
template! {
struct HelloWorld {}

// TODO: Macro generated code
#[no_mangle]
extern "C" fn HelloWorld_abi() -> *mut u8 {
let template_name = "HelloWorld".to_string();

let functions = vec![FunctionDef {
name: "greet".to_string(),
arguments: vec![],
output: Type::String,
}];

generate_abi(template_name, functions)
}

#[no_mangle]
extern "C" fn HelloWorld_main(call_info: *mut u8, call_info_len: usize) -> *mut u8 {
let mut template_impl = TemplateImpl::new();

template_impl.add_function("greet".to_string(), Box::new(|_| encode_with_len(&"Hello World!")));

generate_main(call_info, call_info_len, template_impl)
}

extern "C" {
pub fn tari_engine(op: u32, input_ptr: *const u8, input_len: usize) -> *mut u8;
impl HelloWorld {
pub fn greet() -> String {
"Hello World!".to_string()
}
}
}
185 changes: 185 additions & 0 deletions dan_layer/engine/tests/macros/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions dan_layer/engine/tests/macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[workspace]
[package]
name = "tari_template_macros"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
proc-macro = true

[dependencies]
tari_template_abi = { path = "../../../template_abi" }
syn = { version = "1.0.98", features = ["full"] }
proc-macro2 = "1.0.42"
quote = "1.0.20"
Loading

0 comments on commit 594ca0e

Please sign in to comment.