pull master

This commit is contained in:
collin 2020-08-15 02:28:34 -07:00
commit e1f4fe1846
178 changed files with 4217 additions and 1382 deletions

149
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,149 @@
name: Leo Release
on:
push:
tags:
- 'v*.*.*'
env:
RUST_BACKTRACE: 1
jobs:
ubuntu:
name: Ubuntu
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Load snarkOS
run: |
mkdir ~/.ssh
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s)
ssh-add -k ~/.ssh/id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_ubuntu
mv target/release/leo leo_${{ steps.get_version.outputs.version }}_ubuntu
zip -r leo_${{ steps.get_version.outputs.version }}_ubuntu.zip leo_${{ steps.get_version.outputs.version }}_ubuntu
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_ubuntu.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
macos:
name: macOS
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Load snarkOS
run: |
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s)
ssh-add -k ~/.ssh/id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_mac
mv target/release/leo leo_${{ steps.get_version.outputs.version }}_mac
zip -r leo_${{ steps.get_version.outputs.version }}_mac.zip leo_${{ steps.get_version.outputs.version }}_mac
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_mac.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
windows:
name: Windows
runs-on: windows-latest
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install SSH key
uses: shimataro/ssh-key-action@v1
with:
private-key: ${{ secrets.SNARKOS_DEPLOY_KEY_WINDOWS }}
public-key: ${{ secrets.SNARKOS_DEPLOY_KEY_WINDOWS_PUBLIC }}
name: id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_windows
mv target/release/leo.exe leo_${{ steps.get_version.outputs.version }}_windows
Compress-Archive leo_${{ steps.get_version.outputs.version }}_windows leo_${{ steps.get_version.outputs.version }}_windows.zip
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_windows.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

577
Cargo.lock generated
View File

@ -33,12 +33,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "arc-swap"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -158,7 +152,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [ dependencies = [
"generic-array 0.14.3", "generic-array 0.14.4",
] ]
[[package]] [[package]]
@ -262,9 +256,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.13" version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
dependencies = [ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
@ -294,9 +288,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.1" version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
@ -512,7 +506,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
] ]
[[package]] [[package]]
@ -530,7 +524,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [ dependencies = [
"generic-array 0.14.3", "generic-array 0.14.4",
] ]
[[package]] [[package]]
@ -541,9 +535,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
[[package]] [[package]]
name = "either" name = "either"
version = "1.5.3" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
@ -595,7 +589,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
"synstructure", "synstructure",
] ]
@ -769,9 +763,9 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.3" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60fb4bb6bba52f78a471264d9a3b7d026cc0af47b22cd2cffbc0b787ca003e63" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
@ -836,9 +830,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.8.1" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb" checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -944,9 +938,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.5.0" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7" checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -1066,9 +1060,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "lazycell" name = "lazycell"
version = "1.2.1" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "leo" name = "leo"
@ -1086,18 +1080,19 @@ dependencies = [
"leo-state", "leo-state",
"log", "log",
"notify", "notify",
"num-bigint",
"rand", "rand",
"rand_core", "rand_core",
"reqwest", "reqwest",
"rusty-hook", "rusty-hook",
"serde", "serde",
"serde_json", "serde_json",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-gadgets",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
"thiserror", "thiserror",
"toml", "toml",
] ]
@ -1135,13 +1130,13 @@ dependencies = [
"rand_xorshift", "rand_xorshift",
"serde", "serde",
"sha2", "sha2",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-dpc 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-dpc",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-gadgets",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-objects",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
"thiserror", "thiserror",
] ]
@ -1151,9 +1146,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"rand", "rand",
"rand_xorshift", "rand_xorshift",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
"thiserror", "thiserror",
] ]
@ -1165,11 +1160,11 @@ dependencies = [
"pest", "pest",
"pest-ast", "pest-ast",
"pest_derive", "pest_derive",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-gadgets",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"thiserror", "thiserror",
] ]
@ -1198,14 +1193,14 @@ dependencies = [
"leo-typed", "leo-typed",
"rand", "rand",
"rand_xorshift", "rand_xorshift",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-dpc 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-dpc",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-objects",
"snarkos-testing", "snarkos-storage",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
"thiserror", "thiserror",
] ]
@ -1219,8 +1214,8 @@ dependencies = [
"pest", "pest",
"serde", "serde",
"serde_json", "serde_json",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
] ]
[[package]] [[package]]
@ -1253,9 +1248,9 @@ dependencies = [
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.0.25" version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1352,7 +1347,7 @@ dependencies = [
"kernel32-sys", "kernel32-sys",
"libc", "libc",
"log", "log",
"miow 0.2.1", "miow",
"net2", "net2",
"slab", "slab",
"winapi 0.2.8", "winapi 0.2.8",
@ -1370,29 +1365,6 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "mio-named-pipes"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
dependencies = [
"log",
"mio",
"miow 0.3.5",
"winapi 0.3.9",
]
[[package]]
name = "mio-uds"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
"iovec",
"libc",
"mio",
]
[[package]] [[package]]
name = "miow" name = "miow"
version = "0.2.1" version = "0.2.1"
@ -1405,16 +1377,6 @@ dependencies = [
"ws2_32-sys", "ws2_32-sys",
] ]
[[package]]
name = "miow"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
dependencies = [
"socket2",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "native-tls" name = "native-tls"
version = "0.2.4" version = "0.2.4"
@ -1661,7 +1623,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
] ]
[[package]] [[package]]
@ -1692,7 +1654,7 @@ checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
] ]
[[package]] [[package]]
@ -2046,9 +2008,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.114" version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2065,13 +2027,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.114" version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
] ]
[[package]] [[package]]
@ -2128,16 +2090,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "signal-hook-registry"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
dependencies = [
"arc-swap",
"libc",
]
[[package]] [[package]]
name = "single" name = "single"
version = "1.0.0" version = "1.0.0"
@ -2155,14 +2107,14 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.4.1" version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
[[package]] [[package]]
name = "snarkos-algorithms" name = "snarkos-algorithms"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"blake2", "blake2",
"derivative", "derivative",
@ -2173,161 +2125,62 @@ dependencies = [
"rayon", "rayon",
"sha2", "sha2",
"smallvec", "smallvec",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-profiler 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-profiler",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-algorithms"
version = "0.8.0"
dependencies = [
"blake2",
"derivative",
"digest 0.8.1",
"itertools 0.9.0",
"rand",
"rand_chacha",
"rayon",
"sha2",
"smallvec",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-consensus"
version = "0.8.0"
dependencies = [
"bincode",
"chrono",
"hex",
"log",
"rand",
"serde",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-posw",
"snarkos-profiler 0.8.0",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
] ]
[[package]] [[package]]
name = "snarkos-curves" name = "snarkos-curves"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"derivative", "derivative",
"rand", "rand",
"rand_xorshift", "rand_xorshift",
"rustc_version", "rustc_version",
"serde", "serde",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-curves"
version = "0.8.0"
dependencies = [
"derivative",
"rand",
"rand_xorshift",
"rustc_version",
"serde",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
] ]
[[package]] [[package]]
name = "snarkos-derives" name = "snarkos-derives"
version = "0.1.0" version = "0.1.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
]
[[package]]
name = "snarkos-derives"
version = "0.1.0"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
] ]
[[package]] [[package]]
name = "snarkos-dpc" name = "snarkos-dpc"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"blake2", "blake2",
"derivative", "derivative",
"hex", "hex",
"itertools 0.9.0", "itertools 0.9.0",
"rand", "rand",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-gadgets",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-objects",
"snarkos-parameters 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-parameters",
"snarkos-profiler 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-profiler",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-dpc"
version = "0.8.0"
dependencies = [
"blake2",
"derivative",
"hex",
"itertools 0.9.0",
"rand",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-errors"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
dependencies = [
"base58",
"bech32",
"bincode",
"curl",
"hex",
"jsonrpc-core",
"rocksdb",
"thiserror",
] ]
[[package]] [[package]]
name = "snarkos-errors" name = "snarkos-errors"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"base58", "base58",
"bech32", "bech32",
@ -2337,60 +2190,28 @@ dependencies = [
"jsonrpc-core", "jsonrpc-core",
"rocksdb", "rocksdb",
"thiserror", "thiserror",
"toml",
] ]
[[package]] [[package]]
name = "snarkos-gadgets" name = "snarkos-gadgets"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"derivative", "derivative",
"digest 0.8.1", "digest 0.8.1",
"itertools 0.9.0", "itertools 0.9.0",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-gadgets"
version = "0.8.0"
dependencies = [
"derivative",
"digest 0.8.1",
"itertools 0.9.0",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-marlin"
version = "0.1.0"
dependencies = [
"blake2",
"derivative",
"digest 0.8.1",
"rand_chacha",
"rand_core",
"rayon",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-models 0.8.0",
"snarkos-polycommit",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
] ]
[[package]] [[package]]
name = "snarkos-models" name = "snarkos-models"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"bincode", "bincode",
"derivative", "derivative",
@ -2399,51 +2220,14 @@ dependencies = [
"rand_xorshift", "rand_xorshift",
"serde", "serde",
"smallvec", "smallvec",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-models"
version = "0.8.0"
dependencies = [
"bincode",
"derivative",
"itertools 0.9.0",
"rand",
"rand_xorshift",
"serde",
"smallvec",
"snarkos-errors 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-network"
version = "0.8.0"
dependencies = [
"bincode",
"byteorder",
"chrono",
"hex",
"log",
"rand",
"serde",
"snarkos-algorithms 0.8.0",
"snarkos-consensus",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
] ]
[[package]] [[package]]
name = "snarkos-objects" name = "snarkos-objects"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"base58", "base58",
"bech32", "bech32",
@ -2454,103 +2238,35 @@ dependencies = [
"rand", "rand",
"serde", "serde",
"sha2", "sha2",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-algorithms",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-curves",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-models",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-utilities",
]
[[package]]
name = "snarkos-objects"
version = "0.8.0"
dependencies = [
"base58",
"bech32",
"chrono",
"derivative",
"hex",
"once_cell",
"rand",
"serde",
"sha2",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-parameters"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
dependencies = [
"hex",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
] ]
[[package]] [[package]]
name = "snarkos-parameters" name = "snarkos-parameters"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"curl", "curl",
"hex", "hex",
"snarkos-algorithms 0.8.0", "snarkos-algorithms",
"snarkos-errors 0.8.0", "snarkos-errors",
"snarkos-models 0.8.0", "snarkos-models",
"snarkos-utilities 0.8.0", "snarkos-utilities",
]
[[package]]
name = "snarkos-polycommit"
version = "0.1.0"
dependencies = [
"derivative",
"digest 0.8.1",
"rand_core",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-posw"
version = "0.8.0"
dependencies = [
"blake2",
"rand",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-marlin",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-polycommit",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
"thiserror",
] ]
[[package]] [[package]]
name = "snarkos-profiler" name = "snarkos-profiler"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
[[package]]
name = "snarkos-profiler"
version = "0.8.0"
[[package]] [[package]]
name = "snarkos-storage" name = "snarkos-storage"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"bincode", "bincode",
"hex", "hex",
@ -2558,55 +2274,23 @@ dependencies = [
"rand", "rand",
"rocksdb", "rocksdb",
"serde", "serde",
"snarkos-algorithms 0.8.0", "snarkos-algorithms",
"snarkos-errors 0.8.0", "snarkos-errors",
"snarkos-models 0.8.0", "snarkos-models",
"snarkos-objects 0.8.0", "snarkos-objects",
"snarkos-parameters 0.8.0", "snarkos-parameters",
"snarkos-utilities 0.8.0", "snarkos-utilities",
]
[[package]]
name = "snarkos-testing"
version = "0.8.0"
dependencies = [
"once_cell",
"rand",
"rand_xorshift",
"snarkos-algorithms 0.8.0",
"snarkos-consensus",
"snarkos-curves 0.8.0",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-network",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-posw",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
] ]
[[package]] [[package]]
name = "snarkos-utilities" name = "snarkos-utilities"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [ dependencies = [
"bincode", "bincode",
"rand", "rand",
"snarkos-derives 0.1.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-derives",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)", "snarkos-errors",
]
[[package]]
name = "snarkos-utilities"
version = "0.8.0"
dependencies = [
"bincode",
"rand",
"snarkos-derives 0.1.0",
"snarkos-errors 0.8.0",
] ]
[[package]] [[package]]
@ -2646,9 +2330,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.36" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
@ -2663,7 +2347,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
"unicode-xid 0.2.1", "unicode-xid 0.2.1",
] ]
@ -2716,7 +2400,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
] ]
[[package]] [[package]]
@ -2765,28 +2449,11 @@ dependencies = [
"futures-core", "futures-core",
"iovec", "iovec",
"lazy_static", "lazy_static",
"libc",
"memchr", "memchr",
"mio", "mio",
"mio-named-pipes",
"mio-uds",
"num_cpus", "num_cpus",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry",
"slab", "slab",
"tokio-macros",
"winapi 0.3.9",
]
[[package]]
name = "tokio-macros"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
] ]
[[package]] [[package]]
@ -2996,7 +2663,7 @@ dependencies = [
"log", "log",
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3030,7 +2697,7 @@ checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
"syn 1.0.36", "syn 1.0.38",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]

