Merge branch 'master' into feature/opti-cli-flag

This commit is contained in:
damirka 2021-04-10 00:33:19 +03:00
commit 1e1697b7fe
190 changed files with 6572 additions and 2488 deletions

View File

@ -1,2 +1,2 @@
[target.'cfg(not(target_arch = "wasm32"))']
[target.'cfg(any(not(target_arch = "wasm32"), feature = "noconfig"))']
rustflags = ["-C", "target-cpu=native"]

View File

@ -44,7 +44,7 @@ jobs:
rust-stable:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- checkout
@ -62,7 +62,7 @@ jobs:
rust-nightly:
docker:
- image: howardwu/snarkos-ci:2021-01-31
- image: howardwu/snarkos-ci:2021-03-25
resource_class: xlarge
steps:
- checkout
@ -77,7 +77,7 @@ jobs:
leo-executable:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- checkout
@ -86,7 +86,7 @@ jobs:
- run:
name: Build and install Leo
no_output_timeout: 30m
command: cargo install --path . --root .
command: cargo install --path . --root . --locked
- persist_to_workspace:
root: ~/
paths: project/
@ -95,7 +95,7 @@ jobs:
leo-new:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -108,7 +108,7 @@ jobs:
leo-init:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -121,7 +121,7 @@ jobs:
leo-clean:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -134,7 +134,7 @@ jobs:
leo-setup:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -147,7 +147,7 @@ jobs:
leo-add-remove:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -160,7 +160,7 @@ jobs:
leo-login-logout:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -173,7 +173,7 @@ jobs:
leo-clone:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:
@ -186,7 +186,7 @@ jobs:
leo-publish:
docker:
- image: cimg/rust:1.50.0
- image: cimg/rust:1.51.0
resource_class: xlarge
steps:
- attach_workspace:

View File

@ -1,6 +1,6 @@
# leo add (w/o login) & remove
$LEO new my-app && cd my-app
$LEO new my-app && cd my-app || exit 1
$LEO add howard/silly-sudoku
$LEO remove silly-sudoku
$LEO clean

View File

@ -1,4 +1,5 @@
mkdir hello-world && cd hello-world || exit 1
$LEO init
ls -la
mkdir hello-world
cd hello-world
$LEO init || exit 1
ls -la hello-world
$LEO run

View File

@ -25,7 +25,7 @@ jobs:
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
cargo build --all --release --features noconfig && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
@ -67,7 +67,7 @@ jobs:
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
cargo build --all --release --features noconfig && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
@ -95,7 +95,6 @@ jobs:
windows:
name: Windows
runs-on: windows-latest
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v1
@ -111,12 +110,15 @@ jobs:
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v1
with:
version: "10.0"
directory: ~ / .clang
version: "11"
directory: ${{ runner.temp }}/llvm
- name: Set LIBCLANG_PATH
run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
- name: Build Leo
run: |
cargo build --all --release
cargo build --all --release --features noconfig
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
@ -125,18 +127,13 @@ jobs:
- name: Zip
run: |
mkdir tempdir
mv target/release/leo tempdir
cd tempdir
Compress-Archive leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu leo
cd ..
mv leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu .
Compress-Archive target/release/leo.exe leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-msvc.zip
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu.zip
leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-msvc.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1 +1 @@
v1.2.3
v1.3.0

216
Cargo.lock generated
View File

