mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-20 02:07:38 +03:00
Merge branch 'feature/lib-and-imports' of github.com:AleoHQ/leo into feature/comparator
This commit is contained in:
commit
45a2664fd9
152
.github/workflows/ci.yml
vendored
Normal file
152
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
style:
|
||||
name: Check Style
|
||||
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: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: cargo fmt --check
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTFLAGS: -Dwarnings
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- stable
|
||||
- nightly
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- 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 (${{ matrix.rust }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
|
||||
- name: Check examples
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: check
|
||||
args: --examples --all
|
||||
|
||||
- name: Check examples with all features on stable
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --examples --all-features --all
|
||||
if: matrix.rust == 'stable'
|
||||
|
||||
- name: Check benchmarks on nightly
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --all-features --examples --all --benches
|
||||
if: matrix.rust == 'nightly'
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --release --all --no-fail-fast
|
||||
|
||||
codecov:
|
||||
name: Code Coverage
|
||||
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: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
CARGO_INCREMENTAL: "0"
|
||||
|
||||
- name: Install dependencies for code coverage
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install binutils-dev libcurl4-openssl-dev zlib1g-dev libdw-dev libiberty-dev
|
||||
|
||||
- name: Generate coverage report
|
||||
run: |
|
||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz
|
||||
tar xzf master.tar.gz
|
||||
cd kcov-master
|
||||
mkdir build && cd build
|
||||
cmake .. && make
|
||||
make install DESTDIR=../../kcov-build
|
||||
cd ../..
|
||||
rm -rf kcov-master
|
||||
for file in target/debug/deps/*-*; do if [[ "$file" != *\.* ]]; then mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; fi done
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
137
Cargo.lock
generated
137
Cargo.lock
generated
@ -78,9 +78,9 @@ checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.2.1"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
|
||||
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
@ -149,6 +149,33 @@ version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.9+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1be3409f94d7bdceeb5f5fac551039d9b3f00e25da7a74fc4d33400a0d96368"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
@ -190,6 +217,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
@ -334,6 +370,18 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crc32fast",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "from-pest"
|
||||
version = "0.3.1"
|
||||
@ -492,6 +540,8 @@ dependencies = [
|
||||
"snarkos-utilities",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -519,7 +569,7 @@ dependencies = [
|
||||
"log",
|
||||
"pest",
|
||||
"rand",
|
||||
"sha2 0.8.2",
|
||||
"sha2",
|
||||
"snarkos-curves",
|
||||
"snarkos-errors",
|
||||
"snarkos-gadgets",
|
||||
@ -691,6 +741,18 @@ dependencies = [
|
||||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
|
||||
[[package]]
|
||||
name = "podio"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b18befed8bc2b61abc79a457295e7e838417326da1586050b919414073977f19"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
@ -840,9 +902,9 @@ checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
|
||||
[[package]]
|
||||
name = "rusty-hook"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27138b73a8ce63ae918707a5e3b57f9b0c0842a57b82f0e43474cf4e3aaf0ff4"
|
||||
checksum = "96cee9be61be7e1cbadd851e58ed7449c29c620f00b23df937cb9cbc04ac21a3"
|
||||
dependencies = [
|
||||
"ci_info",
|
||||
"getopts",
|
||||
@ -856,6 +918,15 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@ -905,18 +976,6 @@ dependencies = [
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3",
|
||||
"digest 0.8.1",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.0"
|
||||
@ -947,6 +1006,7 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
[[package]]
|
||||
name = "snarkos-algorithms"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"derivative",
|
||||
@ -954,7 +1014,7 @@ dependencies = [
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rayon",
|
||||
"sha2 0.9.0",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"snarkos-errors",
|
||||
"snarkos-models",
|
||||
@ -965,6 +1025,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-curves"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"rand",
|
||||
@ -978,6 +1039,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-derives"
|
||||
version = "0.1.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
@ -987,6 +1049,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-errors"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bech32",
|
||||
@ -999,6 +1062,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-gadgets"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"digest 0.8.1",
|
||||
@ -1012,6 +1076,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-models"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"derivative",
|
||||
@ -1026,10 +1091,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "snarkos-profiler"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
|
||||
[[package]]
|
||||
name = "snarkos-utilities"
|
||||
version = "0.8.0"
|
||||
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git?rev=c7a56d9#c7a56d97a76dd6e7841aa6bb86e086f7128e5620"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"rand",
|
||||
@ -1130,6 +1197,16 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
@ -1187,6 +1264,17 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
@ -1223,3 +1311,16 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58287c28d78507f5f91f2a4cf1e8310e2c76fd4c6932f93ac60fd1ceb402db7d"
|
||||
dependencies = [
|
||||
"bzip2",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"podio",
|
||||
"time",
|
||||
]
|
||||
|
16
Cargo.toml
16
Cargo.toml
@ -19,12 +19,12 @@ members = [ "ast", "compiler", "leo-inputs", "types" ]
|
||||
leo-compiler = { path = "compiler", version = "0.1.0" }
|
||||
leo-inputs = { path = "leo-inputs", version = "0.1.0"}
|
||||
|
||||
snarkos-algorithms = { path = "../snarkOS/algorithms", version = "0.8.0", default-features = false }
|
||||
snarkos-curves = { path = "../snarkOS/curves", version = "0.8.0", default-features = false }
|
||||
snarkos-errors = { path = "../snarkOS/errors", version = "0.8.0", default-features = false }
|
||||
snarkos-gadgets = { path = "../snarkOS/gadgets", version = "0.8.0", default-features = false }
|
||||
snarkos-models = { path = "../snarkOS/models", version = "0.8.0", default-features = false }
|
||||
snarkos-utilities = { path = "../snarkOS/utilities", version = "0.8.0" }
|
||||
snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" }
|
||||
|
||||
clap = { version = "2.33.0" }
|
||||
colored = { version = "1.9" }
|
||||
@ -37,9 +37,11 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
toml = { version = "0.5" }
|
||||
thiserror = { version = "1.0" }
|
||||
walkdir = { version = "2" }
|
||||
zip = { version = "0.5" }
|
||||
|
||||
[dev-dependencies]
|
||||
rusty-hook = { version = "0.11.1" }
|
||||
rusty-hook = { version = "0.11.2" }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
144
README.md
144
README.md
@ -356,40 +356,111 @@ function main() -> Circ {
|
||||
```
|
||||
|
||||
## Imports
|
||||
Both struct and function imports are supported.
|
||||
Leo supports importing functions and circuits by name into the current file with the following syntax:
|
||||
|
||||
```leo
|
||||
import all: `*`
|
||||
import alias: `symbol as alias`
|
||||
```rust
|
||||
import [package].[name];
|
||||
```
|
||||
|
||||
`src/simple_import.leo`
|
||||
#### Import Aliases
|
||||
To import a name using an alias:
|
||||
```rust
|
||||
circuit Point {
|
||||
x: u32
|
||||
y: u32
|
||||
import [package].[name] as [alias];
|
||||
```
|
||||
|
||||
#### Import Multiple
|
||||
To import multiple names from the same package:
|
||||
```rust
|
||||
import [package].(
|
||||
[name_1],
|
||||
[name_2] as [alias],
|
||||
);
|
||||
```
|
||||
|
||||
#### Import Star
|
||||
To import all symbols from a package:
|
||||
```rust
|
||||
import [package].*;
|
||||
```
|
||||
|
||||
### Local
|
||||
You can import from a local file in the `src/` directory by using its `[file].leo` as the `[package]` name.
|
||||
|
||||
```rust
|
||||
import [file].[name];
|
||||
```
|
||||
|
||||
#### Example:
|
||||
`src/bar.leo`
|
||||
```rust
|
||||
circuit Bar {
|
||||
b: u32
|
||||
}
|
||||
|
||||
function test() -> (u32, u32[2]) {
|
||||
return 1, [2, 3]
|
||||
function baz() -> u32 {
|
||||
return 1u32
|
||||
}
|
||||
```
|
||||
|
||||
`src/simple.leo`
|
||||
`src/main.leo`
|
||||
```rust
|
||||
from "./simple_import" import {
|
||||
Point as Foo,
|
||||
test
|
||||
};
|
||||
import bar.(
|
||||
Bar,
|
||||
baz
|
||||
);
|
||||
|
||||
// from "./simple_import" import *
|
||||
function main() {
|
||||
const bar = Bar { b: 1u32};
|
||||
const z = baz();
|
||||
}
|
||||
```
|
||||
|
||||
function main() -> (u32[3]) {
|
||||
let p = Foo { x: 1, y: 2};
|
||||
### Foreign
|
||||
You can import from a foreign package in the `imports/` directory using its `[package]` name.
|
||||
```rust
|
||||
import [package].[name];
|
||||
```
|
||||
|
||||
let (a, b) = test();
|
||||
#### Example:
|
||||
`imports/bar/src/lib.leo`
|
||||
```rust
|
||||
circuit Bar {
|
||||
b: u32
|
||||
}
|
||||
```
|
||||
|
||||
return [a, ...b]
|
||||
`src/main.leo`
|
||||
```rust
|
||||
import bar.Bar;
|
||||
|
||||
function main() {
|
||||
const bar = Bar { b: 1u32 };
|
||||
}
|
||||
```
|
||||
|
||||
### Package Paths
|
||||
Leo treats directories as package names when importing.
|
||||
```rust
|
||||
import [package].[directory].[file].[name]
|
||||
```
|
||||
|
||||
#### Example:
|
||||
We wish to import the `Baz` circuit from the `baz.leo` file in the `bar` directory in the `foo` package
|
||||
|
||||
|
||||
`imports/foo/src/bar/baz.leo`
|
||||
```rust
|
||||
circuit Baz {
|
||||
b: u32
|
||||
}
|
||||
```
|
||||
|
||||
`src/main.leo`
|
||||
```rust
|
||||
import foo.bar.baz.Baz;
|
||||
|
||||
function main() {
|
||||
const baz = Baz { b: 1u32 };
|
||||
}
|
||||
```
|
||||
|
||||
@ -400,11 +471,11 @@ This will enforce that the two values are equal in the constraint system.
|
||||
|
||||
```rust
|
||||
function main() {
|
||||
assert_eq(45, 45);
|
||||
assert_eq!(45, 45);
|
||||
|
||||
assert_eq(2fe, 2fe);
|
||||
assert_eq!(2fe, 2fe);
|
||||
|
||||
assert_eq(true, true);
|
||||
assert_eq!(true, true);
|
||||
}
|
||||
```
|
||||
|
||||
@ -490,13 +561,28 @@ This will create a new directory with a given package name. The new package will
|
||||
- inputs.leo # Your program inputs for main.leo
|
||||
- outputs # Your program outputs
|
||||
- src
|
||||
- lib.leo # Your program library
|
||||
- main.leo # Your program
|
||||
- tests
|
||||
- test.leo # Your program tests
|
||||
- Leo.toml # Your program manifest
|
||||
```
|
||||
|
||||
#### Flags
|
||||
```rust
|
||||
leo new {$Name} --bin
|
||||
```
|
||||
This will create a new directory with a given package name. The new package will have a directory structure as above.
|
||||
|
||||
```rust
|
||||
leo new {$Name} --lib
|
||||
```
|
||||
This will create a new directory with a given package name. The new package will have a directory structure as follows:
|
||||
```
|
||||
- src
|
||||
- lib.leo # Your program library
|
||||
- Leo.toml # Your program manifest
|
||||
```
|
||||
|
||||
### `leo init`
|
||||
|
||||
To initialize an existing directory, run:
|
||||
@ -505,6 +591,16 @@ leo init
|
||||
```
|
||||
This will initialize the current directory with the same package directory setup.
|
||||
|
||||
#### Flags
|
||||
`leo init` supports the same flags as `leo new`
|
||||
```rust
|
||||
leo init --bin
|
||||
```
|
||||
```rust
|
||||
leo init --lib
|
||||
```
|
||||
|
||||
|
||||
### `leo build`
|
||||
|
||||
To compile your program and verify that it builds properly, run:
|
||||
|
@ -1,8 +1,4 @@
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
common::LineEnd,
|
||||
imports::{ImportSource, ImportSymbol},
|
||||
};
|
||||
use crate::{ast::Rule, common::LineEnd, imports::Package};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
@ -10,8 +6,7 @@ use pest_ast::FromPest;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::import))]
|
||||
pub struct Import<'ast> {
|
||||
pub source: ImportSource<'ast>,
|
||||
pub symbols: Vec<ImportSymbol<'ast>>,
|
||||
pub package: Package<'ast>,
|
||||
pub line_end: LineEnd,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -1,13 +0,0 @@
|
||||
use crate::ast::{span_into_string, Rule};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::import_source))]
|
||||
pub struct ImportSource<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub value: String,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
pub mod import;
|
||||
pub use import::*;
|
||||
|
||||
pub mod import_source;
|
||||
pub use import_source::*;
|
||||
|
||||
pub mod import_symbol;
|
||||
pub use import_symbol::*;
|
||||
|
||||
pub mod package;
|
||||
pub use package::*;
|
||||
|
||||
pub mod package_access;
|
||||
pub use package_access::*;
|
||||
|
||||
pub mod star;
|
||||
pub use star::*;
|
||||
|
13
ast/src/imports/package.rs
Normal file
13
ast/src/imports/package.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::{ast::Rule, common::Identifier, imports::PackageAccess};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::package))]
|
||||
pub struct Package<'ast> {
|
||||
pub name: Identifier<'ast>,
|
||||
pub access: PackageAccess<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
15
ast/src/imports/package_access.rs
Normal file
15
ast/src/imports/package_access.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use crate::{
|
||||
ast::Rule,
|
||||
imports::{ImportSymbol, Package, Star},
|
||||
};
|
||||
|
||||
use pest_ast::FromPest;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::package_access))]
|
||||
pub enum PackageAccess<'ast> {
|
||||
Star(Star<'ast>),
|
||||
SubPackage(Box<Package<'ast>>),
|
||||
Symbol(ImportSymbol<'ast>),
|
||||
Multiple(Vec<PackageAccess<'ast>>),
|
||||
}
|
11
ast/src/imports/star.rs
Normal file
11
ast/src/imports/star.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use crate::ast::Rule;
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::star))]
|
||||
pub struct Star<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
@ -18,7 +18,7 @@ protected_name = {
|
||||
LINE_END = { ";" ~ NEWLINE* }
|
||||
|
||||
// Declared in common/mutable.rs
|
||||
mutable = { "mut" }
|
||||
mutable = { "mut " }
|
||||
|
||||
// Declared in common/range.rs
|
||||
range = { expression? ~ ".." ~ expression? }
|
||||
@ -33,15 +33,15 @@ spread = { "..." ~ expression }
|
||||
spread_or_expression = { spread | expression }
|
||||
|
||||
// Declared in common/static_.rs
|
||||
static_ = { "static" }
|
||||
static_ = { "static " }
|
||||
|
||||
// Declared in common/variable.rs
|
||||
variable = { mutable? ~ identifier ~ (":" ~ type_)? }
|
||||
|
||||
// Declared in common/declare.rs
|
||||
declare = { let_ | const_ }
|
||||
const_ = { "const" }
|
||||
let_ = { "let" }
|
||||
const_ = { "const " }
|
||||
let_ = { "let " }
|
||||
|
||||
/// Operations
|
||||
|
||||
@ -175,23 +175,23 @@ access_static_member = { "::" ~ identifier }
|
||||
/// Circuits
|
||||
|
||||
// Declared in circuits/circuit_definition.rs
|
||||
circuit = { "circuit" ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
circuit = { "circuit " ~ identifier ~ "{" ~ NEWLINE* ~ circuit_member* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
|
||||
// Declared in circuits/circuit_field.rs
|
||||
circuit_field = { identifier ~ ":" ~ expression }
|
||||
|
||||
// Declared in circuits/circuit_field_definition.rs
|
||||
circuit_field_definition = { identifier ~ ":" ~ type_ ~ NEWLINE* }
|
||||
circuit_field_definition = { identifier ~ ":" ~ type_ ~ ","?}
|
||||
|
||||
// Declared in circuits/circuit_function.rs
|
||||
circuit_function = { static_? ~ function_definition }
|
||||
|
||||
// Declared in circuits/circuit_member.rs
|
||||
circuit_member = { circuit_function | circuit_field_definition }
|
||||
circuit_member = { circuit_function | circuit_field_definition ~ NEWLINE*}
|
||||
|
||||
/// Conditionals
|
||||
|
||||
expression_conditional = { "if" ~ expression ~ "?" ~ expression ~ ":" ~ expression}
|
||||
expression_conditional = { "if " ~ expression ~ "? " ~ expression ~ ": " ~ expression}
|
||||
|
||||
/// Expressions
|
||||
|
||||
@ -252,7 +252,7 @@ assert_eq = {"assert_eq!" ~ "(" ~ NEWLINE* ~ expression ~ "," ~ NEWLINE* ~ expre
|
||||
statement_assign = { assignee ~ operation_assign ~ expression ~ LINE_END }
|
||||
|
||||
// Declared in statements/conditional_statement.rs
|
||||
statement_conditional = {"if" ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end_statement)?}
|
||||
statement_conditional = {"if " ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end_statement)?}
|
||||
conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"}
|
||||
|
||||
// Declared in statements/definition_statement.rs
|
||||
@ -262,40 +262,52 @@ statement_definition = { declare ~ variable ~ "=" ~ expression ~ LINE_END}
|
||||
statement_expression = { expression ~ LINE_END }
|
||||
|
||||
// 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
|
||||
statement_return = { "return" ~ expression_tuple }
|
||||
statement_return = { "return " ~ expression_tuple }
|
||||
|
||||
/// Functions
|
||||
|
||||
// Declared in functions/function.rs
|
||||
function_definition = { "function" ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
function_definition = { "function " ~ identifier ~ "(" ~ input_model_list ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
|
||||
// Declared in functions/function_input.rs
|
||||
function_input = { mutable? ~ identifier ~ ":" ~ type_ }
|
||||
input_model_list = _{ (function_input ~ ("," ~ function_input)*)? }
|
||||
|
||||
// Declared in functions/test_function.rs
|
||||
test_function = { "test" ~ function_definition }
|
||||
test_function = { "test " ~ function_definition }
|
||||
|
||||
/// Imports
|
||||
|
||||
// Declared in imports/import.rs
|
||||
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}") | import_symbol) ~ LINE_END}
|
||||
import = { "import" ~ package ~ LINE_END}
|
||||
|
||||
// Declared in imports/import_source.rs
|
||||
import_source = @{ (!"\"" ~ ANY)* }
|
||||
// Declared in imports/package.rs
|
||||
package = { identifier ~ "." ~ package_access }
|
||||
|
||||
// Declared in imports/package_access
|
||||
package_access = {
|
||||
star
|
||||
| package // subpackage
|
||||
| multiple_package_access
|
||||
| import_symbol
|
||||
}
|
||||
|
||||
multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ ","? ~ NEWLINE* ~ ")"}
|
||||
|
||||
// Declared in imports/star.rs
|
||||
star = {"*"}
|
||||
|
||||
// Declared in imports/import_symbol.rs
|
||||
import_symbol = { identifier ~ ("as" ~ identifier)? }
|
||||
import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* }
|
||||
|
||||
/// Utilities
|
||||
|
||||
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
||||
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
|
||||
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* } // pest implicit whitespace keyword
|
||||
|
@ -9,18 +9,18 @@ leo-ast = { path = "../ast", version = "0.1.0" }
|
||||
leo-types = { path = "../types", version = "0.1.0" }
|
||||
leo-inputs = { path = "../leo-inputs", version = "0.1.0" }
|
||||
|
||||
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0", default-features = false }
|
||||
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false }
|
||||
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0", default-features = false }
|
||||
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false }
|
||||
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
|
||||
bincode = { version = "1.0" }
|
||||
hex = { version = "0.4.2" }
|
||||
log = { version = "0.4" }
|
||||
pest = { version = "2.0" }
|
||||
rand = { version = "0.7" }
|
||||
sha2 = { version = "0.8" }
|
||||
sha2 = { version = "0.9" }
|
||||
thiserror = { version = "1.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
snarkos-utilities = { path = "../../snarkOS/utilities", version = "0.8.0" }
|
||||
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" }
|
||||
|
@ -66,8 +66,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
|
||||
// Hash the file contents
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.input(unparsed_file.as_bytes());
|
||||
let hash = hasher.result();
|
||||
hasher.update(unparsed_file.as_bytes());
|
||||
let hash = hasher.finalize();
|
||||
|
||||
Ok(hex::encode(hash))
|
||||
}
|
||||
|
@ -1,91 +0,0 @@
|
||||
use crate::{
|
||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
||||
errors::constraints::ImportError,
|
||||
new_scope,
|
||||
GroupType,
|
||||
};
|
||||
use leo_ast::LeoParser;
|
||||
use leo_types::{Import, Program};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::env::current_dir;
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> {
|
||||
let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?;
|
||||
|
||||
// Sanitize the package path to the imports directory
|
||||
let mut package_path = path.clone();
|
||||
if package_path.is_file() {
|
||||
package_path.pop();
|
||||
}
|
||||
|
||||
// Construct the path to the import file in the import directory
|
||||
let mut main_file_path = package_path.clone();
|
||||
main_file_path.push(import.path_string_full());
|
||||
|
||||
println!("Compiling import - {:?}", main_file_path);
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let file_path = &main_file_path;
|
||||
let input_file = &LeoParser::load_file(file_path)?;
|
||||
let syntax_tree = LeoParser::parse_file(file_path, input_file)?;
|
||||
|
||||
// Generate aleo program from file
|
||||
let mut program = Program::from(syntax_tree, import.path_string.clone());
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
|
||||
// * -> import all imports, circuits, functions in the current scope
|
||||
if import.is_star() {
|
||||
// recursively evaluate program statements
|
||||
self.resolve_definitions(program)
|
||||
} else {
|
||||
let program_name = program.name.clone();
|
||||
|
||||
// match each import symbol to a symbol in the imported file
|
||||
for symbol in import.symbols.into_iter() {
|
||||
// see if the imported symbol is a circuit
|
||||
let matched_circuit = program
|
||||
.circuits
|
||||
.clone()
|
||||
.into_iter()
|
||||
.find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name);
|
||||
|
||||
let value = match matched_circuit {
|
||||
Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def),
|
||||
None => {
|
||||
// see if the imported symbol is a function
|
||||
let matched_function = program
|
||||
.functions
|
||||
.clone()
|
||||
.into_iter()
|
||||
.find(|(function_name, _function)| symbol.symbol.name == *function_name.name);
|
||||
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => ConstrainedValue::Function(None, function),
|
||||
None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// take the alias if it is present
|
||||
let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
|
||||
let resolved_circuit_name = new_scope(program_name.clone(), resolved_name.to_string());
|
||||
|
||||
// store imported circuit under resolved name
|
||||
self.store(resolved_circuit_name, value);
|
||||
}
|
||||
|
||||
// evaluate all import statements in imported file
|
||||
program
|
||||
.imports
|
||||
.into_iter()
|
||||
.map(|nested_import| self.enforce_import(program_name.clone(), nested_import))
|
||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
13
compiler/src/constraints/import/import.rs
Normal file
13
compiler/src/constraints/import/import.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType};
|
||||
use leo_types::Import;
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::env::current_dir;
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> {
|
||||
let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?;
|
||||
|
||||
self.enforce_package(scope, path, import.package)
|
||||
}
|
||||
}
|
136
compiler/src/constraints/import/import_symbol.rs
Normal file
136
compiler/src/constraints/import/import_symbol.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use crate::{
|
||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
||||
errors::constraints::ImportError,
|
||||
new_scope,
|
||||
GroupType,
|
||||
};
|
||||
use leo_ast::LeoParser;
|
||||
use leo_types::{ImportSymbol, Program, Span};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
fs::{read_dir, DirEntry},
|
||||
};
|
||||
|
||||
static LIBRARY_FILE: &str = "src/lib.leo";
|
||||
|
||||
fn parse_import_file(entry: &DirEntry, span: &Span) -> Result<Program, ImportError> {
|
||||
// make sure the given entry is file
|
||||
let file_type = entry
|
||||
.file_type()
|
||||
.map_err(|error| ImportError::directory_error(error, span.clone()))?;
|
||||
let file_name = entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.map_err(|_| ImportError::convert_os_string(span.clone()))?;
|
||||
|
||||
let mut file_path = entry.path();
|
||||
if file_type.is_dir() {
|
||||
file_path.push(LIBRARY_FILE);
|
||||
|
||||
if !file_path.exists() {
|
||||
return Err(ImportError::expected_lib_file(
|
||||
format!("{:?}", file_path.as_path()),
|
||||
span.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let input_file = &LeoParser::load_file(&file_path)?;
|
||||
let syntax_tree = LeoParser::parse_file(&file_path, input_file)?;
|
||||
|
||||
// Generate aleo program from file
|
||||
Ok(Program::from(syntax_tree, file_name.clone()))
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_import_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> {
|
||||
// import star from a file
|
||||
if entry.path().is_file() {
|
||||
// only parse `.leo` files
|
||||
if let Some(extension) = entry.path().extension() {
|
||||
if extension.eq(&OsString::from("leo")) {
|
||||
let mut program = parse_import_file(entry, &span)?;
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
|
||||
// * -> import all imports, circuits, functions in the current scope
|
||||
self.resolve_definitions(program)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
// import star for every file in the directory
|
||||
for entry in read_dir(entry.path()).map_err(|error| ImportError::directory_error(error, span.clone()))? {
|
||||
match entry {
|
||||
Ok(entry) => self.enforce_import_star(scope.clone(), &entry, span.clone())?,
|
||||
Err(error) => return Err(ImportError::directory_error(error, span.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enforce_import_symbol(
|
||||
&mut self,
|
||||
scope: String,
|
||||
entry: &DirEntry,
|
||||
symbol: ImportSymbol,
|
||||
) -> Result<(), ImportError> {
|
||||
// Generate aleo program from file
|
||||
let mut program = parse_import_file(entry, &symbol.span)?;
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
|
||||
let program_name = program.name.clone();
|
||||
|
||||
// see if the imported symbol is a circuit
|
||||
let matched_circuit = program
|
||||
.circuits
|
||||
.clone()
|
||||
.into_iter()
|
||||
.find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name);
|
||||
|
||||
let value = match matched_circuit {
|
||||
Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def),
|
||||
None => {
|
||||
// see if the imported symbol is a function
|
||||
let matched_function = program
|
||||
.functions
|
||||
.clone()
|
||||
.into_iter()
|
||||
.find(|(function_name, _function)| symbol.symbol == *function_name);
|
||||
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => ConstrainedValue::Function(None, function),
|
||||
None => return Err(ImportError::unknown_symbol(symbol, program_name, &entry.path())),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// take the alias if it is present
|
||||
let name = symbol.alias.unwrap_or(symbol.symbol);
|
||||
let resolved_name = new_scope(program_name.clone(), name.to_string());
|
||||
|
||||
// store imported circuit under resolved name
|
||||
self.store(resolved_name, value);
|
||||
|
||||
// evaluate all import statements in imported file
|
||||
// todo: add logic to detect import loops
|
||||
program
|
||||
.imports
|
||||
.into_iter()
|
||||
.map(|nested_import| self.enforce_import(program_name.clone(), nested_import))
|
||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
8
compiler/src/constraints/import/mod.rs
Normal file
8
compiler/src/constraints/import/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub mod import;
|
||||
pub use import::*;
|
||||
|
||||
pub mod import_symbol;
|
||||
pub use import_symbol::*;
|
||||
|
||||
pub mod package;
|
||||
pub use package::*;
|
91
compiler/src/constraints/import/package.rs
Normal file
91
compiler/src/constraints/import/package.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType};
|
||||
use leo_types::{Package, PackageAccess};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::{fs, fs::DirEntry, path::PathBuf};
|
||||
|
||||
static SOURCE_FILE_EXTENSION: &str = ".leo";
|
||||
static SOURCE_DIRECTORY_NAME: &str = "src/";
|
||||
static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_package_access(
|
||||
&mut self,
|
||||
scope: String,
|
||||
entry: &DirEntry,
|
||||
access: PackageAccess,
|
||||
) -> Result<(), ImportError> {
|
||||
// bring one or more import symbols into scope for the current constrained program
|
||||
// we will recursively traverse sub packages here until we find the desired symbol
|
||||
match access {
|
||||
PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span),
|
||||
PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol),
|
||||
PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package),
|
||||
PackageAccess::Multiple(accesses) => {
|
||||
for access in accesses {
|
||||
self.enforce_package_access(scope.clone(), entry, access)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enforce_package(&mut self, scope: String, mut path: PathBuf, package: Package) -> Result<(), ImportError> {
|
||||
let package_name = package.name;
|
||||
|
||||
// search for package name in local directory
|
||||
let mut source_directory = path.clone();
|
||||
source_directory.push(SOURCE_DIRECTORY_NAME);
|
||||
|
||||
// search for package name in `imports` directory
|
||||
let mut imports_directory = path.clone();
|
||||
imports_directory.push(IMPORTS_DIRECTORY_NAME);
|
||||
|
||||
// read from local `src` directory or the current path
|
||||
if source_directory.exists() {
|
||||
path = source_directory
|
||||
}
|
||||
|
||||
let entries = fs::read_dir(path)
|
||||
.map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
||||
.map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?;
|
||||
|
||||
let matched_source_entry = entries.into_iter().find(|entry| {
|
||||
entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.trim_end_matches(SOURCE_FILE_EXTENSION)
|
||||
.eq(&package_name.name)
|
||||
});
|
||||
|
||||
if imports_directory.exists() {
|
||||
let entries = fs::read_dir(imports_directory)
|
||||
.map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
||||
.map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?;
|
||||
|
||||
let matched_import_entry = entries
|
||||
.into_iter()
|
||||
.find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name));
|
||||
|
||||
// Enforce package access and potential collisions
|
||||
match (matched_source_entry, matched_import_entry) {
|
||||
(Some(_), Some(_)) => Err(ImportError::conflicting_imports(package_name)),
|
||||
(Some(source_entry), None) => self.enforce_package_access(scope, &source_entry, package.access),
|
||||
(None, Some(import_entry)) => self.enforce_package_access(scope, &import_entry, package.access),
|
||||
(None, None) => Err(ImportError::unknown_package(package_name)),
|
||||
}
|
||||
} else {
|
||||
// Enforce local package access with no found imports directory
|
||||
match matched_source_entry {
|
||||
Some(source_entry) => self.enforce_package_access(scope, &source_entry, package.access),
|
||||
None => Err(ImportError::unknown_package(package_name)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -59,7 +59,6 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
||||
match main.clone() {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
let result = resolved_program.enforce_main_function(cs, program_name, function, parameters)?;
|
||||
log::debug!("{}", result);
|
||||
Ok(result)
|
||||
}
|
||||
_ => Err(CompilerError::NoMainFunction),
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
||||
errors::StatementError,
|
||||
errors::{StatementError, ValueError},
|
||||
new_scope,
|
||||
GroupType,
|
||||
Integer,
|
||||
@ -21,7 +21,6 @@ use leo_types::{
|
||||
Variable,
|
||||
};
|
||||
|
||||
use crate::errors::ValueError;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
|
@ -1,5 +1,5 @@
|
||||
use leo_ast::ParserError;
|
||||
use leo_types::{Error as FormattedError, ImportSymbol, Span};
|
||||
use leo_types::{Error as FormattedError, Identifier, ImportSymbol, Span};
|
||||
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
@ -17,12 +17,42 @@ impl ImportError {
|
||||
ImportError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn directory_error(error: io::Error, span: Span) -> Self {
|
||||
let message = format!("attempt to access current directory failed - {:?}", error);
|
||||
pub fn conflicting_imports(identifier: Identifier) -> Self {
|
||||
let message = format!("conflicting imports found for `{}`", identifier.name);
|
||||
|
||||
Self::new_from_span(message, identifier.span)
|
||||
}
|
||||
|
||||
pub fn convert_os_string(span: Span) -> Self {
|
||||
let message = format!("failed to convert file string name, maybe an illegal character?");
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn directory_error(error: io::Error, span: Span) -> Self {
|
||||
let message = format!("compilation failed due to directory error - {:?}", error);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn expected_lib_file(entry: String, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"expected library file`{}` when looking for symbol `{}`",
|
||||
entry, span.text
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn unknown_package(identifier: Identifier) -> Self {
|
||||
let message = format!(
|
||||
"cannot find imported package `{}` in source files or import directory",
|
||||
identifier.name
|
||||
);
|
||||
|
||||
Self::new_from_span(message, identifier.span)
|
||||
}
|
||||
|
||||
pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self {
|
||||
let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file);
|
||||
let mut error = FormattedError::new_from_span(message, symbol.span);
|
||||
|
@ -1,5 +1,5 @@
|
||||
circuit Circ {
|
||||
x: u32
|
||||
x: u32,
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
|
@ -1,5 +1,5 @@
|
||||
circuit Foo {
|
||||
foo: u32
|
||||
foo: u32,
|
||||
|
||||
static function bar() -> u32 {
|
||||
return 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import foo as bar;
|
||||
import test_import.foo as bar;
|
||||
|
||||
function main() -> u32 {
|
||||
return bar()
|
||||
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import foo;
|
||||
import test_import.foo;
|
||||
|
||||
function main() -> u32 {
|
||||
return foo()
|
||||
|
1
compiler/tests/import/imports/bar/.gitignore
vendored
Executable file
1
compiler/tests/import/imports/bar/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
outputs/
|
3
compiler/tests/import/imports/bar/Leo.toml
Executable file
3
compiler/tests/import/imports/bar/Leo.toml
Executable file
@ -0,0 +1,3 @@
|
||||
[package]
|
||||
name = "bar"
|
||||
version = "0.1.0"
|
3
compiler/tests/import/imports/bar/src/bat/bat.leo
Executable file
3
compiler/tests/import/imports/bar/src/bat/bat.leo
Executable file
@ -0,0 +1,3 @@
|
||||
circuit Bat {
|
||||
t: u32
|
||||
}
|
3
compiler/tests/import/imports/bar/src/baz.leo
Executable file
3
compiler/tests/import/imports/bar/src/baz.leo
Executable file
@ -0,0 +1,3 @@
|
||||
circuit Baz {
|
||||
z: u32
|
||||
}
|
3
compiler/tests/import/imports/bar/src/lib.leo
Executable file
3
compiler/tests/import/imports/bar/src/lib.leo
Executable file
@ -0,0 +1,3 @@
|
||||
circuit Bar {
|
||||
r: u32
|
||||
}
|
1
compiler/tests/import/imports/car/.gitignore
vendored
Executable file
1
compiler/tests/import/imports/car/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
outputs/
|
3
compiler/tests/import/imports/car/Leo.toml
Executable file
3
compiler/tests/import/imports/car/Leo.toml
Executable file
@ -0,0 +1,3 @@
|
||||
[package]
|
||||
name = "car"
|
||||
version = "0.1.0"
|
3
compiler/tests/import/imports/car/src/lib.leo
Executable file
3
compiler/tests/import/imports/car/src/lib.leo
Executable file
@ -0,0 +1,3 @@
|
||||
circuit Car {
|
||||
c: u32
|
||||
}
|
25
compiler/tests/import/many_import.leo
Normal file
25
compiler/tests/import/many_import.leo
Normal file
@ -0,0 +1,25 @@
|
||||
import test_import.( // local import
|
||||
Point,
|
||||
foo,
|
||||
);
|
||||
|
||||
import bar.( // imports directory import
|
||||
Bar,
|
||||
baz.Baz,
|
||||
bat.bat.Bat,
|
||||
);
|
||||
|
||||
import car.Car; // imports directory import
|
||||
|
||||
function main() -> u32 {
|
||||
// const point = Point { x: 1u32, y: 1u32 };
|
||||
// const foo = foo();
|
||||
|
||||
const bar = Bar { r: 1u32 };
|
||||
const bat = Bat { t: 1u32 };
|
||||
const baz = Baz { z: 1u32 };
|
||||
|
||||
const car = Car { c: 1u32 };
|
||||
|
||||
return car.c
|
||||
}
|
16
compiler/tests/import/many_import_star.leo
Normal file
16
compiler/tests/import/many_import_star.leo
Normal file
@ -0,0 +1,16 @@
|
||||
import test_import.*; // local import
|
||||
import bar.*; // imports directory import
|
||||
import car.*; // imports directory import
|
||||
|
||||
function main() -> u32 {
|
||||
const point = Point { x: 1u32, y: 1u32 };
|
||||
const foo = foo();
|
||||
|
||||
const bar = Bar { r: 1u32 };
|
||||
const bat = Bat { t: 1u32 };
|
||||
const baz = Baz { z: 1u32 };
|
||||
|
||||
const car = Car { c: 1u32 };
|
||||
|
||||
return car.c
|
||||
}
|
@ -1,13 +1,26 @@
|
||||
use crate::{integers::u32::output_one, parse_program};
|
||||
|
||||
use std::env::{current_dir, set_current_dir};
|
||||
|
||||
static TEST_SOURCE_DIRECTORY: &str = "tests/import";
|
||||
|
||||
// Import tests rely on knowledge of local directories. They should be run locally only.
|
||||
|
||||
fn set_local_dir() {
|
||||
let mut local = current_dir().unwrap();
|
||||
local.push(TEST_SOURCE_DIRECTORY);
|
||||
|
||||
set_current_dir(local).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_basic() {
|
||||
let bytes = include_bytes!("basic.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -17,6 +30,8 @@ fn test_multiple() {
|
||||
let bytes = include_bytes!("multiple.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -26,6 +41,8 @@ fn test_star() {
|
||||
let bytes = include_bytes!("star.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -35,5 +52,30 @@ fn test_alias() {
|
||||
let bytes = include_bytes!("alias.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
// more complex tests
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_many_import() {
|
||||
let bytes = include_bytes!("many_import.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_many_import_star() {
|
||||
let bytes = include_bytes!("many_import_star.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
from "tests/import/test_import" import {
|
||||
import test_import.(
|
||||
Point,
|
||||
foo
|
||||
};
|
||||
);
|
||||
|
||||
function main() -> u32 {
|
||||
let p = Point { x: 1u32, y: 0u32 };
|
||||
return foo()
|
||||
return p.x
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import *;
|
||||
import test_import.*;
|
||||
|
||||
function main() -> u32 {
|
||||
let p = Point { x: 1u32, y: 0u32 };
|
||||
|
@ -15,8 +15,8 @@ circuit PedersenHash {
|
||||
|
||||
// The 'pedersen_hash' main function.
|
||||
function main() -> u32 {
|
||||
let parameters = [0u32; 512];
|
||||
let pedersen = PedersenHash::new(parameters);
|
||||
const parameters = [0u32; 512];
|
||||
const pedersen = PedersenHash::new(parameters);
|
||||
let input: bool[512] = [true; 512];
|
||||
return pedersen.hash(input)
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ authors = ["The Aleo Team <hello@aleo.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
snarkos-algorithms = { path = "../../snarkOS/algorithms", version = "0.8.0", default-features = false }
|
||||
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0", default-features = false }
|
||||
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false }
|
||||
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0", default-features = false }
|
||||
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false }
|
||||
snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
|
||||
from-pest = { version = "0.3.1" }
|
||||
pest = { version = "2.0" }
|
||||
|
15
leo/cli.rs
15
leo/cli.rs
@ -1,4 +1,4 @@
|
||||
use crate::{cli_types::*, errors::CLIError};
|
||||
use crate::{cli_types::*, errors::CLIError, logger};
|
||||
|
||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
|
||||
@ -66,6 +66,19 @@ pub trait CLI {
|
||||
.subcommands(subcommands)
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn process(arguments: &ArgMatches) -> Result<(), CLIError> {
|
||||
// Set logging environment
|
||||
match arguments.is_present("debug") {
|
||||
true => logger::init_logger("leo", 2),
|
||||
false => logger::init_logger("leo", 1),
|
||||
}
|
||||
|
||||
let options = Self::parse(arguments)?;
|
||||
let _output = Self::output(options)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError>;
|
||||
|
||||
|
@ -2,15 +2,15 @@ use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory},
|
||||
errors::{BuildError, CLIError},
|
||||
files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME},
|
||||
errors::CLIError,
|
||||
files::{ChecksumFile, LibFile, MainFile, Manifest, LIB_FILE_NAME, MAIN_FILE_NAME},
|
||||
};
|
||||
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
use snarkos_algorithms::snark::KeypairAssembly;
|
||||
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
||||
|
||||
use crate::files::BytesFile;
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
@ -19,7 +19,7 @@ pub struct BuildCommand;
|
||||
|
||||
impl CLI for BuildCommand {
|
||||
type Options = ();
|
||||
type Output = (Compiler<Fq, EdwardsGroupType>, bool);
|
||||
type Output = Option<(Compiler<Fq, EdwardsGroupType>, bool)>;
|
||||
|
||||
const ABOUT: AboutType = "Compile the current package as a program";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
@ -47,80 +47,75 @@ impl CLI for BuildCommand {
|
||||
package_path.pop();
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if !MainFile::exists_at(&package_path) {
|
||||
return Err(BuildError::MainFileDoesNotExist(package_path.as_os_str().to_owned()).into());
|
||||
}
|
||||
// Compile the package starting with the lib.leo file
|
||||
if LibFile::exists_at(&package_path) {
|
||||
// Construct the path to the library file in the source directory
|
||||
let mut lib_file_path = package_path.clone();
|
||||
lib_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
lib_file_path.push(LIB_FILE_NAME);
|
||||
|
||||
// Create the outputs directory
|
||||
OutputsDirectory::create(&package_path)?;
|
||||
// Compile the library file but do not output
|
||||
let _program = Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), lib_file_path)?;
|
||||
};
|
||||
|
||||
// Construct the path to the main file in the source directory
|
||||
let mut main_file_path = package_path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
// Compile the main.leo file along with constraints
|
||||
if MainFile::exists_at(&package_path) {
|
||||
// Create the outputs directory
|
||||
OutputsDirectory::create(&package_path)?;
|
||||
|
||||
// Check if the program bytes exist
|
||||
let existing_bytes = BytesFile::new(&package_name).exists_at(&path);
|
||||
// Construct the path to the main file in the source directory
|
||||
let mut main_file_path = package_path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
let program = if existing_bytes {
|
||||
// Load the program ast from stored bytes
|
||||
let bytes = BytesFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
let mut program = Compiler::<Fq, EdwardsGroupType>::from_bytes(bytes.as_slice())?;
|
||||
|
||||
program.set_path(main_file_path.clone());
|
||||
|
||||
program
|
||||
} else {
|
||||
// Load the program at `main_file_path`
|
||||
let program =
|
||||
Compiler::<Fq, EdwardsGroupType>::new_from_path(package_name.clone(), main_file_path.clone())?;
|
||||
|
||||
// Store the program ast as bytes
|
||||
let bytes = program.to_bytes()?;
|
||||
// Compute the current program checksum
|
||||
let program_checksum = program.checksum()?;
|
||||
|
||||
BytesFile::new(&package_name).write_to(&path, bytes)?;
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
{
|
||||
let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at: vec![],
|
||||
bt: vec![],
|
||||
ct: vec![],
|
||||
};
|
||||
let temporary_program = program.clone();
|
||||
let output = temporary_program.compile_constraints(&mut cs)?;
|
||||
log::debug!("Compiled constraints - {:#?}", output);
|
||||
log::debug!("Number of constraints - {:#?}", cs.num_constraints());
|
||||
}
|
||||
|
||||
program
|
||||
};
|
||||
|
||||
// Compute the current program checksum
|
||||
let program_checksum = program.checksum()?;
|
||||
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
{
|
||||
let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at: vec![],
|
||||
bt: vec![],
|
||||
ct: vec![],
|
||||
// If a checksum file exists, check if it differs from the new checksum
|
||||
let checksum_file = ChecksumFile::new(&package_name);
|
||||
let checksum_differs = if checksum_file.exists_at(&package_path) {
|
||||
let previous_checksum = checksum_file.read_from(&package_path)?;
|
||||
program_checksum != previous_checksum
|
||||
} else {
|
||||
// By default, the checksum differs if there is no checksum to compare against
|
||||
true
|
||||
};
|
||||
let temporary_program = program.clone();
|
||||
let output = temporary_program.compile_constraints(&mut cs)?;
|
||||
log::debug!("Compiled constraints - {:#?}", output);
|
||||
|
||||
// If checksum differs, compile the program
|
||||
if checksum_differs {
|
||||
// Write the new checksum to the outputs directory
|
||||
checksum_file.write_to(&path, program_checksum)?;
|
||||
|
||||
log::debug!("Checksum saved ({:?})", path);
|
||||
}
|
||||
|
||||
log::info!("Compiled program in {:?}", main_file_path);
|
||||
|
||||
return Ok(Some((program, checksum_differs)));
|
||||
}
|
||||
|
||||
// If a checksum file exists, check if it differs from the new checksum
|
||||
let checksum_file = ChecksumFile::new(&package_name);
|
||||
let checksum_differs = if checksum_file.exists_at(&package_path) {
|
||||
let previous_checksum = checksum_file.read_from(&package_path)?;
|
||||
program_checksum != previous_checksum
|
||||
} else {
|
||||
// By default, the checksum differs if there is no checksum to compare against
|
||||
true
|
||||
};
|
||||
|
||||
// If checksum differs, compile the program
|
||||
if checksum_differs {
|
||||
// Write the new checksum to the outputs directory
|
||||
checksum_file.write_to(&path, program_checksum)?;
|
||||
}
|
||||
|
||||
log::info!("Compiled program in {:?}", main_file_path);
|
||||
|
||||
Ok((program, checksum_differs))
|
||||
// Return None when compiling a package for publishing
|
||||
// The published package does not need to have a main.leo
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
50
leo/commands/clean.rs
Normal file
50
leo/commands/clean.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
errors::CLIError,
|
||||
files::{ChecksumFile, Manifest, ProofFile, ProvingKeyFile, VerificationKeyFile},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CleanCommand;
|
||||
|
||||
impl CLI for CleanCommand {
|
||||
type Options = ();
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Clean the outputs directory";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const NAME: NameType = "clean";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(_options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
// Remove the checksum from the outputs directory
|
||||
ChecksumFile::new(&package_name).remove(&path)?;
|
||||
|
||||
// Remove the proving key from the outputs directory
|
||||
ProvingKeyFile::new(&package_name).remove(&path)?;
|
||||
|
||||
// Remove the verification key from the outputs directory
|
||||
VerificationKeyFile::new(&package_name).remove(&path)?;
|
||||
|
||||
// Remove the proof from the outputs directory
|
||||
ProofFile::new(&package_name).remove(&path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,26 @@ impl CLI for DeployCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
Ok(())
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
cli_types::*,
|
||||
directories::{InputsDirectory, SourceDirectory},
|
||||
errors::{CLIError, InitError},
|
||||
files::{Gitignore, InputsFile, MainFile, Manifest},
|
||||
files::{Gitignore, InputsFile, LibFile, MainFile, Manifest},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
@ -13,35 +13,31 @@ use std::env::current_dir;
|
||||
pub struct InitCommand;
|
||||
|
||||
impl CLI for InitCommand {
|
||||
type Options = Option<String>;
|
||||
type Options = bool;
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Create a new Leo package in an existing directory";
|
||||
const ARGUMENTS: &'static [ArgumentType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")];
|
||||
const NAME: NameType = "init";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(_arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
Ok(None)
|
||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
Ok(arguments.is_present("lib"))
|
||||
}
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let name = options;
|
||||
let path = current_dir()?;
|
||||
|
||||
// Derive the package name
|
||||
let package_name = match name {
|
||||
Some(name) => name,
|
||||
None => path
|
||||
.file_stem()
|
||||
.ok_or_else(|| InitError::ProjectNameInvalid(path.as_os_str().to_owned()))?
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
};
|
||||
let package_name = path
|
||||
.file_stem()
|
||||
.ok_or_else(|| InitError::ProjectNameInvalid(path.as_os_str().to_owned()))?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
// Verify the directory exists
|
||||
if !path.exists() {
|
||||
@ -62,20 +58,30 @@ impl CLI for InitCommand {
|
||||
// Create the source directory
|
||||
SourceDirectory::create(&path)?;
|
||||
|
||||
// Create the inputs directory
|
||||
InputsDirectory::create(&path)?;
|
||||
// Create a new library or binary file
|
||||
|
||||
// Verify the inputs file does not exist
|
||||
let inputs_file = InputsFile::new(&package_name);
|
||||
if !inputs_file.exists_at(&path) {
|
||||
// Create the inputs file in the inputs directory
|
||||
inputs_file.write_to(&path)?;
|
||||
}
|
||||
if options {
|
||||
// Verify the library file does not exist
|
||||
if !LibFile::exists_at(&path) {
|
||||
// Create the library file in the source directory
|
||||
LibFile::new(&package_name).write_to(&path)?;
|
||||
}
|
||||
} else {
|
||||
// Create the inputs directory
|
||||
InputsDirectory::create(&path)?;
|
||||
|
||||
// Verify the main file does not exist
|
||||
if !MainFile::exists_at(&path) {
|
||||
// Create the main file in the source directory
|
||||
MainFile::new(&package_name).write_to(&path)?;
|
||||
// Verify the inputs file does not exist
|
||||
let inputs_file = InputsFile::new(&package_name);
|
||||
if !inputs_file.exists_at(&path) {
|
||||
// Create the inputs file in the inputs directory
|
||||
inputs_file.write_to(&path)?;
|
||||
}
|
||||
|
||||
// Verify the main file does not exist
|
||||
if !MainFile::exists_at(&path) {
|
||||
// Create the main file in the source directory
|
||||
MainFile::new(&package_name).write_to(&path)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,25 @@ impl CLI for LoadCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
log::info!("Unimplemented - `leo load`");
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
pub mod build;
|
||||
pub use self::build::*;
|
||||
|
||||
pub mod clean;
|
||||
pub use self::clean::*;
|
||||
|
||||
pub mod deploy;
|
||||
pub use self::deploy::*;
|
||||
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
cli_types::*,
|
||||
directories::{InputsDirectory, SourceDirectory},
|
||||
errors::{CLIError, NewError},
|
||||
files::{Gitignore, InputsFile, MainFile, Manifest},
|
||||
files::{Gitignore, InputsFile, LibFile, MainFile, Manifest},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
@ -13,7 +13,7 @@ use std::{env::current_dir, fs};
|
||||
pub struct NewCommand;
|
||||
|
||||
impl CLI for NewCommand {
|
||||
type Options = Option<String>;
|
||||
type Options = (Option<String>, bool);
|
||||
type Output = ();
|
||||
|
||||
const ABOUT: AboutType = "Create a new Leo package in a new directory";
|
||||
@ -26,16 +26,21 @@ impl CLI for NewCommand {
|
||||
1u64,
|
||||
),
|
||||
];
|
||||
const FLAGS: &'static [FlagType] = &[];
|
||||
const FLAGS: &'static [FlagType] = &[("--lib"), ("--bin")];
|
||||
const NAME: NameType = "new";
|
||||
const OPTIONS: &'static [OptionType] = &[];
|
||||
const SUBCOMMANDS: &'static [SubCommandType] = &[];
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn parse(arguments: &ArgMatches) -> Result<Self::Options, CLIError> {
|
||||
let mut is_lib = false;
|
||||
if arguments.is_present("lib") {
|
||||
is_lib = true;
|
||||
}
|
||||
|
||||
match arguments.value_of("NAME") {
|
||||
Some(name) => Ok(Some(name.to_string())),
|
||||
None => Ok(None),
|
||||
Some(name) => Ok((Some(name.to_string()), is_lib)),
|
||||
None => Ok((None, is_lib)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +49,7 @@ impl CLI for NewCommand {
|
||||
let mut path = current_dir()?;
|
||||
|
||||
// Derive the package name
|
||||
let package_name = match options {
|
||||
let package_name = match options.0 {
|
||||
Some(name) => name,
|
||||
None => path
|
||||
.file_stem()
|
||||
@ -74,14 +79,20 @@ impl CLI for NewCommand {
|
||||
// Create the source directory
|
||||
SourceDirectory::create(&path)?;
|
||||
|
||||
// Create the inputs directory
|
||||
InputsDirectory::create(&path)?;
|
||||
// Create a new library or binary file
|
||||
if options.1 {
|
||||
// Create the library file in the source directory
|
||||
LibFile::new(&package_name).write_to(&path)?;
|
||||
} else {
|
||||
// Create the inputs directory
|
||||
InputsDirectory::create(&path)?;
|
||||
|
||||
// Create the inputs file in the inputs directory
|
||||
InputsFile::new(&package_name).write_to(&path)?;
|
||||
// Create the inputs file in the inputs directory
|
||||
InputsFile::new(&package_name).write_to(&path)?;
|
||||
|
||||
// Create the main file in the source directory
|
||||
MainFile::new(&package_name).write_to(&path)?;
|
||||
// Create the main file in the source directory
|
||||
MainFile::new(&package_name).write_to(&path)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ impl CLI for ProveCommand {
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Proving...");
|
||||
|
||||
// Fetch program inputs here
|
||||
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
|
||||
program.parse_inputs(&inputs_string)?;
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::outputs::OutputsDirectory,
|
||||
errors::CLIError,
|
||||
files::{Manifest, ZipFile},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,13 +31,24 @@ impl CLI for PublishCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
// Build all program files.
|
||||
// It's okay if there's just a lib.leo file here
|
||||
let _output = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
let package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo publish`");
|
||||
// Create the outputs directory
|
||||
OutputsDirectory::create(&path)?;
|
||||
|
||||
// Create zip file
|
||||
let zip_file = ZipFile::new(&package_name);
|
||||
if zip_file.exists_at(&path) {
|
||||
log::info!("Existing package zip file found. Skipping compression.")
|
||||
} else {
|
||||
zip_file.write(&path)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,8 +2,9 @@ use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
errors::{CLIError, VerificationKeyFileError},
|
||||
files::{Manifest, ProvingKeyFile, VerificationKeyFile},
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError, VerificationKeyFileError},
|
||||
files::{Manifest, ProvingKeyFile, VerificationKeyFile, MAIN_FILE_NAME},
|
||||
};
|
||||
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
@ -40,66 +41,87 @@ impl CLI for SetupCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (program, checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
// Check if a proving key and verification key already exists
|
||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
||||
match BuildCommand::output(options)? {
|
||||
Some((program, checksum_differs)) => {
|
||||
// Check if a proving key and verification key already exists
|
||||
let keys_exist = ProvingKeyFile::new(&package_name).exists_at(&path)
|
||||
&& VerificationKeyFile::new(&package_name).exists_at(&path);
|
||||
|
||||
// If keys do not exist or the checksum differs, run the program setup
|
||||
if !keys_exist || checksum_differs {
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
// If keys do not exist or the checksum differs, run the program setup
|
||||
// If keys do not exist or the checksum differs, run the program setup
|
||||
if !keys_exist || checksum_differs {
|
||||
log::info!("Setup starting...");
|
||||
|
||||
// Run the program setup operation
|
||||
let rng = &mut thread_rng();
|
||||
let parameters = generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap();
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
// Start the timer
|
||||
let start = Instant::now();
|
||||
|
||||
// End the timer
|
||||
log::info!("Setup completed in {:?} milliseconds", start.elapsed().as_millis());
|
||||
// Run the program setup operation
|
||||
let rng = &mut thread_rng();
|
||||
let parameters = generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap();
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
|
||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut proving_key = vec![];
|
||||
parameters.write(&mut proving_key)?;
|
||||
ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?;
|
||||
// End the timer
|
||||
let end = start.elapsed().as_millis();
|
||||
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?;
|
||||
}
|
||||
// TODO (howardwu): Convert parameters to a 'proving key' struct for serialization.
|
||||
// Write the proving key file to the outputs directory
|
||||
let mut proving_key = vec![];
|
||||
parameters.write(&mut proving_key)?;
|
||||
ProvingKeyFile::new(&package_name).write_to(&path, &proving_key)?;
|
||||
log::info!("Saving proving key ({:?})", path);
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
||||
let parameters = Parameters::<Bls12_377>::read(proving_key.as_slice(), true)?;
|
||||
// Write the verification key file to the outputs directory
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
VerificationKeyFile::new(&package_name).write_to(&path, &verification_key)?;
|
||||
log::info!("Saving verification key ({:?})", path);
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
{
|
||||
// Load the stored verification key from the outputs directory
|
||||
let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Convert the prepared_verifying_key to a buffer
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
|
||||
// Check that the constructed prepared verification key matches the stored verification key
|
||||
let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect();
|
||||
for (a, b) in compare {
|
||||
if a != b {
|
||||
return Err(VerificationKeyFileError::IncorrectVerificationKey.into());
|
||||
// Output the setup time
|
||||
log::info!("Setup completed in {:?} milliseconds", end);
|
||||
} else {
|
||||
log::info!("Setup complete");
|
||||
}
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let proving_key = ProvingKeyFile::new(&package_name).read_from(&path)?;
|
||||
let parameters = Parameters::<Bls12_377>::read(proving_key.as_slice(), true)?;
|
||||
|
||||
// Read the proving key file from the outputs directory
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶meters.vk);
|
||||
{
|
||||
// Load the stored verification key from the outputs directory
|
||||
let stored_vk = VerificationKeyFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Convert the prepared_verifying_key to a buffer
|
||||
let mut verification_key = vec![];
|
||||
prepared_verifying_key.write(&mut verification_key)?;
|
||||
|
||||
// Check that the constructed prepared verification key matches the stored verification key
|
||||
let compare: Vec<(u8, u8)> = verification_key.into_iter().zip(stored_vk.into_iter()).collect();
|
||||
for (a, b) in compare {
|
||||
if a != b {
|
||||
return Err(VerificationKeyFileError::IncorrectVerificationKey.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Program setup complete");
|
||||
|
||||
Ok((program, parameters, prepared_verifying_key))
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Completed program setup");
|
||||
|
||||
Ok((program, parameters, prepared_verifying_key))
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
use crate::{cli::*, cli_types::*, commands::BuildCommand, errors::CLIError, files::Manifest};
|
||||
use crate::{
|
||||
cli::*,
|
||||
cli_types::*,
|
||||
commands::BuildCommand,
|
||||
directories::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, RunError},
|
||||
files::{Manifest, MAIN_FILE_NAME},
|
||||
};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
@ -24,14 +31,26 @@ impl CLI for UnloadCommand {
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
|
||||
let (_program, _checksum_differs) = BuildCommand::output(options)?;
|
||||
|
||||
// Get the package name
|
||||
let path = current_dir()?;
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
log::info!("Unimplemented - `leo deploy`");
|
||||
match BuildCommand::output(options)? {
|
||||
Some((_program, _checksum_differs)) => {
|
||||
// Get the package name
|
||||
let _package_name = Manifest::try_from(&path)?.get_package_name();
|
||||
|
||||
Ok(())
|
||||
log::info!("Unimplemented - `leo load`");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let mut main_file_path = path.clone();
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
Err(CLIError::RunError(RunError::MainFileDoesNotExist(
|
||||
main_file_path.into_os_string(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
leo/directories/imports.rs
Normal file
33
leo/directories/imports.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use crate::errors::ImportsDirectoryError;
|
||||
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
||||
|
||||
pub struct ImportsDirectory;
|
||||
|
||||
impl ImportsDirectory {
|
||||
/// Creates a directory at the provided path with the default directory name.
|
||||
pub fn create(path: &PathBuf) -> Result<(), ImportsDirectoryError> {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(IMPORTS_DIRECTORY_NAME));
|
||||
}
|
||||
|
||||
fs::create_dir_all(&path).map_err(ImportsDirectoryError::Creating)
|
||||
}
|
||||
|
||||
/// Removes the directory at the provided path.
|
||||
pub fn remove(path: &PathBuf) -> Result<(), ImportsDirectoryError> {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(IMPORTS_DIRECTORY_NAME));
|
||||
}
|
||||
|
||||
if path.exists() {
|
||||
fs::remove_dir_all(&path).map_err(ImportsDirectoryError::Removing)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
pub mod imports;
|
||||
pub use self::imports::*;
|
||||
|
||||
pub mod inputs;
|
||||
pub use self::inputs::*;
|
||||
|
||||
|
@ -6,7 +6,7 @@ pub enum CLIError {
|
||||
BuildError(BuildError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
BytesFileError(BytesFileError),
|
||||
BytesFileError(ZipFileError),
|
||||
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
@ -26,6 +26,9 @@ pub enum CLIError {
|
||||
#[error("{}", _0)]
|
||||
InputsFileError(InputsFileError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
LibFileError(LibFileError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
MainFileError(MainFileError),
|
||||
|
||||
@ -57,8 +60,8 @@ pub enum CLIError {
|
||||
VerificationKeyFileError(VerificationKeyFileError),
|
||||
}
|
||||
|
||||
impl From<BytesFileError> for CLIError {
|
||||
fn from(error: BytesFileError) -> Self {
|
||||
impl From<ZipFileError> for CLIError {
|
||||
fn from(error: ZipFileError) -> Self {
|
||||
log::error!("{}\n", error);
|
||||
CLIError::BytesFileError(error)
|
||||
}
|
||||
@ -106,6 +109,13 @@ impl From<InputsFileError> for CLIError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LibFileError> for CLIError {
|
||||
fn from(error: LibFileError) -> Self {
|
||||
log::error!("{}\n", error);
|
||||
CLIError::LibFileError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MainFileError> for CLIError {
|
||||
fn from(error: MainFileError) -> Self {
|
||||
log::error!("{}\n", error);
|
||||
|
28
leo/errors/directory/imports.rs
Normal file
28
leo/errors/directory/imports.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use std::{ffi::OsString, fs::FileType, io};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ImportsDirectoryError {
|
||||
#[error("creating: {}", _0)]
|
||||
Creating(io::Error),
|
||||
|
||||
#[error("file entry getting: {}", _0)]
|
||||
GettingFileEntry(io::Error),
|
||||
|
||||
#[error("file {:?} extension getting", _0)]
|
||||
GettingFileExtension(OsString),
|
||||
|
||||
#[error("file {:?} type getting: {}", _0, _1)]
|
||||
GettingFileType(OsString, io::Error),
|
||||
|
||||
#[error("invalid file {:?} extension: {:?}", _0, _1)]
|
||||
InvalidFileExtension(OsString, OsString),
|
||||
|
||||
#[error("invalid file {:?} type: {:?}", _0, _1)]
|
||||
InvalidFileType(OsString, FileType),
|
||||
|
||||
#[error("reading: {}", _0)]
|
||||
Reading(io::Error),
|
||||
|
||||
#[error("removing: {}", _0)]
|
||||
Removing(io::Error),
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
pub mod imports;
|
||||
pub use self::imports::*;
|
||||
|
||||
pub mod inputs;
|
||||
pub use self::inputs::*;
|
||||
|
||||
|
@ -11,6 +11,9 @@ pub enum ChecksumFileError {
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("Cannot remove the provided file - {:?}", _0)]
|
||||
FileRemovalError(PathBuf),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
19
leo/errors/files/lib.rs
Normal file
19
leo/errors/files/lib.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LibFileError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
|
||||
#[error("creating: {}", _0)]
|
||||
Creating(io::Error),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for LibFileError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
LibFileError::Crate("std::io", format!("{}", error))
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
pub mod bytes;
|
||||
pub use self::bytes::*;
|
||||
pub mod zip;
|
||||
pub use self::zip::*;
|
||||
|
||||
pub mod checksum;
|
||||
pub use self::checksum::*;
|
||||
@ -10,6 +10,9 @@ pub use self::gitignore::*;
|
||||
pub mod inputs;
|
||||
pub use self::inputs::*;
|
||||
|
||||
pub mod lib;
|
||||
pub use self::lib::*;
|
||||
|
||||
pub mod main;
|
||||
pub use self::main::*;
|
||||
|
||||
|
@ -11,6 +11,9 @@ pub enum ProofFileError {
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("Cannot remove the provided file - {:?}", _0)]
|
||||
FileRemovalError(PathBuf),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ pub enum ProvingKeyFileError {
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("Cannot remove the provided file - {:?}", _0)]
|
||||
FileRemovalError(PathBuf),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ pub enum VerificationKeyFileError {
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("Cannot remove the provided file - {:?}", _0)]
|
||||
FileRemovalError(PathBuf),
|
||||
|
||||
#[error("Verification key file was corrupted")]
|
||||
IncorrectVerificationKey,
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
use std::{io, path::PathBuf};
|
||||
use walkdir::Error as WalkDirError;
|
||||
use zip::result::ZipError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BytesFileError {
|
||||
pub enum ZipFileError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
|
||||
@ -13,10 +15,16 @@ pub enum BytesFileError {
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
|
||||
#[error("{}", _0)]
|
||||
WalkDirError(#[from] WalkDirError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ZipError(#[from] ZipError),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for BytesFileError {
|
||||
impl From<std::io::Error> for ZipFileError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
BytesFileError::Crate("std::io", format!("{}", error))
|
||||
ZipFileError::Crate("std::io", format!("{}", error))
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
//! The program bytes file.
|
||||
|
||||
use crate::{directories::outputs::OUTPUTS_DIRECTORY_NAME, errors::BytesFileError};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
pub static BYTES_FILE_EXTENSION: &str = ".bytes";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BytesFile {
|
||||
pub package_name: String,
|
||||
}
|
||||
|
||||
impl BytesFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &PathBuf) -> bool {
|
||||
let path = self.setup_file_path(path);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Reads the program bytes from the given file path if it exists.
|
||||
pub fn read_from(&self, path: &PathBuf) -> Result<Vec<u8>, BytesFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
Ok(fs::read(&path).map_err(|_| BytesFileError::FileReadError(path.clone()))?)
|
||||
}
|
||||
|
||||
/// Writes the given program bytes to a file.
|
||||
pub fn write_to(&self, path: &PathBuf, bytes: Vec<u8>) -> Result<(), BytesFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(bytes.as_slice())?;
|
||||
|
||||
log::info!("program bytes stored to {:?}", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(format!("{}{}", self.package_name, BYTES_FILE_EXTENSION)));
|
||||
}
|
||||
path
|
||||
}
|
||||
}
|
@ -42,11 +42,21 @@ impl ChecksumFile {
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(checksum.as_bytes())?;
|
||||
|
||||
log::info!("Checksum stored to {:?}", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the checksum at the given path if it exists. Returns `true` on success,
|
||||
/// `false` if the file doesn't exist, and `Error` if the file system fails during operation.
|
||||
pub fn remove(&self, path: &PathBuf) -> Result<bool, ChecksumFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
fs::remove_file(&path).map_err(|_| ChecksumFileError::FileRemovalError(path.clone()))?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
|
56
leo/files/lib.rs
Normal file
56
leo/files/lib.rs
Normal file
@ -0,0 +1,56 @@
|
||||
//! The `lib.leo` file.
|
||||
|
||||
use crate::{directories::source::SOURCE_DIRECTORY_NAME, errors::LibFileError};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{fs::File, io::Write, path::PathBuf};
|
||||
|
||||
pub static LIB_FILE_NAME: &str = "lib.leo";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LibFile {
|
||||
pub package_name: String,
|
||||
}
|
||||
|
||||
impl LibFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(path: &PathBuf) -> bool {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(LIB_FILE_NAME));
|
||||
}
|
||||
path.exists()
|
||||
}
|
||||
|
||||
pub fn write_to(self, path: &PathBuf) -> Result<(), LibFileError> {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(SOURCE_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(SOURCE_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(LIB_FILE_NAME));
|
||||
}
|
||||
|
||||
let mut file = File::create(&path)?;
|
||||
Ok(file.write_all(self.template().as_bytes())?)
|
||||
}
|
||||
|
||||
fn template(&self) -> String {
|
||||
format!(
|
||||
r#"// The '{}' library circuit.
|
||||
circuit Foo {{
|
||||
a: field
|
||||
}}
|
||||
"#,
|
||||
self.package_name
|
||||
)
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
pub mod bytes;
|
||||
pub use self::bytes::*;
|
||||
pub mod zip;
|
||||
pub use self::zip::*;
|
||||
|
||||
pub mod checksum;
|
||||
pub use self::checksum::*;
|
||||
@ -10,6 +10,9 @@ pub use self::inputs::*;
|
||||
pub mod gitignore;
|
||||
pub use self::gitignore::*;
|
||||
|
||||
pub mod lib;
|
||||
pub use self::lib::*;
|
||||
|
||||
pub mod main;
|
||||
pub use self::main::*;
|
||||
|
||||
|
@ -43,11 +43,23 @@ impl ProofFile {
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(proof)?;
|
||||
|
||||
log::info!("Proof stored to {:?}", path);
|
||||
log::info!("Proof stored ({:?})", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the proof at the given path if it exists. Returns `true` on success,
|
||||
/// `false` if the file doesn't exist, and `Error` if the file system fails during operation.
|
||||
pub fn remove(&self, path: &PathBuf) -> Result<bool, ProofFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
fs::remove_file(&path).map_err(|_| ProofFileError::FileRemovalError(path.clone()))?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
|
@ -42,11 +42,21 @@ impl ProvingKeyFile {
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(proving_key)?;
|
||||
|
||||
log::info!("Proving key stored to {:?}", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the proving key at the given path if it exists. Returns `true` on success,
|
||||
/// `false` if the file doesn't exist, and `Error` if the file system fails during operation.
|
||||
pub fn remove(&self, path: &PathBuf) -> Result<bool, ProvingKeyFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
fs::remove_file(&path).map_err(|_| ProvingKeyFileError::FileRemovalError(path.clone()))?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
|
@ -42,11 +42,21 @@ impl VerificationKeyFile {
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(verification_key)?;
|
||||
|
||||
log::info!("Verification key stored to {:?}", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the verification key at the given path if it exists. Returns `true` on success,
|
||||
/// `false` if the file doesn't exist, and `Error` if the file system fails during operation.
|
||||
pub fn remove(&self, path: &PathBuf) -> Result<bool, VerificationKeyFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
fs::remove_file(&path).map_err(|_| VerificationKeyFileError::FileRemovalError(path.clone()))?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
|
137
leo/files/zip.rs
Normal file
137
leo/files/zip.rs
Normal file
@ -0,0 +1,137 @@
|
||||
//! The program package zip file.
|
||||
|
||||
use crate::{
|
||||
directories::{IMPORTS_DIRECTORY_NAME, INPUTS_DIRECTORY_NAME, OUTPUTS_DIRECTORY_NAME},
|
||||
errors::ZipFileError,
|
||||
files::{
|
||||
CHECKSUM_FILE_EXTENSION,
|
||||
INPUTS_FILE_EXTENSION,
|
||||
PROOF_FILE_EXTENSION,
|
||||
PROVING_KEY_FILE_EXTENSION,
|
||||
VERIFICATION_KEY_FILE_EXTENSION,
|
||||
},
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use walkdir::WalkDir;
|
||||
use zip::write::{FileOptions, ZipWriter};
|
||||
|
||||
pub static ZIP_FILE_EXTENSION: &str = ".zip";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ZipFile {
|
||||
pub package_name: String,
|
||||
}
|
||||
|
||||
impl ZipFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &PathBuf) -> bool {
|
||||
let path = self.setup_file_path(path);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
// /// Reads the program bytes from the given file path if it exists.
|
||||
// pub fn read_from(&self, path: &PathBuf) -> Result<Vec<u8>, ZipFileError> {
|
||||
// let path = self.setup_file_path(path);
|
||||
//
|
||||
// Ok(fs::read(&path).map_err(|_| ZipFileError::FileReadError(path.clone()))?)
|
||||
// }
|
||||
|
||||
/// Writes the current package contents to a zip file.
|
||||
pub fn write(&self, src_dir: &PathBuf) -> Result<(), ZipFileError> {
|
||||
// Build walkdir iterator from current package
|
||||
let walkdir = WalkDir::new(src_dir.clone());
|
||||
|
||||
// Create zip file
|
||||
let path = self.setup_file_path(src_dir);
|
||||
|
||||
let file = &mut File::create(&path)?;
|
||||
let mut zip = ZipWriter::new(file);
|
||||
let options = FileOptions::default()
|
||||
.compression_method(zip::CompressionMethod::Stored)
|
||||
.unix_permissions(0o755);
|
||||
|
||||
// Walk through files in directory and write desired ones to the zip file
|
||||
let mut buffer = Vec::new();
|
||||
for entry in walkdir.into_iter().filter_map(|e| e.ok()) {
|
||||
let path = entry.path();
|
||||
let name = path.strip_prefix(src_dir.as_path()).unwrap();
|
||||
|
||||
// filter excluded paths
|
||||
if is_excluded(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// write file or directory
|
||||
if path.is_file() {
|
||||
log::info!("\tadding file {:?} as {:?}", path, name);
|
||||
zip.start_file_from_path(name, options)?;
|
||||
let mut f = File::open(path)?;
|
||||
|
||||
f.read_to_end(&mut buffer)?;
|
||||
zip.write_all(&*buffer)?;
|
||||
buffer.clear();
|
||||
} else if name.as_os_str().len() != 0 {
|
||||
// Only if not root Avoids path spec / warning
|
||||
// and mapname conversion failed error on unzip
|
||||
log::info!("\tadding dir {:?} as {:?}", path, name);
|
||||
zip.add_directory_from_path(name, options)?;
|
||||
}
|
||||
}
|
||||
|
||||
zip.finish()?;
|
||||
|
||||
log::info!("Package zip file created successfully {:?}", path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(format!("{}{}", self.package_name, ZIP_FILE_EXTENSION)));
|
||||
}
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
fn is_excluded(path: &Path) -> bool {
|
||||
// excluded directories: `inputs`, `outputs`, `imports`
|
||||
if path.ends_with(INPUTS_DIRECTORY_NAME.trim_end_matches("/"))
|
||||
| path.ends_with(OUTPUTS_DIRECTORY_NAME.trim_end_matches("/"))
|
||||
| path.ends_with(IMPORTS_DIRECTORY_NAME.trim_end_matches("/"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// excluded extensions: `.in`, `.bytes`, `lpk`, `lvk`, `.proof`, `.sum`
|
||||
path.extension()
|
||||
.map(|ext| {
|
||||
if ext.eq(INPUTS_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(ZIP_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(PROVING_KEY_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(VERIFICATION_KEY_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(PROOF_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(CHECKSUM_FILE_EXTENSION.trim_start_matches("."))
|
||||
| ext.eq(ZIP_FILE_EXTENSION.trim_start_matches("."))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
@ -3,33 +3,18 @@ use std::io::Write;
|
||||
|
||||
const LEVEL_NAME_LENGTH: usize = 10;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn level_string(level: log::Level) -> colored::ColoredString {
|
||||
match level {
|
||||
log::Level::Error => "ERROR".bold().red(),
|
||||
log::Level::Warn => "WARN".bold().yellow(),
|
||||
log::Level::Info => "INFO".bold().blue(),
|
||||
log::Level::Debug => "DEBUG".bold().magenta(),
|
||||
log::Level::Trace => "TRACE".bold(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn colored_string(level: log::Level, message: &str) -> colored::ColoredString {
|
||||
match level {
|
||||
log::Level::Error => message.bold().red(),
|
||||
log::Level::Warn => message.bold().yellow(),
|
||||
log::Level::Info => message.bold().blue(),
|
||||
log::Level::Info => message.bold().cyan(),
|
||||
log::Level::Debug => message.bold().magenta(),
|
||||
log::Level::Trace => message.bold(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize logger with custom format and verbosity.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `verbosity` - Verbosity level. 0 for `Warn`, 1 for `Info`, 2 for `Debug`, more for `Trace`
|
||||
pub fn init_logger(app_name: &'static str, verbosity: usize) {
|
||||
env_logger::builder()
|
||||
.filter_level(match verbosity {
|
||||
@ -46,8 +31,7 @@ pub fn init_logger(app_name: &'static str, verbosity: usize) {
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"{:>5}{:>5} {}",
|
||||
level_string(record.level()),
|
||||
"{:>5} {}",
|
||||
colored_string(record.level(), app_name),
|
||||
record.args().to_string().replace("\n", &padding)
|
||||
)
|
||||
|
63
leo/main.rs
63
leo/main.rs
@ -1,11 +1,9 @@
|
||||
use leo::{cli::*, commands::*, errors::CLIError, logger};
|
||||
use leo::{cli::*, commands::*, errors::CLIError};
|
||||
|
||||
use clap::{App, AppSettings};
|
||||
use clap::{App, AppSettings, Arg};
|
||||
|
||||
#[cfg_attr(tarpaulin, skip)]
|
||||
fn main() -> Result<(), CLIError> {
|
||||
logger::init_logger("leo", 1);
|
||||
|
||||
let arguments = App::new("leo")
|
||||
.version("v0.1.0")
|
||||
.about("Leo compiler and package manager")
|
||||
@ -16,46 +14,41 @@ fn main() -> Result<(), CLIError> {
|
||||
AppSettings::DisableVersion,
|
||||
AppSettings::SubcommandRequiredElseHelp,
|
||||
])
|
||||
.args(&[Arg::with_name("debug")
|
||||
.short("d")
|
||||
.long("debug")
|
||||
.help("Enables debugging mode")
|
||||
.global(true)])
|
||||
.subcommands(vec![
|
||||
NewCommand::new().display_order(0),
|
||||
InitCommand::new().display_order(1),
|
||||
BuildCommand::new().display_order(2),
|
||||
LoadCommand::new().display_order(3),
|
||||
UnloadCommand::new().display_order(4),
|
||||
SetupCommand::new().display_order(5),
|
||||
ProveCommand::new().display_order(6),
|
||||
RunCommand::new().display_order(7),
|
||||
PublishCommand::new().display_order(8),
|
||||
DeployCommand::new().display_order(9),
|
||||
TestCommand::new().display_order(10),
|
||||
TestCommand::new().display_order(3),
|
||||
LoadCommand::new().display_order(4),
|
||||
UnloadCommand::new().display_order(5),
|
||||
SetupCommand::new().display_order(6),
|
||||
ProveCommand::new().display_order(7),
|
||||
RunCommand::new().display_order(8),
|
||||
PublishCommand::new().display_order(9),
|
||||
DeployCommand::new().display_order(10),
|
||||
CleanCommand::new().display_order(11),
|
||||
])
|
||||
.set_term_width(0)
|
||||
.get_matches();
|
||||
|
||||
match arguments.subcommand() {
|
||||
("new", Some(arguments)) => NewCommand::output(NewCommand::parse(arguments)?),
|
||||
("init", Some(arguments)) => InitCommand::output(InitCommand::parse(arguments)?),
|
||||
("build", Some(arguments)) => {
|
||||
BuildCommand::output(BuildCommand::parse(arguments)?)?;
|
||||
Ok(())
|
||||
}
|
||||
("load", Some(arguments)) => LoadCommand::output(LoadCommand::parse(arguments)?),
|
||||
("unload", Some(arguments)) => UnloadCommand::output(UnloadCommand::parse(arguments)?),
|
||||
("setup", Some(arguments)) => {
|
||||
SetupCommand::output(SetupCommand::parse(arguments)?)?;
|
||||
Ok(())
|
||||
}
|
||||
("prove", Some(arguments)) => {
|
||||
ProveCommand::output(ProveCommand::parse(arguments)?)?;
|
||||
Ok(())
|
||||
}
|
||||
("run", Some(arguments)) => RunCommand::output(RunCommand::parse(arguments)?),
|
||||
("publish", Some(arguments)) => PublishCommand::output(PublishCommand::parse(arguments)?),
|
||||
("deploy", Some(arguments)) => DeployCommand::output(DeployCommand::parse(arguments)?),
|
||||
("test", Some(arguments)) => {
|
||||
TestCommand::output(TestCommand::parse(arguments)?)?;
|
||||
Ok(())
|
||||
}
|
||||
("new", Some(arguments)) => NewCommand::process(arguments),
|
||||
("init", Some(arguments)) => InitCommand::process(arguments),
|
||||
("build", Some(arguments)) => BuildCommand::process(arguments),
|
||||
("test", Some(arguments)) => TestCommand::process(arguments),
|
||||
("load", Some(arguments)) => LoadCommand::process(arguments),
|
||||
("unload", Some(arguments)) => UnloadCommand::process(arguments),
|
||||
("setup", Some(arguments)) => SetupCommand::process(arguments),
|
||||
("prove", Some(arguments)) => ProveCommand::process(arguments),
|
||||
("run", Some(arguments)) => RunCommand::process(arguments),
|
||||
("publish", Some(arguments)) => PublishCommand::process(arguments),
|
||||
("deploy", Some(arguments)) => DeployCommand::process(arguments),
|
||||
("clean", Some(arguments)) => CleanCommand::process(arguments),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ edition = "2018"
|
||||
leo-ast = { path = "../ast", version = "0.1.0" }
|
||||
leo-inputs = { path = "../leo-inputs", version = "0.1.0" }
|
||||
|
||||
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0", default-features = false }
|
||||
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0", default-features = false }
|
||||
snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
|
||||
|
||||
pest = { version = "2.0" }
|
||||
serde = { version = "1.0" }
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! The import type for a Leo program.
|
||||
|
||||
use crate::{ImportSymbol, Span};
|
||||
use crate::{Package, Span};
|
||||
use leo_ast::imports::Import as AstImport;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -8,20 +8,14 @@ use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Import {
|
||||
pub path_string: String,
|
||||
pub symbols: Vec<ImportSymbol>,
|
||||
pub package: Package,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<AstImport<'ast>> for Import {
|
||||
fn from(import: AstImport<'ast>) -> Self {
|
||||
Import {
|
||||
path_string: import.source.value,
|
||||
symbols: import
|
||||
.symbols
|
||||
.into_iter()
|
||||
.map(|symbol| ImportSymbol::from(symbol))
|
||||
.collect(),
|
||||
package: Package::from(import.package),
|
||||
span: Span::from(import.span),
|
||||
}
|
||||
}
|
||||
@ -29,28 +23,17 @@ impl<'ast> From<AstImport<'ast>> for Import {
|
||||
|
||||
impl Import {
|
||||
pub fn path_string_full(&self) -> String {
|
||||
format!("{}.leo", self.path_string)
|
||||
format!("{}.leo", self.package.name)
|
||||
}
|
||||
|
||||
// from "./import" import *;
|
||||
pub fn is_star(&self) -> bool {
|
||||
self.symbols.is_empty()
|
||||
// self.symbols.is_empty()
|
||||
false
|
||||
}
|
||||
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "from {} import ", self.path_string)?;
|
||||
if self.symbols.is_empty() {
|
||||
write!(f, "*")
|
||||
} else {
|
||||
write!(f, "{{\n")?;
|
||||
for (i, symbol) in self.symbols.iter().enumerate() {
|
||||
write!(f, "{}", symbol)?;
|
||||
if i < self.symbols.len() - 1 {
|
||||
write!(f, ",\n")?;
|
||||
}
|
||||
}
|
||||
write!(f, "\n}}")
|
||||
}
|
||||
write!(f, "import {};", self.package)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ impl<'ast> From<AstImportSymbol<'ast>> for ImportSymbol {
|
||||
impl fmt::Display for ImportSymbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.alias.is_some() {
|
||||
write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||
} else {
|
||||
write!(f, "\t{}", self.symbol)
|
||||
write!(f, "{}", self.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,3 +3,9 @@ pub use import::*;
|
||||
|
||||
pub mod import_symbol;
|
||||
pub use import_symbol::*;
|
||||
|
||||
pub mod package;
|
||||
pub use package::*;
|
||||
|
||||
pub mod package_access;
|
||||
pub use package_access::*;
|
||||
|
40
types/src/imports/package.rs
Normal file
40
types/src/imports/package.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use crate::{common::Identifier, PackageAccess, Span};
|
||||
use leo_ast::imports::Package as AstPackage;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Package {
|
||||
pub name: Identifier,
|
||||
pub access: PackageAccess,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<AstPackage<'ast>> for Package {
|
||||
fn from(package: AstPackage<'ast>) -> Self {
|
||||
Package {
|
||||
name: Identifier::from(package.name),
|
||||
access: PackageAccess::from(package.access),
|
||||
span: Span::from(package.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Package {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.{}", self.name, self.access)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Package {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Package {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
58
types/src/imports/package_access.rs
Normal file
58
types/src/imports/package_access.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use crate::{ImportSymbol, Package, Span};
|
||||
use leo_ast::imports::PackageAccess as AstPackageAccess;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub enum PackageAccess {
|
||||
Star(Span),
|
||||
SubPackage(Box<Package>),
|
||||
Symbol(ImportSymbol),
|
||||
Multiple(Vec<PackageAccess>),
|
||||
}
|
||||
|
||||
impl<'ast> From<AstPackageAccess<'ast>> for PackageAccess {
|
||||
fn from(access: AstPackageAccess<'ast>) -> Self {
|
||||
match access {
|
||||
AstPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)),
|
||||
AstPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))),
|
||||
AstPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)),
|
||||
AstPackageAccess::Multiple(accesses) => {
|
||||
PackageAccess::Multiple(accesses.into_iter().map(|access| PackageAccess::from(access)).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PackageAccess {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PackageAccess::Star(ref _span) => write!(f, ".*"),
|
||||
PackageAccess::SubPackage(ref package) => write!(f, ".{}", package),
|
||||
PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol),
|
||||
PackageAccess::Multiple(ref accesses) => {
|
||||
write!(f, ".(")?;
|
||||
for (i, access) in accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < accesses.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PackageAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PackageAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user