View File

@ -29,13 +29,14 @@ snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-models", default-features = false } snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-models", default-features = false }
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-utilities" } snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-utilities" }
clap = { version = "2.33.0" } clap = { version = "2.33.3" }
colored = { version = "2.0" } colored = { version = "2.0" }
env_logger = { version = "0.7" } env_logger = { version = "0.7" }
from-pest = { version = "0.3.1" } from-pest = { version = "0.3.1" }
lazy_static = { version = "1.4.0" } lazy_static = { version = "1.4.0" }
log = { version = "0.4" } log = { version = "0.4" }
notify= { version = "4.0.15" } notify= { version = "4.0.15" }
num-bigint = { version = "0.3" }
rand = { version = "0.7" } rand = { version = "0.7" }
rand_core = { version = "0.5.1" } rand_core = { version = "0.5.1" }
reqwest = { version = "0.10.7", features = ["blocking", "json"] } reqwest = { version = "0.10.7", features = ["blocking", "json"] }

26
FAQ.md Normal file
View File

@ -0,0 +1,26 @@
# FAQs
#### For some given code, changing the value in a constant variable changes the number of constraints in the generated circuit. Is this behavior correct?
**Yes**, take the integers as an example. In Leo, integers are represented as its binary decomposition,
with each bit occupying one field element (that takes on 0 or 1). Then, for an expression such as `a == 4u32`, the operation to evaluate equality
would comprise a linear pass of bitwise `AND` operations, comparing every bit in the **variable** value with each bit in the **constant** value.
As the constant value is already known to the compiler during circuit synthesis, the compiler is already able to complete part of the equality evaluation,
by assuming that any bit in the constant value that is `0` will clearly evaluate to `0`. As such, depending on the value of the constant integer in your code,
the total number of constraints in the generate circuit can vary.
To illustrate this, here are two examples to show the difference:
```
const = 00000001
variable = abcdefgh
---------------------------------
output = 0000000h (1 constraint)
```
```
const = 01110001
variable = abcdefgh
---------------------------------
output = 0bcd000h (4 constraints)
```

View File

@ -3,6 +3,8 @@
![CI](https://github.com/AleoHQ/leo/workflows/CI/badge.svg) ![CI](https://github.com/AleoHQ/leo/workflows/CI/badge.svg)
[![codecov](https://codecov.io/gh/AleoHQ/leo/branch/master/graph/badge.svg?token=S6MWO60SYL)](https://codecov.io/gh/AleoHQ/leo) [![codecov](https://codecov.io/gh/AleoHQ/leo/branch/master/graph/badge.svg?token=S6MWO60SYL)](https://codecov.io/gh/AleoHQ/leo)
# Overview
## Compiler Architecture ## Compiler Architecture
<!-- generated by mermaid compile action - START --> <!-- generated by mermaid compile action - START -->

View File

@ -7,6 +7,7 @@ use serde::Serialize;
#[pest_ast(rule(Rule::access))] #[pest_ast(rule(Rule::access))]
pub enum Access<'ast> { pub enum Access<'ast> {
Array(ArrayAccess<'ast>), Array(ArrayAccess<'ast>),
Tuple(TupleAccess<'ast>),
Call(CallAccess<'ast>), Call(CallAccess<'ast>),
Object(MemberAccess<'ast>), Object(MemberAccess<'ast>),
StaticObject(StaticMemberAccess<'ast>), StaticObject(StaticMemberAccess<'ast>),

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
access::{ArrayAccess, MemberAccess}, access::{ArrayAccess, MemberAccess, TupleAccess},
ast::Rule, ast::Rule,
}; };
@ -11,6 +11,7 @@ use std::fmt;
#[pest_ast(rule(Rule::access_assignee))] #[pest_ast(rule(Rule::access_assignee))]
pub enum AssigneeAccess<'ast> { pub enum AssigneeAccess<'ast> {
Array(ArrayAccess<'ast>), Array(ArrayAccess<'ast>),
Tuple(TupleAccess<'ast>),
Member(MemberAccess<'ast>), Member(MemberAccess<'ast>),
} }
@ -18,6 +19,7 @@ impl<'ast> fmt::Display for AssigneeAccess<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
AssigneeAccess::Array(ref array) => write!(f, "[{}]", array.expression), AssigneeAccess::Array(ref array) => write!(f, "[{}]", array.expression),
AssigneeAccess::Tuple(ref tuple) => write!(f, ".{}", tuple.number),
AssigneeAccess::Member(ref member) => write!(f, ".{}", member.identifier), AssigneeAccess::Member(ref member) => write!(f, ".{}", member.identifier),
} }
} }

View File

@ -1,4 +1,4 @@
use crate::{ast::Rule, expressions::Expression, SpanDef}; use crate::{ast::Rule, expressions::TupleExpression, SpanDef};
use pest::Span; use pest::Span;
use pest_ast::FromPest; use pest_ast::FromPest;
@ -7,7 +7,7 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::access_call))] #[pest_ast(rule(Rule::access_call))]
pub struct CallAccess<'ast> { pub struct CallAccess<'ast> {
pub expressions: Vec<Expression<'ast>>, pub expressions: TupleExpression<'ast>,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]
pub span: Span<'ast>, pub span: Span<'ast>,

View File

@ -15,3 +15,6 @@ pub use member_access::*;
pub mod static_member_access; pub mod static_member_access;
pub use static_member_access::*; pub use static_member_access::*;
pub mod tuple_access;
pub use tuple_access::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, values::PositiveNumber, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::access_tuple))]
pub struct TupleAccess<'ast> {
pub number: PositiveNumber<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -14,6 +14,7 @@ use crate::{
values::Value, values::Value,
}; };
use crate::expressions::TupleExpression;
use from_pest::{ConversionError, FromPest, Void}; use from_pest::{ConversionError, FromPest, Void};
use pest::{ use pest::{
error::Error, error::Error,
@ -64,6 +65,9 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
let next = clone.into_inner().next().unwrap(); let next = clone.into_inner().next().unwrap();
match next.as_rule() { match next.as_rule() {
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
Rule::expression_tuple => {
Expression::Tuple(TupleExpression::from_pest(&mut pair.into_inner()).unwrap())
}
Rule::expression_array_inline => { Rule::expression_array_inline => {
Expression::ArrayInline(ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap()) Expression::ArrayInline(ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
} }

View File

@ -22,12 +22,6 @@ pub use range::*;
pub mod range_or_expression; pub mod range_or_expression;
pub use range_or_expression::*; pub use range_or_expression::*;
pub mod return_;
pub use return_::*;
pub mod return_tuple;
pub use return_tuple::*;
pub mod spread; pub mod spread;
pub use spread::*; pub use spread::*;
@ -37,5 +31,8 @@ pub use spread_or_expression::*;
pub mod static_; pub mod static_;
pub use static_::*; pub use static_::*;
pub mod variable; pub mod variables;
pub use variable::*; pub use variables::*;
pub mod variable_name;
pub use variable_name::*;

View File

@ -1,21 +0,0 @@
use crate::{ast::Rule, common::ReturnTuple, expressions::Expression};
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::return_))]
pub enum Return<'ast> {
Single(Expression<'ast>),
Tuple(ReturnTuple<'ast>),
}
impl<'ast> fmt::Display for Return<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Return::Single(ref expression) => write!(f, "{}", expression),
Return::Tuple(ref expressions) => write!(f, "{}", expressions),
}
}
}

View File

@ -1,27 +0,0 @@
use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::return_tuple))]
pub struct ReturnTuple<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for ReturnTuple<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, expression) in self.expressions.iter().enumerate() {
write!(f, "{}", expression)?;
if i < self.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}

View File

@ -1,7 +1,6 @@
use crate::{ use crate::{
ast::Rule, ast::Rule,
common::{Identifier, Mutable}, common::{Identifier, Mutable},
types::Type,
SpanDef, SpanDef,
}; };
@ -11,28 +10,21 @@ use serde::Serialize;
use std::fmt; use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::variable))] #[pest_ast(rule(Rule::variable_name))]
pub struct Variable<'ast> { pub struct VariableName<'ast> {
pub mutable: Option<Mutable>, pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>, pub identifier: Identifier<'ast>,
pub _type: Option<Type<'ast>>,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]
pub span: Span<'ast>, pub span: Span<'ast>,
} }
impl<'ast> fmt::Display for Variable<'ast> { impl<'ast> fmt::Display for VariableName<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref _mutable) = self.mutable { if let Some(ref _mutable) = self.mutable {
write!(f, "mut ")?; write!(f, "mut ")?;
} }
write!(f, "{}", self.identifier)?; write!(f, "{}", self.identifier)
if let Some(ref _type) = self._type {
write!(f, ": {}", _type)?;
}
write!(f, "")
} }
} }

View File

@ -0,0 +1,41 @@
use crate::{ast::Rule, common::VariableName, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::variables))]
pub struct Variables<'ast> {
pub names: Vec<VariableName<'ast>>,
pub type_: Option<Type<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Variables<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.names.len() == 1 {
// mut a
write!(f, "{}", self.names[0])?;
} else {
// (a, mut b)
let names = self
.names
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(",");
write!(f, "({})", names)?;
}
if self.type_.is_some() {
write!(f, ": {}", self.type_.as_ref().unwrap())?;
}
write!(f, "")
}
}

View File

@ -15,6 +15,7 @@ pub enum Expression<'ast> {
ArrayInitializer(ArrayInitializerExpression<'ast>), ArrayInitializer(ArrayInitializerExpression<'ast>),
CircuitInline(CircuitInlineExpression<'ast>), CircuitInline(CircuitInlineExpression<'ast>),
Postfix(PostfixExpression<'ast>), Postfix(PostfixExpression<'ast>),
Tuple(TupleExpression<'ast>),
} }
impl<'ast> Expression<'ast> { impl<'ast> Expression<'ast> {
@ -57,6 +58,7 @@ impl<'ast> Expression<'ast> {
Expression::ArrayInitializer(expression) => &expression.span, Expression::ArrayInitializer(expression) => &expression.span,
Expression::CircuitInline(expression) => &expression.span, Expression::CircuitInline(expression) => &expression.span,
Expression::Postfix(expression) => &expression.span, Expression::Postfix(expression) => &expression.span,
Expression::Tuple(expression) => &expression.span,
} }
} }
} }
@ -85,10 +87,9 @@ impl<'ast> fmt::Display for Expression<'ast> {
Expression::ArrayInitializer(ref expression) => { Expression::ArrayInitializer(ref expression) => {
write!(f, "[{} ; {}]", expression.expression, expression.count) write!(f, "[{} ; {}]", expression.expression, expression.count)
} }
Expression::CircuitInline(ref expression) => { Expression::CircuitInline(ref expression) => write!(f, "{}", expression.span.as_str()),
write!(f, "inline circuit display not impl {}", expression.identifier) Expression::Postfix(ref expression) => write!(f, "{}", expression.span.as_str()),
} Expression::Tuple(ref expression) => write!(f, "{}", expression.span.as_str()),
Expression::Postfix(ref expression) => write!(f, "Postfix display not impl {}", expression.identifier),
} }
} }
} }

