solve conflicts except compile loop
This commit is contained in:
parent
c06ca06cb7
commit
cdf394c7e1
70 changed files with 5090 additions and 5618 deletions
Binary file not shown.
658
Cargo.lock
generated
658
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
4
test.sh
4
test.sh
|
@ -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
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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, you’ve 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!
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {}),
|
||||
|
|
1
zokrates_cli/tests/code/n_choose_k.arguments.json
Normal file
1
zokrates_cli/tests/code/n_choose_k.arguments.json
Normal file
|
@ -0,0 +1 @@
|
|||
[5, 1]
|
12
zokrates_cli/tests/code/n_choose_k.code
Normal file
12
zokrates_cli/tests/code/n_choose_k.code
Normal 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))
|
1
zokrates_cli/tests/code/n_choose_k.expected.witness
Normal file
1
zokrates_cli/tests/code/n_choose_k.expected.witness
Normal file
|
@ -0,0 +1 @@
|
|||
~out_0 5
|
375
zokrates_core/Cargo.lock
generated
375
zokrates_core/Cargo.lock
generated
|
@ -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"
|
|
@ -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 }
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
521
zokrates_core/src/absy/from_ast.rs
Normal file
521
zokrates_core/src/absy/from_ast.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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)]
|
||||
|
|
|
@ -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)| {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
))
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
mod expression;
|
||||
mod expression_list;
|
||||
mod function;
|
||||
mod import;
|
||||
mod module;
|
||||
mod statement;
|
||||
|
||||
pub use self::module::parse_module;
|
|
@ -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,
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,3 @@
|
|||
mod position;
|
||||
mod token;
|
||||
mod tokenizer;
|
||||
|
||||
pub use self::position::Position;
|
||||
pub use self::token::Token;
|
||||
pub use self::tokenizer::*;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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(")", "")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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![],
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
12
zokrates_parser/Cargo.toml
Normal file
12
zokrates_parser/Cargo.toml
Normal 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"
|
3
zokrates_parser/README.md
Normal file
3
zokrates_parser/README.md
Normal 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
146
zokrates_parser/src/lib.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
100
zokrates_parser/src/zokrates.pest
Normal file
100
zokrates_parser/src/zokrates.pest
Normal 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"
|
||||
}
|
16
zokrates_pest_ast/Cargo.toml
Normal file
16
zokrates_pest_ast/Cargo.toml
Normal 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"
|
3
zokrates_pest_ast/README.md
Normal file
3
zokrates_pest_ast/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# zokrates_pest_ast
|
||||
|
||||
ZoKrates AST generation based on pest output.
|
880
zokrates_pest_ast/src/lib.rs
Normal file
880
zokrates_pest_ast/src/lib.rs
Normal 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());
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
1
zokrates_stdlib/src/lib.rs
Normal file
1
zokrates_stdlib/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -1 +0,0 @@
|
|||
fn main() {}
|
Loading…
Reference in a new issue