merge master

This commit is contained in:
collin 2020-06-08 10:49:31 -07:00
commit e10a1e1be0
406 changed files with 11263 additions and 5534 deletions

2
.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["-C", "target-cpu=native"]

3
.gitignore vendored
View File

@ -1,7 +1,4 @@
/target
**.idea/
Leo.toml
src/
inputs/
outputs/
*.DS_Store

317
Cargo.lock generated
View File

@ -99,13 +99,14 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2"
version = "0.7.1"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b77e29dbd0115e43938be2d5128ecf81c0353e00acaa65339a1242586951d9"
checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330"
dependencies = [
"byte-tools 0.2.0",
"byte-tools",
"crypto-mac",
"digest 0.7.6",
"digest",
"opaque-debug",
]
[[package]]
@ -115,9 +116,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools 0.3.1",
"byte-tools",
"byteorder",
"generic-array 0.12.3",
"generic-array",
]
[[package]]
@ -126,15 +127,9 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools 0.3.1",
"byte-tools",
]
[[package]]
name = "byte-tools"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -208,12 +203,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crossbeam-deque"
version = "0.7.3"
@ -263,32 +252,53 @@ dependencies = [
[[package]]
name = "crypto-mac"
version = "0.5.2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958"
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
dependencies = [
"constant_time_eq",
"generic-array 0.9.0",
"generic-array",
"subtle",
]
[[package]]
name = "curl"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "762e34611d2d5233a506a79072be944fddd057db2f18e04c0d6fa79e3fd466fd"
dependencies = [
"curl-sys",
"libc",
"openssl-probe",
"openssl-sys",
"schannel",
"socket2",
"winapi",
]
[[package]]
name = "curl-sys"
version = "0.4.31+curl-7.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcd62757cc4f5ab9404bc6ca9f0ae447e729a1403948ce5106bd588ceac6a3b0"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
"winapi",
]
[[package]]
name = "derivative"
version = "1.0.4"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135"
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "digest"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
dependencies = [
"generic-array 0.9.0",
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
]
[[package]]
@ -297,7 +307,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.3",
"generic-array",
]
[[package]]
@ -363,15 +373,6 @@ version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
[[package]]
name = "generic-array"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.12.3"
@ -398,15 +399,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.8"
@ -448,9 +440,9 @@ checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
[[package]]
name = "jsonrpc-core"
version = "14.1.0"
version = "14.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25525f6002338fb4debb5167a89a0b47f727a5a48418417545ad3429758b7fec"
checksum = "a0747307121ffb9703afd93afbd0fb4f854c38fb873f2c8b90e0e902f27c7b62"
dependencies = [
"futures",
"log",
@ -478,7 +470,6 @@ dependencies = [
"clap",
"colored",
"env_logger",
"failure",
"from-pest",
"leo-compiler",
"leo-inputs",
@ -493,36 +484,31 @@ dependencies = [
"snarkos-gadgets",
"snarkos-models",
"snarkos-utilities",
"structopt",
"thiserror",
"toml",
]
[[package]]
name = "leo-benchmark"
name = "leo-ast"
version = "0.1.0"
dependencies = [
"from-pest",
"leo-compiler",
"rand",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"lazy_static",
"log",
"pest",
"pest-ast",
"pest_derive",
"thiserror",
]
[[package]]
name = "leo-compiler"
version = "0.1.0"
dependencies = [
"failure",
"from-pest",
"hex",
"lazy_static",
"leo-ast",
"leo-types",
"log",
"pest",
"pest-ast",
"pest_derive",
"rand",
"sha2",
"snarkos-algorithms",
@ -530,6 +516,8 @@ dependencies = [
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"snarkos-utilities",
"thiserror",
]
[[package]]
@ -548,6 +536,16 @@ dependencies = [
"snarkos-models",
]
[[package]]
name = "leo-types"
version = "0.1.0"
dependencies = [
"leo-ast",
"snarkos-errors",
"snarkos-models",
"thiserror",
]
[[package]]
name = "libc"
version = "0.2.67"
@ -576,6 +574,18 @@ dependencies = [
"libc",
]
[[package]]
name = "libz-sys"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "log"
version = "0.4.8"
@ -638,6 +648,25 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openssl-probe"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7410fef80af8ac071d4f63755c0ab89ac3df0fd1ea91f1d1f37cf5cec4395990"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
@ -700,38 +729,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 = "ppv-lite86"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
[[package]]
name = "proc-macro-error"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
dependencies = [
"proc-macro-error-attr",
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
dependencies = [
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
"syn-mid",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
@ -848,6 +857,12 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "regex"
version = "1.3.4"
@ -894,6 +909,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
"winapi",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -938,7 +963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer",
"digest 0.8.1",
"digest",
"fake-simd",
"opaque-debug",
]
@ -950,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0"
dependencies = [
"block-buffer",
"digest 0.8.1",
"digest",
"fake-simd",
"opaque-debug",
]
@ -982,8 +1007,9 @@ version = "0.8.0"
dependencies = [
"blake2",
"derivative",
"digest 0.7.6",
"digest",
"rand",
"rand_chacha",
"rayon",
"sha2",
"smallvec",
@ -1009,10 +1035,11 @@ name = "snarkos-errors"
version = "0.8.0"
dependencies = [
"bincode",
"failure",
"curl",
"hex",
"jsonrpc-core",
"rocksdb",
"thiserror",
]
[[package]]
@ -1020,7 +1047,7 @@ name = "snarkos-gadgets"
version = "0.8.0"
dependencies = [
"derivative",
"digest 0.7.6",
"digest",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
@ -1033,7 +1060,6 @@ name = "snarkos-models"
version = "0.8.0"
dependencies = [
"derivative",
"failure",
"rand",
"rand_xorshift",
"smallvec",
@ -1052,6 +1078,18 @@ dependencies = [
"rand",
]
[[package]]
name = "socket2"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "strsim"
version = "0.8.0"
@ -1059,28 +1097,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
version = "0.3.14"
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
]
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
name = "syn"
@ -1104,17 +1124,6 @@ dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "syn-mid"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
dependencies = [
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
]
[[package]]
name = "synstructure"
version = "0.12.3"
@ -1145,6 +1154,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d12a1dae4add0f0d568eebc7bf142f145ba1aa2544cafb195c76f0f409091b60"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f34e0c1caaa462fd840ec6b768946ea1e7842620d94fe29d5b847138f521269"
dependencies = [
"proc-macro2 1.0.9",
"quote 1.0.3",
"syn 1.0.16",
]
[[package]]
name = "thread_local"
version = "1.0.1"
@ -1175,12 +1204,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2"
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
[[package]]
name = "unicode-width"
version = "0.1.7"
@ -1199,6 +1222,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "vcpkg"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
[[package]]
name = "vec_map"
version = "0.8.1"

View File

@ -13,7 +13,7 @@ name = "leo"
path = "leo/main.rs"
[workspace]
members = [ "benchmark", "compiler", "leo-inputs" ]
members = [ "ast", "compiler", "types" ]
[dependencies]
leo-compiler = { path = "compiler", version = "0.1.0" }
@ -23,18 +23,17 @@ snarkos-algorithms = { path = "../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../snarkOS/errors", version = "0.8.0" }
snarkos-gadgets = { path = "../snarkOS/gadgets", version = "0.8.0" }
snarkos-models = { path = "../snarkOS/models", version = "0.8.0" }
snarkos-models = { path = "../snarkOS/models", version = "0.8.0" }
snarkos-utilities = { path = "../snarkOS/utilities", version = "0.8.0" }
clap = { version = "2.33.0" }
colored = { version = "1.9" }
env_logger = { version = "0.7" }
failure = { version = "0.1.5" }
from-pest = { version = "0.3.1" }
log = { version = "0.4" }
rand = { version = "0.7" }
rand_core = { version = "0.5.1" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
structopt = { version = "0.3.14" }
toml = { version = "0.5" }
thiserror = { version = "1.0" }

3
Leo.toml Normal file
View File

@ -0,0 +1,3 @@
[package]
name = "language"
version = "0.1.0"

332
README.md
View File

@ -1,41 +1,87 @@
# The Leo Language
* All code examples can be copied and pasted into `main.leo` directly and executed with cargo run
# The Leo Programming Language
* Programs should be formatted:
1. Import definitions
2. Struct definitions
2. Circuit definitions
3. Function definitions
### Integers:
Currently, all integers are parsed as u32.
You can choose to explicitly add the type or let the compiler interpret implicitly.
## Mutability
* All defined variables in Leo are immutable by default.
* Variables can be made mutable with the `mut` keyword.
```rust
function main() -> u32 {
let a : u32 = 1u32 + 1u32; // explicit type
let b = 1 - 1; // implicit type
let c = 2 * 2;
let d = 4 / 2;
let e = 2 ** 3;
function main() {
let a = 0u32;
//a = 1 <- Will fail
let mut b = 0u32;
b = 1; // <- Ok
}
```
## Booleans
Explicit types are optional.
```rust
function main() -> bool {
let a: bool = true || false;
let b = false && false;
let c = 1u32 == 1u32;
return a
}
```
### Field Elements:
Field elements must have the type added explicitly.
## Numbers
* The definition of a number must include an explict type.
* After assignment, you can choose to explicitly add the type or let the compiler interpret implicitly.
* Type casting is not supported.
* Comparators are not supported.
### Integers
Supported integer types: `u8`, `u16`, `u32`, `u64`, `u128`
```rust
function main() -> fe {
let f : fe = 21888242871839275222246405745257275088548364400416034343698204186575808495617fe;
let a = 1fe + 1fe;
let b = 1fe - 1fe;
let c = 2fe * 2fe;
let d = 4fe / 2fe;
return a
function main() -> u32 {
let a = 2u32; // explicit type
let a: u32 = 1 + 1; // explicit type
let b = a - 1; // implicit type
let c = b * 4;
let d = c / 2;
let e = d ** 3;
return e
}
```
### Operator Assignment Statements:
### Field Elements
```rust
function main() -> field {
let a = 1000field; // explicit type
let a: field = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // explicit type
let b = a + 1; // implicit type
let c = b - 1;
let d = c * 4;
let e = d / 2;
return e
}
```
### Affine Points
The set of affine points on the elliptic curve passed into the leo compiler forms a group.
Leo supports this set as a primitive data type.
```rust
function main() -> group {
let a = 1000group; // explicit type
let a = (21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617)group; // explicit type
let b = a + 0; // implicit type
let c = b - 0;
return c
}
```
### Operator Assignment Statements
```rust
function main() -> u32 {
let a = 10;
let mut a = 10;
a += 5;
a -= 10;
a *= 5;
@ -46,30 +92,18 @@ function main() -> u32 {
}
```
### Booleans:
```rust
function main() -> bool {
let a : bool = true || false;
let b = false && false;
let c = 1 == 1;
return a
}
```
### Arrays:
## Arrays
Leo supports static arrays with fixed length.
Array type must be explicitly stated
```rust
function main() -> u32[2] {
// initialize an integer array with integer values
let a : u32[3] = [1, 2, 3];
let mut a: u32[3] = [1, 2, 3];
// set a member to a value
// set a mutable member to a value
a[2] = 4;
// initialize an array of 4 values all equal to 42
let b = [42; 4];
let b = [42u8; 4];
// initialize an array of 5 values copying all elements of b using a spread
let c = [1, ...b];
@ -78,63 +112,42 @@ function main() -> u32[2] {
let d = c[1..3];
// initialize a field array
let e = [5fe; 2];
let e = [5field; 2];
// initialize a boolean array
let f = [true, false || true, true];
// return an array
return d
}
```
### Structs:
### Multidimensional Arrays
```rust
struct Point {
u32 x
u32 y
}
function main() -> u32 {
Point p = Point {x: 1, y: 0}
return p.x
}
```
```rust
struct Foo {
bool x
}
function main() -> Foo {
let f = Foo {x: true};
f.x = false;
return f
function main() -> u32[3][2] {
let m = [[0u32, 0u32], [0u32, 0u32]];
let m: u32[3][2] = [[0; 3]; 2];
return m
}
```
### Assert Equals:
This will enforce that the two values are equal in the constraint system.
## Conditionals
```rust
function main() {
assert_eq(45, 45);
assert_eq(2fe, 2fe);
assert_eq(true, true);
}
```
### Conditionals:
#### If Else Ternary Expression
### If Else Ternary Expression
```rust
function main() -> u32 {
let y = if 3==3 ? 1 : 5;
return y
}
```
#### If Else Conditional Statement
### If Else Conditional Statement
** **Experimental** **
The current constraint system is not optimized for statement branching. Please use the ternary expression above until this feature is stable.
```rust
function main(a: private bool, b: private bool) -> u32 {
let res = 0;
let mut res = 0u32;
if (a) {
res = 1;
} else if (b) {
@ -145,25 +158,26 @@ function main(a: private bool, b: private bool) -> u32 {
return res
}
```
#### For loop
### For loop
```rust
function main() -> fe {
let a = 1fe;
let mut a = 1field;
for i in 0..4 {
a = a + 1fe;
a = a + 1;
}
return a
}
```
### Functions:
## Functions
```rust
function test1(a : u32) -> u32 {
return a + 1
}
function test2(b: fe) -> fe {
return b * 2fe
function test2(b: fe) -> field {
return b * 2field
}
function test3(c: bool) -> bool {
@ -176,20 +190,20 @@ function main() -> u32 {
```
#### Function Scope:
### Function Scope
```rust
function foo() -> field {
// return myGlobal <- not allowed
return 42fe
return 42field
}
function main() -> field {
let myGlobal = 42fe;
let myGlobal = 42field;
return foo()
}
```
#### Multiple returns:
### Multiple returns
Functions can return tuples whose types are specified in the function signature.
```rust
function test() -> (u32, u32[2]) {
@ -198,26 +212,32 @@ function test() -> (u32, u32[2]) {
function main() -> u32[3] {
let (a, b) = test();
// a, u32[2] b = test() <- explicit type also works
// (a, u32[2] b) = test() <- explicit type also works
return [a, ...b]
}
```
#### Parameters:
Main function arguments are allocated as public or private variables in the program's constaint system.
### Main function inputs
Main function inputs are allocated as public or private variables in the program's constaint system.
```rust
function main(a: private fe) -> fe {
function main(a: private field) -> field {
return a
}
```
```rust
function main(a: public fe) -> fe {
function main(a: public field) -> field {
return a
}
```
Function parameters are passed by value.
Private by default. Below `a` is implicitly private.
```rust
function test(a: u32) {
function main(a: field) -> field {
return a
}
```
Function inputs are passed by value.
```rust
function test(mut a: u32) {
a = 0;
}
@ -229,17 +249,76 @@ function main() -> u32 {
}
```
### Imports:
## Circuits
Circuits in Leo are similar to classes in object oriented langauges. Circuits are defined above functions in a Leo program. Circuits can have one or more members.
Members can be defined as fields which hold primitive values
```rust
circuit Point {
x: u32
y: u32
}
function main() -> u32 {
let p = Point {x: 1, y: 0};
return p.x
}
```
Members can also be defined as functions.
```rust
circuit Circ {
function echo(x: u32) -> u32 {
return x
}
}
function main() -> u32 {
let c = Circ { };
return c.echo(1u32)
}
```
Circuit functions can be made static, enabling them to be called without instantiation.
```rust
circuit Circ {
static function echo(x: u32) -> u32 {
return x
}
}
function main() -> u32 {
return Circ::echo(1u32)
}
```
The `Self` keyword is supported in circuit functions.
```rust
circuit Circ {
b: bool
static function new() -> Self {
return Self { b: true }
}
}
function main() -> Circ {
let c = Circ::new();
return c.b
}
```
## Imports
Both struct and function imports are supported.
import all: `*`
import alias: `symbol as alias`
/simple_import.leo
`src/simple_import.leo`
```rust
struct Point {
u32 x
u32 y
circuit Point {
x: u32
y: u32
}
function test() -> (u32, u32[2]) {
@ -247,7 +326,7 @@ function test() -> (u32, u32[2]) {
}
```
/simple.leo
`src/simple.leo`
```rust
from "./simple_import" import {
Point as Foo,
@ -257,12 +336,50 @@ from "./simple_import" import {
// from "./simple_import" import *
function main() -> (u32[3]) {
let (a, b) = test();
let p = Foo { x: 1, y: 2};
let (a, b) = test();
return [a, ...b]
}
```
## Constraints
### Assert Equals
This will enforce that the two values are equal in the constraint system.
```rust
function main() {
assert_eq(45, 45);
assert_eq(2fe, 2fe);
assert_eq(true, true);
}
```
## Testing
Use the `test` keyword to add tests to a leo program. Tests must have 0 function inputs and 0 function returns.
```rust
function main(a: u32) -> u32 {
return a
}
test function expect_pass() {
let a = 1u32;
let res = main(a);
assert_eq!(res, 1u32);
}
test function expect_fail() {
assert_eq!(1u8, 0u8);
}
```
# Leo CLI
@ -283,7 +400,7 @@ This will create a new directory with a given package name. The new package will
- lib.leo # Your program library
- main.leo # Your program
- tests
- tests.leo # Your program tests
- test.leo # Your program tests
- Leo.toml # Your program manifest
```
@ -308,6 +425,12 @@ To execute unit tests on your program, run:
```
leo test
```
The results of test compilation and the constraint system will be printed:
```
INFO leo Running 2 tests
INFO leo test language::expect_pass compiled. Constraint system satisfied: true
ERROR leo test language::expect_fail errored: Assertion 1u8 == 0u8 failed
```
## Run
@ -377,6 +500,13 @@ To deploy your program to Aleo, run:
leo deploy
```
# Install
To install Leo from source, in the root directory of the repository, run:
```
cargo install --path .
```
## TODO
- Change `target` directory to some other directory to avoid collision.

14
ast/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "leo-ast"
version = "0.1.0"
authors = ["The Aleo Team <hello@aleo.org>"]
edition = "2018"
[dependencies]
from-pest = { version = "0.3.1" }
lazy_static = { version = "1.3.0" }
log = { version = "0.4" }
pest = { version = "2.0" }
pest-ast = { version = "0.3.3" }
pest_derive = { version = "2.0" }
thiserror = { version = "1.0" }

1
ast/README.md Normal file
View File

@ -0,0 +1 @@
# leo-ast

12
ast/src/access/access.rs Normal file
View File

@ -0,0 +1,12 @@
use crate::{access::*, ast::Rule};
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access))]
pub enum Access<'ast> {
Array(ArrayAccess<'ast>),
Call(CallAccess<'ast>),
Object(MemberAccess<'ast>),
StaticObject(StaticMemberAccess<'ast>),
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::RangeOrExpression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access_array))]
pub struct ArrayAccess<'ast> {
pub expression: RangeOrExpression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,20 @@
use crate::{access::{ArrayAccess, MemberAccess}, ast::Rule};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access_assignee))]
pub enum AssigneeAccess<'ast> {
Array(ArrayAccess<'ast>),
Member(MemberAccess<'ast>),
}
impl<'ast> fmt::Display for AssigneeAccess<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AssigneeAccess::Array(ref array) => write!(f, "[{}]", array.expression),
AssigneeAccess::Member(ref member) => write!(f, ".{}", member.identifier),
}
}
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access_call))]
pub struct CallAccess<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access_member))]
pub struct MemberAccess<'ast> {
pub identifier: Identifier<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