View File

@ -21,3 +21,6 @@ pub use postfix_expression::*;
pub mod ternary_expression; pub mod ternary_expression;
pub use ternary_expression::*; pub use ternary_expression::*;
pub mod tuple_expression;
pub use tuple_expression::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::expression_tuple))]
pub struct TupleExpression<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -9,7 +9,7 @@ use serde::Serialize;
pub struct Function<'ast> { pub struct Function<'ast> {
pub identifier: Identifier<'ast>, pub identifier: Identifier<'ast>,
pub parameters: Vec<Input<'ast>>, pub parameters: Vec<Input<'ast>>,
pub returns: Vec<Type<'ast>>, pub returns: Option<Type<'ast>>,
pub statements: Vec<Statement<'ast>>, pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]

View File

@ -57,17 +57,16 @@ spread = { "..." ~ expression }
// Declared in common/spread_or_expression.rs // Declared in common/spread_or_expression.rs
spread_or_expression = { spread | expression } spread_or_expression = { spread | expression }
// Declared in common/return_.rs
return_ = { return_tuple | expression }
// Declared in common/return_tuple.rs
return_tuple = {"(" ~ expression ~ ("," ~ expression)+ ~ ")"}
// Declared in common/static_.rs // Declared in common/static_.rs
static_ = { "static " } static_ = { "static " }
// Declared in common/variable.rs // Declared in common/variable_name.rs
variable = { mutable? ~ identifier ~ (":" ~ type_)? }
variable_name = {mutable? ~ identifier}
variable_name_tuple = _{"(" ~ variable_name ~ ("," ~ variable_name)+ ~ ")"}
// Declared in common/variables.rs
variables = { ( variable_name_tuple | variable_name ) ~ (":" ~ type_ )? }
// Declared in common/declare.rs // Declared in common/declare.rs
declare = { let_ | const_ } declare = { let_ | const_ }
@ -124,7 +123,7 @@ operation_pow_assign = { "**=" }
/// Types /// Types
// Declared in types/type_.rs // Declared in types/type_.rs
type_ = { type_self | type_array | type_data | type_circuit } type_ = { type_self | type_tuple | type_array | type_data | type_circuit }
// Declared in types/integer_type.rs // Declared in types/integer_type.rs
type_integer = { type_integer = {
@ -192,7 +191,7 @@ type_circuit = { identifier }
// Declared in types/array_type.rs // Declared in types/array_type.rs
type_array = { type_data ~ ("[" ~ number_positive ~ "]")+ } type_array = { type_data ~ ("[" ~ number_positive ~ "]")+ }
type_list = _{ (type_ ~ ("," ~ type_)*)? } type_tuple = { "(" ~ NEWLINE* ~ type_ ~ ("," ~ NEWLINE* ~ type_)+ ~ ","? ~ NEWLINE* ~ ")" }
/// Values /// Values
@ -244,16 +243,19 @@ value_address = ${ type_address ~ "(" ~ address ~ ")" }
/// Access /// Access
// Declared in access/access.rs // Declared in access/access.rs
access = { access_array | access_call | access_member | access_static_member} access = { access_array | access_tuple | access_call | access_member | access_static_member}
// Declared in access/array_access.rs // Declared in access/array_access.rs
access_array = !{ "[" ~ range_or_expression ~ "]" } access_array = !{ "[" ~ range_or_expression ~ "]" }
// Declared in access/tuple_access.rs
access_tuple = ${ "." ~ number_positive }
// Declared in access/assignee_access.rs // Declared in access/assignee_access.rs
access_assignee = { access_array | access_member } access_assignee = { access_array | access_tuple | access_member }
// Declared in access/call_access.rs // Declared in access/call_access.rs
access_call = !{ "(" ~ expression_tuple ~ ")" } access_call = !{ expression_tuple }
// Declared in access/member_access.rs // Declared in access/member_access.rs
access_member = ${ "." ~ identifier } access_member = ${ "." ~ identifier }
@ -285,22 +287,25 @@ expression_conditional = { "if " ~ expression ~ "? " ~ expression ~ ": " ~ expre
/// Expressions /// Expressions
expression_term = { expression_term = {
("(" ~ expression ~ ")") value
| ("(" ~ expression ~ ")")
| expression_tuple
| expression_conditional
| expression_array_initializer | expression_array_initializer
| expression_array_inline | expression_array_inline
| expression_circuit_inline | expression_circuit_inline
| expression_conditional | expression_unary
| value
| expression_unary // must be defined below value to avoid conflicts with negative values
| expression_postfix | expression_postfix
| identifier | identifier
} }
expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
// Declared in expressions/expression.rs // Declared in expressions/expression.rs
expression = { expression_term ~ (operation_binary ~ expression_term)* } expression = { expression_term ~ (operation_binary ~ expression_term)* }
// Declared in expressions/expression_tuple.rs
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
// Declared in expressions/array_initializer_expression.rs // Declared in expressions/array_initializer_expression.rs
expression_array_initializer = { "[" ~ spread_or_expression ~ ";" ~ number_positive ~ "]" } expression_array_initializer = { "[" ~ spread_or_expression ~ ";" ~ number_positive ~ "]" }
@ -325,7 +330,6 @@ statement = {
(statement_return (statement_return
| statement_conditional | statement_conditional
| statement_for | statement_for
| statement_multiple_assignment
| statement_macro | statement_macro
| statement_definition | statement_definition
| statement_assign | statement_assign
@ -347,7 +351,7 @@ statement_conditional = {"if " ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ N
conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"} conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/definition_statement.rs // Declared in statements/definition_statement.rs
statement_definition = { declare ~ variable ~ "=" ~ expression ~ LINE_END} statement_definition = { declare ~ variables ~ "=" ~ expression ~ LINE_END}
// Declared in statements/expression_statement.rs // Declared in statements/expression_statement.rs
statement_expression = { expression ~ LINE_END } statement_expression = { expression ~ LINE_END }
@ -355,12 +359,8 @@ statement_expression = { expression ~ LINE_END }
// Declared in statements/for_statement.rs // Declared in statements/for_statement.rs
statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"} statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/multiple_assignment_statement.rs
statement_multiple_assignment = { declare ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END}
variable_tuple = _{ variable ~ ("," ~ variable)* }
// Declared in statements/return_statement.rs // Declared in statements/return_statement.rs
statement_return = { "return " ~ return_} statement_return = { "return " ~ expression}
/// Functions /// Functions
@ -368,7 +368,7 @@ statement_return = { "return " ~ return_}
test_function = { "test " ~ function } test_function = { "test " ~ function }
// Declared in functions/function.rs // Declared in functions/function.rs
function = { "function " ~ identifier ~ "(" ~ NEWLINE* ~ input_list ~ NEWLINE* ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* } function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
// Declared in functions/input/function_input.rs // Declared in functions/input/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ } function_input = { mutable? ~ identifier ~ ":" ~ type_ }
@ -381,7 +381,7 @@ input = {
function_input function_input
| input_keyword | input_keyword
} }
input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? } input_tuple = _{ "(" ~ NEWLINE* ~ (input ~ ("," ~ NEWLINE* ~ input)* ~ ","?)? ~ NEWLINE* ~ ")"}
/// Imports /// Imports

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::Rule, ast::Rule,
common::{Declare, LineEnd, Variable}, common::{Declare, LineEnd, Variables},
expressions::Expression, expressions::Expression,
SpanDef, SpanDef,
}; };
@ -14,8 +14,8 @@ use std::fmt;
#[pest_ast(rule(Rule::statement_definition))] #[pest_ast(rule(Rule::statement_definition))]
pub struct DefinitionStatement<'ast> { pub struct DefinitionStatement<'ast> {
pub declare: Declare, pub declare: Declare,
pub variable: Variable<'ast>, pub variables: Variables<'ast>,
pub expression: Expression<'ast>, pub expressions: Vec<Expression<'ast>>,
pub line_end: LineEnd, pub line_end: LineEnd,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]
@ -24,6 +24,13 @@ pub struct DefinitionStatement<'ast> {
impl<'ast> fmt::Display for DefinitionStatement<'ast> { impl<'ast> fmt::Display for DefinitionStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "let {} = {};", self.variable, self.expression) let expressions = self
.expressions
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(",");
write!(f, "let {} = {};", self.variables, expressions)
} }
} }

View File

@ -19,9 +19,6 @@ pub use expression_statement::*;
pub mod for_statement; pub mod for_statement;
pub use for_statement::*; pub use for_statement::*;
pub mod multiple_assignment_statement;
pub use multiple_assignment_statement::*;
pub mod return_statement; pub mod return_statement;
pub use return_statement::*; pub use return_statement::*;

View File

@ -1,36 +0,0 @@
use crate::{
ast::Rule,
common::{Declare, Identifier, LineEnd, Variable},
expressions::Expression,
SpanDef,
};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::statement_multiple_assignment))]
pub struct MultipleAssignmentStatement<'ast> {
pub declare: Declare,
pub variables: Vec<Variable<'ast>>,
pub function_name: Identifier<'ast>,
pub arguments: Vec<Expression<'ast>>,
pub line_end: LineEnd,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for MultipleAssignmentStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, id) in self.variables.iter().enumerate() {
write!(f, "{}", id)?;
if i < self.variables.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " = {}", self.function_name)
}
}

View File

@ -1,4 +1,4 @@
use crate::{ast::Rule, common::Return, SpanDef}; use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span; use pest::Span;
use pest_ast::FromPest; use pest_ast::FromPest;
@ -8,7 +8,7 @@ use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::statement_return))] #[pest_ast(rule(Rule::statement_return))]
pub struct ReturnStatement<'ast> { pub struct ReturnStatement<'ast> {
pub return_: Return<'ast>, pub expression: Expression<'ast>,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]
pub span: Span<'ast>, pub span: Span<'ast>,
@ -16,6 +16,6 @@ pub struct ReturnStatement<'ast> {
impl<'ast> fmt::Display for ReturnStatement<'ast> { impl<'ast> fmt::Display for ReturnStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.return_) write!(f, "return {}", self.expression)
} }
} }

View File

