1
0
Fork 0
mirror of synced 2025-09-23 20:28:36 +00:00

solve conflicts except compile loop

This commit is contained in:
schaeff 2019-06-11 11:12:37 +02:00
parent c06ca06cb7
commit cdf394c7e1
70 changed files with 5090 additions and 5618 deletions

Binary file not shown.

658
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,8 @@
# Exit if any subcommand fails
set -e
cargo test --release -- --ignored
if [ -n "$WITH_LIBSNARK" ]; then
cargo -Z package-features test --release --package zokrates_cli --features="libsnark" -- --ignored
else
cargo test --release -- --ignored
fi

View file

@ -3,8 +3,8 @@
# Exit if any subcommand fails
set -e
cargo test --release
if [ -n "$WITH_LIBSNARK" ]; then
cargo -Z package-features test --release --package zokrates_cli --features="libsnark"
else
cargo test --release
fi

View file

@ -27,8 +27,8 @@ You can build the container yourself from [source](https://github.com/ZoKrates/Z
```bash
git clone https://github.com/ZoKrates/ZoKrates
cd ZoKrates
cargo build --release
cd ZoKrates/target/release
cargo +nightly build --release
cd target/release
```
## Hello ZoKrates!

View file

@ -88,17 +88,17 @@ Based on that Victor can run the setup phase and export verifier smart contract
./zokrates export-verifier
```
`setup` creates a `verifiation.key` file and a `proving.key` file. Victor gives the proving key to Alice.
`setup` creates a `verifiation.key` file and a `proving.key` file. Victor gives the proving key to Peggy.
`export-verifier` creates a `verifier.sol` contract that contains our verification key and a function `verifyTx`. Victor deploys this smart contract to the Ethereum network.
Alice provides the correct pre-image as an argument to the program.
Peggy provides the correct pre-image as an argument to the program.
```sh
./zokrates compute-witness -a 0 0 0 5
```
Finally, Alice can run the command to construct the proof:
Finally, Peggy can run the command to construct the proof:
```sh
./zokrates generate-proof
@ -111,18 +111,18 @@ ZoKrates creates a file, `proof.json`, consisting of the eight variables that m
* any public inputs to the main function, declared without the `private` keyword
* the return values of the ZoKrates function
In the example we're considering, all inputs are private and there is a single return value of `1`, hence Alice has to define her public input array as follows: `[1]`
In the example we're considering, all inputs are private and there is a single return value of `1`, hence Peggy has to define her public input array as follows: `[1]`
Alice can then submit her proof by calling `verifyTx`.
Peggy can then submit her proof by calling `verifyTx`.
Victor monitors the verification smart contract for the `Verified` event, which is emitted upon successful verification of a transaction. As soon as he observes the event triggered by a transaction from Alice's public address, he can be sure that Alice has a valid pre-image for the hash he set in the smart contract.
Victor monitors the verification smart contract for the `Verified` event, which is emitted upon successful verification of a transaction. As soon as he observes the event triggered by a transaction from Peggy's public address, he can be sure that Peggy has a valid pre-image for the hash he set in the smart contract.
## Conclusion
At this point, youve successfully ran you first zkSNARK on the Ethereum blockchain. Congratulations!
>Remember that in this example only two parties were involved. This special case makes it easy to deal with the trust assumptions of zkSNARKs: only Victor was interested in verifying the claim by Alice, hence he can trust his execution of the setup phase.
>Remember that in this example only two parties were involved. This special case makes it easy to deal with the trust assumptions of zkSNARKs: only Victor was interested in verifying the claim by Peggy, hence he can trust his execution of the setup phase.
>
>In general, multiple parties may be interested in verifying the correctness of Alice's statement. For example, in the zero-knowledge based cryptocurrency Zcash, each node needs to be able to validate the correctness of transactions. In order to generalize the setup phase to these multi-party use-cases a tricky process, commonly referred to as “trusted setup” or "ceremony" needs to be conducted.
>In general, multiple parties may be interested in verifying the correctness of Peggy's statement. For example, in the zero-knowledge based cryptocurrency Zcash, each node needs to be able to validate the correctness of transactions. In order to generalize the setup phase to these multi-party use-cases a tricky process, commonly referred to as “trusted setup” or "ceremony" needs to be conducted.
>
>ZoKrates would welcome ideas to add support for such ceremonies!

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_cli"
version = "0.4.4"
version = "0.4.5"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
edition = "2018"

View file

@ -432,7 +432,7 @@ fn cli() -> Result<(), String> {
Ok(())
}
fn get_scheme(scheme_str: &str) -> Result<&'static ProofSystem, String> {
fn get_scheme(scheme_str: &str) -> Result<&'static dyn ProofSystem, String> {
match scheme_str.to_lowercase().as_ref() {
#[cfg(feature = "libsnark")]
"pghr13" => Ok(&PGHR13 {}),

View file

@ -0,0 +1 @@
[5, 1]

View file

@ -0,0 +1,12 @@
// Binomial Coeffizient, n!/(k!*(n-k)!).
def fac(field x) -> (field):
field f = 1
field counter = 0
for field i in 1..100 do
f = if counter == x then f else f * i fi
counter = if counter == x then counter else counter + 1 fi
endfor
return f
def main(field n, field k) -> (field):
return fac(n)/(fac(k)*fac(n-k))

View file

@ -0,0 +1 @@
~out_0 5

375
zokrates_core/Cargo.lock generated
View file

@ -1,375 +0,0 @@
[[package]]
name = "aho-corasick"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cmake"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-complex"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "reduce"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "zokrates"
version = "0.1.0"
dependencies = [
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"reduce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0ba20154ea1f47ce2793322f049c5646cc6d0fa9759d5f333f286e507bf8080"
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
"checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6"
"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum reduce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f77b717415291f4d7929a111402316b272c566ae9d4b75a61507dba88ecbd89"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)" = "429fcc4efa8a11341b5422c2ace724daba276c1748467e869478f53c0ba4562e"
"checksum serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)" = "6a25ad0bf818ed2d180c89addbe29198d1de6c89ed08a48aa6a4d3d16a63cbfe"
"checksum serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8035cabe9b35878adec8ac5fe03d5f6bc97ff6edd7ccb96b44c1276ba390e"
"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_core"
version = "0.3.7"
version = "0.3.8"
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
repository = "https://github.com/JacobEberhardt/ZoKrates"
readme = "README.md"
@ -24,11 +24,11 @@ serde_json = "1.0"
serde_bytes = "0.10"
bincode = "0.8.0"
regex = "0.2"
bimap = "0.1"
bellman = { git = "https://github.com/matterinc/bellman", tag = "0.2.0" }
pairing = { git = "https://github.com/matterinc/pairing", tag = "0.16.2" }
ff = { git = 'https://github.com/matterinc/ff', features = ["derive"], tag = "0.5" }
zokrates_field = { version = "0.3.0", path = "../zokrates_field" }
zokrates_pest_ast = { version = "0.1.0", path = "../zokrates_pest_ast" }
zokrates_embed = { path = "../zokrates_embed" }
rand = "0.4"
wasmi = { version = "0.4.2", optional = true }

View file

@ -136,7 +136,7 @@ void exportProof(r1cs_se_ppzksnark_proof<libff::alt_bn128_pp> proof, const char*
if(i!=1){
ss << ",";
}
ss << HexStringFromLibsnarkBigint(libsnarkBigintFromBytes(public_inputs + i*32));
ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i*32));
}
ss << "]" << "\n";
ss << "}" << "\n";

View file

@ -144,7 +144,7 @@ void exportProof(r1cs_ppzksnark_proof<libff::alt_bn128_pp> proof, const char* pr
if(i!=1){
ss << ",";
}
ss << HexStringFromLibsnarkBigint(libsnarkBigintFromBytes(public_inputs + i*32));
ss << outputInputAsHex(libsnarkBigintFromBytes(public_inputs + i*32));
}
ss << "]" << "\n";
ss << "}" << "\n";

View file