17
ast/src/access/mod.rs Normal file
View File

@ -0,0 +1,17 @@
pub mod access;
pub use access::*;
pub mod array_access;
pub use array_access::*;
pub mod assignee_access;
pub use assignee_access::*;
pub mod call_access;
pub use call_access::*;
pub mod member_access;
pub use member_access::*;
pub mod static_member_access;
pub use static_member_access::*;

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::access_static_member))]
pub struct StaticMemberAccess<'ast> {
pub identifier: Identifier<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

173
ast/src/ast.rs Normal file
View File

@ -0,0 +1,173 @@
//! Abstract syntax tree (ast) representation from leo.pest.
use crate::{
common::Identifier,
expressions::{
ArrayInlineExpression,
ArrayInitializerExpression,
CircuitInlineExpression,
Expression,
TernaryExpression,
NotExpression,
PostfixExpression
},
operations::{
BinaryOperation,
NotOperation,
},
values::Value,
};
use from_pest::{ConversionError, FromPest, Void};
use pest::{
error::Error,
iterators::{Pair, Pairs},
prec_climber::{Assoc, Operator, PrecClimber},
Parser, Span,
};
#[derive(Parser)]
#[grammar = "leo.pest"]
pub struct LanguageParser;
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
LanguageParser::parse(Rule::file, input)
}
pub(crate) fn span_into_string(span: Span) -> String {
span.as_str().to_string()
}
lazy_static! {
static ref PRECEDENCE_CLIMBER: PrecClimber<Rule> = precedence_climber();
}
// Expressions
fn precedence_climber() -> PrecClimber<Rule> {
PrecClimber::new(vec![
Operator::new(Rule::operation_or, Assoc::Left),
Operator::new(Rule::operation_and, Assoc::Left),
Operator::new(Rule::operation_eq, Assoc::Left)
| Operator::new(Rule::operation_ne, Assoc::Left),
Operator::new(Rule::operation_ge, Assoc::Left)
| Operator::new(Rule::operation_gt, Assoc::Left)
| Operator::new(Rule::operation_le, Assoc::Left)
| Operator::new(Rule::operation_lt, Assoc::Left),
Operator::new(Rule::operation_add, Assoc::Left)
| Operator::new(Rule::operation_sub, Assoc::Left),
Operator::new(Rule::operation_mul, Assoc::Left)
| Operator::new(Rule::operation_div, Assoc::Left),
Operator::new(Rule::operation_pow, Assoc::Left),
])
}
fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
Box::new(match pair.as_rule() {
Rule::expression_term => {
let clone = pair.clone();
let next = clone.into_inner().next().unwrap();
match next.as_rule() {
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
Rule::expression_array_inline => {
Expression::ArrayInline(
ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap()
)
},
Rule::expression_array_initializer => {
Expression::ArrayInitializer(
ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap()
)
},
Rule::expression_circuit_inline => {
Expression::CircuitInline(
CircuitInlineExpression::from_pest(&mut pair.into_inner()).unwrap(),
)
},
Rule::expression_conditional => {
Expression::Ternary(
TernaryExpression::from_pest(&mut pair.into_inner()).unwrap(),
)
},
Rule::expression_not => {
let span = next.as_span();
let mut inner = next.into_inner();
let operation = match inner.next().unwrap().as_rule() {
Rule::operation_not => NotOperation::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
rule => unreachable!("`expression_not` should yield `operation_pre_not`, found {:#?}", rule)
};
let expression = parse_term(inner.next().unwrap());
Expression::Not(NotExpression { operation, expression, span })
},
Rule::expression_postfix => {
Expression::Postfix(
PostfixExpression::from_pest(&mut pair.into_inner()).unwrap(),
)
}
Rule::expression_primitive => {
let next = next.into_inner().next().unwrap();
match next.as_rule() {
Rule::value => {
Expression::Value(
Value::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap()
)
},
Rule::identifier => Expression::Identifier(
Identifier::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
),
rule => unreachable!("`expression_primitive` should contain one of [`value`, `identifier`], found {:#?}", rule)
}
},
rule => unreachable!("`term` should contain one of ['value', 'identifier', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}", rule)
}
}
rule => unreachable!(
"`parse_expression_term` should be invoked on `Rule::expression_term`, found {:#?}",
rule
),
})
}
fn binary_expression<'ast>(
lhs: Box<Expression<'ast>>,
pair: Pair<'ast, Rule>,
rhs: Box<Expression<'ast>>,
) -> Box<Expression<'ast>> {
let (start, _) = lhs.span().clone().split();
let (_, end) = rhs.span().clone().split();
let span = start.span(&end);
Box::new(match pair.as_rule() {
Rule::operation_or => Expression::binary(BinaryOperation::Or, lhs, rhs, span),
Rule::operation_and => Expression::binary(BinaryOperation::And, lhs, rhs, span),
Rule::operation_eq => Expression::binary(BinaryOperation::Eq, lhs, rhs, span),
Rule::operation_ne => Expression::binary(BinaryOperation::Ne, lhs, rhs, span),
Rule::operation_ge => Expression::binary(BinaryOperation::Ge, lhs, rhs, span),
Rule::operation_gt => Expression::binary(BinaryOperation::Gt, lhs, rhs, span),
Rule::operation_le => Expression::binary(BinaryOperation::Le, lhs, rhs, span),
Rule::operation_lt => Expression::binary(BinaryOperation::Lt, lhs, rhs, span),
Rule::operation_add => Expression::binary(BinaryOperation::Add, lhs, rhs, span),
Rule::operation_sub => Expression::binary(BinaryOperation::Sub, lhs, rhs, span),
Rule::operation_mul => Expression::binary(BinaryOperation::Mul, lhs, rhs, span),
Rule::operation_div => Expression::binary(BinaryOperation::Div, lhs, rhs, span),
Rule::operation_pow => Expression::binary(BinaryOperation::Pow, lhs, rhs, span),
_ => unreachable!(),
})
}
impl<'ast> FromPest<'ast> for Expression<'ast> {
type Rule = Rule;
type FatalError = Void;
fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
let mut clone = pest.clone();
let pair = clone.next().ok_or(::from_pest::ConversionError::NoMatch)?;
match pair.as_rule() {
Rule::expression => {
// Transfer iterated state to pest.
*pest = clone;
Ok(*PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
}
_ => Err(ConversionError::NoMatch),
}
}
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, circuits::CircuitMember, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::circuit_definition))]
pub struct Circuit<'ast> {
pub identifier: Identifier<'ast>,
pub members: Vec<CircuitMember<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::Identifier, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::circuit_field))]
pub struct CircuitField<'ast> {
pub identifier: Identifier<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::Identifier, types::Type};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::circuit_field_definition))]
pub struct CircuitFieldDefinition<'ast> {
pub identifier: Identifier<'ast>,
pub _type: Type<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::Static, functions::Function};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::circuit_function))]
pub struct CircuitFunction<'ast> {
pub _static: Option<Static>,
pub function: Function<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,10 @@
use crate::{ast::Rule, circuits::{CircuitFunction, CircuitFieldDefinition}};
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::circuit_member))]
pub enum CircuitMember<'ast> {
CircuitFieldDefinition(CircuitFieldDefinition<'ast>),
CircuitFunction(CircuitFunction<'ast>),
}

14
ast/src/circuits/mod.rs Normal file
View File

@ -0,0 +1,14 @@
pub mod circuit;
pub use circuit::*;
pub mod circuit_field;
pub use circuit_field::*;
pub mod circuit_field_definition;
pub use circuit_field_definition::*;
pub mod circuit_function;
pub use circuit_function::*;
pub mod circuit_member;
pub use circuit_member::*;

View File

@ -0,0 +1,27 @@
use crate::{access::AssigneeAccess, ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::assignee))]
pub struct Assignee<'ast> {
pub identifier: Identifier<'ast>,
pub accesses: Vec<AssigneeAccess<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Assignee<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.identifier)?;
for (i, access) in self.accesses.iter().enumerate() {
write!(f, "{}", access)?;
if i < self.accesses.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}