@ -10,7 +10,6 @@ pub enum Statement<'ast> {
Return(ReturnStatement<'ast>), Return(ReturnStatement<'ast>),
Definition(DefinitionStatement<'ast>), Definition(DefinitionStatement<'ast>),
Assign(AssignStatement<'ast>), Assign(AssignStatement<'ast>),
MultipleAssignment(MultipleAssignmentStatement<'ast>),
Conditional(ConditionalStatement<'ast>), Conditional(ConditionalStatement<'ast>),
Iteration(ForStatement<'ast>), Iteration(ForStatement<'ast>),
Assert(MacroStatement<'ast>), Assert(MacroStatement<'ast>),
@ -23,7 +22,6 @@ impl<'ast> fmt::Display for Statement<'ast> {
Statement::Return(ref statement) => write!(f, "{}", statement), Statement::Return(ref statement) => write!(f, "{}", statement),
Statement::Definition(ref statement) => write!(f, "{}", statement), Statement::Definition(ref statement) => write!(f, "{}", statement),
Statement::Assign(ref statement) => write!(f, "{}", statement), Statement::Assign(ref statement) => write!(f, "{}", statement),
Statement::MultipleAssignment(ref statement) => write!(f, "{}", statement),
Statement::Conditional(ref statement) => write!(f, "{}", statement), Statement::Conditional(ref statement) => write!(f, "{}", statement),
Statement::Iteration(ref statement) => write!(f, "{}", statement), Statement::Iteration(ref statement) => write!(f, "{}", statement),
Statement::Assert(ref statement) => write!(f, "{}", statement), Statement::Assert(ref statement) => write!(f, "{}", statement),

View File

@ -28,6 +28,9 @@ pub use self_type::*;
pub mod signed_integer_type; pub mod signed_integer_type;
pub use signed_integer_type::*; pub use signed_integer_type::*;
pub mod tuple_type;
pub use tuple_type::*;
pub mod type_; pub mod type_;
pub use type_::*; pub use type_::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::type_tuple))]
pub struct TupleType<'ast> {
pub types: Vec<Type<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -9,6 +9,7 @@ use std::fmt;
pub enum Type<'ast> { pub enum Type<'ast> {
Basic(DataType), Basic(DataType),
Array(ArrayType<'ast>), Array(ArrayType<'ast>),
Tuple(TupleType<'ast>),
Circuit(CircuitType<'ast>), Circuit(CircuitType<'ast>),
SelfType(SelfType), SelfType(SelfType),
} }
@ -18,6 +19,7 @@ impl<'ast> fmt::Display for Type<'ast> {
match *self { match *self {
Type::Basic(ref _type) => write!(f, "basic"), Type::Basic(ref _type) => write!(f, "basic"),
Type::Array(ref _type) => write!(f, "array"), Type::Array(ref _type) => write!(f, "array"),
Type::Tuple(ref _type) => write!(f, "tuple"),
Type::Circuit(ref _type) => write!(f, "struct"), Type::Circuit(ref _type) => write!(f, "struct"),
Type::SelfType(ref _type) => write!(f, "Self"), Type::SelfType(ref _type) => write!(f, "Self"),
} }

View File

@ -11,47 +11,45 @@
} }
}, },
"parameters": [], "parameters": [],
"returns": [], "returns": null,
"statements": [ "statements": [
{ {
"Return": { "Return": {
"return_": { "expression": {
"Single": { "Binary": {
"Binary": { "operation": "Add",
"operation": "Add", "left": {
"left": { "Value": {
"Value": { "Implicit": {
"Implicit": { "Positive": {
"Positive": { "value": "1",
"value": "1", "span": {
"span": { "input": "1",
"input": "1", "start": 29,
"start": 29, "end": 30
"end": 30
}
} }
} }
} }
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
}
}
}
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
} }
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
}
}
}
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
} }
} }
}, },

View File

@ -140,13 +140,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
/// Synthesizes the circuit without program input to verify correctness. /// Synthesizes the circuit without program input to verify correctness.
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> { pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
let path = self.main_file_path; let path = self.main_file_path;
let input = self.program_input.empty();
generate_constraints::<F, G, CS>(cs, self.program, input, &self.imported_programs).map_err(|mut error| { generate_constraints::<F, G, CS>(cs, self.program, self.program_input, &self.imported_programs).map_err(
error.set_path(path); |mut error| {
error.set_path(path);
error error
}) },
)
} }
/// Synthesizes the circuit for test functions with program input. /// Synthesizes the circuit for test functions with program input.

View File

@ -5,7 +5,7 @@ use crate::{
value::ConstrainedValue, value::ConstrainedValue,
GroupType, GroupType,
}; };
use leo_typed::Variable; use leo_typed::Identifier;
use snarkos_models::curves::{Field, PrimeField}; use snarkos_models::curves::{Field, PrimeField};
@ -13,15 +13,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn store_definition( pub fn store_definition(
&mut self, &mut self,
function_scope: String, function_scope: String,
variable: Variable, mutable: bool,
identifier: Identifier,
mut value: ConstrainedValue<F, G>, mut value: ConstrainedValue<F, G>,
) -> () { ) -> () {
// Store with given mutability // Store with given mutability
if variable.mutable { if mutable {
value = ConstrainedValue::Mutable(Box::new(value)); value = ConstrainedValue::Mutable(Box::new(value));
} }
let variable_program_identifier = new_scope(function_scope, variable.identifier.name); let variable_program_identifier = new_scope(function_scope, identifier.name);
self.store(variable_program_identifier, value); self.store(variable_program_identifier, value);
} }

View File

@ -70,14 +70,14 @@ impl ExpressionError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn unexpected_array(expected: String, actual: String, span: Span) -> Self { pub fn incompatible_types(operation: String, span: Span) -> Self {
let message = format!("expected type `{}`, found array with elements `{}`", expected, actual); let message = format!("no implementation for `{}`", operation);
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn incompatible_types(operation: String, span: Span) -> Self { pub fn index_out_of_bounds(index: usize, span: Span) -> Self {
let message = format!("no implementation for `{}`", operation); let message = format!("cannot access index {} of tuple out of bounds", index);
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
@ -159,4 +159,16 @@ impl ExpressionError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn unexpected_array(expected: String, actual: String, span: Span) -> Self {
let message = format!("expected type `{}`, found array with elements `{}`", expected, actual);
Self::new_from_span(message, span)
}
pub fn unexpected_tuple(expected: String, actual: String, span: Span) -> Self {
let message = format!("expected type `{}`, found tuple with values `{}`", expected, actual);
Self::new_from_span(message, span)
}
} }

View File

@ -78,6 +78,12 @@ impl FunctionError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn invalid_tuple(actual: String, span: Span) -> Self {
let message = format!("Expected function input tuple, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn return_arguments_length(expected: usize, actual: usize, span: Span) -> Self { pub fn return_arguments_length(expected: usize, actual: usize, span: Span) -> Self {
let message = format!("function expected {} returns, found {} returns", expected, actual); let message = format!("function expected {} returns, found {} returns", expected, actual);

View File

@ -19,12 +19,6 @@ impl OutputBytesError {
OutputBytesError::Error(FormattedError::new_from_span(message, span)) OutputBytesError::Error(FormattedError::new_from_span(message, span))
} }
pub fn illegal_return(value: String, span: Span) -> Self {
let message = format!("program return must be a return value, found `{}`", value);
Self::new_from_span(message, span)
}
pub fn not_enough_registers(span: Span) -> Self { pub fn not_enough_registers(span: Span) -> Self {
let message = format!("number of input registers must be greater than or equal to output registers"); let message = format!("number of input registers must be greater than or equal to output registers");

View File

@ -113,6 +113,12 @@ impl StatementError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn multiple_definition(value: String, span: Span) -> Self {
let message = format!("cannot assign multiple variables to a single value: {}", value,);
Self::new_from_span(message, span)
}
pub fn select_fail(first: String, second: String, span: Span) -> Self { pub fn select_fail(first: String, second: String, span: Span) -> Self {
let message = format!( let message = format!(
"Conditional select gadget failed to select between `{}` or `{}`", "Conditional select gadget failed to select between `{}` or `{}`",
@ -122,6 +128,18 @@ impl StatementError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn tuple_assign_index(span: Span) -> Self {
let message = format!("Cannot assign single index to tuple of values");
Self::new_from_span(message, span)
}
pub fn tuple_type(type_: String, span: Span) -> Self {
let message = format!("Expected tuple type, found type `{}`", type_);
Self::new_from_span(message, span)
}
pub fn unassigned(name: String, span: Span) -> Self { pub fn unassigned(name: String, span: Span) -> Self {
let message = format!("Expected assignment of return values for expression `{}`", name); let message = format!("Expected assignment of return values for expression `{}`", name);

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
array: Box<Expression>, array: Box<Expression>,
index: RangeOrExpression, index: RangeOrExpression,
span: Span, span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*array, *array,
span.clone(), span.clone(),
)? { )? {

View File

@ -20,23 +20,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, mut expected_type: Option<Type>,
array: Vec<Box<SpreadOrExpression>>, array: Vec<Box<SpreadOrExpression>>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit array type dimension if given // Check explicit array type dimension if given
let mut expected_types = expected_types.clone();
let expected_dimensions = vec![]; let expected_dimensions = vec![];
if !expected_types.is_empty() { if expected_type.is_some() {
match expected_types[0] { match expected_type.unwrap() {
Type::Array(ref _type, ref dimensions) => { Type::Array(ref type_, ref dimensions) => {
expected_types = vec![expected_types[0].inner_dimension(dimensions)]; expected_type = Some(type_.inner_dimension(dimensions).clone());
} }
ref _type => { ref _type => {
return Err(ExpressionError::unexpected_array( return Err(ExpressionError::unexpected_array(
expected_types[0].to_string(),
_type.to_string(), _type.to_string(),
format!("{:?}", array),
span, span,
)); ));
} }
@ -66,7 +65,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&expected_types, expected_type.clone(),
expression, expression,
)?); )?);
} }

View File

@ -17,12 +17,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
index: Expression, index: Expression,
span: Span, span: Span,
) -> Result<usize, ExpressionError> { ) -> Result<usize, ExpressionError> {
let expected_types = vec![Type::IntegerType(IntegerType::U32)]; let expected_type = Some(Type::IntegerType(IntegerType::U32));
match self.enforce_operand( match self.enforce_operand(
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&expected_types, expected_type,
index, index,
span.clone(), span.clone(),
)? { )? {

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
left: Expression, left: Expression,
right: Expression, right: Expression,
span: Span, span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type.clone(),
left, left,
span.clone(), span.clone(),
)?; )?;
@ -31,12 +31,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type.clone(),
right, right,
span.clone(), span.clone(),
)?; )?;
resolved_left.resolve_types(&mut resolved_right, expected_types, span)?; resolved_left.resolve_types(&mut resolved_right, expected_type, span)?;
Ok((resolved_left, resolved_right)) Ok((resolved_left, resolved_right))
} }

View File

@ -17,14 +17,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
expression: Expression, expression: Expression,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?; let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_type.clone(), expression)?;
branch.get_inner_mut(); branch.get_inner_mut();
branch.resolve_type(expected_types, span)?; branch.resolve_type(expected_type, span)?;
Ok(branch) Ok(branch)
} }

View File

@ -21,7 +21,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
circuit_identifier: Box<Expression>, circuit_identifier: Box<Expression>,
circuit_member: Identifier, circuit_member: Identifier,
span: Span, span: Span,
@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let self_function_scope = new_scope(self_file_scope.clone(), identifier.name.to_string()); let self_function_scope = new_scope(self_file_scope.clone(), identifier.name.to_string());
let member_value = let member_value =
self.evaluate_identifier(self_file_scope, self_function_scope, &vec![], circuit_member.clone())?; self.evaluate_identifier(self_file_scope, self_function_scope, None, circuit_member.clone())?;
return Ok(member_value); return Ok(member_value);
} }
@ -43,7 +43,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*circuit_identifier.clone(), *circuit_identifier.clone(),
span.clone(), span.clone(),
)? { )? {

View File

@ -51,7 +51,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![_type.clone()], Some(_type.clone()),
field.expression, field.expression,
)?; )?;

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
circuit_identifier: Box<Expression>, circuit_identifier: Box<Expression>,
circuit_member: Identifier, circuit_member: Identifier,
span: Span, span: Span,
@ -24,7 +24,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*circuit_identifier.clone(), *circuit_identifier.clone(),
)? { )? {
ConstrainedValue::CircuitDefinition(circuit_definition) => circuit_definition, ConstrainedValue::CircuitDefinition(circuit_definition) => circuit_definition,

View File

@ -15,7 +15,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
conditional: Expression, conditional: Expression,
first: Expression, first: Expression,
second: Expression, second: Expression,
@ -25,7 +25,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![Type::Boolean], Some(Type::Boolean),
conditional, conditional,
)? { )? {
ConstrainedValue::Boolean(resolved) => resolved, ConstrainedValue::Boolean(resolved) => resolved,
@ -36,7 +36,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type.clone(),
first, first,
span.clone(), span.clone(),
)?; )?;
@ -45,7 +45,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
second, second,
span.clone(), span.clone(),
)?; )?;

