LALRPOP parser for AIR (#13)

This commit is contained in:
folex 2020-11-03 17:43:58 +03:00 committed by GitHub
parent 12398697f2
commit 1786ab8f4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 3817 additions and 735 deletions

386
Cargo.lock generated
View File

@ -9,6 +9,18 @@ dependencies = [
"memchr",
]
[[package]]
name = "air-parser"
version = "0.1.0"
dependencies = [
"codespan",
"codespan-reporting",
"fstrings",
"lalrpop",
"lalrpop-util",
"regex",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
@ -20,9 +32,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
[[package]]
name = "aqua-test-module"
@ -80,6 +92,15 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "ascii-canvas"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8eb72df928aafb99fe5d37b383f2fe25bd2a765e3e5f7c365916b6f2463a29"
dependencies = [
"term",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -97,6 +118,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "bincode"
version = "1.3.1"
@ -107,12 +134,38 @@ dependencies = [
"serde",
]
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "blake3"
version = "0.3.7"
@ -128,6 +181,27 @@ dependencies = [
"digest 0.9.0",
]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array 0.12.3",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "boolinator"
version = "2.4.0"
@ -152,6 +226,12 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.3.4"
@ -212,10 +292,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475bd7aa7680b4ed8f6bb59745e882bcbaeb39326532bb79ffb1716480d9a274"
[[package]]
name = "const_fn"
version = "0.4.2"
name = "codespan"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2"
checksum = "8ebaf6bb6a863ad6aa3a18729e9710c53d75df03306714d9cc1f7357a00cd789"
dependencies = [
"codespan-reporting",
]
[[package]]
name = "codespan-reporting"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e0762455306b1ed42bc651ef6a2197aabda5e1d4a43c34d5eab5c1a3634e81d"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "const_fn"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab"
[[package]]
name = "constant_time_eq"
@ -326,7 +425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
"crossbeam-utils 0.8.0",
]
[[package]]
@ -337,7 +436,7 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
"crossbeam-utils 0.8.0",
]
[[package]]
@ -348,12 +447,23 @@ checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f"
dependencies = [
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils",
"crossbeam-utils 0.8.0",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"cfg-if 0.1.10",
"lazy_static",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.0"
@ -408,6 +518,12 @@ dependencies = [
"syn",
]
[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]]
name = "difference"
version = "2.0.0"
@ -432,12 +548,44 @@ dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "docopt"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969"
dependencies = [
"lazy_static",
"regex",
"serde",
"strsim",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@ -481,6 +629,12 @@ dependencies = [
"libc",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fce"
version = "0.1.9"
@ -523,6 +677,12 @@ dependencies = [
"wasmer-runtime-core-fl",
]
[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fluence"
version = "0.2.8"
@ -618,6 +778,28 @@ dependencies = [
"uuid",
]
[[package]]
name = "fstrings"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7845a0f15da505ac36baad0486612dab57f8b8d34e19c5470a265bbcdd572ae6"
dependencies = [
"fstrings-proc-macro",
"proc-macro-hack",
]
[[package]]
name = "fstrings-proc-macro"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b58c0e7581dc33478a32299182cbe5ae3b8c028be26728a47fb0a113c92d9d"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gcc"
version = "0.3.55"
@ -650,7 +832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check 0.9.2",
"version_check",
]
[[package]]
@ -806,6 +988,40 @@ dependencies = [
"serde_json",
]
[[package]]
name = "lalrpop"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60fb56191fb8ed5311597e5750debe6779c9fdb487dbaa5ff302592897d7a2c8"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"docopt",
"ena",
"itertools",
"lalrpop-util",
"petgraph",
"regex",
"regex-syntax",
"serde",
"serde_derive",
"sha2",
"string_cache",
"term",
"unicode-xid",
]
[[package]]
name = "lalrpop-util"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6771161eff561647fad8bb7e745e002c304864fb8f436b52b30acda51fca4408"
dependencies = [
"regex",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -901,6 +1117,12 @@ dependencies = [
"serde",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.15.0"
@ -914,16 +1136,6 @@ dependencies = [
"void",
]
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
dependencies = [
"memchr",
"version_check 0.1.5",
]
[[package]]
name = "nom"
version = "5.1.2"
@ -932,7 +1144,7 @@ checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"lexical-core",
"memchr",
"version_check 0.9.2",
"version_check",
]
[[package]]
@ -966,6 +1178,12 @@ version = "11.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "output_vt100"
version = "0.1.2"
@ -1015,6 +1233,25 @@ dependencies = [
"winapi",
]
[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "plotters"
version = "0.2.15"
@ -1029,9 +1266,15 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "pretty_assertions"
@ -1045,6 +1288,12 @@ dependencies = [
"output_vt100",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.24"
@ -1152,7 +1401,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"crossbeam-utils 0.8.0",
"lazy_static",
"num_cpus",
]
@ -1164,10 +1413,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
version = "1.4.1"
name = "redox_users"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom",
"redox_syscall",
"rust-argon2",
]
[[package]]
name = "regex"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
dependencies = [
"aho-corasick",
"memchr",
@ -1186,9 +1446,21 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.20"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c"
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
[[package]]
name = "rust-argon2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils 0.7.2",
]
[[package]]
name = "rustc_version"
@ -1303,15 +1575,23 @@ dependencies = [
]
[[package]]
name = "serde_sexpr"
version = "0.1.0"
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5318bfeed779c64075ce317c81462ed54dc00021be1c6b34957d798e11a68bdb"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"nom 4.2.3",
"serde",
"block-buffer",
"digest 0.8.1",
"fake-simd",
"opaque-debug",
]
[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7"
[[package]]
name = "smallvec"
version = "1.4.2"
@ -1328,6 +1608,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
name = "stepper-lib"
version = "0.1.2"
dependencies = [
"air-parser",
"aqua-test-utils",
"aquamarine-vm",
"boolinator",
@ -1342,10 +1623,28 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"serde_sexpr",
"wasm-bindgen",
]
[[package]]
name = "string_cache"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
]
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "2.3.0"
@ -1369,6 +1668,17 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
dependencies = [
"byteorder",
"dirs",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.0"
@ -1503,12 +1813,6 @@ dependencies = [
"rand",
]
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.2"
@ -1683,7 +1987,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de496e366bd1c198942248fc1de4b94e4647b263dd60099d5f7776f0d621656"
dependencies = [
"log",
"nom 5.1.2",
"nom",
"safe-transmute",
"serde",
"serde_json",

View File

@ -1,5 +1,6 @@
[workspace]
members = [
"crates/air-parser",
"crates/test-module",
"crates/test-utils",
"stepper",

Binary file not shown.

View File

@ -0,0 +1,17 @@
[package]
name = "air-parser"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
[build-dependencies]
lalrpop = { version = "0.19.1", features = ["lexer"] }
[dependencies]
lalrpop-util = { version = "0.19.1", features = ["lexer"] }
regex = "1.4.1"
codespan = "0.9.5"
codespan-reporting = "0.9.5"
[dev-dependencies]
fstrings = "0.2.3"

View File

@ -0,0 +1,24 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* 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.
*/
extern crate lalrpop;
fn main() {
lalrpop::Configuration::new()
.generate_in_source_tree()
.process()
.unwrap();
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* 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.
*/
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)]
pub enum Instruction<'i> {
Null(Null),
Call(Call<'i>),
Seq(Seq<'i>),
Par(Par<'i>),
Xor(Xor<'i>),
Fold(Fold<'i>),
Next(Next<'i>),
Error,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PeerPart<'i> {
PeerPk(Value<'i>),
PeerPkWithServiceId(Value<'i>, Value<'i>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum FunctionPart<'i> {
FuncName(Value<'i>),
ServiceIdWithFuncName(Value<'i>, Value<'i>),
}
#[derive(Debug, PartialEq, Eq)]
pub struct Call<'i> {
pub peer_part: PeerPart<'i>,
pub function_part: FunctionPart<'i>,
pub args: Vec<Value<'i>>,
pub output: CallOutput<'i>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Value<'i> {
Variable(&'i str),
Literal(&'i str),
JsonPath { variable: &'i str, path: &'i str },
CurrentPeerId,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum CallOutput<'i> {
Scalar(&'i str),
Accumulator(&'i str),
}
impl<'i> CallOutput<'i> {
pub fn name(&self) -> &'i str {
use CallOutput::*;
match self {
Scalar(name) | Accumulator(name) => name,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Seq<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
#[derive(Debug, PartialEq, Eq)]
pub struct Par<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
#[derive(Debug, PartialEq, Eq)]
pub struct Xor<'i>(pub Box<Instruction<'i>>, pub Box<Instruction<'i>>);
#[derive(Debug, PartialEq, Eq)]
pub struct Fold<'i> {
pub iterable: &'i str,
pub iterator: &'i str,
pub instruction: Rc<Instruction<'i>>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Next<'i>(pub &'i str);
#[derive(Debug, PartialEq, Eq)]
pub struct Null;

View File

@ -0,0 +1,90 @@
use crate::ast::*;
use crate::lalrpop::parser::InstructionError;
use lalrpop_util::ErrorRecovery;
use std::rc::Rc;
grammar<'err>(errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, InstructionError>>);
extern {
type Error = InstructionError;
}
pub Instr: Box<Instruction<'input>> = {
"(" "seq" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Seq(Seq(l, r))),
"(" "par" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Par(Par(l, r))),
"(" "xor" <l:Instr> <r:Instr> ")" => Box::new(Instruction::Xor(Xor(l, r))),
"(" "call" <peer:PeerPart> <f:FPart> <args:Args> <output:Output> ")" =>
Box::new(Instruction::Call(Call{peer, f, args, output})),
"(" "fold" <iterable:Alphanumeric> <iterator:Alphanumeric> <i:Instr> ")" => {
let instruction = Rc::new(*i);
Box::new(Instruction::Fold(Fold{ iterable, iterator, instruction }))
},
"(" "next" <i:Alphanumeric> ")" => Box::new(Instruction::Next(Next(i))),
"(" "null" ")" => Box::new(Instruction::Null(Null)),
! => { errors.push(<>); Box::new(Instruction::Error) },
}
Args: Vec<Value<'input>> = {
"[" <args:(<Arg>)*> "]" => args
}
FPart: FunctionPart<'input> = {
<f:Function> => FunctionPart::FuncName(f),
"(" <sid:ServiceId> <f:Function> ")" => FunctionPart::ServiceIdWithFuncName(sid, f),
}
PeerPart: PeerPart<'input> = {
<pid:PeerId> => PeerPart::PeerPk(pid),
"(" <pid:PeerId> <sid:ServiceId> ")" => PeerPart::PeerPkWithServiceId(pid, sid),
}
// TODO: make output one of _ () "" and absence
Output: CallOutput<'input> = {
<o:Alphanumeric> => CallOutput::Scalar(o),
<o:ACCUMULATOR> => CallOutput::Accumulator(&o[..o.len()-2]),
};
Function = Value;
PeerId = Value;
ServiceId = Value;
Arg = Value;
Value: Value<'input> = {
"\"" "\"" => Value::Literal(""), // TODO: signal absence somehow?
"\"" <v: Alphanumeric> "\"" => Value::Literal(v),
<v:Alphanumeric> => Value::Variable(v),
<v:JSON_PATH> => {
let mut path = v.splitn(2, ".");
let variable = path.next().expect("must contain dot");
let path = path.next().expect("contain component after dot");
Value::JsonPath { variable, path }
},
CURRENT_PEER_ID => Value::CurrentPeerId,
}
Alphanumeric = ALPHANUMERIC;
match {
r"[\w_-]+" => ALPHANUMERIC,
r"[\w_-]+\[\]" => ACCUMULATOR,
r"[\w_-]+\.\$[^ ]+" => JSON_PATH,
"%current_peer_id%" => CURRENT_PEER_ID,
"seq",
"call",
"null",
"par",
"xor",
"fold",
"next",
} else {
_
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,119 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* 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.
*/
use super::aqua;
use crate::ast::Instruction;
use crate::lalrpop::aqua::Token;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{Buffer, ColorChoice, StandardStream};
use lalrpop_util::{ErrorRecovery, ParseError};
use std::fmt::Formatter;
#[derive(Debug)]
/// Represents custom parsing errors. Isn't used yet.
pub enum InstructionError {
#[allow(dead_code)]
InvalidPeerId,
}
impl std::error::Error for InstructionError {}
impl std::fmt::Display for InstructionError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "InstructionError")
}
}
// Caching parser to cache internal regexes, which are expensive to instantiate
// See also https://github.com/lalrpop/lalrpop/issues/269
thread_local!(static PARSER: aqua::InstrParser = aqua::InstrParser::new());
/// Parse AIR `source_code` to `Box<Instruction>`
pub fn parse(source_code: &str) -> Result<Box<Instruction>, String> {
let mut files = SimpleFiles::new();
let file_id = files.add("script.aqua", source_code);
PARSER.with(|parser| {
let mut errors = Vec::new();
match parser.parse(&mut errors, source_code) {
Ok(r) if errors.is_empty() => Ok(r),
Ok(_) => Err(report_errors(file_id, files, errors)),
Err(err) => Err(report_errors(
file_id,
files,
vec![ErrorRecovery {
error: err,
dropped_tokens: vec![],
}],
)),
}
})
}
fn report_errors(
file_id: usize,
files: SimpleFiles<&str, &str>,
errors: Vec<ErrorRecovery<usize, Token, InstructionError>>,
) -> String {
let labels: Vec<Label<usize>> = errors
.into_iter()
.map(|err| match err.error {
ParseError::UnrecognizedToken {
token: (start, _, end),
expected,
} => Label::primary(file_id, start..end)
.with_message(format!("expected {}", pretty_expected(expected))),
ParseError::InvalidToken { location } => {
Label::primary(file_id, location..(location + 1)).with_message("unexpected token")
}
ParseError::ExtraToken {
token: (start, _, end),
} => Label::primary(file_id, start..end).with_message("extra token"),
ParseError::UnrecognizedEOF { location, expected } => {
Label::primary(file_id, location..(location + 1))
.with_message(format!("expected {}", pretty_expected(expected)))
}
// TODO: capture start & end in user error; maybe return it as a separate Diagnostic::error?
ParseError::User { error } => {
Label::primary(file_id, 0..0).with_message(error.to_string())
}
})
.collect();
let diagnostic = Diagnostic::error().with_labels(labels);
let config = codespan_reporting::term::Config::default();
// Write to stderr
let writer = StandardStream::stderr(ColorChoice::Auto);
term::emit(&mut writer.lock(), &config, &files, &diagnostic).expect("term emit to stderr");
// Return as a string
let mut buffer = Buffer::no_color();
term::emit(&mut buffer, &config, &files, &diagnostic).expect("term emit to buffer");
String::from_utf8_lossy(buffer.as_slice())
.as_ref()
.to_string()
}
fn pretty_expected(expected: Vec<String>) -> String {
if expected.is_empty() {
"<nothing>".to_string()
} else {
expected.join(" or ")
}
}

View File

@ -0,0 +1,364 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* 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.
*/
use crate::ast::*;
use CallOutput::*;
use FunctionPart::*;
use PeerPart::*;
use Value::*;
use fstrings::f;
fn parse(source_code: &str) -> Instruction {
*super::parse(source_code).expect("parsing failed")
}
#[test]
fn parse_seq() {
let source_code = r#"
(seq
(call peerid function [] void)
(call "id" "f" ["hello" name] void[])
)
"#;
let instruction = parse(source_code);
let expected = seq(
Instruction::Call(Call {
peer_part: PeerPk(Variable("peerid")),
function_part: FuncName(Variable("function")),
args: vec![],
output: Scalar("void"),
}),
Instruction::Call(Call {
peer_part: PeerPk(Literal("id")),
function_part: FuncName(Literal("f")),
args: vec![Literal("hello"), Variable("name")],
output: Accumulator("void"),
}),
);
assert_eq!(instruction, expected);
}
#[test]
fn parse_seq_seq() {
let source_code = r#"
(seq
(seq
(call peerid function [] void)
(call (peerid serviceA) ("serviceB" function) [] void)
)
(call "id" "f" ["hello" name] void[])
)
"#;
let instruction = parse(source_code);
let expected = seq(
seq(
Instruction::Call(Call {
peer_part: PeerPk(Variable("peerid")),
function_part: FuncName(Variable("function")),
args: vec![],
output: Scalar("void"),
}),
Instruction::Call(Call {
peer_part: PeerPkWithServiceId(Variable("peerid"), Variable("serviceA")),
function_part: ServiceIdWithFuncName(Literal("serviceB"), Variable("function")),
args: vec![],
output: Scalar("void"),
}),
),
Instruction::Call(Call {
peer_part: PeerPk(Literal("id")),
function_part: FuncName(Literal("f")),
args: vec![Literal("hello"), Variable("name")],
output: Accumulator("void"),
}),
);
assert_eq!(instruction, expected);
}
#[test]
fn parse_json_path() {
let source_code = r#"
(call id.$.a "f" ["hello" name] void[])
"#;
let instruction = parse(source_code);
let expected = Instruction::Call(Call {
peer_part: PeerPk(JsonPath {
variable: "id",
path: "$.a",
}),
function_part: FuncName(Literal("f")),
args: vec![Literal("hello"), Variable("name")],
output: Accumulator("void"),
});
assert_eq!(instruction, expected);
}
#[test]
fn parse_json_path_complex() {
let source_code = r#"
(seq
(call m.$.[1] "f" [] void)
(call m.$.abc.cde[a][0].cde "f" [] void)
)
"#;
let instruction = parse(source_code);
let expected = seq(
Instruction::Call(Call {
peer_part: PeerPk(JsonPath {
variable: "m",
path: "$.[1]",
}),
function_part: FuncName(Literal("f")),
args: vec![],
output: Scalar("void"),
}),
Instruction::Call(Call {
peer_part: PeerPk(JsonPath {
variable: "m",
path: "$.abc.cde[a][0].cde",
}),
function_part: FuncName(Literal("f")),
args: vec![],
output: Scalar("void"),
}),
);
assert_eq!(instruction, expected);
}
#[test]
fn parse_null() {
let source_code = r#"
(seq
(null)
( null )
)
"#;
let instruction = parse(source_code);
let expected = Instruction::Seq(Seq(Box::new(null()), Box::new(null())));
assert_eq!(instruction, expected)
}
fn source_seq_with(name: &'static str) -> String {
f!(r#"
(seq
({name}
(seq (null) (null))
(null)
)
({name} (null) (seq (null) (null)) )
)
"#)
}
#[test]
fn parse_seq_par_xor_seq() {
for name in &["xor", "par", "seq"] {
let source_code = source_seq_with(name);
let instruction = parse(&source_code.as_ref());
let instr = binary_instruction(*name);
let expected = seq(instr(seqnn(), null()), instr(null(), seqnn()));
assert_eq!(instruction, expected);
}
}
#[test]
fn parse_fold() {
let source_code = r#"
(fold iterable i
(null)
)
"#;
let instruction = parse(&source_code.as_ref());
let expected = fold("iterable", "i", null());
assert_eq!(instruction, expected);
}
fn source_fold_with(name: &str) -> String {
f!(r#"(fold iterable i
({name} (null) (null))
)"#)
}
#[test]
fn parse_fold_with_xor_par_seq() {
for name in &["xor", "par", "seq"] {
let source_code = source_fold_with(name);
let instruction = parse(&source_code.as_ref());
let instr = binary_instruction(*name);
let expected = fold("iterable", "i", instr(null(), null()));
assert_eq!(instruction, expected);
}
}
#[test]
fn seq_par_call() {
let source_code = r#"
(seq
(par
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_2)
)"#;
let instruction = parse(&source_code.as_ref());
let expected = seq(
par(
Instruction::Call(Call {
peer_part: PeerPk(CurrentPeerId),
function_part: ServiceIdWithFuncName(
Literal("local_service_id"),
Literal("local_fn_name"),
),
args: vec![],
output: Scalar("result_1"),
}),
Instruction::Call(Call {
peer_part: PeerPk(Literal("remote_peer_id")),
function_part: ServiceIdWithFuncName(Literal("service_id"), Literal("fn_name")),
args: vec![],
output: Scalar("g"),
}),
),
Instruction::Call(Call {
peer_part: PeerPk(CurrentPeerId),
function_part: ServiceIdWithFuncName(
Literal("local_service_id"),
Literal("local_fn_name"),
),
args: vec![],
output: Scalar("result_2"),
}),
);
assert_eq!(instruction, expected);
}
#[test]
fn seq_with_empty_and_dash() {
let source_code = r#"
(seq
(seq
(seq
(call "set_variables" ("" "") ["module-bytes"] module-bytes)
(call "set_variables" ("" "") ["module_config"] module_config)
)
(call "set_variables" ("" "") ["blueprint"] blueprint)
)
(seq
(call "A" ("add_module" "") [module-bytes module_config] module)
(seq
(call "A" ("add_blueprint" "") [blueprint] blueprint_id)
(seq
(call "A" ("create" "") [blueprint_id] service_id)
(call "remote_peer_id" ("" "") [service_id] client_result)
)
)
)
)
"#;
let instruction = parse(&source_code.as_ref());
let expected = seq(
seq(
seq(
Instruction::Call(Call {
peer_part: PeerPk(Literal("set_variables")),
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
args: vec![Literal("module-bytes")],
output: Scalar("module-bytes"),
}),
Instruction::Call(Call {
peer_part: PeerPk(Literal("set_variables")),
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
args: vec![Literal("module_config")],
output: Scalar("module_config"),
}),
),
Instruction::Call(Call {
peer_part: PeerPk(Literal("set_variables")),
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
args: vec![Literal("blueprint")],
output: Scalar("blueprint"),
}),
),
seq(
Instruction::Call(Call {
peer_part: PeerPk(Literal("A")),
function_part: ServiceIdWithFuncName(Literal("add_module"), Literal("")),
args: vec![Variable("module-bytes"), Variable("module_config")],
output: Scalar("module"),
}),
seq(
Instruction::Call(Call {
peer_part: PeerPk(Literal("A")),
function_part: ServiceIdWithFuncName(Literal("add_blueprint"), Literal("")),
args: vec![Variable("blueprint")],
output: Scalar("blueprint_id"),
}),
seq(
Instruction::Call(Call {
peer_part: PeerPk(Literal("A")),
function_part: ServiceIdWithFuncName(Literal("create"), Literal("")),
args: vec![Variable("blueprint_id")],
output: Scalar("service_id"),
}),
Instruction::Call(Call {
peer_part: PeerPk(Literal("remote_peer_id")),
function_part: ServiceIdWithFuncName(Literal(""), Literal("")),
args: vec![Variable("service_id")],
output: Scalar("client_result"),
}),
),
),
),
);
assert_eq!(instruction, expected);
}
// Test DSL
fn seq<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
Instruction::Seq(Seq(Box::new(l), Box::new(r)))
}
fn par<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
Instruction::Par(Par(Box::new(l), Box::new(r)))
}
fn xor<'a>(l: Instruction<'a>, r: Instruction<'a>) -> Instruction<'a> {
Instruction::Xor(Xor(Box::new(l), Box::new(r)))
}
fn seqnn() -> Instruction<'static> {
seq(null(), null())
}
fn null() -> Instruction<'static> {
Instruction::Null(Null)
}
fn fold<'a>(iterable: &'a str, iterator: &'a str, instruction: Instruction<'a>) -> Instruction<'a> {
Instruction::Fold(Fold {
iterable,
iterator,
instruction: std::rc::Rc::new(instruction),
})
}
fn binary_instruction<'a, 'b>(
name: &'a str,
) -> impl Fn(Instruction<'b>, Instruction<'b>) -> Instruction<'b> {
match name {
"xor" => |l, r| xor(l, r),
"par" => |l, r| par(l, r),
"seq" => |l, r| seq(l, r),
_ => unreachable!(),
}
}

View File

@ -0,0 +1,20 @@
#![deny(unused_imports, unused_variables, dead_code)]
#[cfg(test)]
#[macro_use]
extern crate fstrings;
pub mod ast;
mod lalrpop {
#[cfg(test)]
mod tests;
// aqua is auto-generated, so exclude it from `cargo fmt -- --check`
#[rustfmt::skip]
mod aqua;
mod parser;
pub use parser::parse;
}
pub use lalrpop::parse;

View File

@ -147,7 +147,9 @@ pub fn set_variables_call_service(ret_mapping: HashMap<String, String>) -> HostE
#[macro_export]
macro_rules! call_vm {
($vm:expr, $init_user_id:expr, $script:expr, $prev_data:expr, $data:expr) => {
$vm.call_with_prev_data($init_user_id, $script, $prev_data, $data)
.expect("call should be successful");
match $vm.call_with_prev_data($init_user_id, $script, $prev_data, $data) {
Ok(v) => v,
Err(err) => panic!("VM call failed: {}", err),
}
};
}

View File

@ -9,11 +9,11 @@ name = "stepper_lib"
path = "src/lib.rs"
[dependencies]
air-parser = { path = "../crates/air-parser" }
fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] }
serde = { version = "1.0.116", features = [ "derive", "rc" ] }
serde_derive = "1.0.116"
serde_sexpr = "0.1.0"
jsonpath_lib = "0.2.5"

View File

@ -13,7 +13,7 @@ use std::cell::RefCell;
thread_local!(static VM: RefCell<AquamarineVM> = RefCell::new(create_aqua_vm(unit_call_service(), "test_peer_id")));
thread_local!(static SCRIPT: String = String::from(
r#"
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_name))
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_name)
"#,
)
);