7
ast/src/common/eoi.rs Normal file
View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;

View File

@ -0,0 +1,20 @@
use crate::ast::{span_into_string, Rule};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Identifier<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::LINE_END))]
pub struct LineEnd;

35
ast/src/common/mod.rs Normal file
View File

@ -0,0 +1,35 @@
pub mod assignee;
pub use assignee::*;
pub mod eoi;
pub use eoi::*;
pub mod identifier;
pub use identifier::*;
pub mod line_end;
pub use line_end::*;
pub mod mutable;
pub use mutable::*;
pub mod range;
pub use range::*;
pub mod range_or_expression;
pub use range_or_expression::*;
pub mod spread;
pub use spread::*;
pub mod spread_or_expression;
pub use spread_or_expression::*;
pub mod static_;
pub use static_::*;
pub mod variable;
pub use variable::*;
pub mod visibility;
pub use visibility::*;

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::mutable))]
pub struct Mutable {}

21
ast/src/common/range.rs Normal file
View File

@ -0,0 +1,21 @@
use crate::{ast::Rule, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::range))]
pub struct Range<'ast> {
pub from: Option<FromExpression<'ast>>,
pub to: Option<ToExpression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::from_expression))]
pub struct FromExpression<'ast>(pub Expression<'ast>);
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::to_expression))]
pub struct ToExpression<'ast>(pub Expression<'ast>);