@ -38,6 +38,10 @@ std::string HexStringFromLibsnarkBigint(libff::bigint<libff::alt_bn128_r_limbs>
return ss.str();
}
std::string outputInputAsHex(libff::bigint<libff::alt_bn128_r_limbs> _x){
return "\"0x" + HexStringFromLibsnarkBigint(_x) + "\"";
}
std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p)
{
libff::alt_bn128_G1 aff = _p;

View file

@ -11,6 +11,8 @@ libff::bigint<libff::alt_bn128_r_limbs> libsnarkBigintFromBytes(const uint8_t* _
std::string HexStringFromLibsnarkBigint(libff::bigint<libff::alt_bn128_r_limbs> _x);
std::string outputInputAsHex(libff::bigint<libff::alt_bn128_r_limbs> _x);
std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p);
std::string outputPointG1AffineAsHexJson(libff::alt_bn128_G1 _p);

View file

@ -0,0 +1,521 @@
use absy;
use imports;
use types::Type;
use zokrates_field::field::Field;
use zokrates_pest_ast as pest;
impl<'ast, T: Field> From<pest::File<'ast>> for absy::Module<'ast, T> {
fn from(prog: pest::File<'ast>) -> absy::Module<T> {
absy::Module {
functions: prog
.functions
.into_iter()
.map(|f| absy::FunctionDeclarationNode::from(f))
.collect(),
imports: prog
.imports
.into_iter()
.map(|i| absy::ImportNode::from(i))
.collect(),
}
}
}
impl<'ast> From<pest::ImportDirective<'ast>> for absy::ImportNode {
fn from(import: pest::ImportDirective<'ast>) -> absy::ImportNode {
use absy::NodeValue;
imports::Import::new(import.source.value)
.alias(import.alias.map(|a| a.value))
.span(import.span)
}
}
impl<'ast, T: Field> From<pest::Function<'ast>> for absy::FunctionDeclarationNode<'ast, T> {
fn from(function: pest::Function<'ast>) -> absy::FunctionDeclarationNode<T> {
use absy::NodeValue;
let span = function.span;
let signature = absy::Signature::new()
.inputs(
function
.parameters
.clone()
.into_iter()
.map(|p| absy::ParameterNode::from(p).value.id.value.get_type())
.collect(),
)
.outputs(
function
.returns
.clone()
.into_iter()
.map(|r| Type::from(r))
.collect(),
);
let id = function.id.span.as_str();
let function = absy::Function::<T> {
arguments: function
.parameters
.into_iter()
.map(|a| absy::ParameterNode::from(a))
.collect(),
statements: function
.statements
.into_iter()
.flat_map(|s| statements_from_statement(s))
.collect(),
signature,
}
.span(span.clone()); // TODO check
absy::FunctionDeclaration {
id,
symbol: absy::FunctionSymbol::Here(function),
}
.span(span)
}
}
impl<'ast> From<pest::Parameter<'ast>> for absy::ParameterNode<'ast> {
fn from(param: pest::Parameter<'ast>) -> absy::ParameterNode {
use absy::NodeValue;
let private = param
.visibility
.map(|v| match v {
pest::Visibility::Private(_) => true,
pest::Visibility::Public(_) => false,
})
.unwrap_or(false);
let variable =
absy::Variable::new(param.id.span.as_str(), Type::from(param.ty)).span(param.id.span);
absy::Parameter::new(variable, private).span(param.span)
}
}
fn statements_from_statement<'ast, T: Field>(
statement: pest::Statement<'ast>,
) -> Vec<absy::StatementNode<T>> {
match statement {
pest::Statement::Definition(s) => statements_from_definition(s),
pest::Statement::Iteration(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Assertion(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Assignment(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Return(s) => vec![absy::StatementNode::from(s)],
pest::Statement::MultiAssignment(s) => statements_from_multi_assignment(s),
}
}
fn statements_from_multi_assignment<'ast, T: Field>(
assignment: pest::MultiAssignmentStatement<'ast>,
) -> Vec<absy::StatementNode<T>> {
use absy::NodeValue;
let declarations = assignment
.lhs
.clone()
.into_iter()
.filter(|i| i.ty.is_some())
.map(|i| {
absy::Statement::Declaration(
absy::Variable::new(i.id.span.as_str(), Type::from(i.ty.unwrap())).span(i.id.span),
)
.span(i.span)
});
let lhs = assignment
.lhs
.into_iter()
.map(|i| absy::Assignee::Identifier(i.id.span.as_str()).span(i.id.span))
.collect();
let multi_def = absy::Statement::MultipleDefinition(
lhs,
absy::Expression::FunctionCall(
&assignment.function_id.span.as_str(),
assignment
.arguments
.into_iter()
.map(|e| absy::ExpressionNode::from(e))
.collect(),
)
.span(assignment.function_id.span),
)
.span(assignment.span);
declarations.chain(std::iter::once(multi_def)).collect()
}
fn statements_from_definition<'ast, T: Field>(
definition: pest::DefinitionStatement<'ast>,
) -> Vec<absy::StatementNode<T>> {
use absy::NodeValue;
vec![
absy::Statement::Declaration(
absy::Variable::new(definition.id.span.as_str(), Type::from(definition.ty))
.span(definition.id.span.clone()),
)
.span(definition.span.clone()),
absy::Statement::Definition(
absy::AssigneeNode::from(definition.id),
absy::ExpressionNode::from(definition.expression),
)
.span(definition.span),
]
}
impl<'ast, T: Field> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast, T> {
fn from(statement: pest::ReturnStatement<'ast>) -> absy::StatementNode<T> {
use absy::NodeValue;
absy::Statement::Return(
absy::ExpressionList {
expressions: statement
.expressions
.into_iter()
.map(|e| absy::ExpressionNode::from(e))
.collect(),
}
.span(statement.span.clone()),
)
.span(statement.span)
}
}
impl<'ast, T: Field> From<pest::AssertionStatement<'ast>> for absy::StatementNode<'ast, T> {
fn from(statement: pest::AssertionStatement<'ast>) -> absy::StatementNode<T> {
use absy::NodeValue;
match statement.expression {
pest::Expression::Binary(e) => match e.op {
pest::BinaryOperator::Eq => absy::Statement::Condition(
absy::ExpressionNode::from(*e.left),
absy::ExpressionNode::from(*e.right),
),
_ => unimplemented!(
"Assertion statements should be an equality check, found {}",
statement.span.as_str()
),
},
_ => unimplemented!(
"Assertion statements should be an equality check, found {}",
statement.span.as_str()
),
}
.span(statement.span)
}
}
impl<'ast, T: Field> From<pest::IterationStatement<'ast>> for absy::StatementNode<'ast, T> {
fn from(statement: pest::IterationStatement<'ast>) -> absy::StatementNode<T> {
use absy::NodeValue;
let from = absy::ExpressionNode::from(statement.from);
let to = absy::ExpressionNode::from(statement.to);
let index = statement.index.span.as_str();
let ty = Type::from(statement.ty);
let statements: Vec<absy::StatementNode<T>> = statement
.statements
.into_iter()
.flat_map(|s| statements_from_statement(s))
.collect();
let from = match from.value {
absy::Expression::Number(n) => n,
e => unimplemented!("For loop bounds should be constants, found {}", e),
};
let to = match to.value {
absy::Expression::Number(n) => n,
e => unimplemented!("For loop bounds should be constants, found {}", e),
};
let var = absy::Variable::new(index, ty).span(statement.index.span);
absy::Statement::For(var, from, to, statements).span(statement.span)
}
}
impl<'ast, T: Field> From<pest::AssignmentStatement<'ast>> for absy::StatementNode<'ast, T> {
fn from(statement: pest::AssignmentStatement<'ast>) -> absy::StatementNode<T> {
use absy::NodeValue;
absy::Statement::Definition(
absy::AssigneeNode::from(statement.assignee),
absy::ExpressionNode::from(statement.expression),
)
.span(statement.span)
}
}
impl<'ast, T: Field> From<pest::Expression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::Expression<'ast>) -> absy::ExpressionNode<'ast, T> {
match expression {
pest::Expression::Binary(e) => absy::ExpressionNode::from(e),
pest::Expression::Ternary(e) => absy::ExpressionNode::from(e),
pest::Expression::Constant(e) => absy::ExpressionNode::from(e),
pest::Expression::Identifier(e) => absy::ExpressionNode::from(e),
pest::Expression::Postfix(e) => absy::ExpressionNode::from(e),
pest::Expression::InlineArray(e) => absy::ExpressionNode::from(e),
pest::Expression::Unary(e) => absy::ExpressionNode::from(e),
}
}
}
impl<'ast, T: Field> From<pest::BinaryExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::BinaryExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
match expression.op {
pest::BinaryOperator::Add => absy::Expression::Add(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Sub => absy::Expression::Sub(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Mul => absy::Expression::Mult(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Div => absy::Expression::Div(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Eq => absy::Expression::Eq(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Lt => absy::Expression::Lt(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Lte => absy::Expression::Le(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Gt => absy::Expression::Gt(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Gte => absy::Expression::Ge(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::And => absy::Expression::And(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Or => absy::Expression::Or(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Pow => absy::Expression::Pow(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
o => unimplemented!("Operator {:?} not implemented", o),
}
.span(expression.span)
}
}
impl<'ast, T: Field> From<pest::TernaryExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::TernaryExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
absy::Expression::IfElse(
box absy::ExpressionNode::from(*expression.first),
box absy::ExpressionNode::from(*expression.second),
box absy::ExpressionNode::from(*expression.third),
)
.span(expression.span)
}
}
impl<'ast, T: Field> From<pest::InlineArrayExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(array: pest::InlineArrayExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
absy::Expression::InlineArray(
array
.expressions
.into_iter()
.map(|e| absy::ExpressionNode::from(e))
.collect(),
)
.span(array.span)
}
}
impl<'ast, T: Field> From<pest::UnaryExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(unary: pest::UnaryExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
match unary.op {
pest::UnaryOperator::Not(_) => {
absy::Expression::Not(Box::new(absy::ExpressionNode::from(*unary.expression)))
}
}
.span(unary.span)
}
}
impl<'ast, T: Field> From<pest::PostfixExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::PostfixExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
assert!(expression.access.len() == 1); // we only allow a single access: function call or array access
match expression.access[0].clone() {
pest::Access::Call(a) => absy::Expression::FunctionCall(
&expression.id.span.as_str(),
a.expressions
.into_iter()
.map(|e| absy::ExpressionNode::from(e))
.collect(),
),
pest::Access::Select(a) => absy::Expression::Select(
box absy::ExpressionNode::from(expression.id),
box absy::ExpressionNode::from(a.expression),
),
}
.span(expression.span)
}
}
impl<'ast, T: Field> From<pest::ConstantExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::ConstantExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
absy::Expression::Number(T::try_from_dec_str(&expression.value).unwrap())
.span(expression.span)
}
}
impl<'ast, T: Field> From<pest::IdentifierExpression<'ast>> for absy::ExpressionNode<'ast, T> {
fn from(expression: pest::IdentifierExpression<'ast>) -> absy::ExpressionNode<'ast, T> {
use absy::NodeValue;
absy::Expression::Identifier(expression.span.as_str()).span(expression.span)
}
}
impl<'ast, T: Field> From<pest::IdentifierExpression<'ast>> for absy::AssigneeNode<'ast, T> {
fn from(expression: pest::IdentifierExpression<'ast>) -> absy::AssigneeNode<T> {
use absy::NodeValue;
absy::Assignee::Identifier(expression.span.as_str()).span(expression.span)
}
}
impl<'ast, T: Field> From<pest::Assignee<'ast>> for absy::AssigneeNode<'ast, T> {
fn from(assignee: pest::Assignee<'ast>) -> absy::AssigneeNode<T> {
use absy::NodeValue;
let a = absy::AssigneeNode::from(assignee.id);
match assignee.indices.len() {
0 => a,
1 => absy::Assignee::ArrayElement(
box a,
box absy::ExpressionNode::from(assignee.indices[0].clone()),
)
.span(assignee.span),
n => unimplemented!("Array should have one dimension, found {} in {}", n, a),
}
}
}
impl<'ast> From<pest::Type<'ast>> for Type {
fn from(t: pest::Type<'ast>) -> Type {
match t {
pest::Type::Basic(t) => match t {
pest::BasicType::Field(_) => Type::FieldElement,
pest::BasicType::Boolean(_) => Type::Boolean,
},
pest::Type::Array(t) => {
let size = match t.size {
pest::Expression::Constant(c) => str::parse::<usize>(&c.value).unwrap(),
e => {
unimplemented!("Array size should be constant, found {}", e.span().as_str())
}
};
match t.ty {
pest::BasicType::Field(_) => Type::FieldElementArray(size),
_ => unimplemented!(
"Array elements should be field elements, found {}",
t.span.as_str()
),
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::field::FieldPrime;
#[test]
fn forty_two() {
let source = "def main() -> (field): return 42
";
let ast = pest::generate_ast(&source).unwrap();
let expected: absy::Prog<FieldPrime> = absy::Prog {
functions: vec![absy::Function {
id: &source[4..8],
arguments: vec![],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![absy::Expression::Number(FieldPrime::from(42)).into()],
}
.into(),
)
.into()],
signature: absy::Signature::new()
.inputs(vec![])
.outputs(vec![Type::FieldElement]),
}
.into()],
imports: vec![],
imported_functions: vec![],
};
assert_eq!(absy::Prog::<FieldPrime>::from(ast), expected);
}
#[test]
fn arguments() {
let source = "def main(private field a, bool b) -> (field): return 42
";
let ast = pest::generate_ast(&source).unwrap();
let expected: absy::Prog<FieldPrime> = absy::Prog {
functions: vec![absy::Function {
id: &source[4..8],
arguments: vec![
absy::Parameter::private(absy::Variable::field_element(&source[23..24]).into())
.into(),
absy::Parameter::public(absy::Variable::boolean(&source[31..32]).into()).into(),
],
statements: vec![absy::Statement::Return(
absy::ExpressionList {
expressions: vec![absy::Expression::Number(FieldPrime::from(42)).into()],
}
.into(),
)
.into()],
signature: absy::Signature::new()
.inputs(vec![Type::FieldElement, Type::Boolean])
.outputs(vec![Type::FieldElement]),
}
.into()],
imports: vec![],
imported_functions: vec![],
};
assert_eq!(absy::Prog::<FieldPrime>::from(ast), expected);
}
}

View file

@ -5,6 +5,7 @@
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
//! @date 2017
mod from_ast;
mod node;
pub mod parameter;
pub mod variable;
@ -12,7 +13,7 @@ pub mod variable;
pub use crate::absy::node::{Node, NodeValue};
pub use crate::absy::parameter::{Parameter, ParameterNode};
pub use crate::absy::variable::{Variable, VariableNode};
use crate::types::Signature;
use crate::types::{FunctionIdentifier, Signature};
use crate::flat_absy::*;
use crate::imports::ImportNode;
@ -21,26 +22,26 @@ use zokrates_field::field::Field;
use std::collections::HashMap;
pub type Identifier = String;
pub type Identifier<'ast> = &'ast str;
pub type ModuleId = String;
pub type Modules<T> = HashMap<ModuleId, Module<T>>;
pub type Modules<'ast, T> = HashMap<ModuleId, Module<'ast, T>>;
pub type FunctionDeclarations<T> = Vec<FunctionDeclarationNode<T>>;
pub type FunctionDeclarations<'ast, T> = Vec<FunctionDeclarationNode<'ast, T>>;
pub struct Program<T: Field> {
pub modules: HashMap<ModuleId, Module<T>>,
pub struct Program<'ast, T: Field> {
pub modules: HashMap<ModuleId, Module<'ast, T>>,
pub main: ModuleId,
}
#[derive(PartialEq, Debug, Clone)]
pub struct FunctionDeclaration<T: Field> {
pub id: Identifier,
pub symbol: FunctionSymbol<T>,
pub struct FunctionDeclaration<'ast, T: Field> {
pub id: Identifier<'ast>,
pub symbol: FunctionSymbol<'ast, T>,
}
impl<T: Field> fmt::Display for FunctionDeclaration<T> {
impl<'ast, T: Field> fmt::Display for FunctionDeclaration<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.symbol {
FunctionSymbol::Here(ref fun) => write!(f, "def {}{}", self.id, fun),
@ -52,32 +53,32 @@ impl<T: Field> fmt::Display for FunctionDeclaration<T> {
}
}
type FunctionDeclarationNode<T> = Node<FunctionDeclaration<T>>;
type FunctionDeclarationNode<'ast, T> = Node<FunctionDeclaration<'ast, T>>;
#[derive(Clone, PartialEq)]
pub struct Module<T: Field> {
pub struct Module<'ast, T: Field> {
/// Functions of the module
pub functions: FunctionDeclarations<T>,
pub functions: FunctionDeclarations<'ast, T>,
pub imports: Vec<ImportNode>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum FunctionSymbol<T: Field> {
Here(FunctionNode<T>),
There(FunctionImportNode),
pub enum FunctionSymbol<'ast, T: Field> {
Here(FunctionNode<'ast, T>),
There(FunctionImportNode<'ast>),
Flat(FlatFunction<T>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionImport {
pub function_id: Identifier,
pub struct FunctionImport<'ast> {
pub function_id: Identifier<'ast>,
pub module_id: ModuleId,
}
type FunctionImportNode = Node<FunctionImport>;
type FunctionImportNode<'ast> = Node<FunctionImport<'ast>>;
impl FunctionImport {
pub fn with_id_in_module<S: Into<Identifier>, U: Into<ModuleId>>(
impl<'ast> FunctionImport<'ast> {
pub fn with_id_in_module<S: Into<Identifier<'ast>>, U: Into<ModuleId>>(
function_id: S,
module_id: U,
) -> Self {
@ -88,13 +89,13 @@ impl FunctionImport {
}
}
impl fmt::Display for FunctionImport {
impl<'ast> fmt::Display for FunctionImport<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} from {}", self.function_id, self.module_id)
}
}
impl<T: Field> fmt::Display for Module<T> {
impl<'ast, T: Field> fmt::Display for Module<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut res = vec![];
res.extend(
@ -113,7 +114,7 @@ impl<T: Field> fmt::Display for Module<T> {
}
}
impl<T: Field> fmt::Debug for Module<T> {
impl<'ast, T: Field> fmt::Debug for Module<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -133,18 +134,18 @@ impl<T: Field> fmt::Debug for Module<T> {
}
#[derive(Clone, PartialEq)]
pub struct Function<T: Field> {
pub struct Function<'ast, T: Field> {
/// Arguments of the function
pub arguments: Vec<ParameterNode>,
pub arguments: Vec<ParameterNode<'ast>>,
/// Vector of statements that are executed when running the function
pub statements: Vec<StatementNode<T>>,
pub statements: Vec<StatementNode<'ast, T>>,
/// function signature
pub signature: Signature,
}
pub type FunctionNode<T> = Node<Function<T>>;
pub type FunctionNode<'ast, T> = Node<Function<'ast, T>>;
impl<T: Field> fmt::Display for Function<T> {
impl<'ast, T: Field> fmt::Display for Function<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -163,7 +164,7 @@ impl<T: Field> fmt::Display for Function<T> {
}
}
impl<T: Field> fmt::Debug for Function<T> {
impl<'ast, T: Field> fmt::Debug for Function<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -179,14 +180,14 @@ impl<T: Field> fmt::Debug for Function<T> {
}
#[derive(Clone, PartialEq)]
pub enum Assignee<T: Field> {
Identifier(String),
ArrayElement(Box<AssigneeNode<T>>, Box<ExpressionNode<T>>),
pub enum Assignee<'ast, T: Field> {
Identifier(Identifier<'ast>),
ArrayElement(Box<AssigneeNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
}
pub type AssigneeNode<T> = Node<Assignee<T>>;
pub type AssigneeNode<'ast, T> = Node<Assignee<'ast, T>>;
impl<T: Field> fmt::Debug for Assignee<T> {
impl<'ast, T: Field> fmt::Debug for Assignee<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Assignee::Identifier(ref s) => write!(f, "{}", s),
@ -195,48 +196,25 @@ impl<T: Field> fmt::Debug for Assignee<T> {
}
}
impl<T: Field> fmt::Display for Assignee<T> {
impl<'ast, T: Field> fmt::Display for Assignee<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl<T: Field> From<ExpressionNode<T>> for AssigneeNode<T> {
fn from(e: ExpressionNode<T>) -> Self {
match e.value {
Expression::Select(box e1, box e2) => match e1 {
ExpressionNode {
value: Expression::Identifier(id),
start,
end,
} => Node::new(
e.start,
e.end,
Assignee::ArrayElement(
box Node::new(start, end, Assignee::Identifier(id)),
box e2,
),
),
_ => panic!("only use expression to assignee for elements like foo[bar]"),
},
_ => panic!("only use expression to assignee for elements like foo[bar]"),
}
}
}
#[derive(Clone, PartialEq)]
pub enum Statement<T: Field> {
Return(ExpressionListNode<T>),
Declaration(VariableNode),
Definition(AssigneeNode<T>, ExpressionNode<T>),
Condition(ExpressionNode<T>, ExpressionNode<T>),
For(VariableNode, T, T, Vec<StatementNode<T>>),
MultipleDefinition(Vec<AssigneeNode<T>>, ExpressionNode<T>),
pub enum Statement<'ast, T: Field> {
Return(ExpressionListNode<'ast, T>),
Declaration(VariableNode<'ast>),
Definition(AssigneeNode<'ast, T>, ExpressionNode<'ast, T>),
Condition(ExpressionNode<'ast, T>, ExpressionNode<'ast, T>),
For(VariableNode<'ast>, T, T, Vec<StatementNode<'ast, T>>),
MultipleDefinition(Vec<AssigneeNode<'ast, T>>, ExpressionNode<'ast, T>),
}
pub type StatementNode<T> = Node<Statement<T>>;
pub type StatementNode<'ast, T> = Node<Statement<'ast, T>>;
impl<T: Field> fmt::Display for Statement<T> {
impl<'ast, T: Field> fmt::Display for Statement<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref expr) => write!(f, "return {}", expr),
@ -263,7 +241,7 @@ impl<T: Field> fmt::Display for Statement<T> {
}
}
impl<T: Field> fmt::Debug for Statement<T> {
impl<'ast, T: Field> fmt::Debug for Statement<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref expr) => write!(f, "Return({:?})", expr),
@ -286,36 +264,36 @@ impl<T: Field> fmt::Debug for Statement<T> {
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum Expression<T: Field> {
#[derive(Clone, PartialEq)]
pub enum Expression<'ast, T: Field> {
Number(T),
Identifier(String),
Add(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Sub(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Mult(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Div(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Pow(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Identifier(Identifier<'ast>),
Add(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Sub(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Mult(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Div(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Pow(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
IfElse(
Box<ExpressionNode<T>>,
Box<ExpressionNode<T>>,
Box<ExpressionNode<T>>,
Box<ExpressionNode<'ast, T>>,
Box<ExpressionNode<'ast, T>>,
Box<ExpressionNode<'ast, T>>,
),
FunctionCall(String, Vec<ExpressionNode<T>>),
Lt(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Le(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Eq(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Ge(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Gt(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
And(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Not(Box<ExpressionNode<T>>),
InlineArray(Vec<ExpressionNode<T>>),
Select(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
Or(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
FunctionCall(FunctionIdentifier<'ast>, Vec<ExpressionNode<'ast, T>>),
Lt(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Le(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Eq(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Ge(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Gt(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
And(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Not(Box<ExpressionNode<'ast, T>>),
InlineArray(Vec<ExpressionNode<'ast, T>>),
Select(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
Or(Box<ExpressionNode<'ast, T>>, Box<ExpressionNode<'ast, T>>),
}
pub type ExpressionNode<T> = Node<Expression<T>>;
pub type ExpressionNode<'ast, T> = Node<Expression<'ast, T>>;
impl<T: Field> fmt::Display for Expression<T> {
impl<'ast, T: Field> fmt::Display for Expression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Number(ref i) => write!(f, "{}", i),
@ -363,7 +341,7 @@ impl<T: Field> fmt::Display for Expression<T> {
}
}
impl<T: Field> fmt::Debug for Expression<T> {
impl<'ast, T: Field> fmt::Debug for Expression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Number(ref i) => write!(f, "Num({})", i),
@ -401,22 +379,22 @@ impl<T: Field> fmt::Debug for Expression<T> {
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct ExpressionList<T: Field> {
pub expressions: Vec<ExpressionNode<T>>,
#[derive(Clone, PartialEq)]
pub struct ExpressionList<'ast, T: Field> {
pub expressions: Vec<ExpressionNode<'ast, T>>,
}
pub type ExpressionListNode<T> = Node<ExpressionList<T>>;
pub type ExpressionListNode<'ast, T> = Node<ExpressionList<'ast, T>>;
impl<T: Field> ExpressionList<T> {
pub fn new() -> ExpressionList<T> {
impl<'ast, T: Field> ExpressionList<'ast, T> {
pub fn new() -> ExpressionList<'ast, T> {
ExpressionList {
expressions: vec![],
}
}
}
impl<T: Field> fmt::Display for ExpressionList<T> {
impl<'ast, T: Field> fmt::Display for ExpressionList<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, param) in self.expressions.iter().enumerate() {
r#try!(write!(f, "{}", param));
@ -428,7 +406,7 @@ impl<T: Field> fmt::Display for ExpressionList<T> {
}
}
impl<T: Field> fmt::Debug for ExpressionList<T> {
impl<'ast, T: Field> fmt::Debug for ExpressionList<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ExpressionList({:?})", self.expressions)
}

View file

@ -1,5 +1,6 @@
use crate::parser::Position;
use std::fmt;
use zokrates_pest_ast::Span;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node<T: fmt::Display> {
@ -40,6 +41,22 @@ pub trait NodeValue: fmt::Display + Sized + PartialEq {
fn mock(self) -> Node<Self> {
Node::new(Position::mock(), Position::mock(), self)
}
fn span(self, span: Span) -> Node<Self> {
let from = span.start_pos().line_col();
let to = span.end_pos().line_col();
let from = Position {
line: from.0,
col: from.1,
};
let to = Position {
line: to.0,
col: to.1,
};
Node::new(from, to, self)
}
}
impl<V: NodeValue> From<V> for Node<V> {
@ -53,16 +70,16 @@ use crate::absy::*;
use crate::imports::*;
use zokrates_field::field::Field;
impl<T: Field> NodeValue for Expression<T> {}
impl<T: Field> NodeValue for ExpressionList<T> {}
impl<T: Field> NodeValue for Assignee<T> {}
impl<T: Field> NodeValue for Statement<T> {}
impl<T: Field> NodeValue for FunctionDeclaration<T> {}
impl<T: Field> NodeValue for Function<T> {}
impl<T: Field> NodeValue for Module<T> {}
impl NodeValue for FunctionImport {}
impl NodeValue for Variable {}
impl NodeValue for Parameter {}
impl<'ast, T: Field> NodeValue for Expression<'ast, T> {}
impl<'ast, T: Field> NodeValue for ExpressionList<'ast, T> {}
impl<'ast, T: Field> NodeValue for Assignee<'ast, T> {}
impl<'ast, T: Field> NodeValue for Statement<'ast, T> {}
impl<'ast, T: Field> NodeValue for FunctionDeclaration<'ast, T> {}
impl<'ast, T: Field> NodeValue for Function<'ast, T> {}
impl<'ast, T: Field> NodeValue for Module<'ast, T> {}
impl<'ast> NodeValue for FunctionImport<'ast> {}
impl<'ast> NodeValue for Variable<'ast> {}
impl<'ast> NodeValue for Parameter<'ast> {}
impl NodeValue for Import {}
impl<T: NodeValue> std::cmp::PartialEq for Node<T> {

View file

@ -1,21 +1,25 @@
use crate::absy::{Node, VariableNode};
use std::fmt;
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct Parameter {
pub id: VariableNode,
#[derive(Clone, PartialEq)]
pub struct Parameter<'ast> {
pub id: VariableNode<'ast>,
pub private: bool,
}
impl Parameter {
pub fn public(v: VariableNode) -> Self {
impl<'ast> Parameter<'ast> {
pub fn new(v: VariableNode<'ast>, private: bool) -> Self {
Parameter { id: v, private }
}
pub fn public(v: VariableNode<'ast>) -> Self {
Parameter {
id: v,
private: false,
}
}
pub fn private(v: VariableNode) -> Self {
pub fn private(v: VariableNode<'ast>) -> Self {
Parameter {
id: v,
private: true,
@ -23,9 +27,9 @@ impl Parameter {
}
}
pub type ParameterNode = Node<Parameter>;
pub type ParameterNode<'ast> = Node<Parameter<'ast>>;
impl fmt::Display for Parameter {
impl<'ast> fmt::Display for Parameter<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let visibility = if self.private { "private " } else { "" };
write!(
@ -38,8 +42,12 @@ impl fmt::Display for Parameter {
}
}
impl fmt::Debug for Parameter {
impl<'ast> fmt::Debug for Parameter<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Parameter(variable: {:?})", self.id)
write!(
f,
"Parameter(variable: {:?}, private: {:?})",
self.id, self.private
)
}
}

View file

@ -1,5 +1,59 @@
use crate::absy::Node;
use std::fmt;
use types::Type;
pub use crate::types::Variable;
use crate::absy::Identifier;
pub type VariableNode = Node<Variable>;
#[derive(Clone, PartialEq, Hash, Eq)]
pub struct Variable<'ast> {
pub id: Identifier<'ast>,
pub _type: Type,
}
pub type VariableNode<'ast> = Node<Variable<'ast>>;
impl<'ast> Variable<'ast> {
pub fn new<S: Into<&'ast str>>(id: S, t: Type) -> Variable<'ast> {
Variable {
id: id.into(),
_type: t,
}
}
pub fn field_element<S: Into<&'ast str>>(id: S) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::FieldElement,
}
}
pub fn boolean<S: Into<&'ast str>>(id: S) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::Boolean,
}
}
pub fn field_array<S: Into<&'ast str>>(id: S, size: usize) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::FieldElementArray(size),
}
}
pub fn get_type(&self) -> Type {
self._type.clone()
}
}
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self._type, self.id,)
}
}
impl<'ast> fmt::Debug for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,)
}
}

View file

@ -8,7 +8,6 @@ use crate::flatten::Flattener;
use crate::imports::{self, Importer};
use crate::ir;
use crate::optimizer::Optimize;
use crate::parser::{self, parse_module};
use crate::semantics::{self, Checker};
use crate::static_analysis::Analyse;
use std::collections::HashMap;
@ -16,17 +15,18 @@ use std::fmt;
use std::io;
use std::io::BufRead;
use zokrates_field::field::Field;
use zokrates_pest_ast as pest;
#[derive(Debug)]
pub struct CompileErrors<T: Field>(Vec<CompileError<T>>);
pub struct CompileErrors(Vec<CompileError>);
impl<T: Field> From<CompileError<T>> for CompileErrors<T> {
fn from(e: CompileError<T>) -> CompileErrors<T> {
impl From<CompileError> for CompileErrors {
fn from(e: CompileError) -> CompileErrors {
CompileErrors(vec![e])
}
}
impl<T: Field> fmt::Display for CompileErrors<T> {
impl fmt::Display for CompileErrors {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -41,15 +41,15 @@ impl<T: Field> fmt::Display for CompileErrors<T> {
}
#[derive(Debug)]
pub enum CompileErrorInner<T: Field> {
ParserError(parser::Error<T>),
pub enum CompileErrorInner {
ParserError(pest::Error),
ImportError(imports::Error),
SemanticError(semantics::Error),
ReadError(io::Error),
}
impl<T: Field> CompileErrorInner<T> {
pub fn with_context(self, context: &Option<String>) -> CompileError<T> {
impl CompileErrorInner {
pub fn with_context(self, context: &Option<String>) -> CompileError {
CompileError {
value: self,
context: context.clone(),
@ -58,12 +58,12 @@ impl<T: Field> CompileErrorInner<T> {
}
#[derive(Debug)]
pub struct CompileError<T: Field> {
pub struct CompileError {
context: Option<String>,
value: CompileErrorInner<T>,
value: CompileErrorInner,
}
impl<T: Field> CompileErrors<T> {
impl CompileErrors {
pub fn with_context(self, context: Option<String>) -> Self {
CompileErrors(
self.0
@ -77,7 +77,7 @@ impl<T: Field> CompileErrors<T> {
}
}
impl<T: Field> fmt::Display for CompileError<T> {
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let context = match self.context {
Some(ref x) => x.clone(),
@ -87,31 +87,31 @@ impl<T: Field> fmt::Display for CompileError<T> {
}
}
impl<T: Field> From<parser::Error<T>> for CompileErrorInner<T> {
fn from(error: parser::Error<T>) -> Self {
impl From<pest::Error> for CompileErrorInner {
fn from(error: pest::Error) -> Self {
CompileErrorInner::ParserError(error)
}
}
impl<T: Field> From<imports::Error> for CompileErrorInner<T> {
impl From<imports::Error> for CompileErrorInner {
fn from(error: imports::Error) -> Self {
CompileErrorInner::ImportError(error)
}
}
impl<T: Field> From<io::Error> for CompileErrorInner<T> {
impl From<io::Error> for CompileErrorInner {
fn from(error: io::Error) -> Self {
CompileErrorInner::ReadError(error)
}
}
impl<T: Field> From<semantics::Error> for CompileErrorInner<T> {
impl From<semantics::Error> for CompileErrorInner {
fn from(error: semantics::Error) -> Self {
CompileErrorInner::SemanticError(error)
}
}
impl<T: Field> fmt::Display for CompileErrorInner<T> {
impl fmt::Display for CompileErrorInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let res = match *self {
CompileErrorInner::ParserError(ref e) => format!("{}", e),
@ -127,11 +127,14 @@ pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
reader: &mut R,
location: Option<String>,
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
) -> Result<ir::Prog<T>, CompileErrors<T>> {
let compiled = compile_program(reader, location.clone(), resolve_option)?;
) -> Result<ir::Prog<T>, CompileErrors> {
let mut source = String::new();
reader.read_to_string(&mut source).unwrap();
let compiled = compile_program(&source, location.clone(), resolve_option)?;
// check semantics
let typed_ast = Checker::new().check_program(compiled).map_err(|errors| {
let typed_ast = Checker::check(compiled).map_err(|errors| {
CompileErrors(
errors
.into_iter()
@ -152,14 +155,14 @@ pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
Ok(ir::Prog::from(program_flattened).optimize())
}
pub fn compile_program<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
reader: &mut R,
pub fn compile_program<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
source: &'ast str,
location: Option<String>,
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
) -> Result<Program<T>, CompileErrors<T>> {
) -> Result<Program<T>, CompileErrors> {
let mut modules = HashMap::new();
let main = compile_module(reader, location.clone(), resolve_option, &mut modules)?;
let main = compile_module(&source, location.clone(), resolve_option, &mut modules)?;
let location = location.unwrap_or("???".to_string());
@ -171,14 +174,15 @@ pub fn compile_program<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>
})
}
pub fn compile_module<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
reader: &mut R,
pub fn compile_module<'ast, T: Field, S: BufRead, E: Into<imports::Error>>(
source: &'ast str,
location: Option<String>,
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
modules: &mut HashMap<ModuleId, Module<T>>,
) -> Result<Module<T>, CompileErrors<T>> {
let module_without_imports: Module<T> = parse_module(reader)
modules: &mut HashMap<ModuleId, Module<'ast, T>>,
) -> Result<Module<'ast, T>, CompileErrors> {
let ast = pest::generate_ast(&source)
.map_err(|e| CompileErrors::from(CompileErrorInner::from(e).with_context(&location)))?;
let module_without_imports: Module<T> = Module::from(ast);
Importer::new().apply_imports(
module_without_imports,
@ -204,7 +208,7 @@ mod test {
"#
.as_bytes(),
);
let res: Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> = compile(
let res: Result<ir::Prog<FieldPrime>, CompileErrors> = compile(
&mut r,
Some(String::from("./path/to/file")),
None::<
@ -230,7 +234,7 @@ mod test {
"#
.as_bytes(),
);
let res: Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> = compile(
let res: Result<ir::Prog<FieldPrime>, CompileErrors> = compile(
&mut r,
Some(String::from("./path/to/file")),
None::<

File diff suppressed because it is too large Load diff

View file

@ -79,6 +79,11 @@ impl Import {
}
}
pub fn alias(mut self, alias: Option<String>) -> Self {
self.alias = alias;
self
}
pub fn get_source(&self) -> &String {
&self.source
}
@ -109,154 +114,165 @@ impl Importer {
Importer {}
}
// Based on Imports of a program, populate `functions` for external imports and `flat_functions` for flat imports
pub fn apply_imports<T: Field, S: BufRead, E: Into<Error>>(
// Inject dependencies declared for `destination`
// The lifetime of the Program before injection outlives the lifetime after
pub fn apply_imports<'before, 'after, T: Field, S: BufRead, E: Into<Error>>(
&self,
destination: Module<T>,
destination: Module<'before, T>,
location: Option<String>,
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
modules: &mut HashMap<ModuleId, Module<T>>,
) -> Result<Module<T>, CompileErrors<T>> {
let mut functions = vec![]; // functions, base case to import from other modules
for import in destination.imports.iter() {
let pos = import.pos();
let import = &import.value;
// handle the case of special bellman and packing imports
if import.source.starts_with("BELLMAN") {
match import.source.as_ref() {
"BELLMAN/sha256round" => {
use crate::standard::sha_round;
let compiled = sha_round();
let alias = match import.alias {
Some(ref alias) => {
if alias == "sha256" {
alias.clone()
} else {
return Err(CompileErrorInner::from(Error::new(format!(
"Aliasing gadgets is not supported, found alias {}",
alias
)))
.with_context(&location)
.into());
}
}
None => String::from("sha256"),
};
functions.push(
FunctionDeclaration {
id: alias.clone(),
symbol: FunctionSymbol::Flat(compiled),
}
.start_end(pos.0, pos.1),
);
}
s => {
return Err(CompileErrorInner::ImportError(
Error::new(format!("Gadget {} not found", s)).with_pos(Some(pos)),
)
.with_context(&location)
.into());
}
}
} else if import.source.starts_with("PACKING") {
use crate::types::conversions::split;
match import.source.as_ref() {
"PACKING/split" => {
let compiled = split();
let alias = match import.alias {
Some(ref alias) => {
if alias == "split" {
alias.clone()
} else {
return Err(CompileErrorInner::from(Error::new(format!(
"Aliasing gadgets is not supported, found alias {}",
alias
)))
.with_context(&location)
.into());
}
}
None => String::from("split"),
};
functions.push(
FunctionDeclaration {
id: alias.clone(),
symbol: FunctionSymbol::Flat(compiled),
}
.start_end(pos.0, pos.1),
);
}
s => {
return Err(CompileErrorInner::ImportError(
Error::new(format!("Packing helper {} not found", s))
.with_pos(Some(pos)),
)
.with_context(&location)
.into());
}
}
} else {
// to resolve imports, we need a resolver
match resolve_option {
Some(resolve) => match resolve(&location, &import.source) {
Ok((mut reader, location, auto_alias)) => {
let compiled = compile_module(
&mut reader,
Some(location),
resolve_option,
modules,
)
.map_err(|e| e.with_context(Some(import.source.clone())))?;
let alias = import.alias.clone().unwrap_or(auto_alias);
modules.insert(import.source.clone(), compiled);
functions.push(
FunctionDeclaration {
id: alias.clone(),
symbol: FunctionSymbol::There(
FunctionImport::with_id_in_module(
"main",
import.source.clone(),
)
.start_end(pos.0, pos.1),
),
}
.start_end(pos.0, pos.1),
);
}
Err(err) => {
return Err(CompileErrorInner::ImportError(
err.into().with_pos(Some(pos)),
)
.with_context(&location)
.into());
}
},
None => {
return Err(CompileErrorInner::from(Error::new(
"Can't resolve import without a resolver",
))
.with_context(&location)
.into());
}
}
}
}
functions.extend(destination.functions);
Ok(Module {
imports: vec![],
functions: functions,
})
) -> Result<Module<'after, T>, CompileErrors>
where
'before: 'after,
{
unimplemented!()
}
// {
// let mut functions: Vec<_> = vec![];
// for import in destination.imports {
// let pos = import.pos();
// let import = import.value;
// // handle the case of special bellman and packing imports
// if import.source.starts_with("BELLMAN") {
// match import.source.as_ref() {
// "BELLMAN/sha256round" => {
// use crate::standard::sha_round;
// let compiled = sha_round();
// let alias = match import.alias {
// Some(alias) => {
// if alias == "sha256" {
// alias.clone()
// } else {
// return Err(CompileErrorInner::from(Error::new(format!(
// "Aliasing gadgets is not supported, found alias {}",
// alias
// )))
// .with_context(&location)
// .into());
// }
// }
// None => String::from("sha256"),
// };
// functions.push(
// FunctionDeclaration {
// id: &alias,
// symbol: FunctionSymbol::Flat(compiled),
// }
// .start_end(pos.0, pos.1),
// );
// }
// s => {
// return Err(CompileErrorInner::ImportError(
// Error::new(format!("Gadget {} not found", s)).with_pos(Some(pos)),
// )
// .with_context(&location)
// .into());
// }
// }
// } else if import.source.starts_with("PACKING") {
// use crate::types::conversions::split;
// match import.source.as_ref() {
// "PACKING/split" => {
// let compiled = split();
// let alias = match import.alias {
// Some(alias) => {
// if alias == "split" {
// alias.clone()
// } else {
// return Err(CompileErrorInner::from(Error::new(format!(
// "Aliasing gadgets is not supported, found alias {}",
// alias
// )))
// .with_context(&location)
// .into());
// }
// }
// None => String::from("split"),
// };
// functions.push(
// FunctionDeclaration {
// id: &alias,
// symbol: FunctionSymbol::Flat(compiled),
// }
// .start_end(pos.0, pos.1),
// );
// }
// s => {
// return Err(CompileErrorInner::ImportError(
// Error::new(format!("Packing helper {} not found", s))
// .with_pos(Some(pos)),
// )
// .with_context(&location)
// .into());
// }
// }
// } else {
// // to resolve imports, we need a resolver
// match resolve_option {
// Some(resolve) => match resolve(&location, &import.source) {
// Ok((mut reader, location, auto_alias)) => {
// let mut source = String::new();
// reader.read_to_string(&mut source).unwrap();
// let compiled = compile_module(
// &source,
// Some(location),
// resolve_option,
// modules,
// )
// .map_err(|e| e.with_context(Some(import.source.clone())))?;
// let alias = import.alias.clone().unwrap_or(auto_alias);
// modules.insert(import.source.clone(), compiled);
// functions.push(
// FunctionDeclaration {
// id: &alias,
// symbol: FunctionSymbol::There(
// FunctionImport::with_id_in_module(
// "main",
// import.source.clone(),
// )
// .start_end(pos.0, pos.1),
// ),
// }
// .start_end(pos.0, pos.1),
// );
// }
// Err(err) => {
// return Err(CompileErrorInner::ImportError(
// err.into().with_pos(Some(pos)),
// )
// .with_context(&location)
// .into());
// }
// },
// None => {
// return Err(CompileErrorInner::from(Error::new(
// "Can't resolve import without a resolver",
// ))
// .with_context(&location)
// .into());
// }
// }
// }
// }
// functions.extend(destination.functions);
// Ok(Module {
// imports: vec![],
// functions: functions,
// })
// }
}
#[cfg(test)]

View file

@ -63,7 +63,7 @@ impl<T: Field> PartialEq for LinComb<T> {
}
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord, Hash, Debug, Serialize, Deserialize)]
pub struct CanonicalLinComb<T: Field>(BTreeMap<FlatVariable, T>);
pub struct CanonicalLinComb<T: Field>(pub BTreeMap<FlatVariable, T>);
impl<T: Field> LinComb<T> {
pub fn summand<U: Into<T>>(mult: U, var: FlatVariable) -> LinComb<T> {
@ -105,7 +105,7 @@ impl<T: Field> LinComb<T> {
}
}
fn as_canonical(&self) -> CanonicalLinComb<T> {
pub fn as_canonical(&self) -> CanonicalLinComb<T> {
CanonicalLinComb(self.0.clone().into_iter().fold(
BTreeMap::new(),
|mut acc, (val, coeff)| {

View file

@ -10,8 +10,8 @@ mod from_flat;
mod interpreter;
mod witness;
pub use self::expression::LinComb;
use self::expression::QuadComb;
pub use self::expression::{CanonicalLinComb, LinComb};
pub use self::interpreter::{Error, ExecutionResult};
pub use self::witness::Witness;

View file

@ -8,9 +8,9 @@ extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate bellman;
extern crate bimap;
extern crate bincode;
extern crate ff;
extern crate lazy_static;
extern crate pairing;
#[cfg(feature = "wasm")]
extern crate parity_wasm;
@ -23,6 +23,7 @@ extern crate serde_bytes;
extern crate wasmi;
extern crate zokrates_embed;
extern crate zokrates_field;
extern crate zokrates_pest_ast;
mod flatten;
mod helpers;

View file

@ -1,29 +0,0 @@
use crate::parser::tokenize::Position;
use crate::parser::tokenize::Token;
use std::fmt;
use zokrates_field::field::Field;
#[derive(PartialEq)]
pub struct Error<T: Field> {
pub expected: Vec<Token<T>>,
pub got: Token<T>,
pub pos: Position,
}
impl<T: Field> fmt::Display for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}\n\tExpected one of {:?}, got {:?}",
self.pos.col(-(self.got.to_string().len() as isize)),
self.expected,
self.got
)
}
}
impl<T: Field> fmt::Debug for Error<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}

View file

@ -1,7 +1,3 @@
mod error;
mod parse;
mod tokenize;
pub use crate::parser::error::Error;
pub use crate::parser::parse::parse_module;
pub use crate::parser::tokenize::Position;
pub use parser::tokenize::Position;

File diff suppressed because it is too large Load diff

View file

@ -1,100 +0,0 @@
use zokrates_field::field::Field;
use crate::parser::tokenize::{next_token, Position, Token};
use crate::parser::Error;
use super::expression::parse_expr;
use crate::absy::{ExpressionList, ExpressionListNode, Node};
// parse an expression list
pub fn parse_expression_list<T: Field>(
input: String,
pos: Position,
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
let mut res = ExpressionList::new();
parse_comma_separated_expression_list_rec(input, pos, &mut res)
}
fn parse_comma_separated_expression_list_rec<T: Field>(
input: String,
pos: Position,
mut acc: &mut ExpressionList<T>,
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
match parse_expr(&input, &pos) {
Ok((e1, s1, p1)) => {
acc.expressions.push(e1);
match next_token::<T>(&s1, &p1) {
(Token::Comma, s2, p2) => {
parse_comma_separated_expression_list_rec(s2, p2, &mut acc)
}
(..) => Ok((Node::new(pos, p1, acc.clone()), s1, p1)),
}
}
Err(err) => Err(err),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::absy::Expression;
use zokrates_field::field::FieldPrime;
fn parse_comma_separated_list<T: Field>(
input: String,
pos: Position,
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
let mut res = ExpressionList::new().into();
parse_comma_separated_expression_list_rec(input, pos, &mut res)
}
#[test]
fn comma_separated_list() {
let pos = Position { line: 45, col: 121 };
let string = String::from("b, c");
let expr = ExpressionList::<FieldPrime> {
expressions: vec![
Expression::Identifier(String::from("b")).into(),
Expression::Identifier(String::from("c")).into(),
],
}
.into();
assert_eq!(
Ok((expr, String::from(""), pos.col(string.len() as isize))),
parse_expression_list(string, pos)
)
}
#[test]
fn comma_separated_list_single() {
let pos = Position { line: 45, col: 121 };
let string = String::from("a");
let exprs = ExpressionList {
expressions: vec![Expression::Identifier(String::from("a")).into()],
}
.into();
assert_eq!(
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
parse_comma_separated_list::<FieldPrime>(string, pos)
)
}
#[test]
fn comma_separated_list_three() {
let pos = Position { line: 45, col: 121 };
let string = String::from("a, b, c");
let exprs = ExpressionList {
expressions: vec![
Expression::Identifier(String::from("a")).into(),
Expression::Identifier(String::from("b")).into(),
Expression::Identifier(String::from("c")).into(),
],
}
.into();
assert_eq!(
Ok((exprs, String::from(""), pos.col(string.len() as isize))),
parse_comma_separated_list::<FieldPrime>(string, pos)
)
}
}

View file

@ -1,319 +0,0 @@
use zokrates_field::field::Field;
use std::io::prelude::*;
use std::io::Lines;
use crate::parser::tokenize::{next_token, Position, Token};
use crate::parser::Error;
use super::statement::parse_statement;
use crate::absy::{
Function, FunctionNode, Identifier, Node, Parameter, ParameterNode, Statement, Variable,
VariableNode,
};
use crate::types::{Signature, Type};
fn parse_function_identifier<T: Field>(
input: &String,
pos: &Position,
) -> Result<(String, String, Position), Error<T>> {
match next_token::<T>(&input, &pos) {
(Token::Ide(x), s, p) => Ok((x, s, p)),
(t, _, p) => Err(Error {
expected: vec![Token::Ide(String::from("name"))],
got: t,
pos: p,
}),
}
}
fn parse_function_header<T: Field>(
input: &String,
pos: &Position,
) -> Result<(String, Vec<ParameterNode>, Signature), Error<T>> {
// parse function identifier
let (id, s, p) = parse_function_identifier(input, pos)?;
// parse function arguments, enclosed by parentheses
let (args, s, p) = match next_token(&s, &p) {
(Token::Open, s1, p1) => match parse_function_arguments(s1, p1) {
Ok((args, s2, p2)) => match next_token::<T>(&s2, &p2) {
(Token::Close, s3, p3) => Ok((args, s3, p3)),
(t3, _, p3) => {
return Err(Error {
expected: vec![Token::Close],
got: t3,
pos: p3,
});
}
},
Err(e) => return Err(e),
},
(t1, _, p1) => {
return Err(Error {
expected: vec![Token::Open],
got: t1,
pos: p1,
});
}
}?;
// parse function return types, enclosed by parentheses
let (return_types, s, p) = match next_token(&s, &p) {
(Token::Arrow, s0, p0) => match next_token(&s0, &p0) {
(Token::Open, s1, p1) => match parse_function_return_types(s1, p1) {
Ok((types, s2, p2)) => match next_token::<T>(&s2, &p2) {
(Token::Close, s3, p3) => Ok((types, s3, p3)),
(t3, _, p3) => {
return Err(Error {
expected: vec![Token::Close],
got: t3,
pos: p3,
});
}
},
Err(e) => return Err(e),
},
(t1, _, p1) => {
return Err(Error {
expected: vec![Token::Open],
got: t1,
pos: p1,
});
}
},
(t0, _, p0) => {
return Err(Error {
expected: vec![Token::Arrow],
got: t0,
pos: p0,
});
}
}?;
let sig = Signature {
inputs: args.iter().map(|a| a.value.id.value.get_type()).collect(),
outputs: return_types,
};
match next_token(&s, &p) {
(Token::Colon, s5, p5) => match next_token(&s5, &p5) {
(Token::InlineComment(_), _, _) => return Ok((id, args, sig)),
(Token::Unknown(ref x6), ..) if x6 == "" => return Ok((id, args, sig)),
(t6, _, p6) => {
return Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t6,
pos: p6,
});
}
},
(t5, _, p5) => {
return Err(Error {
expected: vec![Token::Colon],
got: t5,
pos: p5,
});
}
}
}
fn parse_function_argument_variable<T: Field>(
input: &String,
pos: &Position,
) -> Result<(VariableNode, String, Position), Error<T>> {
let s4 = input;
let p4 = pos;
match next_token::<T>(&s4, &p4) {
(Token::Type(t), s5, p5) => match next_token(&s5, &p5) {
(Token::Ide(x), s6, p6) => Ok((Node::new(*pos, p6, Variable::new(x, t)), s6, p6)),
(t6, _, p6) => Err(Error {
expected: vec![Token::Ide(String::from("identifier"))],
got: t6,
pos: p6,
}),
},
(t5, _, p5) => Err(Error {
expected: vec![Token::Type(Type::FieldElement)],
got: t5,
pos: p5,
}),
}
}
fn parse_function_arguments<T: Field>(
input: String,
pos: Position,
) -> Result<(Vec<ParameterNode>, String, Position), Error<T>> {
let mut args = Vec::new();
let mut s = input;
let mut p = pos;
loop {
match next_token(&s, &p) {
(Token::Private, s1, p1) => {
let (var, s2, p2) = parse_function_argument_variable::<T>(&s1, &p1)?;
args.push(Node::new(p, p1, Parameter::private(var)));
match next_token::<T>(&s2, &p2) {
(Token::Comma, s3, p3) => {
s = s3;
p = p3;
}
(Token::Close, _, _) => return Ok((args, s2, p2)),
(t3, _, p3) => {
return Err(Error {
expected: vec![Token::Comma, Token::Close],
got: t3,
pos: p3,
});
}
}
}
(Token::Type(_), _, _) => {
let (var, s2, p2) = parse_function_argument_variable::<T>(&s, &p)?;
args.push(Node::new(p, p2, Parameter::public(var)));
match next_token::<T>(&s2, &p2) {
(Token::Comma, s3, p3) => {
s = s3;
p = p3;
}
(Token::Close, _, _) => return Ok((args, s2, p2)),
(t3, _, p3) => {
return Err(Error {
expected: vec![Token::Comma, Token::Close],
got: t3,
pos: p3,
});
}
}
}
(Token::Close, _, _) => return Ok((vec![], s, p)),
(t4, _, p4) => {
return Err(Error {
expected: vec![
Token::Type(Type::FieldElement),
Token::Private,
Token::Close,
],
got: t4,
pos: p4,
});
}
}
}
}
fn parse_function_return_types<T: Field>(
input: String,
pos: Position,
) -> Result<(Vec<Type>, String, Position), Error<T>> {
let mut types = Vec::new();
let mut s = input;
let mut p = pos;
loop {
match next_token(&s, &p) {
(Token::Type(t), s1, p1) => {
types.push(t);
match next_token::<T>(&s1, &p1) {
(Token::Comma, s3, p3) => {
s = s3;
p = p3;
}
(Token::Close, _, _) => return Ok((types, s1, p1)),
(t3, _, p3) => {
return Err(Error {
expected: vec![Token::Comma, Token::Close],
got: t3,
pos: p3,
});
}
}
}
(Token::Close, _, _) => return Ok((vec![], s, p)),
(t4, _, p4) => {
return Err(Error {
expected: vec![
Token::Type(Type::FieldElement),
Token::Private,
Token::Close,
],
got: t4,
pos: p4,
});
}
}
}
}
pub fn parse_function<T: Field, R: BufRead>(
mut lines: &mut Lines<R>,
input: &String,
pos: &Position,
) -> Result<(Identifier, FunctionNode<T>, Position), Error<T>> {
let mut current_line = pos.line;
let (id, args, sig) = parse_function_header(input, pos)?;
current_line += 1;
// parse function body
let mut stats = Vec::new();
loop {
match lines.next() {
Some(Ok(ref x)) if x.trim().starts_with("//") || x.trim() == "" => {} // skip
Some(Ok(ref x)) => match parse_statement(
&mut lines,
x,
&Position {
line: current_line,
col: 1,
},
) {
Ok((ref statements, _, ref pos)) => {
for stat in statements {
stats.push(stat.clone());
}
match statements[0].value {
Statement::Return(_) => {
break;
}
_ => {
current_line = pos.line // update the interal line counter to continue where statement ended.
}
}
}
Err(err) => return Err(err),
},
None => panic!("Function {} does not return before program ends", id),
Some(Err(err)) => panic!("Error while reading function statements: {}", err),
}
current_line += 1;
}
match stats.last().clone().unwrap().value {
Statement::Return(_) => {}
ref x => panic!("Last function statement not Return: {}", x),
}
let next_pos = Position {
line: current_line,
col: 1,
};
Ok((
id,
Node::new(
*pos,
next_pos,
Function {
arguments: args,
statements: stats,
signature: sig,
},
),
next_pos,
))
}

View file

@ -1,118 +0,0 @@
use zokrates_field::field::Field;
use crate::parser::tokenize::{next_token, Position, Token};
use crate::parser::Error;
use crate::parser::tokenize::parse_quoted_path;
use crate::absy::Node;
use crate::imports::{Import, ImportNode};
pub fn parse_import<T: Field>(
input: &String,
pos: &Position,
) -> Result<(ImportNode, Position), Error<T>> {
match next_token(input, pos) {
(Token::DoubleQuote, s1, p1) => match parse_quoted_path(&s1, &p1) {
(Token::Path(code_path), s2, p2) => match next_token::<T>(&s2, &p2) {
(Token::As, s3, p3) => match next_token(&s3, &p3) {
(Token::Ide(id), _, p4) => {
return Ok((
Node::new(*pos, p4, Import::new_with_alias(code_path, &id)),
p4,
));
}
(t4, _, p4) => {
return Err(Error {
expected: vec![Token::Ide("ide".to_string())],
got: t4,
pos: p4,
});
}
},
(Token::Unknown(_), _, p3) => {
return Ok((Node::new(*pos, p3, Import::new(code_path)), p3));
}
(t3, _, p3) => {
return Err(Error {
expected: vec![
Token::Ide("id".to_string()),
Token::Unknown("".to_string()),
],
got: t3,
pos: p3,
});
}
},
(t2, _, p2) => Err(Error {
expected: vec![Token::Path("./path/to/program.code".to_string())],
got: t2,
pos: p2,
}),
},
(t1, _, p1) => Err(Error {
expected: vec![Token::DoubleQuote],
got: t1,
pos: p1,
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::field::FieldPrime;
#[test]
fn quoted_path() {
let pos = Position { line: 45, col: 121 };
let string = String::from("./foo.code\" as foo");
let path: Token<FieldPrime> = Token::Path("./foo.code".to_string());
assert_eq!(
(path, " as foo".to_string(), pos.col(11 as isize)),
parse_quoted_path(&string, &pos)
);
}
#[test]
fn import() {
let pos = Position { line: 45, col: 121 };
let string = String::from("import \"./foo.code\"");
let import: Token<FieldPrime> = Token::Import;
assert_eq!(
(import, " \"./foo.code\"".to_string(), pos.col(6 as isize)),
next_token(&string, &pos)
)
}
#[test]
fn parse_import_test() {
let pos = Position { line: 45, col: 121 };
let string = String::from("\"./foo.code\"");
let import = Import::new("./foo.code".to_string()).into();
let position = Position {
line: 45,
col: pos.col + 1 + "./foo.code".len() + 1,
};
assert_eq!(
Ok((import, position)),
parse_import::<FieldPrime>(&string, &pos)
)
}
#[test]
fn parse_import_with_alias_test() {
let pos = Position { line: 45, col: 121 };
let string = String::from("\"./foo.code\" as myalias");
let alias = "myalias".to_string();
let import = Import::new_with_alias("./foo.code".to_string(), &alias).into();
let position = Position {
line: 45,
col: pos.col + string.len(),
};
assert_eq!(
Ok((import, position)),
parse_import::<FieldPrime>(&string, &pos)
)
}
}

View file

@ -1,8 +0,0 @@
mod expression;
mod expression_list;
mod function;
mod import;
mod module;
mod statement;
pub use self::module::parse_module;

View file

@ -1,69 +0,0 @@
use zokrates_field::field::Field;
use std::io::prelude::*;
use crate::parser::error::Error;
use crate::parser::tokenize::{next_token, Position, Token};
use super::function::parse_function;
use super::import::parse_import;
use crate::absy::{FunctionDeclaration, FunctionSymbol, Module, Node};
pub fn parse_module<T: Field, R: BufRead>(reader: &mut R) -> Result<Module<T>, Error<T>> {
let mut current_line = 1;
let mut lines = reader.lines();
let mut functions = Vec::new();
let mut imports = Vec::new();
loop {
match lines.next() {
Some(Ok(ref x)) if x.trim().starts_with("//") || x.trim() == "" => current_line += 1,
Some(Ok(ref x)) => {
let p0 = Position {
line: current_line,
col: 1,
};
match next_token(x, &p0) {
(Token::Import, ref s1, ref p1) => match parse_import(s1, p1) {
Ok((import, p2)) => {
imports.push(import);
current_line = p2.line; // this is the line of the import statement
current_line += 1;
}
Err(err) => return Err(err),
},
(Token::Def, ref s1, ref p1) => match parse_function(&mut lines, s1, p1) {
Ok((identifier, function, p2)) => {
functions.push(Node::new(
p0,
p2,
FunctionDeclaration {
id: identifier,
symbol: FunctionSymbol::Here(function),
},
));
current_line = p2.line; // this is the line of the return statement
current_line += 1;
}
Err(err) => return Err(err),
},
(t1, _, p1) => {
return Err(Error {
expected: vec![Token::Def],
got: t1,
pos: p1,
});
}
}
}
None => break,
Some(Err(err)) => panic!("Error while reading function definitions: {}", err),
}
}
Ok(Module {
functions: functions,
imports,
})
}

View file

@ -1,789 +0,0 @@
use zokrates_field::field::Field;
use std::io::prelude::*;
use std::io::Lines;
use crate::parser::tokenize::{next_token, Position, Token};
use crate::parser::Error;
use crate::parser::tokenize::skip_whitespaces;
use super::expression::{
parse_array_select, parse_expr, parse_expr1, parse_function_call, parse_term1,
};
use super::expression_list::parse_expression_list;
use crate::absy::{
Assignee, AssigneeNode, Expression, Node, Statement, StatementNode, Variable, VariableNode,
};
use crate::types::Type;
pub fn parse_statement<T: Field, R: BufRead>(
lines: &mut Lines<R>,
input: &String,
pos: &Position,
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
match next_token::<T>(input, pos) {
(Token::Type(t), s1, p1) => parse_declaration_definition(t, s1, p1),
(Token::Ide(x1), s1, p1) => parse_statement1(x1, s1, p1),
(Token::If, ..) | (Token::Open, ..) | (Token::Num(_), ..) => match parse_expr(input, pos) {
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
(Token::Eqeq, s3, p3) => match parse_expr(&s3, &p3) {
Ok((e4, s4, p4)) => match next_token(&s4, &p4) {
(Token::InlineComment(_), ref s5, _) => {
assert_eq!(s5, "");
Ok((
vec![Node::new(*pos, p4, Statement::Condition(e2, e4))],
s4,
p4,
))
}
(Token::Unknown(ref t5), ref s5, _) if t5 == "" => {
assert_eq!(s5, "");
Ok((
vec![Node::new(*pos, p4, Statement::Condition(e2, e4))],
s4,
p4,
))
}
(t5, _, p5) => Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t5,
pos: p5,
}),
},
Err(err) => Err(err),
},
(t3, _, p3) => Err(Error {
expected: vec![Token::Eqeq],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
},
(Token::For, s1, p1) => {
match next_token(&s1, &p1) {
(Token::Type(t), s0, p0) => {
match next_token(&s0, &p0) {
(Token::Ide(x2), s2, p2) => {
match next_token(&s2, &p2) {
(Token::In, s3, p3) => {
match next_token(&s3, &p3) {
(Token::Num(x4), s4, p4) => {
match next_token(&s4, &p4) {
(Token::Dotdot, s5, p5) => {
match next_token(&s5, &p5) {
(Token::Num(x6), s6, p6) => {
match next_token(&s6, &p6) {
(Token::Do, s7, p7) => {
match next_token(&s7, &p7) {
(
Token::InlineComment(_),
ref s8,
_,
) => {
assert_eq!(s8, "");
}
(
Token::Unknown(ref t8),
ref s8,
_,
)
if t8 == "" =>
{
assert_eq!(s8, "");
}
(t8, _, p8) => {
return Err(Error {
expected: vec![
Token::Unknown(
"".to_string(),
),
],
got: t8,
pos: p8,
})
}
}
let mut current_line = p7.line;
let mut statements = Vec::new();
loop {
current_line += 1;
match lines.next() {
Some(Ok(ref x)) if x.trim().starts_with("//") || x.trim() == "" => {}, // skip
Some(Ok(ref x)) if x.trim().starts_with("endfor") => {
let offset = skip_whitespaces(x);
let s8 = x[offset + 6..].to_string();
let p8 = Position{ line: current_line, col: offset + 7 };
match next_token(&s8, &p8) {
(Token::InlineComment(_), ref s9, _) => {
assert_eq!(s9, "");
return Ok((vec![Node::new(*pos, p8, Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements))], s8, p8))
}
(Token::Unknown(ref t9), ref s9, _) if t9 == "" => {
assert_eq!(s9, "");
return Ok((vec![Node::new(*pos, p8, Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements))], s8, p8))
},
(t9, _, p9) => return Err(Error { expected: vec![Token::Unknown("".to_string())], got: t9 , pos: p9 }),
}
},
Some(Ok(ref x)) if !x.trim().starts_with("return") => match parse_statement(lines, x, &Position { line: current_line, col: 1 }) {
Ok((mut statement, ..)) => statements.append(&mut statement),
Err(err) => return Err(err),
},
Some(Err(err)) => panic!("Error while reading Definitions: {}", err),
Some(Ok(ref x)) => {
let (t, ..) = next_token(x, &Position{ line: current_line, col: 1 });
return Err(Error { expected: vec![Token::ErrIde, Token::ErrNum, Token::If, Token::Open, Token::Hash, Token::For, Token::Endfor], got: t , pos: Position{ line: current_line, col: 1 } })
},
None => return Err(Error { expected: vec![Token::ErrIde, Token::ErrNum, Token::If, Token::Open, Token::Hash, Token::For], got: Token::Unknown("".to_string()) , pos: Position{ line: current_line, col: 1 } }),
}
}
}
(t7, _, p7) => Err(Error {
expected: vec![Token::Do],
got: t7,
pos: p7,
}),
}
}
(t6, _, p6) => Err(Error {
expected: vec![Token::ErrNum],
got: t6,
pos: p6,
}),
}
}
(t5, _, p5) => Err(Error {
expected: vec![Token::Dotdot],
got: t5,
pos: p5,
}),
}
}
(t4, _, p4) => Err(Error {
expected: vec![Token::ErrNum],
got: t4,
pos: p4,
}),
}
}
(t3, _, p3) => Err(Error {
expected: vec![Token::In],
got: t3,
pos: p3,
}),
}
}
(t2, _, p2) => Err(Error {
expected: vec![Token::ErrIde],
got: t2,
pos: p2,
}),
}
}
(t0, _, p0) => Err(Error {
expected: vec![Token::Type(Type::FieldElement)],
got: t0,
pos: p0,
}),
}
}
(Token::Return, s1, p1) => match parse_expression_list(s1, p1) {
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
(Token::InlineComment(_), ref s3, _) => {
assert_eq!(s3, "");
Ok((vec![Node::new(*pos, p2, Statement::Return(e2))], s2, p2))
}
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
assert_eq!(s3, "");
Ok((vec![Node::new(*pos, p2, Statement::Return(e2))], s2, p2))
}
(t3, _, p3) => Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
},
(Token::Def, _, p1) => Err(Error {
expected: vec![Token::Return],
got: Token::Def,
pos: p1,
}), // This just covers an error case: Def Token is never part of a valid statement and indicates that a return statement is missing.
(t1, _, p1) => Err(Error {
expected: vec![
Token::ErrIde,
Token::ErrNum,
Token::If,
Token::Open,
Token::Return,
],
got: t1,
pos: p1,
}),
}
}
fn parse_definition1<T: Field>(
x: AssigneeNode<T>,
input: String,
pos: Position,
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
match parse_expr(&input, &pos) {
Ok((e1, s1, p1)) => match next_token(&s1, &p1) {
(Token::InlineComment(_), ref s2, _) => {
assert_eq!(s2, "");
match e1.value {
e @ Expression::FunctionCall(..) => Ok((
vec![Node::new(
x.start,
p1,
Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)),
)],
s1,
p1,
)),
e => Ok((
vec![Node::new(
x.start,
p1,
Statement::Definition(x, Node::new(pos, p1, e)),
)],
s1,
p1,
)),
}
}
(Token::Unknown(ref t2), ref s2, _) if t2 == "" => {
assert_eq!(s2, "");
match e1.value {
e @ Expression::FunctionCall(..) => Ok((
vec![Node::new(
x.start,
p1,
Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)),
)],
s1,
p1,
)),
e => Ok((
vec![Node::new(
x.start,
p1,
Statement::Definition(x, Node::new(pos, p1, e)),
)],
s1,
p1,
)),
}
}
(t2, _, p2) => Err(Error {
expected: vec![Token::Unknown("".to_string())],
got: t2,
pos: p2,
}),
},
Err(err) => Err(err),
}
}
fn parse_declaration_definition<T: Field>(
t: Type,
input: String,
pos: Position,
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
match next_token::<T>(&input, &pos) {
(Token::Ide(x), s0, p0) => match next_token(&s0, &p0) {
(Token::Eq, s1, p1) => match parse_expr(&s1, &p1) {
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
(Token::InlineComment(_), ref s3, _) => {
assert_eq!(s3, "");
match e2.value {
e @ Expression::FunctionCall(..) => Ok((
vec![
Node::new(
pos,
p0,
Statement::Declaration(Node::new(
pos,
p0,
Variable::new(x.clone(), t),
)),
),
Node::new(
pos,
p2,
Statement::MultipleDefinition(
vec![Node::new(pos, p1, Assignee::Identifier(x))],
Node::new(p1, p2, e),
),
),
],
s2,
p2,
)),
e => Ok((
vec![
Node::new(
pos,
p0,
Statement::Declaration(Node::new(
pos,
p0,
Variable::new(x.clone(), t),
)),
),
Node::new(
pos,
p2,
Statement::Definition(
Node::new(pos, p1, Assignee::Identifier(x)),
Node::new(p1, p2, e),
),
),
],
s2,
p2,
)),
}
}
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
assert_eq!(s3, "");
match e2.value {
e @ Expression::FunctionCall(..) => Ok((
vec![
Node::new(
pos,
p0,
Statement::Declaration(Node::new(
pos,
p0,
Variable::new(x.clone(), t),
)),
),
Node::new(
pos,
p2,
Statement::MultipleDefinition(
vec![Node::new(pos, p1, Assignee::Identifier(x))],
Node::new(p1, p2, e),
),
),
],
s2,
p2,
)),
e => Ok((
vec![
Node::new(
pos,
p0,
Statement::Declaration(Node::new(
pos,
p0,
Variable::new(x.clone(), t),
)),
),
Node::new(
pos,
p2,
Statement::Definition(
Node::new(pos, p1, Assignee::Identifier(x)),
Node::new(p1, p2, e),
),
),
],
s2,
p2,
)),
}
}
(t3, _, p3) => Err(Error {
expected: vec![
Token::Add,
Token::Sub,
Token::Pow,
Token::Mult,
Token::Div,
Token::Unknown("".to_string()),
],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
},
(Token::Comma, s1, p1) => match parse_identifier_list1(x, Some(t.clone()), s1, p1) {
// if we find a comma, parse the rest of the destructure
Ok((e2, d2, s2, p2)) => match next_token(&s2, &p2) {
// then we should have an equal sign
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
Ok((e4, s4, p4)) => {
let mut statements: Vec<_> = d2
.iter()
.map(|v| {
Node::new(v.start, v.end, Statement::Declaration(v.clone()))
})
.collect();
statements.push(Node::new(
pos,
p4,
Statement::MultipleDefinition(e2, e4),
));
Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression
}
Err(err) => Err(err),
},
(t3, _, p3) => Err(Error {
expected: vec![Token::Eq],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
},
(t1, _, p1) => Err(Error {
expected: vec![Token::Eq, Token::Unknown("".to_string())],
got: t1,
pos: p1,
}),
},
(t0, _, p0) => Err(Error {
expected: vec![Token::Ide(String::from("identifier"))],
got: t0,
pos: p0,
}),
}
}
// parse statement that starts with an identifier
fn parse_statement1<T: Field>(
ide: String,
input: String,
pos: Position,
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
let ide_start_position = Position {
col: pos.col - ide.len(),
..pos
};
match next_token::<T>(&input, &pos) {
(Token::Eq, s1, p1) => parse_definition1(
Node::new(ide_start_position, pos, Assignee::Identifier(ide)),
s1,
p1,
),
(Token::Comma, s1, p1) => match parse_identifier_list1(ide, None, s1, p1) {
// if we find a comma, parse the rest of the destructure
Ok((e2, d2, s2, p2)) => match next_token(&s2, &p2) {
// then we should have an equal sign
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
Ok((e4, s4, p4)) => {
let mut statements: Vec<_> = d2
.iter()
.map(|v| Node::new(v.start, v.end, Statement::Declaration(v.clone())))
.collect();
statements.push(Node::new(pos, p4, Statement::MultipleDefinition(e2, e4)));
Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression
}
Err(err) => Err(err),
},
(t3, _, p3) => Err(Error {
expected: vec![Token::Eq],
got: t3,
pos: p3,
}),
},
Err(err) => Err(err),
},
(Token::Open, s1, p1) => match parse_function_call(ide, s1, p1) {
Ok((e3, s3, p3)) => match parse_expr1(e3, s3, p3) {
Ok((e4, s4, p4)) => match next_token(&s4, &p4) {
(Token::Eqeq, s5, p5) => match parse_expr(&s5, &p5) {
Ok((e6, s6, p6)) => match next_token(&s6, &p6) {
(Token::InlineComment(_), ref s7, _) => {
assert_eq!(s7, "");
Ok((
vec![Node::new(pos, p6, Statement::Condition(e4, e6))],
s6,
p6,
))
}
(Token::Unknown(ref t7), ref s7, _) if t7 == "" => {
assert_eq!(s7, "");
Ok((
vec![Node::new(pos, p6, Statement::Condition(e4, e6))],
s6,
p6,
))
}
(t7, _, p7) => Err(Error {
expected: vec![
Token::Add,
Token::Sub,
Token::Pow,
Token::Mult,
Token::Div,
Token::Unknown("".to_string()),
],
got: t7,
pos: p7,
}),
},
Err(err) => Err(err),
},
(t4, _, p4) => Err(Error {
expected: vec![Token::Eqeq],
got: t4,
pos: p4,
}),
},
Err(err) => Err(err),
},
Err(err) => Err(err),
},
(Token::LeftBracket, s1, p1) => match parse_array_select(ide, s1, p1) {
Ok((e3, s3, p3)) => match parse_expr1(e3, s3, p3) {
Ok((e4, s4, p4)) => match next_token(&s4, &p4) {
(Token::Eqeq, s5, p5) => match parse_expr(&s5, &p5) {
Ok((e6, s6, p6)) => match next_token(&s6, &p6) {
(Token::InlineComment(_), ref s7, _) => {
assert_eq!(s7, "");
Ok((
vec![Node::new(pos, p6, Statement::Condition(e4, e6))],
s6,
p6,
))
}
(Token::Unknown(ref t7), ref s7, _) if t7 == "" => {
assert_eq!(s7, "");
Ok((
vec![Node::new(pos, p6, Statement::Condition(e4, e6))],
s6,
p6,
))
}
(t7, _, p7) => Err(Error {
expected: vec![
Token::Add,
Token::Sub,
Token::Pow,
Token::Mult,
Token::Div,
Token::Unknown("".to_string()),
],
got: t7,
pos: p7,
}),
},
Err(err) => Err(err),
},
(Token::Eq, s5, p5) => parse_definition1(AssigneeNode::from(e4), s5, p5),
(t4, _, p4) => Err(Error {
expected: vec![Token::Eqeq],
got: t4,
pos: p4,
}),
},
Err(err) => Err(err),
},
Err(err) => Err(err),
},
_ => match parse_term1(
Node::new(ide_start_position, pos, Expression::Identifier(ide)),
input,
pos,
) {
Ok((e2, s2, p2)) => match parse_expr1(e2, s2, p2) {
Ok((e3, s3, p3)) => match next_token(&s3, &p3) {
(Token::Eqeq, s4, p4) => match parse_expr(&s4, &p4) {
Ok((e5, s5, p5)) => match next_token(&s5, &p5) {
(Token::InlineComment(_), ref s6, _) => {
assert_eq!(s6, "");
Ok((
vec![Node::new(pos, p5, Statement::Condition(e3, e5))],
s5,
p5,
))
}
(Token::Unknown(ref t6), ref s6, _) if t6 == "" => {
assert_eq!(s6, "");
Ok((
vec![Node::new(pos, p5, Statement::Condition(e3, e5))],
s5,
p5,
))
}
(t6, _, p6) => Err(Error {
expected: vec![
Token::Add,
Token::Sub,
Token::Pow,
Token::Mult,
Token::Div,
Token::Unknown("".to_string()),
],
got: t6,
pos: p6,
}),
},
Err(err) => Err(err),
},
(t4, _, p4) => Err(Error {
expected: vec![Token::Eqeq],
got: t4,
pos: p4,
}),
},
Err(err) => Err(err),
},
Err(err) => Err(err),
},
}
}
// parse an expression list starting with an identifier
pub fn parse_identifier_list1<T: Field>(
head: String,
_type: Option<Type>,
input: String,
pos: Position,
) -> Result<(Vec<AssigneeNode<T>>, Vec<VariableNode>, String, Position), Error<T>> {
let mut res = Vec::new();
let mut decl = Vec::new();
let start_pos = Position {
col: pos.col - head.len(),
..pos
};
res.push(Node::new(
start_pos,
pos,
Assignee::Identifier(head.clone()),
));
match _type {
Some(t) => {
decl.push(Node::new(start_pos, pos, Variable::new(head, t)));
}
_ => {}
};
parse_comma_separated_identifier_list_rec(input, pos, &mut res, &mut decl)
}
fn parse_comma_separated_identifier_list_rec<T: Field>(
input: String,
pos: Position,
mut acc: &mut Vec<AssigneeNode<T>>,
mut decl: &mut Vec<VariableNode>,
) -> Result<(Vec<AssigneeNode<T>>, Vec<VariableNode>, String, Position), Error<T>> {
match next_token(&input, &pos) {
(Token::Type(t), s1, p1) => match next_token::<T>(&s1, &p1) {
(Token::Ide(id), s2, p2) => {
acc.push(Node::new(p1, p2, Assignee::Identifier(id.clone())));
decl.push(Node::new(pos, p2, Variable::new(id, t)));
match next_token::<T>(&s2, &p2) {
(Token::Comma, s3, p3) => {
parse_comma_separated_identifier_list_rec(s3, p3, &mut acc, &mut decl)
}
(..) => Ok((acc.to_vec(), decl.to_vec(), s2, p2)),
}
}
(t2, _, p2) => Err(Error {
expected: vec![Token::Ide(String::from("ide"))],
got: t2,
pos: p2,
}),
},
(Token::Ide(id), s1, p1) => {
acc.push(Node::new(pos, p1, Assignee::Identifier(id)));
match next_token::<T>(&s1, &p1) {
(Token::Comma, s2, p2) => {
parse_comma_separated_identifier_list_rec(s2, p2, &mut acc, &mut decl)
}
(..) => Ok((acc.to_vec(), decl.to_vec(), s1, p1)),
}
}
(t1, _, p1) => Err(Error {
expected: vec![Token::Ide(String::from("ide"))],
got: t1,
pos: p1,
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::field::FieldPrime;
mod parse_statement1 {
use super::*;
#[test]
fn left_call_in_assertion() {
let pos = Position { line: 45, col: 121 };
let string = String::from("() == 1");
let cond = Statement::Condition(
Expression::FunctionCall(String::from("foo"), vec![]).into(),
Expression::Number(FieldPrime::from(1)).into(),
)
.into();
assert_eq!(
Ok((vec![cond], String::from(""), pos.col(string.len() as isize))),
parse_statement1(String::from("foo"), string, pos)
);
}
#[test]
fn left_call_in_assertion2() {
let pos = Position { line: 45, col: 121 };
let string = String::from("() - g() - 1 == 1");
let cond = Statement::Condition(
Expression::Sub(
box Expression::Sub(
box Expression::FunctionCall(String::from("foo"), vec![]).into(),
box Expression::FunctionCall(String::from("g"), vec![]).into(),
)
.into(),
box Expression::Number(FieldPrime::from(1)).into(),
)
.into(),
Expression::Number(FieldPrime::from(1)).into(),
)
.into();
assert_eq!(
Ok((vec![cond], String::from(""), pos.col(string.len() as isize))),
parse_statement1(String::from("foo"), string, pos)
);
}
#[test]
fn left_select_in_assertion2() {
let pos = Position { line: 45, col: 121 };
let string = String::from("[3] - g() - 1 == 1");
let cond = Statement::Condition(
Expression::Sub(
box Expression::Sub(
box Expression::Select(
box Expression::Identifier(String::from("foo")).into(),
box Expression::Number(FieldPrime::from(3)).into(),
)
.into(),
box Expression::FunctionCall(String::from("g"), vec![]).into(),
)
.into(),
box Expression::Number(FieldPrime::from(1)).into(),
)
.into(),
Expression::Number(FieldPrime::from(1)).into(),
)
.into();
assert_eq!(
Ok((vec![cond], String::from(""), pos.col(string.len() as isize))),
parse_statement1(String::from("foo"), string, pos)
);
}
}
}

View file

@ -1,7 +1,3 @@
mod position;
mod token;
mod tokenizer;
pub use self::position::Position;
pub use self::token::Token;
pub use self::tokenizer::*;

View file

@ -1,113 +0,0 @@
use crate::types::Type;
use std::fmt;
use zokrates_field::field::Field;
#[derive(PartialEq)]
pub enum Token<T: Field> {
Open,
Close,
Comma,
Colon,
Hash,
Eq,
Return,
Def,
If,
Then,
Else,
Fi,
For,
In,
Dotdot,
Do,
Endfor,
Lt,
Le,
Eqeq,
Ge,
Gt,
And,
Or,
Add,
Not,
Sub,
Mult,
Div,
Pow,
Private,
Ide(String),
Num(T),
Unknown(String),
InlineComment(String),
Import,
DoubleQuote,
Path(String),
As,
LeftBracket,
RightBracket,
// following used for error messages
ErrIde,
ErrNum,
// types
Type(Type),
Arrow,
}
impl<T: Field> fmt::Display for Token<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Token::Open => write!(f, "("),
Token::Close => write!(f, ")"),
Token::Comma => write!(f, ","),
Token::Colon => write!(f, ":"),
Token::Hash => write!(f, "#"),
Token::Eq => write!(f, "="),
Token::Def => write!(f, "def"),
Token::Return => write!(f, "return"),
Token::If => write!(f, "if"),
Token::Then => write!(f, "then"),
Token::Else => write!(f, "else"),
Token::Fi => write!(f, "fi"),
Token::For => write!(f, "for"),
Token::In => write!(f, "in"),
Token::Dotdot => write!(f, ".."),
Token::Do => write!(f, "do"),
Token::Endfor => write!(f, "endfor"),
Token::Lt => write!(f, "<"),
Token::Le => write!(f, "<="),
Token::Eqeq => write!(f, "=="),
Token::Ge => write!(f, ">="),
Token::Gt => write!(f, ">"),
Token::And => write!(f, "&&"),
Token::Not => write!(f, "!"),
Token::Or => write!(f, "||"),
Token::Add => write!(f, "+"),
Token::Sub => write!(f, "-"),
Token::Mult => write!(f, "*"),
Token::Div => write!(f, "/"),
Token::Pow => write!(f, "**"),
Token::Private => write!(f, "private"),
Token::Ide(ref x) => write!(f, "{}", x),
Token::Num(ref x) => write!(f, "{}", x),
Token::Unknown(ref x) => write!(f, "{}", x),
Token::InlineComment(ref x) => write!(f, "// {}", x),
Token::Import => write!(f, "import"),
Token::DoubleQuote => write!(f, "\""),
Token::Path(ref x) => write!(f, "\"{}\"", x),
Token::As => write!(f, "as"),
Token::ErrIde => write!(f, "identifier"),
Token::ErrNum => write!(f, "number"),
Token::Type(ref x) => write!(f, "{}", x),
Token::Arrow => write!(f, "->"),
Token::LeftBracket => write!(f, "["),
Token::RightBracket => write!(f, "]"),
}
}
}
impl<T: Field> fmt::Debug for Token<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ref t @ Token::ErrIde | ref t @ Token::ErrNum => write!(f, "{}", t),
ref t => write!(f, "`{}`", t),
}
}
}

View file

@ -1,554 +0,0 @@
use super::position::Position;
use super::token::Token;
use crate::types::Type;
use zokrates_field::field::Field;
pub fn parse_num<T: Field>(input: &String, pos: &Position) -> (Token<T>, String, Position) {
let mut end = 0;
loop {
match input.chars().nth(end) {
Some(x) => match x {
'0'...'9' => end += 1,
_ => break,
},
None => break,
}
}
assert!(end > 0);
(
Token::Num(T::try_from_dec_str(&input[0..end]).unwrap()),
input[end..].to_string(),
Position {
line: pos.line,
col: pos.col + end,
},
)
}
pub fn parse_ide<T: Field>(input: &String, pos: &Position) -> (Token<T>, String, Position) {
assert!(match input.chars().next().unwrap() {
'a'...'z' | 'A'...'Z' => true,
_ => false,
});
let mut end = 1;
loop {
match input.chars().nth(end) {
Some(x) => match x {
'a'...'z' | 'A'...'Z' | '0'...'9' => end += 1,
_ => break,
},
None => break,
}
}
let token = match &input[0..end] {
"import" => Token::Import,
"as" => Token::As,
"if" => Token::If,
"then" => Token::Then,
"else" => Token::Else,
"fi" => Token::Fi,
"for" => Token::For,
"in" => Token::In,
"do" => Token::Do,
"endfor" => Token::Endfor,
"private" => Token::Private,
"def" => Token::Def,
"return" => Token::Return,
"field" => match input.chars().nth(end) {
Some('[') => {
let size_start = end + 1;
let mut size_len = 0;
loop {
match input.chars().nth(size_start + size_len) {
Some(x) => match x {
'0'...'9' => size_len += 1,
_ => break,
},
None => break,
}
}
assert!(size_len > 0);
let size_end = size_start + size_len;
match input.chars().nth(size_end) {
Some(']') => {
end = size_end + 1;
Token::Type(Type::FieldElementArray(
input[size_start..(size_start + size_len)]
.parse::<usize>()
.unwrap(),
))
}
_ => panic!(),
}
}
_ => Token::Type(Type::FieldElement),
},
"bool" => Token::Type(Type::Boolean),
_ => Token::Ide(input[0..end].to_string()),
};
(
token,
input[end..].to_string(),
Position {
line: pos.line,
col: pos.col + end,
},
)
}
pub fn skip_whitespaces(input: &String) -> usize {
let mut i = 0;
loop {
match input.chars().nth(i) {
Some(' ') | Some('\t') => i += 1,
_ => return i,
}
}
}
pub fn parse_quoted_path<T: Field>(input: &String, pos: &Position) -> (Token<T>, String, Position) {
let mut end = 0;
loop {
match input.chars().nth(end) {
Some(x) => {
end += 1;
match x {
'\"' => break,
_ => continue,
}
}
None => panic!("Invalid import path, should end with '\"'"),
}
}
(
Token::Path(input[0..end - 1].to_string()),
input[end..].to_string(),
Position {
line: pos.line,
col: pos.col + end,
},
)
}
pub fn next_token<T: Field>(input: &String, pos: &Position) -> (Token<T>, String, Position) {
let offset = skip_whitespaces(input);
match input.chars().nth(offset) {
Some('(') => (
Token::Open,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some(')') => (
Token::Close,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some(',') => (
Token::Comma,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some(':') => (
Token::Colon,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('#') => (
Token::Hash,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('=') => match input.chars().nth(offset + 1) {
Some('=') => (
Token::Eqeq,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Eq,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('<') => match input.chars().nth(offset + 1) {
Some('=') => (
Token::Le,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Lt,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('>') => match input.chars().nth(offset + 1) {
Some('=') => (
Token::Ge,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Gt,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('&') => match input.chars().nth(offset + 1) {
Some('&') => (
Token::And,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Unknown(String::from("&")),
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('|') => match input.chars().nth(offset + 1) {
Some('|') => (
Token::Or,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Unknown(String::from("|")),
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('!') => (
Token::Not,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('+') => (
Token::Add,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('-') => match input.chars().nth(offset + 1) {
Some('>') => (
Token::Arrow,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Sub,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('"') => (
Token::DoubleQuote,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('*') => match input.chars().nth(offset + 1) {
Some('*') => (
Token::Pow,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
_ => (
Token::Mult,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some('[') => (
Token::LeftBracket,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some(']') => (
Token::RightBracket,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
Some('/') => match input.chars().nth(offset + 1) {
Some('/') => (
Token::InlineComment(input[offset + 2..].to_string()),
"".to_string(),
Position {
line: pos.line,
col: pos.col + offset + input[offset + 2..].len(),
},
),
_ => (
Token::Div,
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
Some(_) if input[offset..].starts_with("..") => (
Token::Dotdot,
input[offset + 2..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 2,
},
),
Some(x) => match x {
'0'...'9' => parse_num(
&input[offset..].to_string(),
&Position {
line: pos.line,
col: pos.col + offset,
},
),
'a'...'z' | 'A'...'Z' => parse_ide(
&input[offset..].to_string(),
&Position {
line: pos.line,
col: pos.col + offset,
},
),
_ => (
Token::Unknown(x.to_string()),
input[offset + 1..].to_string(),
Position {
line: pos.line,
col: pos.col + offset + 1,
},
),
},
None => (
Token::Unknown("".to_string()),
input[offset..].to_string(),
Position {
line: pos.line,
col: pos.col + offset,
},
),
}
}
#[cfg(test)]
mod tests {
use super::*;
use zokrates_field::field::FieldPrime;
#[test]
fn inline_comment() {
let pos = Position {
line: 100,
col: 258,
};
let (token, _, _) = next_token::<FieldPrime>(&" //inline comment".to_string(), &pos);
assert_eq!(Token::InlineComment("inline comment".to_string()), token);
}
mod types {
use super::*;
#[test]
fn field() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Type::<FieldPrime>(Type::FieldElement),
String::from(""),
pos.col(5)
),
parse_ide(&"field".to_string(), &pos)
);
}
#[test]
fn field_array() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Type::<FieldPrime>(Type::FieldElementArray(123)),
String::from(" "),
pos.col(10)
),
parse_ide(&"field[123] ".to_string(), &pos)
);
}
#[test]
fn field_array_2() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Type::<FieldPrime>(Type::FieldElementArray(1)),
String::from(" "),
pos.col(8)
),
parse_ide(&"field[1] ".to_string(), &pos)
);
}
#[should_panic]
#[test]
fn field_array_no_size() {
let pos = Position { line: 45, col: 121 };
parse_ide::<FieldPrime>(&"field[] ".to_string(), &pos);
}
#[should_panic]
#[test]
fn field_array_unclosed() {
let pos = Position { line: 45, col: 121 };
parse_ide::<FieldPrime>(&"field[123 ".to_string(), &pos);
}
#[should_panic]
#[test]
fn field_array_empty_unclosed() {
let pos = Position { line: 45, col: 121 };
parse_ide::<FieldPrime>(&"field[ ".to_string(), &pos);
}
#[test]
fn field_array_empty_unopened() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Type::<FieldPrime>(Type::FieldElement),
String::from("] "),
pos.col(5)
),
parse_ide::<FieldPrime>(&"field] ".to_string(), &pos)
);
}
}
mod parse_num {
use super::*;
#[test]
fn single() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Num(FieldPrime::from(12234)),
String::from(""),
pos.col(5)
),
parse_num(&"12234".to_string(), &pos)
);
}
#[test]
fn add() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Num(FieldPrime::from(354)),
String::from("+879"),
pos.col(3)
),
parse_num(&"354+879".to_string(), &pos)
);
}
#[test]
fn space_after() {
let pos = Position { line: 45, col: 121 };
assert_eq!(
(
Token::Num(FieldPrime::from(354)),
String::from(" "),
pos.col(3)
),
parse_num(&"354 ".to_string(), &pos)
);
}
#[test]
#[should_panic]
fn space_before() {
let pos = Position { line: 45, col: 121 };
parse_num::<FieldPrime>(&" 354".to_string(), &pos);
}
#[test]
#[should_panic]
fn x_before() {
let pos = Position { line: 45, col: 121 };
parse_num::<FieldPrime>(&"x324312".to_string(), &pos);
}
}
}

View file

@ -138,6 +138,9 @@ impl ProofSystem for G16 {
mod serialize {
use crate::proof_system::bn128::utils::bellman::{
parse_fr_json, parse_g1_hex, parse_g1_json, parse_g2_hex, parse_g2_json,
};
use bellman::groth16::{Proof, VerifyingKey};
use pairing::bn256::{Bn256, Fr};
@ -149,25 +152,18 @@ mod serialize {
vk.delta = {}
vk.gammaABC.len() = {}
{}",
vk.alpha_g1,
vk.beta_g2,
vk.gamma_g2,
vk.delta_g2,
parse_g1_hex(&vk.alpha_g1),
parse_g2_hex(&vk.beta_g2),
parse_g2_hex(&vk.gamma_g2),
parse_g2_hex(&vk.delta_g2),
vk.ic.len(),
vk.ic
.iter()
.enumerate()
.map(|(i, x)| format!("vk.gammaABC[{}] = {}", i, x))
.map(|(i, x)| format!("vk.gammaABC[{}] = {}", i, parse_g1_hex(x)))
.collect::<Vec<_>>()
.join("\n")
)
.replace("G2(x=Fq2(Fq(", "[")
.replace("), y=Fq(", ", ")
.replace("G1(x=Fq(", "")
.replace(") + Fq(", ", ")
.replace("))", "")
.replace(") * u), y=Fq2(Fq(", "], [")
.replace(") * u", "]")
}
pub fn serialize_proof(p: &Proof<Bn256>, inputs: &Vec<Fr>) -> String {
@ -180,25 +176,15 @@ mod serialize {
}},
\"inputs\": [{}]
}}",
p.a,
p.b,
p.c,
parse_g1_json(&p.a),
parse_g2_json(&p.b),
parse_g1_json(&p.a),
inputs
.iter()
.map(|v| format!("\"{}\"", v))
.map(parse_fr_json)
.collect::<Vec<_>>()
.join(", "),
)
.replace("G2(x=Fq2(Fq(", "[[\"")
.replace("), y=Fq(", "\", \"")
.replace("G1(x=Fq(", "[\"")
.replace(") + Fq(", "\", \"")
.replace(") * u), y=Fq2(Fq(", "\"], [\"")
.replace(") * u]", "\"]]")
.replace(") * u))", "\"]]")
.replace("))", "\"]")
.replace("Fr(", "")
.replace(")", "")
}
}

View file

@ -1,6 +1,6 @@
extern crate libc;
use self::libc::{c_char, c_int, uint8_t};
use self::libc::{c_char, c_int};
use ir;
use proof_system::bn128::utils::libsnark::{prepare_generate_proof, prepare_setup};
use proof_system::bn128::utils::solidity::{SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB};
@ -21,9 +21,9 @@ impl GM17 {
extern "C" {
fn _gm17_setup(
A: *const uint8_t,
B: *const uint8_t,
C: *const uint8_t,
A: *const u8,
B: *const u8,
C: *const u8,
A_len: c_int,
B_len: c_int,
C_len: c_int,
@ -37,9 +37,9 @@ extern "C" {
fn _gm17_generate_proof(
pk_path: *const c_char,
proof_path: *const c_char,
publquery_inputs: *const uint8_t,
publquery_inputs: *const u8,
publquery_inputs_length: c_int,
private_inputs: *const uint8_t,
private_inputs: *const u8,
private_inputs_length: c_int,
) -> bool;
}

View file

@ -1,6 +1,6 @@
extern crate libc;
use self::libc::{c_char, c_int, uint8_t};
use self::libc::{c_char, c_int};
use ir;
use proof_system::bn128::utils::libsnark::{prepare_generate_proof, prepare_setup};
use proof_system::bn128::utils::solidity::{SOLIDITY_G2_ADDITION_LIB, SOLIDITY_PAIRING_LIB};
@ -22,9 +22,9 @@ impl PGHR13 {
extern "C" {
fn _pghr13_setup(
A: *const uint8_t,
B: *const uint8_t,
C: *const uint8_t,
A: *const u8,
B: *const u8,
C: *const u8,
A_len: c_int,
B_len: c_int,
C_len: c_int,
@ -38,9 +38,9 @@ extern "C" {
fn _pghr13_generate_proof(
pk_path: *const c_char,
proof_path: *const c_char,
public_inputs: *const uint8_t,
public_inputs: *const u8,
public_inputs_length: c_int,
private_inputs: *const uint8_t,
private_inputs: *const u8,
private_inputs_length: c_int,
) -> bool;
}

View file

@ -1,6 +1,6 @@
extern crate rand;
use crate::ir::{LinComb, Prog, Statement, Witness};
use crate::ir::{CanonicalLinComb, Prog, Statement, Witness};
use bellman::groth16::Proof;
use bellman::groth16::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
@ -14,6 +14,8 @@ use zokrates_field::field::{Field, FieldPrime};
use self::rand::*;
use crate::flat_absy::FlatVariable;
pub use self::parse::*;
#[derive(Clone)]
pub struct Computation<T: Field> {
program: Prog<T>,
@ -37,7 +39,7 @@ impl<T: Field> Computation<T> {
}
fn bellman_combination<CS: ConstraintSystem<Bn256>>(
l: LinComb<FieldPrime>,
l: CanonicalLinComb<FieldPrime>,
cs: &mut CS,
symbols: &mut BTreeMap<FlatVariable, Variable>,
witness: &mut Witness<FieldPrime>,
@ -131,10 +133,20 @@ impl Prog<FieldPrime> {
for statement in main.statements {
match statement {
Statement::Constraint(quad, lin) => {
let a = &bellman_combination(quad.left.clone(), cs, &mut symbols, &mut witness);
let b =
&bellman_combination(quad.right.clone(), cs, &mut symbols, &mut witness);
let c = &bellman_combination(lin, cs, &mut symbols, &mut witness);
let a = &bellman_combination(
quad.left.clone().as_canonical(),
cs,
&mut symbols,
&mut witness,
);
let b = &bellman_combination(
quad.right.clone().as_canonical(),
cs,
&mut symbols,
&mut witness,
);
let c =
&bellman_combination(lin.as_canonical(), cs, &mut symbols, &mut witness);
cs.enforce(|| "Constraint", |lc| lc + a, |lc| lc + b, |lc| lc + c);
}
@ -189,10 +201,99 @@ impl Circuit<Bn256> for Computation<FieldPrime> {
}
}
mod parse {
use lazy_static::lazy_static;
use super::*;
use regex::Regex;
lazy_static! {
static ref G2_REGEX: Regex = Regex::new(r"G2\(x=Fq2\(Fq\((?P<x0>0[xX][0-9a-fA-F]{64})\) \+ Fq\((?P<x1>0[xX][0-9a-fA-F]{64})\) \* u\), y=Fq2\(Fq\((?P<y0>0[xX][0-9a-fA-F]{64})\) \+ Fq\((?P<y1>0[xX][0-9a-fA-F]{64})\) \* u\)\)").unwrap();
}
lazy_static! {
static ref G1_REGEX: Regex = Regex::new(
r"G1\(x=Fq\((?P<x>0[xX][0-9a-fA-F]{64})\), y=Fq\((?P<y>0[xX][0-9a-fA-F]{64})\)\)"
)
.unwrap();
}
lazy_static! {
static ref FR_REGEX: Regex = Regex::new(r"Fr\((?P<x>0[xX][0-9a-fA-F]{64})\)").unwrap();
}
fn parse_g1(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> (String, String) {
let raw_e = e.to_string();
let captures = G1_REGEX.captures(&raw_e).unwrap();
(
captures.name(&"x").unwrap().as_str().to_string(),
captures.name(&"y").unwrap().as_str().to_string(),
)
}
fn parse_g2(
e: &<Bn256 as bellman::pairing::Engine>::G2Affine,
) -> (String, String, String, String) {
let raw_e = e.to_string();
let captures = G2_REGEX.captures(&raw_e).unwrap();
(
captures.name(&"x1").unwrap().as_str().to_string(),
captures.name(&"x0").unwrap().as_str().to_string(),
captures.name(&"y1").unwrap().as_str().to_string(),
captures.name(&"y0").unwrap().as_str().to_string(),
)
}
fn parse_fr(e: &Fr) -> String {
let raw_e = e.to_string();
let captures = FR_REGEX.captures(&raw_e).unwrap();
captures.name(&"x").unwrap().as_str().to_string()
}
pub fn parse_g1_json(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> String {
let parsed = parse_g1(e);
format!("[\"{}\", \"{}\"]", parsed.0, parsed.1)
}
pub fn parse_g2_json(e: &<Bn256 as bellman::pairing::Engine>::G2Affine) -> String {
let parsed = parse_g2(e);
format!(
"[[\"{}\", \"{}\"], [\"{}\", \"{}\"]]",
parsed.0, parsed.1, parsed.2, parsed.3,
)
}
pub fn parse_fr_json(e: &Fr) -> String {
let parsed = parse_fr(e);
format!("\"{}\"", parsed)
}
pub fn parse_g1_hex(e: &<Bn256 as bellman::pairing::Engine>::G1Affine) -> String {
let parsed = parse_g1(e);
format!("{}, {}", parsed.0, parsed.1)
}
pub fn parse_g2_hex(e: &<Bn256 as bellman::pairing::Engine>::G2Affine) -> String {
let parsed = parse_g2(e);
format!("[{}, {}], [{}, {}]", parsed.0, parsed.1, parsed.2, parsed.3,)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::Function;
use crate::ir::{Function, LinComb};
use zokrates_field::field::FieldPrime;
mod prove {

View file

@ -7,6 +7,7 @@
//! @date 2017
use crate::absy::variable::Variable;
use crate::absy::Identifier;
use crate::absy::*;
use crate::typed_absy::*;
use std::collections::{HashMap, HashSet};
@ -35,13 +36,13 @@ impl fmt::Display for Error {
}
}
pub struct FunctionQuery {
id: String,
pub struct FunctionQuery<'ast> {
id: Identifier<'ast>,
inputs: Vec<Type>,
outputs: Vec<Option<Type>>,
}
impl fmt::Display for FunctionQuery {
impl<'ast> fmt::Display for FunctionQuery<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
r#try!(write!(f, "("));
for (i, t) in self.inputs.iter().enumerate() {
@ -64,8 +65,12 @@ impl fmt::Display for FunctionQuery {
}
}
impl FunctionQuery {
fn new(id: String, inputs: &Vec<Type>, outputs: &Vec<Option<Type>>) -> FunctionQuery {
impl<'ast> FunctionQuery<'ast> {
fn new(
id: Identifier<'ast>,
inputs: &Vec<Type>,
outputs: &Vec<Option<Type>>,
) -> FunctionQuery<'ast> {
FunctionQuery {
id,
inputs: inputs.clone(),
@ -83,7 +88,7 @@ impl FunctionQuery {
})
}
fn match_funcs(&self, funcs: &HashSet<FunctionKey>) -> Vec<FunctionKey> {
fn match_funcs(&self, funcs: &HashSet<FunctionKey<'ast>>) -> Vec<FunctionKey<'ast>> {
funcs
.iter()
.filter(|func| self.match_func(func))
@ -93,34 +98,33 @@ impl FunctionQuery {
}
#[derive(Clone, Debug)]
pub struct ScopedVariable {
id: Variable,
pub struct ScopedVariable<'ast> {
id: Variable<'ast>,
level: usize,
}
impl Hash for ScopedVariable {
impl<'ast> Hash for ScopedVariable<'ast> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.id.hash(state);
}
}
impl PartialEq for ScopedVariable {
impl<'ast> PartialEq for ScopedVariable<'ast> {
fn eq(&self, other: &ScopedVariable) -> bool {
self.id.id == other.id.id
}
}
impl Eq for ScopedVariable {}
impl<'ast> Eq for ScopedVariable<'ast> {}
// Checker, checks the semantics of a program.
pub struct Checker {
scope: HashSet<ScopedVariable>,
functions: HashSet<FunctionKey>,
pub struct Checker<'ast> {
scope: HashSet<ScopedVariable<'ast>>,
functions: HashSet<FunctionKey<'ast>>,
level: usize,
}
impl Checker {
pub fn new() -> Checker {
impl<'ast> Checker<'ast> {
fn new() -> Checker<'ast> {
Checker {
scope: HashSet::new(),
functions: HashSet::new(),
@ -128,10 +132,14 @@ impl Checker {
}
}
pub fn check_program<T: Field>(
pub fn check<T: Field>(prog: Program<'ast, T>) -> Result<TypedProgram<'ast, T>, Vec<Error>> {
Checker::new().check_program(prog)
}
fn check_program<T: Field>(
&mut self,
program: Program<T>,
) -> Result<TypedProgram<T>, Vec<Error>> {
program: Program<'ast, T>,
) -> Result<TypedProgram<'ast, T>, Vec<Error>> {
let mut modules = program.modules;
let main = modules.remove(&program.main).unwrap();
let mut typed_modules = HashMap::new();
@ -150,10 +158,10 @@ impl Checker {
fn check_module<T: Field>(
&mut self,
module: Module<T>,
modules: &mut Modules<T>,
typed_modules: &mut TypedModules<T>,
) -> Result<TypedModule<T>, Vec<Error>> {
module: Module<'ast, T>,
modules: &mut Modules<'ast, T>,
typed_modules: &mut TypedModules<'ast, T>,
) -> Result<TypedModule<'ast, T>, Vec<Error>> {
let mut errors = vec![];
let mut checked_functions = HashMap::new();
@ -254,8 +262,8 @@ impl Checker {
fn check_function<T: Field>(
&mut self,
funct_node: FunctionNode<T>,
) -> Result<TypedFunction<T>, Vec<Error>> {
funct_node: FunctionNode<'ast, T>,
) -> Result<TypedFunction<'ast, T>, Vec<Error>> {
let mut errors = vec![];
let funct = funct_node.value;
@ -267,7 +275,7 @@ impl Checker {
let mut statements_checked = vec![];
for stat in funct.statements.iter() {
for stat in funct.statements {
match self.check_statement(stat, &funct.signature.outputs) {
Ok(statement) => {
statements_checked.push(statement);
@ -295,10 +303,10 @@ impl Checker {
fn check_function_symbol<T: Field>(
&mut self,
funct_symbol: FunctionSymbol<T>,
modules: &mut Modules<T>,
typed_modules: &mut TypedModules<T>,
) -> Result<Vec<TypedFunctionSymbol<T>>, Vec<Error>> {
funct_symbol: FunctionSymbol<'ast, T>,
modules: &mut Modules<'ast, T>,
typed_modules: &mut TypedModules<'ast, T>,
) -> Result<Vec<TypedFunctionSymbol<'ast, T>>, Vec<Error>> {
let mut errors = vec![];
match funct_symbol {
@ -375,14 +383,16 @@ impl Checker {
fn check_statement<T: Field>(
&mut self,
stat: &StatementNode<T>,
stat: StatementNode<'ast, T>,
header_return_types: &Vec<Type>,
) -> Result<TypedStatement<T>, Error> {
) -> Result<TypedStatement<'ast, T>, Error> {
let pos = stat.pos();
match stat.value {
Statement::Return(ref list) => {
Statement::Return(list) => {
let mut expression_list_checked = vec![];
for e in list.value.expressions.clone() {
let e_checked = self.check_expression(&e)?;
for e in list.value.expressions {
let e_checked = self.check_expression(e)?;
expression_list_checked.push(e_checked);
}
@ -394,7 +404,7 @@ impl Checker {
match return_statement_types == *header_return_types {
true => Ok(TypedStatement::Return(expression_list_checked)),
false => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!(
"Expected ({}) in return statement, found ({})",
header_return_types
@ -411,14 +421,14 @@ impl Checker {
}),
}
}
Statement::Declaration(ref var) => match self.insert_scope(var.clone().value) {
true => Ok(TypedStatement::Declaration(var.value.clone().into())),
Statement::Declaration(var) => match self.insert_scope(var.clone().value) {
true => Ok(TypedStatement::Declaration(var.value.into())),
false => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!("Duplicate declaration for variable named {}", var.value.id),
}),
},
Statement::Definition(ref assignee, ref expr) => {
Statement::Definition(assignee, expr) => {
// we create multidef when rhs is a function call to benefit from inference
// check rhs is not a function call here
match expr.value {
@ -427,11 +437,11 @@ impl Checker {
}
// check the expression to be assigned
let checked_expr = self.check_expression(&expr)?;
let checked_expr = self.check_expression(expr)?;
let expression_type = checked_expr.get_type();
// check that the assignee is declared and is well formed
let var = self.check_assignee(&assignee)?;
let var = self.check_assignee(assignee)?;
let var_type = var.get_type();
@ -439,35 +449,35 @@ impl Checker {
match var_type == expression_type {
true => Ok(TypedStatement::Definition(var, checked_expr)),
false => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!(
"Expression {} of type {} cannot be assigned to {} of type {}",
expr, expression_type, assignee, var_type
checked_expr, expression_type, var, var_type
),
}),
}
}
Statement::Condition(ref lhs, ref rhs) => {
let checked_lhs = self.check_expression(&lhs)?;
let checked_rhs = self.check_expression(&rhs)?;
Statement::Condition(lhs, rhs) => {
let checked_lhs = self.check_expression(lhs)?;
let checked_rhs = self.check_expression(rhs)?;
match (checked_lhs.clone(), checked_rhs.clone()) {
(ref r, ref l) if r.get_type() == l.get_type() => {
(ref l, ref r) if r.get_type() == l.get_type() => {
Ok(TypedStatement::Condition(checked_lhs, checked_rhs))
}
(e1, e2) => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {:?} to {} of type {:?}",
lhs,
checked_lhs,
e1.get_type(),
rhs,
checked_rhs,
e2.get_type(),
),
}),
}
}
Statement::For(ref var, ref from, ref to, ref statements) => {
Statement::For(var, from, to, statements) => {
self.enter_scope();
self.check_for_var(&var)?;
@ -483,29 +493,29 @@ impl Checker {
self.exit_scope();
Ok(TypedStatement::For(
var.value.clone().into(),
from.clone(),
to.clone(),
var.value.into(),
from,
to,
checked_statements,
))
}
Statement::MultipleDefinition(ref assignees, ref rhs) => {
Statement::MultipleDefinition(assignees, rhs) => {
match rhs.value {
// Right side has to be a function call
Expression::FunctionCall(ref fun_id, ref arguments) => {
Expression::FunctionCall(fun_id, arguments) => {
// find lhs types
let mut vars_types: Vec<Option<Type>> = vec![];
let mut var_names = vec![];
for assignee in assignees {
let (name, t) = match assignee.value {
Assignee::Identifier(ref name) => {
Assignee::Identifier(name) => {
Ok((name, match self.get_scope(&name) {
None => None,
Some(sv) => Some(sv.id.get_type())
}))
}
ref a => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!("Left hand side of function return assignment must be a list of identifiers, found {}", a)})
}?;
vars_types.push(t);
@ -514,41 +524,44 @@ impl Checker {
// find arguments types
let mut arguments_checked = vec![];
for arg in arguments {
let arg_checked = self.check_expression(&arg)?;
let arg_checked = self.check_expression(arg)?;
arguments_checked.push(arg_checked);
}
let arguments_types =
arguments_checked.iter().map(|a| a.get_type()).collect();
let query =
FunctionQuery::new(fun_id.to_string(), &arguments_types, &vars_types);
let candidates = self.find_candidates(&query).clone();
let query = FunctionQuery::new(&fun_id, &arguments_types, &vars_types);
let candidates = self.find_candidates(&query);
match candidates.len() {
// the function has to be defined
1 => {
let f = &candidates[0];
let lhs = var_names.iter().enumerate().map(|(index, name)|
Variable::new(name.to_string(), f.signature.outputs[index].clone())
);
// we can infer the left hand side to be typed as the return values
let lhs: Vec<_> = var_names.iter().enumerate().map(|(index, name)|
Variable::new(*name, f.signature.outputs[index].clone())
).collect();
// we can infer the left hand side to be typed as the return values
for var in lhs.clone() {
self.insert_scope(var);
}
let assignees: Vec<_> = lhs.iter().map(|v| v.clone().into()).collect();
Ok(TypedStatement::MultipleDefinition(lhs.map(|v| v.into()).collect(), TypedExpressionList::FunctionCall(FunctionKey {id: f.id.clone(), signature: f.signature.clone()}, arguments_checked, f.signature.outputs.clone())))
let call = TypedExpressionList::FunctionCall(f.clone(), arguments_checked, f.signature.outputs.clone());
for var in lhs {
self.insert_scope(var);
}
Ok(TypedStatement::MultipleDefinition(assignees, call))
},
0 => Err(Error { pos: Some(stat.pos()),
0 => Err(Error { pos: Some(pos),
message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
_ => Err(Error { pos: Some(stat.pos()),
_ => Err(Error { pos: Some(pos),
message: format!("Function call for function {} with arguments {:?} is ambiguous.", fun_id, arguments_types) }),
}
}
_ => Err(Error {
pos: Some(stat.pos()),
pos: Some(pos),
message: format!("{} should be a FunctionCall", rhs),
}),
}
@ -558,29 +571,35 @@ impl Checker {
fn check_assignee<T: Field>(
&mut self,
assignee: &AssigneeNode<T>,
) -> Result<TypedAssignee<T>, Error> {
assignee: AssigneeNode<'ast, T>,
) -> Result<TypedAssignee<'ast, T>, Error> {
let pos = assignee.pos();
// check that the assignee is declared
match assignee.value {
Assignee::Identifier(ref variable_name) => match self.get_scope(&variable_name) {
Some(var) => Ok(TypedAssignee::Identifier(var.id.clone().into())),
Assignee::Identifier(variable_name) => match self.get_scope(&variable_name) {
Some(var) => Ok(TypedAssignee::Identifier(
crate::typed_absy::Variable::with_id_and_type(
variable_name.into(),
var.id.get_type(),
),
)),
None => Err(Error {
pos: Some(assignee.pos()),
message: format!("Undeclared variable: {:?}", variable_name),
}),
},
Assignee::ArrayElement(ref assignee, ref index) => {
let checked_assignee = self.check_assignee(&assignee)?;
let checked_index = self.check_expression(&index)?;
Assignee::ArrayElement(box assignee, box index) => {
let checked_assignee = self.check_assignee(assignee)?;
let checked_index = self.check_expression(index)?;
let checked_typed_index = match checked_index {
TypedExpression::FieldElement(e) => Ok(e),
e => Err(Error {
pos: Some(assignee.pos()),
pos: Some(pos),
message: format!(
"Expected array {} index to have type field, found {}",
assignee,
checked_assignee,
e.get_type()
),
}),
@ -596,37 +615,39 @@ impl Checker {
fn check_expression<T: Field>(
&mut self,
expr: &ExpressionNode<T>,
) -> Result<TypedExpression<T>, Error> {
match &expr.value {
&Expression::Identifier(ref name) => {
expr: ExpressionNode<'ast, T>,
) -> Result<TypedExpression<'ast, T>, Error> {
let pos = expr.pos();
match expr.value {
Expression::Identifier(name) => {
// check that `id` is defined in the scope
match self.get_scope(&name) {
Some(v) => match v.id.get_type() {
Type::Boolean => Ok(BooleanExpression::Identifier(name.to_string()).into()),
Type::Boolean => Ok(BooleanExpression::Identifier(name.into()).into()),
Type::FieldElement => {
Ok(FieldElementExpression::Identifier(name.to_string()).into())
Ok(FieldElementExpression::Identifier(name.into()).into())
}
Type::FieldElementArray(n) => {
Ok(FieldElementArrayExpression::Identifier(n, name.to_string()).into())
Ok(FieldElementArrayExpression::Identifier(n, name.into()).into())
}
},
None => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!("Identifier is undefined: {}", name),
}),
}
}
&Expression::Add(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Add(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(FieldElementExpression::Add(box e1, box e2).into())
}
(t1, t2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
@ -636,16 +657,16 @@ impl Checker {
}),
}
}
&Expression::Sub(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Sub(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(FieldElementExpression::Sub(box e1, box e2).into())
}
(t1, t2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
@ -655,16 +676,16 @@ impl Checker {
}),
}
}
&Expression::Mult(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Mult(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(FieldElementExpression::Mult(box e1, box e2).into())
}
(t1, t2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
@ -674,16 +695,16 @@ impl Checker {
}),
}
}
&Expression::Div(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Div(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(FieldElementExpression::Div(box e1, box e2).into())
}
(t1, t2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
@ -693,16 +714,16 @@ impl Checker {
}),
}
}
&Expression::Pow(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Pow(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => Ok(
TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)),
),
(t1, t2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
@ -712,10 +733,10 @@ impl Checker {
}),
}
}
&Expression::IfElse(ref condition, ref consequence, ref alternative) => {
let condition_checked = self.check_expression(&condition)?;
let consequence_checked = self.check_expression(&consequence)?;
let alternative_checked = self.check_expression(&alternative)?;
Expression::IfElse(box condition, box consequence, box alternative) => {
let condition_checked = self.check_expression(condition)?;
let consequence_checked = self.check_expression(consequence)?;
let alternative_checked = self.check_expression(alternative)?;
match condition_checked {
TypedExpression::Boolean(condition) => {
@ -732,13 +753,13 @@ impl Checker {
_ => unimplemented!()
}
false => Err(Error {
pos: Some(alternative.pos()),
pos: Some(pos),
message: format!("{{consequence}} and {{alternative}} in `if/else` expression should have the same type, found {}, {}", consequence_type, alternative_type)
})
}
}
c => Err(Error {
pos: Some(condition.pos()),
pos: Some(pos),
message: format!(
"{{condition}} after `if` should be a boolean, found {}",
c.get_type()
@ -746,12 +767,12 @@ impl Checker {
}),
}
}
&Expression::Number(ref n) => Ok(FieldElementExpression::Number(n.clone()).into()),
&Expression::FunctionCall(ref fun_id, ref arguments) => {
Expression::Number(n) => Ok(FieldElementExpression::Number(n).into()),
Expression::FunctionCall(fun_id, arguments) => {
// check the arguments
let mut arguments_checked = vec![];
for arg in arguments {
let arg_checked = self.check_expression(&arg.clone())?;
let arg_checked = self.check_expression(arg)?;
arguments_checked.push(arg_checked);
}
@ -762,7 +783,7 @@ impl Checker {
// outside of multidef, function calls must have a single return value
// we use type inference to determine the type of the return, so we don't specify it
let query = FunctionQuery::new(fun_id.to_string(), &arguments_types, &vec![None]);
let query = FunctionQuery::new(&fun_id, &arguments_types, &vec![None]);
let candidates = self.find_candidates(&query);
@ -795,7 +816,7 @@ impl Checker {
_ => unimplemented!(),
},
n => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"{} returns {} values but is called outside of a definition",
@ -805,7 +826,7 @@ impl Checker {
}
}
0 => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Function definition for function {} with signature {} not found.",
@ -815,15 +836,15 @@ impl Checker {
_ => panic!("duplicate definition should have been caught before the call"),
}
}
&Expression::Lt(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Lt(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(BooleanExpression::Lt(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
@ -834,15 +855,15 @@ impl Checker {
}),
}
}
&Expression::Le(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Le(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(BooleanExpression::Le(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
@ -853,15 +874,15 @@ impl Checker {
}),
}
}
&Expression::Eq(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Eq(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(BooleanExpression::Eq(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
@ -872,15 +893,15 @@ impl Checker {
}),
}
}
&Expression::Ge(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Ge(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(BooleanExpression::Ge(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
@ -891,15 +912,15 @@ impl Checker {
}),
}
}
&Expression::Gt(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Gt(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(BooleanExpression::Gt(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
@ -910,16 +931,15 @@ impl Checker {
}),
}
}
&Expression::Select(ref array, ref index) => {
let array = self.check_expression(&array)?;
let index = self.check_expression(&index)?;
match (array.clone(), index.clone()) {
(
TypedExpression::FieldElementArray(ref a),
TypedExpression::FieldElement(ref i),
) => Ok(FieldElementExpression::Select(box a.clone(), box i.clone()).into()),
Expression::Select(box array, box index) => {
let array = self.check_expression(array)?;
let index = self.check_expression(index)?;
match (array, index) {
(TypedExpression::FieldElementArray(a), TypedExpression::FieldElement(i)) => {
Ok(FieldElementExpression::Select(box a, box i).into())
}
(a, e) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Cannot access element {} on expression of type {}",
e,
@ -928,7 +948,7 @@ impl Checker {
}),
}
}
&Expression::InlineArray(ref expressions) => {
Expression::InlineArray(expressions) => {
// we should have at least one expression
let size = expressions.len();
assert!(size > 0);
@ -950,7 +970,7 @@ impl Checker {
let unwrapped_e = match e {
TypedExpression::FieldElement(e) => Ok(e),
e => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Expected {} to have type {}, but type is {}",
@ -966,7 +986,7 @@ impl Checker {
Ok(FieldElementArrayExpression::Value(size, unwrapped_expressions).into())
}
_ => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"Only arrays of {} are supported, found {}",
@ -976,15 +996,15 @@ impl Checker {
}),
}
}
&Expression::And(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::And(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
Ok(BooleanExpression::And(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!(
"cannot apply boolean operators to {} and {}",
@ -994,26 +1014,26 @@ impl Checker {
}),
}
}
&Expression::Or(ref e1, ref e2) => {
let e1_checked = self.check_expression(&e1)?;
let e2_checked = self.check_expression(&e2)?;
Expression::Or(box e1, box e2) => {
let e1_checked = self.check_expression(e1)?;
let e2_checked = self.check_expression(e2)?;
match (e1_checked, e2_checked) {
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
Ok(BooleanExpression::Or(box e1, box e2).into())
}
(e1, e2) => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()),
}),
}
}
&Expression::Not(ref e) => {
Expression::Not(box e) => {
let e_checked = self.check_expression(e)?;
match e_checked {
TypedExpression::Boolean(e) => Ok(BooleanExpression::Not(box e).into()),
e => Err(Error {
pos: Some(expr.pos()),
pos: Some(pos),
message: format!("cannot negate {}", e.get_type()),
}),
@ -1022,21 +1042,21 @@ impl Checker {
}
}
fn get_scope(&self, variable_name: &String) -> Option<&ScopedVariable> {
fn get_scope(&self, variable_name: &Identifier<'ast>) -> Option<&ScopedVariable> {
self.scope.get(&ScopedVariable {
id: Variable::new(variable_name.clone(), Type::FieldElement),
id: Variable::new(*variable_name, Type::FieldElement),
level: 0,
})
}
fn insert_scope(&mut self, v: Variable) -> bool {
fn insert_scope(&mut self, v: Variable<'ast>) -> bool {
self.scope.insert(ScopedVariable {
id: v,
level: self.level,
})
}
fn find_candidates(&self, query: &FunctionQuery) -> Vec<FunctionKey> {
fn find_candidates(&self, query: &FunctionQuery<'ast>) -> Vec<FunctionKey<'ast>> {
query.match_funcs(&self.functions)
}
@ -1135,11 +1155,11 @@ mod tests {
}
}
pub fn new_with_args(
pub fn new_with_args<'ast>(
scope: HashSet<ScopedVariable>,
level: usize,
functions: HashSet<FunctionKey>,
) -> Checker {
) -> Checker<'ast> {
Checker {
scope: scope,
functions: functions,

View file

@ -16,8 +16,8 @@ impl CoreLibInjector {
}
}
impl<T: Field> Folder<T> for CoreLibInjector {
fn fold_program(&mut self, p: TypedProgram<T>) -> TypedProgram<T> {
impl<'ast, T: Field> Folder<'ast, T> for CoreLibInjector {
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
// instanciate core lib functions
// IfElse
@ -30,21 +30,21 @@ impl<T: Field> Folder<T> for CoreLibInjector {
arguments: vec![
Parameter {
id: Variable {
id: "condition".to_string(),
id: "condition".into(),
_type: Type::Boolean,
},
private: true,
},
Parameter {
id: Variable {
id: "consequence".to_string(),
id: "consequence".into(),
_type: Type::FieldElement,
},
private: true,
},
Parameter {
id: Variable {
id: "alternative".to_string(),
id: "alternative".into(),
_type: Type::FieldElement,
},
private: true,
@ -52,30 +52,28 @@ impl<T: Field> Folder<T> for CoreLibInjector {
],
statements: vec![
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("condition_as_field")),
TypedAssignee::Identifier(Variable::field_element("condition_as_field".into())),
FieldElementExpression::FunctionCall(
FunctionKey::with_id("_bool_to_field").signature(
Signature::new()
.inputs(vec![Type::Boolean])
.outputs(vec![Type::FieldElement]),
),
vec![BooleanExpression::Identifier("condition".to_string()).into()],
vec![BooleanExpression::Identifier("condition".into()).into()],
)
.into(),
),
TypedStatement::Return(vec![FieldElementExpression::Add(
box FieldElementExpression::Mult(
box FieldElementExpression::Identifier("condition_as_field".to_string()),
box FieldElementExpression::Identifier("consequence".to_string()),
box FieldElementExpression::Identifier("condition_as_field".into()),
box FieldElementExpression::Identifier("consequence".into()),
),
box FieldElementExpression::Mult(
box FieldElementExpression::Sub(
box FieldElementExpression::Number(T::one()),
box FieldElementExpression::Identifier(
"condition_as_field".to_string(),
),
box FieldElementExpression::Identifier("condition_as_field".into()),
),
box FieldElementExpression::Identifier("alternative".to_string()),
box FieldElementExpression::Identifier("alternative".into()),
),
)
.into()]),
@ -118,7 +116,7 @@ impl<T: Field> Folder<T> for CoreLibInjector {
}
}
fn fold_module(&mut self, m: TypedModule<T>) -> TypedModule<T> {
fn fold_module(&mut self, m: TypedModule<'ast, T>) -> TypedModule<'ast, T> {
let mut functions = m.functions;
functions.extend(vec![
(

File diff suppressed because it is too large Load diff

View file

@ -6,13 +6,13 @@
mod core_lib_injector;
mod flat_propagation;
mod inline;
//mod inline;
mod power_check;
mod propagation;
mod unroll;
pub use self::core_lib_injector::CoreLibInjector;
use self::inline::Inliner;
//use self::inline::Inliner;
use self::power_check::PowerChecker;
use self::propagation::Propagator;
use self::unroll::Unroller;
@ -24,19 +24,17 @@ pub trait Analyse {
fn analyse(self) -> Self;
}
impl<T: Field> Analyse for TypedProgram<T> {
impl<'ast, T: Field> Analyse for TypedProgram<'ast, T> {
fn analyse(self) -> Self {
let r = PowerChecker::check(self);
// unroll
let r = Unroller::unroll(r);
// inline
let r = Inliner::inline(r);
print!("{}", r);
//let r = Inliner::inline(r);
// propagate
let r = Propagator::propagate(r);
// inject core lib
let r = CoreLibInjector::inject(r);
print!("{}", r);
r
}
}

View file

@ -15,8 +15,11 @@ impl PowerChecker {
}
}
impl<T: Field> Folder<T> for PowerChecker {
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
impl<'ast, T: Field> Folder<'ast, T> for PowerChecker {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Pow(box FieldElementExpression::Identifier(..), _) | FieldElementExpression::Pow(box FieldElementExpression::Number(..), _)=> {
fold_field_expression(self, e)

View file

@ -9,29 +9,29 @@ use crate::typed_absy::*;
use std::collections::HashMap;
use zokrates_field::field::Field;
pub struct Propagator<T: Field> {
constants: HashMap<TypedAssignee<T>, TypedExpression<T>>,
pub struct Propagator<'ast, T: Field> {
constants: HashMap<TypedAssignee<'ast, T>, TypedExpression<'ast, T>>,
}
impl<T: Field> Propagator<T> {
impl<'ast, T: Field> Propagator<'ast, T> {
fn new() -> Self {
Propagator {
constants: HashMap::new(),
}
}
pub fn propagate(p: TypedProgram<T>) -> TypedProgram<T> {
pub fn propagate(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
Propagator::new().fold_program(p)
}
}
impl<T: Field> Folder<T> for Propagator<T> {
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
self.constants = HashMap::new();
fold_function(self, f)
}
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
let res = match s {
TypedStatement::Declaration(v) => Some(TypedStatement::Declaration(v)),
TypedStatement::Return(expressions) => Some(TypedStatement::Return(expressions.into_iter().map(|e| self.fold_expression(e)).collect())),
@ -116,7 +116,10 @@ impl<T: Field> Folder<T> for Propagator<T> {
}
}
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Identifier(id) => {
match self
@ -241,8 +244,8 @@ impl<T: Field> Folder<T> for Propagator<T> {
fn fold_field_array_expression(
&mut self,
e: FieldElementArrayExpression<T>,
) -> FieldElementArrayExpression<T> {
e: FieldElementArrayExpression<'ast, T>,
) -> FieldElementArrayExpression<'ast, T> {
match e {
FieldElementArrayExpression::Identifier(size, id) => {
match self
@ -262,7 +265,10 @@ impl<T: Field> Folder<T> for Propagator<T> {
}
}
fn fold_boolean_expression(&mut self, e: BooleanExpression<T>) -> BooleanExpression<T> {
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
match e {
BooleanExpression::Identifier(id) => match self
.constants
@ -595,9 +601,9 @@ mod tests {
// a[1] = 42
// // constants should store [21, 42]
let declaration = TypedStatement::Declaration(Variable::field_array("a", 2));
let declaration = TypedStatement::Declaration(Variable::field_array("a".into(), 2));
let definition = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array("a", 2)),
TypedAssignee::Identifier(Variable::field_array("a".into(), 2)),
FieldElementArrayExpression::Value(
2,
vec![
@ -609,7 +615,7 @@ mod tests {
);
let overwrite = TypedStatement::Definition(
TypedAssignee::ArrayElement(
box TypedAssignee::Identifier(Variable::field_array("a", 2)),
box TypedAssignee::Identifier(Variable::field_array("a".into(), 2)),
box FieldElementExpression::Number(FieldPrime::from(1)),
),
FieldElementExpression::Number(FieldPrime::from(42)).into(),
@ -631,7 +637,10 @@ mod tests {
assert_eq!(
p.constants
.get(&TypedAssignee::Identifier(Variable::field_array("a", 2)))
.get(&TypedAssignee::Identifier(Variable::field_array(
"a".into(),
2
)))
.unwrap(),
&expected_value
);
@ -649,7 +658,10 @@ mod tests {
assert_eq!(
p.constants
.get(&TypedAssignee::Identifier(Variable::field_array("a", 2)))
.get(&TypedAssignee::Identifier(Variable::field_array(
"a".into(),
2
)))
.unwrap(),
&expected_value
);
@ -665,11 +677,11 @@ mod tests {
// a[1] = 42
// // constants should store nothing
let declaration = TypedStatement::Declaration(Variable::field_array("a", 2));
let declaration = TypedStatement::Declaration(Variable::field_array("a".into(), 2));
let overwrite = TypedStatement::Definition(
TypedAssignee::ArrayElement(
box TypedAssignee::Identifier(Variable::field_array("a", 2)),
box TypedAssignee::Identifier(Variable::field_array("a".into(), 2)),
box FieldElementExpression::Number(FieldPrime::from(1)),
),
FieldElementExpression::Number(FieldPrime::from(42)).into(),
@ -682,7 +694,10 @@ mod tests {
assert_eq!(
p.constants
.get(&TypedAssignee::Identifier(Variable::field_array("a", 2))),
.get(&TypedAssignee::Identifier(Variable::field_array(
"a".into(),
2
))),
None
);
}

View file

@ -10,27 +10,28 @@ use crate::types::Type;
use std::collections::HashMap;
use zokrates_field::field::Field;
pub struct Unroller {
substitution: HashMap<String, usize>,
pub struct Unroller<'ast> {
substitution: HashMap<Identifier<'ast>, usize>,
}
impl Unroller {
impl<'ast> Unroller<'ast> {
fn new() -> Self {
Unroller {
substitution: HashMap::new(),
}
}
fn issue_next_ssa_variable(&mut self, v: Variable) -> Variable {
fn issue_next_ssa_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
let res = match self.substitution.get(&v.id) {
Some(i) => Variable {
id: format!("{}_{}", v.id, i + 1),
..v
},
None => Variable {
id: format!("{}_{}", v.id, 0),
id: Identifier {
id: v.id.id,
version: i + 1,
stack: vec![],
},
..v
},
None => Variable { ..v.clone() },
};
self.substitution
.entry(v.id)
@ -44,8 +45,8 @@ impl Unroller {
}
}
impl<T: Field> Folder<T> for Unroller {
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
match s {
TypedStatement::Declaration(_) => vec![],
TypedStatement::Definition(TypedAssignee::Identifier(variable), expr) => {
@ -156,7 +157,7 @@ impl<T: Field> Folder<T> for Unroller {
}
}
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
self.substitution = HashMap::new();
for arg in &f.arguments {
self.substitution.insert(arg.id.id.clone(), 0);
@ -165,8 +166,11 @@ impl<T: Field> Folder<T> for Unroller {
fold_function(self, f)
}
fn fold_name(&mut self, n: String) -> String {
format!("{}_{}", n, self.substitution.get(&n).unwrap())
fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> {
Identifier {
version: self.substitution.get(&n).unwrap_or(&0).clone(),
..n
}
}
}
@ -194,42 +198,54 @@ mod tests {
// foo_2 = i_2
let s = TypedStatement::For(
Variable::field_element("i"),
Variable::field_element("i".into()),
FieldPrime::from(2),
FieldPrime::from(5),
vec![
TypedStatement::Declaration(Variable::field_element("foo")),
TypedStatement::Declaration(Variable::field_element("foo".into())),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("foo")),
FieldElementExpression::Identifier(String::from("i")).into(),
TypedAssignee::Identifier(Variable::field_element("foo".into())),
FieldElementExpression::Identifier("i".into()).into(),
),
],
);
let expected = vec![
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("i_0")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("i").version(0),
)),
FieldElementExpression::Number(FieldPrime::from(2)).into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("foo_0")),
FieldElementExpression::Identifier(String::from("i_0")).into(),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("foo").version(0),
)),
FieldElementExpression::Identifier(Identifier::from("i").version(0)).into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("i_1")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("i").version(1),
)),
FieldElementExpression::Number(FieldPrime::from(3)).into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("foo_1")),
FieldElementExpression::Identifier(String::from("i_1")).into(),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("foo").version(1),
)),
FieldElementExpression::Identifier(Identifier::from("i").version(1)).into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("i_2")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("i").version(2),
)),
FieldElementExpression::Number(FieldPrime::from(4)).into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("foo_2")),
FieldElementExpression::Identifier(String::from("i_2")).into(),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("foo").version(2),
)),
FieldElementExpression::Identifier(Identifier::from("i").version(2)).into(),
),
];
@ -253,38 +269,42 @@ mod tests {
let mut u = Unroller::new();
let s: TypedStatement<FieldPrime> =
TypedStatement::Declaration(Variable::field_element("a"));
TypedStatement::Declaration(Variable::field_element("a".into()));
assert_eq!(u.fold_statement(s), vec![]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a")),
TypedAssignee::Identifier(Variable::field_element("a".into())),
FieldElementExpression::Number(FieldPrime::from(5)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a_0")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(0)
)),
FieldElementExpression::Number(FieldPrime::from(5)).into()
)]
);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a")),
TypedAssignee::Identifier(Variable::field_element("a".into())),
FieldElementExpression::Number(FieldPrime::from(6)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a_1")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(1)
)),
FieldElementExpression::Number(FieldPrime::from(6)).into()
)]
);
let e: FieldElementExpression<FieldPrime> =
FieldElementExpression::Identifier(String::from("a"));
FieldElementExpression::Identifier("a".into());
assert_eq!(
u.fold_field_expression(e),
FieldElementExpression::Identifier(String::from("a_1"))
FieldElementExpression::Identifier(Identifier::from("a").version(1))
);
}
@ -301,25 +321,27 @@ mod tests {
let mut u = Unroller::new();
let s: TypedStatement<FieldPrime> =
TypedStatement::Declaration(Variable::field_element("a"));
TypedStatement::Declaration(Variable::field_element("a".into()));
assert_eq!(u.fold_statement(s), vec![]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a")),
TypedAssignee::Identifier(Variable::field_element("a".into())),
FieldElementExpression::Number(FieldPrime::from(5)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a_0")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(0)
)),
FieldElementExpression::Number(FieldPrime::from(5)).into()
)]
);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a")),
TypedAssignee::Identifier(Variable::field_element("a".into())),
FieldElementExpression::Add(
box FieldElementExpression::Identifier(String::from("a")),
box FieldElementExpression::Identifier("a".into()),
box FieldElementExpression::Number(FieldPrime::from(1)),
)
.into(),
@ -327,9 +349,11 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a_1")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(1)
)),
FieldElementExpression::Add(
box FieldElementExpression::Identifier(String::from("a_0")),
box FieldElementExpression::Identifier(Identifier::from("a").version(0)),
box FieldElementExpression::Number(FieldPrime::from(1))
)
.into()
@ -352,44 +376,49 @@ mod tests {
let mut u = Unroller::new();
let s: TypedStatement<FieldPrime> =
TypedStatement::Declaration(Variable::field_element("a"));
TypedStatement::Declaration(Variable::field_element("a".into()));
assert_eq!(u.fold_statement(s), vec![]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a")),
TypedAssignee::Identifier(Variable::field_element("a".into())),
FieldElementExpression::Number(FieldPrime::from(2)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("a_0")),
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(0)
)),
FieldElementExpression::Number(FieldPrime::from(2)).into()
)]
);
let s: TypedStatement<FieldPrime> = TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a".into())],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
.inputs(vec![Type::FieldElement])
.outputs(vec![Type::FieldElement]),
),
vec![FieldElementExpression::Identifier(String::from("a")).into()],
vec![FieldElementExpression::Identifier("a".into()).into()],
vec![Type::FieldElement],
),
);
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::MultipleDefinition(
vec![Variable::field_element("a_1")],
vec![Variable::field_element(Identifier::from("a").version(1))],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
.inputs(vec![Type::FieldElement])
.outputs(vec![Type::FieldElement])
),
vec![FieldElementExpression::Identifier(String::from("a_0")).into()],
vec![
FieldElementExpression::Identifier(Identifier::from("a").version(0))
.into()
],
vec![Type::FieldElement],
)
)]
@ -408,11 +437,11 @@ mod tests {
let mut u = Unroller::new();
let s: TypedStatement<FieldPrime> =
TypedStatement::Declaration(Variable::field_array("a", 2));
TypedStatement::Declaration(Variable::field_array("a".into(), 2));
assert_eq!(u.fold_statement(s), vec![]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array("a", 2)),
TypedAssignee::Identifier(Variable::field_array("a".into(), 2)),
FieldElementArrayExpression::Value(
2,
vec![
@ -426,7 +455,10 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array("a_0", 2)),
TypedAssignee::Identifier(Variable::field_array(
Identifier::from("a").version(0),
2
)),
FieldElementArrayExpression::Value(
2,
vec![
@ -440,7 +472,7 @@ mod tests {
let s: TypedStatement<FieldPrime> = TypedStatement::Definition(
TypedAssignee::ArrayElement(
box TypedAssignee::Identifier(Variable::field_array("a", 2)),
box TypedAssignee::Identifier(Variable::field_array("a".into(), 2)),
box FieldElementExpression::Number(FieldPrime::from(1)),
),
FieldElementExpression::Number(FieldPrime::from(2)).into(),
@ -449,7 +481,10 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array("a_1", 2)),
TypedAssignee::Identifier(Variable::field_array(
Identifier::from("a").version(1),
2
)),
FieldElementArrayExpression::Value(
2,
vec![
@ -462,7 +497,7 @@ mod tests {
box FieldElementExpression::Select(
box FieldElementArrayExpression::Identifier(
2,
String::from("a_0")
Identifier::from("a").version(0)
),
box FieldElementExpression::Number(FieldPrime::from(0))
),
@ -476,7 +511,7 @@ mod tests {
box FieldElementExpression::Select(
box FieldElementArrayExpression::Identifier(
2,
String::from("a_0")
Identifier::from("a").version(0)
),
box FieldElementExpression::Number(FieldPrime::from(1))
),

View file

@ -3,42 +3,45 @@
use crate::typed_absy::*;
use zokrates_field::field::Field;
pub trait Folder<T: Field>: Sized {
fn fold_program(&mut self, p: TypedProgram<T>) -> TypedProgram<T> {
pub trait Folder<'ast, T: Field>: Sized {
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
fold_program(self, p)
}
fn fold_module(&mut self, p: TypedModule<T>) -> TypedModule<T> {
fn fold_module(&mut self, p: TypedModule<'ast, T>) -> TypedModule<'ast, T> {
fold_module(self, p)
}
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
fold_function(self, f)
}
fn fold_function_symbol(&mut self, s: TypedFunctionSymbol<T>) -> TypedFunctionSymbol<T> {
fn fold_function_symbol(
&mut self,
s: TypedFunctionSymbol<'ast, T>,
) -> TypedFunctionSymbol<'ast, T> {
fold_function_symbol(self, s)
}
fn fold_parameter(&mut self, p: Parameter) -> Parameter {
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
fold_function(self, f)
}
fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> {
Parameter {
id: self.fold_variable(p.id),
..p
}
}
fn fold_name(&mut self, n: String) -> String {
fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> {
n
}
fn fold_variable(&mut self, v: Variable) -> Variable {
fn fold_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
Variable {
id: self.fold_name(v.id),
..v
}
}
fn fold_assignee(&mut self, a: TypedAssignee<T>) -> TypedAssignee<T> {
fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> {
match a {
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
TypedAssignee::ArrayElement(box a, box index) => TypedAssignee::ArrayElement(
@ -48,11 +51,11 @@ pub trait Folder<T: Field>: Sized {
}
}
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
fold_statement(self, s)
}
fn fold_expression(&mut self, e: TypedExpression<T>) -> TypedExpression<T> {
fn fold_expression(&mut self, e: TypedExpression<'ast, T>) -> TypedExpression<'ast, T> {
match e {
TypedExpression::FieldElement(e) => self.fold_field_expression(e).into(),
TypedExpression::Boolean(e) => self.fold_boolean_expression(e).into(),
@ -60,7 +63,10 @@ pub trait Folder<T: Field>: Sized {
}
}
fn fold_expression_list(&mut self, es: TypedExpressionList<T>) -> TypedExpressionList<T> {
fn fold_expression_list(
&mut self,
es: TypedExpressionList<'ast, T>,
) -> TypedExpressionList<'ast, T> {
match es {
TypedExpressionList::FunctionCall(id, arguments, types) => {
TypedExpressionList::FunctionCall(
@ -75,21 +81,30 @@ pub trait Folder<T: Field>: Sized {
}
}
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
fold_field_expression(self, e)
}
fn fold_boolean_expression(&mut self, e: BooleanExpression<T>) -> BooleanExpression<T> {
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
fold_boolean_expression(self, e)
}
fn fold_field_array_expression(
&mut self,
e: FieldElementArrayExpression<T>,
) -> FieldElementArrayExpression<T> {
e: FieldElementArrayExpression<'ast, T>,
) -> FieldElementArrayExpression<'ast, T> {
fold_field_array_expression(self, e)
}
}
pub fn fold_module<T: Field, F: Folder<T>>(f: &mut F, p: TypedModule<T>) -> TypedModule<T> {
pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
p: TypedModule<'ast, T>,
) -> TypedModule<'ast, T> {
TypedModule {
functions: p
.functions
@ -100,10 +115,10 @@ pub fn fold_module<T: Field, F: Folder<T>>(f: &mut F, p: TypedModule<T>) -> Type
}
}
pub fn fold_statement<T: Field, F: Folder<T>>(
pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
s: TypedStatement<T>,
) -> Vec<TypedStatement<T>> {
s: TypedStatement<'ast, T>,
) -> Vec<TypedStatement<'ast, T>> {
let res = match s {
TypedStatement::Return(expressions) => TypedStatement::Return(
expressions
@ -135,10 +150,10 @@ pub fn fold_statement<T: Field, F: Folder<T>>(
vec![res]
}
pub fn fold_field_array_expression<T: Field, F: Folder<T>>(
pub fn fold_field_array_expression<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: FieldElementArrayExpression<T>,
) -> FieldElementArrayExpression<T> {
e: FieldElementArrayExpression<'ast, T>,
) -> FieldElementArrayExpression<'ast, T> {
match e {
FieldElementArrayExpression::Identifier(size, id) => {
FieldElementArrayExpression::Identifier(size, f.fold_name(id))
@ -164,10 +179,10 @@ pub fn fold_field_array_expression<T: Field, F: Folder<T>>(
}
}
pub fn fold_field_expression<T: Field, F: Folder<T>>(
pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: FieldElementExpression<T>,
) -> FieldElementExpression<T> {
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Number(n) => FieldElementExpression::Number(n),
FieldElementExpression::Identifier(id) => {
@ -216,10 +231,10 @@ pub fn fold_field_expression<T: Field, F: Folder<T>>(
}
}
pub fn fold_boolean_expression<T: Field, F: Folder<T>>(
pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
e: BooleanExpression<T>,
) -> BooleanExpression<T> {
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
match e {
BooleanExpression::Value(v) => BooleanExpression::Value(v),
BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)),
@ -265,7 +280,10 @@ pub fn fold_boolean_expression<T: Field, F: Folder<T>>(
}
}
pub fn fold_function<T: Field, F: Folder<T>>(f: &mut F, fun: TypedFunction<T>) -> TypedFunction<T> {
pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
fun: TypedFunction<'ast, T>,
) -> TypedFunction<'ast, T> {
TypedFunction {
arguments: fun
.arguments
@ -281,17 +299,20 @@ pub fn fold_function<T: Field, F: Folder<T>>(f: &mut F, fun: TypedFunction<T>) -
}
}
pub fn fold_function_symbol<T: Field, F: Folder<T>>(
pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
s: TypedFunctionSymbol<T>,
) -> TypedFunctionSymbol<T> {
s: TypedFunctionSymbol<'ast, T>,
) -> TypedFunctionSymbol<'ast, T> {
match s {
TypedFunctionSymbol::Here(fun) => TypedFunctionSymbol::Here(f.fold_function(fun)),
there => there, // by default, do not fold modules recursively
}
}
pub fn fold_program<T: Field, F: Folder<T>>(f: &mut F, p: TypedProgram<T>) -> TypedProgram<T> {
pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
p: TypedProgram<'ast, T>,
) -> TypedProgram<'ast, T> {
TypedProgram {
modules: p
.modules

View file

@ -9,34 +9,37 @@ pub mod folder;
mod parameter;
mod variable;
pub use crate::typed_absy::parameter::Parameter;
pub use crate::typed_absy::variable::Variable;
use crate::types::{FunctionKey, Signature};
use std::collections::HashMap;
use crate::flat_absy::*;
use crate::imports::Import;
use crate::types::Type;
pub use crate::typed_absy::parameter::Parameter;
pub use crate::typed_absy::variable::Variable;
use crate::types::{FunctionKey, Signature, Type};
use std::collections::HashMap;
use std::fmt;
use zokrates_field::field::Field;
pub use self::folder::Folder;
pub type Identifier = String;
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
pub struct Identifier<'ast> {
pub id: &'ast str,
pub version: usize,
pub stack: Vec<(&'ast str, Signature, usize)>,
}
pub type TypedModuleId = String;
pub type TypedModules<T> = HashMap<TypedModuleId, TypedModule<T>>;
pub type TypedModules<'ast, T> = HashMap<TypedModuleId, TypedModule<'ast, T>>;
pub type TypedFunctionSymbols<T> = HashMap<FunctionKey, TypedFunctionSymbol<T>>;
pub type TypedFunctionSymbols<'ast, T> = HashMap<FunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
#[derive(PartialEq, Debug)]
pub struct TypedProgram<T: Field> {
pub modules: TypedModules<T>,
pub struct TypedProgram<'ast, T: Field> {
pub modules: TypedModules<'ast, T>,
pub main: TypedModuleId,
}
impl<T: Field> fmt::Display for TypedProgram<T> {
impl<'ast, T: Field> fmt::Display for TypedProgram<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (module_id, module) in &self.modules {
writeln!(
@ -59,20 +62,54 @@ impl<T: Field> fmt::Display for TypedProgram<T> {
}
#[derive(PartialEq, Clone)]
pub struct TypedModule<T: Field> {
pub struct TypedModule<'ast, T: Field> {
/// Functions of the program
pub functions: TypedFunctionSymbols<T>,
pub functions: TypedFunctionSymbols<'ast, T>,
pub imports: Vec<Import>,
}
impl<'ast> fmt::Display for Identifier<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}_{}_{}",
self.stack
.iter()
.map(|(name, sig, count)| format!("{}_{}_{}", name, sig.to_slug(), count))
.collect::<Vec<_>>()
.join("_"),
self.id,
self.version
)
}
}
impl<'ast> From<&'ast str> for Identifier<'ast> {
fn from(id: &'ast str) -> Identifier<'ast> {
Identifier {
id,
version: 0,
stack: vec![],
}
}
}
#[cfg(test)]
impl<'ast> Identifier<'ast> {
pub fn version(mut self, version: usize) -> Self {
self.version = version;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypedFunctionSymbol<T: Field> {
Here(TypedFunction<T>),
There(FunctionKey, TypedModuleId),
pub enum TypedFunctionSymbol<'ast, T: Field> {
Here(TypedFunction<'ast, T>),
There(FunctionKey<'ast>, TypedModuleId),
Flat(FlatFunction<T>),
}
impl<T: Field> TypedFunctionSymbol<T> {
impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
pub fn signature<'a>(&'a self, modules: &'a TypedModules<T>) -> &'a Signature {
match self {
TypedFunctionSymbol::Here(f) => &f.signature,
@ -88,7 +125,7 @@ impl<T: Field> TypedFunctionSymbol<T> {
}
}
impl<T: Field> fmt::Display for TypedModule<T> {
impl<'ast, T: Field> fmt::Display for TypedModule<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut res = vec![];
res.extend(
@ -118,7 +155,7 @@ impl<T: Field> fmt::Display for TypedModule<T> {
}
}
impl<T: Field> fmt::Debug for TypedModule<T> {
impl<'ast, T: Field> fmt::Debug for TypedModule<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -138,16 +175,16 @@ impl<T: Field> fmt::Debug for TypedModule<T> {
}
#[derive(Clone, PartialEq)]
pub struct TypedFunction<T: Field> {
pub struct TypedFunction<'ast, T: Field> {
/// Arguments of the function
pub arguments: Vec<Parameter>,
pub arguments: Vec<Parameter<'ast>>,
/// Vector of statements that are executed when running the function
pub statements: Vec<TypedStatement<T>>,
pub statements: Vec<TypedStatement<'ast, T>>,
/// function signature
pub signature: Signature,
}
impl<T: Field> fmt::Display for TypedFunction<T> {
impl<'ast, T: Field> fmt::Display for TypedFunction<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -172,7 +209,7 @@ impl<T: Field> fmt::Display for TypedFunction<T> {
}
}
impl<T: Field> fmt::Debug for TypedFunction<T> {
impl<'ast, T: Field> fmt::Debug for TypedFunction<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@ -188,12 +225,15 @@ impl<T: Field> fmt::Debug for TypedFunction<T> {
}
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum TypedAssignee<T: Field> {
Identifier(Variable),
ArrayElement(Box<TypedAssignee<T>>, Box<FieldElementExpression<T>>),
pub enum TypedAssignee<'ast, T: Field> {
Identifier(Variable<'ast>),
ArrayElement(
Box<TypedAssignee<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
}
impl<T: Field> Typed for TypedAssignee<T> {
impl<'ast, T: Field> Typed for TypedAssignee<'ast, T> {
fn get_type(&self) -> Type {
match *self {
TypedAssignee::Identifier(ref v) => v.get_type(),
@ -208,7 +248,7 @@ impl<T: Field> Typed for TypedAssignee<T> {
}
}
impl<T: Field> fmt::Debug for TypedAssignee<T> {
impl<'ast, T: Field> fmt::Debug for TypedAssignee<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedAssignee::Identifier(ref s) => write!(f, "{}", s.id),
@ -217,23 +257,23 @@ impl<T: Field> fmt::Debug for TypedAssignee<T> {
}
}
impl<T: Field> fmt::Display for TypedAssignee<T> {
impl<'ast, T: Field> fmt::Display for TypedAssignee<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Clone, PartialEq)]
pub enum TypedStatement<T: Field> {
Return(Vec<TypedExpression<T>>),
Definition(TypedAssignee<T>, TypedExpression<T>),
Declaration(Variable),
Condition(TypedExpression<T>, TypedExpression<T>),
For(Variable, T, T, Vec<TypedStatement<T>>),
MultipleDefinition(Vec<Variable>, TypedExpressionList<T>),
pub enum TypedStatement<'ast, T: Field> {
Return(Vec<TypedExpression<'ast, T>>),
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
Declaration(Variable<'ast>),
Condition(TypedExpression<'ast, T>, TypedExpression<'ast, T>),
For(Variable<'ast>, T, T, Vec<TypedStatement<'ast, T>>),
MultipleDefinition(Vec<Variable<'ast>>, TypedExpressionList<'ast, T>),
}
impl<T: Field> fmt::Debug for TypedStatement<T> {
impl<'ast, T: Field> fmt::Debug for TypedStatement<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedStatement::Return(ref exprs) => {
@ -267,7 +307,7 @@ impl<T: Field> fmt::Debug for TypedStatement<T> {
}
}
impl<T: Field> fmt::Display for TypedStatement<T> {
impl<'ast, T: Field> fmt::Display for TypedStatement<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedStatement::Return(ref exprs) => {
@ -308,31 +348,31 @@ pub trait Typed {
}
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum TypedExpression<T: Field> {
Boolean(BooleanExpression<T>),
FieldElement(FieldElementExpression<T>),
FieldElementArray(FieldElementArrayExpression<T>),
pub enum TypedExpression<'ast, T: Field> {
Boolean(BooleanExpression<'ast, T>),
FieldElement(FieldElementExpression<'ast, T>),
FieldElementArray(FieldElementArrayExpression<'ast, T>),
}
impl<T: Field> From<BooleanExpression<T>> for TypedExpression<T> {
fn from(e: BooleanExpression<T>) -> TypedExpression<T> {
impl<'ast, T: Field> From<BooleanExpression<'ast, T>> for TypedExpression<'ast, T> {
fn from(e: BooleanExpression<'ast, T>) -> TypedExpression<T> {
TypedExpression::Boolean(e)
}
}
impl<T: Field> From<FieldElementExpression<T>> for TypedExpression<T> {
fn from(e: FieldElementExpression<T>) -> TypedExpression<T> {
impl<'ast, T: Field> From<FieldElementExpression<'ast, T>> for TypedExpression<'ast, T> {
fn from(e: FieldElementExpression<'ast, T>) -> TypedExpression<T> {
TypedExpression::FieldElement(e)
}
}
impl<T: Field> From<FieldElementArrayExpression<T>> for TypedExpression<T> {
fn from(e: FieldElementArrayExpression<T>) -> TypedExpression<T> {
impl<'ast, T: Field> From<FieldElementArrayExpression<'ast, T>> for TypedExpression<'ast, T> {
fn from(e: FieldElementArrayExpression<'ast, T>) -> TypedExpression<T> {
TypedExpression::FieldElementArray(e)
}
}
impl<T: Field> fmt::Display for TypedExpression<T> {
impl<'ast, T: Field> fmt::Display for TypedExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedExpression::Boolean(ref e) => write!(f, "{}", e),
@ -342,7 +382,7 @@ impl<T: Field> fmt::Display for TypedExpression<T> {
}
}
impl<T: Field> fmt::Debug for TypedExpression<T> {
impl<'ast, T: Field> fmt::Debug for TypedExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedExpression::Boolean(ref e) => write!(f, "{:?}", e),
@ -352,7 +392,7 @@ impl<T: Field> fmt::Debug for TypedExpression<T> {
}
}
impl<T: Field> Typed for TypedExpression<T> {
impl<'ast, T: Field> Typed for TypedExpression<'ast, T> {
fn get_type(&self) -> Type {
match *self {
TypedExpression::Boolean(_) => Type::Boolean,
@ -362,7 +402,7 @@ impl<T: Field> Typed for TypedExpression<T> {
}
}
impl<T: Field> Typed for FieldElementArrayExpression<T> {
impl<'ast, T: Field> Typed for FieldElementArrayExpression<'ast, T> {
fn get_type(&self) -> Type {
match *self {
FieldElementArrayExpression::Identifier(n, _) => Type::FieldElementArray(n),
@ -378,11 +418,11 @@ pub trait MultiTyped {
}
#[derive(Clone, PartialEq)]
pub enum TypedExpressionList<T: Field> {
FunctionCall(FunctionKey, Vec<TypedExpression<T>>, Vec<Type>),
pub enum TypedExpressionList<'ast, T: Field> {
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>, Vec<Type>),
}
impl<T: Field> MultiTyped for TypedExpressionList<T> {
impl<'ast, T: Field> MultiTyped for TypedExpressionList<'ast, T> {
fn get_types(&self) -> &Vec<Type> {
match *self {
TypedExpressionList::FunctionCall(_, _, ref types) => types,
@ -391,84 +431,90 @@ impl<T: Field> MultiTyped for TypedExpressionList<T> {
}
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum FieldElementExpression<T: Field> {
pub enum FieldElementExpression<'ast, T: Field> {
Number(T),
Identifier(Identifier),
Identifier(Identifier<'ast>),
Add(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Sub(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Mult(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Div(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Pow(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
IfElse(
Box<BooleanExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<BooleanExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
FunctionCall(FunctionKey, Vec<TypedExpression<T>>),
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
Select(
Box<FieldElementArrayExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementArrayExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
}
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum BooleanExpression<T: Field> {
Identifier(Identifier),
pub enum BooleanExpression<'ast, T: Field> {
Identifier(Identifier<'ast>),
Value(bool),
Lt(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Le(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Eq(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Ge(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Gt(
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<T>>,
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
),
Or(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
And(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
Not(Box<BooleanExpression<T>>),
Or(
Box<BooleanExpression<'ast, T>>,
Box<BooleanExpression<'ast, T>>,
),
And(
Box<BooleanExpression<'ast, T>>,
Box<BooleanExpression<'ast, T>>,
),
Not(Box<BooleanExpression<'ast, T>>),
}
// for now we store the array size in the variants
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum FieldElementArrayExpression<T: Field> {
Identifier(usize, Identifier),
Value(usize, Vec<FieldElementExpression<T>>),
FunctionCall(usize, FunctionKey, Vec<TypedExpression<T>>),
pub enum FieldElementArrayExpression<'ast, T: Field> {
Identifier(usize, Identifier<'ast>),
Value(usize, Vec<FieldElementExpression<'ast, T>>),
FunctionCall(usize, FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
IfElse(
Box<BooleanExpression<T>>,
Box<FieldElementArrayExpression<T>>,
Box<FieldElementArrayExpression<T>>,
Box<BooleanExpression<'ast, T>>,
Box<FieldElementArrayExpression<'ast, T>>,
Box<FieldElementArrayExpression<'ast, T>>,
),
}
impl<T: Field> FieldElementArrayExpression<T> {
impl<'ast, T: Field> FieldElementArrayExpression<'ast, T> {
pub fn size(&self) -> usize {
match *self {
FieldElementArrayExpression::Identifier(s, _)
@ -479,7 +525,7 @@ impl<T: Field> FieldElementArrayExpression<T> {
}
}
impl<T: Field> fmt::Display for FieldElementExpression<T> {
impl<'ast, T: Field> fmt::Display for FieldElementExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldElementExpression::Number(ref i) => write!(f, "{}", i),
@ -511,7 +557,7 @@ impl<T: Field> fmt::Display for FieldElementExpression<T> {
}
}
impl<T: Field> fmt::Display for BooleanExpression<T> {
impl<'ast, T: Field> fmt::Display for BooleanExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
BooleanExpression::Identifier(ref var) => write!(f, "{}", var),
@ -528,7 +574,7 @@ impl<T: Field> fmt::Display for BooleanExpression<T> {
}
}
impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
impl<'ast, T: Field> fmt::Display for FieldElementArrayExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldElementArrayExpression::Identifier(_, ref var) => write!(f, "{}", var),
@ -562,13 +608,13 @@ impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
}
}
impl<T: Field> fmt::Debug for BooleanExpression<T> {
impl<'ast, T: Field> fmt::Debug for BooleanExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<T: Field> fmt::Debug for FieldElementExpression<T> {
impl<'ast, T: Field> fmt::Debug for FieldElementExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldElementExpression::Number(ref i) => write!(f, "Num({})", i),
@ -599,7 +645,7 @@ impl<T: Field> fmt::Debug for FieldElementExpression<T> {
}
}
impl<T: Field> fmt::Debug for FieldElementArrayExpression<T> {
impl<'ast, T: Field> fmt::Debug for FieldElementArrayExpression<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldElementArrayExpression::Identifier(_, ref var) => write!(f, "{:?}", var),
@ -620,7 +666,7 @@ impl<T: Field> fmt::Debug for FieldElementArrayExpression<T> {
}
}
impl<T: Field> fmt::Display for TypedExpressionList<T> {
impl<'ast, T: Field> fmt::Display for TypedExpressionList<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedExpressionList::FunctionCall(ref key, ref p, _) => {
@ -637,7 +683,7 @@ impl<T: Field> fmt::Display for TypedExpressionList<T> {
}
}
impl<T: Field> fmt::Debug for TypedExpressionList<T> {
impl<'ast, T: Field> fmt::Debug for TypedExpressionList<'ast, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TypedExpressionList::FunctionCall(ref i, ref p, _) => {
@ -648,3 +694,10 @@ impl<T: Field> fmt::Debug for TypedExpressionList<T> {
}
}
}
impl<'ast, T: Field> TypedFunction<'ast, T> {
pub fn to_slug(&self) -> String {
unimplemented!()
// format!("NONAME_{}", self.signature.to_slug())
}
}

View file

@ -2,15 +2,15 @@ use crate::absy;
use crate::typed_absy::Variable;
use std::fmt;
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct Parameter {
pub id: Variable,
#[derive(Clone, PartialEq)]
pub struct Parameter<'ast> {
pub id: Variable<'ast>,
pub private: bool,
}
impl Parameter {
impl<'ast> Parameter<'ast> {
#[cfg(test)]
pub fn private(v: Variable) -> Self {
pub fn private(v: Variable<'ast>) -> Self {
Parameter {
id: v,
private: true,
@ -18,21 +18,21 @@ impl Parameter {
}
}
impl fmt::Display for Parameter {
impl<'ast> fmt::Display for Parameter<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let visibility = if self.private { "private " } else { "" };
write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id)
}
}
impl fmt::Debug for Parameter {
impl<'ast> fmt::Debug for Parameter<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Parameter(variable: {:?})", self.id)
}
}
impl From<absy::Parameter> for Parameter {
fn from(p: absy::Parameter) -> Parameter {
impl<'ast> From<absy::Parameter<'ast>> for Parameter<'ast> {
fn from(p: absy::Parameter<'ast>) -> Parameter {
Parameter {
private: p.private,
id: p.id.value.into(),

View file

@ -1 +1,57 @@
pub use types::Variable;
use crate::absy;
use crate::typed_absy::Identifier;
use crate::types::Type;
use std::fmt;
#[derive(Clone, PartialEq, Hash, Eq)]
pub struct Variable<'ast> {
pub id: Identifier<'ast>,
pub _type: Type,
}
impl<'ast> Variable<'ast> {
pub fn field_element(id: Identifier<'ast>) -> Variable<'ast> {
Self::with_id_and_type(id, Type::FieldElement)
}
pub fn boolean(id: Identifier<'ast>) -> Variable<'ast> {
Self::with_id_and_type(id, Type::Boolean)
}
pub fn field_array(id: Identifier<'ast>, size: usize) -> Variable<'ast> {
Self::with_id_and_type(id, Type::FieldElementArray(size))
}
pub fn with_id_and_type(id: Identifier<'ast>, _type: Type) -> Variable<'ast> {
Variable { id, _type }
}
pub fn get_type(&self) -> Type {
self._type.clone()
}
}
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self._type, self.id,)
}
}
impl<'ast> fmt::Debug for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,)
}
}
impl<'ast> From<absy::Variable<'ast>> for Variable<'ast> {
fn from(v: absy::Variable) -> Variable {
Variable::with_id_and_type(
Identifier {
id: v.id,
version: 0,
stack: vec![],
},
v._type,
)
}
}

View file

@ -4,16 +4,16 @@ use crate::flat_absy::*;
use crate::helpers::{DirectiveStatement, Helper};
use crate::types::signature::Signature;
use crate::types::Type;
use bimap::BiMap;
use std::collections::HashMap;
use zokrates_field::field::Field;
fn use_variable(
bijection: &mut BiMap<String, FlatVariable>,
layout: &mut HashMap<String, FlatVariable>,
name: String,
index: &mut usize,
) -> FlatVariable {
let var = FlatVariable::new(*index);
bijection.insert(name, var);
layout.insert(name, var);
*index = *index + 1;
var
}
@ -23,7 +23,7 @@ pub fn split<T: Field>() -> FlatFunction<T> {
let mut counter = 0;
let mut bijection = BiMap::new();
let mut layout = HashMap::new();
let arguments = vec![FlatParameter {
id: FlatVariable::new(0),
@ -33,12 +33,12 @@ pub fn split<T: Field>() -> FlatFunction<T> {
// o0, ..., o253 = ToBits(i0)
let directive_inputs = vec![FlatExpression::Identifier(use_variable(
&mut bijection,
&mut layout,
format!("i0"),
&mut counter,
))];
let directive_outputs: Vec<FlatVariable> = (0..T::get_required_bits())
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
.map(|index| use_variable(&mut layout, format!("o{}", index), &mut counter))
.collect();
let helper = Helper::bits();
@ -110,7 +110,7 @@ pub fn split<T: Field>() -> FlatFunction<T> {
pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
let mut counter = 0;
let mut bijection = BiMap::new();
let mut layout = HashMap::new();
let arguments = (0..from.get_primitive_count())
.enumerate()
@ -121,10 +121,10 @@ pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
.collect();
let binding_inputs: Vec<_> = (0..from.get_primitive_count())
.map(|index| use_variable(&mut bijection, format!("i{}", index), &mut counter))
.map(|index| use_variable(&mut layout, format!("i{}", index), &mut counter))
.collect();
let binding_outputs: Vec<FlatVariable> = (0..to.get_primitive_count())
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
.map(|index| use_variable(&mut layout, format!("o{}", index), &mut counter))
.collect();
let outputs = binding_outputs

View file

@ -1,6 +1,8 @@
pub use crate::types::signature::Signature;
use std::fmt;
pub type Identifier<'ast> = &'ast str;
pub mod conversions;
mod signature;
@ -32,6 +34,14 @@ impl fmt::Debug for Type {
}
impl Type {
fn to_slug(&self) -> String {
match *self {
Type::FieldElement => String::from("f"),
Type::Boolean => String::from("b"),
Type::FieldElementArray(size) => format!("{}[{}]", Type::FieldElement.to_slug(), size), // TODO differentiate types?
}
}
// the number of field elements the type maps to
pub fn get_primitive_count(&self) -> usize {
match self {
@ -42,35 +52,35 @@ impl Type {
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
pub struct Variable {
pub id: Identifier,
#[derive(Clone, PartialEq, Hash, Eq)]
pub struct Variable<'ast> {
pub id: Identifier<'ast>,
pub _type: Type,
}
impl Variable {
pub fn new<S: Into<String>>(id: S, t: Type) -> Variable {
impl<'ast> Variable<'ast> {
pub fn new<S: Into<Identifier<'ast>>>(id: S, t: Type) -> Variable<'ast> {
Variable {
id: id.into(),
_type: t,
}
}
pub fn field_element<S: Into<String>>(id: S) -> Variable {
pub fn field_element<S: Into<Identifier<'ast>>>(id: S) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::FieldElement,
}
}
pub fn boolean<S: Into<String>>(id: S) -> Variable {
pub fn boolean<S: Into<Identifier<'ast>>>(id: S) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::Boolean,
}
}
pub fn field_array<S: Into<String>>(id: S, size: usize) -> Variable {
pub fn field_array<S: Into<Identifier<'ast>>>(id: S, size: usize) -> Variable<'ast> {
Variable {
id: id.into(),
_type: Type::FieldElementArray(size),
@ -82,28 +92,28 @@ impl Variable {
}
}
impl fmt::Display for Variable {
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self._type, self.id,)
}
}
impl fmt::Debug for Variable {
impl<'ast> fmt::Debug for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,)
}
}
type Identifier = String;
pub type FunctionIdentifier<'ast> = &'ast str;
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct FunctionKey {
pub id: Identifier,
pub struct FunctionKey<'ast> {
pub id: FunctionIdentifier<'ast>,
pub signature: Signature,
}
impl FunctionKey {
pub fn with_id<S: Into<Identifier>>(id: S) -> Self {
impl<'ast> FunctionKey<'ast> {
pub fn with_id<S: Into<Identifier<'ast>>>(id: S) -> Self {
FunctionKey {
id: id.into(),
signature: Signature::new(),

View file

@ -38,6 +38,49 @@ impl fmt::Display for Signature {
}
impl Signature {
/// Returns a slug for a signature, with the following encoding:
/// i{inputs}o{outputs} where {inputs} and {outputs} each encode a list of types.
/// A list of types is encoded by compressing sequences of the same type like so:
///
/// [field, field, field] -> 3f
/// [field] -> f
/// [field, bool, field] -> fbf
/// [field, field, bool, field] -> 2fbf
///
pub fn to_slug(&self) -> String {
let to_slug = |types| {
let mut res = vec![];
for t in types {
let len = res.len();
if len == 0 {
res.push((1, t))
} else {
if res[len - 1].1 == t {
res[len - 1].0 += 1;
} else {
res.push((1, t))
}
}
}
res.into_iter()
.map(|(n, t): (usize, &Type)| {
let mut r = String::new();
if n > 1 {
r.push_str(&format!("{}", n));
}
r.push_str(&t.to_slug());
r
})
.fold(String::new(), |mut acc, e| {
acc.push_str(&e);
acc
})
};
format!("i{}o{}", to_slug(&self.inputs), to_slug(&self.outputs))
}
pub fn new() -> Signature {
Signature {
inputs: vec![],

View file

@ -81,7 +81,7 @@ pub fn read_file(path: &str) -> String {
contents
}
pub fn compile(code: &str) -> Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> {
pub fn compile(code: &str) -> Result<ir::Prog<FieldPrime>, CompileErrors> {
generic_compile::<FieldPrime, &[u8], &[u8], io::Error>(&mut code.as_bytes(), None, None)
}

View file

@ -104,7 +104,26 @@ mod tests {
}
#[test]
fn no_file_name() {
#[should_panic]
fn no_file_name_without_stdlib() {
// an empty string is interpreted relative to the HOME folder. If there's none, panic
std::env::remove_var(ZOKRATES_HOME);
let _res = resolve(&Some(String::from(".")), &String::from(""));
}
#[test]
fn no_file_name_with_stdlib() {
use std::io::Write;
// create a HOME folder with a code file
let zokrates_home_folder = tempfile::tempdir().unwrap();
let file_path = zokrates_home_folder.path().join("bar.code");
let mut file = File::create(file_path).unwrap();
writeln!(file, "<stdlib code>").unwrap();
// assign HOME folder to ZOKRATES_HOME
std::env::set_var(ZOKRATES_HOME, zokrates_home_folder.path());
let res = resolve(&Some(String::from(".")), &String::from(""));
assert!(res.is_err());
}

View file

@ -0,0 +1,12 @@
[package]
name = "zokrates_parser"
version = "0.1.0"
authors = ["JacobEberhardt <jacob.eberhardt@tu-berlin.de>"]
edition = "2018"
[dependencies]
pest = "2.0"
pest_derive = "2.0"
[dev-dependencies]
glob = "0.2"

View file

@ -0,0 +1,3 @@
# zokrates_parser
Formal grammar specification of the ZoKrates DSL in PEG (Pest).

146
zokrates_parser/src/lib.rs Normal file
View file

@ -0,0 +1,146 @@
extern crate pest;
#[macro_use]
extern crate pest_derive;
use pest::error::Error;
use pest::iterators::Pairs;
use pest::Parser;
#[derive(Parser)]
#[grammar = "zokrates.pest"]
struct ZoKratesParser;
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
ZoKratesParser::parse(Rule::file, input)
}
#[cfg(test)]
mod tests {
use super::*;
use pest::*;
mod examples {
use super::*;
#[test]
fn examples_dir() {
use glob::glob;
use std::fs;
use std::io::Read;
// Traverse all .code files in examples dir
for entry in
glob("../zokrates_cli/examples/**/*.code").expect("Failed to read glob pattern")
{
match entry {
Ok(path) => {
if path.to_str().unwrap().contains("error") {
continue;
}
println!("Parsing {:?}", path.display());
let mut file = fs::File::open(path).unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();
assert!(ZoKratesParser::parse(Rule::file, &data).is_ok());
}
Err(e) => panic!("{:?}", e),
}
}
}
}
mod rules {
use super::*;
#[test]
fn parse_valid_identifier() {
parses_to! {
parser: ZoKratesParser,
input: "valididentifier_01",
rule: Rule::identifier,
tokens: [
identifier(0, 18)
]
};
}
#[test]
fn parse_parameter_list() {
parses_to! {
parser: ZoKratesParser,
input: "def foo(field a) -> (field, field): return 1
",
rule: Rule::function_definition,
tokens: [
function_definition(0, 45, [
identifier(4, 7),
// parameter_list is not created (silent rule)
parameter(8, 15, [
ty(8, 13, [
ty_basic(8, 13, [
ty_field(8, 13)
])
]),
identifier(14, 15)
]),
// type_list is not created (silent rule)
ty(21, 26, [
ty_basic(21, 26, [
ty_field(21, 26)
])
]),
ty(28, 33, [
ty_basic(28, 33, [
ty_field(28, 33)
])
]),
statement(36, 45, [
return_statement(36, 44, [
expression(43, 44, [
term(43, 44, [
primary_expression(43, 44, [
constant(43, 44)
])
])
])
])
])
])
]
};
}
#[test]
fn parse_invalid_identifier() {
fails_with! {
parser: ZoKratesParser,
input: "0_invalididentifier",
rule: Rule::identifier,
positives: vec![Rule::identifier],
negatives: vec![],
pos: 0
};
}
#[test]
fn parse_invalid_identifier_because_keyword() {
fails_with! {
parser: ZoKratesParser,
input: "endfor",
rule: Rule::identifier,
positives: vec![Rule::identifier],
negatives: vec![],
pos: 0
};
}
#[test]
fn parse_for_loop() {
let input = "for field i in 0..3 do \n c = c + a[i] \n endfor";
let parse = ZoKratesParser::parse(Rule::iteration_statement, input);
assert!(parse.is_ok());
}
}
}

View file

@ -0,0 +1,100 @@
/**
* ZoKrates Grammar
* Author: Jacob Eberhardt, Thibaut Schaeffer
*/
file = { SOI ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ function_definition* ~ EOI }
import_directive = {"import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ identifier)? ~ NEWLINE+}
import_source = @{(!"\"" ~ ANY)*}
function_definition = {"def" ~ identifier ~ "(" ~ parameter_list ~ ")" ~ "->" ~ "(" ~ type_list ~ ")" ~ ":" ~ NEWLINE* ~ statement* }
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
parameter = {vis? ~ ty ~ identifier}
// basic types
ty_field = {"field"}
ty_bool = {"bool"}
ty_basic = { ty_field | ty_bool }
// (unidimensional for now) arrays of (basic for now) types
ty_array = { ty_basic ~ ("[" ~ expression ~ "]") }
ty = { ty_array | ty_basic }
type_list = _{(ty ~ ("," ~ ty)*)?}
vis_private = {"private"}
vis_public = {"public"}
vis = { vis_private | vis_public }
// Statements
statement = { (return_statement // does not require subsequent newline
| (iteration_statement
| multi_assignment_statement // try this first as we want all assignments based on return of function calls match here and not later
| definition_statement
| assignment_statement
| expression_statement
) ~ NEWLINE
) ~ NEWLINE* }
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
return_statement = { "return" ~ expression_list}
multi_assignment_statement = { optionally_typed_identifier_list ~ "=" ~ identifier ~ "(" ~ expression_list ~ ")"} // This is very specific with regards to parsing. However, I think more generality is not needed here.
definition_statement = {ty ~ identifier ~ "=" ~ expression} // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
assignment_statement = {assignee ~ "=" ~ expression } // TODO: Is this optimal? Can the left side be written more elegantly?
expression_statement = {expression}
optionally_typed_identifier_list = _{ optionally_typed_identifier ~ ("," ~ optionally_typed_identifier)* }
optionally_typed_identifier = { ty? ~ identifier }
// Expressions
expression_list = _{(expression ~ ("," ~ expression)*)?}
expression = { term ~ (op_binary ~ term)* }
term = { ("(" ~ expression ~ ")") | conditional_expression | postfix_expression | primary_expression | inline_array_expression | unary_expression }
conditional_expression = { "if" ~ expression ~ "then" ~ expression ~ "else" ~ expression ~ "fi"}
postfix_expression = { identifier ~ access+ } // we force there to be at least one access, otherwise this matches single identifiers. Not sure that's what we want.
access = { array_access | call_access }
array_access = { "[" ~ expression ~ "]" }
call_access = { "(" ~ expression_list ~ ")" }
primary_expression = { identifier
| constant
}
inline_array_expression = { "[" ~ expression_list ~ "]" }
unary_expression = { op_unary ~ term }
// End Expressions
assignee = { identifier ~ ("[" ~ expression ~ "]")* }
identifier = @{ ((!keyword ~ ASCII_ALPHA) | (keyword ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
constant = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
op_inclusive_or = {"||"}
op_exclusive_or = {"^"}
op_and = {"&&"}
op_equal = {"=="}
op_not_equal = {"!="}
op_lt = {"<"}
op_lte = {"<="}
op_gt = {">"}
op_gte = {">="}
op_add = {"+"}
op_sub = {"-"}
op_mul = {"*"}
op_div = {"/"}
op_pow = {"**"}
op_not = {"!"}
op_binary = _ { op_pow | op_inclusive_or | op_exclusive_or | op_and | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div }
op_unary = { op_not }
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
// TODO: Order by alphabet
keyword = @{"for" | "endfor" | "as" | "in" | "return" | "byte" | "field" | "bool" | "if" | "do" | "else" | "export" | "false" |
"def" | "for" | "import" | "uint" |
"in" | "public" | "private" | "return" |
"struct" | "true"
}

View file

@ -0,0 +1,16 @@
[package]
name = "zokrates_pest_ast"
version = "0.1.0"
authors = ["schaeff <thibaut@schaeff.fr>"]
edition = "2018"
[dependencies]
zokrates_parser = { version = "0.1.0", path = "../zokrates_parser" }
zokrates_field = { version = "0.3.0", path = "../zokrates_field" }
pest = "2.0"
pest-ast = "0.3.3"
from-pest = "0.3.1"
lazy_static = "1.3.0"
[dev-dependencies]
glob = "0.2"

View file

@ -0,0 +1,3 @@
# zokrates_pest_ast
ZoKrates AST generation based on pest output.

View file

@ -0,0 +1,880 @@
use from_pest::FromPest;
use pest::error::Error as PestError;
use pest::iterators::Pairs;
use std::fmt;
use zokrates_parser::parse;
use zokrates_parser::Rule;
#[macro_use]
extern crate lazy_static;
pub use ast::{
Access, ArrayAccess, ArrayType, AssertionStatement, Assignee, AssignmentStatement, BasicType,
BinaryExpression, BinaryOperator, CallAccess, ConstantExpression, DefinitionStatement,
Expression, File, Function, IdentifierExpression, ImportDirective, ImportSource,
InlineArrayExpression, IterationStatement, MultiAssignmentStatement, Parameter,
PostfixExpression, ReturnStatement, Span, Statement, TernaryExpression, Type, UnaryExpression,
UnaryOperator, Visibility,
};
mod ast {
use from_pest::ConversionError;
use from_pest::FromPest;
use from_pest::Void;
use pest::iterators::{Pair, Pairs};
use pest::prec_climber::{Assoc, Operator, PrecClimber};
pub use pest::Span;
use pest_ast::FromPest;
use zokrates_parser::Rule;
lazy_static! {
static ref PREC_CLIMBER: PrecClimber<Rule> = build_precedence_climber();
}
fn build_precedence_climber() -> PrecClimber<Rule> {
PrecClimber::new(vec![
Operator::new(Rule::op_inclusive_or, Assoc::Left),
Operator::new(Rule::op_exclusive_or, Assoc::Left),
Operator::new(Rule::op_and, Assoc::Left),
Operator::new(Rule::op_equal, Assoc::Left)
| Operator::new(Rule::op_not_equal, Assoc::Left),
Operator::new(Rule::op_lte, Assoc::Left)
| Operator::new(Rule::op_gte, Assoc::Left)
| Operator::new(Rule::op_lt, Assoc::Left)
| Operator::new(Rule::op_gt, Assoc::Left),
Operator::new(Rule::op_add, Assoc::Left) | Operator::new(Rule::op_sub, Assoc::Left),
Operator::new(Rule::op_mul, Assoc::Left) | Operator::new(Rule::op_div, Assoc::Left),
Operator::new(Rule::op_pow, Assoc::Left),
])
}
// Create an Expression from left and right terms and an operator
// Precondition: `pair` MUST be a binary operator
fn infix_rule<'ast>(
lhs: Box<Expression<'ast>>,
pair: Pair<'ast, Rule>,
rhs: Box<Expression<'ast>>,
) -> Box<Expression<'ast>> {
// a + b spans from the start of a to the end of b
let (start, _) = lhs.span().clone().split();
let (_, end) = rhs.span().clone().split();
let span = start.span(&end);
Box::new(match pair.as_rule() {
Rule::op_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
Rule::op_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
Rule::op_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span),
Rule::op_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span),
Rule::op_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span),
Rule::op_equal => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
Rule::op_not_equal => Expression::binary(BinaryOperator::NotEq, lhs, rhs, span),
Rule::op_lte => Expression::binary(BinaryOperator::Lte, lhs, rhs, span),
Rule::op_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
Rule::op_gte => Expression::binary(BinaryOperator::Gte, lhs, rhs, span),
Rule::op_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
Rule::op_inclusive_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
Rule::op_exclusive_or => Expression::binary(BinaryOperator::Xor, lhs, rhs, span),
Rule::op_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
_ => unreachable!(),
})
}
// Create an Expression from an `expression`. `build_factor` turns each term into an `Expression` and `infix_rule` turns each (Expression, operator, Expression) into an Expression
pub fn climb(pair: Pair<Rule>) -> Box<Expression> {
PREC_CLIMBER.climb(pair.into_inner(), build_factor, infix_rule)
}
// Create an Expression from a `term`.
// Precondition: `pair` MUST be a term
fn build_factor(pair: Pair<Rule>) -> Box<Expression> {
Box::new(match pair.as_rule() {
Rule::term => {
// clone the pair to peek into what we should create
let clone = pair.clone();
// define the child pair
let next = clone.into_inner().next().unwrap();
match next.as_rule() {
// this happens when we have an expression in parentheses: it needs to be processed as another sequence of terms and operators
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(),
Rule::conditional_expression => Expression::Ternary(
TernaryExpression::from_pest(&mut pair.into_inner()).unwrap(),
),
Rule::primary_expression => {
// maybe this could be simplified
let next = next.into_inner().next().unwrap();
match next.as_rule() {
Rule::constant => Expression::Constant(
ConstantExpression::from_pest(
&mut pair.into_inner().next().unwrap().into_inner(),
)
.unwrap(),
),
Rule::identifier => Expression::Identifier(
IdentifierExpression::from_pest(
&mut pair.into_inner().next().unwrap().into_inner(),
)
.unwrap(),
),
r => unreachable!("`primary_expression` should contain one of [`constant`, `identifier`], found {:#?}", r),
}
}
Rule::postfix_expression => Expression::Postfix(
PostfixExpression::from_pest(&mut pair.into_inner()).unwrap(),
),
Rule::inline_array_expression => Expression::InlineArray(
InlineArrayExpression::from_pest(&mut pair.into_inner()).unwrap(),
),
Rule::unary_expression => {
let span = next.as_span();
let mut inner = next.into_inner();
let op = match inner.next().unwrap().as_rule() {
Rule::op_unary => UnaryOperator::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
r => unreachable!("`unary_expression` should yield `op_unary`, found {:#?}", r)
};
let expression = build_factor(inner.next().unwrap());
Expression::Unary(UnaryExpression {
op,
expression,
span
})
},
r => unreachable!("`term` should contain one of [`expression`, `conditional_expression`, `primary_expression`, `postfix_expression`, `inline_array_expression`, `unary_expression`], found {:#?}", r)
}
}
r => unreachable!(
"`build_factor` can only be called on `term`, found {:#?}",
r
),
})
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub imports: Vec<ImportDirective<'ast>>,
pub functions: Vec<Function<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::function_definition))]
pub struct Function<'ast> {
pub id: IdentifierExpression<'ast>,
pub parameters: Vec<Parameter<'ast>>,
pub returns: Vec<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::import_directive))]
pub struct ImportDirective<'ast> {
pub source: ImportSource<'ast>,
pub alias: Option<IdentifierExpression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::import_source))]
pub struct ImportSource<'ast> {
#[pest_ast(outer(with(span_into_str)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::ty))]
pub enum Type<'ast> {
Basic(BasicType<'ast>),
Array(ArrayType<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::ty_basic))]
pub enum BasicType<'ast> {
Field(FieldType),
Boolean(BooleanType<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::ty_field))]
pub struct FieldType {}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::ty_array))]
pub struct ArrayType<'ast> {
pub ty: BasicType<'ast>,
pub size: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::ty_bool))]
pub struct BooleanType<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::parameter))]
pub struct Parameter<'ast> {
pub visibility: Option<Visibility>,
pub ty: Type<'ast>,
pub id: IdentifierExpression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::vis))]
pub enum Visibility {
Public(PublicVisibility),
Private(PrivateVisibility),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::vis_public))]
pub struct PublicVisibility {}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::vis_private))]
pub struct PrivateVisibility {}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Return(ReturnStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Assertion(AssertionStatement<'ast>),
Iteration(IterationStatement<'ast>),
Assignment(AssignmentStatement<'ast>),
MultiAssignment(MultiAssignmentStatement<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::definition_statement))]
pub struct DefinitionStatement<'ast> {
pub ty: Type<'ast>,
pub id: IdentifierExpression<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::assignment_statement))]
pub struct AssignmentStatement<'ast> {
pub assignee: Assignee<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::expression_statement))]
pub struct AssertionStatement<'ast> {
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::iteration_statement))]
pub struct IterationStatement<'ast> {
pub ty: Type<'ast>,
pub index: IdentifierExpression<'ast>,
pub from: Expression<'ast>,
pub to: Expression<'ast>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::multi_assignment_statement))]
pub struct MultiAssignmentStatement<'ast> {
pub lhs: Vec<OptionallyTypedIdentifier<'ast>>,
pub function_id: IdentifierExpression<'ast>,
pub arguments: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::return_statement))]
pub struct ReturnStatement<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryOperator {
Xor,
Or,
And,
Add,
Sub,
Mul,
Div,
Eq,
NotEq,
Lt,
Gt,
Lte,
Gte,
Pow,
}
#[derive(Debug, PartialEq, FromPest, Clone)]
#[pest_ast(rule(Rule::op_unary))]
pub enum UnaryOperator<'ast> {
Not(Not<'ast>),
}
#[derive(Debug, PartialEq, FromPest, Clone)]
#[pest_ast(rule(Rule::op_not))]
pub struct Not<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Expression<'ast> {
Ternary(TernaryExpression<'ast>),
Binary(BinaryExpression<'ast>),
Postfix(PostfixExpression<'ast>),
Identifier(IdentifierExpression<'ast>),
Constant(ConstantExpression<'ast>),
InlineArray(InlineArrayExpression<'ast>),
Unary(UnaryExpression<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::postfix_expression))]
pub struct PostfixExpression<'ast> {
pub id: IdentifierExpression<'ast>,
pub access: Vec<Access<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::unary_expression))]
pub struct UnaryExpression<'ast> {
pub op: UnaryOperator<'ast>,
pub expression: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::inline_array_expression))]
pub struct InlineArrayExpression<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::optionally_typed_identifier))]
pub struct OptionallyTypedIdentifier<'ast> {
pub ty: Option<Type<'ast>>,
pub id: IdentifierExpression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::access))]
pub enum Access<'ast> {
Call(CallAccess<'ast>),
Select(ArrayAccess<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::call_access))]
pub struct CallAccess<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::array_access))]
pub struct ArrayAccess<'ast> {
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct BinaryExpression<'ast> {
pub op: BinaryOperator,
pub left: Box<Expression<'ast>>,
pub right: Box<Expression<'ast>>,
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::conditional_expression))]
pub struct TernaryExpression<'ast> {
pub first: Box<Expression<'ast>>,
pub second: Box<Expression<'ast>>,
pub third: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> Expression<'ast> {
pub fn ternary(
first: Box<Expression<'ast>>,
second: Box<Expression<'ast>>,
third: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Ternary(TernaryExpression {
first,
second,
third,
span,
})
}
pub fn binary(
op: BinaryOperator,
left: Box<Expression<'ast>>,
right: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Binary(BinaryExpression {
op,
left,
right,
span,
})
}
pub fn span(&self) -> &Span<'ast> {
match self {
Expression::Binary(b) => &b.span,
Expression::Identifier(i) => &i.span,
Expression::Constant(c) => &c.span,
Expression::Ternary(t) => &t.span,
Expression::Postfix(p) => &p.span,
Expression::InlineArray(a) => &a.span,
Expression::Unary(u) => &u.span,
}
}
}
impl<'ast> FromPest<'ast> for Expression<'ast> {
type Rule = Rule;
type FatalError = Void;
// We implement AST creation manually here for Expression
// `pest` should yield an `expression` which we can generate AST with, based on precedence rules
fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
// get a clone to "try" to match
let mut clone = pest.clone();
// advance by one pair in the clone, if none error out, `pest` is still the original
let pair = clone.next().ok_or(::from_pest::ConversionError::NoMatch)?;
// this should be an expression
match pair.as_rule() {
Rule::expression => {
// we can replace `pest` with the clone we tried with and got pairs from to create the AST
*pest = clone;
Ok(*climb(pair))
}
_ => Err(ConversionError::NoMatch),
}
}
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::constant))]
pub struct ConstantExpression<'ast> {
#[pest_ast(outer(with(span_into_str)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::identifier))]
pub struct IdentifierExpression<'ast> {
#[pest_ast(outer(with(span_into_str)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::assignee))]
pub struct Assignee<'ast> {
pub id: IdentifierExpression<'ast>, // a
pub indices: Vec<Expression<'ast>>, // [42 + x][31][7]
#[pest_ast(outer())]
pub span: Span<'ast>,
}
fn span_into_str(span: Span) -> String {
span.as_str().to_string()
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;
}
struct Prog<'ast>(ast::File<'ast>);
impl<'ast> From<Pairs<'ast, Rule>> for Prog<'ast> {
fn from(mut pairs: Pairs<'ast, Rule>) -> Prog<'ast> {
Prog(ast::File::from_pest(&mut pairs).unwrap())
}
}
#[derive(PartialEq, Clone, Debug)]
pub struct Error(PestError<Rule>);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub fn generate_ast(input: &str) -> Result<ast::File, Error> {
let parse_tree = parse(input).map_err(|e| Error(e))?;
Ok(Prog::from(parse_tree).0)
}
#[cfg(test)]
mod tests {
use super::ast::*;
use super::*;
use pest::Span;
#[test]
fn examples() {
use glob::glob;
use std::fs;
use std::io::Read;
// Traverse all .code files in examples dir
for entry in
glob("../zokrates_cli/examples/**/*.code").expect("Failed to read glob pattern")
{
match entry {
Ok(path) => {
if path.to_str().unwrap().contains("error") {
continue;
}
println!("Parsing {:?}", path.display());
let mut file = fs::File::open(path).unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();
let _res = generate_ast(&data).unwrap();
}
Err(e) => println!("{:?}", e),
}
}
}
impl<'ast> Expression<'ast> {
pub fn add(left: Expression<'ast>, right: Expression<'ast>, span: Span<'ast>) -> Self {
Self::binary(BinaryOperator::Add, Box::new(left), Box::new(right), span)
}
pub fn mul(left: Expression<'ast>, right: Expression<'ast>, span: Span<'ast>) -> Self {
Self::binary(BinaryOperator::Mul, Box::new(left), Box::new(right), span)
}
pub fn pow(left: Expression<'ast>, right: Expression<'ast>, span: Span<'ast>) -> Self {
Self::binary(BinaryOperator::Pow, Box::new(left), Box::new(right), span)
}
pub fn if_else(
condition: Expression<'ast>,
consequence: Expression<'ast>,
alternative: Expression<'ast>,
span: Span<'ast>,
) -> Self {
Self::ternary(
Box::new(condition),
Box::new(consequence),
Box::new(alternative),
span,
)
}
}
#[test]
fn one_plus_one() {
let source = r#"import "foo"
def main() -> (field): return 1 + 1
"#;
assert_eq!(
generate_ast(&source),
Ok(File {
functions: vec![Function {
id: IdentifierExpression {
value: String::from("main"),
span: Span::new(&source, 33, 37).unwrap()
},
parameters: vec![],
returns: vec![Type::Basic(BasicType::Field(FieldType {}))],
statements: vec![Statement::Return(ReturnStatement {
expressions: vec![Expression::add(
Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 59, 60).unwrap()
}),
Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 63, 64).unwrap()
}),
Span::new(&source, 59, 64).unwrap()
)],
span: Span::new(&source, 52, 64).unwrap(),
})],
span: Span::new(&source, 29, source.len()).unwrap(),
}],
imports: vec![ImportDirective {
source: ImportSource {
value: String::from("foo"),
span: Span::new(&source, 8, 11).unwrap()
},
alias: None,
span: Span::new(&source, 0, 29).unwrap()
}],
eoi: EOI {},
span: Span::new(&source, 0, 65).unwrap()
})
);
}
#[test]
fn precedence() {
let source = r#"import "foo"
def main() -> (field): return 1 + 2 * 3 ** 4
"#;
assert_eq!(
generate_ast(&source),
Ok(File {
functions: vec![Function {
id: IdentifierExpression {
value: String::from("main"),
span: Span::new(&source, 33, 37).unwrap()
},
parameters: vec![],
returns: vec![Type::Basic(BasicType::Field(FieldType {}))],
statements: vec![Statement::Return(ReturnStatement {
expressions: vec![Expression::add(
Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 59, 60).unwrap()
}),
Expression::mul(
Expression::Constant(ConstantExpression {
value: String::from("2"),
span: Span::new(&source, 63, 64).unwrap()
}),
Expression::pow(
Expression::Constant(ConstantExpression {
value: String::from("3"),
span: Span::new(&source, 67, 68).unwrap()
}),
Expression::Constant(ConstantExpression {
value: String::from("4"),
span: Span::new(&source, 72, 73).unwrap()
}),
Span::new(&source, 67, 73).unwrap()
),
Span::new(&source, 63, 73).unwrap()
),
Span::new(&source, 59, 73).unwrap()
)],
span: Span::new(&source, 52, 73).unwrap(),
})],
span: Span::new(&source, 29, 74).unwrap(),
}],
imports: vec![ImportDirective {
source: ImportSource {
value: String::from("foo"),
span: Span::new(&source, 8, 11).unwrap()
},
alias: None,
span: Span::new(&source, 0, 29).unwrap()
}],
eoi: EOI {},
span: Span::new(&source, 0, 74).unwrap()
})
);
}
#[test]
fn ternary() {
let source = r#"import "foo"
def main() -> (field): return if 1 then 2 else 3 fi
"#;
assert_eq!(
generate_ast(&source),
Ok(File {
functions: vec![Function {
id: IdentifierExpression {
value: String::from("main"),
span: Span::new(&source, 33, 37).unwrap()
},
parameters: vec![],
returns: vec![Type::Basic(BasicType::Field(FieldType {}))],
statements: vec![Statement::Return(ReturnStatement {
expressions: vec![Expression::if_else(
Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 62, 63).unwrap()
}),
Expression::Constant(ConstantExpression {
value: String::from("2"),
span: Span::new(&source, 69, 70).unwrap()
}),
Expression::Constant(ConstantExpression {
value: String::from("3"),
span: Span::new(&source, 76, 77).unwrap()
}),
Span::new(&source, 59, 80).unwrap()
)],
span: Span::new(&source, 52, 80).unwrap(),
})],
span: Span::new(&source, 29, 81).unwrap(),
}],
imports: vec![ImportDirective {
source: ImportSource {
value: String::from("foo"),
span: Span::new(&source, 8, 11).unwrap()
},
alias: None,
span: Span::new(&source, 0, 29).unwrap()
}],
eoi: EOI {},
span: Span::new(&source, 0, 81).unwrap()
})
);
}
#[test]
fn parentheses() {
let source = r#"def main() -> (field): return (1)
"#;
assert_eq!(
generate_ast(&source),
Ok(File {
functions: vec![Function {
id: IdentifierExpression {
value: String::from("main"),
span: Span::new(&source, 4, 8).unwrap()
},
parameters: vec![],
returns: vec![Type::Basic(BasicType::Field(FieldType {}))],
statements: vec![Statement::Return(ReturnStatement {
expressions: vec![Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 31, 32).unwrap()
})],
span: Span::new(&source, 23, 33).unwrap(),
})],
span: Span::new(&source, 0, 34).unwrap(),
}],
imports: vec![],
eoi: EOI {},
span: Span::new(&source, 0, 34).unwrap()
})
);
}
#[test]
fn multidef() {
let source = r#"def main() -> (field): field a, b = foo(1, 2 + 3)
"#;
assert_eq!(
generate_ast(&source),
Ok(File {
functions: vec![Function {
id: IdentifierExpression {
value: String::from("main"),
span: Span::new(&source, 4, 8).unwrap()
},
parameters: vec![],
returns: vec![Type::Basic(BasicType::Field(FieldType {}))],
statements: vec![Statement::MultiAssignment(MultiAssignmentStatement {
function_id: IdentifierExpression {
value: String::from("foo"),
span: Span::new(&source, 36, 39).unwrap()
},
lhs: vec![
OptionallyTypedIdentifier {
ty: Some(Type::Basic(BasicType::Field(FieldType {}))),
id: IdentifierExpression {
value: String::from("a"),
span: Span::new(&source, 29, 30).unwrap(),
},
span: Span::new(&source, 23, 30).unwrap()
},
OptionallyTypedIdentifier {
ty: None,
id: IdentifierExpression {
value: String::from("b"),
span: Span::new(&source, 32, 33).unwrap(),
},
span: Span::new(&source, 32, 33).unwrap()
},
],
arguments: vec![
Expression::Constant(ConstantExpression {
value: String::from("1"),
span: Span::new(&source, 40, 41).unwrap()
}),
Expression::add(
Expression::Constant(ConstantExpression {
value: String::from("2"),
span: Span::new(&source, 43, 44).unwrap()
}),
Expression::Constant(ConstantExpression {
value: String::from("3"),
span: Span::new(&source, 47, 48).unwrap()
}),
Span::new(&source, 43, 48).unwrap()
),
],
span: Span::new(&source, 23, 49).unwrap()
})],
span: Span::new(&source, 0, 50).unwrap(),
}],
imports: vec![],
eoi: EOI {},
span: Span::new(&source, 0, 50).unwrap()
})
);
}
#[test]
fn playground() {
let source = r#"import "heyman" as yo
def main(private field[23] a) -> (bool[234 + 6]):
field a = 1
a[32 + x][55] = y
for field i in 0..3 do
a == 1 + 2 + 3+ 4+ 5+ 6+ 6+ 7+ 8 + 4+ 5+ 3+ 4+ 2+ 3
endfor
a == 1
return a
"#;
let res = generate_ast(&source);
println!("{:#?}", generate_ast(&source));
assert!(res.is_ok());
}
}

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_stdlib"
version = "0.1.0"
version = "0.1.1"
authors = ["Stefan Deml <stefandeml@gmail.com>", "schaeff <thibaut@schaeff.fr>"]
edition = "2018"

View file

@ -0,0 +1 @@

View file

@ -1 +0,0 @@
fn main() {}