View File

@ -25,13 +25,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
expression: Expression, expression: Expression,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match expression { match expression {
// Variables // Variables
Expression::Identifier(unresolved_variable) => { Expression::Identifier(unresolved_variable) => {
self.evaluate_identifier(file_scope, function_scope, expected_types, unresolved_variable) self.evaluate_identifier(file_scope, function_scope, expected_type, unresolved_variable)
} }
// Values // Values
@ -39,7 +39,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, span)?)), Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, span)?)),
Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)), Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)),
Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)), Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)),
Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_types, value, span)?), Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_type, value, span)?),
Expression::Integer(type_, integer, span) => { Expression::Integer(type_, integer, span) => {
Ok(ConstrainedValue::Integer(Integer::new_constant(&type_, integer, span)?)) Ok(ConstrainedValue::Integer(Integer::new_constant(&type_, integer, span)?))
} }
@ -47,7 +47,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Binary operations // Binary operations
Expression::Negate(expression, span) => { Expression::Negate(expression, span) => {
let resolved_value = let resolved_value =
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?; self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?;
enforce_negate(cs, resolved_value, span) enforce_negate(cs, resolved_value, span)
} }
@ -56,7 +56,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -69,7 +69,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -82,7 +82,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -95,7 +95,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -108,7 +108,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -119,7 +119,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Boolean operations // Boolean operations
Expression::Not(expression, span) => Ok(evaluate_not( Expression::Not(expression, span) => Ok(evaluate_not(
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?, self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?,
span, span,
)?), )?),
Expression::Or(left, right, span) => { Expression::Or(left, right, span) => {
@ -127,7 +127,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -140,7 +140,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -153,7 +153,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -166,7 +166,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -179,7 +179,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -192,7 +192,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -205,7 +205,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
*left, *left,
*right, *right,
span.clone(), span.clone(),
@ -219,7 +219,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope, file_scope,
function_scope, function_scope,
expected_types, expected_type,
*conditional, *conditional,
*first, *first,
*second, *second,
@ -228,10 +228,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Arrays // Arrays
Expression::Array(array, span) => { Expression::Array(array, span) => {
self.enforce_array(cs, file_scope, function_scope, expected_types, array, span) self.enforce_array(cs, file_scope, function_scope, expected_type, array, span)
} }
Expression::ArrayAccess(array, index, span) => { Expression::ArrayAccess(array, index, span) => {
self.enforce_array_access(cs, file_scope, function_scope, expected_types, array, *index, span) self.enforce_array_access(cs, file_scope, function_scope, expected_type, array, *index, span)
}
// Tuples
Expression::Tuple(tuple, span) => {
self.enforce_tuple(cs, file_scope, function_scope, expected_type, tuple, span)
}
Expression::TupleAccess(tuple, index, span) => {
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, tuple, index, span)
} }
// Circuits // Circuits
@ -242,7 +250,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope, file_scope,
function_scope, function_scope,
expected_types, expected_type,
circuit_variable, circuit_variable,
circuit_member, circuit_member,
span, span,
@ -252,7 +260,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope, file_scope,
function_scope, function_scope,
expected_types, expected_type,
circuit_identifier, circuit_identifier,
circuit_member, circuit_member,
span, span,
@ -263,7 +271,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope, file_scope,
function_scope, function_scope,
expected_types, expected_type,
function, function,
arguments, arguments,
span, span,

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
function: Box<Expression>, function: Box<Expression>,
arguments: Vec<Expression>, arguments: Vec<Expression>,
span: Span, span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
expected_types, expected_type,
*function.clone(), *function.clone(),
)?; )?;
@ -36,22 +36,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.start, span.start,
); );
match self.enforce_function( self.enforce_function(
&mut cs.ns(|| name_unique), &mut cs.ns(|| name_unique),
outer_scope, outer_scope,
function_scope, function_scope,
function_call, function_call,
arguments, arguments,
) { )
Ok(ConstrainedValue::Return(return_values)) => { .map_err(|error| ExpressionError::from(Box::new(error)))
if return_values.len() == 1 {
Ok(return_values[0].clone())
} else {
Ok(ConstrainedValue::Return(return_values))
}
}
Ok(_) => Err(ExpressionError::function_no_return(function.to_string(), span)),
Err(error) => Err(ExpressionError::from(Box::new(error))),
}
} }
} }

View File

@ -17,7 +17,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&mut self, &mut self,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expected_types: &Vec<Type>, expected_type: Option<Type>,
unresolved_identifier: Identifier, unresolved_identifier: Identifier,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Evaluate the identifier name in the current function scope // Evaluate the identifier name in the current function scope
@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} else if let Some(value) = self.get(&unresolved_identifier.name) { } else if let Some(value) = self.get(&unresolved_identifier.name) {
// Check imported file scope // Check imported file scope
value.clone() value.clone()
} else if expected_types.contains(&Type::Address) { } else if expected_type.is_some() && expected_type.unwrap() == Type::Address {
// If we expect an address type, try to return an address // If we expect an address type, try to return an address
let address = Address::new(unresolved_identifier.name, unresolved_identifier.span)?; let address = Address::new(unresolved_identifier.name, unresolved_identifier.span)?;
@ -42,7 +42,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(ExpressionError::undefined_identifier(unresolved_identifier)); return Err(ExpressionError::undefined_identifier(unresolved_identifier));
}; };
result_value.resolve_type(expected_types, unresolved_identifier.span.clone())?; result_value.resolve_type(expected_type, unresolved_identifier.span.clone())?;
Ok(result_value) Ok(result_value)
} }

View File

@ -29,3 +29,6 @@ pub use self::logical::*;
pub mod relational; pub mod relational;
pub use self::relational::*; pub use self::relational::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,40 @@
//! Enforces array access in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_tuple_access<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_type: Option<Type>,
tuple: Box<Expression>,
index: usize,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let tuple = match self.enforce_operand(
cs,
file_scope.clone(),
function_scope.clone(),
expected_type,
*tuple,
span.clone(),
)? {
ConstrainedValue::Tuple(tuple) => tuple,
value => return Err(ExpressionError::undefined_array(value.to_string(), span.clone())),
};
if index > tuple.len() - 1 {
return Err(ExpressionError::index_out_of_bounds(index, span));
}
Ok(tuple[index].to_owned())
}
}

View File

@ -0,0 +1,7 @@
//! Methods to enforce tuple expressions in a compiled Leo program.
pub mod access;
pub use self::access::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,53 @@
//! Enforces an tuple expression in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Enforce tuple expressions
pub fn enforce_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_type: Option<Type>,
tuple: Vec<Expression>,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit tuple type dimension if given
let mut expected_types = vec![];
if expected_type.is_some() {
match expected_type.unwrap() {
Type::Tuple(ref types) => {
expected_types = types.clone();
}
ref type_ => {
return Err(ExpressionError::unexpected_tuple(
type_.to_string(),
format!("{:?}", tuple),
span,
));
}
}
}
let mut result = vec![];
for (i, expression) in tuple.into_iter().enumerate() {
let type_ = if expected_types.is_empty() {
None
} else {
Some(expected_types[i].clone())
};
result.push(self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), type_, expression)?);
}
Ok(ConstrainedValue::Tuple(result))
}
}

View File

@ -7,7 +7,7 @@ use crate::{
GroupType, GroupType,
}; };
use leo_typed::{Expression, Function, InputVariable, Span}; use leo_typed::{Expression, Function, InputVariable, Span, Type};
use snarkos_models::{ use snarkos_models::{
curves::{Field, PrimeField}, curves::{Field, PrimeField},
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope.clone(), scope.clone(),
caller_scope.clone(), caller_scope.clone(),
function_name.clone(), function_name.clone(),
vec![], None,
input_expression, input_expression,
)?; )?;
@ -59,7 +59,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope.clone(), scope.clone(),
caller_scope.clone(), caller_scope.clone(),
function_name.clone(), function_name.clone(),
vec![input_model.type_.clone()], Some(input_model.type_.clone()),
input_expression, input_expression,
)?; )?;
@ -93,14 +93,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} }
// Conditionally select a result based on returned indicators // Conditionally select a result based on returned indicators
let mut return_values = ConstrainedValue::Return(vec![]); let mut return_values = ConstrainedValue::Tuple(vec![]);
Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?; Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?;
if let ConstrainedValue::Return(ref returns) = return_values { if let ConstrainedValue::Tuple(ref returns) = return_values {
if function.returns.len() != returns.len() { let return_types = match function.returns {
Some(Type::Tuple(types)) => types.len(),
Some(_) => 1usize,
None => 0usize,
};
if return_types != returns.len() {
return Err(FunctionError::return_arguments_length( return Err(FunctionError::return_arguments_length(
function.returns.len(), return_types,
returns.len(), returns.len(),
function.span.clone(), function.span.clone(),
)); ));

View File

@ -16,16 +16,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope: String, scope: String,
caller_scope: String, caller_scope: String,
function_name: String, function_name: String,
expected_types: Vec<Type>, expected_type: Option<Type>,
input: Expression, input: Expression,
) -> Result<ConstrainedValue<F, G>, FunctionError> { ) -> Result<ConstrainedValue<F, G>, FunctionError> {
// Evaluate the function input value as pass by value from the caller or // Evaluate the function input value as pass by value from the caller or
// evaluate as an expression in the current function scope // evaluate as an expression in the current function scope
match input { match input {
Expression::Identifier(identifier) => { Expression::Identifier(identifier) => {
Ok(self.evaluate_identifier(caller_scope, function_name, &expected_types, identifier)?) Ok(self.evaluate_identifier(caller_scope, function_name, expected_type, identifier)?)
} }
expression => Ok(self.enforce_expression(cs, scope, function_name, &expected_types, expression)?), expression => Ok(self.enforce_expression(cs, scope, function_name, expected_type, expression)?),
} }
} }
} }

View File

@ -42,7 +42,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
input_option, input_option,
span, span,
)?)), )?)),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_option, span), Type::Array(type_, dimensions) => self.allocate_array(cs, name, *type_, dimensions, input_option, span),
Type::Tuple(types) => self.allocate_tuple(cs, name, types, input_option, span),
_ => unimplemented!("main function input not implemented for type"), _ => unimplemented!("main function input not implemented for type"),
} }
} }

View File

@ -14,3 +14,6 @@ pub use self::input_keyword::*;
pub mod input_section; pub mod input_section;
pub use self::input_section::*; pub use self::input_section::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,56 @@
//! Allocates an array as a main function input parameter in a compiled Leo program.
use crate::{
errors::FunctionError,
program::{new_scope, ConstrainedProgram},
value::ConstrainedValue,
GroupType,
};
use leo_typed::{InputValue, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn allocate_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
name: String,
types: Vec<Type>,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
let mut tuple_values = vec![];
match input_value {
Some(InputValue::Tuple(values)) => {
// Allocate each value in the tuple
for (i, (value, type_)) in values.into_iter().zip(types.into_iter()).enumerate() {
let value_name = new_scope(name.clone(), i.to_string());
tuple_values.push(self.allocate_main_function_input(
cs,
type_,
value_name,
Some(value),
span.clone(),
)?)
}
}
None => {
// Allocate all tuple values as none
for (i, type_) in types.into_iter().enumerate() {
let value_name = new_scope(name.clone(), i.to_string());
tuple_values.push(self.allocate_main_function_input(cs, type_, value_name, None, span.clone())?);
}
}
_ => return Err(FunctionError::invalid_tuple(input_value.unwrap().to_string(), span)),
}
Ok(ConstrainedValue::Tuple(tuple_values))
}
}