View File

@ -34,24 +34,24 @@ thread_local!(static CLIENT_2_VM: RefCell<AquamarineVM> = RefCell::new(create_aq
fn chat_sent_message_benchmark() -> Result<StepperOutcome, AquamarineVMError> {
let script = String::from(
r#"
(seq (
(call ("Relay1" ("identity" "") () void1[]))
(seq (
(call ("Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") () void2[]))
(seq (
(call ("Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") () members))
(fold (members m
(par (
(seq (
(call (m.$.[1] ("identity" "") () void[]))
(call (m.$.[0] ("fgemb3" "add") () void3[]))
))
(seq
(call "Relay1" ("identity" "") [] void1[])
(seq
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] void2[])
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call m.$.[1] ("identity" "") [] void[])
(call m.$.[0] ("fgemb3" "add") [] void3[])
)
(next m)
))
))
))
))
))
)
)
)
)
)
"#,
);

View File

@ -71,25 +71,25 @@ thread_local!(static SET_VARIABLES_VM: RefCell<AquamarineVM> = RefCell::new({
fn create_service_benchmark() -> Result<StepperOutcome, AquamarineVMError> {
let script = String::from(
r#"
(seq (
(seq (
(seq (
(call ("set_variables" ("" "") ("module_bytes") module_bytes))
(call ("set_variables" ("" "") ("module_config") module_config))
))
(call ("set_variables" ("" "") ("blueprint") blueprint))
))
(seq (
(call ("A" ("add_module" "") (module_bytes module_config) module))
(seq (
(call ("A" ("add_blueprint" "") (blueprint) blueprint_id))
(seq (
(call ("A" ("create" "") (blueprint_id) service_id))
(call ("remote_peer_id" ("" "") (service_id) client_result))
))
))
))
))"#,
(seq
(seq
(seq
(call "set_variables" ("" "") ["module_bytes"] module_bytes)
(call "set_variables" ("" "") ["module_config"] module_config)
)
(call "set_variables" ("" "") ["blueprint"] blueprint)
)
(seq
(call "A" ("add_module" "") [module_bytes module_config] module)
(seq
(call "A" ("add_blueprint" "") [blueprint] blueprint_id)
(seq
(call "A" ("create" "") [blueprint_id] service_id)
(call "remote_peer_id" ("" "") [service_id] client_result)
)
)
)
)"#,
);
let res = SET_VARIABLES_VM

View File

@ -15,6 +15,7 @@
*/
mod parsed_call;
mod triplet;
mod utils;
use parsed_call::ParsedCall;
@ -26,10 +27,7 @@ use crate::AquamarineError::VariableNotFound;
use crate::AquamarineError::VariableNotInJsonPath;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
const CURRENT_PEER_ALIAS: &str = "%current_peer_id%";
use air_parser::ast::Call;
/*
(current)
@ -42,25 +40,8 @@ const CURRENT_PEER_ALIAS: &str = "%current_peer_id%";
FN_PART: resolves to (fn_name) \/ (fn_srv_id, fn_name)
*/
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)]
pub(self) enum PeerPart {
PeerPk(String),
PeerPkWithServiceId(String, String),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)]
pub(self) enum FunctionPart {
FuncName(String),
ServiceIdWithFuncName(String, String),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Call(PeerPart, FunctionPart, Vec<String>, String);
impl super::ExecutableInstruction for Call {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Call<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
log_instruction!(call, exec_ctx, call_ctx);
let parsed_call = match ParsedCall::new(self, exec_ctx) {
@ -113,7 +94,7 @@ mod tests {
let script = String::from(
r#"
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_name))
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_name)
"#,
);
@ -129,7 +110,7 @@ mod tests {
let script = String::from(
r#"
(call ("test_peer_id" ("local_service_id" "local_fn_name") () result_name))
(call "test_peer_id" ("local_service_id" "local_fn_name") [] result_name)
"#,
);
@ -154,7 +135,7 @@ mod tests {
let remote_peer_id = String::from("some_remote_peer_id");
let script = format!(
r#"(call ("{}" ("local_service_id" "local_fn_name") (value) result_name))"#,
r#"(call "{}" ("local_service_id" "local_fn_name") [value] result_name)"#,
remote_peer_id
);
@ -173,10 +154,10 @@ mod tests {
let script = format!(
r#"
(seq (
(call ("set_variable" ("some_service_id" "local_fn_name") () remote_peer_id))
(call (remote_peer_id ("some_service_id" "local_fn_name") () result_name))
))
(seq
(call "set_variable" ("some_service_id" "local_fn_name") [] remote_peer_id)
(call remote_peer_id ("some_service_id" "local_fn_name") [] result_name)
)
"#,
);
@ -207,10 +188,10 @@ mod tests {
let script = String::from(
r#"
(seq (
(call ("set_variable" ("some_service_id" "local_fn_name") () arg3))
(call ("A" ("some_service_id" "local_fn_name") ("arg1" "arg2" arg3) result))
))
(seq
(call "set_variable" ("some_service_id" "local_fn_name") [] arg3)
(call "A" ("some_service_id" "local_fn_name") ["arg1" "arg2" arg3] result)
)
"#,
);

View File

@ -16,63 +16,62 @@
#![allow(unused_unsafe)] // for wasm_bindgen target where calling FFI is safe
use super::utils::find_by_json_path;
use super::utils::is_string_literal;
use super::utils::set_local_call_result;
use super::triplet::{ResolvedTriplet, Triplet};
use super::utils::{resolve_jvalue, set_local_call_result, set_remote_call_result};
use super::Call;
use super::CURRENT_PEER_ALIAS;
use crate::air::ExecutionCtx;
use crate::build_targets::CALL_SERVICE_SUCCESS;
use crate::call_evidence::CallEvidenceCtx;
use crate::call_evidence::CallResult;
use crate::call_evidence::EvidenceState;
use crate::call_evidence::{CallEvidenceCtx, CallResult, EvidenceState};
use crate::log_targets::EVIDENCE_CHANGING;
use crate::AValue;
use crate::AquamarineError;
use crate::JValue;
use crate::Result;
use std::borrow::Cow;
use air_parser::ast::{CallOutput, Value};
use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)]
pub(super) struct ParsedCall {
pub(super) struct ParsedCall<'i> {
peer_pk: String,
service_id: String,
function_name: String,
function_arg_paths: Vec<String>,
result_variable_name: String,
function_arg_paths: Vec<Value<'i>>,
output: CallOutput<'i>,
}
impl ParsedCall {
pub(super) fn new(raw_call: &Call, exec_ctx: &ExecutionCtx) -> Result<Self> {
let (peer_pk, service_id, function_name) = prepare_peer_fn_parts(raw_call, exec_ctx)?;
let result_variable_name = parse_result_variable_name(raw_call)?;
impl<'i> ParsedCall<'i> {
/// Builds `ParsedCall` from `Call` by transforming `PeerPart` & `FunctionPart` into `ResolvedTriplet`
pub(super) fn new(raw_call: &Call<'i>, exec_ctx: &ExecutionCtx<'i>) -> Result<Self> {
let triplet = Triplet::try_from(&raw_call.peer_part, &raw_call.function_part)?;
#[rustfmt::skip]
let ResolvedTriplet { peer_pk, service_id, function_name } = triplet.resolve(exec_ctx)?;
Ok(Self {
peer_pk,
service_id,
function_name,
function_arg_paths: raw_call.2.clone(),
result_variable_name: result_variable_name.to_string(),
function_arg_paths: raw_call.args.clone(),
output: raw_call.output.clone(),
})
}
pub(super) fn execute(self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
let should_executed = self.prepare_evidence_state(exec_ctx, call_ctx)?;
if !should_executed {
pub(super) fn execute(self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
let should_execute = self.prepare_evidence_state(exec_ctx, call_ctx)?;
if !should_execute {
return Ok(());
}
if self.peer_pk != exec_ctx.current_peer_id && self.peer_pk != CURRENT_PEER_ALIAS {
super::utils::set_remote_call_result(self.peer_pk, exec_ctx, call_ctx);
if self.peer_pk != exec_ctx.current_peer_id {
set_remote_call_result(self.peer_pk, exec_ctx, call_ctx);
return Ok(());
}
let function_args = extract_args_by_paths(&self.function_arg_paths, exec_ctx)?;
let function_args = serde_json::to_string(&function_args)
.map_err(|e| AquamarineError::FuncArgsSerializationError(function_args, e))?;
let function_args = self.function_arg_paths.iter();
let function_args: Result<Vec<_>> = function_args.map(|v| resolve_jvalue(v, exec_ctx)).collect();
let function_args = JValue::Array(function_args?).to_string();
let result = unsafe { crate::call_service(self.service_id, self.function_name, function_args) };
@ -88,7 +87,7 @@ impl ParsedCall {
let result: JValue = serde_json::from_str(&result.result)
.map_err(|e| AquamarineError::CallServiceResultDeserializationError(result, e))?;
let result = Rc::new(result);
super::utils::set_local_call_result(self.result_variable_name, exec_ctx, result.clone())?;
set_local_call_result(self.output, exec_ctx, result.clone())?;
let new_evidence_state = EvidenceState::Call(CallResult::Executed(result));
log::info!(
@ -103,7 +102,7 @@ impl ParsedCall {
pub(super) fn prepare_evidence_state(
&self,
exec_ctx: &mut ExecutionCtx,
exec_ctx: &mut ExecutionCtx<'i>,
call_ctx: &mut CallEvidenceCtx,
) -> Result<bool> {
use crate::call_evidence::CallResult::*;
@ -147,7 +146,7 @@ impl ParsedCall {
}
// this instruction's been already executed
Call(Executed(result)) => {
set_local_call_result(self.result_variable_name.clone(), exec_ctx, result.clone())?;
set_local_call_result(self.output.clone(), exec_ctx, result.clone())?;
call_ctx.new_path.push_back(prev_state);
Ok(false)
}
@ -159,132 +158,3 @@ impl ParsedCall {
}
}
}
fn prepare_peer_fn_parts<'a>(raw_call: &'a Call, exec_ctx: &'a ExecutionCtx) -> Result<(String, String, String)> {
use super::FunctionPart::*;
use super::PeerPart::*;
let (peer_pk, service_id, func_name) = match (&raw_call.0, &raw_call.1) {
(PeerPkWithServiceId(peer_pk, peer_service_id), ServiceIdWithFuncName(_service_id, func_name)) => {
Ok((peer_pk, peer_service_id, func_name))
}
(PeerPkWithServiceId(peer_pk, peer_service_id), FuncName(func_name)) => {
Ok((peer_pk, peer_service_id, func_name))
}
(PeerPk(peer_pk), ServiceIdWithFuncName(service_id, func_name)) => Ok((peer_pk, service_id, func_name)),
(PeerPk(_), FuncName(_)) => Err(AquamarineError::InstructionError(String::from(
"call should have service id specified by peer part or function part",
))),
}?;
let peer_pk = if peer_pk != CURRENT_PEER_ALIAS {
prepare_call_arg(peer_pk, exec_ctx)?
} else {
peer_pk.to_string()
};
let service_id = prepare_call_arg(service_id, exec_ctx)?;
let func_name = prepare_call_arg(func_name, exec_ctx)?;
Ok((peer_pk, service_id, func_name))
}
fn extract_args_by_paths(function_arg_paths: &[String], ctx: &ExecutionCtx) -> Result<JValue> {
let mut result = Vec::with_capacity(function_arg_paths.len());
let owned_maybe_json_path = |jvalue: Cow<'_, JValue>, json_path: Option<&str>| -> Result<Vec<JValue>> {
if json_path.is_none() {
return Ok(vec![jvalue.into_owned()]);
}
let json_path = json_path.unwrap();
let values = find_by_json_path(jvalue.as_ref(), json_path)?;
Ok(values.into_iter().cloned().collect())
};
for arg_path in function_arg_paths.iter() {
if is_string_literal(arg_path) {
result.push(JValue::String(arg_path[1..arg_path.len() - 1].to_string()));
} else {
let arg = get_args_by_path(arg_path, ctx, owned_maybe_json_path)?;
result.extend(arg);
}
}
Ok(JValue::Array(result))
}
fn parse_result_variable_name(call: &Call) -> Result<&str> {
let result_variable_name = &call.3;
if result_variable_name.is_empty() {
return Err(AquamarineError::InstructionError(String::from(
"result name of a call instruction must be non empty",
)));
}
if is_string_literal(result_variable_name) {
return Err(AquamarineError::InstructionError(String::from(
"result name of a call instruction must be non string literal",
)));
}
Ok(result_variable_name)
}
fn get_args_by_path<'args_path, 'exec_ctx, T: 'exec_ctx>(
args_path: &'args_path str,
ctx: &'exec_ctx ExecutionCtx,
maybe_json_path: impl FnOnce(Cow<'exec_ctx, JValue>, Option<&str>) -> Result<T>,
) -> Result<T> {
let mut split_arg: Vec<&str> = args_path.splitn(2, '.').collect();
let arg_path_head = split_arg.remove(0);
match ctx.data_cache.get(arg_path_head) {
Some(AValue::JValueFoldCursor(fold_state)) => match fold_state.iterable.as_ref() {
JValue::Array(array) => {
let jvalue = &array[fold_state.cursor];
maybe_json_path(Cow::Borrowed(jvalue), split_arg.pop())
}
_ => unreachable!("fold state must be well-formed because it is changed only by stepper"),
},
Some(AValue::JValueRef(value)) => maybe_json_path(Cow::Borrowed(value.as_ref()), split_arg.pop()),
Some(AValue::JValueAccumulatorRef(acc)) => {
let owned_acc = acc.borrow().iter().map(|v| v.as_ref()).cloned().collect::<Vec<_>>();
let jvalue = JValue::Array(owned_acc);
maybe_json_path(Cow::Owned(jvalue), split_arg.pop())
}
None => Err(AquamarineError::VariableNotFound(arg_path_head.to_string())),
}
}
// Prepare arguments of call
fn prepare_call_arg<'a>(arg_path: &'a str, ctx: &'a ExecutionCtx) -> Result<String> {
fn borrowed_maybe_json_path(jvalue: Cow<'_, JValue>, json_path: Option<&str>) -> Result<JValue> {
if json_path.is_none() {
return Ok(jvalue.into_owned());
}
let json_path = json_path.unwrap();
let values = find_by_json_path(jvalue.as_ref(), json_path)?;
if values.is_empty() {
return Err(AquamarineError::VariableNotFound(json_path.to_string()));
}
if values.len() != 1 {
return Err(AquamarineError::MultipleValuesInJsonPath(json_path.to_string()));
}
Ok(values[0].clone())
}
if is_string_literal(arg_path) {
return Ok(arg_path[1..arg_path.len() - 1].to_string());
}
let arg = get_args_by_path(arg_path, ctx, borrowed_maybe_json_path)?;
match arg {
JValue::String(str) => Ok(str),
v => Err(AquamarineError::IncompatibleJValueType(v, String::from("string"))),
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* 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.
*/
use super::utils::resolve_value;
use crate::air::ExecutionCtx;
use crate::{AquamarineError, Result};
use air_parser::ast::{FunctionPart, PeerPart, Value};
/// Triplet represents a location of the executable code in the network
/// It is build from `PeerPart` and `FunctionPart` of a `Call` instruction
pub(super) struct Triplet<'a, 'i> {
pub(super) peer_pk: &'a Value<'i>,
pub(super) service_id: &'a Value<'i>,
pub(super) function_name: &'a Value<'i>,
}
/// ResolvedTriplet represents same location as `Triplet`, but with all
/// variables, literals and etc resolved into final `String`
pub(super) struct ResolvedTriplet {
pub(super) peer_pk: String,
pub(super) service_id: String,
pub(super) function_name: String,
}
impl<'a, 'i> Triplet<'a, 'i> {
/// Build a `Triplet` from `Call`'s `PeerPart` and `FunctionPart`
pub fn try_from(peer: &'a PeerPart<'i>, f: &'a FunctionPart<'i>) -> Result<Self> {
use air_parser::ast::FunctionPart::*;
use air_parser::ast::PeerPart::*;
let (peer_pk, service_id, function_name) = match (peer, f) {
(PeerPkWithServiceId(peer_pk, peer_service_id), ServiceIdWithFuncName(_service_id, func_name)) => {
Ok((peer_pk, peer_service_id, func_name))
}
(PeerPkWithServiceId(peer_pk, peer_service_id), FuncName(func_name)) => {
Ok((peer_pk, peer_service_id, func_name))
}
(PeerPk(peer_pk), ServiceIdWithFuncName(service_id, func_name)) => Ok((peer_pk, service_id, func_name)),
(PeerPk(_), FuncName(_)) => Err(AquamarineError::InstructionError(String::from(
"call should have service id specified by peer part or function part",
))),
}?;
Ok(Self {
peer_pk,
service_id,
function_name,
})
}
/// Resolve variables, literals, etc in the `Triplet`, and build a `ResolvedTriplet`
pub fn resolve(self, ctx: &'a ExecutionCtx<'i>) -> Result<ResolvedTriplet> {
let Triplet {
peer_pk,
service_id,
function_name,
} = self;
let peer_pk = resolve_value(peer_pk, ctx)?.as_ref().to_string();
let service_id = resolve_value(service_id, ctx)?.as_ref().to_string();
let function_name = resolve_value(function_name, ctx)?.as_ref().to_string();
Ok(ResolvedTriplet {
peer_pk,
service_id,
function_name,
})
}
}

View File

@ -24,43 +24,49 @@ use crate::AquamarineError;
use crate::JValue;
use crate::Result;
use std::cell::RefCell;
use std::rc::Rc;
use air_parser::ast::{CallOutput, Value};
pub(super) fn set_local_call_result(
result_variable_name: String,
exec_ctx: &mut ExecutionCtx,
use std::{borrow::Cow, cell::RefCell, rc::Rc};
/// Writes result of a local `Call` instruction to `ExecutionCtx` at `output`
pub(super) fn set_local_call_result<'i>(
output: CallOutput<'i>,
exec_ctx: &mut ExecutionCtx<'i>,
result: Rc<JValue>,
) -> Result<()> {
use std::collections::hash_map::Entry::{Occupied, Vacant};
use AquamarineError::*;
let stripped_result_name = result_variable_name.strip_suffix("[]");
if stripped_result_name.is_none() {
// if result is not an array, simply insert it into data
match exec_ctx.data_cache.entry(result_variable_name) {
Vacant(entry) => entry.insert(AValue::JValueRef(result)),
Occupied(entry) => return Err(MultipleVariablesFound(entry.key().clone())),
};
return Ok(());
}
// unwrap is safe because it's been checked for []
match exec_ctx.data_cache.entry(stripped_result_name.unwrap().to_string()) {
Occupied(mut entry) => match entry.get_mut() {
// if result is an array, insert result to the end of the array
AValue::JValueAccumulatorRef(values) => values.borrow_mut().push(result),
v => return Err(IncompatibleAValueType(format!("{:?}", v), String::from("Array"))),
},
Vacant(entry) => {
entry.insert(AValue::JValueAccumulatorRef(RefCell::new(vec![result])));
match output {
CallOutput::Scalar(name) => {
match exec_ctx.data_cache.entry(name.to_string()) {
Vacant(entry) => entry.insert(AValue::JValueRef(result)),
Occupied(entry) => return Err(MultipleVariablesFound(entry.key().clone())),
};
}
CallOutput::Accumulator(name) => {
match exec_ctx.data_cache.entry(name.to_string()) {
Occupied(mut entry) => match entry.get_mut() {
// if result is an array, insert result to the end of the array
AValue::JValueAccumulatorRef(values) => values.borrow_mut().push(result),
v => return Err(IncompatibleAValueType(format!("{:?}", v), String::from("Array"))),
},
Vacant(entry) => {
entry.insert(AValue::JValueAccumulatorRef(RefCell::new(vec![result])));
}
};
}
}
Ok(())
}
pub(super) fn set_remote_call_result(peer_pk: String, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) {
/// Writes evidence of a particle being sent to remote node
pub(super) fn set_remote_call_result<'i>(
peer_pk: String,
exec_ctx: &mut ExecutionCtx<'i>,
call_ctx: &mut CallEvidenceCtx,
) {
exec_ctx.next_peer_pks.push(peer_pk);
exec_ctx.subtree_complete = false;
@ -73,6 +79,7 @@ pub(super) fn set_remote_call_result(peer_pk: String, exec_ctx: &mut ExecutionCt
call_ctx.new_path.push_back(new_evidence_state);
}
/// Applies `json_path` to `jvalue`
pub(super) fn find_by_json_path<'jvalue, 'json_path>(
jvalue: &'jvalue JValue,
json_path: &'json_path str,
@ -82,6 +89,86 @@ pub(super) fn find_by_json_path<'jvalue, 'json_path>(
jsonpath_lib::select(jvalue, json_path).map_err(|e| JsonPathError(jvalue.clone(), String::from(json_path), e))
}
pub(super) fn is_string_literal(value: &str) -> bool {
value.starts_with('"') && value.ends_with('"')
/// Takes variable's value from `ExecutionCtx::data_cache`
/// TODO: maybe return &'i JValue?
pub(super) fn resolve_variable<'exec_ctx, 'i>(variable: &'i str, ctx: &'exec_ctx ExecutionCtx<'i>) -> Result<JValue> {
use AquamarineError::VariableNotFound;
let value = ctx
.data_cache
.get(variable)
.ok_or_else(|| VariableNotFound(variable.to_string()))?;
match value {
AValue::JValueFoldCursor(fold_state) => {
if let JValue::Array(array) = fold_state.iterable.as_ref() {
Ok(array[fold_state.cursor].clone())
} else {
unreachable!("fold state must be well-formed because it is changed only by stepper")
}
}
AValue::JValueRef(value) => Ok(value.as_ref().clone()),
AValue::JValueAccumulatorRef(acc) => {
let owned_acc = acc.borrow().iter().map(|v| v.as_ref()).cloned().collect::<Vec<_>>();
Ok(JValue::Array(owned_acc))
}
}
}
pub(super) fn apply_json_path<'i>(jvalue: JValue, json_path: &'i str) -> Result<JValue> {
let values = find_by_json_path(&jvalue, json_path)?;
if values.is_empty() {
return Err(AquamarineError::VariableNotFound(json_path.to_string()));
}
if values.len() != 1 {
return Err(AquamarineError::MultipleValuesInJsonPath(json_path.to_string()));
}
// TODO: sure need this clone?
Ok(values[0].clone())
}
pub(super) fn require_string(value: JValue) -> Result<String> {
if let JValue::String(s) = value {
Ok(s)
} else {
Err(AquamarineError::IncompatibleJValueType(value, "string".to_string()))
}
}
/// Resolve value to string by either resolving variable from `ExecutionCtx`, taking literal value, or etc
pub(super) fn resolve_value<'i, 'a: 'i>(value: &'a Value<'i>, ctx: &'a ExecutionCtx<'i>) -> Result<Cow<'i, str>> {
let resolved = match value {
Value::CurrentPeerId => Cow::Borrowed(ctx.current_peer_id.as_str()),
Value::Literal(value) => Cow::Borrowed(*value),
Value::Variable(name) => {
let resolved = resolve_variable(name, ctx)?;
let resolved = require_string(resolved)?;
Cow::Owned(resolved)
}
Value::JsonPath { variable, path } => {
let resolved = resolve_variable(variable, ctx)?;
let resolved = apply_json_path(resolved, path)?;
let resolved = require_string(resolved)?;
Cow::Owned(resolved)
}
};
Ok(resolved)
}
/// Resolve value to JValue, similar to `resolve_value`
pub(super) fn resolve_jvalue<'i>(value: &Value<'i>, ctx: &ExecutionCtx<'i>) -> Result<JValue> {
let value = match value {
Value::CurrentPeerId => JValue::String(ctx.current_peer_id.clone()),
Value::Literal(value) => JValue::String(value.to_string()),
Value::Variable(name) => resolve_variable(name, ctx)?,
Value::JsonPath { variable, path } => {
let value = resolve_variable(variable, ctx)?;
apply_json_path(value, path)?
}
};
Ok(value)
}

View File

@ -22,9 +22,9 @@ use std::fmt::Formatter;
/// Execution context contains all necessary information needed to execute aqua script.
#[derive(Clone, Default, Debug)]
pub(crate) struct ExecutionCtx {
pub(crate) struct ExecutionCtx<'i> {
/// Contains all set variables.
pub data_cache: HashMap<String, AValue>,
pub data_cache: HashMap<String, AValue<'i>>,
/// Set of peer public keys that should receive resulted data.
pub next_peer_pks: Vec<String>,
@ -41,7 +41,7 @@ pub(crate) struct ExecutionCtx {
pub subtree_complete: bool,
}
impl ExecutionCtx {
impl<'i> ExecutionCtx<'i> {
pub(crate) fn new(current_peer_id: String) -> Self {
Self {
data_cache: HashMap::new(),
@ -52,7 +52,7 @@ impl ExecutionCtx {
}
}
impl Display for ExecutionCtx {
impl<'i> Display for ExecutionCtx<'i> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "data cache:")?;
for (key, value) in self.data_cache.iter() {

View File

@ -23,8 +23,8 @@ use crate::AquamarineError;
use crate::JValue;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::{Fold, Next};
use std::rc::Rc;
/*
@ -36,32 +36,22 @@ use std::rc::Rc;
)
*/
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Fold(String, String, Rc<Instruction>);
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Next(String);
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct FoldState {
pub(crate) struct FoldState<'i> {
// TODO: maybe change to bidirectional iterator
pub(crate) cursor: usize,
pub(crate) iterable: Rc<JValue>,
pub(crate) instr_head: Rc<Instruction>,
pub(crate) instr_head: Rc<Instruction<'i>>,
}
impl super::ExecutableInstruction for Fold {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Fold<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
use AquamarineError::*;
log_instruction!(fold, exec_ctx, call_ctx);
let iterable_name = &self.0;
let iterator_name = &self.1;
let instr_head = self.2.clone();
// check that value exists and has array type
let iterable = match exec_ctx.data_cache.get(iterable_name) {
let iterable = match exec_ctx.data_cache.get(self.iterable) {
Some(AValue::JValueRef(jvalue_rc)) => {
match jvalue_rc.as_ref() {
JValue::Array(array) => {
@ -76,41 +66,41 @@ impl super::ExecutableInstruction for Fold {
}
}
Some(v) => return Err(IncompatibleAValueType(format!("{:?}", v), String::from("JValueRef"))),
None => return Err(VariableNotFound(String::from(iterable_name))),
None => return Err(VariableNotFound(self.iterable.to_string())),
};
let fold_state = FoldState {
cursor: 0,
iterable: iterable.clone(),
instr_head: instr_head.clone(),
instr_head: self.instruction.clone(),
};
let previous_value = exec_ctx
.data_cache
.insert(iterator_name.clone(), AValue::JValueFoldCursor(fold_state));
.insert(self.iterator.to_string(), AValue::JValueFoldCursor(fold_state));
if previous_value.is_some() {
return Err(MultipleFoldStates(iterable_name.clone()));
return Err(MultipleFoldStates(self.iterable.to_string()));
}
instr_head.execute(exec_ctx, call_ctx)?;
exec_ctx.data_cache.remove(iterator_name);
self.instruction.execute(exec_ctx, call_ctx)?;
exec_ctx.data_cache.remove(self.iterator);
Ok(())
}
}
impl super::ExecutableInstruction for Next {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Next<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
use AquamarineError::IncompatibleAValueType;
log_instruction!(next, exec_ctx, call_ctx);
let iterator_name = &self.0;
let iterator_name = self.0;
let avalue = exec_ctx
.data_cache
.get_mut(iterator_name)
.ok_or_else(|| AquamarineError::FoldStateNotFound(iterator_name.clone()))?;
.ok_or_else(|| AquamarineError::FoldStateNotFound(iterator_name.to_string()))?;
let fold_state = match avalue {
AValue::JValueFoldCursor(state) => state,
v => {
@ -172,15 +162,15 @@ mod tests {
let lfold = String::from(
r#"
(seq (
(call ("set_variable" ("" "") () Iterable))
(fold (Iterable i
(seq (
(call ("A" ("" "") (i) acc[]))
(seq
(call "set_variable" ("" "") [] Iterable)
(fold Iterable i
(seq
(call "A" ("" "") [i] acc[])
(next i)
))
))
))"#,
)
)
)"#,
);
let res = call_vm!(set_variable_vm, "", lfold.clone(), "[]", "[]");
@ -205,15 +195,15 @@ mod tests {
let rfold = String::from(
r#"
(seq (
(call ("set_variable" ("" "") () Iterable))
(fold (Iterable i
(seq (
(seq
(call "set_variable" ("" "") [] Iterable)
(fold Iterable i
(seq
(next i)
(call ("A" ("" "") (i) acc[]))
))
))
))"#,
(call "A" ("" "") [i] acc[])
)
)
)"#,
);
let res = call_vm!(set_variable_vm, "", rfold.clone(), "[]", "[]");
@ -238,23 +228,23 @@ mod tests {
let script = String::from(
r#"
(seq (
(seq (
(call ("set_variable" ("" "") () Iterable1))
(call ("set_variable" ("" "") () Iterable2))
))
(fold (Iterable1 i
(seq (
(fold (Iterable2 j
(seq (
(call ("A" ("" "") (i) acc[]))
(seq
(seq
(call "set_variable" ("" "") [] Iterable1)
(call "set_variable" ("" "") [] Iterable2)
)
(fold Iterable1 i
(seq
(fold Iterable2 j
(seq
(call "A" ("" "") [i] acc[])
(next j)
))
))
)
)
(next i)
))
))
))"#,
)
)
)"#,
);
let res = call_vm!(set_variable_vm, "", script.clone(), "[]", "[]");
@ -281,23 +271,23 @@ mod tests {
let script = String::from(
r#"
(seq (
(seq (
(call ("set_variable" ("" "") () Iterable1))
(call ("set_variable" ("" "") () Iterable2))
))
(fold (Iterable1 i
(seq (
(fold (Iterable2 i
(seq (
(call ("A" ("" "") (i) acc[]))
(seq
(seq
(call "set_variable" ("" "") [] Iterable1)
(call "set_variable" ("" "") [] Iterable2)
)
(fold Iterable1 i
(seq
(fold Iterable2 i
(seq
(call "A" ("" "") [i] acc[])
(next i)
))
))
)
)
(next i)
))
))
))"#,
)
)
)"#,
);
let res = vm.call_with_prev_data("", script, "[]", "[]");
@ -325,15 +315,15 @@ mod tests {
let empty_fold = String::from(
r#"
(seq (
(call ("set_variable" ("" "") () Iterable))
(fold (Iterable i
(seq (
(call ("A" ("" "") (i) acc[]))
(seq
(call "set_variable" ("" "") [] Iterable)
(fold Iterable i
(seq
(call "A" ("" "") [i] acc[])
(next i)
))
))
))"#,
)
)
)"#,
);
let res = call_vm!(set_variable_vm, "", empty_fold.clone(), "[]", "[]");

View File

@ -29,43 +29,24 @@ pub(self) use crate::call_evidence::CallEvidenceCtx;
pub(self) use crate::call_evidence::EvidenceState;
use crate::Result;
use call::Call;
use fold::Fold;
use fold::Next;
use null::Null;
use par::Par;
use seq::Seq;
use xor::Xor;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::Instruction;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum Instruction {
Null(Null),
Call(Call),
Fold(Fold),
Next(Next),
Par(Par),
Seq(Seq),
Xor(Xor),
pub(crate) trait ExecutableInstruction<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()>;
}
pub(crate) trait ExecutableInstruction {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()>;
}
impl ExecutableInstruction for Instruction {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> ExecutableInstruction<'i> for Instruction<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
match self {
Instruction::Null(null) => null.execute(exec_ctx, call_ctx),
Instruction::Seq(seq) => seq.execute(exec_ctx, call_ctx),
Instruction::Call(call) => call.execute(exec_ctx, call_ctx),
Instruction::Null(null) => null.execute(exec_ctx, call_ctx),
Instruction::Fold(fold) => fold.execute(exec_ctx, call_ctx),
Instruction::Next(next) => next.execute(exec_ctx, call_ctx),
Instruction::Par(par) => par.execute(exec_ctx, call_ctx),
Instruction::Seq(seq) => seq.execute(exec_ctx, call_ctx),
Instruction::Xor(xor) => xor.execute(exec_ctx, call_ctx),
Instruction::Error => unreachable!("should not execute if parsing failed. QED."),
}
}
}

View File

@ -19,14 +19,10 @@ use super::ExecutionCtx;
use crate::log_instruction;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::Null;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Null {}
impl super::ExecutableInstruction for Null {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Null {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
log_instruction!(null, exec_ctx, call_ctx);
Ok(())

View File

@ -23,14 +23,10 @@ use crate::log_instruction;
use crate::log_targets::EVIDENCE_CHANGING;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::Par;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Par(Box<Instruction>, Box<Instruction>);
impl ExecutableInstruction for Par {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> ExecutableInstruction<'i> for Par<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
log_instruction!(par, exec_ctx, call_ctx);
let (left_subtree_size, right_subtree_size) = extract_subtree_sizes(call_ctx)?;
@ -87,10 +83,10 @@ fn extract_subtree_sizes(call_ctx: &mut CallEvidenceCtx) -> Result<(usize, usize
}
}
fn execute_subtree(
subtree: &Instruction,
fn execute_subtree<'i>(
subtree: &Instruction<'i>,
subtree_size: usize,
exec_ctx: &mut ExecutionCtx,
exec_ctx: &mut ExecutionCtx<'i>,
call_ctx: &mut CallEvidenceCtx,
) -> Result<usize> {
call_ctx.current_subtree_elements_count = subtree_size;
@ -104,14 +100,14 @@ fn execute_subtree(
Ok(call_ctx.new_path.len() - before_states_count)
}
fn determine_subtree_complete(next_instruction: &Instruction) -> bool {
fn determine_subtree_complete(next_instruction: &Instruction<'_>) -> bool {
// this is needed to prevent situation when on such pattern
// (fold (Iterable i
// (par (
// (call (..))
// (par
// (call ..)
// (next i)
// ))
// ))
// )
// )
// par will be executed after the last next that wouldn't change subtree_complete
!matches!(next_instruction, Instruction::Next(_))
}
@ -130,10 +126,10 @@ mod tests {
let script = String::from(
r#"
(par (
(call ("remote_peer_id_1" ("local_service_id" "local_fn_name") () result_name))
(call ("remote_peer_id_2" ("service_id" "fn_name") () g))
))"#,
(par
(call "remote_peer_id_1" ("local_service_id" "local_fn_name") [] result_name)
(call "remote_peer_id_2" ("service_id" "fn_name") [] g)
)"#,
);
let mut res = call_vm!(vm, "", script, "[]", "[]");
@ -151,10 +147,10 @@ mod tests {
let script = String::from(
r#"
(par (
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_name))
(call ("remote_peer_id_2" ("service_id" "fn_name") () g))
))"#,
(par
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_name)
(call "remote_peer_id_2" ("service_id" "fn_name") [] g)
)"#,
);
let res = call_vm!(vm, "", script, "[]", "[]");

View File

@ -16,18 +16,13 @@
use super::CallEvidenceCtx;
use super::ExecutionCtx;
use super::Instruction;
use crate::log_instruction;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::Seq;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Seq(Box<Instruction>, Box<Instruction>);
impl super::ExecutableInstruction for Seq {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Seq<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
log_instruction!(seq, exec_ctx, call_ctx);
exec_ctx.subtree_complete = true;
@ -55,10 +50,10 @@ mod tests {
let script = String::from(
r#"
(seq (
(call ("remote_peer_id_1" ("local_service_id" "local_fn_name") () result_name))
(call ("remote_peer_id_2" ("service_id" "fn_name") () g))
))"#,
(seq
(call "remote_peer_id_1" ("local_service_id" "local_fn_name") [] result_name)
(call "remote_peer_id_2" ("service_id" "fn_name") [] g)
)"#,
);
let res = call_vm!(vm, "asd", script.clone(), "[]", "[]");
@ -74,10 +69,10 @@ mod tests {
let script = String::from(
r#"
(seq (
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_name))
(call ("remote_peer_id_2" ("service_id" "fn_name") () g))
))"#,
(seq
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_name)
(call "remote_peer_id_2" ("service_id" "fn_name") [] g)
)"#,
);
let res = call_vm!(vm, "asd", script, "[]", "[]");

View File

@ -16,19 +16,14 @@
use super::CallEvidenceCtx;
use super::ExecutionCtx;
use super::Instruction;
use crate::log_instruction;
use crate::AquamarineError::LocalServiceError;
use crate::Result;
use serde_derive::Deserialize;
use serde_derive::Serialize;
use air_parser::ast::Xor;
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub(crate) struct Xor(Box<Instruction>, Box<Instruction>);
impl super::ExecutableInstruction for Xor {
fn execute(&self, exec_ctx: &mut ExecutionCtx, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
impl<'i> super::ExecutableInstruction<'i> for Xor<'i> {
fn execute(&self, exec_ctx: &mut ExecutionCtx<'i>, call_ctx: &mut CallEvidenceCtx) -> Result<()> {
log_instruction!(xor, exec_ctx, call_ctx);
exec_ctx.subtree_complete = true;
@ -83,10 +78,10 @@ mod tests {
let script = String::from(
r#"
(xor (
(call (%current_peer_id% ("service_id_1" "local_fn_name") () result_1))
(call (%current_peer_id% ("service_id_2" "local_fn_name") () result_2))
))"#,
(xor
(call %current_peer_id% ("service_id_1" "local_fn_name") [] result_1)
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_2)
)"#,
);
let res = call_vm!(vm, "asd", script, "[]", "[]");
@ -101,10 +96,10 @@ mod tests {
let script = String::from(
r#"
(xor (
(call (%current_peer_id% ("service_id_2" "local_fn_name") () result_1))
(call (%current_peer_id% ("service_id_1" "local_fn_name") () result_2))
))"#,
(xor
(call %current_peer_id% ("service_id_2" "local_fn_name") [] result_1)
(call %current_peer_id% ("service_id_1" "local_fn_name") [] result_2)
)"#,
);
let res = call_vm!(vm, "asd", script, "[]", "[]");

View File

@ -22,7 +22,6 @@ use crate::StepperOutcome;
use jsonpath_lib::JsonPathError;
use serde_json::Error as SerdeJsonError;
use serde_sexpr::Error as SExprError;
use std::convert::Into;
use std::env::VarError;
@ -30,8 +29,8 @@ use std::error::Error;
#[derive(Debug)]
pub enum AquamarineError {
/// Errors occurred while parsing aqua script in the form of S expressions.
SExprParseError(SExprError),
/// Error occurred while parsing AIR script
AIRParseError(String),
/// Errors occurred while parsing function arguments of an expression.
FuncArgsSerializationError(JValue, SerdeJsonError),
@ -76,7 +75,7 @@ pub enum AquamarineError {
InvalidEvidenceState(EvidenceState, String),
/// Errors occurred on call evidence deserialization.
CallEvidenceDeserializationError(SerdeJsonError),
CallEvidenceDeserializationError(SerdeJsonError, String),
/// Errors occurred on call evidence serialization.
CallEvidenceSerializationError(SerdeJsonError),
@ -96,7 +95,7 @@ impl Error for AquamarineError {}
impl std::fmt::Display for AquamarineError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
AquamarineError::SExprParseError(err) => write!(f, "aqua script can't be parsed: {:?}", err),
AquamarineError::AIRParseError(err) => write!(f, "aqua script can't be parsed:\n{}", err),
AquamarineError::FuncArgsSerializationError(args, err) => write!(
f,
"function arguments {} can't be serialized or deserialized with an error: {:?}",
@ -145,9 +144,11 @@ impl std::fmt::Display for AquamarineError {
"invalid evidence state: expected {}, but found {:?}",
expected, found
),
AquamarineError::CallEvidenceDeserializationError(err) => {
write!(f, "an error occurred while data deserialization: {:?}", err)
}
AquamarineError::CallEvidenceDeserializationError(err, path) => write!(
f,
"an error occurred while call evidence path deserialization on {:?}: {:?}",
path, err
),
AquamarineError::CallEvidenceSerializationError(err) => {
write!(f, "an error occurred while data serialization: {:?}", err)
}
@ -170,12 +171,6 @@ impl std::fmt::Display for AquamarineError {
}
}
impl From<SExprError> for AquamarineError {
fn from(err: SExprError) -> Self {
AquamarineError::SExprParseError(err)
}
}
impl From<std::convert::Infallible> for AquamarineError {
fn from(_: std::convert::Infallible) -> Self {
unreachable!()
@ -185,7 +180,7 @@ impl From<std::convert::Infallible> for AquamarineError {
impl Into<StepperOutcome> for AquamarineError {
fn into(self) -> StepperOutcome {
let ret_code = match self {
AquamarineError::SExprParseError(_) => 1,
AquamarineError::AIRParseError(_) => 1,
AquamarineError::FuncArgsSerializationError(..) => 2,
AquamarineError::CallServiceResultDeserializationError(..) => 3,
AquamarineError::CurrentPeerIdEnvError(..) => 4,

View File

@ -38,7 +38,7 @@ pub fn execute_aqua(init_user_id: String, aqua: String, prev_data: String, data:
}
fn execute_aqua_impl(_init_user_id: String, aqua: String, prev_path: String, path: String) -> Result<StepperOutcome> {
let (prev_path, path, aqua) = prepare(prev_path, path, aqua)?;
let (prev_path, path, aqua) = prepare(prev_path, path, aqua.as_str())?;
let (mut exec_ctx, mut call_ctx) = make_contexts(prev_path, path)?;
aqua.execute(&mut exec_ctx, &mut call_ctx)?;

View File

@ -14,9 +14,7 @@
* limitations under the License.
*/
use super::utils::format_aqua;
use crate::air::ExecutionCtx;
use crate::air::Instruction;
use crate::call_evidence::merge_call_paths;
use crate::call_evidence::CallEvidenceCtx;
use crate::get_current_peer_id;
@ -25,19 +23,21 @@ use crate::AquamarineError;
use crate::CallEvidencePath;
use crate::Result;
use air_parser::ast::Instruction;
/// Parse and prepare supplied data and aqua script.
pub(super) fn prepare(
pub(super) fn prepare<'i>(
raw_prev_path: String,
raw_path: String,
raw_aqua: String,
) -> Result<(CallEvidencePath, CallEvidencePath, Instruction)> {
raw_aqua: &'i str,
) -> Result<(CallEvidencePath, CallEvidencePath, Instruction<'i>)> {
use AquamarineError::CallEvidenceDeserializationError as CallDeError;
let prev_path: CallEvidencePath = serde_json::from_str(&raw_prev_path).map_err(CallDeError)?;
let path: CallEvidencePath = serde_json::from_str(&raw_path).map_err(CallDeError)?;
let prev_path: CallEvidencePath =
serde_json::from_str(&raw_prev_path).map_err(|err| CallDeError(err, raw_prev_path))?;
let path: CallEvidencePath = serde_json::from_str(&raw_path).map_err(|err| CallDeError(err, raw_path))?;
let formatted_aqua = format_aqua(raw_aqua);
let aqua: Instruction = serde_sexpr::from_str(&formatted_aqua)?;
let aqua: Instruction<'i> = *air_parser::parse(raw_aqua).map_err(|msg| AquamarineError::AIRParseError(msg))?;
log::info!(
target: RUN_PARAMS,
@ -55,7 +55,7 @@ pub(super) fn prepare(
pub(super) fn make_contexts(
prev_path: CallEvidencePath,
path: CallEvidencePath,
) -> Result<(ExecutionCtx, CallEvidenceCtx)> {
) -> Result<(ExecutionCtx<'static>, CallEvidenceCtx)> {
use AquamarineError::CurrentPeerIdEnvError as EnvError;
let current_peer_id = get_current_peer_id().map_err(|e| EnvError(e, String::from("CURRENT_PEER_ID")))?;

View File

@ -16,36 +16,6 @@
use std::hash::Hash;
/// Formats aqua script in a form of S-expressions to a form compatible with the serde_sexpr crate.
pub(super) fn format_aqua(aqua: String) -> String {
use std::iter::FromIterator;
let mut formatted_aqua = Vec::with_capacity(aqua.len());
// whether to skip the next whitespace
let mut skip_next_whitespace = false;
// whether c was a closing brace
let mut was_cbr = false;
for c in aqua.chars() {
let is_whitespace = c == ' ';
if (skip_next_whitespace && is_whitespace) || c == '\n' {
continue;
}
let is_cbr = c == ')';
skip_next_whitespace = is_whitespace || c == '(' || is_cbr;
if was_cbr && !is_cbr {
formatted_aqua.push(' ');
}
was_cbr = is_cbr;
formatted_aqua.push(c)
}
String::from_iter(formatted_aqua.into_iter())
}
/// Deduplicate values in a supplied vector.
pub(super) fn dedup<T: Eq + Hash>(mut vec: Vec<T>) -> Vec<T> {
use std::collections::HashSet;
@ -53,28 +23,3 @@ pub(super) fn dedup<T: Eq + Hash>(mut vec: Vec<T>) -> Vec<T> {
let set: HashSet<_> = vec.drain(..).collect();
set.into_iter().collect()
}
#[cfg(test)]
mod tests {
#[test]
fn format_aqua_test() {
let aqua = format!(
r#"(( (( (seq (
(call (%current_peer_id% (add_module ||) (module) module))
(seq (
(call (%current_peer_id% (add_blueprint ||) (blueprint) blueprint_id))
(seq (
(call (%current_peer_id% (create ||) (blueprint_id) service_id))
(call ({} (|| ||) (service_id) client_result))
) )
) )
))"#,
"abc"
);
let aqua = super::format_aqua(aqua);
let formatted_aqua = String::from("(((((seq ((call (%current_peer_id% (add_module ||) (module) module)) (seq ((call (%current_peer_id% (add_blueprint ||) (blueprint) blueprint_id)) (seq ((call (%current_peer_id% (create ||) (blueprint_id) service_id)) (call (abc (|| ||) (service_id) client_result))))))))");
assert_eq!(aqua, formatted_aqua);
}
}

View File

@ -54,13 +54,13 @@ use std::fmt::Formatter;
use std::rc::Rc;
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum AValue {
pub(crate) enum AValue<'i> {
JValueRef(Rc<JValue>),
JValueAccumulatorRef(RefCell<Vec<Rc<JValue>>>),
JValueFoldCursor(crate::air::FoldState),
JValueFoldCursor(crate::air::FoldState<'i>),
}
impl Display for AValue {
impl<'i> Display for AValue<'i> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AValue::JValueRef(value) => write!(f, "{:?}", value)?,

View File

@ -38,13 +38,13 @@ fn seq_par_call() {
let script = String::from(
r#"
(seq (
(par (
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_1))
(call ("remote_peer_id" ("service_id" "fn_name") () g))
))
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_2))
))"#,
(seq
(par
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let res = call_vm!(vm, "asd", script, "[]", "[]");
@ -72,13 +72,13 @@ fn par_par_call() {
let script = String::from(
r#"
(par (
(par (
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_1))
(call ("remote_peer_id" ("service_id" "fn_name") () g))
))
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_2))
))"#,
(par
(par
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let res = call_vm!(vm, "asd", script, "[]", "[]");
@ -153,25 +153,25 @@ fn create_service() {
let script = String::from(
r#"
(seq (
(seq (
(seq (
(call ("set_variables" ("" "") ("module_bytes") module_bytes))
(call ("set_variables" ("" "") ("module_config") module_config))
))
(call ("set_variables" ("" "") ("blueprint") blueprint))
))
(seq (
(call ("A" ("add_module" "") (module_bytes module_config) module))
(seq (
(call ("A" ("add_blueprint" "") (blueprint) blueprint_id))
(seq (
(call ("A" ("create" "") (blueprint_id) service_id))
(call ("remote_peer_id" ("" "") (service_id) client_result))
))
))
))
))"#,
(seq
(seq
(seq
(call "set_variables" ("" "") ["module_bytes"] module_bytes)
(call "set_variables" ("" "") ["module_config"] module_config)
)
(call "set_variables" ("" "") ["blueprint"] blueprint)
)
(seq
(call "A" ("add_module" "") [module_bytes module_config] module)
(seq
(call "A" ("add_blueprint" "") [blueprint] blueprint_id)
(seq
(call "A" ("create" "") [blueprint_id] service_id)
(call "remote_peer_id" ("" "") [service_id] client_result)
)
)
)
)"#,
);
let res = call_vm!(set_variables_vm, "init_user_id", script.clone(), "[]", "[]");

View File

@ -37,13 +37,13 @@ fn evidence_seq_par_call() {
let script = String::from(
r#"
(seq (
(par (
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_1))
(call ("remote_peer_id" ("service_id" "fn_name") () g))
))
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_2))
))"#,
(seq
(par
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let initial_state = json!([
@ -77,13 +77,13 @@ fn evidence_par_par_call() {
let script = String::from(
r#"
(par (
(par (
(call ("some_peer_id" ("local_service_id" "local_fn_name") () result_1))
(call ("remote_peer_id" ("service_id" "fn_name") () g))
))
(call (%current_peer_id% ("local_service_id" "local_fn_name") () result_2))
))"#,
(par
(par
(call "some_peer_id" ("local_service_id" "local_fn_name") [] result_1)
(call "remote_peer_id" ("service_id" "fn_name") [] g)
)
(call %current_peer_id% ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let initial_state = json!([
@ -122,13 +122,13 @@ fn evidence_seq_seq() {
let script = format!(
r#"
(seq (
(call ("{}" ("identity" "") () void0))
(seq (
(call ("{}" ("add_blueprint" "") () blueprint_id))
(call ("{}" ("addBlueprint-14d8488e-d10d-474d-96b2-878f6a7d74c8" "") () void1))
))
))
(seq
(call "{}" ("identity" "") [] void0)
(seq
(call "{}" ("add_blueprint" "") [] blueprint_id)
(call "{}" ("addBlueprint-14d8488e-d10d-474d-96b2-878f6a7d74c8" "") [] void1)
)
)
"#,
peer_id_1, peer_id_1, peer_id_2
);
@ -201,25 +201,25 @@ fn evidence_create_service() {
let script = String::from(
r#"
(seq (
(seq (
(seq (
(call ("set_variables" ("add_module" "") ("module_bytes") module_bytes))
(call ("set_variables" ("add_module" "") ("module_config") module_config))
))
(call ("set_variables" ("add_module" "") ("blueprint") blueprint))
))
(seq (
(call ("A" ("add_module" "") (module_bytes module_config) module))
(seq (
(call ("A" ("add_blueprint" "") (blueprint) blueprint_id))
(seq (
(call ("A" ("create" "") (blueprint_id) service_id))
(call ("remote_peer_id" ("" "") (service_id) client_result))
))
))
))
))"#,
(seq
(seq
(seq
(call "set_variables" ("add_module" "") ["module_bytes"] module_bytes)
(call "set_variables" ("add_module" "") ["module_config"] module_config)
)
(call "set_variables" ("add_module" "") ["blueprint"] blueprint)
)
(seq
(call "A" ("add_module" "") [module_bytes module_config] module)
(seq
(call "A" ("add_blueprint" "") [blueprint] blueprint_id)
(seq
(call "A" ("create" "") [blueprint_id] service_id)
(call "remote_peer_id" ("" "") [service_id] client_result)
)
)
)
)"#,
);
let add_module_response = String::from("add_module response");
@ -263,18 +263,18 @@ fn evidence_par_seq_fold_call() {
let script = String::from(
r#"
(par (
(seq (
(call ("some_peer_id_1" ("local_service_id" "local_fn_name") () IterableResultPeer1))
(fold (IterableResultPeer1 i
(par (
(call ("some_peer_id_2" ("local_service_id" "local_fn_name") (i) acc[]))
(par
(seq
(call "some_peer_id_1" ("local_service_id" "local_fn_name") [] IterableResultPeer1)
(fold IterableResultPeer1 i
(par
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] acc[])
(next i)
))
))
))
(call ("some_peer_id_3" ("local_service_id" "local_fn_name") () result_2))
))"#,
)
)
)
(call "some_peer_id_3" ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let res = call_vm!(vm2, "asd", script.clone(), "[]", "[]");
@ -339,18 +339,18 @@ fn evidence_par_seq_fold_in_cycle_call() {
let script = String::from(
r#"
(par (
(seq (
(call ("some_peer_id_1" ("local_service_id" "local_fn_name") () IterableResultPeer1))
(fold (IterableResultPeer1 i
(par (
(call ("some_peer_id_2" ("local_service_id" "local_fn_name") (i) acc[]))
(par
(seq
(call "some_peer_id_1" ("local_service_id" "local_fn_name") [] IterableResultPeer1)
(fold IterableResultPeer1 i
(par
(call "some_peer_id_2" ("local_service_id" "local_fn_name") [i] acc[])
(next i)
))
))
))
(call ("some_peer_id_3" ("local_service_id" "local_fn_name") () result_2))
))"#,
)
)
)
(call "some_peer_id_3" ("local_service_id" "local_fn_name") [] result_2)
)"#,
);
let mut data = String::from("[]");
@ -401,19 +401,19 @@ fn evidence_seq_par_seq_seq() {
let mut vm2 = create_aqua_vm(unit_call_service(), peer_id_2.clone());
let script = format!(
r#"
(seq (
(par (
(seq (
(call ("{}" ("" "") () result_1))
(call ("{}" ("" "") () result_2))
))
(seq (
(call ("{}" ("" "") () result_3))
(call ("{}" ("" "") () result_4))
))
))
(call ("{}" ("" "") () result_5))
))
(seq
(par
(seq
(call "{}" ("" "") [] result_1)
(call "{}" ("" "") [] result_2)
)
(seq
(call "{}" ("" "") [] result_3)
(call "{}" ("" "") [] result_4)
)
)
(call "{}" ("" "") [] result_5)
)
"#,
peer_id_1, peer_id_2, peer_id_2, peer_id_1, peer_id_2
);

View File

@ -45,29 +45,29 @@ fn data_merge() {
let script = String::from(
r#"
(seq (
(call (%current_peer_id% ("neighborhood" "") () neighborhood))
(seq (
(seq (
(fold (neighborhood i
(par (
(call (i ("add_provider" "") () void[]))
(seq
(call %current_peer_id% ("neighborhood" "") [] neighborhood)
(seq
(seq
(fold neighborhood i
(par
(call i ("add_provider" "") [] void[])
(next i)
))
))
(fold (neighborhood i
(par (
(call (i ("get_providers" "") () providers[]))
)
)
(fold neighborhood i
(par
(call i ("get_providers" "") [] providers[])
(next i)
))
))
))
(seq (
(call ("A" ("identity" "") () void[]))
(call ("B" ("" "") () none))
))
))
))
)
)
)
(seq
(call "A" ("identity" "") [] void[])
(call "B" ("" "") [] none)
)
)
)
"#,
);
@ -187,22 +187,22 @@ fn acc_merge() {
let script = String::from(
r#"
(seq (
(call ("A" ("add_provider" "") () void[]))
(seq (
(call ("A" ("add_provider" "") () void[]))
(seq (
(call ("A" ("get_providers" "") () providers[]))
(seq (
(call ("A" ("get_providers" "") () providers[]))
(seq (
(call ("B" ("" "2") (providers) void[]))
(call ("B" ("" "3") (void) void[]))
))
))
))
))
))
(seq
(call "A" ("add_provider" "") [] void[])
(seq
(call "A" ("add_provider" "") [] void[])
(seq
(call "A" ("get_providers" "") [] providers[])
(seq
(call "A" ("get_providers" "") [] providers[])
(seq
(call "B" ("" "2") [providers] void[])
(call "B" ("" "3") [void] void[])
)
)
)
)
)
"#,
);

View File

@ -48,24 +48,24 @@ fn join_chat() {
let script = String::from(
r#"
(seq (
(call ("Relay1" ("identity" "") () void1[]))
(seq (
(call ("Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") () void2[]))
(seq (
(call ("Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") () members))
(fold (members m
(par (
(seq (
(call (m.$.[1] ("identity" "") () void[]))
(call (m.$.[0] ("fgemb3" "add") () void3[]))
))
(seq
(call "Relay1" ("identity" "") [] void1[])
(seq
(call "Remote" ("552196ea-b9b2-4761-98d4-8e7dba77fac4" "add") [] void2[])
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call m.$.[1] ("identity" "") [] void[])
(call m.$.[0] ("fgemb3" "add") [] void3[])
)
(next m)
))
))
))
))
))
)
)
)
)
)
"#,
);
@ -202,21 +202,21 @@ fn join() {
let script = String::from(
r#"
(seq (
(call ("Relay1" ("identity" "") () void1[]))
(seq (
(call ("Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") () members))
(fold (members m
(par (
(seq (
(call ("Relay1" ("identity" "") () void[]))
(call ("A" ("fgemb3" "add") (m) void3[]))
))
(next m)
))
))
))
))
(seq
(call "Relay1" ("identity" "") [] void1[])
(seq
(call "Remote" ("920e3ba3-cbdf-4ae3-8972-0fa2f31fffd9" "get_users") [] members)
(fold members m
(par
(seq
(call "Relay1" ("identity" "") [] void[])
(call "A" ("fgemb3" "add") [m] void3[])
)
(next m)
)
)
)
)
"#,
);