@ -2,6 +2,25 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "abnf"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd8863e7db43447ad50376e19b0549343b72ad45cbd394b3fc8fe3ede961facc"
dependencies = [
"abnf-core",
"nom 6.1.2",
]
[[package]]
name = "abnf-core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b514944cb7199c4201f54406bc58676a3e4f37d40bf8e3dbe30652ca82e3ddb4"
dependencies = [
"nom 6.1.2",
]
[[package]]
name = "addr2line"
version = "0.14.1"
@ -52,9 +71,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.39"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767"
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
[[package]]
name = "arrayref"
@ -157,6 +176,18 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitvec"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2"
version = "0.9.1"
@ -290,7 +321,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
"nom 5.1.2",
]
[[package]]
@ -787,6 +818,22 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futf"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
dependencies = [
"mac",
"new_debug_unreachable",
]
[[package]]
name = "futures-channel"
version = "0.3.13"
@ -1192,9 +1239,17 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "leo-abnf"
version = "1.3.0"
dependencies = [
"abnf",
"anyhow",
]
[[package]]
name = "leo-asg"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"criterion",
"indexmap",
@ -1203,20 +1258,21 @@ dependencies = [
"num-bigint",
"serde",
"serde_json",
"tendril",
"thiserror",
"typed-arena",
]
[[package]]
name = "leo-asg-passes"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"leo-asg",
]
[[package]]
name = "leo-ast"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"anyhow",
"criterion",
@ -1225,12 +1281,13 @@ dependencies = [
"pest",
"serde",
"serde_json",
"tendril",
"thiserror",
]
[[package]]
name = "leo-compiler"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"bincode",
"hex",
@ -1257,13 +1314,14 @@ dependencies = [
"snarkvm-gadgets",
"snarkvm-r1cs",
"snarkvm-utilities",
"tempfile",
"thiserror",
"tracing",
]
[[package]]
name = "leo-imports"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"indexmap",
"leo-asg",
@ -1275,7 +1333,7 @@ dependencies = [
[[package]]
name = "leo-input"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"from-pest",
"pest",
@ -1287,7 +1345,7 @@ dependencies = [
[[package]]
name = "leo-lang"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"anyhow",
"clap",
@ -1326,11 +1384,11 @@ dependencies = [
[[package]]
name = "leo-linter"
version = "1.2.3"
version = "1.3.0"
[[package]]
name = "leo-package"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"lazy_static",
"serde",
@ -1343,7 +1401,7 @@ dependencies = [
[[package]]
name = "leo-parser"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"criterion",
"indexmap",
@ -1351,13 +1409,14 @@ dependencies = [
"leo-ast",
"serde",
"serde_json",
"tendril",
"thiserror",
"tracing",
]
[[package]]
name = "leo-state"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"indexmap",
"leo-ast",
@ -1375,7 +1434,7 @@ dependencies = [
[[package]]
name = "leo-synthesizer"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"num-bigint",
"serde",
@ -1386,6 +1445,19 @@ dependencies = [
"snarkvm-r1cs",
]
[[package]]
name = "lexical-core"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if 1.0.0",
"ryu",
"static_assertions",
]
[[package]]
name = "libc"
version = "0.2.89"
@ -1444,6 +1516,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "mac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "maplit"
version = "1.0.2"
@ -1610,6 +1688,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nias"
version = "0.5.0"
@ -1626,6 +1710,19 @@ dependencies = [
"version_check",
]
[[package]]
name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
dependencies = [
"bitvec",
"funty",
"lexical-core",
"memchr",
"version_check",
]
[[package]]
name = "notify"
version = "4.0.15"
@ -2011,6 +2108,12 @@ dependencies = [
"proc-macro2 1.0.24",
]
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]]
name = "rand"
version = "0.8.3"
@ -2468,9 +2571,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "snarkvm-algorithms"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "472ed062cdd1f54076312dd34e5fb56bd585c80c12209045f4b5bbbd368e9000"
checksum = "bdf8ca73d429824090b96f751846e37e539f24c527f1f1ce0254984ade6d17b2"
dependencies = [
"blake2",
"derivative",
@ -2491,9 +2594,9 @@ dependencies = [
[[package]]
name = "snarkvm-curves"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdfdfa3aa137f64a7f49df03393e5d0269f133ca8c8c79e569cb3bb13181aeb2"
checksum = "64610b135b8b1152439d5dfa4f745515933366082f08651961344aa0bb5abfca"
dependencies = [
"derivative",
"rand",
@ -2507,9 +2610,9 @@ dependencies = [
[[package]]
name = "snarkvm-derives"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a2ba967601ff2534adbc6a71a691be4285e61c83d23d54a59824f8fa80f6038"
checksum = "46c9829b6e2023b4c7c4d6c55e88fe755dd997171a6c9c063b75c28161d04326"
dependencies = [
"proc-macro-crate",
"proc-macro-error",
@ -2520,9 +2623,9 @@ dependencies = [
[[package]]
name = "snarkvm-dpc"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4cb55898089843ba44b9f96448dcb2badcc1ce12daa8d7365d4e41513e37bc"
checksum = "491ae936e24e17c358d112ff8638b260500b5a982ecefc804861e28b5279f552"
dependencies = [
"anyhow",
"base58",
@ -2546,9 +2649,9 @@ dependencies = [
[[package]]
name = "snarkvm-fields"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca9ea954196e76fe8968fb99eced7ccf08f901ab22747c4c489bda6674a7cb39"
checksum = "8c49c69d02df11be58e07f626c9d6f5804c6dd4ccf42e425f2be8d79fe6e5bb7"
dependencies = [
"bincode",
"derivative",
@ -2561,9 +2664,9 @@ dependencies = [
[[package]]
name = "snarkvm-gadgets"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdda42a0a6484d9f008801a8a4d494a69a4db3f7b317057a8cc3c6e4b3ef6884"
checksum = "bd6f9ac2a166d926e1755a06fdae21ce40ce6164c75c89120401b8d78f3b7ba4"
dependencies = [
"derivative",
"digest 0.9.0",
@ -2578,9 +2681,9 @@ dependencies = [
[[package]]
name = "snarkvm-objects"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e20d13db49cedc147df06c4a6f2dd727ea25640bdf50b876f40005331767a68f"
checksum = "9bd9779ec6ab9211f34a6ba25566feb575a396f4c41cc0e002ec2d48d7560a2a"
dependencies = [
"anyhow",
"bincode",
@ -2599,9 +2702,9 @@ dependencies = [
[[package]]
name = "snarkvm-parameters"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d35fa1819d803e45b4e99fe822e6981f177716f5384eef27245b5f6ed59a8305"
checksum = "98378f612206fc7dd44a26f4e345bd1f3ba51bd325acad1e5cc3785d14750ec5"
dependencies = [
"curl",
"hex",
@ -2612,15 +2715,15 @@ dependencies = [
[[package]]
name = "snarkvm-profiler"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7834d57af37a31f2f280f08b61d07a04a9a4b7720819b06ca325da32a5a925f5"
checksum = "b2460ac01c25f79f5ea306e4de82a1d4105e811f868206b4fd31c0c9b62a3d7b"
[[package]]
name = "snarkvm-r1cs"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0838118f276e7bb673cbf3741f4966c56861aaff399a46d343fc98c12851d9eb"
checksum = "a3a0d54b15802976aff7522765dd29d5733f338612449629cc57c5a4a4d51f05"
dependencies = [
"cfg-if 1.0.0",
"fxhash",
@ -2633,9 +2736,9 @@ dependencies = [
[[package]]
name = "snarkvm-storage"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a42d92a817502878f315cc264704fa2a3d563755f16186316d8177ea685769af"
checksum = "1d76881939f008d7bba4c8cc4118d29567b5c71908ad66bef9880f8aa7c52881"
dependencies = [
"anyhow",
"bincode",
@ -2654,9 +2757,9 @@ dependencies = [
[[package]]
name = "snarkvm-utilities"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5598f7f71c8aaf4fc267b5b420b2440a4d86c9243cecd57ff0af5c366217e5cc"
checksum = "c763843fa67a3aa4ce68173c8cd96b4f04aaa135a5792bc051c36eec0fe1cd73"
dependencies = [
"bincode",
"rand",
@ -2675,6 +2778,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.8.0"
@ -2745,6 +2854,12 @@ dependencies = [
"unicode-xid 0.2.1",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tempfile"
version = "3.2.0"
@ -2759,6 +2874,17 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tendril"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33"
dependencies = [
"futf",
"mac",
"utf-8",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@ -3077,6 +3203,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf-8"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
[[package]]
name = "vcpkg"
version = "0.2.11"
@ -3283,6 +3415,12 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "zip"
version = "0.5.10"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-lang"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
@ -27,64 +27,64 @@ path = "leo/main.rs"
[workspace]
members = [
"asg",
"asg-passes",
"ast",
"compiler",
"grammar",
"imports",
"input",
"linter",
"package",
"parser",
"state",
"synthesizer",
"asg-passes",
"synthesizer"
]
[dependencies.leo-ast]
path = "./ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-compiler]
path = "./compiler"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-imports]
path = "./imports"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-input]
path = "./input"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-package]
path = "./package"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-state]
path = "./state"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-synthesizer]
path = "./synthesizer"
version = "1.2.3"
version = "1.3.0"
[dependencies.snarkvm-algorithms]
version = "0.2.1"
#default-features = false
version = "0.2.2"
[dependencies.snarkvm-curves]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-gadgets]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-r1cs]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-utilities]
version = "0.2.1"
version = "0.2.2"
[dependencies.anyhow]
version = "1.0"
@ -156,6 +156,7 @@ version = "0.11.2"
[features]
default = [ ]
ci_skip = [ "leo-compiler/ci_skip" ]
noconfig = [ ]
[profile.release]
opt-level = 3

View File

@ -1,6 +1,6 @@
[package]
name = "leo-asg-passes"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
@ -13,7 +13,7 @@ keywords = [
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "leo", "README.md", "LICENSE.md" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
@ -22,4 +22,4 @@ path = "src/lib.rs"
[dependencies.leo-asg]
path = "../asg"
version = "1.2.3"
version = "1.3.0"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-asg"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "ASG of the Leo programming language"
homepage = "https://aleo.org"
@ -30,11 +30,11 @@ version = "1.6"
version = "1.0"
[dependencies.leo-ast]
version = "1.2.3"
version = "1.3.0"
path = "../ast"
[dependencies.leo-parser]
version = "1.2.3"
version = "1.3.0"
path = "../parser"
[dependencies.num-bigint]
@ -43,5 +43,8 @@ version = "0.4"
[dependencies.typed-arena]
version = "2.0"
[dependencies.tendril]
version = "0.4"
[dev-dependencies.criterion]
version = "0.3"

View File

@ -18,6 +18,7 @@ use crate::{AsgConvertError, IntegerType, Span, Type};
use num_bigint::BigInt;
use std::{convert::TryInto, fmt};
use tendril::StrTendril;
/// Constant integer values in a program.
#[derive(Clone, Debug, PartialEq)]
@ -38,7 +39,7 @@ pub enum ConstInt {
#[derive(Clone, Debug, PartialEq)]
pub enum GroupCoordinate {
/// Explicit field element number string.
Number(String),
Number(StrTendril),
/// Attempt to recover with a sign high bit.
SignHigh,
@ -87,7 +88,7 @@ impl Into<leo_ast::GroupCoordinate> for &GroupCoordinate {
#[derive(Clone, Debug, PartialEq)]
pub enum GroupValue {
Single(String),
Single(StrTendril),
Tuple(GroupCoordinate, GroupCoordinate),
}
@ -106,7 +107,7 @@ pub enum ConstValue {
Int(ConstInt),
Group(GroupValue),
Field(BigInt),
Address(String),
Address(StrTendril),
Boolean(bool),
// compounds

View File

@ -35,25 +35,7 @@ pub enum AsgConvertError {
SyntaxError(#[from] SyntaxError),
}
impl LeoError for AsgConvertError {
fn get_path(&self) -> Option<&str> {
match self {
AsgConvertError::Error(error) => error.get_path(),
AsgConvertError::SyntaxError(error) => error.get_path(),
AsgConvertError::ImportError(error) => error.get_path(),
AsgConvertError::InternalError(_) => None,
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
AsgConvertError::Error(error) => error.set_path(path, contents),
AsgConvertError::SyntaxError(error) => error.set_path(path, contents),
AsgConvertError::ImportError(error) => error.set_path(path, contents),
AsgConvertError::InternalError(_) => {}
}
}
}
impl LeoError for AsgConvertError {}
impl AsgConvertError {
fn new_from_span(message: String, span: &Span) -> Self {
@ -190,6 +172,13 @@ impl AsgConvertError {
)
}
pub fn duplicate_function_definition(name: &str, span: &Span) -> Self {
Self::new_from_span(
format!("a function named \"{}\" already exists in this scope", name),
span,
)
}
pub fn index_into_non_tuple(name: &str, span: &Span) -> Self {
Self::new_from_span(format!("failed to index into non-tuple '{}'", name), span)
}
@ -198,6 +187,14 @@ impl AsgConvertError {
Self::new_from_span(format!("tuple index out of bounds: '{}'", index), span)
}
pub fn array_index_out_of_bounds(index: usize, span: &Span) -> Self {
Self::new_from_span(format!("array index out of bounds: '{}'", index), span)
}
pub fn unknown_array_size(span: &Span) -> Self {
Self::new_from_span("array size cannot be inferred, add explicit types".to_string(), span)
}
pub fn unexpected_call_argument_count(expected: usize, got: usize, span: &Span) -> Self {
Self::new_from_span(
format!("function call expected {} arguments, got {}", expected, got),

View File

@ -89,8 +89,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<'
&*value.array,
Some(PartialType::Array(expected_type.map(Box::new), None)),
)?;
match array.get_type() {
Some(Type::Array(..)) => (),
let array_len = match array.get_type() {
Some(Type::Array(_, len)) => len,
type_ => {
return Err(AsgConvertError::unexpected_type(
"array",
@ -98,7 +98,7 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<'
&value.span,
));
}
}
};
let index = <&Expression<'a>>::from_ast(
scope,
@ -106,10 +106,17 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<'
Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?;
if !index.is_consty() {
return Err(AsgConvertError::unexpected_nonconst(
&index.span().cloned().unwrap_or_default(),
));
if let Some(index) = index
.const_value()
.map(|x| x.int().map(|x| x.to_usize()).flatten())
.flatten()
{
if index >= array_len {
return Err(AsgConvertError::array_index_out_of_bounds(
index,
&array.span().cloned().unwrap_or_default(),
));
}
}
Ok(ArrayAccessExpression {

View File

@ -152,7 +152,7 @@ impl<'a> Into<leo_ast::ArrayInitExpression> for &ArrayInitExpression<'a> {
leo_ast::ArrayInitExpression {
element: Box::new(self.element.get().into()),
dimensions: leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber {
value: self.len.to_string(),
value: self.len.to_string().into(),
}]),
span: self.span.clone().unwrap_or_default(),
}

View File

@ -26,6 +26,9 @@ pub struct ArrayRangeAccessExpression<'a> {
pub array: Cell<&'a Expression<'a>>,
pub left: Cell<Option<&'a Expression<'a>>>,
pub right: Cell<Option<&'a Expression<'a>>>,
// this is either const(right) - const(left) OR the length inferred by type checking
// special attention must be made to update this if semantic-altering changes are made to left or right.
pub length: usize,
}
impl<'a> Node for ArrayRangeAccessExpression<'a> {
@ -55,25 +58,12 @@ impl<'a> ExpressionNode<'a> for ArrayRangeAccessExpression<'a> {
}
fn get_type(&self) -> Option<Type<'a>> {
let (element, array_len) = match self.array.get().get_type() {
Some(Type::Array(element, len)) => (element, len),
let element = match self.array.get().get_type() {
Some(Type::Array(element, _)) => element,
_ => return None,
};
let const_left = match self.left.get().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => 0,
_ => return None,
};
let const_right = match self.right.get().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array_len,
_ => return None,
};
if const_left > const_right || const_right > array_len {
return None;
}
Some(Type::Array(element, const_right - const_left))
Some(Type::Array(element, self.length))
}
fn is_mut_ref(&self) -> bool {
@ -113,9 +103,9 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
value: &leo_ast::ArrayRangeAccessExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<ArrayRangeAccessExpression<'a>, AsgConvertError> {
let expected_array = match expected_type {
Some(PartialType::Array(element, _len)) => Some(PartialType::Array(element, None)),
None => None,
let (expected_array, expected_len) = match expected_type.clone() {
Some(PartialType::Array(element, len)) => (Some(PartialType::Array(element, None)), len),
None => (None, None),
Some(x) => {
return Err(AsgConvertError::unexpected_type(
&x.to_string(),
@ -126,8 +116,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
};
let array = <&Expression<'a>>::from_ast(scope, &*value.array, expected_array)?;
let array_type = array.get_type();
match array_type {
Some(Type::Array(_, _)) => (),
let (parent_element, parent_size) = match array_type {
Some(Type::Array(inner, size)) => (inner, size),
type_ => {
return Err(AsgConvertError::unexpected_type(
"array",
@ -135,7 +125,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
&value.span,
));
}
}
};
let left = value
.left
.as_deref()
@ -151,26 +142,72 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx
})
.transpose()?;
if let Some(left) = left.as_ref() {
if !left.is_consty() {
return Err(AsgConvertError::unexpected_nonconst(
&left.span().cloned().unwrap_or_default(),
));
let const_left = match left.map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize(),
None => Some(0),
_ => None,
};
let const_right = match right.map(|x| x.const_value()) {
Some(Some(ConstValue::Int(value))) => {
let value = value.to_usize();
if let Some(value) = value {
if value > parent_size {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&right.unwrap().span().cloned().unwrap_or_default(),
));
} else if let Some(left) = const_left {
if left > value {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&right.unwrap().span().cloned().unwrap_or_default(),
));
}
}
}
value
}
}
if let Some(right) = right.as_ref() {
if !right.is_consty() {
return Err(AsgConvertError::unexpected_nonconst(
&right.span().cloned().unwrap_or_default(),
));
None => Some(parent_size),
_ => None,
};
let mut length = if let (Some(left), Some(right)) = (const_left, const_right) {
Some(right - left)
} else {
None
};
if let Some(expected_len) = expected_len {
if let Some(length) = length {
if length != expected_len {
let concrete_type = Type::Array(parent_element, length);
return Err(AsgConvertError::unexpected_type(
&expected_type.as_ref().unwrap().to_string(),
Some(&concrete_type.to_string()),
&value.span,
));
}
}
if let Some(value) = const_left {
if value + expected_len > parent_size {
return Err(AsgConvertError::array_index_out_of_bounds(
value,
&left.unwrap().span().cloned().unwrap_or_default(),
));
}
}
length = Some(expected_len);
}
if length.is_none() {
return Err(AsgConvertError::unknown_array_size(&value.span));
}
Ok(ArrayRangeAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
array: Cell::new(array),
left: Cell::new(left),
right: Cell::new(right),
length: length.unwrap(),
})
}
}

View File

@ -116,7 +116,7 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
let circuit_name = circuit.name.borrow().name.clone();
let member = circuit.members.borrow();
let member = member
.get(&name.name)
.get(name.name.as_ref())
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {
@ -156,7 +156,7 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
let member = circuit.members.borrow();
let member = member
.get(&name.name)
.get(name.name.as_ref())
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {

View File

@ -67,7 +67,7 @@ impl<'a> ExpressionNode<'a> for CircuitAccessExpression<'a> {
None // function target only for static
} else {
let members = self.circuit.get().members.borrow();
let member = members.get(&self.member.name)?;
let member = members.get(self.member.name.as_ref())?;
match member {
CircuitMember::Variable(type_) => Some(type_.clone()),
CircuitMember::Function(_) => None,
@ -112,7 +112,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessEx
// scoping refcell reference
let found_member = {
if let Some(member) = circuit.members.borrow().get(&value.name.name) {
if let Some(member) = circuit.members.borrow().get(value.name.name.as_ref()) {
if let Some(expected_type) = &expected_type {
if let CircuitMember::Variable(type_) = &member {
let type_: Type = type_.clone();
@ -136,10 +136,10 @@ impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessEx
} else if circuit.is_input_pseudo_circuit() {
// add new member to implicit input
if let Some(expected_type) = expected_type.map(PartialType::full).flatten() {
circuit
.members
.borrow_mut()
.insert(value.name.name.clone(), CircuitMember::Variable(expected_type.clone()));
circuit.members.borrow_mut().insert(
value.name.name.to_string(),
CircuitMember::Variable(expected_type.clone()),
);
} else {
return Err(AsgConvertError::input_ref_needs_type(
&circuit.name.borrow().name,
@ -192,7 +192,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitStaticFunctionAccessExpression> for Circuit
));
}
if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(&value.name.name) {
if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(value.name.name.as_ref()) {
// okay
} else {
return Err(AsgConvertError::unresolved_circuit_member(

View File

@ -67,7 +67,7 @@ impl<'a> ExpressionNode<'a> for CircuitInitExpression<'a> {
}
fn is_mut_ref(&self) -> bool {
false
true
}
fn const_value(&self) -> Option<ConstValue> {
@ -99,10 +99,10 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'
));
}
}
let members: IndexMap<&String, (&Identifier, Option<&leo_ast::Expression>)> = value
let members: IndexMap<&str, (&Identifier, Option<&leo_ast::Expression>)> = value
.members
.iter()
.map(|x| (&x.identifier.name, (&x.identifier, x.expression.as_ref())))
.map(|x| (x.identifier.name.as_ref(), (&x.identifier, x.expression.as_ref())))
.collect();
let mut values: Vec<(Identifier, Cell<&'a Expression<'a>>)> = vec![];
@ -124,7 +124,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'
} else {
continue;
};
if let Some((identifier, receiver)) = members.get(&name) {
if let Some((identifier, receiver)) = members.get(&**name) {
let received = if let Some(receiver) = *receiver {
<&Expression<'a>>::from_ast(scope, receiver, Some(type_.partial()))?
} else {

View File

@ -174,12 +174,12 @@ impl<'a> FromAst<'a, leo_ast::ValueExpression> for Constant<'a> {
Some(PartialType::Type(Type::Group)) => Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Group(GroupValue::Single(value.to_string())),
value: ConstValue::Group(GroupValue::Single(value.clone())),
},
Some(PartialType::Type(Type::Address)) => Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Address(value.to_string()),
value: ConstValue::Address(value.clone()),
},
Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some("unknown"), span)),
},
@ -213,10 +213,10 @@ impl<'a> Into<leo_ast::ValueExpression> for &Constant<'a> {
leo_ast::ValueExpression::Address(value.clone(), self.span.clone().unwrap_or_default())
}
ConstValue::Boolean(value) => {
leo_ast::ValueExpression::Boolean(value.to_string(), self.span.clone().unwrap_or_default())
leo_ast::ValueExpression::Boolean(value.to_string().into(), self.span.clone().unwrap_or_default())
}
ConstValue::Field(value) => {
leo_ast::ValueExpression::Field(value.to_string(), self.span.clone().unwrap_or_default())
leo_ast::ValueExpression::Field(value.to_string().into(), self.span.clone().unwrap_or_default())
}
ConstValue::Group(value) => leo_ast::ValueExpression::Group(Box::new(match value {
GroupValue::Single(single) => {
@ -230,7 +230,7 @@ impl<'a> Into<leo_ast::ValueExpression> for &Constant<'a> {
})),
ConstValue::Int(int) => leo_ast::ValueExpression::Integer(
int.get_int_type(),
int.raw_value(),
int.raw_value().into(),
self.span.clone().unwrap_or_default(),
),
ConstValue::Tuple(_) => unimplemented!(),

View File

@ -109,7 +109,7 @@ impl<'a> Into<leo_ast::TupleAccessExpression> for &TupleAccessExpression<'a> {
leo_ast::TupleAccessExpression {
tuple: Box::new(self.tuple_ref.get().into()),
index: leo_ast::PositiveNumber {
value: self.index.to_string(),
value: self.index.to_string().into(),
},
span: self.span.clone().unwrap_or_default(),
}

View File

@ -136,7 +136,7 @@ impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> {
value: &leo_ast::Identifier,
expected_type: Option<PartialType<'a>>,
) -> Result<&'a Expression<'a>, AsgConvertError> {
let variable = if value.name == "input" {
let variable = if value.name.as_ref() == "input" {
if let Some(function) = scope.resolve_current_function() {
if !function.has_input {
return Err(AsgConvertError::unresolved_reference(&value.name, &value.span));

View File

@ -40,7 +40,7 @@ impl<'a> Input<'a> {
fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> {
scope.context.alloc_circuit(Circuit {
id: scope.context.get_id(),
name: RefCell::new(Identifier::new(name.to_string())),
name: RefCell::new(Identifier::new(name.into())),
members: RefCell::new(IndexMap::new()),
core_mapping: RefCell::new(None),
scope,
@ -69,7 +69,7 @@ impl<'a> Input<'a> {
let container_circuit = input_scope.context.alloc_circuit(Circuit {
id: scope.context.get_id(),
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.to_string())),
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.into())),
members: RefCell::new(container_members),
core_mapping: RefCell::new(None),
scope: input_scope,
@ -84,7 +84,7 @@ impl<'a> Input<'a> {
container_circuit,
container: input_scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
id: scope.context.get_id(),
name: Identifier::new("input".to_string()),
name: Identifier::new("input".into()),
type_: Type::Circuit(container_circuit),
mutable: false,
const_: false,

View File

@ -69,7 +69,7 @@ impl<'a> Circuit<'a> {
let mut members = circuit.members.borrow_mut();
for member in value.members.iter() {
if let leo_ast::CircuitMember::CircuitVariable(name, type_) = member {
if members.contains_key(&name.name) {
if members.contains_key(name.name.as_ref()) {
return Err(AsgConvertError::redefined_circuit_member(
&value.circuit_name.name,
&name.name,
@ -77,7 +77,7 @@ impl<'a> Circuit<'a> {
));
}
members.insert(
name.name.clone(),
name.name.to_string(),
CircuitMember::Variable(new_scope.resolve_ast_type(type_)?),
);
}
@ -93,13 +93,13 @@ impl<'a> Circuit<'a> {
let new_scope = scope.make_subscope();
let circuits = scope.circuits.borrow();
let circuit = circuits.get(&value.circuit_name.name).unwrap();
let circuit = circuits.get(value.circuit_name.name.as_ref()).unwrap();
new_scope.circuit_self.replace(Some(circuit));
let mut members = circuit.members.borrow_mut();
for member in value.members.iter() {
if let leo_ast::CircuitMember::CircuitFunction(function) = member {
if members.contains_key(&function.identifier.name) {
if members.contains_key(function.identifier.name.as_ref()) {
return Err(AsgConvertError::redefined_circuit_member(
&value.circuit_name.name,
&function.identifier.name,
@ -111,7 +111,10 @@ impl<'a> Circuit<'a> {
if asg_function.is_test() {
return Err(AsgConvertError::circuit_test_function(&function.identifier.span));
}
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
members.insert(
function.identifier.name.to_string(),
CircuitMember::Function(asg_function),
);
}
}
@ -126,7 +129,7 @@ impl<'a> Circuit<'a> {
let asg_function = match *self
.members
.borrow()
.get(&function.identifier.name)
.get(function.identifier.name.as_ref())
.expect("missing header for defined circuit function")
{
CircuitMember::Function(f) => f,
@ -148,7 +151,7 @@ impl<'a> Into<leo_ast::Circuit> for &Circuit<'a> {
.iter()
.map(|(name, member)| match &member {
CircuitMember::Variable(type_) => {
leo_ast::CircuitMember::CircuitVariable(Identifier::new(name.clone()), type_.into())
leo_ast::CircuitMember::CircuitVariable(Identifier::new((&**name).into()), type_.into())
}
CircuitMember::Function(func) => leo_ast::CircuitMember::CircuitFunction((*func).into()),
})

View File

@ -113,7 +113,7 @@ impl<'a> Function<'a> {
references: vec![],
assignments: vec![],
}));
arguments.insert(identifier.name.clone(), Cell::new(&*variable));
arguments.insert(identifier.name.to_string(), Cell::new(&*variable));
}
}
}
@ -144,7 +144,7 @@ impl<'a> Function<'a> {
let circuit = self.circuit.get();
let self_variable = self.scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
id: self.scope.context.get_id(),
name: Identifier::new("self".to_string()),
name: Identifier::new("self".into()),
type_: Type::Circuit(circuit.as_ref().unwrap()),
mutable: self.qualifier == FunctionQualifier::MutSelfRef,
const_: false,
@ -186,7 +186,7 @@ impl<'a> Function<'a> {
}
pub fn is_test(&self) -> bool {
self.annotations.iter().any(|x| x.name.name == "test")
self.annotations.iter().any(|x| x.name.name.as_ref() == "test")
}
}

View File

@ -75,11 +75,11 @@ fn resolve_import_package(
) {
match package_or_packages {
PackageOrPackages::Package(package) => {
package_segments.push(package.name.name.clone());
package_segments.push(package.name.name.to_string());
resolve_import_package_access(output, package_segments, &package.access);
}
PackageOrPackages::Packages(packages) => {
package_segments.push(packages.name.name.clone());
package_segments.push(packages.name.name.to_string());
for access in packages.accesses.clone() {
resolve_import_package_access(output, package_segments.clone(), &access);
}
@ -106,14 +106,14 @@ fn resolve_import_package_access(
PackageAccess::Symbol(symbol) => {
let span = symbol.symbol.span.clone();
let symbol = if let Some(alias) = symbol.alias.as_ref() {
ImportSymbol::Alias(symbol.symbol.name.clone(), alias.name.clone())
ImportSymbol::Alias(symbol.symbol.name.to_string(), alias.name.to_string())
} else {
ImportSymbol::Direct(symbol.symbol.name.clone())
ImportSymbol::Direct(symbol.symbol.name.to_string())
};
output.push((package_segments, symbol, span));
}
PackageAccess::Multiple(packages) => {
package_segments.push(packages.name.name.clone());
package_segments.push(packages.name.name.to_string());
for subaccess in packages.accesses.iter() {
resolve_import_package_access(output, package_segments.clone(), &subaccess);
}
@ -240,7 +240,7 @@ impl<'a> Program<'a> {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = Circuit::init(scope, circuit)?;
scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit);
scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit);
}
// Second pass for circuit members.
@ -248,35 +248,41 @@ impl<'a> Program<'a> {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = Circuit::init_member(scope, circuit)?;
scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit);
scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit);
}
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let function = Function::init(scope, function)?;
scope.functions.borrow_mut().insert(name.name.clone(), function);
scope.functions.borrow_mut().insert(name.name.to_string(), function);
}
// Load concrete definitions.
let mut functions = IndexMap::new();
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let asg_function = *scope.functions.borrow().get(&name.name).unwrap();
let asg_function = *scope.functions.borrow().get(name.name.as_ref()).unwrap();
asg_function.fill_from_ast(function)?;
functions.insert(name.name.clone(), asg_function);
let name = name.name.to_string();
if functions.contains_key(&name) {
return Err(AsgConvertError::duplicate_function_definition(&name, &function.span));
}
functions.insert(name, asg_function);
}
let mut circuits = IndexMap::new();
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = *scope.circuits.borrow().get(&name.name).unwrap();
let asg_circuit = *scope.circuits.borrow().get(name.name.as_ref()).unwrap();
asg_circuit.fill_from_ast(circuit)?;
circuits.insert(name.name.clone(), asg_circuit);
circuits.insert(name.name.to_string(), asg_circuit);
}
Ok(Program {
@ -338,7 +344,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
for (_, program) in all_programs.into_iter() {
for (name, circuit) in program.circuits.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
circuit.name.borrow_mut().name = identifier.clone();
circuit.name.borrow_mut().name = identifier.clone().into();
all_circuits.insert(identifier, *circuit);
}
for (name, function) in program.functions.iter() {
@ -347,7 +353,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
} else {
format!("{}{}", identifiers.next().unwrap(), name)
};
function.name.borrow_mut().name = identifier.clone();
function.name.borrow_mut().name = identifier.clone().into();
all_functions.insert(identifier, *function);
}
}
@ -358,7 +364,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
.iter()
.map(|(module, _)| leo_ast::ImportStatement {
package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package {
name: Identifier::new(module.clone()),
name: Identifier::new(module.clone().into()),
access: leo_ast::PackageAccess::Star(Span::default()),
span: Default::default(),
}),

View File

@ -74,6 +74,7 @@ pub trait ReconstructingReducerExpression<'a> {
left: Cell::new(left),
right: Cell::new(right),
span: input.span,
length: input.length,
})
}

View File

@ -194,7 +194,7 @@ impl<'a> Scope<'a> {
.map(|x| self.resolve_ast_type(x))
.collect::<Result<Vec<_>, AsgConvertError>>()?,
),
Circuit(name) if name.name == "Self" => Type::Circuit(
Circuit(name) if name.name.as_ref() == "Self" => Type::Circuit(
self.resolve_circuit_self()
.ok_or_else(|| AsgConvertError::unresolved_circuit(&name.name, &name.span))?,
),

View File

@ -69,7 +69,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
) -> Result<Self, AsgConvertError> {
let (name, span) = (&statement.assignee.identifier.name, &statement.assignee.identifier.span);
let variable = if name == "input" {
let variable = if name.as_ref() == "input" {
if let Some(function) = scope.resolve_current_function() {
if !function.has_input {
return Err(AsgConvertError::unresolved_reference(name, &span));
@ -188,7 +188,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
let circuit = circuit;
let members = circuit.members.borrow();
let member = members.get(&name.name).ok_or_else(|| {
let member = members.get(name.name.as_ref()).ok_or_else(|| {
AsgConvertError::unresolved_circuit_member(
&circuit.name.borrow().name,
&name.name,
@ -251,7 +251,7 @@ impl<'a> Into<leo_ast::AssignStatement> for &AssignStatement<'a> {
AssignAccess::ArrayIndex(index) => AstAssigneeAccess::ArrayIndex(index.get().into()),
AssignAccess::Tuple(index) => AstAssigneeAccess::Tuple(
leo_ast::PositiveNumber {
value: index.to_string(),
value: index.to_string().into(),
},
self.span.clone().unwrap_or_default(),
),

View File

@ -106,7 +106,7 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
scope
.variables
.borrow_mut()
.insert(variable.borrow().name.name.clone(), *variable);
.insert(variable.borrow().name.name.to_string(), *variable);
}
let statement = scope

View File

@ -85,7 +85,7 @@ impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> {
scope
.variables
.borrow_mut()
.insert(statement.variable.name.clone(), variable);
.insert(statement.variable.name.to_string(), variable);
let statement = scope.context.alloc_statement(Statement::Iteration(IterationStatement {
parent: Cell::new(None),

View File

@ -204,7 +204,9 @@ impl<'a> Into<leo_ast::Type> for &Type<'a> {
Integer(int_type) => leo_ast::Type::IntegerType(int_type.clone()),
Array(type_, len) => leo_ast::Type::Array(
Box::new(type_.as_ref().into()),
leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber { value: len.to_string() }]),
leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber {
value: len.to_string().into(),
}]),
),
Tuple(subtypes) => leo_ast::Type::Tuple(subtypes.iter().map(Into::into).collect()),
Circuit(circuit) => leo_ast::Type::Circuit(circuit.name.borrow().clone()),

View File

@ -1,6 +1,6 @@
[package]
name = "leo-ast"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Core AST of the Leo programming language"
homepage = "https://aleo.org"
@ -19,7 +19,7 @@ edition = "2018"
[dependencies.leo-input]
path = "../input"
version = "1.2.3"
version = "1.3.0"
[dependencies.indexmap]
version = "1.6.2"
@ -30,7 +30,7 @@ version = "2.0"
[dependencies.serde]
version = "1.0"
features = ["derive", "rc"]
features = [ "derive", "rc" ]
[dependencies.serde_json]
version = "1.0"
@ -41,6 +41,9 @@ version = "1.0"
[dependencies.thiserror]
version = "1.0"
[dependencies.tendril]
version = "0.4"
[dev-dependencies.criterion]
version = "0.3"

View File

@ -17,10 +17,12 @@
use crate::{Identifier, Span};
use serde::{Deserialize, Serialize};
use tendril::StrTendril;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Annotation {
pub span: Span,
pub name: Identifier,
pub arguments: Vec<String>,
#[serde(with = "crate::common::vec_tendril_json")]
pub arguments: Vec<StrTendril>,
}

View File

@ -26,18 +26,6 @@ use std::fmt;
pub struct ArrayDimensions(pub Vec<PositiveNumber>);
impl ArrayDimensions {
///
/// Creates a new `PositiveNumber` from the given `usize` and `Span`.
/// Appends the new `PositiveNumber` to the array dimensions.
///
pub fn push_usize(&mut self, number: usize) {
let positive_number = PositiveNumber {
value: number.to_string(),
};
self.0.push(positive_number)
}
///
/// Appends a vector of array dimensions to the self array dimensions.
///

View File

@ -16,6 +16,7 @@
use crate::Span;
use leo_input::common::Identifier as InputIdentifier;
use tendril::StrTendril;
use crate::Node;
use serde::{
@ -41,7 +42,7 @@ use std::{
/// to reflect the new struct instantiation.
#[derive(Clone)]
pub struct Identifier {
pub name: String,
pub name: StrTendril,
pub span: Span,
}
@ -56,7 +57,7 @@ impl Node for Identifier {
}
impl Identifier {
pub fn new(name: String) -> Self {
pub fn new(name: StrTendril) -> Self {
Self {
name,
span: Span::default(),
@ -65,24 +66,16 @@ impl Identifier {
pub fn new_with_span(name: &str, span: Span) -> Self {
Self {
name: name.to_owned(),
name: name.into(),
span,
}
}
pub fn is_self_type(&self) -> bool {
self.name == "Self"
}
pub fn is_self(&self) -> bool {
self.is_self_type() || self.name == "self"
}
}
impl<'ast> From<InputIdentifier<'ast>> for Identifier {
fn from(identifier: InputIdentifier<'ast>) -> Self {
Self {
name: identifier.value,
name: identifier.value.into(),
span: Span::from(identifier.span),
}
}
@ -123,7 +116,7 @@ impl Serialize for Identifier {
// Load the struct elements into a BTreeMap (to preserve serialized ordering of keys).
let mut key: BTreeMap<String, String> = BTreeMap::new();
key.insert("name".to_string(), self.name.clone());
key.insert("name".to_string(), self.name.to_string());
key.insert("span".to_string(), to_json_string(&self.span)?);
// Convert the serialized object into a string for use as a key.
@ -164,7 +157,10 @@ impl<'de> Deserialize<'de> for Identifier {
None => return Err(E::custom("missing 'span' in serialized Identifier struct")),
};
Ok(Identifier { name, span })
Ok(Identifier {
name: name.into(),
span,
})
}
}

View File

@ -40,3 +40,7 @@ pub use span::*;
pub mod spread_or_expression;
pub use spread_or_expression::*;
pub mod tendril_json;
pub mod vec_tendril_json;

View File

@ -18,11 +18,13 @@ use leo_input::values::PositiveNumber as InputPositiveNumber;
use serde::{Deserialize, Serialize};
use std::fmt;
use tendril::StrTendril;
/// A number string guaranteed to be positive by the pest grammar.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
pub struct PositiveNumber {
pub value: String,
#[serde(with = "crate::common::tendril_json")]
pub value: StrTendril,
}
impl PositiveNumber {
@ -30,14 +32,16 @@ impl PositiveNumber {
/// Returns `true` if this number is zero.
///
pub fn is_zero(&self) -> bool {
self.value.eq("0")
self.value.as_ref().eq("0")
}
}
/// Create a new [`PositiveNumber`] from an [`InputPositiveNumber`] in a Leo input file.
impl<'ast> From<InputPositiveNumber<'ast>> for PositiveNumber {
fn from(array: InputPositiveNumber<'ast>) -> Self {
Self { value: array.value }
Self {
value: array.value.into(),
}
}
}

View File

@ -14,9 +14,10 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::{fmt, rc::Rc};
use std::{fmt, sync::Arc};
use serde::{Deserialize, Serialize};
use tendril::StrTendril;
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Span {
@ -24,7 +25,9 @@ pub struct Span {
pub line_stop: usize,
pub col_start: usize,
pub col_stop: usize,
pub path: Rc<String>,
pub path: Arc<String>,
#[serde(with = "crate::common::tendril_json")]
pub content: StrTendril,
}
impl fmt::Display for Span {
@ -51,7 +54,8 @@ impl<'ast> From<pest::Span<'ast>> for Span {
line_stop: end.0,
col_start: start.1,
col_stop: end.1,
path: Rc::new(String::new()),
path: Arc::new(String::new()),
content: span.as_str().into(),
}
}
}
@ -76,22 +80,40 @@ impl std::ops::Add for Span {
col_start: self.col_start.min(other.col_start),
col_stop: self.col_stop.max(other.col_stop),
path: self.path,
}
} else if self.line_start < other.line_stop {
Span {
line_start: self.line_start,
line_stop: other.line_stop,
col_start: self.col_start,
col_stop: other.col_stop,
path: self.path,
content: self.content,
}
} else {
Span {
line_start: other.line_start,
line_stop: self.line_stop,
col_start: other.col_start,
col_stop: self.col_stop,
path: self.path,
let mut new_content = vec![];
let self_lines = self.content.lines().collect::<Vec<_>>();
let other_lines = other.content.lines().collect::<Vec<_>>();
for line in self.line_start.min(other.line_start)..self.line_stop.max(other.line_stop) + 1 {
if line >= self.line_start && line <= self.line_stop {
new_content.push(self_lines.get(line - self.line_start).copied().unwrap_or_default());
} else if line >= other.line_start && line <= other.line_stop {
new_content.push(other_lines.get(line - other.line_start).copied().unwrap_or_default());
} else if new_content.last().map(|x| *x != "...").unwrap_or(true) {
new_content.push("...");
}
}
let new_content = new_content.join("\n").into();
if self.line_start < other.line_stop {
Span {
line_start: self.line_start,
line_stop: other.line_stop,
col_start: self.col_start,
col_stop: other.col_stop,
path: self.path,
content: new_content,
}
} else {
Span {
line_start: other.line_start,
line_stop: self.line_stop,
col_start: other.col_start,
col_stop: self.col_stop,
path: self.path,
content: new_content,
}
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use serde::{Deserialize, Deserializer, Serializer};
use tendril::StrTendril;
pub fn serialize<S: Serializer>(tendril: &StrTendril, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&tendril[..])
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<StrTendril, D::Error> {
Ok(String::deserialize(deserializer)?.into())
}

View File

@ -0,0 +1,34 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use tendril::StrTendril;
#[allow(clippy::ptr_arg)]
pub fn serialize<S: Serializer>(tendril: &Vec<StrTendril>, serializer: S) -> Result<S::Ok, S::Error> {
tendril
.iter()
.map(|x| x.as_ref())
.collect::<Vec<_>>()
.serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<StrTendril>, D::Error> {
Ok(Vec::<String>::deserialize(deserializer)?
.into_iter()
.map(|x| x.into())
.collect())
}

View File

@ -16,12 +16,12 @@
use crate::{LeoError, Span};
use std::fmt;
use std::{fmt, sync::Arc};
pub const INDENT: &str = " ";
/// Formatted compiler error type
/// --> file.leo 2:8
/// --> file.leo: 2:8
/// |
/// 2 | let a = x;
/// | ^
@ -29,60 +29,30 @@ pub const INDENT: &str = " ";
/// = undefined value `x`
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct FormattedError {
/// File path where error occurred
pub path: Option<String>,
/// Line start number
pub line_start: usize,
/// Line end number
pub line_stop: usize,
/// Starting column
pub start: usize,
/// Ending column
pub end: usize,
/// Text of errored lines
pub text: Option<Vec<String>>,
/// Error explanation
pub col_start: usize,
pub col_stop: usize,
pub path: Arc<String>,
pub content: String,
pub message: String,
}
impl FormattedError {
pub fn new_from_span(message: String, span: &Span) -> Self {
Self {
path: None,
line_start: span.line_start,
line_stop: span.line_stop,
start: span.col_start,
end: span.col_stop,
text: None,
col_start: span.col_start,
col_stop: span.col_stop,
path: span.path.clone(),
content: span.content.to_string(),
message,
}
}
}
impl LeoError for FormattedError {
fn set_path(&mut self, path: &str, content: &[String]) {
self.path = Some(path.to_string());
if self.line_stop - 1 > content.len() {
self.text = Some(vec!["corrupt file".to_string()]);
return;
}
assert!(self.line_stop >= self.line_start);
// if self.line_stop == self.line_start {
// self.text = Some(vec![content[self.line_start - 1][self.start - 1..self.end - 1].to_string()]);
// } else {
self.text = Some(
content[self.line_start - 1..self.line_stop]
.iter()
.map(|x| x.to_string())
.collect(),
);
// }
}
fn get_path(&self) -> Option<&str> {
self.path.as_deref()
}
}
impl LeoError for FormattedError {}
fn underline(mut start: usize, mut end: usize) -> String {
if start > end {
@ -105,29 +75,26 @@ fn underline(mut start: usize, mut end: usize) -> String {
impl fmt::Display for FormattedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default();
let underline = underline(self.start - 1, self.end - 1);
let underline = underline(self.col_start - 1, self.col_stop - 1);
write!(
f,
"{indent }--> {path} {line_start}:{start}\n\
"{indent }--> {path}: {line_start}:{start}\n\
{indent } |\n",
indent = INDENT,
path = path,
path = &*self.path,
line_start = self.line_start,
start = self.start,
start = self.col_start,
)?;
if let Some(lines) = &self.text {
for (line_no, line) in lines.iter().enumerate() {
writeln!(
f,
"{line_no:width$} | {text}",
width = INDENT.len(),
line_no = self.line_start + line_no,
text = line,
)?;
}
for (line_no, line) in self.content.lines().enumerate() {
writeln!(
f,
"{line_no:width$} | {text}",
width = INDENT.len(),
line_no = self.line_start + line_no,
text = line,
)?;
}
write!(
@ -151,12 +118,12 @@ impl std::error::Error for FormattedError {
#[test]
fn test_error() {
let err = FormattedError {
path: Some("file.leo".to_string()),
path: std::sync::Arc::new("file.leo".to_string()),
line_start: 2,
line_stop: 2,
start: 8,
end: 9,
text: Some(vec!["let a = x;".to_string()]),
col_start: 8,
col_stop: 9,
content: "let a = x;".into(),
message: "undefined value `x`".to_string(),
};

View File

@ -17,8 +17,4 @@
pub mod error;
pub use error::*;
pub trait LeoError {
fn get_path(&self) -> Option<&str>;
fn set_path(&mut self, path: &str, contents: &[String]);
}
pub trait LeoError {}

View File

@ -14,18 +14,24 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use tendril::StrTendril;
use super::*;
use crate::GroupTuple;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ValueExpression {
// todo: deserialize values here
Address(String, Span),
Boolean(String, Span),
Field(String, Span),
Address(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
Boolean(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
Field(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
Group(Box<GroupValue>),
Implicit(String, Span),
Integer(IntegerType, String, Span),
Implicit(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
Integer(
IntegerType,
#[serde(with = "crate::common::tendril_json")] StrTendril,
Span,
),
}
impl fmt::Display for ValueExpression {

View File

@ -25,10 +25,11 @@ use leo_input::values::{
use serde::{Deserialize, Serialize};
use std::fmt;
use tendril::StrTendril;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum GroupCoordinate {
Number(String, Span),
Number(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
SignHigh,
SignLow,
Inferred,
@ -61,7 +62,7 @@ impl<'ast> From<InputNumberValue<'ast>> for GroupCoordinate {
let value = number.to_string();
let span = Span::from(number.span().clone());
GroupCoordinate::Number(value, span)
GroupCoordinate::Number(value.into(), span)
}
}

View File

@ -23,10 +23,11 @@ use leo_input::values::{
use serde::{Deserialize, Serialize};
use std::fmt;
use tendril::StrTendril;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum GroupValue {
Single(String, Span),
Single(#[serde(with = "crate::common::tendril_json")] StrTendril, Span),
Tuple(GroupTuple),
}
@ -51,7 +52,7 @@ impl<'ast> From<InputGroupValue<'ast>> for GroupValue {
let span = Span::from(ast_group.span);
match ast_group.value {
InputGroupRepresentation::Single(number) => GroupValue::Single(number.to_string(), span),
InputGroupRepresentation::Single(number) => GroupValue::Single(number.to_string().into(), span),
InputGroupRepresentation::Tuple(tuple) => GroupValue::Tuple(GroupTuple::from(tuple)),
}
}

View File

@ -51,7 +51,7 @@ impl ImportSymbol {
pub fn star(span: &Span) -> Self {
Self {
symbol: Identifier {
name: "*".to_string(),
name: "*".into(),
span: span.clone(),
},
alias: None,
@ -60,6 +60,6 @@ impl ImportSymbol {
}
pub fn is_star(&self) -> bool {
self.symbol.name.eq("*")
self.symbol.name.as_ref().eq("*")
}
}

View File

@ -96,13 +96,13 @@ impl Input {
/// Returns the main function input value with the given `name`.
#[allow(clippy::ptr_arg)]
pub fn get(&self, name: &String) -> Option<Option<InputValue>> {
pub fn get(&self, name: &str) -> Option<Option<InputValue>> {
self.program_input.get(name)
}
/// Returns the constant input value with the given `name`.
#[allow(clippy::ptr_arg)]
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
pub fn get_constant(&self, name: &str) -> Option<Option<InputValue>> {
self.program_input.get_constant(name)
}

View File

@ -74,12 +74,12 @@ impl ProgramInput {
/// Returns the main function input value with the given `name`
#[allow(clippy::ptr_arg)]
pub fn get(&self, name: &String) -> Option<Option<InputValue>> {
pub fn get(&self, name: &str) -> Option<Option<InputValue>> {
self.main.get(name)
}
#[allow(clippy::ptr_arg)]
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
pub fn get_constant(&self, name: &str) -> Option<Option<InputValue>> {
self.constants.get(name)
}

View File

@ -171,7 +171,7 @@ impl Canonicalizer {
Expression::CircuitInit(circuit_init) => {
let mut name = circuit_init.name.clone();
if name.name == *"Self" {
if name.name.as_ref() == "Self" {
name = self.circuit_name.as_ref().unwrap().clone();
}
@ -470,7 +470,35 @@ impl ReconstructingReducer for Canonicalizer {
) -> Result<AssignStatement, CanonicalizeError> {
match value {
Expression::Value(value_expr) if assign.operation != AssignOperation::Assign => {
let left = Box::new(Expression::Identifier(assignee.identifier.clone()));
let mut left = Box::new(Expression::Identifier(assignee.identifier.clone()));
for access in assignee.accesses.iter().rev() {
match self.canonicalize_assignee_access(&access) {
AssigneeAccess::ArrayIndex(index) => {
left = Box::new(Expression::ArrayAccess(ArrayAccessExpression {
array: left,
index: Box::new(index),
span: assign.span.clone(),
}));
}
AssigneeAccess::Tuple(positive_number, _) => {
left = Box::new(Expression::TupleAccess(TupleAccessExpression {
tuple: left,
index: positive_number,
span: assign.span.clone(),
}));
}
AssigneeAccess::Member(identifier) => {
left = Box::new(Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
circuit: left,
name: identifier,
span: assign.span.clone(),
}));
}
_ => unimplemented!(), // No reason for someone to compute ArrayRanges.
}
}
let right = Box::new(Expression::Value(value_expr));
let op = match assign.operation {

View File

@ -18,10 +18,11 @@ use crate::{Expression, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
use tendril::StrTendril;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum FormattedStringPart {
Const(String),
Const(#[serde(with = "crate::common::tendril_json")] StrTendril),
Container,
}

View File

@ -1,6 +1,6 @@
[package]
name = "leo-compiler"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Compiler of the Leo programming language"
homepage = "https://aleo.org"
@ -19,58 +19,58 @@ edition = "2018"
[dependencies.leo-ast]
path = "../ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-imports]
path = "../imports"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-input]
path = "../input"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-package]
path = "../package"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-state]
path = "../state"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-asg]
path = "../asg"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-parser]
path = "../parser"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-asg-passes]
path = "../asg-passes"
version = "1.2.3"
version = "1.3.0"
[dependencies.snarkvm-curves]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-fields]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-dpc]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-gadgets]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-r1cs]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dependencies.snarkvm-utilities]
version = "0.2.1"
version = "0.2.2"
[dependencies.bincode]
version = "1.3"
@ -111,9 +111,12 @@ version = "0.3"
default-features = false
[dev-dependencies.snarkvm-algorithms]
version = "0.2.1"
version = "0.2.2"
default-features = false
[dev-dependencies.tempfile]
version = "3.0.4"
[features]
default = [ ]
ci_skip = [ "leo-ast/ci_skip" ]

View File

@ -24,10 +24,9 @@ use crate::{
OutputBytes,
OutputFile,
};
use indexmap::IndexMap;
pub use leo_asg::{new_context, AsgContext as Context, AsgContext};
use leo_asg::{Asg, AsgPass, FormattedError, Program as AsgProgram};
use leo_ast::{Input, LeoError, MainInput, Program as AstProgram};
use leo_ast::{Input, MainInput, Program as AstProgram};
use leo_input::LeoInputParser;
use leo_package::inputs::InputPairs;
use leo_parser::parse_ast;
@ -39,11 +38,9 @@ use snarkvm_r1cs::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
use sha2::{Digest, Sha256};
use std::{
cell::RefCell,
fs,
marker::PhantomData,
path::{Path, PathBuf},
rc::Rc,
};
thread_local! {
@ -68,7 +65,6 @@ pub struct Compiler<'a, F: PrimeField, G: GroupType<F>> {
program_input: Input,
context: AsgContext<'a>,
asg: Option<AsgProgram<'a>>,
file_contents: RefCell<IndexMap<String, Rc<Vec<String>>>>,
options: CompilerOptions,
_engine: PhantomData<F>,
_group: PhantomData<G>,
@ -94,7 +90,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
asg: None,
context,
options: options.unwrap_or_default(),
file_contents: RefCell::new(IndexMap::new()),
_engine: PhantomData,
_group: PhantomData,
}
@ -203,20 +198,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
Ok(())
}
fn resolve_content(&self, path: &str) -> Result<Rc<Vec<String>>, CompilerError> {
let mut file_contents = self.file_contents.borrow_mut();
if file_contents.contains_key(path) {
// using this pattern because of mutable reference in branch below
Ok(file_contents.get(path).unwrap().clone())
} else {
let content = fs::read_to_string(path).map_err(|e| CompilerError::FileReadError(PathBuf::from(path), e))?;
let content = Rc::new(content.lines().map(|x| x.to_string()).collect::<Vec<String>>());
file_contents.insert(path.to_string(), content);
Ok(file_contents.get(path).unwrap().clone())
}
}
///
/// Parses and stores the main program file, constructs a syntax tree, and generates a program.
///
@ -227,31 +208,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
let content = fs::read_to_string(&self.main_file_path)
.map_err(|e| CompilerError::FileReadError(self.main_file_path.clone(), e))?;
self.parse_program_from_string(&content).map_err(|mut error| {
// Return a formatted error with file path and code text.
let path = match error.get_path().map(|x| x.to_string()) {
// Get the file path if it exists
Some(path) => path,
// If a file path does not exist, then insert the main file path.
None => match self.main_file_path.clone().into_os_string().into_string() {
Err(e) => return CompilerError::FileStringError(e),
Ok(path) => path,
},
};
// Resolve the code text using the file path.
let content = match self.resolve_content(&path) {
Err(e) => return e,
Ok(x) => x,
};
// Update the formatted error.
error.set_path(&path, &content[..]);
error
})
self.parse_program_from_string(&content)
}
///
@ -260,11 +217,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
///
pub fn parse_program_from_string(&mut self, program_string: &str) -> Result<(), CompilerError> {
// Use the parser to construct the abstract syntax tree (ast).
let lines = program_string.lines().map(|x| x.to_string()).collect();
self.file_contents.borrow_mut().insert(
self.main_file_path.to_str().map(|x| x.to_string()).unwrap_or_default(),
Rc::new(lines),
);
let mut ast = parse_ast(self.main_file_path.to_str().unwrap_or_default(), program_string)?;
// Preform compiler optimization via canonicalizing AST if its enabled.
@ -316,28 +268,14 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
/// Synthesizes the circuit with program input to verify correctness.
///
pub fn compile_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
generate_constraints::<F, G, CS>(cs, &self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
if let Some(path) = error.get_path().map(|x| x.to_string()) {
let content = match self.resolve_content(&path) {
Err(e) => return e,
Ok(x) => x,
};
error.set_path(&path, &content[..]);
}
error
})
generate_constraints::<F, G, CS>(cs, &self.asg.as_ref().unwrap(), &self.program_input)
}
///
/// Synthesizes the circuit for test functions with program input.
///
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
generate_test_constraints::<F, G>(
&self.asg.as_ref().unwrap(),
input_pairs,
&self.main_file_path,
&self.output_directory,
)
generate_test_constraints::<F, G>(&self.asg.as_ref().unwrap(), input_pairs, &self.output_directory)
}
///

View File

@ -18,7 +18,7 @@
use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile};
use leo_asg::Program;
use leo_ast::{Input, LeoError};
use leo_ast::Input;
use leo_input::LeoInputParser;
use leo_package::inputs::InputPairs;
@ -50,7 +50,6 @@ pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSy
pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
program: &Program<'a>,
input: InputPairs,
main_file_path: &Path,
output_directory: &Path,
) -> Result<(u32, u32), CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
@ -78,7 +77,7 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
let input_file = function
.annotations
.iter()
.find(|x| x.name.name == "test")
.find(|x| x.name.name.as_ref() == "test")
.unwrap()
.arguments
.get(0);
@ -87,11 +86,11 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
Some(file_id) => {
let file_name = file_id.clone();
output_file_name = file_name.clone();
output_file_name = file_name.to_string();
match input.pairs.get(&file_name) {
match input.pairs.get(file_name.as_ref()) {
Some(pair) => pair.to_owned(),
None => return Err(CompilerError::InvalidTestContext(file_name)),
None => return Err(CompilerError::InvalidTestContext(file_name.to_string())),
}
}
None => default.ok_or(CompilerError::NoTestInput)?,
@ -135,8 +134,7 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
}
(false, _) => {
// Set file location of error
let mut error = result.unwrap_err();
error.set_path(main_file_path.to_str().unwrap_or_default(), &[]);
let error = result.unwrap_err();
tracing::error!("{} failed due to error\n\n{}\n", full_test_name, error);

View File

@ -14,16 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError};
use crate::errors::FunctionError;
use leo_asg::{AsgConvertError, FormattedError};
use leo_ast::{CanonicalizeError, LeoError};
use leo_imports::ImportParserError;
use leo_input::InputParserError;
use leo_parser::SyntaxError;
use leo_state::LocalDataVerificationError;
use bincode::Error as SerdeError;
use std::{ffi::OsString, path::PathBuf};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum CompilerError {
@ -33,12 +31,6 @@ pub enum CompilerError {
#[error("{}", _0)]
AsgPassError(FormattedError),
#[error("{}", _0)]
ImportError(#[from] ImportError),
#[error("{}", _0)]
ImportParserError(#[from] ImportParserError),
#[error("{}", _0)]
InputParserError(#[from] InputParserError),
@ -51,30 +43,15 @@ pub enum CompilerError {
#[error("Cannot read from the provided file path '{:?}': {}", _0, _1)]
FileReadError(PathBuf, std::io::Error),
#[error("Cannot parse file string `{:?}`", _0)]
FileStringError(OsString),
#[error("{}", _0)]
LocalDataVerificationError(#[from] LocalDataVerificationError),
#[error("`main` function not found")]
NoMain,
#[error("`main` must be a function")]
NoMainFunction,
#[error("Failed to find input files for the current test")]
NoTestInput,
#[error("{}", _0)]
OutputError(#[from] OutputFileError),
#[error("{}", _0)]
OutputStringError(#[from] OutputBytesError),
#[error("{}", _0)]
SerdeError(#[from] SerdeError),
#[error("{}", _0)]
AsgConvertError(#[from] AsgConvertError),
@ -82,30 +59,4 @@ pub enum CompilerError {
CanonicalizeError(#[from] CanonicalizeError),
}
impl LeoError for CompilerError {
fn get_path(&self) -> Option<&str> {
match self {
CompilerError::SyntaxError(error) => error.get_path(),
CompilerError::ImportError(error) => error.get_path(),
CompilerError::ImportParserError(error) => error.get_path(),
CompilerError::InputParserError(error) => error.get_path(),
CompilerError::FunctionError(error) => error.get_path(),
CompilerError::OutputStringError(error) => error.get_path(),
CompilerError::AsgConvertError(error) => error.get_path(),
_ => None,
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
CompilerError::SyntaxError(error) => error.set_path(path, contents),
CompilerError::ImportError(error) => error.set_path(path, contents),
CompilerError::ImportParserError(error) => error.set_path(path, contents),
CompilerError::InputParserError(error) => error.set_path(path, contents),
CompilerError::FunctionError(error) => error.set_path(path, contents),
CompilerError::OutputStringError(error) => error.set_path(path, contents),
CompilerError::AsgConvertError(error) => error.set_path(path, contents),
_ => {}
}
}
}
impl LeoError for CompilerError {}

View File

@ -26,21 +26,7 @@ pub enum ConsoleError {
Expression(#[from] ExpressionError),
}
impl LeoError for ConsoleError {
fn get_path(&self) -> Option<&str> {
match self {
ConsoleError::Error(error) => error.get_path(),
ConsoleError::Expression(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
ConsoleError::Error(error) => error.set_path(path, contents),
ConsoleError::Expression(error) => error.set_path(path, contents),
}
}
}
impl LeoError for ConsoleError {}
impl ConsoleError {
fn new_from_span(message: String, span: &Span) -> Self {

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
use leo_ast::{ArrayDimensions, FormattedError, Identifier, LeoError, PositiveNumber, Span};
use leo_ast::{FormattedError, Identifier, LeoError, Span};
use snarkvm_r1cs::SynthesisError;
#[derive(Debug, Error)]
@ -45,33 +45,7 @@ pub enum ExpressionError {
ValueError(#[from] ValueError),
}
impl LeoError for ExpressionError {
fn get_path(&self) -> Option<&str> {
match self {
ExpressionError::AddressError(error) => error.get_path(),
ExpressionError::BooleanError(error) => error.get_path(),
ExpressionError::Error(error) => error.get_path(),
ExpressionError::FieldError(error) => error.get_path(),
ExpressionError::FunctionError(error) => error.get_path(),
ExpressionError::GroupError(error) => error.get_path(),
ExpressionError::IntegerError(error) => error.get_path(),
ExpressionError::ValueError(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
ExpressionError::AddressError(error) => error.set_path(path, contents),
ExpressionError::BooleanError(error) => error.set_path(path, contents),
ExpressionError::Error(error) => error.set_path(path, contents),
ExpressionError::FieldError(error) => error.set_path(path, contents),
ExpressionError::FunctionError(error) => error.set_path(path, contents),
ExpressionError::GroupError(error) => error.set_path(path, contents),
ExpressionError::IntegerError(error) => error.set_path(path, contents),
ExpressionError::ValueError(error) => error.set_path(path, contents),
}
}
}
impl LeoError for ExpressionError {}
impl ExpressionError {
fn new_from_span(message: String, span: &Span) -> Self {
@ -93,6 +67,18 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn array_length_out_of_bounds(span: &Span) -> Self {
let message = "array length cannot be >= 2^32".to_string();
Self::new_from_span(message, span)
}
pub fn array_index_out_of_legal_bounds(span: &Span) -> Self {
let message = "array index cannot be >= 2^32".to_string();
Self::new_from_span(message, span)
}
pub fn conditional_boolean(actual: String, span: &Span) -> Self {
let message = format!("if, else conditional must resolve to a boolean, found `{}`", actual);
@ -111,26 +97,20 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn index_out_of_bounds(index: usize, span: &Span) -> Self {
pub fn tuple_index_out_of_bounds(index: usize, span: &Span) -> Self {
let message = format!("cannot access index {} of tuple out of bounds", index);
Self::new_from_span(message, span)
}
pub fn invalid_dimensions(expected: &ArrayDimensions, actual: &ArrayDimensions, span: &Span) -> Self {
let message = format!(
"expected array dimensions {}, found array dimensions {}",
expected, actual
);
pub fn array_index_out_of_bounds(index: usize, span: &Span) -> Self {
let message = format!("cannot access index {} of array out of bounds", index);
Self::new_from_span(message, span)
}
pub fn invalid_first_dimension(expected: &PositiveNumber, actual: &PositiveNumber, span: &Span) -> Self {
let message = format!(
"expected array dimension {}, found array dimension {}",
expected, actual
);
pub fn array_invalid_slice_length(span: &Span) -> Self {
let message = "illegal length of slice".to_string();
Self::new_from_span(message, span)
}
@ -147,48 +127,18 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn invalid_spread(actual: String, span: &Span) -> Self {
let message = format!("spread should contain an array, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn invalid_member_access(member: String, span: &Span) -> Self {
let message = format!("non-static member `{}` must be accessed using `.` syntax", member);
Self::new_from_span(message, span)
}
pub fn invalid_static_access(member: String, span: &Span) -> Self {
let message = format!("static member `{}` must be accessed using `::` syntax", member);
Self::new_from_span(message, span)
}
pub fn function_no_return(function: String, span: &Span) -> Self {
let message = format!("inline function call to `{}` did not return", function);
Self::new_from_span(message, span)
}
pub fn self_keyword(span: &Span) -> Self {
let message = "cannot call keyword `Self` outside of a circuit function".to_string();
Self::new_from_span(message, span)
}
pub fn undefined_array(actual: String, span: &Span) -> Self {
let message = format!("array `{}` must be declared before it is used in an expression", actual);
Self::new_from_span(message, span)
}
pub fn undefined_tuple(actual: String, span: &Span) -> Self {
let message = format!("tuple `{}` must be declared before it is used in an expression", actual);
Self::new_from_span(message, span)
}
pub fn undefined_circuit(actual: String, span: &Span) -> Self {
let message = format!(
"circuit `{}` must be declared before it is used in an expression",
@ -198,21 +148,6 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn undefined_first_dimension(span: &Span) -> Self {
let message = "the first dimension of the array must be a number".to_string();
Self::new_from_span(message, span)
}
pub fn undefined_function(function: String, span: &Span) -> Self {
let message = format!(
"function `{}` must be declared before it is used in an inline expression",
function
);
Self::new_from_span(message, span)
}
pub fn undefined_identifier(identifier: Identifier) -> Self {
let message = format!("Cannot find value `{}` in this scope", identifier.name);
@ -224,22 +159,4 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn undefined_static_access(circuit: String, member: String, span: &Span) -> Self {
let message = format!("Circuit `{}` has no static member `{}`", circuit, member);
Self::new_from_span(message, span)
}
pub fn unexpected_array(expected: String, span: &Span) -> Self {
let message = format!("expected type `{}`, found array with elements", expected);
Self::new_from_span(message, span)
}
pub fn unexpected_tuple(expected: String, actual: String, span: &Span) -> Self {
let message = format!("expected type `{}`, found tuple with values `{}`", expected, actual);
Self::new_from_span(message, span)
}
}

View File

@ -64,39 +64,7 @@ pub enum FunctionError {
ImportASGError(#[from] AsgConvertError),
}
impl LeoError for FunctionError {
fn get_path(&self) -> Option<&str> {
match self {
FunctionError::AddressError(error) => error.get_path(),
FunctionError::BooleanError(error) => error.get_path(),
FunctionError::ExpressionError(error) => error.get_path(),
FunctionError::Error(error) => error.get_path(),
FunctionError::FieldError(error) => error.get_path(),
FunctionError::GroupError(error) => error.get_path(),
FunctionError::IntegerError(error) => error.get_path(),
FunctionError::OutputStringError(error) => error.get_path(),
FunctionError::StatementError(error) => error.get_path(),
FunctionError::ValueError(error) => error.get_path(),
FunctionError::ImportASGError(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
FunctionError::AddressError(error) => error.set_path(path, contents),
FunctionError::BooleanError(error) => error.set_path(path, contents),
FunctionError::ExpressionError(error) => error.set_path(path, contents),
FunctionError::Error(error) => error.set_path(path, contents),
FunctionError::FieldError(error) => error.set_path(path, contents),
FunctionError::GroupError(error) => error.set_path(path, contents),
FunctionError::IntegerError(error) => error.set_path(path, contents),
FunctionError::OutputStringError(error) => error.set_path(path, contents),
FunctionError::StatementError(error) => error.set_path(path, contents),
FunctionError::ValueError(error) => error.set_path(path, contents),
FunctionError::ImportASGError(error) => error.set_path(path, contents),
}
}
}
impl LeoError for FunctionError {}
impl FunctionError {
fn new_from_span(message: String, span: &Span) -> Self {
@ -160,18 +128,6 @@ impl FunctionError {
Self::new_from_span(message, span)
}
pub fn return_arguments_length(expected: usize, actual: usize, span: &Span) -> Self {
let message = format!("function expected {} returns, found {} returns", expected, actual);
Self::new_from_span(message, span)
}
pub fn return_argument_type(expected: String, actual: String, span: &Span) -> Self {
let message = format!("Expected function return type `{}`, found `{}`", expected, actual);
Self::new_from_span(message, span)
}
pub fn input_not_found(expected: String, span: &Span) -> Self {
let message = format!("main function input {} not found", expected);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::{FormattedError, Identifier, ImportSymbol, LeoError, Span};
use leo_ast::{FormattedError, LeoError};
#[derive(Debug, Error)]
pub enum ImportError {
@ -22,38 +22,4 @@ pub enum ImportError {
Error(#[from] FormattedError),
}
impl LeoError for ImportError {
fn get_path(&self) -> Option<&str> {
match self {
ImportError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
ImportError::Error(error) => error.set_path(path, contents),
}
}
}
impl ImportError {
fn new_from_span(message: String, span: &Span) -> Self {
ImportError::Error(FormattedError::new_from_span(message, span))
}
pub fn unknown_package(identifier: Identifier) -> Self {
let message = format!(
"cannot find imported package `{}` in source files or import directory",
identifier.name
);
Self::new_from_span(message, &identifier.span)
}
pub fn unknown_symbol(symbol: ImportSymbol, file: String) -> Self {
let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file);
let error = FormattedError::new_from_span(message, &symbol.span);
ImportError::Error(error)
}
}
impl LeoError for ImportError {}

View File

@ -30,23 +30,7 @@ pub enum OutputBytesError {
AsgConvertError(#[from] AsgConvertError),
}
impl LeoError for OutputBytesError {
fn get_path(&self) -> Option<&str> {
match self {
OutputBytesError::Error(error) => error.get_path(),
OutputBytesError::ValueError(error) => error.get_path(),
OutputBytesError::AsgConvertError(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
OutputBytesError::Error(error) => error.set_path(path, contents),
OutputBytesError::ValueError(error) => error.set_path(path, contents),
OutputBytesError::AsgConvertError(error) => error.set_path(path, contents),
}
}
}
impl LeoError for OutputBytesError {}
impl OutputBytesError {
fn new_from_span(message: String, span: &Span) -> Self {

View File

@ -21,9 +21,6 @@ pub enum OutputFileError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("creating: {}", _0)]
Creating(io::Error),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),

View File

@ -42,45 +42,21 @@ pub enum StatementError {
ValueError(#[from] ValueError),
}
impl LeoError for StatementError {
fn get_path(&self) -> Option<&str> {
match self {
StatementError::AddressError(error) => error.get_path(),
StatementError::BooleanError(error) => error.get_path(),
StatementError::Error(error) => error.get_path(),
StatementError::ExpressionError(error) => error.get_path(),
StatementError::IntegerError(error) => error.get_path(),
StatementError::MacroError(error) => error.get_path(),
StatementError::ValueError(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
StatementError::AddressError(error) => error.set_path(path, contents),
StatementError::BooleanError(error) => error.set_path(path, contents),
StatementError::Error(error) => error.set_path(path, contents),
StatementError::ExpressionError(error) => error.set_path(path, contents),
StatementError::IntegerError(error) => error.set_path(path, contents),
StatementError::MacroError(error) => error.set_path(path, contents),
StatementError::ValueError(error) => error.set_path(path, contents),
}
}
}
impl LeoError for StatementError {}
impl StatementError {
fn new_from_span(message: String, span: &Span) -> Self {
StatementError::Error(FormattedError::new_from_span(message, span))
}
pub fn arguments_type(expected: &Type, actual: &Type, span: &Span) -> Self {
let message = format!("expected return argument type `{}`, found type `{}`", expected, actual);
pub fn array_assign_index(span: &Span) -> Self {
let message = "Cannot assign single index to array of values".to_string();
Self::new_from_span(message, span)
}
pub fn array_assign_index(span: &Span) -> Self {
let message = "Cannot assign single index to array of values".to_string();
pub fn array_assign_index_const(span: &Span) -> Self {
let message = "Cannot assign to non-const array index".to_string();
Self::new_from_span(message, span)
}
@ -121,24 +97,6 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn immutable_assign(name: String, span: &Span) -> Self {
let message = format!("Cannot assign to immutable variable `{}`", name);
Self::new_from_span(message, span)
}
pub fn immutable_circuit_function(name: String, span: &Span) -> Self {
let message = format!("Cannot mutate circuit function, `{}`", name);
Self::new_from_span(message, span)
}
pub fn immutable_circuit_variable(name: String, span: &Span) -> Self {
let message = format!("Circuit member variable `{}` is immutable", name);
Self::new_from_span(message, span)
}
pub fn indicator_calculation(name: String, span: &Span) -> Self {
let message = format!(
"Constraint system failed to evaluate branch selection indicator `{}`",
@ -157,15 +115,6 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn invalid_number_of_returns(expected: usize, actual: usize, span: &Span) -> Self {
let message = format!(
"Function return statement expected {} return values, found {} values",
expected, actual
);
Self::new_from_span(message, span)
}
pub fn multiple_definition(value: String, span: &Span) -> Self {
let message = format!("cannot assign multiple variables to a single value: {}", value,);
@ -212,12 +161,6 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn tuple_type(type_: String, span: &Span) -> Self {
let message = format!("Expected tuple type, found type `{}`", type_);
Self::new_from_span(message, span)
}
pub fn unassigned(span: &Span) -> Self {
let message = "Expected assignment of return values for expression".to_string();
@ -241,4 +184,10 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn loop_index_const(span: &Span) -> Self {
let message = "iteration range must be const".to_string();
Self::new_from_span(message, span)
}
}

View File

@ -16,7 +16,6 @@
use leo_ast::{FormattedError, LeoError, Span};
use snarkvm_dpc::AccountError;
use snarkvm_r1cs::SynthesisError;
#[derive(Debug, Error)]
pub enum AddressError {
@ -24,19 +23,7 @@ pub enum AddressError {
Error(#[from] FormattedError),
}
impl LeoError for AddressError {
fn get_path(&self) -> Option<&str> {
match self {
AddressError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
AddressError::Error(error) => error.set_path(path, contents),
}
}
}
impl LeoError for AddressError {}
impl AddressError {
fn new_from_span(message: String, span: &Span) -> Self {
@ -49,21 +36,6 @@ impl AddressError {
Self::new_from_span(message, span)
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: &Span) -> Self {
let message = format!(
"the address operation `{:?}` failed due to the synthesis error `{}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn cannot_evaluate(operation: String, span: &Span) -> Self {
let message = format!("no implementation found for `{}`", operation);
Self::new_from_span(message, span)
}
pub fn invalid_address(actual: String, span: &Span) -> Self {
let message = format!("expected address input type, found `{}`", actual);

View File

@ -23,19 +23,7 @@ pub enum BooleanError {
Error(#[from] FormattedError),
}
impl LeoError for BooleanError {
fn get_path(&self) -> Option<&str> {
match self {
BooleanError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
BooleanError::Error(error) => error.set_path(path, contents),
}
}
}
impl LeoError for BooleanError {}
impl BooleanError {
fn new_from_span(message: String, span: &Span) -> Self {

View File

@ -23,19 +23,7 @@ pub enum FieldError {
Error(#[from] FormattedError),
}
impl LeoError for FieldError {
fn get_path(&self) -> Option<&str> {
match self {
FieldError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
FieldError::Error(error) => error.set_path(path, contents),
}
}
}
impl LeoError for FieldError {}
impl FieldError {
fn new_from_span(message: String, span: &Span) -> Self {
@ -74,10 +62,4 @@ impl FieldError {
Self::new_from_span(message, span)
}
pub fn synthesis_error(error: SynthesisError, span: &Span) -> Self {
let message = format!("compilation failed due to field synthesis error `{:?}`", error);
Self::new_from_span(message, span)
}
}

View File

@ -23,19 +23,7 @@ pub enum GroupError {
Error(#[from] FormattedError),
}
impl LeoError for GroupError {
fn get_path(&self) -> Option<&str> {
match self {
GroupError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
GroupError::Error(error) => error.set_path(path, contents),
}
}
}
impl LeoError for GroupError {}
impl GroupError {
fn new_from_span(message: String, span: &Span) -> Self {

View File

@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::{FormattedError, IntegerType, LeoError, Span, Type};
use leo_ast::{FormattedError, LeoError, Span};
use snarkvm_gadgets::errors::SignedIntegerError;
use snarkvm_gadgets::errors::{SignedIntegerError, UnsignedIntegerError};
use snarkvm_r1cs::SynthesisError;
#[derive(Debug, Error)]
@ -25,44 +25,23 @@ pub enum IntegerError {
Error(#[from] FormattedError),
}
impl LeoError for IntegerError {
fn get_path(&self) -> Option<&str> {
match self {
IntegerError::Error(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
IntegerError::Error(error) => error.set_path(path, contents),
}
}
}
impl LeoError for IntegerError {}
impl IntegerError {
fn new_from_span(message: String, span: &Span) -> Self {
IntegerError::Error(FormattedError::new_from_span(message, span))
}
pub fn cannot_enforce(operation: String, error: SynthesisError, span: &Span) -> Self {
let message = format!(
"the integer operation `{}` failed due to the synthesis error `{:?}`",
operation, error,
);
Self::new_from_span(message, span)
}
pub fn signed(error: SignedIntegerError, span: &Span) -> Self {
let message = format!("integer operation failed due to the signed integer error `{:?}`", error);
Self::new_from_span(message, span)
}
pub fn signed_error(operation: String, error: SignedIntegerError, span: &Span) -> Self {
pub fn unsigned(error: UnsignedIntegerError, span: &Span) -> Self {
let message = format!(
"the integer operation `{}` failed due to the signed integer error `{:?}`",
operation, error
"integer operation failed due to the unsigned integer error `{:?}`",
error
);
Self::new_from_span(message, span)
@ -89,32 +68,12 @@ impl IntegerError {
Self::new_from_span(message, span)
}
pub fn invalid_index(span: &Span) -> Self {
let message =
"index must be a constant value unsigned integer. allocated indices produce a circuit of unknown size"
.to_string();
Self::new_from_span(message, span)
}
pub fn invalid_integer(actual: String, span: &Span) -> Self {
let message = format!("failed to parse `{}` as expected integer type", actual);
Self::new_from_span(message, span)
}
pub fn invalid_integer_type(expected: &IntegerType, actual: &IntegerType, span: &Span) -> Self {
let message = format!("expected integer type {} found integer type {}", expected, actual);
Self::new_from_span(message, span)
}
pub fn invalid_type(actual: &Type, span: &Span) -> Self {
let message = format!("expected type {}, found type IntegerType", actual);
Self::new_from_span(message, span)
}
pub fn missing_integer(expected: String, span: &Span) -> Self {
let message = format!("expected integer input `{}` not found", expected);

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::errors::{AddressError, BooleanError, FieldError, GroupError, IntegerError};
use leo_ast::{FormattedError, LeoError, Span};
use leo_ast::{FormattedError, LeoError};
#[derive(Debug, Error)]
pub enum ValueError {
@ -38,44 +38,4 @@ pub enum ValueError {
IntegerError(#[from] IntegerError),
}
impl LeoError for ValueError {
fn get_path(&self) -> Option<&str> {
match self {
ValueError::AddressError(error) => error.get_path(),
ValueError::BooleanError(error) => error.get_path(),
ValueError::Error(error) => error.get_path(),
ValueError::FieldError(error) => error.get_path(),
ValueError::GroupError(error) => error.get_path(),
ValueError::IntegerError(error) => error.get_path(),
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
ValueError::AddressError(error) => error.set_path(path, contents),
ValueError::BooleanError(error) => error.set_path(path, contents),
ValueError::Error(error) => error.set_path(path, contents),
ValueError::FieldError(error) => error.set_path(path, contents),
ValueError::GroupError(error) => error.set_path(path, contents),
ValueError::IntegerError(error) => error.set_path(path, contents),
}
}
}
impl ValueError {
fn new_from_span(message: String, span: &Span) -> Self {
ValueError::Error(FormattedError::new_from_span(message, span))
}
pub fn implicit(value: String, span: &Span) -> Self {
let message = format!("explicit type needed for `{}`", value);
Self::new_from_span(message, span)
}
pub fn implicit_group(span: &Span) -> Self {
let message = "group coordinates should be in (x, y)group format".to_string();
Self::new_from_span(message, span)
}
}
impl LeoError for ValueError {}

View File

@ -16,10 +16,24 @@
//! Enforces array access in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_asg::{Expression, Span};
use std::convert::TryInto;
use crate::{
arithmetic::*,
errors::ExpressionError,
program::ConstrainedProgram,
relational::*,
value::{ConstrainedValue, Integer},
GroupType,
};
use leo_asg::{ConstInt, Expression, Span};
use snarkvm_fields::PrimeField;
use snarkvm_gadgets::utilities::{
boolean::Boolean,
eq::{EqGadget, EvaluateEqGadget},
select::CondSelectGadget,
};
use snarkvm_r1cs::ConstraintSystem;
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
@ -31,13 +45,65 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
index: &'a Expression<'a>,
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
let array = match self.enforce_expression(cs, array)? {
let mut array = match self.enforce_expression(cs, array)? {
ConstrainedValue::Array(array) => array,
value => return Err(ExpressionError::undefined_array(value.to_string(), span)),
};
let index_resolved = self.enforce_index(cs, index, span)?;
Ok(array[index_resolved].to_owned())
if let Some(resolved) = index_resolved.to_usize() {
if resolved >= array.len() {
return Err(ExpressionError::array_index_out_of_bounds(resolved, span));
}
Ok(array[resolved].to_owned())
} else {
if array.is_empty() {
return Err(ExpressionError::array_index_out_of_bounds(0, span));
}
{
let array_len: u32 = array
.len()
.try_into()
.map_err(|_| ExpressionError::array_length_out_of_bounds(span))?;
let bounds_check = evaluate_lt::<F, G, CS>(
cs,
ConstrainedValue::Integer(index_resolved.clone()),
ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array_len))),
span,
)?;
let bounds_check = match bounds_check {
ConstrainedValue::Boolean(b) => b,
_ => unimplemented!("illegal non-Integer returned from lt"),
};
let namespace_string = format!("evaluate array access bounds {}:{}", span.line_start, span.col_start);
let mut unique_namespace = cs.ns(|| namespace_string);
bounds_check
.enforce_equal(&mut unique_namespace, &Boolean::Constant(true))
.map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?;
}
let mut current_value = array.pop().unwrap();
for (i, item) in array.into_iter().enumerate() {
let namespace_string = format!("evaluate array access eq {} {}:{}", i, span.line_start, span.col_start);
let eq_namespace = cs.ns(|| namespace_string);
let index_bounded = i
.try_into()
.map_err(|_| ExpressionError::array_index_out_of_legal_bounds(span))?;
let const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type());
let index_comparison = index_resolved
.evaluate_equal(eq_namespace, &Integer::new(&const_index))
.map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), span))?;
let unique_namespace =
cs.ns(|| format!("select array access {} {}:{}", i, span.line_start, span.col_start));
let value =
ConstrainedValue::conditionally_select(unique_namespace, &index_comparison, &item, &current_value)
.map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, span))?;
current_value = value;
}
Ok(current_value)
}
}
#[allow(clippy::too_many_arguments)]
@ -47,6 +113,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
array: &'a Expression<'a>,
left: Option<&'a Expression<'a>>,
right: Option<&'a Expression<'a>>,
length: usize,
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
let array = match self.enforce_expression(cs, array)? {
@ -56,12 +123,103 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let from_resolved = match left {
Some(from_index) => self.enforce_index(cs, from_index, span)?,
None => 0usize, // Array slice starts at index 0
None => Integer::new(&ConstInt::U32(0)), // Array slice starts at index 0
};
let to_resolved = match right {
Some(to_index) => self.enforce_index(cs, to_index, span)?,
None => array.len(), // Array slice ends at array length
None => {
let index_bounded: u32 = array
.len()
.try_into()
.map_err(|_| ExpressionError::array_length_out_of_bounds(span))?;
Integer::new(&ConstInt::U32(index_bounded))
} // Array slice ends at array length
};
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
let const_dimensions = match (from_resolved.to_usize(), to_resolved.to_usize()) {
(Some(from), Some(to)) => Some((from, to)),
(Some(from), None) => Some((from, from + length)),
(None, Some(to)) => Some((to - length, to)),
(None, None) => None,
};
Ok(if let Some((left, right)) = const_dimensions {
if right - left != length {
return Err(ExpressionError::array_invalid_slice_length(span));
}
if right > array.len() {
return Err(ExpressionError::array_index_out_of_bounds(right, span));
}
ConstrainedValue::Array(array[left..right].to_owned())
} else {
{
let calc_len = enforce_sub::<F, G, _>(
cs,
ConstrainedValue::Integer(to_resolved.clone()),
ConstrainedValue::Integer(from_resolved.clone()),
span,
)?;
let calc_len = match calc_len {
ConstrainedValue::Integer(i) => i,
_ => unimplemented!("illegal non-Integer returned from sub"),
};
let namespace_string = format!(
"evaluate array range access length check {}:{}",
span.line_start, span.col_start
);
let mut unique_namespace = cs.ns(|| namespace_string);
calc_len
.enforce_equal(&mut unique_namespace, &Integer::new(&ConstInt::U32(length as u32)))
.map_err(|e| ExpressionError::cannot_enforce("array length check".to_string(), e, span))?;
}
{
let bounds_check = evaluate_le::<F, G, _>(
cs,
ConstrainedValue::Integer(to_resolved),
ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32))),
span,
)?;
let bounds_check = match bounds_check {
ConstrainedValue::Boolean(b) => b,
_ => unimplemented!("illegal non-Integer returned from le"),
};
let namespace_string = format!(
"evaluate array range access bounds {}:{}",
span.line_start, span.col_start
);
let mut unique_namespace = cs.ns(|| namespace_string);
bounds_check
.enforce_equal(&mut unique_namespace, &Boolean::Constant(true))
.map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?;
}
let mut windows = array.windows(length);
let mut result = ConstrainedValue::Array(vec![]);
for i in 0..length {
let window = if let Some(window) = windows.next() {
window
} else {
break;
};
let array_value = ConstrainedValue::Array(window.to_vec());
let mut unique_namespace =
cs.ns(|| format!("array index eq-check {} {}:{}", i, span.line_start, span.col_start));
let equality = evaluate_eq::<F, G, _>(
&mut unique_namespace,
ConstrainedValue::Integer(from_resolved.clone()),
ConstrainedValue::Integer(Integer::new(&ConstInt::U32(i as u32))),
span,
)?;
let equality = match equality {
ConstrainedValue::Boolean(b) => b,
_ => unimplemented!("unexpected non-Boolean for evaluate_eq"),
};
let unique_namespace =
unique_namespace.ns(|| format!("array index {} {}:{}", i, span.line_start, span.col_start));
result = ConstrainedValue::conditionally_select(unique_namespace, &equality, &array_value, &result)
.map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, span))?;
}
result
})
}
}

View File

@ -16,7 +16,7 @@
//! Enforces an array index expression in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, Integer};
use leo_asg::{Expression, Span};
use snarkvm_fields::PrimeField;
@ -28,9 +28,9 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
cs: &mut CS,
index: &'a Expression<'a>,
span: &Span,
) -> Result<usize, ExpressionError> {
) -> Result<Integer, ExpressionError> {
match self.enforce_expression(cs, index)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
ConstrainedValue::Integer(number) => Ok(number),
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
}
}

View File

@ -32,8 +32,15 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
left: &'a Expression<'a>,
right: &'a Expression<'a>,
) -> Result<ConstrainedValuePair<'a, F, G>, ExpressionError> {
let resolved_left = self.enforce_expression(cs, left)?;
let resolved_right = self.enforce_expression(cs, right)?;
let resolved_left = {
let mut left_namespace = cs.ns(|| "left".to_string());
self.enforce_expression(&mut left_namespace, left)?
};
let resolved_right = {
let mut right_namespace = cs.ns(|| "right".to_string());
self.enforce_expression(&mut right_namespace, right)?
};
Ok((resolved_left, resolved_right))
}

View File

@ -42,7 +42,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// type checking is already done in asg
for (name, inner) in expr.values.iter() {
let target = members
.get(&name.name)
.get(name.name.as_ref())
.expect("illegal name in asg circuit init expression");
match target {
CircuitMember::Variable(_type_) => {

View File

@ -41,7 +41,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
span: &Span,
) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
Ok(match value {
ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.clone(), span)?),
ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.to_string(), span)?),
ConstValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::Constant(*value)),
ConstValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value.to_string(), span)?),
ConstValue::Group(value) => ConstrainedValue::Group(G::constant(value, span)?),
@ -133,9 +133,13 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => {
self.enforce_array_access(cs, array.get(), index.get(), span)
}
Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => {
self.enforce_array_range_access(cs, array.get(), left.get(), right.get(), span)
}
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
array,
left,
right,
length,
..
}) => self.enforce_array_range_access(cs, array.get(), left.get(), right.get(), *length, span),
// Tuples
Expression::TupleInit(TupleInitExpression { elements, .. }) => self.enforce_tuple(cs, &elements[..]),

View File

@ -40,7 +40,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// Check for out of bounds access.
if index > tuple.len() - 1 {
// probably safe to be a panic here
return Err(ExpressionError::index_out_of_bounds(index, span));
return Err(ExpressionError::tuple_index_out_of_bounds(index, span));
}
Ok(tuple[index].to_owned())

View File

@ -37,19 +37,19 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// Create an identifier for each input variable
let registers_name = Identifier {
name: REGISTERS_VARIABLE_NAME.to_string(),
name: REGISTERS_VARIABLE_NAME.into(),
span: span.clone(),
};
let record_name = Identifier {
name: RECORD_VARIABLE_NAME.to_string(),
name: RECORD_VARIABLE_NAME.into(),
span: span.clone(),
};
let state_name = Identifier {
name: STATE_VARIABLE_NAME.to_string(),
name: STATE_VARIABLE_NAME.into(),
span: span.clone(),
};
let state_leaf_name = Identifier {
name: STATE_LEAF_VARIABLE_NAME.to_string(),
name: STATE_LEAF_VARIABLE_NAME.into(),
span: span.clone(),
};
@ -72,7 +72,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let mut members = Vec::with_capacity(sections.len());
for (name, values) in sections {
let sub_circuit = match expected_type.members.borrow().get(&name.name) {
let sub_circuit = match expected_type.members.borrow().get(name.name.as_ref()) {
Some(CircuitMember::Variable(Type::Circuit(circuit))) => *circuit,
_ => panic!("illegal input type definition from asg"),
};

View File

@ -36,7 +36,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// Allocate each section definition as a circuit member value
for (parameter, option) in section.into_iter() {
let section_members = expected_type.members.borrow();
let expected_type = match section_members.get(&parameter.variable.name) {
let expected_type = match section_members.get(parameter.variable.name.as_ref()) {
Some(CircuitMember::Variable(inner)) => inner,
_ => continue, // present, but unused
};

View File

@ -62,11 +62,15 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let input_variable = input_variable.get().borrow();
let name = input_variable.name.name.clone();
let input_value = match (input_variable.const_, input.get(&name), input.get_constant(&name)) {
let input_value = match (
input_variable.const_,
input.get(&name),
input.get_constant(name.as_ref()),
) {
// If variable is in both [main] and [constants] sections - error.
(_, Some(_), Some(_)) => {
return Err(FunctionError::double_input_declaration(
name.clone(),
name.to_string(),
&function.span.clone().unwrap_or_default(),
));
}
@ -89,21 +93,21 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// Function argument is const, input is not.
(true, Some(_), None) => {
return Err(FunctionError::expected_const_input(
name.clone(),
name.to_string(),
&function.span.clone().unwrap_or_default(),
));
}
// Input is const, function argument is not.
(false, None, Some(_)) => {
return Err(FunctionError::expected_non_const_input(
name.clone(),
name.to_string(),
&function.span.clone().unwrap_or_default(),
));
}
// When not found - Error out.
(_, _, _) => {
return Err(FunctionError::input_not_found(
name.clone(),
name.to_string(),
&function.span.clone().unwrap_or_default(),
));
}

View File

@ -51,15 +51,31 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let start_index = left
.get()
.map(|start| self.enforce_index(cs, start, span))
.transpose()?
.map(|x| {
x.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(span))
})
.transpose()?;
let stop_index = right
.get()
.map(|stop| self.enforce_index(cs, stop, span))
.transpose()?
.map(|x| {
x.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(span))
})
.transpose()?;
let stop_index = right.get().map(|stop| self.enforce_index(cs, stop, span)).transpose()?;
output.push(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index));
Ok(inner)
}
Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => {
let inner = self.prepare_mut_access(cs, array.get(), span, output)?;
let index = self.enforce_index(cs, index.get(), span)?;
let index = self
.enforce_index(cs, index.get(), span)?
.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(span))?;
output.push(ResolvedAssigneeAccess::ArrayIndex(index));
Ok(inner)

View File

@ -42,19 +42,6 @@ impl OutputFile {
}
}
pub fn exists_at(&self, path: &Path) -> bool {
let path = self.setup_file_path(path);
path.exists()
}
/// Reads the output register variables from the given file path if it exists.
pub fn read_from(&self, path: &Path) -> Result<String, OutputFileError> {
let path = self.setup_file_path(path);
let output = fs::read_to_string(&path).map_err(|_| OutputFileError::FileReadError(path.into_owned()))?;
Ok(output)
}
/// Writes output to a file.
pub fn write(&self, path: &Path, bytes: &[u8]) -> Result<(), OutputFileError> {
// create output file
@ -88,3 +75,26 @@ impl OutputFile {
path
}
}
#[cfg(test)]
mod test_output_file {
use crate::{OutputFile, OUTPUTS_DIRECTORY_NAME};
use std::{error::Error, fs};
#[test]
fn test_all() -> Result<(), Box<dyn Error>> {
let dir = tempfile::tempdir()?;
let file = OutputFile::new("test");
let path = dir.path();
assert!(file.write(path, Default::default()).is_err());
assert!(!(file.remove(path)?));
fs::create_dir(dir.path().join(OUTPUTS_DIRECTORY_NAME))?;
assert!(file.write(path, Default::default()).is_ok());
assert!(file.remove(path)?);
Ok(())
}
}

View File

@ -56,7 +56,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> CoreCircuit<'a, F, G> for Blake2s {
mut arguments: Vec<ConstrainedValue<'a, F, G>>,
) -> Result<ConstrainedValue<'a, F, G>, ExpressionError> {
assert_eq!(arguments.len(), 2); // asg enforced
assert!(function.name.borrow().name == "hash"); // asg enforced
assert!(function.name.borrow().name.as_ref() == "hash"); // asg enforced
assert!(target.is_none()); // asg enforced
let input = unwrap_argument(arguments.remove(1));
let seed = unwrap_argument(arguments.remove(0));

View File

@ -45,19 +45,35 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let start_index = start
.get()
.map(|start| self.enforce_index(cs, start, &span))
.transpose()?
.map(|x| {
x.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(&span))
})
.transpose()?;
let stop_index = stop
.get()
.map(|stop| self.enforce_index(cs, stop, &span))
.transpose()?
.map(|x| {
x.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(&span))
})
.transpose()?;
let stop_index = stop.get().map(|stop| self.enforce_index(cs, stop, &span)).transpose()?;
Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index))
}
AssignAccess::ArrayIndex(index) => {
let index = self.enforce_index(cs, index.get(), &span)?;
let index = self
.enforce_index(cs, index.get(), &span)?
.to_usize()
.ok_or_else(|| StatementError::array_assign_index_const(&span))?;
Ok(ResolvedAssigneeAccess::ArrayIndex(index))
}
AssignAccess::Tuple(index) => Ok(ResolvedAssigneeAccess::Tuple(*index, span.clone())),
AssignAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier.clone())),
})
.collect::<Result<Vec<_>, crate::errors::ExpressionError>>()?;
.collect::<Result<Vec<_>, StatementError>>()?;
let variable = assignee.target_variable.get().borrow();

View File

@ -17,11 +17,13 @@
//! Enforces an iteration statement in a compiled Leo program.
use crate::{
errors::StatementError,
program::ConstrainedProgram,
value::ConstrainedValue,
GroupType,
IndicatorAndConstrainedValue,
Integer,
IntegerTrait,
StatementResult,
};
use leo_asg::IterationStatement;
@ -42,8 +44,14 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let span = statement.span.clone().unwrap_or_default();
let from = self.enforce_index(cs, statement.start.get(), &span)?;
let to = self.enforce_index(cs, statement.stop.get(), &span)?;
let from = self
.enforce_index(cs, statement.start.get(), &span)?
.to_usize()
.ok_or_else(|| StatementError::loop_index_const(&span))?;
let to = self
.enforce_index(cs, statement.stop.get(), &span)?
.to_usize()
.ok_or_else(|| StatementError::loop_index_const(&span))?;
for i in from..to {
// Store index in current function scope.

View File

@ -17,7 +17,7 @@
//! Enforces a statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_asg::Statement;
use leo_asg::{Node, Statement};
use snarkvm_fields::PrimeField;
use snarkvm_gadgets::traits::utilities::boolean::Boolean;
@ -42,6 +42,9 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
statement: &'a Statement<'a>,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<'a, F, G>>> {
let mut results = vec![];
let span = statement.span().cloned().unwrap_or_default();
let mut cs = cs.ns(|| format!("statement {}:{}", span.line_start, span.col_start));
let cs = &mut cs;
match statement {
Statement::Return(statement) => {

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{errors::AddressError, ConstrainedValue, GroupType};
use crate::{errors::AddressError, ConstrainedValue, GroupType, IntegerTrait};
use leo_ast::{InputValue, Span};
use snarkvm_dpc::{account::AccountAddress, base_dpc::instantiated::Components};
@ -24,7 +24,7 @@ use snarkvm_gadgets::traits::utilities::{
boolean::Boolean,
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
select::CondSelectGadget,
uint::{UInt, UInt8},
uint::UInt8,
};
use snarkvm_r1cs::{Assignment, ConstraintSystem, SynthesisError};
use snarkvm_utilities::ToBytes;

View File

@ -28,10 +28,10 @@ use snarkvm_gadgets::traits::utilities::{
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
int::{Int128, Int16, Int32, Int64, Int8},
select::CondSelectGadget,
uint::*,
uint::{Sub as UIntSub, *},
};
use snarkvm_r1cs::{ConstraintSystem, SynthesisError};
use std::fmt;
use std::{convert::TryInto, fmt};
/// An integer type enum wrapping the integer value.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
@ -83,7 +83,7 @@ impl Integer {
pub fn get_bits(&self) -> Vec<Boolean> {
let integer = self;
match_integer!(integer => integer.get_bits())
match_integer!(integer => integer.to_bits_le())
}
// pub fn get_bits_typed(&self) -> (Vec<Boolean>, IntegerType) {
@ -111,15 +111,9 @@ impl Integer {
match_integer!(integer => integer.get_value())
}
pub fn to_usize(&self, span: &Span) -> Result<usize, IntegerError> {
pub fn to_usize(&self) -> Option<usize> {
let unsigned_integer = self;
let value_option: Option<String> = match_unsigned_integer!(unsigned_integer => unsigned_integer.get_value());
let value = value_option.ok_or_else(|| IntegerError::invalid_index(span))?;
let value_usize = value
.parse::<usize>()
.map_err(|_| IntegerError::invalid_integer(value, span))?;
Ok(value_usize)
match_unsigned_integer!(unsigned_integer => unsigned_integer.value.map(|num| num.try_into().ok()).flatten())
}
pub fn get_type(&self) -> IntegerType {
@ -146,148 +140,17 @@ impl Integer {
span: &Span,
) -> Result<Self, IntegerError> {
Ok(match integer_type {
IntegerType::U8 => {
let u8_option = option.map(|s| {
s.parse::<u8>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
IntegerType::U8 => allocate_type!(u8, UInt8, Integer::U8, cs, name, option, span),
IntegerType::U16 => allocate_type!(u16, UInt16, Integer::U16, cs, name, option, span),
IntegerType::U32 => allocate_type!(u32, UInt32, Integer::U32, cs, name, option, span),
IntegerType::U64 => allocate_type!(u64, UInt64, Integer::U64, cs, name, option, span),
IntegerType::U128 => allocate_type!(u128, UInt128, Integer::U128, cs, name, option, span),
let u8_result = UInt8::alloc(
cs.ns(|| format!("`{}: u8` {}:{}", name, span.line_start, span.col_start)),
|| u8_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: u8", name), span))?;
Integer::U8(u8_result)
}
IntegerType::U16 => {
let u16_option = option.map(|s| {
s.parse::<u16>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let u16_result = UInt16::alloc(
cs.ns(|| format!("`{}: u16` {}:{}", name, span.line_start, span.col_start)),
|| u16_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: u16", name), span))?;
Integer::U16(u16_result)
}
IntegerType::U32 => {
let u32_option = option.map(|s| {
s.parse::<u32>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let u32_result = UInt32::alloc(
cs.ns(|| format!("`{}: u32` {}:{}", name, span.line_start, span.col_start)),
|| u32_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: u32", name), span))?;
Integer::U32(u32_result)
}
IntegerType::U64 => {
let u64_option = option.map(|s| {
s.parse::<u64>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let u64_result = UInt64::alloc(
cs.ns(|| format!("`{}: u64` {}:{}", name, span.line_start, span.col_start)),
|| u64_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: u64", name), span))?;
Integer::U64(u64_result)
}
IntegerType::U128 => {
let u128_option = option.map(|s| {
s.parse::<u128>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let u128_result = UInt128::alloc(
cs.ns(|| format!("`{}: u128` {}:{}", name, span.line_start, span.col_start)),
|| u128_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: u128", name), span))?;
Integer::U128(u128_result)
}
IntegerType::I8 => {
let i8_option = option.map(|s| {
s.parse::<i8>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let i8_result = Int8::alloc(
cs.ns(|| format!("`{}: i8` {}:{}", name, span.line_start, span.col_start)),
|| i8_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: i8", name), span))?;
Integer::I8(i8_result)
}
IntegerType::I16 => {
let i16_option = option.map(|s| {
s.parse::<i16>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let i16_result = Int16::alloc(
cs.ns(|| format!("`{}: i16` {}:{}", name, span.line_start, span.col_start)),
|| i16_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: i16", name), span))?;
Integer::I16(i16_result)
}
IntegerType::I32 => {
let i32_option = option.map(|s| {
s.parse::<i32>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let i32_result = Int32::alloc(
cs.ns(|| format!("`{}: i32` {}:{}", name, span.line_start, span.col_start)),
|| i32_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: i32", name), span))?;
Integer::I32(i32_result)
}
IntegerType::I64 => {
let i64_option = option.map(|s| {
s.parse::<i64>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let i64_result = Int64::alloc(
cs.ns(|| format!("`{}: i64` {}:{}", name, span.line_start, span.col_start)),
|| i64_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: i64", name), span))?;
Integer::I64(i64_result)
}
IntegerType::I128 => {
let i128_option = option.map(|s| {
s.parse::<i128>()
.map_err(|_| IntegerError::invalid_integer(s, span))
.unwrap()
});
let i128_result = Int128::alloc(
cs.ns(|| format!("`{}: i128` {}:{}", name, span.line_start, span.col_start)),
|| i128_option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: i128", name), span))?;
Integer::I128(i128_result)
}
IntegerType::I8 => allocate_type!(i8, Int8, Integer::I8, cs, name, option, span),
IntegerType::I16 => allocate_type!(i16, Int16, Integer::I16, cs, name, option, span),
IntegerType::I32 => allocate_type!(i32, Int32, Integer::I32, cs, name, option, span),
IntegerType::I64 => allocate_type!(i64, Int64, Integer::I64, cs, name, option, span),
IntegerType::I128 => allocate_type!(i128, Int128, Integer::I128, cs, name, option, span),
})
}

View File

@ -14,35 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use snarkvm_gadgets::traits::utilities::{
boolean::Boolean,
int::{Int128, Int16, Int32, Int64, Int8},
uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
};
use std::fmt::Debug;
pub trait IntegerTrait: Sized + Clone + Debug {
fn get_value(&self) -> Option<String>;
fn get_bits(&self) -> Vec<Boolean>;
}
macro_rules! integer_trait_impl {
($($gadget: ident)*) => ($(
impl IntegerTrait for $gadget {
fn get_value(&self) -> Option<String> {
self.value.map(|num| num.to_string())
}
fn get_bits(&self) -> Vec<Boolean> {
self.bits.clone()
}
}
)*)
}
integer_trait_impl!(UInt8 UInt16 UInt32 UInt64 UInt128 Int8 Int16 Int32 Int64 Int128);
pub use snarkvm_gadgets::traits::utilities::integer::Integer as IntegerTrait;
/// Useful macros to avoid duplicating `match` constructions.
#[macro_export]
@ -119,19 +91,19 @@ macro_rules! match_integers_span {
(($a: ident, $b: ident), $span: ident => $expression:expr) => {
match ($a, $b) {
(Integer::U8($a), Integer::U8($b)) => {
Some(Integer::U8($expression.map_err(|e| IntegerError::synthesis(e, $span))?))
Some(Integer::U8($expression.map_err(|e| IntegerError::unsigned(e, $span))?))
}
(Integer::U16($a), Integer::U16($b)) => {
Some(Integer::U16($expression.map_err(|e| IntegerError::unsigned(e, $span))?))
}
(Integer::U32($a), Integer::U32($b)) => {
Some(Integer::U32($expression.map_err(|e| IntegerError::unsigned(e, $span))?))
}
(Integer::U64($a), Integer::U64($b)) => {
Some(Integer::U64($expression.map_err(|e| IntegerError::unsigned(e, $span))?))
}
(Integer::U16($a), Integer::U16($b)) => Some(Integer::U16(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U32($a), Integer::U32($b)) => Some(Integer::U32(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U64($a), Integer::U64($b)) => Some(Integer::U64(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U128($a), Integer::U128($b)) => Some(Integer::U128(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
$expression.map_err(|e| IntegerError::unsigned(e, $span))?,
)),
(Integer::I8($a), Integer::I8($b)) => {
@ -153,3 +125,29 @@ macro_rules! match_integers_span {
}
};
}
macro_rules! allocate_type {
($rust_ty:ty, $gadget_ty:ty, $leo_ty:path, $cs:expr, $name:expr, $option:expr, $span:expr) => {{
let option = $option.map(|s| {
s.parse::<$rust_ty>()
.map_err(|_| IntegerError::invalid_integer(s, $span))
.unwrap()
});
let result = <$gadget_ty>::alloc(
$cs.ns(|| {
format!(
"`{}: {}` {}:{}",
$name,
stringify!($rust_ty),
$span.line_start,
$span.col_start
)
}),
|| option.ok_or(SynthesisError::AssignmentMissing),
)
.map_err(|_| IntegerError::missing_integer(format!("{}: {}", $name, stringify!($rust_ty)), $span))?;
$leo_ty(result)
}};
}

View File

@ -539,3 +539,178 @@ fn test_variable_slice_fail() {
expect_asg_error(error);
}
#[test]
fn test_array_index() {
let program_string = r#"
function main(i: u32) {
let b = [1u8, 2, 3, 4];
console.assert(2 == b[i]);
console.assert(3 == b[2]);
}
"#;
let input_string = r#"
[main]
i: u32 = 1;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
assert_satisfied(program);
}
#[test]
fn test_array_index_bounds_fail() {
let program_string = r#"
function main(i: u32) {
let b = [1u8, 2, 3, 4];
console.assert(2 == b[i]);
}
"#;
let input_string = r#"
[main]
i: u32 = 4;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_const_array_index_bounds_fail() {
let program_string = r#"
function main() {
let b = [1u8, 2, 3, 4];
const i: u32 = 4;
console.assert(2 == b[i]);
}
"#;
let error = parse_program(program_string).err().unwrap();
expect_asg_error(error);
}
#[test]
fn test_array_range_index() {
let program_string = r#"
function main(i: u32) {
let b = [1u8, 2, 3, 4];
console.assert([1u8, 2] == b[0..i]);
console.assert([3u8, 4] == b[i..4]);
}
"#;
let input_string = r#"
[main]
i: u32 = 2;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
assert_satisfied(program);
}
#[test]
fn test_array_range_index_dyn() {
let program_string = r#"
function main(i: u32) {
let b = [1u8, 2, 3, 4];
console.assert([1u8, 2] == b[..i]);
console.assert([3u8, 4] == b[i..]);
}
"#;
let input_string = r#"
[main]
i: u32 = 2;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
assert_satisfied(program);
}
#[test]
fn test_array_range_index_full_dyn() {
let program_string = r#"
function main(i: u32, y: u32) {
let b = [1u8, 2, 3, 4];
console.assert([3u8, 4] == b[i..y]);
}
"#;
let input_string = r#"
[main]
i: u32 = 2;
y: u32 = 4;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
assert_satisfied(program);
}
#[test]
fn test_array_range_index_out_of_bounds_fail() {
let program_string = r#"
function main() {
let b = [1u8, 2, 3, 4];
console.assert([1, 2] == b[3..5]);
}
"#;
let error = parse_program(program_string).err().unwrap();
expect_asg_error(error);
}
#[test]
fn test_array_range_index_invalid_bounds_fail() {
let program_string = r#"
function main() {
let b = [1u8, 2, 3, 4];
console.assert([1, 2] == b[2..1]);
}
"#;
let error = parse_program(program_string).err().unwrap();
expect_asg_error(error);
}
#[test]
fn test_array_range_index_full_dyn_resized_fail() {
let program_string = r#"
function main(i: u32, y: u32) {
let b = [1u8, 2, 3, 4];
console.assert([3u8, 4] == b[i..y]);
}
"#;
let input_string = r#"
[main]
i: u32 = 1;
y: u32 = 4;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_array_range_index_full_dyn_bounds_fail() {
let program_string = r#"
function main(i: u32, y: u32) {
let b = [1u8, 2, 3, 4];
console.assert([3u8, 4] == b[i..y]);
}
"#;
let input_string = r#"
[main]
i: u32 = 3;
y: u32 = 5;
"#;
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_compiler_error(program);
}

View File

@ -4,15 +4,15 @@
"imports": [],
"circuits": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}",
"input": [
{
"Variable": {
"identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\"}\"}",
"identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}",
"const_": false,
"mutable": false,
"mutable": true,
"type_": {
"Array": [
{
@ -37,7 +37,8 @@
"line_stop": 1,
"col_start": 15,
"col_stop": 16,
"path": ""
"path": "",
"content": "function main(a: [group; (2, 1)]) {"
}
}
}
@ -52,14 +53,15 @@
"declaration_type": "Let",
"variable_names": [
{
"mutable": false,
"identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
"mutable": true,
"identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let b = [true; (6, 5, 4, 3, 2)];\\\"}\"}",
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 7,
"col_stop": 8,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
],
@ -83,7 +85,8 @@
"line_stop": 2,
"col_start": 12,
"col_stop": 16,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
]
}
@ -98,7 +101,8 @@
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -112,7 +116,8 @@
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -126,7 +131,8 @@
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -140,7 +146,8 @@
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -154,7 +161,8 @@
"line_stop": 2,
"col_start": 11,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -163,7 +171,8 @@
"line_stop": 2,
"col_start": 3,
"col_stop": 34,
"path": ""
"path": "",
"content": " let b = [true; (6, 5, 4, 3, 2)];"
}
}
},
@ -172,14 +181,15 @@
"declaration_type": "Let",
"variable_names": [
{
"mutable": false,
"identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
"mutable": true,
"identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let c: [u32; (1, 2)] = [0u32; (1, 2)];\\\"}\"}",
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 7,
"col_stop": 8,
"path": ""
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
],
@ -218,7 +228,8 @@
"line_stop": 3,
"col_start": 27,
"col_stop": 31,
"path": ""
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
]
}
@ -233,7 +244,8 @@
"line_stop": 3,
"col_start": 26,
"col_stop": 40,
"path": ""
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
@ -247,7 +259,8 @@
"line_stop": 3,
"col_start": 26,
"col_stop": 40,
"path": ""
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
@ -256,7 +269,8 @@
"line_stop": 3,
"col_start": 3,
"col_stop": 40,
"path": ""
"path": "",
"content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];"
}
}
},
@ -265,14 +279,15 @@
"declaration_type": "Let",
"variable_names": [
{
"mutable": false,
"identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
"mutable": true,
"identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let d = [0i8; (1)];\\\"}\"}",
"span": {
"line_start": 4,
"line_stop": 4,
"col_start": 7,
"col_stop": 8,
"path": ""
"path": "",
"content": " let d = [0i8; (1)];"
}
}
],
@ -289,7 +304,8 @@
"line_stop": 4,
"col_start": 12,
"col_stop": 15,
"path": ""
"path": "",
"content": " let d = [0i8; (1)];"
}
]
}
@ -304,7 +320,8 @@
"line_stop": 4,
"col_start": 11,
"col_stop": 21,
"path": ""
"path": "",
"content": " let d = [0i8; (1)];"
}
}
},
@ -313,26 +330,29 @@
"line_stop": 4,
"col_start": 3,
"col_stop": 21,
"path": ""
"path": "",
"content": " let d = [0i8; (1)];"
}
}
}
],
"span": {
"line_start": 1,
"line_stop": 5,
"line_stop": 7,
"col_start": 35,
"col_stop": 2,
"path": ""
"path": "",
"content": "function main(a: [group; (2, 1)]) {\n...\n}"
}
},
"span": {
"line_start": 1,
"line_stop": 5,
"line_stop": 7,
"col_start": 1,
"col_stop": 2,
"path": ""
"path": "",
"content": "function main(a: [group; (2, 1)]) {\n...\n}\n\n\n\n"
}
}
}
}
}

View File

@ -1,206 +1,218 @@
{
"name": "",
"expected_input": [],
"imports": [],
"circuits": {
"{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}": {
"circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
"members": [
{
"CircuitVariable": [
"{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}",
{
"IntegerType": "U32"
}
]
},
{
"CircuitFunction": {
"annotations": [],
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}",
"input": [],
"output": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}"
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": false,
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
"span": {
"line_start": 5,
"line_stop": 5,
"col_start": 9,
"col_stop": 12,
"path": ""
}
"name": "",
"expected_input": [],
"imports": [],
"circuits": {
"{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}": {
"circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"CircuitVariable": [
"{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: u32\\\"}\"}",
{
"IntegerType": "U32"
}
]
},
{
"CircuitFunction": {
"annotations": [],
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" function new() -> Self {\\\"}\"}",
"input": [],
"output": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}"
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let new: Self = Self {\\\"}\"}",
"span": {
"line_start": 5,
"line_stop": 5,
"col_start": 9,
"col_stop": 12,
"path": "",
"content": " let new: Self = Self {"
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}"
},
"value": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
"expression": {
"Value": {
"Integer": [
"U32",
"1",
{
"line_start": 6,
"line_stop": 6,
"col_start": 10,
"col_stop": 14,
"path": ""
}
]
}
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}"
},
"value": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: 1u32\\\"}\"}",
"expression": {
"Value": {
"Integer": [
"U32",
"1",
{
"line_start": 6,
"line_stop": 6,
"col_start": 10,
"col_stop": 14,
"path": "",
"content": " x: 1u32"
}
]
}
}
],
"span": {
"line_start": 5,
"line_stop": 7,
"col_start": 21,
"col_stop": 6,
"path": ""
}
}
},
"span": {
"line_start": 5,
"line_stop": 7,
"col_start": 5,
"col_stop": 6,
"path": ""
}
}
},
{
"Return": {
"expression": {
"Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}"
},
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 5,
"col_stop": 15,
"path": ""
}
}
}
],
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 26,
"col_stop": 4,
"path": ""
}
},
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 3,
"col_stop": 4,
"path": ""
}
}
}
]
}
},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": false,
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}",
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 7,
"col_stop": 10,
"path": ""
}
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}"
},
"value": {
"Call": {
"function": {
"CircuitStaticFunctionAccess": {
"circuit": {
"Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}"
},
"name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\"}\"}",
],
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 18,
"col_stop": 26,
"path": ""
"line_start": 5,
"line_stop": 7,
"col_start": 21,
"col_stop": 6,
"path": "",
"content": " let new: Self = Self {\n...\n };"
}
}
},
"arguments": [],
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 18,
"col_stop": 28,
"path": ""
"line_start": 5,
"line_stop": 7,
"col_start": 5,
"col_stop": 6,
"path": "",
"content": " let new: Self = Self {\n...\n };"
}
}
},
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 28,
"path": ""
{
"Return": {
"expression": {
"Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" return new\\\"}\"}"
},
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 5,
"col_stop": 15,
"path": "",
"content": " return new"
}
}
}
],
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 26,
"col_stop": 4,
"path": "",
"content": " function new() -> Self {\n...\n }"
}
},
"span": {
"line_start": 4,
"line_stop": 10,
"col_start": 3,
"col_stop": 4,
"path": "",
"content": " function new() -> Self {\n...\n }\n\n\n\n"
}
}
}
]
}
},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}",
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 7,
"col_stop": 10,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
],
"type_": {
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}"
},
"value": {
"Call": {
"function": {
"CircuitStaticFunctionAccess": {
"circuit": {
"Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}"
},
"name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}",
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 18,
"col_stop": 26,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
},
"arguments": [],
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 18,
"col_stop": 28,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
},
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 28,
"path": "",
"content": " let foo: Foo = Foo::new();"
}
}
],
"span": {
"line_start": 13,
"line_stop": 15,
"col_start": 17,
"col_stop": 2,
"path": ""
}
},
],
"span": {
"line_start": 13,
"line_stop": 15,
"col_start": 1,
"col_start": 17,
"col_stop": 2,
"path": ""
"path": "",
"content": "function main() {\n...\n}"
}
},
"span": {
"line_start": 13,
"line_stop": 15,
"col_start": 1,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n}"
}
}
}
}

View File

@ -1,128 +1,867 @@
{
"name": "",
"expected_input": [],
"imports": [],
"circuits": {},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
"name": "",
"expected_input": [],
"imports": [],
"circuits": {
"{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}": {
"circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}",
"members": [
{
"CircuitVariable": [
"{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" f: u8,\\\"}\"}",
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":11,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 7,
"col_stop": 12,
"path": ""
}
}
],
"type_": null,
"value": {
"Value": {
"Integer": [
"U32",
"10",
{
"line_start": 2,
"line_stop": 2,
"col_start": 15,
"col_stop": 20,
"path": ""
}
]
}
},
"span": {
"line_start": 2,
"line_stop": 2,
"col_start": 3,
"col_stop": 20,
"path": ""
}
}
},
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}",
"accesses": [],
"IntegerType": "U8"
}
]
}
]
}
},
"functions": {
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": {
"annotations": [],
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}",
"input": [],
"output": {
"Tuple": []
},
"block": {
"statements": [
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let x = 10u32;\\\"}\"}",
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 3,
"col_stop": 4,
"path": ""
"line_start": 5,
"line_stop": 5,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let x = 10u32;"
}
},
"value": {
}
],
"type_": null,
"value": {
"Value": {
"Integer": [
"U32",
"10",
{
"line_start": 5,
"line_stop": 5,
"col_start": 11,
"col_stop": 16,
"path": "",
"content": " let x = 10u32;"
}
]
}
},
"span": {
"line_start": 5,
"line_stop": 5,
"col_start": 3,
"col_stop": 16,
"path": "",
"content": " let x = 10u32;"
}
}
},
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x += 20;\\\"}\"}",
"accesses": [],
"span": {
"line_start": 6,
"line_stop": 6,
"col_start": 3,
"col_stop": 4,
"path": "",
"content": " x += 20;"
}
},
"value": {
"Binary": {
"left": {
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x += 20;\\\"}\"}"
},
"right": {
"Value": {
"Implicit": [
"20",
{
"line_start": 6,
"line_stop": 6,
"col_start": 8,
"col_stop": 10,
"path": "",
"content": " x += 20;"
}
]
}
},
"op": "Add",
"span": {
"line_start": 6,
"line_stop": 6,
"col_start": 3,
"col_stop": 10,
"path": "",
"content": " x += 20;"
}
}
},
"span": {
"line_start": 6,
"line_stop": 6,
"col_start": 3,
"col_stop": 10,
"path": "",
"content": " x += 20;"
}
}
},
{
"Console": {
"function": {
"Assert": {
"Binary": {
"left": {
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}"
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":7,\\\"line_stop\\\":7,\\\"col_start\\\":18,\\\"col_stop\\\":19,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(x == 30u32);\\\"}\"}"
},
"right": {
"Value": {
"Implicit": [
"20",
"Integer": [
"U32",
"30",
{
"line_start": 3,
"line_stop": 3,
"col_start": 8,
"col_stop": 10,
"path": ""
"line_start": 7,
"line_stop": 7,
"col_start": 23,
"col_stop": 28,
"path": "",
"content": " console.assert(x == 30u32);"
}
]
}
},
"op": "Add",
"op": "Eq",
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 3,
"col_stop": 10,
"path": ""
"line_start": 7,
"line_stop": 7,
"col_start": 18,
"col_stop": 28,
"path": "",
"content": " console.assert(x == 30u32);"
}
}
},
"span": {
"line_start": 3,
"line_stop": 3,
"col_start": 3,
"col_stop": 10,
"path": ""
}
},
"span": {
"line_start": 7,
"line_stop": 7,
"col_start": 3,
"col_stop": 28,
"path": "",
"content": " console.assert(x == 30u32);"
}
}
},
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let y = [1u8, 2u8];\\\"}\"}",
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let y = [1u8, 2u8];"
}
}
],
"type_": null,
"value": {
"ArrayInline": {
"elements": [
{
"Expression": {
"Value": {
"Integer": [
"U8",
"1",
{
"line_start": 9,
"line_stop": 9,
"col_start": 12,
"col_stop": 15,
"path": "",
"content": " let y = [1u8, 2u8];"
}
]
}
}
},
{
"Expression": {
"Value": {
"Integer": [
"U8",
"2",
{
"line_start": 9,
"line_stop": 9,
"col_start": 17,
"col_stop": 20,
"path": "",
"content": " let y = [1u8, 2u8];"
}
]
}
}
}
],
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 11,
"col_stop": 21,
"path": "",
"content": " let y = [1u8, 2u8];"
}
}
},
"span": {
"line_start": 9,
"line_stop": 9,
"col_start": 3,
"col_stop": 21,
"path": "",
"content": " let y = [1u8, 2u8];"
}
}
},
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":10,\\\"line_stop\\\":10,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[0] += 3u8;\\\"}\"}",
"accesses": [
{
"ArrayIndex": {
"Value": {
"Implicit": [
"0",
{
"line_start": 10,
"line_stop": 10,
"col_start": 5,
"col_stop": 6,
"path": "",
"content": " y[0] += 3u8;"
}
]
}
}
}
],
"span": {
"line_start": 10,
"line_stop": 10,
"col_start": 3,
"col_stop": 7,
"path": "",
"content": " y[0] += 3u8;"
}
},
"value": {
"Binary": {
"left": {
"ArrayAccess": {
"array": {
"Identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":10,\\\"line_stop\\\":10,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" y[0] += 3u8;\\\"}\"}"
},
"index": {
"Value": {
"Implicit": [
"0",
{
"line_start": 10,
"line_stop": 10,
"col_start": 5,
"col_stop": 6,
"path": "",
"content": " y[0] += 3u8;"
}
]
}
},
"span": {
"line_start": 10,
"line_stop": 10,
"col_start": 3,
"col_stop": 14,
"path": "",
"content": " y[0] += 3u8;"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"3",
{
"line_start": 10,
"line_stop": 10,
"col_start": 11,
"col_stop": 14,
"path": "",
"content": " y[0] += 3u8;"
}
]
}
},
"op": "Add",
"span": {
"line_start": 10,
"line_stop": 10,
"col_start": 3,
"col_stop": 14,
"path": "",
"content": " y[0] += 3u8;"
}
}
},
"span": {
"line_start": 10,
"line_stop": 10,
"col_start": 3,
"col_stop": 14,
"path": "",
"content": " y[0] += 3u8;"
}
}
},
{
"Console": {
"function": {
"Assert": {
"Binary": {
"left": {
"ArrayAccess": {
"array": {
"Identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":11,\\\"line_stop\\\":11,\\\"col_start\\\":18,\\\"col_stop\\\":19,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(y[0] == 4u8);\\\"}\"}"
},
"index": {
"Value": {
"Implicit": [
"0",
{
"line_start": 11,
"line_stop": 11,
"col_start": 20,
"col_stop": 21,
"path": "",
"content": " console.assert(y[0] == 4u8);"
}
]
}
},
"span": {
"line_start": 11,
"line_stop": 11,
"col_start": 18,
"col_stop": 22,
"path": "",
"content": " console.assert(y[0] == 4u8);"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"4",
{
"line_start": 11,
"line_stop": 11,
"col_start": 26,
"col_stop": 29,
"path": "",
"content": " console.assert(y[0] == 4u8);"
}
]
}
},
"op": "Eq",
"span": {
"line_start": 11,
"line_stop": 11,
"col_start": 18,
"col_stop": 29,
"path": "",
"content": " console.assert(y[0] == 4u8);"
}
}
}
},
"span": {
"line_start": 11,
"line_stop": 11,
"col_start": 3,
"col_stop": 29,
"path": "",
"content": " console.assert(y[0] == 4u8);"
}
}
},
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let z = (1u8, 2u8);\\\"}\"}",
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 7,
"col_stop": 8,
"path": "",
"content": " let z = (1u8, 2u8);"
}
}
],
"type_": null,
"value": {
"TupleInit": {
"elements": [
{
"Value": {
"Integer": [
"U8",
"1",
{
"line_start": 13,
"line_stop": 13,
"col_start": 12,
"col_stop": 15,
"path": "",
"content": " let z = (1u8, 2u8);"
}
]
}
},
{
"Value": {
"Integer": [
"U8",
"2",
{
"line_start": 13,
"line_stop": 13,
"col_start": 17,
"col_stop": 20,
"path": "",
"content": " let z = (1u8, 2u8);"
}
]
}
}
],
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 11,
"col_stop": 21,
"path": "",
"content": " let z = (1u8, 2u8);"
}
}
},
"span": {
"line_start": 13,
"line_stop": 13,
"col_start": 3,
"col_stop": 21,
"path": "",
"content": " let z = (1u8, 2u8);"
}
}
},
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" z.1 += 3u8;\\\"}\"}",
"accesses": [
{
"Tuple": [
{
"value": "1"
},
{
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 6,
"path": "",
"content": " z.1 += 3u8;"
}
]
}
],
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 6,
"path": "",
"content": " z.1 += 3u8;"
}
},
"value": {
"Binary": {
"left": {
"TupleAccess": {
"tuple": {
"Identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" z.1 += 3u8;\\\"}\"}"
},
"index": {
"value": "1"
},
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 13,
"path": "",
"content": " z.1 += 3u8;"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"3",
{
"line_start": 14,
"line_stop": 14,
"col_start": 10,
"col_stop": 13,
"path": "",
"content": " z.1 += 3u8;"
}
]
}
},
"op": "Add",
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 13,
"path": "",
"content": " z.1 += 3u8;"
}
}
},
"span": {
"line_start": 14,
"line_stop": 14,
"col_start": 3,
"col_stop": 13,
"path": "",
"content": " z.1 += 3u8;"
}
}
},
{
"Console": {
"function": {
"Assert": {
"Binary": {
"left": {
"TupleAccess": {
"tuple": {
"Identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":15,\\\"line_stop\\\":15,\\\"col_start\\\":18,\\\"col_stop\\\":19,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(z.1 == 5u8);\\\"}\"}"
},
"index": {
"value": "1"
},
"span": {
"line_start": 15,
"line_stop": 15,
"col_start": 18,
"col_stop": 21,
"path": "",
"content": " console.assert(z.1 == 5u8);"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"5",
{
"line_start": 15,
"line_stop": 15,
"col_start": 25,
"col_stop": 28,
"path": "",
"content": " console.assert(z.1 == 5u8);"
}
]
}
},
"op": "Eq",
"span": {
"line_start": 15,
"line_stop": 15,
"col_start": 18,
"col_stop": 28,
"path": "",
"content": " console.assert(z.1 == 5u8);"
}
}
}
},
"span": {
"line_start": 15,
"line_stop": 15,
"col_start": 3,
"col_stop": 28,
"path": "",
"content": " console.assert(z.1 == 5u8);"
}
}
},
{
"Definition": {
"declaration_type": "Let",
"variable_names": [
{
"mutable": true,
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo = Foo { f: 6u8 };\\\"}\"}",
"span": {
"line_start": 17,
"line_stop": 17,
"col_start": 7,
"col_stop": 10,
"path": "",
"content": " let foo = Foo { f: 6u8 };"
}
}
],
"type_": null,
"value": {
"CircuitInit": {
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":13,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo = Foo { f: 6u8 };\\\"}\"}",
"members": [
{
"identifier": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":19,\\\"col_stop\\\":20,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo = Foo { f: 6u8 };\\\"}\"}",
"expression": {
"Value": {
"Integer": [
"U8",
"6",
{
"line_start": 17,
"line_stop": 17,
"col_start": 22,
"col_stop": 25,
"path": "",
"content": " let foo = Foo { f: 6u8 };"
}
]
}
}
}
],
"span": {
"line_start": 17,
"line_stop": 17,
"col_start": 13,
"col_stop": 27,
"path": "",
"content": " let foo = Foo { f: 6u8 };"
}
}
},
"span": {
"line_start": 17,
"line_stop": 17,
"col_start": 3,
"col_stop": 27,
"path": "",
"content": " let foo = Foo { f: 6u8 };"
}
}
},
{
"Assign": {
"operation": "Assign",
"assignee": {
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":3,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}",
"accesses": [
{
"Member": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}"
}
],
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 3,
"col_stop": 8,
"path": "",
"content": " foo.f += 2u8;"
}
},
"value": {
"Binary": {
"left": {
"CircuitMemberAccess": {
"circuit": {
"Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":3,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}"
},
"name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}",
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 3,
"col_stop": 15,
"path": "",
"content": " foo.f += 2u8;"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"2",
{
"line_start": 18,
"line_stop": 18,
"col_start": 12,
"col_stop": 15,
"path": "",
"content": " foo.f += 2u8;"
}
]
}
},
"op": "Add",
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 3,
"col_stop": 15,
"path": "",
"content": " foo.f += 2u8;"
}
}
},
"span": {
"line_start": 18,
"line_stop": 18,
"col_start": 3,
"col_stop": 15,
"path": "",
"content": " foo.f += 2u8;"
}
}
},
{
"Console": {
"function": {
"Assert": {
"Binary": {
"left": {
"CircuitMemberAccess": {
"circuit": {
"Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":19,\\\"line_stop\\\":19,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(foo.f == 8u8);\\\"}\"}"
},
"name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":19,\\\"line_stop\\\":19,\\\"col_start\\\":22,\\\"col_stop\\\":23,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" console.assert(foo.f == 8u8);\\\"}\"}",
"span": {
"line_start": 19,
"line_stop": 19,
"col_start": 18,
"col_stop": 23,
"path": "",
"content": " console.assert(foo.f == 8u8);"
}
}
},
"right": {
"Value": {
"Integer": [
"U8",
"8",
{
"line_start": 19,
"line_stop": 19,
"col_start": 27,
"col_stop": 30,
"path": "",
"content": " console.assert(foo.f == 8u8);"
}
]
}
},
"op": "Eq",
"span": {
"line_start": 19,
"line_stop": 19,
"col_start": 18,
"col_stop": 30,
"path": "",
"content": " console.assert(foo.f == 8u8);"
}
}
}
},
"span": {
"line_start": 19,
"line_stop": 19,
"col_start": 3,
"col_stop": 30,
"path": "",
"content": " console.assert(foo.f == 8u8);"
}
}
],
"span": {
"line_start": 1,
"line_stop": 4,
"col_start": 17,
"col_stop": 2,
"path": ""
}
},
],
"span": {
"line_start": 1,
"line_stop": 4,
"col_start": 1,
"line_start": 4,
"line_stop": 20,
"col_start": 17,
"col_stop": 2,
"path": ""
"path": "",
"content": "function main() {\n...\n} "
}
},
"span": {
"line_start": 4,
"line_stop": 20,
"col_start": 1,
"col_stop": 2,
"path": "",
"content": "function main() {\n...\n} \n\n\n\n\n\n\n\n\n\n\n\n\n\n"
}
}
}
}

View File

@ -1,4 +1,20 @@
circuit Foo {
f: u8,
}
function main() {
let x = 10u32;
x += 20;
console.assert(x == 30u32);
let y = [1u8, 2u8];
y[0] += 3u8;
console.assert(y[0] == 4u8);
let z = (1u8, 2u8);
z.1 += 3u8;
console.assert(z.1 == 5u8);
let foo = Foo { f: 6u8 };
foo.f += 2u8;
console.assert(foo.f == 8u8);
}

View File

@ -308,3 +308,11 @@ fn test_duplicate_name_context() {
assert_satisfied(program);
}
#[test]
fn test_mutable_call_immutable_context() {
let program_string = include_str!("mutable_call_immutable_context.leo");
let program = parse_program(program_string).unwrap();
assert_satisfied(program);
}

View File

@ -0,0 +1,12 @@
circuit TestMe {
x: u8,
function test_me(mut self) -> u8 {
self.x += 1;
return self.x
}
}
function main () {
const t = TestMe {x: 6u8}.test_me();
}

View File

@ -74,6 +74,14 @@ fn test_field() {
assert_satisfied(program)
}
#[test]
fn test_no_space_between_literal() {
let program_string = include_str!("no_space_between_literal.leo");
let mut program = parse_program(program_string).unwrap();
expect_compiler_error(program)
}
#[test]
fn test_add() {
use std::ops::Add;

View File

@ -0,0 +1,3 @@
function main() {
const f = 1 field;
}

View File

@ -5,5 +5,5 @@ function main() {
do_nothing(arr);
do_nothing([...arr]);
do_nothing(arr[1u32..]);
do_nothing(arr[0u32..]);
}

View File

@ -0,0 +1,7 @@
function main() {
console.log("{}", 1u8);
}
function main() {
console.log("{}", 2u8);
}

View File

@ -211,3 +211,11 @@ fn test_array_params_direct_call() {
assert_satisfied(program);
}
#[test]
fn test_duplicate_function_definition() {
let program_string = include_str!("duplicate_definition.leo");
let error = parse_program(program_string).err().unwrap();
expect_asg_error(error);
}

View File

@ -45,6 +45,14 @@ pub fn group_element_to_input_value(g: EdwardsAffine) -> GroupValue {
})
}
#[test]
fn test_no_space_between_literal() {
let program_string = include_str!("no_space_between_literal.leo");
let mut program = parse_program(program_string).unwrap();
expect_compiler_error(program)
}
#[test]
fn test_one() {
let program_string = include_str!("one.leo");

View File

@ -0,0 +1,3 @@
function main() {
const g = (0,1) group;
}

View File

@ -132,3 +132,11 @@ fn test_i128_assert_eq() {
fn test_i128_ternary() {
TestI128::test_ternary();
}
#[test]
fn test_no_space_between_literal() {
let program_string = include_str!("no_space_between_literal.leo");
let program = parse_program(program_string);
assert!(program.is_err());
}

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