View File

@ -0,0 +1,33 @@
use crate::{ast::Rule, common::Range, expressions::Expression};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::range_or_expression))]
pub enum RangeOrExpression<'ast> {
Range(Range<'ast>),
Expression(Expression<'ast>),
}
impl<'ast> fmt::Display for RangeOrExpression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RangeOrExpression::Expression(ref expression) => write!(f, "{}", expression),
RangeOrExpression::Range(ref range) => write!(
f,
"{}..{}",
range
.from
.as_ref()
.map(|e| e.0.to_string())
.unwrap_or("".to_string()),
range
.to
.as_ref()
.map(|e| e.0.to_string())
.unwrap_or("".to_string())
),
}
}
}

19
ast/src/common/spread.rs Normal file
View File

@ -0,0 +1,19 @@
use crate::{ast::Rule, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::spread))]
pub struct Spread<'ast> {
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Spread<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "...{}", self.expression)
}
}

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, common::Spread, expressions::Expression};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::spread_or_expression))]
pub enum SpreadOrExpression<'ast> {
Spread(Spread<'ast>),
Expression(Expression<'ast>),
}
impl<'ast> fmt::Display for SpreadOrExpression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SpreadOrExpression::Spread(ref spread) => write!(f, "{}", spread),
SpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
}
}
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::static_))]
pub struct Static {}

View File

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

View File

@ -0,0 +1,18 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility))]
pub enum Visibility {
Public(Public),
Private(Private),
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_public))]
pub struct Public {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_private))]
pub struct Private {}

5
ast/src/errors/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod parser;
pub use parser::*;
pub mod syntax;
pub use syntax::*;

22
ast/src/errors/parser.rs Normal file
View File

@ -0,0 +1,22 @@
use crate::{ast::Rule, errors::SyntaxError};
use pest::error::Error;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum ParserError {
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("{}", _0)]
SyntaxError(#[from] SyntaxError),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
}
impl From<Error<Rule>> for ParserError {
fn from(error: Error<Rule>) -> Self {
ParserError::SyntaxError(SyntaxError::from(error))
}
}

44
ast/src/errors/syntax.rs Normal file
View File

@ -0,0 +1,44 @@
use crate::ast::Rule;
use pest::error::Error;
#[derive(Debug, Error)]
pub enum SyntaxError {
#[error("aborting due to syntax error")]
Error,
}
impl From<Error<Rule>> for SyntaxError {
fn from(mut error: Error<Rule>) -> Self {
error = error.renamed_rules(|rule| match *rule {
Rule::LINE_END => "`;`".to_owned(),
Rule::type_integer => "`u32`".to_owned(),
Rule::type_field => "`field`".to_owned(),
Rule::type_group => "`group`".to_owned(),
Rule::file => "an import, circuit, or function".to_owned(),
Rule::identifier => "a variable name".to_owned(),
Rule::type_ => "a type".to_owned(),
Rule::access => "`.`, `::`, `()`".to_owned(),
Rule::operation_and => "`&&`".to_owned(),
Rule::operation_or => "`||`".to_owned(),
Rule::operation_eq => "`==`".to_owned(),
Rule::operation_ne => "`!=`".to_owned(),
Rule::operation_ge => "`>=`".to_owned(),
Rule::operation_gt => "`>`".to_owned(),
Rule::operation_le => "`<=`".to_owned(),
Rule::operation_lt => "`<`".to_owned(),
Rule::operation_add => "`+`".to_owned(),
Rule::operation_sub => "`-`".to_owned(),
Rule::operation_mul => "`*`".to_owned(),
Rule::operation_div => "`/`".to_owned(),
Rule::operation_pow => "`**`".to_owned(),
rule => format!("{:?}", rule),
});
log::error!("{}\n", error);
SyntaxError::Error
}
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::SpreadOrExpression, values::Value};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_array_initializer))]
pub struct ArrayInitializerExpression<'ast> {
pub expression: Box<SpreadOrExpression<'ast>>,
pub count: Value<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::SpreadOrExpression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_array_inline))]
pub struct ArrayInlineExpression<'ast> {
pub expressions: Vec<SpreadOrExpression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,11 @@
use crate::{expressions::Expression, operations::BinaryOperation};
use pest::Span;
#[derive(Clone, Debug, PartialEq)]
pub struct BinaryExpression<'ast> {
pub operation: BinaryOperation,
pub left: Box<Expression<'ast>>,
pub right: Box<Expression<'ast>>,
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, circuits::CircuitField, common::Identifier,};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_circuit_inline))]
pub struct CircuitInlineExpression<'ast> {
pub identifier: Identifier<'ast>,
pub members: Vec<CircuitField<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,99 @@
use crate::{common::Identifier, expressions::*, operations::BinaryOperation, values::Value,};
use pest::Span;
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub enum Expression<'ast> {
Value(Value<'ast>),
Identifier(Identifier<'ast>),
Not(NotExpression<'ast>),
Binary(BinaryExpression<'ast>),
Ternary(TernaryExpression<'ast>),
ArrayInline(ArrayInlineExpression<'ast>),
ArrayInitializer(ArrayInitializerExpression<'ast>),
CircuitInline(CircuitInlineExpression<'ast>),
Postfix(PostfixExpression<'ast>),
}
impl<'ast> Expression<'ast> {
pub fn binary(
operation: BinaryOperation,
left: Box<Expression<'ast>>,
right: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Binary(BinaryExpression {
operation,
left,
right,
span,
})
}
pub fn ternary(
first: Box<Expression<'ast>>,
second: Box<Expression<'ast>>,
third: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Ternary(TernaryExpression {
first,
second,
third,
span,
})
}
pub fn span(&self) -> &Span<'ast> {
match self {
Expression::Value(expression) => &expression.span(),
Expression::Identifier(expression) => &expression.span,
Expression::Not(expression) => &expression.span,
Expression::Binary(expression) => &expression.span,
Expression::Ternary(expression) => &expression.span,
Expression::ArrayInline(expression) => &expression.span,
Expression::ArrayInitializer(expression) => &expression.span,
Expression::CircuitInline(expression) => &expression.span,
Expression::Postfix(expression) => &expression.span,
}
}
}
impl<'ast> fmt::Display for Expression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Value(ref expression) => write!(f, "{}", expression),
Expression::Identifier(ref expression) => write!(f, "{}", expression),
Expression::Not(ref expression) => write!(f, "!{}", expression.expression),
Expression::Binary(ref expression) => {
write!(f, "{} == {}", expression.left, expression.right)
}
Expression::Ternary(ref expression) => write!(
f,
"if {} ? {} : {}",
expression.first, expression.second, expression.third
),
Expression::ArrayInline(ref expression) => {
for (i, spread_or_expression) in expression.expressions.iter().enumerate() {
write!(f, "{}", spread_or_expression)?;
if i < expression.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
Expression::ArrayInitializer(ref expression) => {
write!(f, "[{} ; {}]", expression.expression, expression.count)
}
Expression::CircuitInline(ref expression) => write!(
f,
"inline circuit display not impl {}",
expression.identifier
),
Expression::Postfix(ref expression) => {
write!(f, "Postfix display not impl {}", expression.identifier)
}
}
}
}

View File

@ -0,0 +1,23 @@
pub mod array_initializer_expression;
pub use array_initializer_expression::*;
pub mod array_inline_expression;
pub use array_inline_expression::*;
pub mod binary_expression;
pub use binary_expression::*;
pub mod circuit_inline_expression;
pub use circuit_inline_expression::*;
pub mod expression;
pub use expression::*;
pub mod not_expression;
pub use not_expression::*;
pub mod postfix_expression;
pub use postfix_expression::*;
pub mod ternary_expression;
pub use ternary_expression::*;

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, expressions::Expression, operations::NotOperation};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_not))]
pub struct NotExpression<'ast> {
pub operation: NotOperation<'ast>,
pub expression: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{access::Access, ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_postfix))]
pub struct PostfixExpression<'ast> {
pub identifier: Identifier<'ast>,
pub accesses: Vec<Access<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_conditional))]
pub struct TernaryExpression<'ast> {
pub first: Box<Expression<'ast>>,
pub second: Box<Expression<'ast>>,
pub third: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