View File

@ -41,7 +41,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![], None,
parameter.expression, parameter.expression,
)?; )?;

View File

@ -20,8 +20,8 @@ impl OutputBytes {
span: Span, span: Span,
) -> Result<Self, OutputBytesError> { ) -> Result<Self, OutputBytesError> {
let return_values = match value { let return_values = match value {
ConstrainedValue::Return(values) => values, ConstrainedValue::Tuple(values) => values,
value => return Err(OutputBytesError::illegal_return(value.to_string(), span)), value => vec![value],
}; };
let register_hashmap = registers.values(); let register_hashmap = registers.values();

View File

@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Modify the single value of the array in place // Modify the single value of the array in place
match self.get_mutable_assignee(name, span.clone())? { match self.get_mutable_assignee(name, span.clone())? {
ConstrainedValue::Array(old) => { ConstrainedValue::Array(old) => {
new_value.resolve_type(&vec![old[index].to_type(span.clone())?], span.clone())?; new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select( let selected_value = ConstrainedValue::conditionally_select(

View File

@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Evaluate new value // Evaluate new value
let mut new_value = let mut new_value =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), &vec![], expression)?; self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), None, expression)?;
// Mutate the old value into the new value // Mutate the old value into the new value
match assignee { match assignee {
@ -41,7 +41,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let condition = indicator.unwrap_or(Boolean::Constant(true)); let condition = indicator.unwrap_or(Boolean::Constant(true));
let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?; let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?;
new_value.resolve_type(&vec![old_value.to_type(span.clone())?], span.clone())?; new_value.resolve_type(Some(old_value.to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = let selected_value =
@ -62,6 +62,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
new_value, new_value,
span, span,
), ),
Assignee::Tuple(_tuple, index) => self.assign_tuple(cs, indicator, variable_name, index, new_value, span),
Assignee::CircuitField(_assignee, object_name) => { Assignee::CircuitField(_assignee, object_name) => {
self.mutute_circuit_field(cs, indicator, variable_name, object_name, new_value, span) self.mutute_circuit_field(cs, indicator, variable_name, object_name, new_value, span)
} }

View File

@ -9,6 +9,7 @@ pub fn resolve_assignee(scope: String, assignee: Assignee) -> String {
match assignee { match assignee {
Assignee::Identifier(name) => new_scope(scope, name.to_string()), Assignee::Identifier(name) => new_scope(scope, name.to_string()),
Assignee::Array(array, _index) => resolve_assignee(scope, *array), Assignee::Array(array, _index) => resolve_assignee(scope, *array),
Assignee::Tuple(tuple, _index) => resolve_assignee(scope, *tuple),
Assignee::CircuitField(circuit_name, _member) => resolve_assignee(scope, *circuit_name), Assignee::CircuitField(circuit_name, _member) => resolve_assignee(scope, *circuit_name),
} }
} }

View File

@ -40,7 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(StatementError::immutable_circuit_function("static".into(), span)); return Err(StatementError::immutable_circuit_function("static".into(), span));
} }
_ => { _ => {
new_value.resolve_type(&vec![object.1.to_type(span.clone())?], span.clone())?; new_value.resolve_type(Some(object.1.to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start); let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select( let selected_value = ConstrainedValue::conditionally_select(

View File

@ -11,3 +11,6 @@ pub use self::assignee::*;
pub mod circuit_field; pub mod circuit_field;
pub use self::circuit_field::*; pub use self::circuit_field::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,45 @@
//! Enforces a tuple assignment statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::Span;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{boolean::Boolean, select::CondSelectGadget},
},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn assign_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
indicator: Option<Boolean>,
name: String,
index: usize,
mut new_value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
// Modify the single value of the tuple in place
match self.get_mutable_assignee(name, span.clone())? {
ConstrainedValue::Tuple(old) => {
new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value =
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, &old[index])
.map_err(|_| {
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span)
})?;
old[index] = selected_value;
}
_ => return Err(StatementError::tuple_assign_index(span)),
}
Ok(())
}
}

View File

@ -16,7 +16,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String, function_scope: String,
indicator: Option<Boolean>, indicator: Option<Boolean>,
statements: Vec<Statement>, statements: Vec<Statement>,
return_types: Vec<Type>, return_type: Option<Type>,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> { ) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![]; let mut results = vec![];
// Evaluate statements. Only allow a single return argument to be returned. // Evaluate statements. Only allow a single return argument to be returned.
@ -27,7 +27,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(), function_scope.clone(),
indicator.clone(), indicator.clone(),
statement.clone(), statement.clone(),
return_types.clone(), return_type.clone(),
)?; )?;
results.append(&mut value); results.append(&mut value);

View File

@ -27,7 +27,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String, function_scope: String,
indicator: Option<Boolean>, indicator: Option<Boolean>,
statement: ConditionalStatement, statement: ConditionalStatement,
return_types: Vec<Type>, return_type: Option<Type>,
span: Span, span: Span,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> { ) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let statement_string = statement.to_string(); let statement_string = statement.to_string();
@ -40,7 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs, cs,
file_scope.clone(), file_scope.clone(),
function_scope.clone(), function_scope.clone(),
&vec![Type::Boolean], Some(Type::Boolean),
statement.condition.clone(), statement.condition.clone(),
)? { )? {
ConstrainedValue::Boolean(resolved) => resolved, ConstrainedValue::Boolean(resolved) => resolved,
@ -70,7 +70,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(), function_scope.clone(),
Some(branch_1_indicator), Some(branch_1_indicator),
statement.statements, statement.statements,
return_types.clone(), return_type.clone(),
)?; )?;
results.append(&mut branch_1_result); results.append(&mut branch_1_result);
@ -98,7 +98,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope, function_scope,
Some(branch_2_indicator), Some(branch_2_indicator),
*nested, *nested,
return_types, return_type,
span, span,
)?, )?,
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch( ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
@ -107,7 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope, function_scope,
Some(branch_2_indicator), Some(branch_2_indicator),
statements, statements,
return_types, return_type,
)?, )?,
}, },
None => vec![], None => vec![],

View File

@ -1,7 +1,7 @@
//! Enforces a definition statement in a compiled Leo program. //! Enforces a definition statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, GroupType}; use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
use leo_typed::{Declare, Expression, Span, Variable}; use leo_typed::{Declare, Expression, Span, Type, VariableName, Variables};
use snarkos_models::{ use snarkos_models::{
curves::{Field, PrimeField}, curves::{Field, PrimeField},
@ -9,39 +9,186 @@ use snarkos_models::{
}; };
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> { impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
fn enforce_single_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
function_scope: String,
is_constant: bool,
variable_name: VariableName,
mut value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> {
if is_constant && variable_name.mutable {
return Err(StatementError::immutable_assign(variable_name.to_string(), span));
} else {
value.allocate_value(cs, span)?
}
self.store_definition(function_scope, variable_name.mutable, variable_name.identifier, value);
Ok(())
}
fn enforce_expressions<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
type_: Option<Type>,
expressions: Vec<Expression>,
span: Span,
) -> Result<Vec<ConstrainedValue<F, G>>, StatementError> {
let types = match type_ {
Some(Type::Tuple(types)) => types,
Some(type_) => return Err(StatementError::tuple_type(type_.to_string(), span.clone())),
None => vec![],
};
let implicit_types = types.is_empty();
let mut expected_types = vec![];
for i in 0..expressions.len() {
let expected_type = if implicit_types { None } else { Some(types[i].clone()) };
expected_types.push(expected_type);
}
let mut values = vec![];
for (expression, expected_type) in expressions.into_iter().zip(expected_types.into_iter()) {
let value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_type,
expression,
)?;
values.push(value);
}
Ok(values)
}
fn enforce_tuple_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
is_constant: bool,
variables: Variables,
expressions: Vec<Expression>,
span: Span,
) -> Result<(), StatementError> {
let values = self.enforce_expressions(
cs,
file_scope,
function_scope.clone(),
variables.type_.clone(),
expressions,
span.clone(),
)?;
let tuple = ConstrainedValue::Tuple(values);
let variable = variables.names[0].clone();
self.enforce_single_definition(cs, function_scope, is_constant, variable, tuple, span)
}
fn enforce_multiple_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
function_scope: String,
is_constant: bool,
variables: Variables,
values: Vec<ConstrainedValue<F, G>>,
span: Span,
) -> Result<(), StatementError> {
if values.len() != variables.names.len() {
return Err(StatementError::invalid_number_of_definitions(
values.len(),
variables.names.len(),
span,
));
}
for (variable, value) in variables.names.into_iter().zip(values.into_iter()) {
self.enforce_single_definition(cs, function_scope.clone(), is_constant, variable, value, span.clone())?;
}
Ok(())
}
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>( pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
declare: Declare, declare: Declare,
variable: Variable, variables: Variables,
expression: Expression, expressions: Vec<Expression>,
span: Span, span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let mut expected_types = vec![]; let num_variables = variables.names.len();
if let Some(ref _type) = variable._type { let num_values = expressions.len();
expected_types.push(_type.clone()); let is_constant = match declare {
Declare::Let => false,
Declare::Const => true,
};
if num_variables == 1 && num_values == 1 {
// Define a single variable with a single value
let variable = variables.names[0].clone();
let expression = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
variables.type_,
expressions[0].clone(),
)?;
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, span)
} else if num_variables == 1 && num_values > 1 {
// Define a tuple (single variable with multiple values)
self.enforce_tuple_definition(
cs,
file_scope,
function_scope,
is_constant,
variables,
expressions,
span,
)
} else if num_variables > 1 && num_values == 1 {
// Define multiple variables for an expression that returns multiple results (multiple definition)
let values = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
variables.type_.clone(),
expressions[0].clone(),
)? {
// ConstrainedValue::Return(values) => values,
ConstrainedValue::Tuple(values) => values,
value => return Err(StatementError::multiple_definition(value.to_string(), span.clone())),
};
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
} else {
// Define multiple variables for multiple expressions
let values = self.enforce_expressions(
cs,
file_scope,
function_scope.clone(),
variables.type_.clone(),
expressions,
span.clone(),
)?;
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
} }
let mut value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
expression,
)?;
match declare {
Declare::Let => value.allocate_value(cs, span)?,
Declare::Const => {
if variable.mutable {
return Err(StatementError::immutable_assign(variable.to_string(), span));
}
}
}
self.store_definition(function_scope, variable, value);
Ok(())
} }
} }

View File

@ -2,6 +2,3 @@
pub mod definition; pub mod definition;
pub use self::definition::*; pub use self::definition::*;
pub mod multiple;
pub use self::multiple::*;

View File

@ -1,54 +0,0 @@
//! Enforces a multiple definition statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Variable};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_multiple_definition_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
variables: Vec<Variable>,
function: Expression,
span: Span,
) -> Result<(), StatementError> {
let mut expected_types = vec![];
for variable in variables.iter() {
if let Some(ref _type) = variable._type {
expected_types.push(_type.clone());
}
}
// Expect return values from function
let return_values = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
function,
)? {
ConstrainedValue::Return(values) => values,
value => unimplemented!("multiple assignment only implemented for functions, got {}", value),
};
if variables.len() != return_values.len() {
return Err(StatementError::invalid_number_of_definitions(
variables.len(),
return_values.len(),
span,
));
}
for (variable, value) in variables.into_iter().zip(return_values.into_iter()) {
self.store_definition(function_scope.clone(), variable, value);
}
Ok(())
}
}

View File