16
ast/src/files/file.rs Normal file
View File

@ -0,0 +1,16 @@
use crate::{ast::Rule, common::EOI, functions::{Function, TestFunction}, imports::Import, circuits::Circuit};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub imports: Vec<Import<'ast>>,
pub circuits: Vec<Circuit<'ast>>,
pub functions: Vec<Function<'ast>>,
pub tests: Vec<TestFunction<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

2
ast/src/files/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod file;
pub use file::*;

View File

@ -0,0 +1,15 @@
use crate::{ast::Rule, common::Identifier, functions::FunctionInput, statements::Statement, types::Type};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::function_definition))]
pub struct Function<'ast> {
pub function_name: Identifier<'ast>,
pub parameters: Vec<FunctionInput<'ast>>,
pub returns: Vec<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,15 @@
use crate::{ast::Rule, common::{Identifier, Visibility, Mutable}, types::Type};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::function_input))]
pub struct FunctionInput<'ast> {
pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>,
pub visibility: Option<Visibility>,
pub _type: Type<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

8
ast/src/functions/mod.rs Normal file
View File

@ -0,0 +1,8 @@
pub mod function;
pub use function::*;
pub mod function_input;
pub use function_input::*;
pub mod test_function;
pub use test_function::*;

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, functions::Function};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::test_function))]
pub struct TestFunction<'ast> {
pub function: Function<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

14
ast/src/imports/import.rs Normal file
View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, common::LineEnd, imports::{ImportSource, ImportSymbol}};
use pest::Span;
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 line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::ast::{Rule, span_into_string};
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>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::import_symbol))]
pub struct ImportSymbol<'ast> {
pub value: Identifier<'ast>,
pub alias: Option<Identifier<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

8
ast/src/imports/mod.rs Normal file
View File

@ -0,0 +1,8 @@
pub mod import;
pub use import::*;
pub mod import_source;
pub use import_source::*;
pub mod import_symbol;
pub use import_symbol::*;

299
ast/src/leo.pest Normal file
View File

@ -0,0 +1,299 @@
/// Common
// Declared in common/assignee.rs
assignee = { identifier ~ access_assignee* }
// Declared in common/file.rs
file = { SOI ~ NEWLINE* ~ import* ~ NEWLINE* ~ circuit_definition* ~ NEWLINE* ~ function_definition* ~ NEWLINE* ~ test_function* ~ NEWLINE* ~ EOI }
// Declared in common/identifier.rs
identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
protected_name = { visibility | "let" | "for"| "if" | "else" | "as" | "return" }
// Declared in common/line_end.rs
LINE_END = { ";" ~ NEWLINE* }
// Declared in common/mutable.rs
mutable = { "mut" }
// Declared in common/range.rs
range = { from_expression? ~ ".." ~ to_expression }
from_expression = { expression }
to_expression = { expression }
// Declared in common/range_or_expression.rs
range_or_expression = { range | expression }
// Declared in common/spread.rs
spread = { "..." ~ expression }
// Declared in common/spread_or_expression.rs
spread_or_expression = { spread | expression }
// Declared in common/static_.rs
static_ = { "static" }
// Declared in common/variable.rs
variable = { mutable? ~ identifier ~ (":" ~ type_)? }
// Declared in common/visibility.rs
visibility = { visibility_public | visibility_private }
visibility_public = { "public" }
visibility_private = { "private" }
/// Operations
// Declared in operations/not_operation.rs
operation_not = { "!" }
// Declared in operations/binary_operation.rs
operation_and = { "&&" }
operation_or = { "||" }
operation_eq = { "==" }
operation_ne = { "!=" }
operation_ge = { ">=" }
operation_gt = { ">" }
operation_le = { "<=" }
operation_lt = { "<" }
operation_add = { "+" }
operation_sub = { "-" }
operation_mul = { "*" }
operation_div = { "/" }
operation_pow = { "**" }
operation_compare = _{
operation_eq | operation_ne |
operation_ge | operation_gt |
operation_le | operation_lt
}
operation_binary = _{
operation_compare | operation_and | operation_or |
operation_add | operation_sub | operation_pow | operation_mul | operation_div
}
// Declared in operations/assign_operation.rs
operation_assign = {
assign | operation_add_assign | operation_sub_assign |
operation_mul_assign | operation_div_assign | operation_pow_assign
}
assign = { "=" }
operation_add_assign = { "+=" }
operation_sub_assign = { "-=" }
operation_mul_assign = { "*=" }
operation_div_assign = { "/=" }
operation_pow_assign = { "**=" }
/// Types
// Declared in types/type_.rs
type_ = { type_self | type_array | type_data | type_circuit }
// Declared in types/integer.rs
type_integer = {
type_u8
| type_u16
| type_u32
| type_u64
| type_u128
}
type_u8 = { "u8" }
type_u16 = { "u16" }
type_u32 = { "u32" }
type_u64 = { "u64" }
type_u128 = { "u128" }
// Declared in types/field_type.rs
type_field = { "field" }
// Declared in types/group_type.rs
type_group = { "group" }
// Declared in types/boolean_type.rs
type_boolean = { "bool" }
// Declared in types/data_type.rs
type_data = { type_field | type_group | type_boolean | type_integer }
// Declared in types/self_type.rs
type_self = { "Self" }
// Declared in types/self_type.rs
type_circuit = { identifier }
// Declared in types/array_type.rs
type_array = { type_data ~ ("[" ~ value ~ "]")+ }
type_list = _{ (type_ ~ ("," ~ type_)*)? }
/// Values
// Declared in values/value.rs
value = { value_field | value_group | value_boolean | value_integer | value_implicit }
// Declared in values/number_value.rs
value_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
// Declared in values/number_implicit_value.rs
value_implicit = { value_number }
// Declared in values/integer_value.rs
value_integer = { value_number ~ type_integer }
// Declared in values/boolean_value.rs
value_boolean = { "true" | "false" }
// Declared in values/field_value.rs
value_field = { value_number ~ type_field }
// Declared in values/group_value.rs
value_group = { group_single_or_tuple ~ type_group }
group_tuple = {"(" ~ value_number ~ "," ~ value_number ~ ")"}
group_single_or_tuple = {value_number | group_tuple}
/// Access
// Declared in access/access.rs
access = { access_array | access_call | access_member | access_static_member}
// Declared in access/array_access.rs
access_array = { "[" ~ range_or_expression ~ "]" }
// Declared in access/assignee_access.rs
access_assignee = { access_array | access_member }
// Declared in access/call_access.rs
access_call = { "(" ~ expression_tuple ~ ")" }
// Declared in access/member_access.rs
access_member = { "." ~ identifier }
// Declared in access/static_member_access.rs
access_static_member = { "::" ~ identifier }
/// Circuits
// Declared in circuits/circuit_definition.rs
circuit_definition = { "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* }
// Declared in circuits/circuit_function.rs
circuit_function = { static_? ~ function_definition }
// Declared in circuits/circuit_member.rs
circuit_member = { circuit_function | circuit_field_definition }
/// Conditionals
expression_conditional = { "if" ~ expression ~ "?" ~ expression ~ ":" ~ expression}
/// Expressions
expression_term = {
("(" ~ expression ~ ")")
| expression_array_initializer
| expression_array_inline
| expression_circuit_inline
| expression_conditional
| expression_not
| expression_postfix
| expression_primitive
}
expression_primitive = { value | identifier }
expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
// Declared in expressions/expression.rs
expression = { expression_term ~ (operation_binary ~ expression_term)* }
// Declared in expressions/array_initializer_expression.rs
expression_array_initializer = { "[" ~ spread_or_expression ~ ";" ~ value ~ "]" }
// Declared in expressions/array_inline_expression.rs
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
inline_array_inner = _{(spread_or_expression ~ ("," ~ NEWLINE* ~ spread_or_expression)*)?}
// Declared in expressions/circuit_inline_expression.rs
expression_circuit_inline = { identifier ~ "{" ~ NEWLINE* ~ circuit_field_list ~ NEWLINE* ~ "}" }
circuit_field_list = _{ (circuit_field ~ ("," ~ NEWLINE* ~ circuit_field)*)? ~ ","? }
// Declared in expressions/not_expression.rs
expression_not = { operation_not ~ expression_term }
// Declared in expressions/postfix_expression.rs
expression_postfix = { identifier ~ access+ }
/// Statements
// Declared in statements/statement.rs
statement = {
(statement_return
| statement_conditional
| statement_for
| (statement_multiple_assignment
| statement_assert
| statement_definition
| statement_assign
| statement_expression
)
) ~ NEWLINE*
}
// Declared in statements/assert_statement.rs
statement_assert = { assert_eq }
assert_eq = {"assert_eq!" ~ "(" ~ NEWLINE* ~ expression ~ "," ~ NEWLINE* ~ expression ~ NEWLINE* ~ ")" ~ LINE_END}
// Declared in statements/assign_statement.rs
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)?}
conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/definition_statement.rs
statement_definition = { "let" ~ variable ~ "=" ~ expression ~ LINE_END}
// Declared in statements/expression_statement.rs
statement_expression = { expression ~ LINE_END }
// Declared in statements/for_statement.rs
statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/multiple_assignment_statement.rs
statement_multiple_assignment = { "let" ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END}
variable_tuple = _{ variable ~ ("," ~ variable)* }
// Declared in statements/return_statement.rs
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* }
// Declared in functions/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ visibility? ~ type_ }
input_model_list = _{ (function_input ~ ("," ~ function_input)*)? }
// Declared in functions/test_function.rs
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}
// Declared in imports/import_source.rs
import_source = @{ (!"\"" ~ ANY)* }
// 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)* }

48
ast/src/lib.rs Normal file
View File

@ -0,0 +1,48 @@
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate thiserror;
pub mod errors;
pub use errors::*;
pub mod access;
mod ast;
pub mod circuits;
pub mod common;
pub mod expressions;
pub mod files;
pub mod functions;
pub mod imports;
pub mod operations;
pub mod statements;
pub mod values;
pub mod types;
use from_pest::FromPest;
use std::{path::PathBuf, fs};
pub struct LeoParser;
impl LeoParser {
/// Reads in the given file path into a string.
pub fn load_file(file_path: &PathBuf) -> Result<String, ParserError> {
Ok(fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?)
}
/// Parses the input file and constructs a syntax tree.
pub fn parse_file<'a>(file_path: &'a PathBuf, input_file: &'a str) -> Result<files::File<'a>, ParserError> {
// Parse the file using leo.pest
let mut file = ast::parse(input_file).map_err(|error| {
ParserError::from(error.with_path(file_path.to_str().unwrap()))
})?;
// Build the abstract syntax tree
let syntax_tree = files::File::from_pest(&mut file).map_err(|_| ParserError::SyntaxTreeError)?;
log::debug!("{:#?}", syntax_tree);
Ok(syntax_tree)
}
}

View File

@ -0,0 +1,38 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_assign))]
pub enum AssignOperation {
Assign(Assign),
AddAssign(AddAssign),
SubAssign(SubAssign),
MulAssign(MulAssign),
DivAssign(DivAssign),
PowAssign(PowAssign),
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::assign))]
pub struct Assign {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_add_assign))]
pub struct AddAssign {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_sub_assign))]
pub struct SubAssign {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_mul_assign))]
pub struct MulAssign {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_div_assign))]
pub struct DivAssign {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_pow_assign))]
pub struct PowAssign {}

View File

@ -0,0 +1,21 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_binary))]
pub enum BinaryOperation {
Or,
And,
Eq,
Ne,
Ge,
Gt,
Le,
Lt,
Add,
Sub,
Mul,
Div,
Pow,
}

View File

@ -0,0 +1,8 @@
pub mod assign_operation;
pub use assign_operation::*;
pub mod binary_operation;
pub use binary_operation::*;
pub mod not_operation;
pub use not_operation::*;

View 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::operation_not))]
pub struct NotOperation<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,31 @@
use crate::{ast::Rule, common::LineEnd, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_assert))]
pub enum AssertStatement<'ast> {
AssertEq(AssertEq<'ast>),
}
impl<'ast> fmt::Display for AssertStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AssertStatement::AssertEq(ref assert) => {
write!(f, "assert_eq({}, {});", assert.left, assert.right)
}
}
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::assert_eq))]
pub struct AssertEq<'ast> {
pub left: Expression<'ast>,
pub right: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,22 @@
use crate::{ast::Rule, common::{Assignee, LineEnd}, expressions::Expression, operations::AssignOperation};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_assign))]
pub struct AssignStatement<'ast> {
pub assignee: Assignee<'ast>,
pub assign: AssignOperation,
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for AssignStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {};", self.assignee, self.expression)
}
}

View File

@ -0,0 +1,22 @@
use crate::{ast::Rule, statements::{ConditionalStatement, Statement}};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::conditional_nested_or_end_statement))]
pub enum ConditionalNestedOrEndStatement<'ast> {
Nested(Box<ConditionalStatement<'ast>>),
End(Vec<Statement<'ast>>),
}
impl<'ast> fmt::Display for ConditionalNestedOrEndStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConditionalNestedOrEndStatement::Nested(ref nested) => write!(f, "else {}", nested),
ConditionalNestedOrEndStatement::End(ref statements) => {
write!(f, "else {{\n \t{:#?}\n }}", statements)
}
}
}
}

View File

@ -0,0 +1,26 @@
use crate::{ast::Rule, expressions::Expression, statements::{ConditionalNestedOrEndStatement, Statement}};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_conditional))]
pub struct ConditionalStatement<'ast> {
pub condition: Expression<'ast>,
pub statements: Vec<Statement<'ast>>,
pub next: Option<ConditionalNestedOrEndStatement<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for ConditionalStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "if ({}) {{\n", self.condition)?;
write!(f, "\t{:#?}\n", self.statements)?;
self.next
.as_ref()
.map(|n_or_e| write!(f, "}} {}", n_or_e))
.unwrap_or(write!(f, "}}"))
}
}

View File

@ -0,0 +1,21 @@
use crate::{ast::Rule, common::{LineEnd, Variable}, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_definition))]
pub struct DefinitionStatement<'ast> {
pub variable: Variable<'ast>,
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for DefinitionStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "let {} = {};", self.variable, self.expression)
}
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::LineEnd, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_expression))]
pub struct ExpressionStatement<'ast> {
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,26 @@
use crate::{ast::Rule, expressions::{Expression}, statements::Statement, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement_for))]
pub struct ForStatement<'ast> {
pub index: Identifier<'ast>,
pub start: Expression<'ast>,
pub stop: Expression<'ast>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for ForStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"for {} in {}..{} {{ {:#?} }}",
self.index, self.start, self.stop, self.statements
)
}
}

29
ast/src/statements/mod.rs Normal file
View File

@ -0,0 +1,29 @@
pub mod assert_statement;
pub use assert_statement::*;
pub mod assign_statement;
pub use assign_statement::*;
pub mod conditional_statement;
pub use conditional_statement::*;
pub mod conditional_nested_or_end_statement;
pub use conditional_nested_or_end_statement::*;
pub mod definition_statement;
pub use definition_statement::*;
pub mod expression_statement;
pub use expression_statement::*;
pub mod for_statement;
pub use for_statement::*;
pub mod multiple_assignment_statement;
pub use multiple_assignment_statement::*;
pub mod return_statement;
pub use return_statement::*;
pub mod statement;
pub use statement::*;

View File

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

View File

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

View File

@ -0,0 +1,32 @@
use crate::{ast::Rule, statements::*};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Return(ReturnStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Assign(AssignStatement<'ast>),
MultipleAssignment(MultipleAssignmentStatement<'ast>),
Conditional(ConditionalStatement<'ast>),
Iteration(ForStatement<'ast>),
Assert(AssertStatement<'ast>),
Expression(ExpressionStatement<'ast>),
}
impl<'ast> fmt::Display for Statement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref statement) => write!(f, "{}", statement),
Statement::Definition(ref statement) => write!(f, "{}", statement),
Statement::Assign(ref statement) => write!(f, "{}", statement),
Statement::MultipleAssignment(ref statement) => write!(f, "{}", statement),
Statement::Conditional(ref statement) => write!(f, "{}", statement),
Statement::Iteration(ref statement) => write!(f, "{}", statement),
Statement::Assert(ref statement) => write!(f, "{}", statement),
Statement::Expression(ref statement) => write!(f, "{}", statement.expression),
}
}
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, types::DataType, values::Value};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_array))]
pub struct ArrayType<'ast> {
pub _type: DataType,
pub dimensions: Vec<Value<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_boolean))]
pub struct BooleanType {}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_circuit))]
pub struct CircuitType<'ast> {
pub identifier: Identifier<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, types::{IntegerType, FieldType, GroupType, BooleanType}};
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_data))]
pub enum DataType {
Integer(IntegerType),
Field(FieldType),
Group(GroupType),
Boolean(BooleanType),
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_field))]
pub struct FieldType {}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_group))]
pub struct GroupType {}

View File

@ -0,0 +1,33 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_integer))]
pub enum IntegerType {
U8Type(U8Type),
U16Type(U16Type),
U32Type(U32Type),
U64Type(U64Type),
U128Type(U128Type),
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u8))]
pub struct U8Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u16))]
pub struct U16Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u32))]
pub struct U32Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u64))]
pub struct U64Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u128))]
pub struct U128Type {}

26
ast/src/types/mod.rs Normal file
View File