@ -29,7 +29,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
start: Expression, start: Expression,
stop: Expression, stop: Expression,
statements: Vec<Statement>, statements: Vec<Statement>,
return_types: Vec<Type>, return_type: Option<Type>,
span: Span, span: Span,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> { ) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![]; let mut results = vec![];
@ -40,6 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
for i in from..to { for i in from..to {
// Store index in current function scope. // Store index in current function scope.
// For loop scope is not implemented. // For loop scope is not implemented.
let index_name = new_scope(function_scope.clone(), index.to_string()); let index_name = new_scope(function_scope.clone(), index.to_string());
self.store( self.store(
@ -55,7 +56,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(), function_scope.clone(),
indicator, indicator,
statements.clone(), statements.clone(),
return_types.clone(), return_type.clone(),
)?; )?;
results.append(&mut result); results.append(&mut result);

View File

@ -1,11 +1,6 @@
//! Enforces a return statement in a compiled Leo program. //! Enforces a return statement in a compiled Leo program.
use crate::{ use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
errors::{StatementError, ValueError},
program::ConstrainedProgram,
value::ConstrainedValue,
GroupType,
};
use leo_typed::{Expression, Span, Type}; use leo_typed::{Expression, Span, Type};
use snarkos_models::{ use snarkos_models::{
@ -13,25 +8,20 @@ use snarkos_models::{
gadgets::r1cs::ConstraintSystem, gadgets::r1cs::ConstraintSystem,
}; };
fn check_return_types(expected: &Vec<Type>, actual: &Vec<Type>, span: Span) -> Result<(), StatementError> { fn check_return_type(expected: Option<Type>, actual: Type, span: Span) -> Result<(), StatementError> {
expected match expected {
.iter() Some(expected) => {
.zip(actual.iter()) if expected.ne(&actual) {
.map(|(type_1, type_2)| { if expected.is_self() && actual.is_circuit() {
if type_1.ne(type_2) { return Ok(());
// catch return Self type
if type_1.is_self() && type_2.is_circuit() {
Ok(())
} else { } else {
Err(StatementError::arguments_type(type_1, type_2, span.clone())) return Err(StatementError::arguments_type(&expected, &actual, span));
} }
} else {
Ok(())
} }
}) Ok(())
.collect::<Result<Vec<()>, StatementError>>()?; }
None => Ok(()),
Ok(()) }
} }
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> { impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
@ -40,41 +30,23 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS, cs: &mut CS,
file_scope: String, file_scope: String,
function_scope: String, function_scope: String,
expressions: Vec<Expression>, expression: Expression,
return_types: Vec<Type>, return_type: Option<Type>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, StatementError> { ) -> Result<ConstrainedValue<F, G>, StatementError> {
// Make sure we return the correct number of values // Make sure we return the correct number of values
if return_types.len() != expressions.len() {
return Err(StatementError::invalid_number_of_returns(
return_types.len(),
expressions.len(),
span,
));
}
let mut returns = vec![]; let result = self.enforce_operand(
for (expression, ty) in expressions.into_iter().zip(return_types.clone().into_iter()) { cs,
let expected_types = vec![ty.clone()]; file_scope.clone(),
let result = self.enforce_operand( function_scope.clone(),
cs, return_type.clone(),
file_scope.clone(), expression,
function_scope.clone(), span.clone(),
&expected_types, )?;
expression,
span.clone(),
)?;
returns.push(result); check_return_type(return_type, result.to_type(span.clone())?, span)?;
}
let actual_types = returns Ok(result)
.iter()
.map(|value| value.to_type(span.clone()))
.collect::<Result<Vec<Type>, ValueError>>()?;
check_return_types(&return_types, &actual_types, span)?;
Ok(ConstrainedValue::Return(returns))
} }
} }

View File

@ -12,8 +12,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Enforce a program statement. /// Enforce a program statement.
/// Returns a Vector of (indicator, value) tuples. /// Returns a Vector of (indicator, value) tuples.
/// Each evaluated statement may execute of one or more statements that may return early. /// Each evaluated statement may execute of one or more statements that may return early.
/// To indicate which of these return values to take, /// To indicate which of these return values to take we conditionally select the value according
/// we conditionally select the value according the `indicator` bit that evaluates to true. /// to the `indicator` bit that evaluates to true.
pub fn enforce_statement<CS: ConstraintSystem<F>>( pub fn enforce_statement<CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
@ -21,24 +21,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String, function_scope: String,
indicator: Option<Boolean>, indicator: Option<Boolean>,
statement: Statement, statement: Statement,
return_types: Vec<Type>, return_type: Option<Type>,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> { ) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![]; let mut results = vec![];
match statement { match statement {
Statement::Return(expressions, span) => { Statement::Return(expression, span) => {
let return_value = ( let return_value = (
indicator, indicator,
self.enforce_return_statement(cs, file_scope, function_scope, expressions, return_types, span)?, self.enforce_return_statement(cs, file_scope, function_scope, expression, return_type, span)?,
); );
results.push(return_value); results.push(return_value);
} }
Statement::Definition(declare, variable, expression, span) => { Statement::Definition(declare, variables, expressions, span) => {
self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression, span)?; self.enforce_definition_statement(
} cs,
Statement::MultipleDefinition(variables, function, span) => { file_scope,
self.enforce_multiple_definition_statement(cs, file_scope, function_scope, variables, function, span)?; function_scope,
declare,
variables,
expressions,
span,
)?;
} }
Statement::Assign(variable, expression, span) => { Statement::Assign(variable, expression, span) => {
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?; self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?;
@ -50,7 +55,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope, function_scope,
indicator, indicator,
statement, statement,
return_types, return_type,
span, span,
)?; )?;
@ -66,7 +71,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
start, start,
stop, stop,
statements, statements,
return_types, return_type,
span, span,
)?; )?;
@ -74,7 +79,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} }
Statement::AssertEq(left, right, span) => { Statement::AssertEq(left, right, span) => {
let (resolved_left, resolved_right) = let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right, span.clone())?; self.enforce_binary_expression(cs, file_scope, function_scope, None, left, right, span.clone())?;
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?; self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?;
} }
@ -83,11 +88,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} }
Statement::Expression(expression, span) => { Statement::Expression(expression, span) => {
let expression_string = expression.to_string(); let expression_string = expression.to_string();
let value = self.enforce_expression(cs, file_scope, function_scope, &vec![], expression)?; let value = self.enforce_expression(cs, file_scope, function_scope, None, expression)?;
// handle empty return value cases // handle empty return value cases
match &value { match &value {
ConstrainedValue::Return(values) => { ConstrainedValue::Tuple(values) => {
if !values.is_empty() { if !values.is_empty() {
return Err(StatementError::unassigned(expression_string, span)); return Err(StatementError::unassigned(expression_string, span));
} }

View File

@ -209,17 +209,10 @@ impl<F: Field + PrimeField> PartialOrd for FieldType<F> {
} }
impl<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> { impl<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> {
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> { fn evaluate_equal<CS: ConstraintSystem<F>>(&self, _cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) { match (self, other) {
(FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.eq(second))), (FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.eq(second))),
(FieldType::Allocated(allocated), FieldType::Constant(constant)) _ => unimplemented!(),
| (FieldType::Constant(constant), FieldType::Allocated(allocated)) => {
let bool_option = allocated.value.map(|f| f.eq(constant));
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(FieldType::Allocated(first), FieldType::Allocated(second)) => first.evaluate_equal(cs, second),
} }
} }
} }

View File

@ -237,35 +237,12 @@ impl PartialEq for EdwardsGroupType {
impl Eq for EdwardsGroupType {} impl Eq for EdwardsGroupType {}
impl EvaluateEqGadget<Fq> for EdwardsGroupType { impl EvaluateEqGadget<Fq> for EdwardsGroupType {
fn evaluate_equal<CS: ConstraintSystem<Fq>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> { fn evaluate_equal<CS: ConstraintSystem<Fq>>(&self, _cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) { match (self, other) {
(EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => { (EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => {
Ok(Boolean::Constant(self_value == other_value)) Ok(Boolean::constant(self_value.eq(other_value)))
}
(EdwardsGroupType::Allocated(self_value), EdwardsGroupType::Allocated(other_value)) => {
let bool_option =
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(self_value)
.and_then(|a| {
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(
other_value,
)
.map(|b| a.eq(&b))
});
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value))
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => {
let bool_option =
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(allocated_value)
.map(|a| a.eq(constant_value));
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
} }
_ => unimplemented!(),
} }
} }
} }

View File

@ -6,13 +6,12 @@ use leo_typed::{Span, Type};
use snarkos_models::curves::{Field, PrimeField}; use snarkos_models::curves::{Field, PrimeField};
pub fn enforce_number_implicit<F: Field + PrimeField, G: GroupType<F>>( pub fn enforce_number_implicit<F: Field + PrimeField, G: GroupType<F>>(
expected_types: &Vec<Type>, expected_type: Option<Type>,
value: String, value: String,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ValueError> { ) -> Result<ConstrainedValue<F, G>, ValueError> {
if expected_types.len() == 1 { match expected_type {
return Ok(ConstrainedValue::from_type(value, &expected_types[0], span)?); Some(type_) => Ok(ConstrainedValue::from_type(value, &type_, span)?),
None => Ok(ConstrainedValue::Unresolved(value)),
} }
Ok(ConstrainedValue::Unresolved(value))
} }

View File

@ -1,5 +1,5 @@
//! Conversion of integer declarations to constraints in Leo. //! Conversion of integer declarations to constraints in Leo.
use crate::{errors::IntegerError, integer::macros::IntegerTrait}; use crate::{errors::IntegerError, IntegerTrait};
use leo_gadgets::{ use leo_gadgets::{
arithmetic::*, arithmetic::*,
bits::comparator::{ComparatorGadget, EvaluateLtGadget}, bits::comparator::{ComparatorGadget, EvaluateLtGadget},
@ -17,7 +17,7 @@ use snarkos_models::{
boolean::Boolean, boolean::Boolean,
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget}, eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
select::CondSelectGadget, select::CondSelectGadget,
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8}, uint::*,
}, },
}, },
}; };
@ -489,7 +489,7 @@ impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
} }
fn cost() -> usize { fn cost() -> usize {
<UInt128 as ConditionalEqGadget<F>>::cost() // upper bound. change trait to increase accuracy unimplemented!() // cannot determine which integer we are enforcing
} }
} }
@ -517,6 +517,6 @@ impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
} }
fn cost() -> usize { fn cost() -> usize {
<UInt128 as CondSelectGadget<F>>::cost() // upper bound. change trait to increase accuracy unimplemented!() // cannot determine which integer we are enforcing
} }
} }

View File

@ -37,13 +37,15 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
// Arrays // Arrays
Array(Vec<ConstrainedValue<F, G>>), Array(Vec<ConstrainedValue<F, G>>),
// Tuples
Tuple(Vec<ConstrainedValue<F, G>>),
// Circuits // Circuits
CircuitDefinition(Circuit), CircuitDefinition(Circuit),
CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>), CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>),
// Functions // Functions
Function(Option<Identifier>, Function), // (optional circuit identifier, function definition) Function(Option<Identifier>, Function), // (optional circuit identifier, function definition)
Return(Vec<ConstrainedValue<F, G>>),
// Modifiers // Modifiers
Mutable(Box<ConstrainedValue<F, G>>), Mutable(Box<ConstrainedValue<F, G>>),
@ -61,8 +63,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
ConstrainedValue::from_type(value, &other_type, span) ConstrainedValue::from_type(value, &other_type, span)
} }
pub(crate) fn from_type(value: String, _type: &Type, span: Span) -> Result<Self, ValueError> { pub(crate) fn from_type(value: String, type_: &Type, span: Span) -> Result<Self, ValueError> {
match _type { match type_ {
// Data types // Data types
Type::Address => Ok(ConstrainedValue::Address(Address::new(value, span)?)), Type::Address => Ok(ConstrainedValue::Address(Address::new(value, span)?)),
Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)), Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)),
@ -103,15 +105,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
Type::Array(Box::new(array_type), vec![count]) Type::Array(Box::new(array_type), vec![count])
} }
ConstrainedValue::Tuple(tuple) => {
let mut types = vec![];
for value in tuple {
let type_ = value.to_type(span.clone())?;
types.push(type_)
}
Type::Tuple(types)
}
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()), ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()),
value => return Err(ValueError::implicit(value.to_string(), span)), value => return Err(ValueError::implicit(value.to_string(), span)),
}) })
} }
pub(crate) fn resolve_type(&mut self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> { pub(crate) fn resolve_type(&mut self, type_: Option<Type>, span: Span) -> Result<(), ValueError> {
if let ConstrainedValue::Unresolved(ref string) = self { if let ConstrainedValue::Unresolved(ref string) = self {
if !types.is_empty() { if type_.is_some() {
*self = ConstrainedValue::from_type(string.clone(), &types[0], span)? *self = ConstrainedValue::from_type(string.clone(), &type_.unwrap(), span)?
} }
} }
@ -119,16 +131,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
} }
/// Expect both `self` and `other` to resolve to the same type /// Expect both `self` and `other` to resolve to the same type
pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> { pub(crate) fn resolve_types(
if !types.is_empty() { &mut self,
self.resolve_type(types, span.clone())?; other: &mut Self,
return other.resolve_type(types, span); type_: Option<Type>,
span: Span,
) -> Result<(), ValueError> {
if type_.is_some() {
self.resolve_type(type_.clone(), span.clone())?;
return other.resolve_type(type_, span);
} }
match (&self, &other) { match (&self, &other) {
(ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()), (ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type(span.clone())?], span), (ConstrainedValue::Unresolved(_), _) => self.resolve_type(Some(other.to_type(span.clone())?), span),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type(span.clone())?], span), (_, ConstrainedValue::Unresolved(_)) => other.resolve_type(Some(self.to_type(span.clone())?), span),
_ => Ok(()), _ => Ok(()),
} }
} }
@ -208,6 +225,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}) })
.collect::<Result<(), ValueError>>()?; .collect::<Result<(), ValueError>>()?;
} }
ConstrainedValue::Tuple(tuple) => {
tuple
.iter_mut()
.enumerate()
.map(|(i, value)| {
let unique_name = format!("allocate tuple member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::CircuitExpression(_id, members) => { ConstrainedValue::CircuitExpression(_id, members) => {
members members
.iter_mut() .iter_mut()
@ -219,17 +247,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}) })
.collect::<Result<(), ValueError>>()?; .collect::<Result<(), ValueError>>()?;
} }
ConstrainedValue::Return(array) => {
array
.iter_mut()
.enumerate()
.map(|(i, value)| {
let unique_name = format!("allocate return member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::Mutable(value) => { ConstrainedValue::Mutable(value) => {
value.allocate_value(cs, span)?; value.allocate_value(cs, span)?;
} }
@ -280,6 +297,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
} }
write!(f, "]") write!(f, "]")
} }
ConstrainedValue::Tuple(ref tuple) => {
let values = tuple.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(", ");
write!(f, "({})", values)
}
ConstrainedValue::CircuitExpression(ref identifier, ref members) => { ConstrainedValue::CircuitExpression(ref identifier, ref members) => {
write!(f, "{} {{", identifier)?; write!(f, "{} {{", identifier)?;
for (i, member) in members.iter().enumerate() { for (i, member) in members.iter().enumerate() {
@ -290,16 +312,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
} }
write!(f, "}}") write!(f, "}}")
} }
ConstrainedValue::Return(ref values) => {
write!(f, "Program output: [")?;
for (i, value) in values.iter().enumerate() {
write!(f, "{}", value)?;
if i < values.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name), ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name),
ConstrainedValue::Function(ref _circuit_option, ref function) => { ConstrainedValue::Function(ref _circuit_option, ref function) => {
write!(f, "function {{ {}() }}", function.identifier) write!(f, "function {{ {}() }}", function.identifier)
@ -347,6 +359,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConditionalEqGadget<F> for Constrai
} }
Ok(()) Ok(())
} }
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Tuple(tuple_2)) => {
for (i, (left, right)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
left.conditional_enforce_equal(cs.ns(|| format!("tuple index {}", i)), right, condition)?;
}
Ok(())
}
(_, _) => return Err(SynthesisError::Unsatisfiable), (_, _) => return Err(SynthesisError::Unsatisfiable),
} }
} }
@ -393,6 +411,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
ConstrainedValue::Array(array) ConstrainedValue::Array(array)
} }
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Array(tuple_2)) => {
let mut array = vec![];
for (i, (first, second)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
array.push(Self::conditionally_select(
cs.ns(|| format!("tuple index {}", i)),
cond,
first,
second,
)?);
}
ConstrainedValue::Tuple(array)
}
(ConstrainedValue::Function(identifier_1, function_1), ConstrainedValue::Function(_, _)) => { (ConstrainedValue::Function(identifier_1, function_1), ConstrainedValue::Function(_, _)) => {
// This is a no-op. functions cannot hold circuit values // This is a no-op. functions cannot hold circuit values
// However, we must return a result here // However, we must return a result here
@ -415,20 +447,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
ConstrainedValue::CircuitExpression(identifier.clone(), members) ConstrainedValue::CircuitExpression(identifier.clone(), members)
} }
(ConstrainedValue::Return(returns_1), ConstrainedValue::Return(returns_2)) => {
let mut returns = vec![];
for (i, (first, second)) in returns_1.into_iter().zip(returns_2.into_iter()).enumerate() {
returns.push(Self::conditionally_select(
cs.ns(|| format!("return[{}]", i)),
cond,
first,
second,
)?);
}
ConstrainedValue::Return(returns)
}
(ConstrainedValue::Static(first), ConstrainedValue::Static(second)) => { (ConstrainedValue::Static(first), ConstrainedValue::Static(second)) => {
let value = Self::conditionally_select(cs, cond, first, second)?; let value = Self::conditionally_select(cs, cond, first, second)?;

View File

@ -169,6 +169,7 @@ fn test_mul() {
} }
#[test] #[test]
#[ignore]
fn test_eq() { fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64); let mut rng = XorShiftRng::seed_from_u64(1231275789u64);

View File

@ -0,0 +1,7 @@
[main]
a: u32 = 0;
b: u32 = 0;
[registers]
a: u32 = 0;
b: u32 = 0;

View File

@ -41,6 +41,20 @@ fn test_iteration_repeated() {
assert_satisfied(program); assert_satisfied(program);
} }
#[test]
fn test_newlines() {
let input_bytes = include_bytes!("input/newlines.in");
let program_bytes = include_bytes!("newlines.leo");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
let expected_bytes = include_bytes!("output_/newlines.out");
let expected = std::str::from_utf8(expected_bytes).unwrap();
let actual_bytes = get_output(program);
let actual = std::str::from_utf8(actual_bytes.bytes().as_slice()).unwrap();
assert_eq!(expected, actual);
}
#[test] #[test]
fn test_multiple_returns() { fn test_multiple_returns() {
let bytes = include_bytes!("multiple.leo"); let bytes = include_bytes!("multiple.leo");

View File

@ -0,0 +1,9 @@
function main(
a: u32,
b: u32,
) -> (
u32,
u32,
) {
return (a, b)
}

View File

@ -0,0 +1,3 @@
[registers]
a: u32 = 0u32;
b: u32 = 0u32;

View File

@ -0,0 +1,2 @@
[main]
a: group = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;

View File

@ -44,6 +44,16 @@ fn test_point() {
assert_satisfied(program); assert_satisfied(program);
} }
#[test]
fn test_point_input() {
let program_bytes = include_bytes!("point_input.leo");
let input_bytes = include_bytes!("input/point.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test] #[test]
fn test_input() { fn test_input() {
let program_bytes = include_bytes!("input.leo"); let program_bytes = include_bytes!("input.leo");
@ -196,6 +206,7 @@ fn test_assert_eq_fail() {
} }
#[test] #[test]
#[ignore]
fn test_eq() { fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64); let mut rng = XorShiftRng::seed_from_u64(1231275789u64);

View File

@ -0,0 +1,3 @@
function main(a: group) {
let b = a;
}

View File

@ -81,6 +81,11 @@ fn test_i128_eq() {
TestI128::test_eq(); TestI128::test_eq();
} }
#[test]
fn test_i128_ne() {
TestI128::test_ne();
}
#[test] #[test]
fn test_i128_ge() { fn test_i128_ge() {
TestI128::test_ge(); TestI128::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i16_eq() {
TestI16::test_eq(); TestI16::test_eq();
} }
#[test]
fn test_i16_ne() {
TestI16::test_ne();
}
#[test] #[test]
fn test_i16_ge() { fn test_i16_ge() {
TestI16::test_ge(); TestI16::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i16, b: i16, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i32_eq() {
TestI32::test_eq(); TestI32::test_eq();
} }
#[test]
fn test_i32_ne() {
TestI32::test_ne();
}
#[test] #[test]
fn test_i32_ge() { fn test_i32_ge() {
TestI32::test_ge(); TestI32::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i32, b: i32, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -81,6 +81,11 @@ fn test_i64_eq() {
TestI64::test_eq(); TestI64::test_eq();
} }
#[test]
fn test_i64_ne() {
TestI64::test_ne();
}
#[test] #[test]
fn test_i64_ge() { fn test_i64_ge() {
TestI64::test_ge(); TestI64::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i64, b: i64, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i8_eq() {
TestI8::test_eq(); TestI8::test_eq();
} }
#[test]
fn test_i8_ne() {
TestI8::test_ne();
}
#[test] #[test]
fn test_i8_ge() { fn test_i8_ge() {
TestI8::test_ge(); TestI8::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i8, b: i8, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -257,6 +257,44 @@ macro_rules! test_int {
} }
} }
fn test_ne() {
for _ in 0..10 {
let a: $type_ = rand::random();
let b: $type_ = rand::random();
// test a != a == false
let bytes = include_bytes!("ne.leo");
let mut program = parse_program(bytes).unwrap();
let main_input = generate_main_input(vec![
("a", Some(InputValue::Integer($integer_type, a.to_string()))),
("b", Some(InputValue::Integer($integer_type, a.to_string()))),
("c", Some(InputValue::Boolean(false))),
]);
program.set_main_input(main_input);
assert_satisfied(program);
// test not equal
let c = a.ne(&b);
let mut program = parse_program(bytes).unwrap();
let main_input = generate_main_input(vec![
("a", Some(InputValue::Integer($integer_type, a.to_string()))),
("b", Some(InputValue::Integer($integer_type, b.to_string()))),
("c", Some(InputValue::Boolean(c))),
]);
program.set_main_input(main_input);
assert_satisfied(program);
}
}
fn test_ge() { fn test_ge() {
for _ in 0..10 { for _ in 0..10 {
let a: $type_ = rand::random(); let a: $type_ = rand::random();

View File

@ -32,6 +32,9 @@ pub trait IntegerTester {
/// Tests == evaluation /// Tests == evaluation
fn test_eq(); fn test_eq();
/// Tests != evaluation
fn test_ne();
/// Tests >= evaluation /// Tests >= evaluation
fn test_ge(); fn test_ge();

View File

@ -8,7 +8,7 @@ pub mod integer_tester;
pub use self::integer_tester::*; pub use self::integer_tester::*;
// must be below macro definitions! // must be below macro definitions!
pub mod u128; // pub mod u128;
pub mod u16; pub mod u16;
pub mod u32; pub mod u32;
pub mod u64; pub mod u64;

View File

@ -65,6 +65,11 @@ fn test_u128_eq() {
TestU128::test_eq(); TestU128::test_eq();
} }
#[test]
fn test_u128_ne() {
TestU128::test_ne();
}
#[test] #[test]
fn test_u128_ge() { fn test_u128_ge() {
TestU128::test_ge(); TestU128::test_ge();

Some files were not shown because too many files have changed in this diff Show More