@ -0,0 +1,26 @@
pub mod array_type;
pub use array_type::*;
pub mod boolean_type;
pub use boolean_type::*;
pub mod circuit_type;
pub use circuit_type::*;
pub mod data_type;
pub use data_type::*;
pub mod field_type;
pub use field_type::*;
pub mod group_type;
pub use group_type::*;
pub mod integer_type;
pub use integer_type::*;
pub mod self_type;
pub use self_type::*;
pub mod type_;
pub use type_::*;

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_self))]
pub struct SelfType {}

24
ast/src/types/type_.rs Normal file
View File

@ -0,0 +1,24 @@
use crate::{ast::Rule, types::*};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_))]
pub enum Type<'ast> {
Basic(DataType),
Array(ArrayType<'ast>),
Circuit(CircuitType<'ast>),
SelfType(SelfType),
}
impl<'ast> fmt::Display for Type<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Basic(ref _type) => write!(f, "basic"),
Type::Array(ref _type) => write!(f, "array"),
Type::Circuit(ref _type) => write!(f, "struct"),
Type::SelfType(ref _type) => write!(f, "Self"),
}
}
}

View File

@ -0,0 +1,20 @@
use crate::ast::{Rule, span_into_string};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_boolean))]
pub struct BooleanValue<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for BooleanValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, types::FieldType, values::NumberValue,};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_field))]
pub struct FieldValue<'ast> {
pub number: NumberValue<'ast>,
pub _type: FieldType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for FieldValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

View File

@ -0,0 +1,51 @@
use crate::{ast::Rule, types::GroupType, values::NumberValue,};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_group))]
pub struct GroupValue<'ast> {
pub value: GroupRepresentation<'ast>,
pub _type: GroupType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for GroupValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::group_single_or_tuple))]
pub enum GroupRepresentation<'ast> {
Single(NumberValue<'ast>),
Tuple(GroupTuple<'ast>),
}
impl<'ast> fmt::Display for GroupRepresentation<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GroupRepresentation::Single(number) => write!(f, "{}", number),
GroupRepresentation::Tuple(tuple) => write!(f, "{}", tuple),
}
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::group_tuple))]
pub struct GroupTuple<'ast> {
pub x: NumberValue<'ast>,
pub y: NumberValue<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for GroupTuple<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, types::IntegerType, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_integer))]
pub struct IntegerValue<'ast> {
pub number: NumberValue<'ast>,
pub _type: IntegerType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for IntegerValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

20
ast/src/values/mod.rs Normal file
View File

@ -0,0 +1,20 @@
pub mod boolean_value;
pub use boolean_value::*;
pub mod field_value;
pub use field_value::*;
pub mod group_value;
pub use group_value::*;
pub mod integer_value;
pub use integer_value::*;
pub mod number_implicit_value;
pub use number_implicit_value::*;
pub mod number_value;
pub use number_value::*;
pub mod value;
pub use value::*;

View File

@ -0,0 +1,19 @@
use crate::{ast::Rule, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_implicit))]
pub struct NumberImplicitValue<'ast> {
pub number: NumberValue<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for NumberImplicitValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

View File

@ -0,0 +1,20 @@
use crate::ast::{Rule, span_into_string};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_number))]
pub struct NumberValue<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for NumberValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

39
ast/src/values/value.rs Normal file
View File

@ -0,0 +1,39 @@
use crate::{ast::Rule, values::{BooleanValue, IntegerValue, FieldValue, GroupValue, NumberImplicitValue}};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value))]
pub enum Value<'ast> {
Integer(IntegerValue<'ast>),
Field(FieldValue<'ast>),
Group(GroupValue<'ast>),
Boolean(BooleanValue<'ast>),
Implicit(NumberImplicitValue<'ast>),
}
impl<'ast> Value<'ast> {
pub fn span(&self) -> &Span<'ast> {
match self {
Value::Integer(value) => &value.span,
Value::Field(value) => &value.span,
Value::Group(value) => &value.span,
Value::Boolean(value) => &value.span,
Value::Implicit(value) => &value.span,
}
}
}
impl<'ast> fmt::Display for Value<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Value::Integer(ref value) => write!(f, "{}", value),
Value::Field(ref value) => write!(f, "{}", value),
Value::Group(ref value) => write!(f, "{}", value),
Value::Boolean(ref value) => write!(f, "{}", value),
Value::Implicit(ref value) => write!(f, "{}", value),
}
}
}

View File

@ -1,17 +0,0 @@
[package]
name = "leo-benchmark"
version = "0.1.0"
authors = ["The Aleo Team <hello@aleo.org>"]
edition = "2018"
[dependencies]
leo-compiler = { path = "../compiler", version = "0.1.0" }
snarkos-algorithms = { path = "../../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }
from-pest = { version = "0.3.1" }
rand = { version = "0.7" }

View File

@ -1,15 +0,0 @@
struct Foo {
x: u32
y: u32
}
function main(a: private fe) {
let b = a + 1fe;
assert_eq(b, 2fe);
let c = Foo {
x: 4,
y: 5,
};
}

View File

@ -1,8 +0,0 @@
struct Point {
u32 x
u32 y
}
function test() -> (u32) {
return 5
}

View File

@ -1,131 +0,0 @@
use leo_compiler::{self, ast, errors::CompilerError, ParameterValue, Program};
use from_pest::FromPest;
use rand::thread_rng;
use snarkos_algorithms::snark::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
};
use snarkos_curves::bls12_377::{Bls12_377, Fr};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem},
};
use std::{
fs,
marker::PhantomData,
time::{Duration, Instant},
};
#[derive(Clone)]
pub struct Benchmark<F: Field + PrimeField> {
program: Program<F>,
parameters: Vec<Option<ParameterValue<F>>>,
_engine: PhantomData<F>,
}
impl<F: Field + PrimeField> Benchmark<F> {
pub fn new() -> Self {
Self {
program: Program::new(),
parameters: vec![],
_engine: PhantomData,
}
}
pub fn evaluate_program(&mut self) -> Result<(), CompilerError> {
// Read in file as string
let unparsed_file = fs::read_to_string("simple.leo").expect("cannot read file");
// Parse the file using leo.pest
let mut file = ast::parse(&unparsed_file).expect("unsuccessful parse");
// Build the abstract syntax tree
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
// println!("{:#?}", syntax_tree);
// Build a leo program from the syntax tree
self.program = Program::<F>::from(syntax_tree, "simple".into());
self.parameters = vec![None; self.program.num_parameters];
println!(" compiled: {:#?}\n", self.program);
Ok(())
}
}
impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
fn generate_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
let _res =
leo_compiler::ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
println!(" Result: {}", _res);
// Write results to file or something
Ok(())
}
}
fn main() {
let mut setup = Duration::new(0, 0);
let mut proving = Duration::new(0, 0);
let mut verifying = Duration::new(0, 0);
let rng = &mut thread_rng();
let start = Instant::now();
// Load and compile program
let mut program = Benchmark::<Fr>::new();
program.evaluate_program().unwrap();
// Generate proof parameters
let params = { generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap() };
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(&params.vk);
setup += start.elapsed();
let start = Instant::now();
// Set main function arguments in compiled program
let argument = Some(ParameterValue::Field(Fr::one()));
program.parameters = vec![argument];
// Generate proof
let proof = create_random_proof(program, &params, rng).unwrap();
proving += start.elapsed();
let start = Instant::now();
// let public_input = Fr::one();
// Verify proof
let is_success = verify_proof(&prepared_verifying_key, &proof, &[]).unwrap();
verifying += start.elapsed();
println!(" ");
println!(" Setup time : {:?} milliseconds", setup.as_millis());
println!(" Prover time : {:?} milliseconds", proving.as_millis());
println!(
" Verifier time : {:?} milliseconds",
verifying.as_millis()
);
println!(" Verifier output : {}", is_success);
println!(" ");
// let mut cs = TestConstraintSystem::<Fr>::new();
//
// println!("\n satisfied: {:?}", cs.is_satisfied());
//
// println!(
// "\n number of constraints for input: {}",
// cs.num_constraints()
// );
//
}

View File

@ -5,19 +5,18 @@ authors = ["The Aleo Team <hello@aleo.org>"]
edition = "2018"
[dependencies]
leo-ast = { path = "../ast", version = "0.1.0" }
leo-types = { path = "../types", version = "0.1.0" }
snarkos-algorithms = { path = "../../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }
snarkos-utilities = { path = "../../snarkOS/utilities", version = "0.8.0" }
failure = { version = "0.1.5" }
from-pest = { version = "0.3.1" }
hex = { version = "0.4.2" }
lazy_static = { version = "1.3.0" }
log = { version = "0.4" }
pest = { version = "2.0" }
pest-ast = { version = "0.3.3" }
pest_derive = { version = "2.0" }
rand = { version = "0.7" }
sha2 = { version = "0.8" }
thiserror = { version = "1.0" }

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,51 @@
//! Compiles a Leo program from a file path.
use crate::{ast, errors::CompilerError, ParameterValue, Program, ResolvedProgram, ResolvedValue};
use crate::{
constraints::{generate_constraints, generate_test_constraints, ConstrainedValue},
errors::CompilerError,
GroupType,
};
use leo_ast::LeoParser;
use leo_types::{InputValue, Program};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem, TestConstraintSystem},
};
use from_pest::FromPest;
use sha2::{Digest, Sha256};
use std::{fs, marker::PhantomData, path::PathBuf};
#[derive(Clone)]
pub struct Compiler<F: Field + PrimeField> {
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
package_name: String,
main_file_path: PathBuf,
program: Program<F>,
parameters: Vec<Option<ParameterValue<F>>>,
output: Option<ResolvedValue<F>>,
program: Program,
program_inputs: Vec<Option<InputValue>>,
output: Option<ConstrainedValue<F, G>>,
_engine: PhantomData<F>,
}
impl<F: Field + PrimeField> Compiler<F> {
pub fn init(package_name: String, main_file_path: PathBuf) -> Self {
Self {
impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
pub fn init(package_name: String, main_file_path: PathBuf) -> Result<Self, CompilerError> {
let mut program = Self {
package_name,
main_file_path,
program: Program::new(),
parameters: vec![],
program_inputs: vec![],
output: None,
_engine: PhantomData,
}
};
// Generate the abstract syntax tree and assemble the program
program.parse_program()?;
Ok(program)
}
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue>>) {
self.program_inputs = program_inputs;
}
pub fn checksum(&self) -> Result<String, CompilerError> {
@ -47,51 +61,45 @@ impl<F: Field + PrimeField> Compiler<F> {
Ok(hex::encode(hash))
}
// pub fn compile(&self) -> Result<ast::File, CompilerError> {
// // Read in the main file as string
// let unparsed_file = fs::read_to_string(&self.main_file_path).map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?;
//
// // Parse the file using leo.pest
// let mut file = ast::parse(&unparsed_file).map_err(|_| CompilerError::FileParsingError)?;
//
// // Build the abstract syntax tree
// let syntax_tree = ast::File::from_pest(&mut file).map_err(|_| CompilerError::SyntaxTreeError)?;
// log::debug!("{:#?}", syntax_tree);
//
// Ok(syntax_tree)
// }
pub fn compile_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, CompilerError> {
generate_constraints(cs, self.program, self.program_inputs)
}
pub fn evaluate_program<CS: ConstraintSystem<F>>(&mut self) -> Result<(), CompilerError> {
// Read in the main file as string
let unparsed_file = fs::read_to_string(&self.main_file_path)
.map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?;
pub fn compile_test_constraints(
self,
cs: &mut TestConstraintSystem<F>,
) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program)
}
// Parse the file using leo.pest
let mut file = ast::parse(&unparsed_file).map_err(|_| CompilerError::FileParsingError)?;
fn parse_program(&mut self) -> Result<(), CompilerError> {
// Build the program syntax tree
let file_path = &self.main_file_path;
let input_file = &LeoParser::load_file(file_path)?;
let syntax_tree = LeoParser::parse_file(file_path, input_file)?;
// Build the abstract syntax tree
let syntax_tree =
ast::File::from_pest(&mut file).map_err(|_| CompilerError::SyntaxTreeError)?;
log::debug!("{:#?}", syntax_tree);
// Build program from abstract syntax tree
// Build program from syntax tree
let package_name = self.package_name.clone();
self.program = Program::<F>::from(syntax_tree, package_name);
self.parameters = vec![None; self.program.num_parameters];
self.program = Program::from(syntax_tree, package_name);
self.program_inputs = vec![None; self.program.num_parameters];
log::debug!("Compilation complete\n{:#?}", self.program);
log::debug!("Program parsing complete\n{:#?}", self.program);
Ok(())
}
}
impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Compiler<F> {
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
fn generate_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
let _res = ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
let _result =
generate_constraints::<_, G, _>(cs, self.program, self.program_inputs).unwrap();
// Write results to file or something

View File

@ -1,9 +1,11 @@
//! Methods to enforce constraints on booleans in a resolved Leo program.
use crate::{
constraints::{new_variable_from_variable, ResolvedProgram, ResolvedValue},
types::{ParameterModel, ParameterValue, Variable},
constraints::{ConstrainedProgram, ConstrainedValue},
errors::BooleanError,
GroupType,
};
use leo_types::InputValue;
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -14,125 +16,97 @@ use snarkos_models::{
},
};
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
pub(crate) fn bool_from_parameter(
impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
pub(crate) fn bool_from_input(
&mut self,
cs: &mut CS,
scope: String,
parameter_model: ParameterModel<F>,
parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
// Check that the parameter value is the correct type
let bool_value = parameter_value.map(|parameter| match parameter {
ParameterValue::Boolean(b) => b,
value => unimplemented!("expected boolean parameter, got {}", value),
});
name: String,
private: bool,
input_value: Option<InputValue>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
// Check that the input value is the correct type
let bool_value = match input_value {
Some(input) => {
if let InputValue::Boolean(bool) = input {
Some(bool)
} else {
return Err(BooleanError::InvalidBoolean(input.to_string()));
}
}
None => None,
};
// Check visibility of parameter
let name = parameter_model.variable.name.clone();
let number = if parameter_model.private {
// Check visibility of input
let number = if private {
Boolean::alloc(cs.ns(|| name), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
})?
} else {
Boolean::alloc_input(cs.ns(|| name), || {
bool_value.ok_or(SynthesisError::AssignmentMissing)
})
.unwrap()
})?
};
let parameter_variable = new_variable_from_variable(scope, &parameter_model.variable);
// store each argument as variable in resolved program
self.store_variable(parameter_variable.clone(), ResolvedValue::Boolean(number));
parameter_variable
Ok(ConstrainedValue::Boolean(number))
}
pub(crate) fn boolean_array_from_parameter(
&mut self,
_cs: &mut CS,
_scope: String,
_parameter_model: ParameterModel<F>,
_parameter_value: Option<ParameterValue<F>>,
) -> Variable<F> {
unimplemented!("Cannot enforce boolean array as parameter")
// // Check visibility of parameter
// let mut array_value = vec![];
// let name = parameter.variable.name.clone();
// for argument in argument_array {
// let number = if parameter.private {
// Boolean::alloc(cs.ns(|| name), ||bool_value.ok_or(SynthesisError::AssignmentMissing).unwrap()
// } else {
// Boolean::alloc_input(cs.ns(|| name), || Ok(argument)).unwrap()
// };
//
// array_value.push(number);
// }
//
//
// let parameter_variable = new_variable_from_variable(scope, &parameter.variable);
//
// // store array as variable in resolved program
// self.store_variable(parameter_variable.clone(), ResolvedValue::BooleanArray(array_value));
//
// parameter_variable
pub(crate) fn get_boolean_constant(bool: Boolean) -> ConstrainedValue<F, G> {
ConstrainedValue::Boolean(bool)
}
pub(crate) fn get_boolean_constant(bool: bool) -> ResolvedValue<F> {
ResolvedValue::Boolean(Boolean::Constant(bool))
}
pub(crate) fn evaluate_not(value: ResolvedValue<F>) -> ResolvedValue<F> {
pub(crate) fn evaluate_not(
value: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match value {
ResolvedValue::Boolean(boolean) => ResolvedValue::Boolean(boolean.not()),
value => unimplemented!("cannot enforce not on non-boolean value {}", value),
ConstrainedValue::Boolean(boolean) => Ok(ConstrainedValue::Boolean(boolean.not())),
value => Err(BooleanError::CannotEvaluate(format!("!{}", value))),
}
}
pub(crate) fn enforce_or(
&mut self,
cs: &mut CS,
left: ResolvedValue<F>,
right: ResolvedValue<F>,
) -> ResolvedValue<F> {
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
ResolvedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool).unwrap())
}
(left_value, right_value) => unimplemented!(
"cannot enforce or on non-boolean values {} || {}",
left_value,
right_value
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => Ok(
ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool)?),
),
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} || {}",
left_value, right_value
))),
}
}
pub(crate) fn enforce_and(
&mut self,
cs: &mut CS,
left: ResolvedValue<F>,
right: ResolvedValue<F>,
) -> ResolvedValue<F> {
left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, BooleanError> {
match (left, right) {
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
ResolvedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool).unwrap())
}
(left_value, right_value) => unimplemented!(
"cannot enforce and on non-boolean values {} && {}",
left_value,
right_value
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => Ok(
ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool)?),
),
(left_value, right_value) => Err(BooleanError::CannotEnforce(format!(
"{} && {}",
left_value, right_value
))),
}
}
pub(crate) fn boolean_eq(left: Boolean, right: Boolean) -> ResolvedValue<F> {
ResolvedValue::Boolean(Boolean::Constant(left.eq(&right)))
pub(crate) fn boolean_eq(left: Boolean, right: Boolean) -> ConstrainedValue<F, G> {
ConstrainedValue::Boolean(Boolean::Constant(left.eq(&right)))
}
pub(crate) fn enforce_boolean_eq(&mut self, cs: &mut CS, left: Boolean, right: Boolean) {
left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)
.unwrap();
pub(crate) fn enforce_boolean_eq(
&mut self,
cs: &mut CS,
left: Boolean,
right: Boolean,
) -> Result<(), BooleanError> {
Ok(left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)?)
}
}

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