mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 23:23:50 +03:00
merge master, slight clean up
This commit is contained in:
commit
c7bcab3ccc
195
.circleci/config.yml
Normal file
195
.circleci/config.yml
Normal file
@ -0,0 +1,195 @@
|
||||
version: 2.1
|
||||
commands:
|
||||
setup_environment:
|
||||
description: "Setup environment"
|
||||
parameters:
|
||||
cache_key:
|
||||
type: string
|
||||
default: leo-stable-cache
|
||||
steps:
|
||||
- run: set -e
|
||||
- setup_remote_docker
|
||||
- run:
|
||||
name: Prepare environment and install dependencies
|
||||
command: |
|
||||
export SCCACHE_CACHE_SIZE=200M
|
||||
export WORK_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache"
|
||||
export SCCACHE_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache"
|
||||
mkdir -p "$CIRCLE_WORKING_DIRECTORY/.bin"
|
||||
wget https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz
|
||||
tar -C "$CIRCLE_WORKING_DIRECTORY/.bin" -xvf sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz
|
||||
mv $CIRCLE_WORKING_DIRECTORY/.bin/sccache-0.2.13-x86_64-unknown-linux-musl/sccache $CIRCLE_WORKING_DIRECTORY/.bin/sccache
|
||||
export PATH="$PATH:$CIRCLE_WORKING_DIRECTORY/.bin"
|
||||
export RUSTC_WRAPPER="sccache"
|
||||
rm -rf "$CIRCLE_WORKING_DIRECTORY/.cargo/registry"
|
||||
sudo apt-get update && sudo apt-get install -y clang llvm-dev llvm pkg-config xz-utils make libssl-dev libssl-dev
|
||||
- restore_cache:
|
||||
keys:
|
||||
- << parameters.cache_key >>
|
||||
clear_environment:
|
||||
description: "Clear environment"
|
||||
parameters:
|
||||
cache_key:
|
||||
type: string
|
||||
default: leo-stable-cache
|
||||
steps:
|
||||
- run: (sccache -s||true)
|
||||
- run: set +e
|
||||
- save_cache:
|
||||
key: << parameters.cache_key >>
|
||||
paths:
|
||||
- .cache/sccache
|
||||
- .cargo
|
||||
jobs:
|
||||
|
||||
rust-stable:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout
|
||||
- setup_environment:
|
||||
cache_key: leo-stable-cache
|
||||
- run:
|
||||
name: Build and run tests
|
||||
no_output_timeout: 30m
|
||||
command: cargo install --path . --root .
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths: project/
|
||||
- clear_environment:
|
||||
cache_key: leo-stable-cache
|
||||
|
||||
leo-new:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo new
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-new.sh
|
||||
|
||||
leo-init:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo init
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-init.sh
|
||||
|
||||
leo-clean:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo clean
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-clean.sh
|
||||
|
||||
leo-setup:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo setup
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-setup.sh
|
||||
|
||||
leo-add-remove:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo add & remove
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-add-remove.sh
|
||||
|
||||
leo-login-logout:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo login & logout
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-login-logout.sh
|
||||
|
||||
leo-clone:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo clone
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-clone.sh
|
||||
|
||||
leo-publish:
|
||||
docker:
|
||||
- image: cimg/rust:1.50.0
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci/project/
|
||||
- run:
|
||||
name: leo publish
|
||||
command: |
|
||||
export LEO=/home/circleci/project/project/bin/leo
|
||||
./project/.circleci/leo-publish.sh
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
main-workflow:
|
||||
jobs:
|
||||
- rust-stable
|
||||
- leo-new:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-init:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-clean:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-setup:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-add-remove:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-login-logout:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-clone:
|
||||
requires:
|
||||
- rust-stable
|
||||
- leo-publish:
|
||||
requires:
|
||||
- rust-stable
|
6
.circleci/leo-add-remove.sh
Executable file
6
.circleci/leo-add-remove.sh
Executable file
@ -0,0 +1,6 @@
|
||||
# leo add (w/o login) & remove
|
||||
|
||||
$LEO new my-app && cd my-app
|
||||
$LEO add howard/silly-sudoku
|
||||
$LEO remove silly-sudoku
|
||||
$LEO clean
|
34
.circleci/leo-clean.sh
Executable file
34
.circleci/leo-clean.sh
Executable file
@ -0,0 +1,34 @@
|
||||
# leo new hello-world
|
||||
|
||||
$LEO new hello-world
|
||||
ls -la
|
||||
cd hello-world && ls -la
|
||||
$LEO run
|
||||
|
||||
# Assert that the 'outputs' folder is not empty
|
||||
|
||||
cd outputs || exit 1
|
||||
if [ "$(ls -A $DIR)" ]; then
|
||||
echo "$DIR is not empty"
|
||||
else
|
||||
echo "$DIR is empty"
|
||||
exit 1
|
||||
fi
|
||||
cd ..
|
||||
|
||||
# leo clean
|
||||
|
||||
$LEO clean
|
||||
cd outputs && ls -la
|
||||
cd ..
|
||||
|
||||
# Assert that the 'outputs' folder is empty
|
||||
|
||||
cd outputs || exit 1
|
||||
if [ "$(ls -A $DIR)" ]; then
|
||||
echo "$DIR is not empty"
|
||||
exit 1
|
||||
else
|
||||
echo "$DIR is empty"
|
||||
exit 0
|
||||
fi
|
18
.circleci/leo-clone.sh
Executable file
18
.circleci/leo-clone.sh
Executable file
@ -0,0 +1,18 @@
|
||||
# leo clone
|
||||
|
||||
# Clone the test-app package.
|
||||
export PACKAGE="$ALEO_PM_USERNAME/test-app"
|
||||
$LEO clone $PACKAGE
|
||||
|
||||
# Assert that the 'test-app' folder is not empty
|
||||
|
||||
cd test-app || exit 1
|
||||
if [ "$(ls -A $DIR)" ]; then
|
||||
echo "$DIR is not empty"
|
||||
else
|
||||
echo "$DIR is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ls -la
|
||||
$LEO run
|
4
.circleci/leo-init.sh
Executable file
4
.circleci/leo-init.sh
Executable file
@ -0,0 +1,4 @@
|
||||
mkdir hello-world && cd hello-world || exit 1
|
||||
$LEO init
|
||||
ls -la
|
||||
$LEO run
|
7
.circleci/leo-login-logout.sh
Executable file
7
.circleci/leo-login-logout.sh
Executable file
@ -0,0 +1,7 @@
|
||||
# leo login & logout
|
||||
|
||||
$LEO new my-app && cd my-app || exit 1
|
||||
$LEO login -u "$ALEO_PM_USERNAME" -p "$ALEO_PM_PASSWORD"
|
||||
$LEO add howard/silly-sudoku
|
||||
$LEO remove silly-sudoku
|
||||
$LEO logout
|
4
.circleci/leo-new.sh
Executable file
4
.circleci/leo-new.sh
Executable file
@ -0,0 +1,4 @@
|
||||
$LEO new hello-world
|
||||
ls -la
|
||||
cd hello-world && ls -la
|
||||
$LEO run
|
56
.circleci/leo-publish.sh
Executable file
56
.circleci/leo-publish.sh
Executable file
@ -0,0 +1,56 @@
|
||||
# leo login, publish and logout
|
||||
|
||||
# Login
|
||||
$LEO login -u "$ALEO_PM_USERNAME" -p "$ALEO_PM_PASSWORD"
|
||||
|
||||
# Clone the test-app package.
|
||||
export PACKAGE="$ALEO_PM_USERNAME/test-app"
|
||||
$LEO clone $PACKAGE
|
||||
cd test-app || exit 1
|
||||
|
||||
# Fetch the current Leo package version number.
|
||||
#
|
||||
# 1. Print out the Leo.toml file.
|
||||
# 2. Search for a line with the word "version".
|
||||
# 3. Isolate that into a single line.
|
||||
# 4. Split the line from the '=' sign and keep the right-hand side.
|
||||
# 5. Remove the quotes around the version number.
|
||||
# 6. Trim any excess whitespace.
|
||||
export CURRENT=$(cat Leo.toml \
|
||||
| grep version \
|
||||
| head -1 \
|
||||
| awk -F= '{ print $2 }' \
|
||||
| sed 's/[",]//g' \
|
||||
| xargs)
|
||||
|
||||
# Increment the current Leo package version number by 1.
|
||||
#
|
||||
# 1. Print out the Leo.toml file.
|
||||
# 2. Search for a line with the word "version".
|
||||
# 3. Isolate that into a single line.
|
||||
# 4. Split the line from the '=' sign and keep the right-hand side.
|
||||
# 5. Remove the quotes around the version number.
|
||||
# 6. Trim any excess whitespace.
|
||||
# 7. Increment the version number by 1 (on the semver patch).
|
||||
#
|
||||
# https://stackoverflow.com/questions/8653126/how-to-increment-version-number-in-a-shell-script
|
||||
export UPDATED=$(cat Leo.toml \
|
||||
| grep version \
|
||||
| head -1 \
|
||||
| awk -F= '{ print $2 }' \
|
||||
| sed 's/[",]//g' \
|
||||
| xargs \
|
||||
| awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF+1)%(10^length($NF))); print}')
|
||||
|
||||
# Write the updated Leo package version number to the Leo.toml file.
|
||||
export TOML=$(cat Leo.toml | sed "s/$CURRENT/$UPDATED/g")
|
||||
echo "$TOML" > Leo.toml
|
||||
|
||||
# Run the package to confirm the manifest remains well-formed.
|
||||
$LEO run
|
||||
|
||||
# Publish the package to Aleo.pm
|
||||
$LEO publish
|
||||
|
||||
# Logout
|
||||
$LEO logout
|
7
.circleci/leo-setup.sh
Executable file
7
.circleci/leo-setup.sh
Executable file
@ -0,0 +1,7 @@
|
||||
# leo setup
|
||||
|
||||
cd ./project/examples/pedersen-hash || exit 1
|
||||
$LEO setup
|
||||
$LEO setup
|
||||
$LEO setup --skip-key-check
|
||||
$LEO clean
|
43
.github/workflows/leo-add-remove.yml
vendored
43
.github/workflows/leo-add-remove.yml
vendored
@ -1,43 +0,0 @@
|
||||
name: leo-add-remove
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
add:
|
||||
name: Add Package ('leo add')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo add (w/o login) & remove'
|
||||
run: |
|
||||
cd .. && leo new my-app && cd my-app
|
||||
leo add argus4130/xnor
|
||||
leo remove xnor
|
||||
leo clean
|
||||
|
76
.github/workflows/leo-clean.yml
vendored
76
.github/workflows/leo-clean.yml
vendored
@ -1,76 +0,0 @@
|
||||
name: leo-clean
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
new:
|
||||
name: Hello Leo ('leo new hello-world')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo new hello-world'
|
||||
run: |
|
||||
cd ..
|
||||
leo new hello-world
|
||||
ls -la
|
||||
cd hello-world && ls -la
|
||||
leo run
|
||||
|
||||
- name: Assert that the 'outputs' folder is not empty
|
||||
run: |
|
||||
cd ../hello-world/outputs
|
||||
if [ "$(ls -A $DIR)" ]; then
|
||||
echo "$DIR is not empty"
|
||||
else
|
||||
echo "$DIR is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 'leo clean'
|
||||
run: |
|
||||
cd ../hello-world
|
||||
leo clean
|
||||
cd outputs && ls -la
|
||||
|
||||
- name: Assert that the 'outputs' folder is empty
|
||||
run: |
|
||||
cd ../hello-world/outputs
|
||||
if [ "$(ls -A $DIR)" ]; then
|
||||
echo "$DIR is not empty"
|
||||
exit 1
|
||||
else
|
||||
echo "$DIR is empty"
|
||||
exit 0
|
||||
fi
|
48
.github/workflows/leo-init.yml
vendored
48
.github/workflows/leo-init.yml
vendored
@ -1,48 +0,0 @@
|
||||
name: leo-init
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
init:
|
||||
name: Hello Leo ('leo init')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo init'
|
||||
run: |
|
||||
cd .. && mkdir hello-world && cd hello-world
|
||||
leo init
|
||||
ls -la
|
||||
leo run
|
47
.github/workflows/leo-login-logout.yml
vendored
47
.github/workflows/leo-login-logout.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: leo-login-logout
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
add:
|
||||
name: Add Package ('leo add')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo login & logout'
|
||||
env:
|
||||
USER: ${{ secrets.ALEO_PM_USERNAME }}
|
||||
PASS: ${{ secrets.ALEO_PM_PASSWORD }}
|
||||
run: |
|
||||
cd .. && leo new my-app && cd my-app
|
||||
leo login -u "$USER" -p "$PASS"
|
||||
leo add argus4130/xnor
|
||||
leo remove xnor
|
||||
leo logout
|
||||
|
49
.github/workflows/leo-new.yml
vendored
49
.github/workflows/leo-new.yml
vendored
@ -1,49 +0,0 @@
|
||||
name: leo-new
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
new:
|
||||
name: Hello Leo ('leo new hello-world')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo new hello-world'
|
||||
run: |
|
||||
cd ..
|
||||
leo new hello-world
|
||||
ls -la
|
||||
cd hello-world && ls -la
|
||||
leo run
|
47
.github/workflows/leo-setup.yml
vendored
47
.github/workflows/leo-setup.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: leo-setup
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'documentation/**'
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
add:
|
||||
name: Add Package ('leo add')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
components: rustfmt
|
||||
|
||||
- name: Install Leo
|
||||
uses: actions-rs/cargo@v1
|
||||
env:
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
with:
|
||||
command: install
|
||||
args: --path .
|
||||
|
||||
- name: 'leo setup for examples'
|
||||
env:
|
||||
USER: ${{ secrets.ALEO_PM_USERNAME }}
|
||||
PASS: ${{ secrets.ALEO_PM_PASSWORD }}
|
||||
run: |
|
||||
cd examples/pedersen-hash
|
||||
leo setup
|
||||
leo setup
|
||||
leo setup --skip-key-check
|
||||
leo clean
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -2,3 +2,9 @@
|
||||
/tmp/
|
||||
**.idea/
|
||||
*.DS_Store
|
||||
|
||||
**/process.yml
|
||||
|
||||
**/.crates.toml
|
||||
**/.crates2.json
|
||||
**/bin/
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
88
CONTRIBUTING.md
Normal file
88
CONTRIBUTING.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Contributing
|
||||
|
||||
Thank you for your interest in contributing to Leo! Below you can find some guidelines that the project strives to follow.
|
||||
|
||||
## Pull requests
|
||||
|
||||
Please follow the instructions below when filing pull requests:
|
||||
|
||||
- Ensure that your branch is forked from the current [master](https://github.com/AleoHQ/leo/tree/master) branch.
|
||||
- Fill out the provided markdown template for the feature or proposal. Be sure to link the pull request to any issues by using keywords. Example: "closes #130".
|
||||
- Run `cargo fmt` before you commit; we use the `nightly` version of `rustfmt` to format the code, so you'll need to have the `nightly` toolchain installed on your machine; there's a [git hook](https://git-scm.com/docs/githooks) that ensures proper formatting before any commits can be made, and [`.rustfmt.toml`](https://github.com/AleoHQ/Leo/blob/master/.rustfmt.toml) specifies some of the formatting conventions.
|
||||
- Run `cargo clippy` to ensure that popular correctness and performance pitfalls are avoided.
|
||||
|
||||
## Style
|
||||
|
||||
These guidelines ensure consistent readable rust code within the Leo repository.
|
||||
|
||||
### Comments
|
||||
|
||||
Prefer line comments (//) to block comments (/* ... */).
|
||||
|
||||
When using single-line block comments there should be a single space after the opening sigil and before the closing sigil. Multi-line block comments should have a newline after the opening sigil and before the closing sigil.
|
||||
|
||||
Prefer to put a comment on its own line. Where a comment follows code, there should be a single space before it. Where a block comment is inline, there should be surrounding whitespace as if it were an identifier or keyword. There should be no trailing whitespace after a comment or at the end of any line in a multi-line comment. Examples:
|
||||
|
||||
```rust
|
||||
// A comment on an item.
|
||||
struct Foo { ... }
|
||||
|
||||
fn foo() {} // A comment after an item.
|
||||
|
||||
pub fn foo(/* a comment before an argument */ x: T) {...}
|
||||
```
|
||||
|
||||
Comments should be complete sentences. Start with a capital letter, end with a period (.). An inline block comment may be treated as a note without punctuation.
|
||||
|
||||
### Imports
|
||||
|
||||
* Stated at the top of the file
|
||||
* Ordered alphabetically
|
||||
* Split in two sections
|
||||
* First party: crate imports + Aleo imports (example: snarkVM)
|
||||
* Third party: rust std + everything else
|
||||
|
||||
Example:
|
||||
```rust
|
||||
|
||||
use crate::Circuit;
|
||||
use leo_ast::IntegerType;
|
||||
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
fmt,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
```
|
||||
|
||||
`rust fmt` should automatically sort imports alphabetically after they are split into the appropriate sections.
|
||||
|
||||
## Coding conventions
|
||||
|
||||
Leo is a big project, so (non-)adherence to best practices related to performance can have a considerable impact; below are the rules we try to follow at all times in order to ensure high quality of the code:
|
||||
|
||||
### Memory handling
|
||||
- If the final size is known, pre-allocate the collections (`Vec`, `HashMap` etc.) using `with_capacity` or `reserve` - this ensures that there are both fewer allocations (which involve system calls) and that the final allocated capacity is as close to the required size as possible.
|
||||
- Create the collections right before they are populated/used, as opposed to e.g. creating a few big ones at the beginning of a function and only using them later on; this reduces the amount of time they occupy memory.
|
||||
- If an intermediate vector is avoidable, use an `Iterator` instead; most of the time this just amounts to omitting the call to `.collect()` if a single-pass iteraton follows afterwards, or returning an `impl Iterator<Item = T>` from a function when the caller only needs to iterate over that result once.
|
||||
- When possible, fill/resize collections "in bulk" instead of pushing a single element in a loop; this is usually (but not always) detected by `clippy`, suggesting to create vectors containing a repeated value with `vec![x; N]` or extending them with `.resize(N, x)`.
|
||||
- When a value is to eventually be consumed in a chain of function calls, pass it by value instead of by reference; this has the following benefits:
|
||||
* It makes the fact that the value is needed by value clear to the caller, who can then potentially reclaim it from the object afterwards if it is "heavy", limiting allocations.
|
||||
* It often enables the value to be cloned fewer times (whenever it's no longer needed at the callsite).
|
||||
* When the value is consumed and is not needed afterwards, the memory it occupies is freed, improving memory utilization.
|
||||
- If a slice may or may _not_ be extended (which requires a promotion to a vector) and does not need to be consumed afterwards, consider using a [`Cow<'a, [T]>`](https://doc.rust-lang.org/std/borrow/enum.Cow.html) combined with `Cow::to_mut` instead to potentially avoid an extra allocation; an example in Leo could be conditional padding of bits.
|
||||
- Prefer arrays and temporary slices to vectors where possible; arrays are often a good choice if their final size is known in advance and isn't too great (as they are stack-bound), and a small temporary slice `&[x, y, z]` is preferable to a `vec![x, y, z]` if it's applicable.
|
||||
- If a reference is sufficient, don't use `.clone()`/`to_vec()`, which is often the case with methods on `struct`s that provide access to their contents; if they only need to be referenced, there's no need for the extra allocation.
|
||||
- Use `into_iter()` instead of `iter().cloned()` where possible, i.e. whenever the values being iterated over can be consumed altogether.
|
||||
- If possible, reuse collections; an example would be a loop that needs a clean vector on each iteration: instead of creating and allocating it over and over, create it _before_ the loop and use `.clear()` on every iteration instead.
|
||||
- Try to keep the sizes of `enum` variants uniform; use `Box<T>` on ones that are large.
|
||||
|
||||
### Misc. performance
|
||||
|
||||
- Avoid the `format!()` macro; if it is used only to convert a single value to a `String`, use `.to_string()` instead, which is also available to all the implementors of `Display`.
|
||||
- Don't check if an element belongs to a map (using `contains` or `get`) if you want to conditionally insert it too, as the return value of `insert` already indicates whether the value was present or not; use that or the `Entry` API instead.
|
||||
- If a reference is sufficient as a function parameter, use:
|
||||
* `&[T]` instead of `&Vec<T>`
|
||||
* `&str` instead of `&String`
|
||||
* `&Path` instead of `&PathBuf`
|
||||
- For `struct`s that can be compared/discerned based on some specific field(s), consider hand-written implementations of `PartialEq` **and** `Hash` ([they must match](https://doc.rust-lang.org/std/hash/trait.Hash.html#hash-and-eq)) for faster comparison and hashing.
|
711
Cargo.lock
generated
711
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
22
Cargo.toml
@ -35,7 +35,7 @@ members = [
|
||||
"input",
|
||||
"linter",
|
||||
"package",
|
||||
"state"
|
||||
"state",
|
||||
]
|
||||
|
||||
[dependencies.leo-ast]
|
||||
@ -67,27 +67,27 @@ path = "./state"
|
||||
version = "1.2.2"
|
||||
|
||||
[dependencies.snarkvm-algorithms]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.snarkvm-curves]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.snarkvm-errors]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.snarkvm-gadgets]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.snarkvm-models]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
default-features = false
|
||||
|
||||
[dependencies.snarkvm-utilities]
|
||||
version = "0.0.4"
|
||||
version = "0.0.5"
|
||||
|
||||
[dependencies.anyhow]
|
||||
version = "1.0"
|
||||
@ -120,17 +120,17 @@ version = "4.0.15"
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.7"
|
||||
version = "0.8"
|
||||
|
||||
[dependencies.rand_core]
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
features = [ "blocking", "json", "multipart" ]
|
||||
|
||||
[dependencies.self_update]
|
||||
version = "0.23.0"
|
||||
version = "0.25.0"
|
||||
features = [ "archive-zip" ]
|
||||
|
||||
[dependencies.serde]
|
||||
|
31
DEVELOPMENT.md
Normal file
31
DEVELOPMENT.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Development Guide
|
||||
|
||||
## Running CircleCI locally
|
||||
|
||||
### Step 1: Install CircleCI
|
||||
|
||||
If you wish to run CircleCI locally, start by installing it:
|
||||
|
||||
- macOS
|
||||
```
|
||||
brew install circleci
|
||||
```
|
||||
|
||||
- Linux (via Snap)
|
||||
```
|
||||
sudo snap install docker circleci
|
||||
sudo snap connect circleci:docker docker
|
||||
```
|
||||
|
||||
- Windows (via Chocolatey)
|
||||
```
|
||||
choco install circleci-cli -y
|
||||
```
|
||||
|
||||
### Step 2: Run CircleCI
|
||||
|
||||
To run a job, export the config to `process.yml`, and specify it when executing:
|
||||
```shell
|
||||
circleci config process .circleci/config.yml > process.yml
|
||||
circleci local execute -c process.yml --job JOB_NAME
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img width="1412" src="./.resources/leo.png">
|
||||
<img width="1412" src=".resources/banner.png">
|
||||
</p>
|
||||
|
||||
<h1 align="center">The Leo Programming Language</h1>
|
||||
@ -27,6 +27,7 @@ Leo is a functional, statically-typed programming language built for writing pri
|
||||
|
||||
|
||||
## 1. Overview
|
||||
|
||||
Welcome to the Leo programming language.
|
||||
|
||||
Leo provides a high-level language that abstracts low-level cryptographic concepts and makes it easy to
|
||||
|
@ -37,12 +37,11 @@ path = "../ast"
|
||||
version = "1.2.2"
|
||||
path = "../grammar"
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "0.8"
|
||||
features = [ "v4", "serde" ]
|
||||
|
||||
[dependencies.num-bigint]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.typed-arena]
|
||||
version = "2.0"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3"
|
||||
|
@ -25,8 +25,6 @@ use crate::{
|
||||
Span,
|
||||
};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct ReturnPathReducer {
|
||||
pub errors: Vec<(Span, String)>,
|
||||
}
|
||||
@ -48,14 +46,14 @@ impl Default for ReturnPathReducer {
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
impl MonoidalReducerExpression<BoolAnd> for ReturnPathReducer {
|
||||
fn reduce_expression(&mut self, input: &Arc<Expression>, value: BoolAnd) -> BoolAnd {
|
||||
impl<'a> MonoidalReducerExpression<'a, BoolAnd> for ReturnPathReducer {
|
||||
fn reduce_expression(&mut self, input: &'a Expression<'a>, value: BoolAnd) -> BoolAnd {
|
||||
BoolAnd(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
impl MonoidalReducerStatement<BoolAnd> for ReturnPathReducer {
|
||||
impl<'a> MonoidalReducerStatement<'a, BoolAnd> for ReturnPathReducer {
|
||||
fn reduce_assign_access(&mut self, input: &AssignAccess, left: Option<BoolAnd>, right: Option<BoolAnd>) -> BoolAnd {
|
||||
BoolAnd(false)
|
||||
}
|
||||
@ -69,7 +67,7 @@ impl MonoidalReducerStatement<BoolAnd> for ReturnPathReducer {
|
||||
BoolAnd(false)
|
||||
} else if let Some(index) = statements[..statements.len() - 1].iter().map(|x| x.0).position(|x| x) {
|
||||
self.record_error(
|
||||
input.statements[index].span(),
|
||||
input.statements[index].get().span(),
|
||||
"dead code due to unconditional early return".to_string(),
|
||||
);
|
||||
BoolAnd(true)
|
||||
|
@ -226,7 +226,7 @@ impl ConstInt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> Type {
|
||||
pub fn get_type<'a>(&self) -> Type<'a> {
|
||||
Type::Integer(self.get_int_type())
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ impl ConstInt {
|
||||
}
|
||||
|
||||
impl ConstValue {
|
||||
pub fn get_type(&self) -> Option<Type> {
|
||||
pub fn get_type<'a>(&self) -> Option<Type<'a>> {
|
||||
Some(match self {
|
||||
ConstValue::Int(i) => i.get_type(),
|
||||
ConstValue::Group(_) => Type::Group,
|
||||
|
46
asg/src/context.rs
Normal file
46
asg/src/context.rs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 std::{cell::Cell, unimplemented};
|
||||
|
||||
use typed_arena::Arena;
|
||||
|
||||
use crate::ArenaNode;
|
||||
|
||||
pub struct AsgContextInner<'a> {
|
||||
pub arena: &'a Arena<ArenaNode<'a>>,
|
||||
pub next_id: Cell<u32>,
|
||||
}
|
||||
|
||||
impl<'a> AsgContextInner<'a> {
|
||||
pub fn new(arena: &'a Arena<ArenaNode<'a>>) -> &'a Self {
|
||||
match arena.alloc(ArenaNode::Inner(AsgContextInner {
|
||||
arena,
|
||||
next_id: Cell::new(0),
|
||||
})) {
|
||||
ArenaNode::Inner(x) => x,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> u32 {
|
||||
let next_id = self.next_id.get();
|
||||
self.next_id.replace(next_id + 1);
|
||||
next_id
|
||||
}
|
||||
}
|
||||
|
||||
pub type AsgContext<'a> = &'a AsgContextInner<'a>;
|
@ -17,56 +17,53 @@
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
use leo_ast::IntegerType;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArrayAccessExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayAccessExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub array: Arc<Expression>,
|
||||
pub index: Arc<Expression>,
|
||||
pub array: Cell<&'a Expression<'a>>,
|
||||
pub index: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for ArrayAccessExpression {
|
||||
impl<'a> Node for ArrayAccessExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for ArrayAccessExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for ArrayAccessExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.array.set_parent(Arc::downgrade(expr));
|
||||
self.index.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.array.get().set_parent(expr);
|
||||
self.index.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
match self.array.get_type() {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
match self.array.get().get_type() {
|
||||
Some(Type::Array(element, _)) => Some(*element),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
self.array.is_mut_ref()
|
||||
self.array.get().is_mut_ref()
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
let mut array = match self.array.const_value()? {
|
||||
let mut array = match self.array.get().const_value()? {
|
||||
ConstValue::Array(values) => values,
|
||||
_ => return None,
|
||||
};
|
||||
let const_index = match self.index.const_value()? {
|
||||
let const_index = match self.index.get().const_value()? {
|
||||
ConstValue::Int(x) => x.to_usize()?,
|
||||
_ => return None,
|
||||
};
|
||||
@ -77,17 +74,17 @@ impl ExpressionNode for ArrayAccessExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.array.is_consty()
|
||||
self.array.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ArrayAccessExpression> for ArrayAccessExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::ArrayAccessExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<ArrayAccessExpression, AsgConvertError> {
|
||||
let array = Arc::<Expression>::from_ast(
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<ArrayAccessExpression<'a>, AsgConvertError> {
|
||||
let array = <&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&*value.array,
|
||||
Some(PartialType::Array(expected_type.map(Box::new), None)),
|
||||
@ -103,7 +100,7 @@ impl FromAst<leo_ast::ArrayAccessExpression> for ArrayAccessExpression {
|
||||
}
|
||||
}
|
||||
|
||||
let index = Arc::<Expression>::from_ast(
|
||||
let index = <&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&*value.index,
|
||||
Some(PartialType::Integer(None, Some(IntegerType::U32))),
|
||||
@ -116,19 +113,19 @@ impl FromAst<leo_ast::ArrayAccessExpression> for ArrayAccessExpression {
|
||||
}
|
||||
|
||||
Ok(ArrayAccessExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
array,
|
||||
index,
|
||||
array: Cell::new(array),
|
||||
index: Cell::new(index),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ArrayAccessExpression> for &ArrayAccessExpression {
|
||||
impl<'a> Into<leo_ast::ArrayAccessExpression> for &ArrayAccessExpression<'a> {
|
||||
fn into(self) -> leo_ast::ArrayAccessExpression {
|
||||
leo_ast::ArrayAccessExpression {
|
||||
array: Box::new(self.array.as_ref().into()),
|
||||
index: Box::new(self.index.as_ref().into()),
|
||||
array: Box::new(self.array.get().into()),
|
||||
index: Box::new(self.index.get().into()),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -16,40 +16,37 @@
|
||||
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArrayInitExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayInitExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub element: Arc<Expression>,
|
||||
pub element: Cell<&'a Expression<'a>>,
|
||||
pub len: usize,
|
||||
}
|
||||
|
||||
impl Node for ArrayInitExpression {
|
||||
impl<'a> Node for ArrayInitExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for ArrayInitExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for ArrayInitExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.element.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.element.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
Some(Type::Array(Box::new(self.element.get_type()?), self.len))
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
Some(Type::Array(Box::new(self.element.get().get_type()?), self.len))
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
@ -62,16 +59,16 @@ impl ExpressionNode for ArrayInitExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.element.is_consty()
|
||||
self.element.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ArrayInitExpression> for ArrayInitExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::ArrayInitExpression> for ArrayInitExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::ArrayInitExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<ArrayInitExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<ArrayInitExpression<'a>, AsgConvertError> {
|
||||
let (mut expected_item, expected_len) = match expected_type {
|
||||
Some(PartialType::Array(item, dims)) => (item.map(|x| *x), dims),
|
||||
None => (None, None),
|
||||
@ -130,17 +127,19 @@ impl FromAst<leo_ast::ArrayInitExpression> for ArrayInitExpression {
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut element = Some(Arc::<Expression>::from_ast(scope, &*value.element, expected_item)?);
|
||||
let mut element = Some(<&'a Expression<'a>>::from_ast(scope, &*value.element, expected_item)?);
|
||||
let mut output = None;
|
||||
|
||||
for dimension in dimensions.iter().rev().copied() {
|
||||
output = Some(ArrayInitExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
element: output
|
||||
.map(Expression::ArrayInit)
|
||||
.map(Arc::new)
|
||||
.unwrap_or_else(|| element.take().unwrap()),
|
||||
element: Cell::new(
|
||||
output
|
||||
.map(Expression::ArrayInit)
|
||||
.map(|expr| &*scope.alloc_expression(expr))
|
||||
.unwrap_or_else(|| element.take().unwrap()),
|
||||
),
|
||||
len: dimension,
|
||||
});
|
||||
}
|
||||
@ -148,10 +147,10 @@ impl FromAst<leo_ast::ArrayInitExpression> for ArrayInitExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ArrayInitExpression> for &ArrayInitExpression {
|
||||
impl<'a> Into<leo_ast::ArrayInitExpression> for &ArrayInitExpression<'a> {
|
||||
fn into(self) -> leo_ast::ArrayInitExpression {
|
||||
leo_ast::ArrayInitExpression {
|
||||
element: Box::new(self.element.as_ref().into()),
|
||||
element: Box::new(self.element.get().into()),
|
||||
dimensions: leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber {
|
||||
value: self.len.to_string(),
|
||||
}]),
|
||||
|
@ -17,25 +17,22 @@
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
use leo_ast::SpreadOrExpression;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArrayInlineExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayInlineExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub elements: Vec<(Arc<Expression>, bool)>, // bool = if spread
|
||||
pub elements: Vec<(Cell<&'a Expression<'a>>, bool)>, // bool = if spread
|
||||
}
|
||||
|
||||
impl ArrayInlineExpression {
|
||||
impl<'a> ArrayInlineExpression<'a> {
|
||||
pub fn expanded_length(&self) -> usize {
|
||||
self.elements
|
||||
.iter()
|
||||
.map(|(expr, is_spread)| {
|
||||
if *is_spread {
|
||||
match expr.get_type() {
|
||||
match expr.get().get_type() {
|
||||
Some(Type::Array(_item, len)) => len,
|
||||
_ => 0,
|
||||
}
|
||||
@ -47,30 +44,30 @@ impl ArrayInlineExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ArrayInlineExpression {
|
||||
impl<'a> Node for ArrayInlineExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for ArrayInlineExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for ArrayInlineExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.elements.iter().for_each(|(element, _)| {
|
||||
element.set_parent(Arc::downgrade(expr));
|
||||
element.get().set_parent(expr);
|
||||
})
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
Some(Type::Array(
|
||||
Box::new(self.elements.first()?.0.get_type()?),
|
||||
Box::new(self.elements.first()?.0.get().get_type()?),
|
||||
self.expanded_length(),
|
||||
))
|
||||
}
|
||||
@ -83,29 +80,28 @@ impl ExpressionNode for ArrayInlineExpression {
|
||||
let mut const_values = vec![];
|
||||
for (expr, spread) in self.elements.iter() {
|
||||
if *spread {
|
||||
match expr.const_value()? {
|
||||
match expr.get().const_value()? {
|
||||
ConstValue::Array(items) => const_values.extend(items),
|
||||
_ => return None,
|
||||
}
|
||||
} else {
|
||||
const_values.push(expr.const_value()?);
|
||||
const_values.push(expr.get().const_value()?);
|
||||
}
|
||||
}
|
||||
Some(ConstValue::Array(const_values))
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.elements.iter().all(|x| x.0.is_consty())
|
||||
self.elements.iter().all(|x| x.0.get().is_consty())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ArrayInlineExpression> for ArrayInlineExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::ArrayInlineExpression> for ArrayInlineExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::ArrayInlineExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<ArrayInlineExpression, AsgConvertError> {
|
||||
// println!("v: {:?}", value);
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<ArrayInlineExpression<'a>, AsgConvertError> {
|
||||
let (mut expected_item, expected_len) = match expected_type {
|
||||
Some(PartialType::Array(item, dims)) => (item.map(|x| *x), dims),
|
||||
None => (None, None),
|
||||
@ -118,13 +114,13 @@ impl FromAst<leo_ast::ArrayInlineExpression> for ArrayInlineExpression {
|
||||
}
|
||||
};
|
||||
|
||||
let mut len = 0;
|
||||
|
||||
if len == 0 && expected_item.is_none() {
|
||||
// If we still don't know the type iterate through processing to get a type.
|
||||
// Once we encouter the type break the loop so we process as little as possible.
|
||||
if expected_item.is_none() {
|
||||
for expr in value.elements.iter() {
|
||||
expected_item = match expr {
|
||||
SpreadOrExpression::Expression(e) => {
|
||||
match Arc::<Expression>::from_ast(scope, e, expected_item.clone()) {
|
||||
match <&Expression<'a>>::from_ast(scope, e, expected_item.clone()) {
|
||||
Ok(expr) => expr.get_type().map(Type::partial),
|
||||
Err(_) => continue,
|
||||
}
|
||||
@ -138,23 +134,25 @@ impl FromAst<leo_ast::ArrayInlineExpression> for ArrayInlineExpression {
|
||||
}
|
||||
}
|
||||
|
||||
let mut len = 0;
|
||||
|
||||
let output = ArrayInlineExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
elements: value
|
||||
.elements
|
||||
.iter()
|
||||
.map(|e| match e {
|
||||
SpreadOrExpression::Expression(e) => {
|
||||
let expr = Arc::<Expression>::from_ast(scope, e, expected_item.clone())?;
|
||||
let expr = <&Expression<'a>>::from_ast(scope, e, expected_item.clone())?;
|
||||
if expected_item.is_none() {
|
||||
expected_item = expr.get_type().map(Type::partial);
|
||||
}
|
||||
len += 1;
|
||||
Ok((expr, false))
|
||||
Ok((Cell::new(expr), false))
|
||||
}
|
||||
SpreadOrExpression::Spread(e) => {
|
||||
let expr = Arc::<Expression>::from_ast(
|
||||
let expr = <&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
e,
|
||||
Some(PartialType::Array(expected_item.clone().map(Box::new), None)),
|
||||
@ -180,7 +178,7 @@ impl FromAst<leo_ast::ArrayInlineExpression> for ArrayInlineExpression {
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok((expr, true))
|
||||
Ok((Cell::new(expr), true))
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, AsgConvertError>>()?,
|
||||
@ -198,14 +196,14 @@ impl FromAst<leo_ast::ArrayInlineExpression> for ArrayInlineExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ArrayInlineExpression> for &ArrayInlineExpression {
|
||||
impl<'a> Into<leo_ast::ArrayInlineExpression> for &ArrayInlineExpression<'a> {
|
||||
fn into(self) -> leo_ast::ArrayInlineExpression {
|
||||
leo_ast::ArrayInlineExpression {
|
||||
elements: self
|
||||
.elements
|
||||
.iter()
|
||||
.map(|(element, spread)| {
|
||||
let element = element.as_ref().into();
|
||||
let element = element.get().into();
|
||||
if *spread {
|
||||
SpreadOrExpression::Spread(element)
|
||||
} else {
|
||||
|
@ -17,57 +17,54 @@
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
use leo_ast::IntegerType;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ArrayRangeAccessExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ArrayRangeAccessExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub array: Arc<Expression>,
|
||||
pub left: Option<Arc<Expression>>,
|
||||
pub right: Option<Arc<Expression>>,
|
||||
pub array: Cell<&'a Expression<'a>>,
|
||||
pub left: Cell<Option<&'a Expression<'a>>>,
|
||||
pub right: Cell<Option<&'a Expression<'a>>>,
|
||||
}
|
||||
|
||||
impl Node for ArrayRangeAccessExpression {
|
||||
impl<'a> Node for ArrayRangeAccessExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for ArrayRangeAccessExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for ArrayRangeAccessExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.array.set_parent(Arc::downgrade(expr));
|
||||
self.array.enforce_parents(&self.array);
|
||||
if let Some(left) = self.left.as_ref() {
|
||||
left.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.array.get().set_parent(expr);
|
||||
self.array.get().enforce_parents(self.array.get());
|
||||
if let Some(left) = self.left.get() {
|
||||
left.set_parent(expr);
|
||||
}
|
||||
if let Some(right) = self.right.as_ref() {
|
||||
right.set_parent(Arc::downgrade(expr));
|
||||
if let Some(right) = self.right.get() {
|
||||
right.set_parent(expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
let (element, array_len) = match self.array.get_type() {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
let (element, array_len) = match self.array.get().get_type() {
|
||||
Some(Type::Array(element, len)) => (element, len),
|
||||
_ => return None,
|
||||
};
|
||||
let const_left = match self.left.as_ref().map(|x| x.const_value()) {
|
||||
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.as_ref().map(|x| x.const_value()) {
|
||||
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,
|
||||
@ -80,20 +77,20 @@ impl ExpressionNode for ArrayRangeAccessExpression {
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
self.array.is_mut_ref()
|
||||
self.array.get().is_mut_ref()
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
let mut array = match self.array.const_value()? {
|
||||
let mut array = match self.array.get().const_value()? {
|
||||
ConstValue::Array(values) => values,
|
||||
_ => return None,
|
||||
};
|
||||
let const_left = match self.left.as_ref().map(|x| x.const_value()) {
|
||||
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.as_ref().map(|x| x.const_value()) {
|
||||
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,
|
||||
@ -106,16 +103,16 @@ impl ExpressionNode for ArrayRangeAccessExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.array.is_consty()
|
||||
self.array.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::ArrayRangeAccessExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<ArrayRangeAccessExpression, AsgConvertError> {
|
||||
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,
|
||||
@ -127,7 +124,7 @@ impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression
|
||||
));
|
||||
}
|
||||
};
|
||||
let array = Arc::<Expression>::from_ast(scope, &*value.array, expected_array)?;
|
||||
let array = <&Expression<'a>>::from_ast(scope, &*value.array, expected_array)?;
|
||||
let array_type = array.get_type();
|
||||
match array_type {
|
||||
Some(Type::Array(_, _)) => (),
|
||||
@ -143,14 +140,14 @@ impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression
|
||||
.left
|
||||
.as_deref()
|
||||
.map(|left| {
|
||||
Arc::<Expression>::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32))))
|
||||
<&Expression<'a>>::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32))))
|
||||
})
|
||||
.transpose()?;
|
||||
let right = value
|
||||
.right
|
||||
.as_deref()
|
||||
.map(|right| {
|
||||
Arc::<Expression>::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32))))
|
||||
<&Expression<'a>>::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32))))
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
@ -169,21 +166,21 @@ impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression
|
||||
}
|
||||
}
|
||||
Ok(ArrayRangeAccessExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
array,
|
||||
left,
|
||||
right,
|
||||
array: Cell::new(array),
|
||||
left: Cell::new(left),
|
||||
right: Cell::new(right),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ArrayRangeAccessExpression> for &ArrayRangeAccessExpression {
|
||||
impl<'a> Into<leo_ast::ArrayRangeAccessExpression> for &ArrayRangeAccessExpression<'a> {
|
||||
fn into(self) -> leo_ast::ArrayRangeAccessExpression {
|
||||
leo_ast::ArrayRangeAccessExpression {
|
||||
array: Box::new(self.array.as_ref().into()),
|
||||
left: self.left.as_ref().map(|left| Box::new(left.as_ref().into())),
|
||||
right: self.right.as_ref().map(|right| Box::new(right.as_ref().into())),
|
||||
array: Box::new(self.array.get().into()),
|
||||
left: self.left.get().map(|left| Box::new(left.into())),
|
||||
right: self.right.get().map(|right| Box::new(right.into())),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -17,44 +17,41 @@
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
pub use leo_ast::{BinaryOperation, BinaryOperationClass};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinaryExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct BinaryExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub operation: BinaryOperation,
|
||||
pub left: Arc<Expression>,
|
||||
pub right: Arc<Expression>,
|
||||
pub left: Cell<&'a Expression<'a>>,
|
||||
pub right: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for BinaryExpression {
|
||||
impl<'a> Node for BinaryExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for BinaryExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for BinaryExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.left.set_parent(Arc::downgrade(expr));
|
||||
self.right.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.left.get().set_parent(expr);
|
||||
self.right.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
match self.operation.class() {
|
||||
BinaryOperationClass::Boolean => Some(Type::Boolean),
|
||||
BinaryOperationClass::Numeric => self.left.get_type(),
|
||||
BinaryOperationClass::Numeric => self.left.get().get_type(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,8 +61,8 @@ impl ExpressionNode for BinaryExpression {
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
use BinaryOperation::*;
|
||||
let left = self.left.const_value()?;
|
||||
let right = self.right.const_value()?;
|
||||
let left = self.left.get().const_value()?;
|
||||
let right = self.right.get().const_value()?;
|
||||
|
||||
match (left, right) {
|
||||
(ConstValue::Int(left), ConstValue::Int(right)) => Some(match self.operation {
|
||||
@ -110,16 +107,16 @@ impl ExpressionNode for BinaryExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.left.is_consty() && self.right.is_consty()
|
||||
self.left.get().is_consty() && self.right.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::BinaryExpression> for BinaryExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::BinaryExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<BinaryExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<BinaryExpression<'a>, AsgConvertError> {
|
||||
let class = value.op.class();
|
||||
let expected_type = match class {
|
||||
BinaryOperationClass::Boolean => match expected_type {
|
||||
@ -148,16 +145,16 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
|
||||
};
|
||||
|
||||
// left
|
||||
let (left, right) = match Arc::<Expression>::from_ast(scope, &*value.left, expected_type.clone()) {
|
||||
let (left, right) = match <&Expression<'a>>::from_ast(scope, &*value.left, expected_type.clone()) {
|
||||
Ok(left) => {
|
||||
if let Some(left_type) = left.get_type() {
|
||||
let right = Arc::<Expression>::from_ast(scope, &*value.right, Some(left_type.partial()))?;
|
||||
let right = <&Expression<'a>>::from_ast(scope, &*value.right, Some(left_type.partial()))?;
|
||||
(left, right)
|
||||
} else {
|
||||
let right = Arc::<Expression>::from_ast(scope, &*value.right, expected_type)?;
|
||||
let right = <&Expression<'a>>::from_ast(scope, &*value.right, expected_type)?;
|
||||
if let Some(right_type) = right.get_type() {
|
||||
(
|
||||
Arc::<Expression>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
|
||||
<&Expression<'a>>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
|
||||
right,
|
||||
)
|
||||
} else {
|
||||
@ -166,10 +163,10 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let right = Arc::<Expression>::from_ast(scope, &*value.right, expected_type)?;
|
||||
let right = <&Expression<'a>>::from_ast(scope, &*value.right, expected_type)?;
|
||||
if let Some(right_type) = right.get_type() {
|
||||
(
|
||||
Arc::<Expression>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
|
||||
<&Expression<'a>>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
|
||||
right,
|
||||
)
|
||||
} else {
|
||||
@ -244,21 +241,21 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
|
||||
(_, _) => (),
|
||||
}
|
||||
Ok(BinaryExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
operation: value.op.clone(),
|
||||
left,
|
||||
right,
|
||||
left: Cell::new(left),
|
||||
right: Cell::new(right),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::BinaryExpression> for &BinaryExpression {
|
||||
impl<'a> Into<leo_ast::BinaryExpression> for &BinaryExpression<'a> {
|
||||
fn into(self) -> leo_ast::BinaryExpression {
|
||||
leo_ast::BinaryExpression {
|
||||
op: self.operation.clone(),
|
||||
left: Box::new(self.left.as_ref().into()),
|
||||
right: Box::new(self.right.as_ref().into()),
|
||||
left: Box::new(self.left.get().into()),
|
||||
right: Box::new(self.right.get().into()),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -31,46 +31,43 @@ use crate::{
|
||||
};
|
||||
pub use leo_ast::{BinaryOperation, Node as AstNode};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CallExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct CallExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub function: Arc<Function>,
|
||||
pub target: Option<Arc<Expression>>,
|
||||
pub arguments: Vec<Arc<Expression>>,
|
||||
pub function: Cell<&'a Function<'a>>,
|
||||
pub target: Cell<Option<&'a Expression<'a>>>,
|
||||
pub arguments: Vec<Cell<&'a Expression<'a>>>,
|
||||
}
|
||||
|
||||
impl Node for CallExpression {
|
||||
impl<'a> Node for CallExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for CallExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for CallExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
if let Some(target) = self.target.as_ref() {
|
||||
target.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
if let Some(target) = self.target.get() {
|
||||
target.set_parent(expr);
|
||||
}
|
||||
self.arguments.iter().for_each(|element| {
|
||||
element.set_parent(Arc::downgrade(expr));
|
||||
element.get().set_parent(expr);
|
||||
})
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
Some(self.function.output.clone().into())
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
Some(self.function.get().output.clone())
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
@ -83,21 +80,20 @@ impl ExpressionNode for CallExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.target.as_ref().map(|x| x.is_consty()).unwrap_or(true) && self.arguments.iter().all(|x| x.is_consty())
|
||||
self.target.get().map(|x| x.is_consty()).unwrap_or(true) && self.arguments.iter().all(|x| x.get().is_consty())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::CallExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<CallExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<CallExpression<'a>, AsgConvertError> {
|
||||
let (target, function) = match &*value.function {
|
||||
leo_ast::Expression::Identifier(name) => (
|
||||
None,
|
||||
scope
|
||||
.borrow()
|
||||
.resolve_function(&name.name)
|
||||
.ok_or_else(|| AsgConvertError::unresolved_function(&name.name, &name.span))?,
|
||||
),
|
||||
@ -106,7 +102,7 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
name,
|
||||
span,
|
||||
}) => {
|
||||
let target = Arc::<Expression>::from_ast(scope, &**ast_circuit, None)?;
|
||||
let target = <&Expression<'a>>::from_ast(scope, &**ast_circuit, None)?;
|
||||
let circuit = match target.get_type() {
|
||||
Some(Type::Circuit(circuit)) => circuit,
|
||||
type_ => {
|
||||
@ -137,7 +133,7 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
&span,
|
||||
));
|
||||
}
|
||||
(Some(target), body.clone())
|
||||
(Some(target), *body)
|
||||
}
|
||||
CircuitMember::Variable(_) => {
|
||||
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span));
|
||||
@ -151,7 +147,6 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
}) => {
|
||||
let circuit = if let leo_ast::Expression::Identifier(circuit_name) = &**ast_circuit {
|
||||
scope
|
||||
.borrow()
|
||||
.resolve_circuit(&circuit_name.name)
|
||||
.ok_or_else(|| AsgConvertError::unresolved_circuit(&circuit_name.name, &circuit_name.span))?
|
||||
} else {
|
||||
@ -172,7 +167,7 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
&span,
|
||||
));
|
||||
}
|
||||
(None, body.clone())
|
||||
(None, *body)
|
||||
}
|
||||
CircuitMember::Variable(_) => {
|
||||
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span));
|
||||
@ -186,7 +181,7 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
}
|
||||
};
|
||||
if let Some(expected) = expected_type {
|
||||
let output: Type = function.output.clone().into();
|
||||
let output: Type = function.output.clone();
|
||||
if !expected.matches(&output) {
|
||||
return Err(AsgConvertError::unexpected_type(
|
||||
&expected.to_string(),
|
||||
@ -207,46 +202,45 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
|
||||
.arguments
|
||||
.iter()
|
||||
.zip(function.arguments.iter())
|
||||
.map(|(expr, argument)| {
|
||||
let argument = argument.borrow();
|
||||
let converted =
|
||||
Arc::<Expression>::from_ast(scope, expr, Some(argument.type_.clone().strong().partial()))?;
|
||||
.map(|(expr, (_, argument))| {
|
||||
let argument = argument.get().borrow();
|
||||
let converted = <&Expression<'a>>::from_ast(scope, expr, Some(argument.type_.clone().partial()))?;
|
||||
if argument.const_ && !converted.is_consty() {
|
||||
return Err(AsgConvertError::unexpected_nonconst(&expr.span()));
|
||||
}
|
||||
Ok(converted)
|
||||
Ok(Cell::new(converted))
|
||||
})
|
||||
.collect::<Result<Vec<_>, AsgConvertError>>()?;
|
||||
|
||||
Ok(CallExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
arguments,
|
||||
function,
|
||||
target,
|
||||
function: Cell::new(function),
|
||||
target: Cell::new(target),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::CallExpression> for &CallExpression {
|
||||
impl<'a> Into<leo_ast::CallExpression> for &CallExpression<'a> {
|
||||
fn into(self) -> leo_ast::CallExpression {
|
||||
let target_function = if let Some(target) = &self.target {
|
||||
target.as_ref().into()
|
||||
let target_function = if let Some(target) = self.target.get() {
|
||||
target.into()
|
||||
} else {
|
||||
let circuit = self.function.circuit.borrow().as_ref().map(|x| x.upgrade()).flatten();
|
||||
let circuit = self.function.get().circuit.get();
|
||||
if let Some(circuit) = circuit {
|
||||
leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression {
|
||||
circuit: Box::new(leo_ast::Expression::Identifier(circuit.name.borrow().clone())),
|
||||
name: self.function.name.borrow().clone(),
|
||||
name: self.function.get().name.borrow().clone(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
})
|
||||
} else {
|
||||
leo_ast::Expression::Identifier(self.function.name.borrow().clone())
|
||||
leo_ast::Expression::Identifier(self.function.get().name.borrow().clone())
|
||||
}
|
||||
};
|
||||
leo_ast::CallExpression {
|
||||
function: Box::new(target_function),
|
||||
arguments: self.arguments.iter().map(|arg| arg.as_ref().into()).collect(),
|
||||
arguments: self.arguments.iter().map(|arg| arg.get().into()).collect(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use crate::{
|
||||
AsgConvertError,
|
||||
Circuit,
|
||||
CircuitMember,
|
||||
CircuitMemberBody,
|
||||
ConstValue,
|
||||
Expression,
|
||||
ExpressionNode,
|
||||
@ -31,56 +30,53 @@ use crate::{
|
||||
Type,
|
||||
};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CircuitAccessExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct CircuitAccessExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub circuit: Arc<Circuit>,
|
||||
pub target: Option<Arc<Expression>>,
|
||||
pub circuit: Cell<&'a Circuit<'a>>,
|
||||
pub target: Cell<Option<&'a Expression<'a>>>,
|
||||
pub member: Identifier,
|
||||
}
|
||||
|
||||
impl Node for CircuitAccessExpression {
|
||||
impl<'a> Node for CircuitAccessExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for CircuitAccessExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for CircuitAccessExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
if let Some(target) = self.target.as_ref() {
|
||||
target.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
if let Some(target) = self.target.get() {
|
||||
target.set_parent(expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
if self.target.is_none() {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
if self.target.get().is_none() {
|
||||
None // function target only for static
|
||||
} else {
|
||||
let members = self.circuit.members.borrow();
|
||||
let members = self.circuit.get().members.borrow();
|
||||
let member = members.get(&self.member.name)?;
|
||||
match member {
|
||||
CircuitMember::Variable(type_) => Some(type_.clone().into()),
|
||||
CircuitMember::Variable(type_) => Some(type_.clone()),
|
||||
CircuitMember::Function(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
if let Some(target) = self.target.as_ref() {
|
||||
if let Some(target) = self.target.get() {
|
||||
target.is_mut_ref()
|
||||
} else {
|
||||
false
|
||||
@ -92,17 +88,17 @@ impl ExpressionNode for CircuitAccessExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.target.as_ref().map(|x| x.is_consty()).unwrap_or(true)
|
||||
self.target.get().map(|x| x.is_consty()).unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::CircuitMemberAccessExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<CircuitAccessExpression, AsgConvertError> {
|
||||
let target = Arc::<Expression>::from_ast(scope, &*value.circuit, None)?;
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<CircuitAccessExpression<'a>, AsgConvertError> {
|
||||
let target = <&'a Expression<'a>>::from_ast(scope, &*value.circuit, None)?;
|
||||
let circuit = match target.get_type() {
|
||||
Some(Type::Circuit(circuit)) => circuit,
|
||||
x => {
|
||||
@ -119,7 +115,7 @@ impl FromAst<leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression
|
||||
if let Some(member) = circuit.members.borrow().get(&value.name.name) {
|
||||
if let Some(expected_type) = &expected_type {
|
||||
if let CircuitMember::Variable(type_) = &member {
|
||||
let type_: Type = type_.clone().into();
|
||||
let type_: Type = type_.clone();
|
||||
if !expected_type.matches(&type_) {
|
||||
return Err(AsgConvertError::unexpected_type(
|
||||
&expected_type.to_string(),
|
||||
@ -140,15 +136,10 @@ impl FromAst<leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression
|
||||
} 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().into()),
|
||||
);
|
||||
let body = circuit.body.borrow().upgrade().expect("stale input circuit body");
|
||||
|
||||
body.members
|
||||
circuit
|
||||
.members
|
||||
.borrow_mut()
|
||||
.insert(value.name.name.clone(), CircuitMemberBody::Variable(expected_type));
|
||||
.insert(value.name.name.clone(), CircuitMember::Variable(expected_type.clone()));
|
||||
} else {
|
||||
return Err(AsgConvertError::input_ref_needs_type(
|
||||
&circuit.name.borrow().name,
|
||||
@ -165,24 +156,23 @@ impl FromAst<leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression
|
||||
}
|
||||
|
||||
Ok(CircuitAccessExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
target: Some(target),
|
||||
circuit,
|
||||
target: Cell::new(Some(target)),
|
||||
circuit: Cell::new(circuit),
|
||||
member: value.name.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::CircuitStaticFunctionAccessExpression> for CircuitAccessExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::CircuitStaticFunctionAccessExpression> for CircuitAccessExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &Scope<'a>,
|
||||
value: &leo_ast::CircuitStaticFunctionAccessExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<CircuitAccessExpression, AsgConvertError> {
|
||||
) -> Result<CircuitAccessExpression<'a>, AsgConvertError> {
|
||||
let circuit = match &*value.circuit {
|
||||
leo_ast::Expression::Identifier(name) => scope
|
||||
.borrow()
|
||||
.resolve_circuit(&name.name)
|
||||
.ok_or_else(|| AsgConvertError::unresolved_circuit(&name.name, &name.span))?,
|
||||
_ => {
|
||||
@ -213,26 +203,28 @@ impl FromAst<leo_ast::CircuitStaticFunctionAccessExpression> for CircuitAccessEx
|
||||
}
|
||||
|
||||
Ok(CircuitAccessExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
target: None,
|
||||
circuit,
|
||||
target: Cell::new(None),
|
||||
circuit: Cell::new(circuit),
|
||||
member: value.name.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Expression> for &CircuitAccessExpression {
|
||||
impl<'a> Into<leo_ast::Expression> for &CircuitAccessExpression<'a> {
|
||||
fn into(self) -> leo_ast::Expression {
|
||||
if let Some(target) = self.target.as_ref() {
|
||||
if let Some(target) = self.target.get() {
|
||||
leo_ast::Expression::CircuitMemberAccess(leo_ast::CircuitMemberAccessExpression {
|
||||
circuit: Box::new(target.as_ref().into()),
|
||||
circuit: Box::new(target.into()),
|
||||
name: self.member.clone(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
})
|
||||
} else {
|
||||
leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression {
|
||||
circuit: Box::new(leo_ast::Expression::Identifier(self.circuit.name.borrow().clone())),
|
||||
circuit: Box::new(leo_ast::Expression::Identifier(
|
||||
self.circuit.get().name.borrow().clone(),
|
||||
)),
|
||||
name: self.member.clone(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
})
|
||||
|
@ -31,42 +31,39 @@ use crate::{
|
||||
};
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CircuitInitExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct CircuitInitExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub circuit: Arc<Circuit>,
|
||||
pub values: Vec<(Identifier, Arc<Expression>)>,
|
||||
pub circuit: Cell<&'a Circuit<'a>>,
|
||||
pub values: Vec<(Identifier, Cell<&'a Expression<'a>>)>,
|
||||
}
|
||||
|
||||
impl Node for CircuitInitExpression {
|
||||
impl<'a> Node for CircuitInitExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for CircuitInitExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for CircuitInitExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.values.iter().for_each(|(_, element)| {
|
||||
element.set_parent(Arc::downgrade(expr));
|
||||
element.get().set_parent(expr);
|
||||
})
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
Some(Type::Circuit(self.circuit.clone()))
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
Some(Type::Circuit(self.circuit.get()))
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
@ -78,18 +75,17 @@ impl ExpressionNode for CircuitInitExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.values.iter().all(|(_, value)| value.is_consty())
|
||||
self.values.iter().all(|(_, value)| value.get().is_consty())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::CircuitInitExpression> for CircuitInitExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::CircuitInitExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<CircuitInitExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<CircuitInitExpression<'a>, AsgConvertError> {
|
||||
let circuit = scope
|
||||
.borrow()
|
||||
.resolve_circuit(&value.name.name)
|
||||
.ok_or_else(|| AsgConvertError::unresolved_circuit(&value.name.name, &value.name.span))?;
|
||||
match expected_type {
|
||||
@ -109,7 +105,7 @@ impl FromAst<leo_ast::CircuitInitExpression> for CircuitInitExpression {
|
||||
.map(|x| (&x.identifier.name, (&x.identifier, &x.expression)))
|
||||
.collect();
|
||||
|
||||
let mut values: Vec<(Identifier, Arc<Expression>)> = vec![];
|
||||
let mut values: Vec<(Identifier, Cell<&'a Expression<'a>>)> = vec![];
|
||||
let mut defined_variables = IndexSet::<String>::new();
|
||||
|
||||
{
|
||||
@ -124,13 +120,13 @@ impl FromAst<leo_ast::CircuitInitExpression> for CircuitInitExpression {
|
||||
}
|
||||
defined_variables.insert(name.clone());
|
||||
let type_: Type = if let CircuitMember::Variable(type_) = &member {
|
||||
type_.clone().into()
|
||||
type_.clone()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
if let Some((identifier, receiver)) = members.get(&name) {
|
||||
let received = Arc::<Expression>::from_ast(scope, *receiver, Some(type_.partial()))?;
|
||||
values.push(((*identifier).clone(), received));
|
||||
let received = <&Expression<'a>>::from_ast(scope, *receiver, Some(type_.partial()))?;
|
||||
values.push(((*identifier).clone(), Cell::new(received)));
|
||||
} else {
|
||||
return Err(AsgConvertError::missing_circuit_member(
|
||||
&circuit.name.borrow().name,
|
||||
@ -152,24 +148,24 @@ impl FromAst<leo_ast::CircuitInitExpression> for CircuitInitExpression {
|
||||
}
|
||||
|
||||
Ok(CircuitInitExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
circuit,
|
||||
circuit: Cell::new(circuit),
|
||||
values,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::CircuitInitExpression> for &CircuitInitExpression {
|
||||
impl<'a> Into<leo_ast::CircuitInitExpression> for &CircuitInitExpression<'a> {
|
||||
fn into(self) -> leo_ast::CircuitInitExpression {
|
||||
leo_ast::CircuitInitExpression {
|
||||
name: self.circuit.name.borrow().clone(),
|
||||
name: self.circuit.get().name.borrow().clone(),
|
||||
members: self
|
||||
.values
|
||||
.iter()
|
||||
.map(|(name, value)| leo_ast::CircuitImpliedVariableDefinition {
|
||||
identifier: name.clone(),
|
||||
expression: value.as_ref().into(),
|
||||
expression: value.get().into(),
|
||||
})
|
||||
.collect(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
|
@ -29,36 +29,33 @@ use crate::{
|
||||
Type,
|
||||
};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Constant {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct Constant<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub value: ConstValue, // should not be compound constants
|
||||
}
|
||||
|
||||
impl Node for Constant {
|
||||
impl<'a> Node for Constant<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for Constant {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for Constant<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, _expr: &Arc<Expression>) {}
|
||||
fn enforce_parents(&self, _expr: &'a Expression<'a>) {}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
self.value.get_type()
|
||||
}
|
||||
|
||||
@ -75,12 +72,12 @@ impl ExpressionNode for Constant {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
impl<'a> FromAst<'a, leo_ast::ValueExpression> for Constant<'a> {
|
||||
fn from_ast(
|
||||
_scope: &Scope,
|
||||
_scope: &'a Scope<'a>,
|
||||
value: &leo_ast::ValueExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<Constant, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Constant<'a>, AsgConvertError> {
|
||||
use leo_ast::ValueExpression::*;
|
||||
Ok(match value {
|
||||
Address(value, span) => {
|
||||
@ -95,7 +92,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Address(value.clone()),
|
||||
}
|
||||
@ -112,7 +109,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Boolean(
|
||||
value
|
||||
@ -133,7 +130,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Field(value.parse().map_err(|_| AsgConvertError::invalid_int(&value, span))?),
|
||||
}
|
||||
@ -150,7 +147,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span().clone()),
|
||||
value: ConstValue::Group(match &**value {
|
||||
leo_ast::GroupValue::Single(value, _) => GroupValue::Single(value.clone()),
|
||||
@ -164,23 +161,23 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
None => return Err(AsgConvertError::unresolved_type("unknown", span)),
|
||||
Some(PartialType::Integer(Some(sub_type), _)) | Some(PartialType::Integer(None, Some(sub_type))) => {
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Int(ConstInt::parse(&sub_type, value, span)?),
|
||||
}
|
||||
}
|
||||
Some(PartialType::Type(Type::Field)) => Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Field(value.parse().map_err(|_| AsgConvertError::invalid_int(&value, span))?),
|
||||
},
|
||||
Some(PartialType::Type(Type::Group)) => Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Group(GroupValue::Single(value.to_string())),
|
||||
},
|
||||
Some(PartialType::Type(Type::Address)) => Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Address(value.to_string()),
|
||||
},
|
||||
@ -200,7 +197,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
Constant {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(span.clone()),
|
||||
value: ConstValue::Int(ConstInt::parse(int_type, value, span)?),
|
||||
}
|
||||
@ -209,7 +206,7 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ValueExpression> for &Constant {
|
||||
impl<'a> Into<leo_ast::ValueExpression> for &Constant<'a> {
|
||||
fn into(self) -> leo_ast::ValueExpression {
|
||||
match &self.value {
|
||||
ConstValue::Address(value) => {
|
||||
|
@ -64,31 +64,29 @@ pub use variable_ref::*;
|
||||
|
||||
use crate::{AsgConvertError, ConstValue, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
#[derive(Clone)]
|
||||
pub enum Expression<'a> {
|
||||
VariableRef(VariableRef<'a>),
|
||||
Constant(Constant<'a>),
|
||||
Binary(BinaryExpression<'a>),
|
||||
Unary(UnaryExpression<'a>),
|
||||
Ternary(TernaryExpression<'a>),
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expression {
|
||||
VariableRef(VariableRef),
|
||||
Constant(Constant),
|
||||
Binary(BinaryExpression),
|
||||
Unary(UnaryExpression),
|
||||
Ternary(TernaryExpression),
|
||||
ArrayInline(ArrayInlineExpression<'a>),
|
||||
ArrayInit(ArrayInitExpression<'a>),
|
||||
ArrayAccess(ArrayAccessExpression<'a>),
|
||||
ArrayRangeAccess(ArrayRangeAccessExpression<'a>),
|
||||
|
||||
ArrayInline(ArrayInlineExpression),
|
||||
ArrayInit(ArrayInitExpression),
|
||||
ArrayAccess(ArrayAccessExpression),
|
||||
ArrayRangeAccess(ArrayRangeAccessExpression),
|
||||
TupleInit(TupleInitExpression<'a>),
|
||||
TupleAccess(TupleAccessExpression<'a>),
|
||||
|
||||
TupleInit(TupleInitExpression),
|
||||
TupleAccess(TupleAccessExpression),
|
||||
CircuitInit(CircuitInitExpression<'a>),
|
||||
CircuitAccess(CircuitAccessExpression<'a>),
|
||||
|
||||
CircuitInit(CircuitInitExpression),
|
||||
CircuitAccess(CircuitAccessExpression),
|
||||
|
||||
Call(CallExpression),
|
||||
Call(CallExpression<'a>),
|
||||
}
|
||||
|
||||
impl Node for Expression {
|
||||
impl<'a> Node for Expression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
use Expression::*;
|
||||
match self {
|
||||
@ -110,19 +108,19 @@ impl Node for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ExpressionNode: Node {
|
||||
fn set_parent(&self, parent: Weak<Expression>);
|
||||
fn get_parent(&self) -> Option<Arc<Expression>>;
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>);
|
||||
pub trait ExpressionNode<'a>: Node {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>);
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>>;
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>);
|
||||
|
||||
fn get_type(&self) -> Option<Type>;
|
||||
fn get_type(&self) -> Option<Type<'a>>;
|
||||
fn is_mut_ref(&self) -> bool;
|
||||
fn const_value(&self) -> Option<ConstValue>; // todo: memoize
|
||||
fn is_consty(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ExpressionNode for Expression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for Expression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
use Expression::*;
|
||||
match self {
|
||||
VariableRef(x) => x.set_parent(parent),
|
||||
@ -142,7 +140,7 @@ impl ExpressionNode for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
use Expression::*;
|
||||
match self {
|
||||
VariableRef(x) => x.get_parent(),
|
||||
@ -162,7 +160,7 @@ impl ExpressionNode for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
use Expression::*;
|
||||
match self {
|
||||
VariableRef(x) => x.enforce_parents(expr),
|
||||
@ -182,7 +180,7 @@ impl ExpressionNode for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
use Expression::*;
|
||||
match self {
|
||||
VariableRef(x) => x.get_type(),
|
||||
@ -263,65 +261,70 @@ impl ExpressionNode for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::Expression> for Arc<Expression> {
|
||||
impl<'a> FromAst<'a, leo_ast::Expression> for &'a Expression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::Expression,
|
||||
expected_type: Option<PartialType>,
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
use leo_ast::Expression::*;
|
||||
let expression = match value {
|
||||
Identifier(identifier) => Self::from_ast(scope, identifier, expected_type)?,
|
||||
Value(value) => Arc::new(Constant::from_ast(scope, value, expected_type).map(Expression::Constant)?),
|
||||
Binary(binary) => {
|
||||
Arc::new(BinaryExpression::from_ast(scope, binary, expected_type).map(Expression::Binary)?)
|
||||
Value(value) => {
|
||||
scope.alloc_expression(Constant::from_ast(scope, value, expected_type).map(Expression::Constant)?)
|
||||
}
|
||||
Unary(unary) => Arc::new(UnaryExpression::from_ast(scope, unary, expected_type).map(Expression::Unary)?),
|
||||
Ternary(conditional) => {
|
||||
Arc::new(TernaryExpression::from_ast(scope, conditional, expected_type).map(Expression::Ternary)?)
|
||||
Binary(binary) => scope
|
||||
.alloc_expression(BinaryExpression::from_ast(scope, binary, expected_type).map(Expression::Binary)?),
|
||||
Unary(unary) => {
|
||||
scope.alloc_expression(UnaryExpression::from_ast(scope, unary, expected_type).map(Expression::Unary)?)
|
||||
}
|
||||
Ternary(conditional) => scope.alloc_expression(
|
||||
TernaryExpression::from_ast(scope, conditional, expected_type).map(Expression::Ternary)?,
|
||||
),
|
||||
|
||||
ArrayInline(array_inline) => Arc::new(
|
||||
ArrayInline(array_inline) => scope.alloc_expression(
|
||||
ArrayInlineExpression::from_ast(scope, array_inline, expected_type).map(Expression::ArrayInline)?,
|
||||
),
|
||||
ArrayInit(array_init) => {
|
||||
Arc::new(ArrayInitExpression::from_ast(scope, array_init, expected_type).map(Expression::ArrayInit)?)
|
||||
}
|
||||
ArrayAccess(array_access) => Arc::new(
|
||||
ArrayInit(array_init) => scope.alloc_expression(
|
||||
ArrayInitExpression::from_ast(scope, array_init, expected_type).map(Expression::ArrayInit)?,
|
||||
),
|
||||
ArrayAccess(array_access) => scope.alloc_expression(
|
||||
ArrayAccessExpression::from_ast(scope, array_access, expected_type).map(Expression::ArrayAccess)?,
|
||||
),
|
||||
ArrayRangeAccess(array_range_access) => Arc::new(
|
||||
ArrayRangeAccess(array_range_access) => scope.alloc_expression(
|
||||
ArrayRangeAccessExpression::from_ast(scope, array_range_access, expected_type)
|
||||
.map(Expression::ArrayRangeAccess)?,
|
||||
),
|
||||
|
||||
TupleInit(tuple_init) => {
|
||||
Arc::new(TupleInitExpression::from_ast(scope, tuple_init, expected_type).map(Expression::TupleInit)?)
|
||||
}
|
||||
TupleAccess(tuple_access) => Arc::new(
|
||||
TupleInit(tuple_init) => scope.alloc_expression(
|
||||
TupleInitExpression::from_ast(scope, tuple_init, expected_type).map(Expression::TupleInit)?,
|
||||
),
|
||||
TupleAccess(tuple_access) => scope.alloc_expression(
|
||||
TupleAccessExpression::from_ast(scope, tuple_access, expected_type).map(Expression::TupleAccess)?,
|
||||
),
|
||||
|
||||
CircuitInit(circuit_init) => Arc::new(
|
||||
CircuitInit(circuit_init) => scope.alloc_expression(
|
||||
CircuitInitExpression::from_ast(scope, circuit_init, expected_type).map(Expression::CircuitInit)?,
|
||||
),
|
||||
CircuitMemberAccess(circuit_member) => Arc::new(
|
||||
CircuitMemberAccess(circuit_member) => scope.alloc_expression(
|
||||
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type)
|
||||
.map(Expression::CircuitAccess)?,
|
||||
),
|
||||
CircuitStaticFunctionAccess(circuit_member) => Arc::new(
|
||||
CircuitStaticFunctionAccess(circuit_member) => scope.alloc_expression(
|
||||
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type)
|
||||
.map(Expression::CircuitAccess)?,
|
||||
),
|
||||
|
||||
Call(call) => Arc::new(CallExpression::from_ast(scope, call, expected_type).map(Expression::Call)?),
|
||||
Call(call) => {
|
||||
scope.alloc_expression(CallExpression::from_ast(scope, call, expected_type).map(Expression::Call)?)
|
||||
}
|
||||
};
|
||||
expression.enforce_parents(&expression);
|
||||
Ok(expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Expression> for &Expression {
|
||||
impl<'a> Into<leo_ast::Expression> for &Expression<'a> {
|
||||
fn into(self) -> leo_ast::Expression {
|
||||
use Expression::*;
|
||||
match self {
|
||||
|
@ -16,55 +16,52 @@
|
||||
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TernaryExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct TernaryExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub condition: Arc<Expression>,
|
||||
pub if_true: Arc<Expression>,
|
||||
pub if_false: Arc<Expression>,
|
||||
pub condition: Cell<&'a Expression<'a>>,
|
||||
pub if_true: Cell<&'a Expression<'a>>,
|
||||
pub if_false: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for TernaryExpression {
|
||||
impl<'a> Node for TernaryExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for TernaryExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for TernaryExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.condition.set_parent(Arc::downgrade(expr));
|
||||
self.if_true.set_parent(Arc::downgrade(expr));
|
||||
self.if_false.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.condition.get().set_parent(expr);
|
||||
self.if_true.get().set_parent(expr);
|
||||
self.if_false.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
self.if_true.get_type()
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
self.if_true.get().get_type()
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
self.if_true.is_mut_ref() && self.if_false.is_mut_ref()
|
||||
self.if_true.get().is_mut_ref() && self.if_false.get().is_mut_ref()
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
if let Some(ConstValue::Boolean(switch)) = self.condition.const_value() {
|
||||
if let Some(ConstValue::Boolean(switch)) = self.condition.get().const_value() {
|
||||
if switch {
|
||||
self.if_true.const_value()
|
||||
self.if_true.get().const_value()
|
||||
} else {
|
||||
self.if_false.const_value()
|
||||
self.if_false.get().const_value()
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -72,32 +69,40 @@ impl ExpressionNode for TernaryExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.condition.is_consty() && self.if_true.is_consty() && self.if_false.is_consty()
|
||||
self.condition.get().is_consty() && self.if_true.get().is_consty() && self.if_false.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::TernaryExpression> for TernaryExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::TernaryExpression> for TernaryExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::TernaryExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<TernaryExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<TernaryExpression<'a>, AsgConvertError> {
|
||||
Ok(TernaryExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
condition: Arc::<Expression>::from_ast(scope, &*value.condition, Some(Type::Boolean.partial()))?,
|
||||
if_true: Arc::<Expression>::from_ast(scope, &*value.if_true, expected_type.clone())?,
|
||||
if_false: Arc::<Expression>::from_ast(scope, &*value.if_false, expected_type)?,
|
||||
condition: Cell::new(<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&*value.condition,
|
||||
Some(Type::Boolean.partial()),
|
||||
)?),
|
||||
if_true: Cell::new(<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&*value.if_true,
|
||||
expected_type.clone(),
|
||||
)?),
|
||||
if_false: Cell::new(<&Expression<'a>>::from_ast(scope, &*value.if_false, expected_type)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::TernaryExpression> for &TernaryExpression {
|
||||
impl<'a> Into<leo_ast::TernaryExpression> for &TernaryExpression<'a> {
|
||||
fn into(self) -> leo_ast::TernaryExpression {
|
||||
leo_ast::TernaryExpression {
|
||||
condition: Box::new(self.condition.as_ref().into()),
|
||||
if_true: Box::new(self.if_true.as_ref().into()),
|
||||
if_false: Box::new(self.if_false.as_ref().into()),
|
||||
condition: Box::new(self.condition.get().into()),
|
||||
if_true: Box::new(self.if_true.get().into()),
|
||||
if_false: Box::new(self.if_false.get().into()),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -16,51 +16,48 @@
|
||||
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TupleAccessExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct TupleAccessExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub tuple_ref: Arc<Expression>,
|
||||
pub tuple_ref: Cell<&'a Expression<'a>>,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl Node for TupleAccessExpression {
|
||||
impl<'a> Node for TupleAccessExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for TupleAccessExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for TupleAccessExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.tuple_ref.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.tuple_ref.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
match self.tuple_ref.get_type()? {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
match self.tuple_ref.get().get_type()? {
|
||||
Type::Tuple(subtypes) => subtypes.get(self.index).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
self.tuple_ref.is_mut_ref()
|
||||
self.tuple_ref.get().is_mut_ref()
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
let tuple_const = self.tuple_ref.const_value()?;
|
||||
let tuple_const = self.tuple_ref.get().const_value()?;
|
||||
match tuple_const {
|
||||
ConstValue::Tuple(sub_consts) => sub_consts.get(self.index).cloned(),
|
||||
_ => None,
|
||||
@ -68,16 +65,16 @@ impl ExpressionNode for TupleAccessExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.tuple_ref.is_consty()
|
||||
self.tuple_ref.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::TupleAccessExpression> for TupleAccessExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::TupleAccessExpression> for TupleAccessExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::TupleAccessExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<TupleAccessExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<TupleAccessExpression<'a>, AsgConvertError> {
|
||||
let index = value
|
||||
.index
|
||||
.value
|
||||
@ -87,7 +84,7 @@ impl FromAst<leo_ast::TupleAccessExpression> for TupleAccessExpression {
|
||||
let mut expected_tuple = vec![None; index + 1];
|
||||
expected_tuple[index] = expected_type;
|
||||
|
||||
let tuple = Arc::<Expression>::from_ast(scope, &*value.tuple, Some(PartialType::Tuple(expected_tuple)))?;
|
||||
let tuple = <&Expression<'a>>::from_ast(scope, &*value.tuple, Some(PartialType::Tuple(expected_tuple)))?;
|
||||
let tuple_type = tuple.get_type();
|
||||
if let Some(Type::Tuple(_items)) = tuple_type {
|
||||
} else {
|
||||
@ -99,18 +96,18 @@ impl FromAst<leo_ast::TupleAccessExpression> for TupleAccessExpression {
|
||||
}
|
||||
|
||||
Ok(TupleAccessExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
tuple_ref: tuple,
|
||||
tuple_ref: Cell::new(tuple),
|
||||
index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::TupleAccessExpression> for &TupleAccessExpression {
|
||||
impl<'a> Into<leo_ast::TupleAccessExpression> for &TupleAccessExpression<'a> {
|
||||
fn into(self) -> leo_ast::TupleAccessExpression {
|
||||
leo_ast::TupleAccessExpression {
|
||||
tuple: Box::new(self.tuple_ref.as_ref().into()),
|
||||
tuple: Box::new(self.tuple_ref.get().into()),
|
||||
index: leo_ast::PositiveNumber {
|
||||
value: self.index.to_string(),
|
||||
},
|
||||
|
@ -16,43 +16,40 @@
|
||||
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TupleInitExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct TupleInitExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub elements: Vec<Arc<Expression>>,
|
||||
pub elements: Vec<Cell<&'a Expression<'a>>>,
|
||||
}
|
||||
|
||||
impl Node for TupleInitExpression {
|
||||
impl<'a> Node for TupleInitExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for TupleInitExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for TupleInitExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.elements.iter().for_each(|element| {
|
||||
element.set_parent(Arc::downgrade(expr));
|
||||
element.get().set_parent(expr);
|
||||
})
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
let mut output = vec![];
|
||||
for element in self.elements.iter() {
|
||||
output.push(element.get_type()?);
|
||||
output.push(element.get().get_type()?);
|
||||
}
|
||||
Some(Type::Tuple(output))
|
||||
}
|
||||
@ -64,7 +61,7 @@ impl ExpressionNode for TupleInitExpression {
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
let mut consts = vec![];
|
||||
for element in self.elements.iter() {
|
||||
if let Some(const_value) = element.const_value() {
|
||||
if let Some(const_value) = element.get().const_value() {
|
||||
consts.push(const_value);
|
||||
} else {
|
||||
return None;
|
||||
@ -74,16 +71,16 @@ impl ExpressionNode for TupleInitExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.elements.iter().all(|x| x.is_consty())
|
||||
self.elements.iter().all(|x| x.get().is_consty())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::TupleInitExpression> for TupleInitExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::TupleInitExpression> for TupleInitExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::TupleInitExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<TupleInitExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<TupleInitExpression<'a>, AsgConvertError> {
|
||||
let tuple_types = match expected_type {
|
||||
Some(PartialType::Tuple(sub_types)) => Some(sub_types),
|
||||
None => None,
|
||||
@ -111,26 +108,27 @@ impl FromAst<leo_ast::TupleInitExpression> for TupleInitExpression {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, e)| {
|
||||
Arc::<Expression>::from_ast(
|
||||
<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
e,
|
||||
tuple_types.as_ref().map(|x| x.get(i)).flatten().cloned().flatten(),
|
||||
)
|
||||
.map(Cell::new)
|
||||
})
|
||||
.collect::<Result<Vec<_>, AsgConvertError>>()?;
|
||||
|
||||
Ok(TupleInitExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
elements,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::TupleInitExpression> for &TupleInitExpression {
|
||||
impl<'a> Into<leo_ast::TupleInitExpression> for &TupleInitExpression<'a> {
|
||||
fn into(self) -> leo_ast::TupleInitExpression {
|
||||
leo_ast::TupleInitExpression {
|
||||
elements: self.elements.iter().map(|e| e.as_ref().into()).collect(),
|
||||
elements: self.elements.iter().map(|e| e.get().into()).collect(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -17,40 +17,37 @@
|
||||
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
|
||||
pub use leo_ast::UnaryOperation;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnaryExpression {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct UnaryExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub operation: UnaryOperation,
|
||||
pub inner: Arc<Expression>,
|
||||
pub inner: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for UnaryExpression {
|
||||
impl<'a> Node for UnaryExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for UnaryExpression {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for UnaryExpression<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, expr: &Arc<Expression>) {
|
||||
self.inner.set_parent(Arc::downgrade(expr));
|
||||
fn enforce_parents(&self, expr: &'a Expression<'a>) {
|
||||
self.inner.get().set_parent(expr);
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
self.inner.get_type()
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
self.inner.get().get_type()
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
@ -58,7 +55,7 @@ impl ExpressionNode for UnaryExpression {
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
if let Some(inner) = self.inner.const_value() {
|
||||
if let Some(inner) = self.inner.get().const_value() {
|
||||
match self.operation {
|
||||
UnaryOperation::Not => match inner {
|
||||
ConstValue::Boolean(value) => Some(ConstValue::Boolean(!value)),
|
||||
@ -79,16 +76,16 @@ impl ExpressionNode for UnaryExpression {
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
self.inner.is_consty()
|
||||
self.inner.get().is_consty()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::UnaryExpression> for UnaryExpression {
|
||||
impl<'a> FromAst<'a, leo_ast::UnaryExpression> for UnaryExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::UnaryExpression,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<UnaryExpression, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<UnaryExpression<'a>, AsgConvertError> {
|
||||
let expected_type = match value.op {
|
||||
UnaryOperation::Not => match expected_type.map(|x| x.full()).flatten() {
|
||||
Some(Type::Boolean) | None => Some(Type::Boolean),
|
||||
@ -115,19 +112,23 @@ impl FromAst<leo_ast::UnaryExpression> for UnaryExpression {
|
||||
},
|
||||
};
|
||||
Ok(UnaryExpression {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
operation: value.op.clone(),
|
||||
inner: Arc::<Expression>::from_ast(scope, &*value.inner, expected_type.map(Into::into))?,
|
||||
inner: Cell::new(<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&*value.inner,
|
||||
expected_type.map(Into::into),
|
||||
)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::UnaryExpression> for &UnaryExpression {
|
||||
impl<'a> Into<leo_ast::UnaryExpression> for &UnaryExpression<'a> {
|
||||
fn into(self) -> leo_ast::UnaryExpression {
|
||||
leo_ast::UnaryExpression {
|
||||
op: self.operation.clone(),
|
||||
inner: Box::new(self.inner.as_ref().into()),
|
||||
inner: Box::new(self.inner.get().into()),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -31,37 +31,34 @@ use crate::{
|
||||
Variable,
|
||||
};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VariableRef {
|
||||
pub parent: RefCell<Option<Weak<Expression>>>,
|
||||
#[derive(Clone)]
|
||||
pub struct VariableRef<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub variable: Variable,
|
||||
pub variable: &'a Variable<'a>,
|
||||
}
|
||||
|
||||
impl Node for VariableRef {
|
||||
impl<'a> Node for VariableRef<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionNode for VariableRef {
|
||||
fn set_parent(&self, parent: Weak<Expression>) {
|
||||
impl<'a> ExpressionNode<'a> for VariableRef<'a> {
|
||||
fn set_parent(&self, parent: &'a Expression<'a>) {
|
||||
self.parent.replace(Some(parent));
|
||||
}
|
||||
|
||||
fn get_parent(&self) -> Option<Arc<Expression>> {
|
||||
self.parent.borrow().as_ref().map(Weak::upgrade).flatten()
|
||||
fn get_parent(&self) -> Option<&'a Expression<'a>> {
|
||||
self.parent.get()
|
||||
}
|
||||
|
||||
fn enforce_parents(&self, _expr: &Arc<Expression>) {}
|
||||
fn enforce_parents(&self, _expr: &'a Expression<'a>) {}
|
||||
|
||||
fn get_type(&self) -> Option<Type> {
|
||||
Some(self.variable.borrow().type_.clone().strong())
|
||||
fn get_type(&self) -> Option<Type<'a>> {
|
||||
Some(self.variable.borrow().type_.clone())
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
@ -74,24 +71,19 @@ impl ExpressionNode for VariableRef {
|
||||
if variable.mutable || variable.assignments.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
let assignment = variable
|
||||
.assignments
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.upgrade()
|
||||
.expect("stale assignment for variable");
|
||||
let assignment = variable.assignments.get(0).unwrap();
|
||||
match &*assignment {
|
||||
Statement::Definition(DefinitionStatement { variables, value, .. }) => {
|
||||
if variables.len() == 1 {
|
||||
let defined_variable = variables.get(0).unwrap().borrow();
|
||||
assert_eq!(variable.id, defined_variable.id);
|
||||
|
||||
value.const_value()
|
||||
value.get().const_value()
|
||||
} else {
|
||||
for defined_variable in variables.iter() {
|
||||
let defined_variable = defined_variable.borrow();
|
||||
if defined_variable.id == variable.id {
|
||||
return value.const_value();
|
||||
return value.get().const_value();
|
||||
}
|
||||
}
|
||||
panic!("no corresponding tuple variable found during const destructuring (corrupt asg?)");
|
||||
@ -109,12 +101,7 @@ impl ExpressionNode for VariableRef {
|
||||
if variable.mutable || variable.assignments.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
let assignment = variable
|
||||
.assignments
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.upgrade()
|
||||
.expect("stale assignment for variable");
|
||||
let assignment = variable.assignments.get(0).unwrap();
|
||||
|
||||
match &*assignment {
|
||||
Statement::Definition(DefinitionStatement { variables, value, .. }) => {
|
||||
@ -122,12 +109,12 @@ impl ExpressionNode for VariableRef {
|
||||
let defined_variable = variables.get(0).unwrap().borrow();
|
||||
assert_eq!(variable.id, defined_variable.id);
|
||||
|
||||
value.is_consty()
|
||||
value.get().is_consty()
|
||||
} else {
|
||||
for defined_variable in variables.iter() {
|
||||
let defined_variable = defined_variable.borrow();
|
||||
if defined_variable.id == variable.id {
|
||||
return value.is_consty();
|
||||
return value.get().is_consty();
|
||||
}
|
||||
}
|
||||
panic!("no corresponding tuple variable found during const destructuring (corrupt asg?)");
|
||||
@ -139,21 +126,21 @@ impl ExpressionNode for VariableRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::Identifier> for Arc<Expression> {
|
||||
impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::Identifier,
|
||||
expected_type: Option<PartialType>,
|
||||
) -> Result<Arc<Expression>, AsgConvertError> {
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<&'a Expression<'a>, AsgConvertError> {
|
||||
let variable = if value.name == "input" {
|
||||
if let Some(function) = scope.borrow().resolve_current_function() {
|
||||
if let Some(function) = scope.resolve_current_function() {
|
||||
if !function.has_input {
|
||||
return Err(AsgConvertError::unresolved_reference(&value.name, &value.span));
|
||||
}
|
||||
} else {
|
||||
return Err(AsgConvertError::unresolved_reference(&value.name, &value.span));
|
||||
}
|
||||
if let Some(input) = scope.borrow().resolve_input() {
|
||||
if let Some(input) = scope.resolve_input() {
|
||||
input.container
|
||||
} else {
|
||||
return Err(AsgConvertError::InternalError(
|
||||
@ -161,12 +148,12 @@ impl FromAst<leo_ast::Identifier> for Arc<Expression> {
|
||||
));
|
||||
}
|
||||
} else {
|
||||
match scope.borrow().resolve_variable(&value.name) {
|
||||
match scope.resolve_variable(&value.name) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
if value.name.starts_with("aleo1") {
|
||||
return Ok(Arc::new(Expression::Constant(Constant {
|
||||
parent: RefCell::new(None),
|
||||
return Ok(scope.alloc_expression(Expression::Constant(Constant {
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
value: ConstValue::Address(value.name.clone()),
|
||||
})));
|
||||
@ -177,11 +164,11 @@ impl FromAst<leo_ast::Identifier> for Arc<Expression> {
|
||||
};
|
||||
|
||||
let variable_ref = VariableRef {
|
||||
parent: RefCell::new(None),
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
variable: variable.clone(),
|
||||
variable,
|
||||
};
|
||||
let expression = Arc::new(Expression::VariableRef(variable_ref));
|
||||
let expression = scope.alloc_expression(Expression::VariableRef(variable_ref));
|
||||
|
||||
if let Some(expected_type) = expected_type {
|
||||
let type_ = expression
|
||||
@ -197,13 +184,13 @@ impl FromAst<leo_ast::Identifier> for Arc<Expression> {
|
||||
}
|
||||
|
||||
let mut variable_ref = variable.borrow_mut();
|
||||
variable_ref.references.push(Arc::downgrade(&expression));
|
||||
variable_ref.references.push(expression);
|
||||
|
||||
Ok(expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Identifier> for &VariableRef {
|
||||
impl<'a> Into<leo_ast::Identifier> for &VariableRef<'a> {
|
||||
fn into(self) -> leo_ast::Identifier {
|
||||
self.variable.borrow().name.clone()
|
||||
}
|
||||
|
@ -16,56 +16,74 @@
|
||||
|
||||
//! Helper methods for resolving imported packages.
|
||||
|
||||
use crate::{AsgConvertError, Program, Span};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{AsgContext, AsgConvertError, Program, Span};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub trait ImportResolver {
|
||||
fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result<Option<Program>, AsgConvertError>;
|
||||
pub trait ImportResolver<'a> {
|
||||
fn resolve_package(
|
||||
&mut self,
|
||||
context: AsgContext<'a>,
|
||||
package_segments: &[&str],
|
||||
span: &Span,
|
||||
) -> Result<Option<Program<'a>>, AsgConvertError>;
|
||||
}
|
||||
|
||||
pub struct NullImportResolver;
|
||||
|
||||
impl ImportResolver for NullImportResolver {
|
||||
impl<'a> ImportResolver<'a> for NullImportResolver {
|
||||
fn resolve_package(
|
||||
&mut self,
|
||||
_context: AsgContext<'a>,
|
||||
_package_segments: &[&str],
|
||||
_span: &Span,
|
||||
) -> Result<Option<Program>, AsgConvertError> {
|
||||
) -> Result<Option<Program<'a>>, AsgConvertError> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CoreImportResolver<'a, T: ImportResolver + 'static>(pub &'a mut T);
|
||||
pub struct CoreImportResolver<'a, 'b, T: ImportResolver<'b>> {
|
||||
inner: &'a mut T,
|
||||
lifetime: PhantomData<&'b ()>,
|
||||
}
|
||||
|
||||
impl<'a, T: ImportResolver + 'static> ImportResolver for CoreImportResolver<'a, T> {
|
||||
fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result<Option<Program>, AsgConvertError> {
|
||||
if !package_segments.is_empty() && package_segments.get(0).unwrap() == &"core" {
|
||||
Ok(crate::resolve_core_module(&*package_segments[1..].join("."))?)
|
||||
} else {
|
||||
self.0.resolve_package(package_segments, span)
|
||||
impl<'a, 'b, T: ImportResolver<'b>> CoreImportResolver<'a, 'b, T> {
|
||||
pub fn new(inner: &'a mut T) -> Self {
|
||||
CoreImportResolver {
|
||||
inner,
|
||||
lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StandardImportResolver;
|
||||
|
||||
impl ImportResolver for StandardImportResolver {
|
||||
impl<'a, 'b, T: ImportResolver<'b>> ImportResolver<'b> for CoreImportResolver<'a, 'b, T> {
|
||||
fn resolve_package(
|
||||
&mut self,
|
||||
_package_segments: &[&str],
|
||||
_span: &Span,
|
||||
) -> Result<Option<Program>, AsgConvertError> {
|
||||
Ok(None)
|
||||
context: AsgContext<'b>,
|
||||
package_segments: &[&str],
|
||||
span: &Span,
|
||||
) -> Result<Option<Program<'b>>, AsgConvertError> {
|
||||
if !package_segments.is_empty() && package_segments.get(0).unwrap() == &"core" {
|
||||
Ok(crate::resolve_core_module(context, &*package_segments[1..].join("."))?)
|
||||
} else {
|
||||
self.inner.resolve_package(context, package_segments, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MockedImportResolver {
|
||||
pub packages: IndexMap<String, Program>,
|
||||
pub struct MockedImportResolver<'a> {
|
||||
pub packages: IndexMap<String, Program<'a>>,
|
||||
}
|
||||
|
||||
impl ImportResolver for MockedImportResolver {
|
||||
fn resolve_package(&mut self, package_segments: &[&str], _span: &Span) -> Result<Option<Program>, AsgConvertError> {
|
||||
impl<'a> ImportResolver<'a> for MockedImportResolver<'a> {
|
||||
fn resolve_package(
|
||||
&mut self,
|
||||
_context: AsgContext<'a>,
|
||||
package_segments: &[&str],
|
||||
_span: &Span,
|
||||
) -> Result<Option<Program<'a>>, AsgConvertError> {
|
||||
Ok(self.packages.get(&package_segments.join(".")).cloned())
|
||||
}
|
||||
}
|
||||
|
122
asg/src/input.rs
122
asg/src/input.rs
@ -14,23 +14,20 @@
|
||||
// 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::{Circuit, CircuitBody, CircuitMember, CircuitMemberBody, Identifier, Scope, Type, Variable, WeakType};
|
||||
use crate::{Circuit, CircuitMember, Identifier, Scope, Type, Variable};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
/// Stores program input values as asg nodes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Input {
|
||||
pub registers: Arc<CircuitBody>,
|
||||
pub state: Arc<CircuitBody>,
|
||||
pub state_leaf: Arc<CircuitBody>,
|
||||
pub record: Arc<CircuitBody>,
|
||||
pub container_circuit: Arc<CircuitBody>,
|
||||
pub container: Variable,
|
||||
/// Stores program input values as ASG nodes.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Input<'a> {
|
||||
pub registers: &'a Circuit<'a>,
|
||||
pub state: &'a Circuit<'a>,
|
||||
pub state_leaf: &'a Circuit<'a>,
|
||||
pub record: &'a Circuit<'a>,
|
||||
pub container_circuit: &'a Circuit<'a>,
|
||||
pub container: &'a Variable<'a>,
|
||||
}
|
||||
|
||||
pub const CONTAINER_PSEUDO_CIRCUIT: &str = "$InputContainer";
|
||||
@ -39,95 +36,56 @@ pub const RECORD_PSEUDO_CIRCUIT: &str = "$InputRecord";
|
||||
pub const STATE_PSEUDO_CIRCUIT: &str = "$InputState";
|
||||
pub const STATE_LEAF_PSEUDO_CIRCUIT: &str = "$InputStateLeaf";
|
||||
|
||||
impl Input {
|
||||
fn make_header(name: &str) -> Arc<Circuit> {
|
||||
Arc::new(Circuit {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
impl<'a> Input<'a> {
|
||||
fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> {
|
||||
scope.alloc_circuit(Circuit {
|
||||
id: scope.context.get_id(),
|
||||
name: RefCell::new(Identifier::new(name.to_string())),
|
||||
body: RefCell::new(Weak::new()),
|
||||
members: RefCell::new(IndexMap::new()),
|
||||
core_mapping: RefCell::new(None),
|
||||
scope,
|
||||
span: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn make_body(scope: &Scope, circuit: &Arc<Circuit>) -> Arc<CircuitBody> {
|
||||
let body = Arc::new(CircuitBody {
|
||||
scope: scope.clone(),
|
||||
span: None,
|
||||
circuit: circuit.clone(),
|
||||
members: RefCell::new(IndexMap::new()),
|
||||
});
|
||||
circuit.body.replace(Arc::downgrade(&body));
|
||||
body
|
||||
}
|
||||
|
||||
pub fn new(scope: &Scope) -> Self {
|
||||
let registers = Self::make_header(REGISTERS_PSEUDO_CIRCUIT);
|
||||
let record = Self::make_header(RECORD_PSEUDO_CIRCUIT);
|
||||
let state = Self::make_header(STATE_PSEUDO_CIRCUIT);
|
||||
let state_leaf = Self::make_header(STATE_LEAF_PSEUDO_CIRCUIT);
|
||||
pub fn new(scope: &'a Scope<'a>) -> Self {
|
||||
let input_scope = scope.make_subscope();
|
||||
let registers = Self::make_header(input_scope, REGISTERS_PSEUDO_CIRCUIT);
|
||||
let record = Self::make_header(input_scope, RECORD_PSEUDO_CIRCUIT);
|
||||
let state = Self::make_header(input_scope, STATE_PSEUDO_CIRCUIT);
|
||||
let state_leaf = Self::make_header(input_scope, STATE_LEAF_PSEUDO_CIRCUIT);
|
||||
|
||||
let mut container_members = IndexMap::new();
|
||||
container_members.insert(
|
||||
"registers".to_string(),
|
||||
CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(®isters))),
|
||||
);
|
||||
container_members.insert(
|
||||
"record".to_string(),
|
||||
CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(&record))),
|
||||
);
|
||||
container_members.insert(
|
||||
"state".to_string(),
|
||||
CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(&state))),
|
||||
CircuitMember::Variable(Type::Circuit(registers)),
|
||||
);
|
||||
container_members.insert("record".to_string(), CircuitMember::Variable(Type::Circuit(record)));
|
||||
container_members.insert("state".to_string(), CircuitMember::Variable(Type::Circuit(state)));
|
||||
container_members.insert(
|
||||
"state_leaf".to_string(),
|
||||
CircuitMember::Variable(WeakType::Circuit(Arc::downgrade(&state_leaf))),
|
||||
CircuitMember::Variable(Type::Circuit(state_leaf)),
|
||||
);
|
||||
|
||||
let container_circuit = Arc::new(Circuit {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
let container_circuit = input_scope.alloc_circuit(Circuit {
|
||||
id: scope.context.get_id(),
|
||||
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.to_string())),
|
||||
body: RefCell::new(Weak::new()),
|
||||
members: RefCell::new(container_members),
|
||||
core_mapping: RefCell::new(None),
|
||||
scope: input_scope,
|
||||
span: Default::default(),
|
||||
});
|
||||
|
||||
let registers_body = Self::make_body(scope, ®isters);
|
||||
let record_body = Self::make_body(scope, &record);
|
||||
let state_body = Self::make_body(scope, &state);
|
||||
let state_leaf_body = Self::make_body(scope, &state_leaf);
|
||||
|
||||
let mut container_body_members = IndexMap::new();
|
||||
container_body_members.insert(
|
||||
"registers".to_string(),
|
||||
CircuitMemberBody::Variable(Type::Circuit(registers)),
|
||||
);
|
||||
container_body_members.insert("record".to_string(), CircuitMemberBody::Variable(Type::Circuit(record)));
|
||||
container_body_members.insert("state".to_string(), CircuitMemberBody::Variable(Type::Circuit(state)));
|
||||
container_body_members.insert(
|
||||
"state_leaf".to_string(),
|
||||
CircuitMemberBody::Variable(Type::Circuit(state_leaf)),
|
||||
);
|
||||
|
||||
let container_circuit_body = Arc::new(CircuitBody {
|
||||
scope: scope.clone(),
|
||||
span: None,
|
||||
circuit: container_circuit.clone(),
|
||||
members: RefCell::new(container_body_members),
|
||||
});
|
||||
container_circuit.body.replace(Arc::downgrade(&container_circuit_body));
|
||||
|
||||
Input {
|
||||
registers: registers_body,
|
||||
record: record_body,
|
||||
state: state_body,
|
||||
state_leaf: state_leaf_body,
|
||||
container_circuit: container_circuit_body,
|
||||
container: Arc::new(RefCell::new(crate::InnerVariable {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
registers,
|
||||
record,
|
||||
state,
|
||||
state_leaf,
|
||||
container_circuit,
|
||||
container: input_scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||
id: scope.context.get_id(),
|
||||
name: Identifier::new("input".to_string()),
|
||||
type_: Type::Circuit(container_circuit).weak(),
|
||||
type_: Type::Circuit(container_circuit),
|
||||
mutable: false,
|
||||
const_: false,
|
||||
declaration: crate::VariableDeclaration::Input,
|
||||
@ -138,7 +96,7 @@ impl Input {
|
||||
}
|
||||
}
|
||||
|
||||
impl Circuit {
|
||||
impl<'a> Circuit<'a> {
|
||||
pub fn is_input_pseudo_circuit(&self) -> bool {
|
||||
matches!(
|
||||
&*self.name.borrow().name,
|
||||
|
@ -65,11 +65,18 @@ pub mod type_;
|
||||
pub use type_::*;
|
||||
|
||||
pub mod variable;
|
||||
use typed_arena::Arena;
|
||||
pub use variable::*;
|
||||
|
||||
pub mod pass;
|
||||
pub use pass::*;
|
||||
|
||||
pub mod context;
|
||||
pub use context::*;
|
||||
|
||||
pub use leo_ast::{Ast, Identifier, Span};
|
||||
|
||||
use std::{cell::RefCell, path::Path, sync::Arc};
|
||||
use std::path::Path;
|
||||
|
||||
/// The abstract semantic graph (ASG) for a Leo program.
|
||||
///
|
||||
@ -77,21 +84,27 @@ use std::{cell::RefCell, path::Path, sync::Arc};
|
||||
/// These data types form a graph that begins from a [`Program`] type node.
|
||||
///
|
||||
/// A new [`Asg`] can be created from an [`Ast`] generated in the `ast` module.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Asg {
|
||||
asg: Arc<RefCell<InternalProgram>>,
|
||||
#[derive(Clone)]
|
||||
pub struct Asg<'a> {
|
||||
context: AsgContext<'a>,
|
||||
asg: Program<'a>,
|
||||
}
|
||||
|
||||
impl Asg {
|
||||
impl<'a> Asg<'a> {
|
||||
/// Creates a new ASG from a given AST and import resolver.
|
||||
pub fn new<T: ImportResolver + 'static>(ast: &Ast, resolver: &mut T) -> Result<Self, AsgConvertError> {
|
||||
pub fn new<T: ImportResolver<'a>>(
|
||||
context: AsgContext<'a>,
|
||||
ast: &Ast,
|
||||
resolver: &mut T,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
Ok(Self {
|
||||
asg: InternalProgram::new(&ast.as_repr(), resolver)?,
|
||||
context,
|
||||
asg: InternalProgram::new(context, &ast.as_repr(), resolver)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the internal program ASG representation.
|
||||
pub fn as_repr(&self) -> Arc<RefCell<InternalProgram>> {
|
||||
pub fn as_repr(&self) -> Program<'a> {
|
||||
self.asg.clone()
|
||||
}
|
||||
|
||||
@ -108,10 +121,22 @@ impl Asg {
|
||||
}
|
||||
|
||||
// TODO (howardwu): Remove this.
|
||||
pub fn load_asg<T: ImportResolver + 'static>(content: &str, resolver: &mut T) -> Result<Program, AsgConvertError> {
|
||||
pub fn load_asg<'a, T: ImportResolver<'a>>(
|
||||
context: AsgContext<'a>,
|
||||
content: &str,
|
||||
resolver: &mut T,
|
||||
) -> Result<Program<'a>, AsgConvertError> {
|
||||
// Parses the Leo file and constructs a grammar ast.
|
||||
let ast = leo_grammar::Grammar::new(&Path::new("input.leo"), content)
|
||||
.map_err(|e| AsgConvertError::InternalError(format!("ast: {:?}", e)))?;
|
||||
|
||||
InternalProgram::new(leo_ast::Ast::new("load_ast", &ast)?.as_repr(), resolver)
|
||||
InternalProgram::new(context, leo_ast::Ast::new("load_ast", &ast)?.as_repr(), resolver)
|
||||
}
|
||||
|
||||
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {
|
||||
Arena::new()
|
||||
}
|
||||
|
||||
pub fn new_context<'a>(arena: &'a Arena<ArenaNode<'a>>) -> AsgContext<'a> {
|
||||
AsgContextInner::new(arena)
|
||||
}
|
||||
|
@ -14,15 +14,40 @@
|
||||
// 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::{AsgConvertError, PartialType, Scope, Span};
|
||||
use crate::{
|
||||
AsgContextInner,
|
||||
AsgConvertError,
|
||||
Circuit,
|
||||
Expression,
|
||||
Function,
|
||||
PartialType,
|
||||
Scope,
|
||||
Span,
|
||||
Statement,
|
||||
Variable,
|
||||
};
|
||||
|
||||
/// A node in the abstract semantic graph.
|
||||
pub trait Node {
|
||||
fn span(&self) -> Option<&Span>;
|
||||
}
|
||||
|
||||
pub(super) trait FromAst<T: leo_ast::Node + 'static>: Sized + 'static {
|
||||
pub(super) trait FromAst<'a, T: leo_ast::Node + 'static>: Sized {
|
||||
// expected_type contract: if present, output expression must be of type expected_type.
|
||||
// type of an element may NEVER be None unless it is functionally a non-expression. (static call targets, function ref call targets are not expressions)
|
||||
fn from_ast(scope: &Scope, value: &T, expected_type: Option<PartialType>) -> Result<Self, AsgConvertError>;
|
||||
fn from_ast(
|
||||
scope: &'a Scope<'a>,
|
||||
value: &T,
|
||||
expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError>;
|
||||
}
|
||||
|
||||
pub enum ArenaNode<'a> {
|
||||
Expression(Expression<'a>),
|
||||
Scope(Scope<'a>),
|
||||
Statement(Statement<'a>),
|
||||
Variable(Variable<'a>),
|
||||
Circuit(Circuit<'a>),
|
||||
Function(Function<'a>),
|
||||
Inner(AsgContextInner<'a>),
|
||||
}
|
||||
|
22
asg/src/pass.rs
Normal file
22
asg/src/pass.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 crate::Program;
|
||||
pub use leo_ast::Error as FormattedError;
|
||||
|
||||
pub trait AsgPass {
|
||||
fn do_pass(asg: &Program) -> Result<(), FormattedError>;
|
||||
}
|
@ -16,15 +16,16 @@
|
||||
|
||||
// TODO (protryon): We should merge this with core
|
||||
|
||||
use crate::{AsgConvertError, Program};
|
||||
use crate::{AsgContext, AsgConvertError, Program};
|
||||
|
||||
// TODO (protryon): Make asg deep copy so we can cache resolved core modules
|
||||
// TODO (protryon): Figure out how to do headers without bogus returns
|
||||
|
||||
pub fn resolve_core_module(module: &str) -> Result<Option<Program>, AsgConvertError> {
|
||||
pub fn resolve_core_module<'a>(context: AsgContext<'a>, module: &str) -> Result<Option<Program<'a>>, AsgConvertError> {
|
||||
match module {
|
||||
"unstable.blake2s" => {
|
||||
let asg = crate::load_asg(
|
||||
context,
|
||||
r#"
|
||||
circuit Blake2s {
|
||||
function hash(seed: [u8; 32], message: [u8; 32]) -> [u8; 32] {
|
||||
@ -34,7 +35,7 @@ pub fn resolve_core_module(module: &str) -> Result<Option<Program>, AsgConvertEr
|
||||
"#,
|
||||
&mut crate::NullImportResolver,
|
||||
)?;
|
||||
asg.borrow().set_core_mapping("blake2s");
|
||||
asg.set_core_mapping("blake2s");
|
||||
Ok(Some(asg))
|
||||
}
|
||||
_ => Ok(None),
|
||||
|
@ -14,37 +14,28 @@
|
||||
// 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::{AsgConvertError, Function, FunctionBody, Identifier, InnerScope, Node, Scope, Span, Type, WeakType};
|
||||
use crate::{AsgConvertError, Function, Identifier, Node, Scope, Span, Type};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CircuitMemberBody {
|
||||
Variable(Type),
|
||||
Function(Arc<FunctionBody>),
|
||||
#[derive(Clone)]
|
||||
pub enum CircuitMember<'a> {
|
||||
Variable(Type<'a>),
|
||||
Function(&'a Function<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CircuitMember {
|
||||
Variable(WeakType),
|
||||
Function(Arc<Function>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Circuit {
|
||||
pub id: Uuid,
|
||||
#[derive(Clone)]
|
||||
pub struct Circuit<'a> {
|
||||
pub id: u32,
|
||||
pub name: RefCell<Identifier>,
|
||||
pub core_mapping: RefCell<Option<String>>,
|
||||
pub body: RefCell<Weak<CircuitBody>>,
|
||||
pub members: RefCell<IndexMap<String, CircuitMember>>,
|
||||
pub scope: &'a Scope<'a>,
|
||||
pub span: Option<Span>,
|
||||
pub members: RefCell<IndexMap<String, CircuitMember<'a>>>,
|
||||
}
|
||||
|
||||
impl PartialEq for Circuit {
|
||||
impl<'a> PartialEq for Circuit<'a> {
|
||||
fn eq(&self, other: &Circuit) -> bool {
|
||||
if self.name != other.name {
|
||||
return false;
|
||||
@ -52,81 +43,30 @@ impl PartialEq for Circuit {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
impl Eq for Circuit {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CircuitBody {
|
||||
pub scope: Scope,
|
||||
pub span: Option<Span>,
|
||||
pub circuit: Arc<Circuit>,
|
||||
pub members: RefCell<IndexMap<String, CircuitMemberBody>>,
|
||||
}
|
||||
impl<'a> Eq for Circuit<'a> {}
|
||||
|
||||
impl PartialEq for CircuitBody {
|
||||
fn eq(&self, other: &CircuitBody) -> bool {
|
||||
self.circuit == other.circuit
|
||||
}
|
||||
}
|
||||
impl Eq for CircuitBody {}
|
||||
|
||||
impl Node for CircuitMemberBody {
|
||||
impl<'a> Node for Circuit<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
None
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Circuit {
|
||||
pub(super) fn init(value: &leo_ast::Circuit) -> Arc<Circuit> {
|
||||
Arc::new(Circuit {
|
||||
id: Uuid::new_v4(),
|
||||
impl<'a> Circuit<'a> {
|
||||
pub(super) fn init(scope: &'a Scope<'a>, value: &leo_ast::Circuit) -> Result<&'a Circuit<'a>, AsgConvertError> {
|
||||
let new_scope = scope.make_subscope();
|
||||
|
||||
let circuit = scope.alloc_circuit(Circuit {
|
||||
id: scope.context.get_id(),
|
||||
name: RefCell::new(value.circuit_name.clone()),
|
||||
body: RefCell::new(Weak::new()),
|
||||
members: RefCell::new(IndexMap::new()),
|
||||
core_mapping: RefCell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn from_ast(self: Arc<Circuit>, scope: &Scope, value: &leo_ast::Circuit) -> Result<(), AsgConvertError> {
|
||||
let new_scope = InnerScope::make_subscope(scope); // temporary scope for function headers
|
||||
new_scope.borrow_mut().circuit_self = Some(self.clone());
|
||||
|
||||
let mut members = self.members.borrow_mut();
|
||||
for member in value.members.iter() {
|
||||
match member {
|
||||
leo_ast::CircuitMember::CircuitVariable(name, type_) => {
|
||||
members.insert(
|
||||
name.name.clone(),
|
||||
CircuitMember::Variable(new_scope.borrow().resolve_ast_type(type_)?.into()),
|
||||
);
|
||||
}
|
||||
leo_ast::CircuitMember::CircuitFunction(function) => {
|
||||
let asg_function = Arc::new(Function::from_ast(&new_scope, function)?);
|
||||
|
||||
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (_, member) in members.iter() {
|
||||
if let CircuitMember::Function(func) = member {
|
||||
func.circuit.borrow_mut().replace(Arc::downgrade(&self));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CircuitBody {
|
||||
pub(super) fn from_ast(
|
||||
scope: &Scope,
|
||||
value: &leo_ast::Circuit,
|
||||
circuit: Arc<Circuit>,
|
||||
) -> Result<CircuitBody, AsgConvertError> {
|
||||
let mut members = IndexMap::new();
|
||||
let new_scope = InnerScope::make_subscope(scope);
|
||||
new_scope.borrow_mut().circuit_self = Some(circuit.clone());
|
||||
span: Some(value.circuit_name.span.clone()),
|
||||
scope: new_scope,
|
||||
});
|
||||
new_scope.circuit_self.replace(Some(circuit));
|
||||
|
||||
let mut members = circuit.members.borrow_mut();
|
||||
for member in value.members.iter() {
|
||||
match member {
|
||||
leo_ast::CircuitMember::CircuitVariable(name, type_) => {
|
||||
@ -139,7 +79,7 @@ impl CircuitBody {
|
||||
}
|
||||
members.insert(
|
||||
name.name.clone(),
|
||||
CircuitMemberBody::Variable(new_scope.borrow().resolve_ast_type(type_)?),
|
||||
CircuitMember::Variable(new_scope.resolve_ast_type(type_)?),
|
||||
);
|
||||
}
|
||||
leo_ast::CircuitMember::CircuitFunction(function) => {
|
||||
@ -150,51 +90,51 @@ impl CircuitBody {
|
||||
&function.identifier.span,
|
||||
));
|
||||
}
|
||||
let asg_function = {
|
||||
let circuit_members = circuit.members.borrow();
|
||||
match circuit_members.get(&function.identifier.name).unwrap() {
|
||||
CircuitMember::Function(f) => f.clone(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
};
|
||||
let function_body = Arc::new(FunctionBody::from_ast(&new_scope, function, asg_function.clone())?);
|
||||
asg_function.body.replace(Arc::downgrade(&function_body));
|
||||
|
||||
members.insert(
|
||||
function.identifier.name.clone(),
|
||||
CircuitMemberBody::Function(function_body),
|
||||
);
|
||||
let asg_function = Function::init(new_scope, function)?;
|
||||
asg_function.circuit.replace(Some(circuit));
|
||||
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CircuitBody {
|
||||
span: Some(value.circuit_name.span.clone()),
|
||||
circuit,
|
||||
members: RefCell::new(members),
|
||||
scope: scope.clone(),
|
||||
})
|
||||
Ok(circuit)
|
||||
}
|
||||
|
||||
pub(super) fn fill_from_ast(self: &'a Circuit<'a>, value: &leo_ast::Circuit) -> Result<(), AsgConvertError> {
|
||||
for member in value.members.iter() {
|
||||
match member {
|
||||
leo_ast::CircuitMember::CircuitVariable(..) => {}
|
||||
leo_ast::CircuitMember::CircuitFunction(function) => {
|
||||
let asg_function = match *self
|
||||
.members
|
||||
.borrow()
|
||||
.get(&function.identifier.name)
|
||||
.expect("missing header for defined circuit function")
|
||||
{
|
||||
CircuitMember::Function(f) => f,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
Function::fill_from_ast(asg_function, function)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Circuit> for &Circuit {
|
||||
impl<'a> Into<leo_ast::Circuit> for &Circuit<'a> {
|
||||
fn into(self) -> leo_ast::Circuit {
|
||||
let members = match self.body.borrow().upgrade() {
|
||||
Some(body) => body
|
||||
.members
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(name, member)| match &member {
|
||||
CircuitMemberBody::Variable(type_) => {
|
||||
leo_ast::CircuitMember::CircuitVariable(Identifier::new(name.clone()), type_.into())
|
||||
}
|
||||
CircuitMemberBody::Function(func) => {
|
||||
leo_ast::CircuitMember::CircuitFunction(func.function.as_ref().into())
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
None => vec![],
|
||||
};
|
||||
let members = self
|
||||
.members
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|(name, member)| match &member {
|
||||
CircuitMember::Variable(type_) => {
|
||||
leo_ast::CircuitMember::CircuitVariable(Identifier::new(name.clone()), type_.into())
|
||||
}
|
||||
CircuitMember::Function(func) => leo_ast::CircuitMember::CircuitFunction((*func).into()),
|
||||
})
|
||||
.collect();
|
||||
leo_ast::Circuit {
|
||||
circuit_name: self.name.borrow().clone(),
|
||||
members,
|
||||
|
@ -20,7 +20,6 @@ use crate::{
|
||||
Circuit,
|
||||
FromAst,
|
||||
Identifier,
|
||||
InnerScope,
|
||||
MonoidalDirector,
|
||||
ReturnPathReducer,
|
||||
Scope,
|
||||
@ -28,72 +27,57 @@ use crate::{
|
||||
Statement,
|
||||
Type,
|
||||
Variable,
|
||||
WeakType,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
use leo_ast::FunctionInput;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum FunctionQualifier {
|
||||
SelfRef,
|
||||
MutSelfRef,
|
||||
Static,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Function {
|
||||
pub id: Uuid,
|
||||
#[derive(Clone)]
|
||||
pub struct Function<'a> {
|
||||
pub id: u32,
|
||||
pub name: RefCell<Identifier>,
|
||||
pub output: WeakType,
|
||||
pub output: Type<'a>,
|
||||
pub has_input: bool,
|
||||
pub arguments: Vec<Variable>,
|
||||
pub circuit: RefCell<Option<Weak<Circuit>>>,
|
||||
pub body: RefCell<Weak<FunctionBody>>,
|
||||
pub arguments: IndexMap<String, Cell<&'a Variable<'a>>>,
|
||||
pub circuit: Cell<Option<&'a Circuit<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub body: Cell<Option<&'a Statement<'a>>>,
|
||||
pub scope: &'a Scope<'a>,
|
||||
pub qualifier: FunctionQualifier,
|
||||
}
|
||||
|
||||
impl PartialEq for Function {
|
||||
fn eq(&self, other: &Function) -> bool {
|
||||
impl<'a> PartialEq for Function<'a> {
|
||||
fn eq(&self, other: &Function<'a>) -> bool {
|
||||
if self.name.borrow().name != other.name.borrow().name {
|
||||
return false;
|
||||
}
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
impl Eq for Function {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionBody {
|
||||
pub span: Option<Span>,
|
||||
pub function: Arc<Function>,
|
||||
pub body: Arc<Statement>,
|
||||
pub scope: Scope,
|
||||
}
|
||||
impl<'a> Eq for Function<'a> {}
|
||||
|
||||
impl PartialEq for FunctionBody {
|
||||
fn eq(&self, other: &FunctionBody) -> bool {
|
||||
self.function == other.function
|
||||
}
|
||||
}
|
||||
impl Eq for FunctionBody {}
|
||||
|
||||
impl Function {
|
||||
pub(crate) fn from_ast(scope: &Scope, value: &leo_ast::Function) -> Result<Function, AsgConvertError> {
|
||||
let output: Type = value
|
||||
impl<'a> Function<'a> {
|
||||
pub(crate) fn init(scope: &'a Scope<'a>, value: &leo_ast::Function) -> Result<&'a Function<'a>, AsgConvertError> {
|
||||
let output: Type<'a> = value
|
||||
.output
|
||||
.as_ref()
|
||||
.map(|t| scope.borrow().resolve_ast_type(t))
|
||||
.map(|t| scope.resolve_ast_type(t))
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| Type::Tuple(vec![]));
|
||||
let mut qualifier = FunctionQualifier::Static;
|
||||
let mut has_input = false;
|
||||
let new_scope = scope.make_subscope();
|
||||
|
||||
let mut arguments = vec![];
|
||||
let mut arguments = IndexMap::new();
|
||||
{
|
||||
for input in value.input.iter() {
|
||||
match input {
|
||||
@ -107,77 +91,74 @@ impl Function {
|
||||
qualifier = FunctionQualifier::MutSelfRef;
|
||||
}
|
||||
FunctionInput::Variable(leo_ast::FunctionInputVariable {
|
||||
identifier,
|
||||
mutable,
|
||||
const_,
|
||||
type_,
|
||||
span: _span,
|
||||
identifier,
|
||||
const_,
|
||||
mutable,
|
||||
..
|
||||
}) => {
|
||||
let variable = Arc::new(RefCell::new(crate::InnerVariable {
|
||||
id: Uuid::new_v4(),
|
||||
let variable = scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||
id: scope.context.get_id(),
|
||||
name: identifier.clone(),
|
||||
type_: scope.borrow().resolve_ast_type(&type_)?.weak(),
|
||||
type_: scope.resolve_ast_type(&type_)?,
|
||||
mutable: *mutable,
|
||||
const_: *const_,
|
||||
declaration: crate::VariableDeclaration::Parameter,
|
||||
references: vec![],
|
||||
assignments: vec![],
|
||||
}));
|
||||
arguments.push(variable.clone());
|
||||
arguments.insert(identifier.name.clone(), Cell::new(&*variable));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if qualifier != FunctionQualifier::Static && scope.borrow().circuit_self.is_none() {
|
||||
if qualifier != FunctionQualifier::Static && scope.circuit_self.get().is_none() {
|
||||
return Err(AsgConvertError::invalid_self_in_global(&value.span));
|
||||
}
|
||||
Ok(Function {
|
||||
id: Uuid::new_v4(),
|
||||
let function = scope.alloc_function(Function {
|
||||
id: scope.context.get_id(),
|
||||
name: RefCell::new(value.identifier.clone()),
|
||||
output: output.into(),
|
||||
output,
|
||||
has_input,
|
||||
arguments,
|
||||
circuit: RefCell::new(None),
|
||||
body: RefCell::new(Weak::new()),
|
||||
circuit: Cell::new(None),
|
||||
body: Cell::new(None),
|
||||
qualifier,
|
||||
})
|
||||
}
|
||||
}
|
||||
scope: new_scope,
|
||||
span: Some(value.span.clone()),
|
||||
});
|
||||
function.scope.function.replace(Some(function));
|
||||
|
||||
impl FunctionBody {
|
||||
pub(super) fn from_ast(
|
||||
scope: &Scope,
|
||||
value: &leo_ast::Function,
|
||||
function: Arc<Function>,
|
||||
) -> Result<FunctionBody, AsgConvertError> {
|
||||
let new_scope = InnerScope::make_subscope(scope);
|
||||
{
|
||||
let mut scope_borrow = new_scope.borrow_mut();
|
||||
if function.qualifier != FunctionQualifier::Static {
|
||||
let circuit = function.circuit.borrow();
|
||||
let self_variable = Arc::new(RefCell::new(crate::InnerVariable {
|
||||
id: Uuid::new_v4(),
|
||||
name: Identifier::new("self".to_string()),
|
||||
type_: WeakType::Circuit(circuit.as_ref().unwrap().clone()),
|
||||
mutable: function.qualifier == FunctionQualifier::MutSelfRef,
|
||||
const_: false,
|
||||
declaration: crate::VariableDeclaration::Parameter,
|
||||
references: vec![],
|
||||
assignments: vec![],
|
||||
}));
|
||||
scope_borrow.variables.insert("self".to_string(), self_variable);
|
||||
}
|
||||
scope_borrow.function = Some(function.clone());
|
||||
for argument in function.arguments.iter() {
|
||||
let name = argument.borrow().name.name.clone();
|
||||
scope_borrow.variables.insert(name, argument.clone());
|
||||
}
|
||||
Ok(function)
|
||||
}
|
||||
|
||||
pub(super) fn fill_from_ast(self: &'a Function<'a>, value: &leo_ast::Function) -> Result<(), AsgConvertError> {
|
||||
if self.qualifier != FunctionQualifier::Static {
|
||||
let circuit = self.circuit.get();
|
||||
let self_variable = self.scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||
id: self.scope.context.get_id(),
|
||||
name: Identifier::new("self".to_string()),
|
||||
type_: Type::Circuit(circuit.as_ref().unwrap()),
|
||||
mutable: self.qualifier == FunctionQualifier::MutSelfRef,
|
||||
const_: false,
|
||||
declaration: crate::VariableDeclaration::Parameter,
|
||||
references: vec![],
|
||||
assignments: vec![],
|
||||
}));
|
||||
self.scope
|
||||
.variables
|
||||
.borrow_mut()
|
||||
.insert("self".to_string(), self_variable);
|
||||
}
|
||||
let main_block = BlockStatement::from_ast(&new_scope, &value.block, None)?;
|
||||
for (name, argument) in self.arguments.iter() {
|
||||
self.scope.variables.borrow_mut().insert(name.clone(), argument.get());
|
||||
}
|
||||
|
||||
let main_block = BlockStatement::from_ast(self.scope, &value.block, None)?;
|
||||
let mut director = MonoidalDirector::new(ReturnPathReducer::new());
|
||||
if !director.reduce_block(&main_block).0 && !function.output.is_unit() {
|
||||
if !director.reduce_block(&main_block).0 && !self.output.is_unit() {
|
||||
return Err(AsgConvertError::function_missing_return(
|
||||
&function.name.borrow().name,
|
||||
&self.name.borrow().name,
|
||||
&value.span,
|
||||
));
|
||||
}
|
||||
@ -185,47 +166,39 @@ impl FunctionBody {
|
||||
#[allow(clippy::never_loop)] // TODO @Protryon: How should we return multiple errors?
|
||||
for (span, error) in director.reducer().errors {
|
||||
return Err(AsgConvertError::function_return_validation(
|
||||
&function.name.borrow().name,
|
||||
&self.name.borrow().name,
|
||||
&error,
|
||||
&span,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(FunctionBody {
|
||||
span: Some(value.span.clone()),
|
||||
function,
|
||||
body: Arc::new(Statement::Block(main_block)),
|
||||
scope: new_scope,
|
||||
})
|
||||
self.body
|
||||
.replace(Some(self.scope.alloc_statement(Statement::Block(main_block))));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Function> for &Function {
|
||||
impl<'a> Into<leo_ast::Function> for &Function<'a> {
|
||||
fn into(self) -> leo_ast::Function {
|
||||
let (input, body, span) = match self.body.borrow().upgrade() {
|
||||
Some(body) => (
|
||||
body.function
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|variable| {
|
||||
let variable = variable.borrow();
|
||||
leo_ast::FunctionInput::Variable(leo_ast::FunctionInputVariable {
|
||||
identifier: variable.name.clone(),
|
||||
mutable: variable.mutable,
|
||||
const_: variable.const_,
|
||||
type_: (&variable.type_.clone().strong()).into(),
|
||||
span: Span::default(),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
match body.body.as_ref() {
|
||||
Statement::Block(block) => block.into(),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
body.span.clone().unwrap_or_default(),
|
||||
),
|
||||
let input = self
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|(_, variable)| {
|
||||
let variable = variable.get().borrow();
|
||||
leo_ast::FunctionInput::Variable(leo_ast::FunctionInputVariable {
|
||||
identifier: variable.name.clone(),
|
||||
mutable: variable.mutable,
|
||||
const_: variable.const_,
|
||||
type_: (&variable.type_).into(),
|
||||
span: Span::default(),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let (body, span) = match self.body.get() {
|
||||
Some(Statement::Block(block)) => (block.into(), block.span.clone().unwrap_or_default()),
|
||||
Some(_) => unimplemented!(),
|
||||
None => (
|
||||
vec![],
|
||||
leo_ast::Block {
|
||||
statements: vec![],
|
||||
span: Default::default(),
|
||||
@ -233,7 +206,7 @@ impl Into<leo_ast::Function> for &Function {
|
||||
Default::default(),
|
||||
),
|
||||
};
|
||||
let output: Type = self.output.clone().into();
|
||||
let output: Type = self.output.clone();
|
||||
leo_ast::Function {
|
||||
identifier: self.name.borrow().clone(),
|
||||
input,
|
||||
|
@ -24,42 +24,44 @@ pub use circuit::*;
|
||||
mod function;
|
||||
pub use function::*;
|
||||
|
||||
use crate::{AsgConvertError, ImportResolver, InnerScope, Input, Scope};
|
||||
use crate::{ArenaNode, AsgContext, AsgConvertError, ImportResolver, Input, Scope};
|
||||
use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
use uuid::Uuid;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
/// Stores the Leo program abstract semantic graph (ASG).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InternalProgram {
|
||||
#[derive(Clone)]
|
||||
pub struct InternalProgram<'a> {
|
||||
pub context: AsgContext<'a>,
|
||||
|
||||
/// The unique id of the program.
|
||||
pub id: Uuid,
|
||||
pub id: u32,
|
||||
|
||||
/// The program file name.
|
||||
pub name: String,
|
||||
|
||||
/// The packages imported by this program.
|
||||
/// these should generally not be accessed directly, but through scoped imports
|
||||
pub imported_modules: IndexMap<String, Program>,
|
||||
pub imported_modules: IndexMap<String, Program<'a>>,
|
||||
|
||||
/// Maps test name => test code block.
|
||||
pub test_functions: IndexMap<String, (Arc<FunctionBody>, Option<Identifier>)>, // identifier = test input file
|
||||
pub test_functions: IndexMap<String, (&'a Function<'a>, Option<Identifier>)>, // identifier = test input file
|
||||
|
||||
/// Maps function name => function code block.
|
||||
pub functions: IndexMap<String, Arc<FunctionBody>>,
|
||||
pub functions: IndexMap<String, &'a Function<'a>>,
|
||||
|
||||
/// Maps circuit name => circuit code block.
|
||||
pub circuits: IndexMap<String, Arc<CircuitBody>>,
|
||||
pub circuits: IndexMap<String, &'a Circuit<'a>>,
|
||||
|
||||
/// Bindings for names and additional program context.
|
||||
pub scope: Scope,
|
||||
pub scope: &'a Scope<'a>,
|
||||
}
|
||||
|
||||
pub type Program = Arc<RefCell<InternalProgram>>;
|
||||
pub type Program<'a> = InternalProgram<'a>;
|
||||
|
||||
/// Enumerates what names are imported from a package.
|
||||
#[derive(Clone)]
|
||||
enum ImportSymbol {
|
||||
/// Import the symbol by name.
|
||||
Direct(String),
|
||||
@ -124,7 +126,7 @@ fn resolve_import_package_access(
|
||||
}
|
||||
}
|
||||
|
||||
impl InternalProgram {
|
||||
impl<'a> InternalProgram<'a> {
|
||||
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
|
||||
///
|
||||
/// Stages:
|
||||
@ -133,10 +135,11 @@ impl InternalProgram {
|
||||
/// 3. finalize declared functions
|
||||
/// 4. resolve all asg nodes
|
||||
///
|
||||
pub fn new<T: ImportResolver + 'static>(
|
||||
pub fn new<T: ImportResolver<'a>>(
|
||||
context: AsgContext<'a>,
|
||||
program: &leo_ast::Program,
|
||||
import_resolver: &mut T,
|
||||
) -> Result<Program, AsgConvertError> {
|
||||
) -> Result<Program<'a>, AsgConvertError> {
|
||||
// Recursively extract imported symbols.
|
||||
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
|
||||
for import in program.imports.iter() {
|
||||
@ -149,24 +152,27 @@ impl InternalProgram {
|
||||
deduplicated_imports.insert(package.clone(), span.clone());
|
||||
}
|
||||
|
||||
let mut wrapped_resolver = crate::CoreImportResolver(import_resolver);
|
||||
let mut wrapped_resolver = crate::CoreImportResolver::new(import_resolver);
|
||||
|
||||
// Load imported programs.
|
||||
let mut resolved_packages: IndexMap<Vec<String>, Program> = IndexMap::new();
|
||||
for (package, span) in deduplicated_imports.iter() {
|
||||
let pretty_package = package.join(".");
|
||||
|
||||
let resolved_package =
|
||||
match wrapped_resolver.resolve_package(&package.iter().map(|x| &**x).collect::<Vec<_>>()[..], span)? {
|
||||
Some(x) => x,
|
||||
None => return Err(AsgConvertError::unresolved_import(&*pretty_package, &Span::default())),
|
||||
};
|
||||
let resolved_package = match wrapped_resolver.resolve_package(
|
||||
context,
|
||||
&package.iter().map(|x| &**x).collect::<Vec<_>>()[..],
|
||||
span,
|
||||
)? {
|
||||
Some(x) => x,
|
||||
None => return Err(AsgConvertError::unresolved_import(&*pretty_package, &Span::default())),
|
||||
};
|
||||
|
||||
resolved_packages.insert(package.clone(), resolved_package);
|
||||
}
|
||||
|
||||
let mut imported_functions: IndexMap<String, Arc<FunctionBody>> = IndexMap::new();
|
||||
let mut imported_circuits: IndexMap<String, Arc<CircuitBody>> = IndexMap::new();
|
||||
let mut imported_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
|
||||
let mut imported_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
|
||||
|
||||
// Prepare locally relevant scope of imports.
|
||||
for (package, symbol, span) in imported_symbols.into_iter() {
|
||||
@ -175,7 +181,6 @@ impl InternalProgram {
|
||||
let resolved_package = resolved_packages
|
||||
.get(&package)
|
||||
.expect("could not find preloaded package");
|
||||
let resolved_package = resolved_package.borrow();
|
||||
match symbol {
|
||||
ImportSymbol::All => {
|
||||
imported_functions.extend(resolved_package.functions.clone().into_iter());
|
||||
@ -183,9 +188,9 @@ impl InternalProgram {
|
||||
}
|
||||
ImportSymbol::Direct(name) => {
|
||||
if let Some(function) = resolved_package.functions.get(&name) {
|
||||
imported_functions.insert(name.clone(), function.clone());
|
||||
} else if let Some(function) = resolved_package.circuits.get(&name) {
|
||||
imported_circuits.insert(name.clone(), function.clone());
|
||||
imported_functions.insert(name.clone(), *function);
|
||||
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
|
||||
imported_circuits.insert(name.clone(), *circuit);
|
||||
} else {
|
||||
return Err(AsgConvertError::unresolved_import(
|
||||
&*format!("{}.{}", pretty_package, name),
|
||||
@ -195,9 +200,9 @@ impl InternalProgram {
|
||||
}
|
||||
ImportSymbol::Alias(name, alias) => {
|
||||
if let Some(function) = resolved_package.functions.get(&name) {
|
||||
imported_functions.insert(alias.clone(), function.clone());
|
||||
} else if let Some(function) = resolved_package.circuits.get(&name) {
|
||||
imported_circuits.insert(alias.clone(), function.clone());
|
||||
imported_functions.insert(alias.clone(), *function);
|
||||
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
|
||||
imported_circuits.insert(alias.clone(), *circuit);
|
||||
} else {
|
||||
return Err(AsgConvertError::unresolved_import(
|
||||
&*format!("{}.{}", pretty_package, name),
|
||||
@ -208,71 +213,54 @@ impl InternalProgram {
|
||||
}
|
||||
}
|
||||
|
||||
let import_scope = Arc::new(RefCell::new(InnerScope {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
parent_scope: None,
|
||||
circuit_self: None,
|
||||
variables: IndexMap::new(),
|
||||
functions: imported_functions
|
||||
.iter()
|
||||
.map(|(name, func)| (name.clone(), func.function.clone()))
|
||||
.collect(),
|
||||
circuits: imported_circuits
|
||||
.iter()
|
||||
.map(|(name, circuit)| (name.clone(), circuit.circuit.clone()))
|
||||
.collect(),
|
||||
function: None,
|
||||
input: None,
|
||||
}));
|
||||
let import_scope = match context.arena.alloc(ArenaNode::Scope(Scope {
|
||||
context,
|
||||
id: context.get_id(),
|
||||
parent_scope: Cell::new(None),
|
||||
circuit_self: Cell::new(None),
|
||||
variables: RefCell::new(IndexMap::new()),
|
||||
functions: RefCell::new(imported_functions),
|
||||
circuits: RefCell::new(imported_circuits),
|
||||
function: Cell::new(None),
|
||||
input: Cell::new(None),
|
||||
})) {
|
||||
ArenaNode::Scope(c) => c,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let scope = import_scope.alloc_scope(Scope {
|
||||
context,
|
||||
input: Cell::new(Some(Input::new(import_scope))), // we use import_scope to avoid recursive scope ref here
|
||||
id: context.get_id(),
|
||||
parent_scope: Cell::new(Some(import_scope)),
|
||||
circuit_self: Cell::new(None),
|
||||
variables: RefCell::new(IndexMap::new()),
|
||||
functions: RefCell::new(IndexMap::new()),
|
||||
circuits: RefCell::new(IndexMap::new()),
|
||||
function: Cell::new(None),
|
||||
});
|
||||
|
||||
// Prepare header-like scope entries.
|
||||
let mut proto_circuits = IndexMap::new();
|
||||
for (name, circuit) in program.circuits.iter() {
|
||||
assert_eq!(name.name, circuit.circuit_name.name);
|
||||
let asg_circuit = Circuit::init(circuit);
|
||||
let asg_circuit = Circuit::init(scope, circuit)?;
|
||||
|
||||
proto_circuits.insert(name.name.clone(), asg_circuit);
|
||||
}
|
||||
|
||||
let scope = Arc::new(RefCell::new(InnerScope {
|
||||
input: Some(Input::new(&import_scope)), // we use import_scope to avoid recursive scope ref here
|
||||
id: uuid::Uuid::new_v4(),
|
||||
parent_scope: Some(import_scope),
|
||||
circuit_self: None,
|
||||
variables: IndexMap::new(),
|
||||
functions: IndexMap::new(),
|
||||
circuits: proto_circuits
|
||||
.iter()
|
||||
.map(|(name, circuit)| (name.clone(), circuit.clone()))
|
||||
.collect(),
|
||||
function: None,
|
||||
}));
|
||||
|
||||
for (name, circuit) in program.circuits.iter() {
|
||||
assert_eq!(name.name, circuit.circuit_name.name);
|
||||
let asg_circuit = proto_circuits.get(&name.name).unwrap();
|
||||
|
||||
asg_circuit.clone().from_ast(&scope, &circuit)?;
|
||||
scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit);
|
||||
}
|
||||
|
||||
let mut proto_test_functions = IndexMap::new();
|
||||
for (name, test_function) in program.tests.iter() {
|
||||
assert_eq!(name.name, test_function.function.identifier.name);
|
||||
let function = Arc::new(Function::from_ast(&scope, &test_function.function)?);
|
||||
let function = Function::init(scope, &test_function.function)?;
|
||||
|
||||
proto_test_functions.insert(name.name.clone(), function);
|
||||
}
|
||||
|
||||
let mut proto_functions = IndexMap::new();
|
||||
for (name, function) in program.functions.iter() {
|
||||
assert_eq!(name.name, function.identifier.name);
|
||||
let asg_function = Arc::new(Function::from_ast(&scope, function)?);
|
||||
let function = Function::init(scope, function)?;
|
||||
|
||||
scope
|
||||
.borrow_mut()
|
||||
.functions
|
||||
.insert(name.name.clone(), asg_function.clone());
|
||||
proto_functions.insert(name.name.clone(), asg_function);
|
||||
scope.functions.borrow_mut().insert(name.name.clone(), function);
|
||||
}
|
||||
|
||||
// Load concrete definitions.
|
||||
@ -281,39 +269,34 @@ impl InternalProgram {
|
||||
assert_eq!(name.name, test_function.function.identifier.name);
|
||||
let function = proto_test_functions.get(&name.name).unwrap();
|
||||
|
||||
let body = Arc::new(FunctionBody::from_ast(
|
||||
&scope,
|
||||
&test_function.function,
|
||||
function.clone(),
|
||||
)?);
|
||||
function.body.replace(Arc::downgrade(&body));
|
||||
function.fill_from_ast(&test_function.function)?;
|
||||
|
||||
test_functions.insert(name.name.clone(), (body, test_function.input_file.clone()));
|
||||
test_functions.insert(name.name.clone(), (*function, test_function.input_file.clone()));
|
||||
}
|
||||
|
||||
let mut functions = IndexMap::new();
|
||||
for (name, function) in program.functions.iter() {
|
||||
assert_eq!(name.name, function.identifier.name);
|
||||
let asg_function = proto_functions.get(&name.name).unwrap();
|
||||
let asg_function = *scope.functions.borrow().get(&name.name).unwrap();
|
||||
|
||||
let body = Arc::new(FunctionBody::from_ast(&scope, function, asg_function.clone())?);
|
||||
asg_function.body.replace(Arc::downgrade(&body));
|
||||
asg_function.fill_from_ast(function)?;
|
||||
|
||||
functions.insert(name.name.clone(), body);
|
||||
functions.insert(name.name.clone(), 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 = proto_circuits.get(&name.name).unwrap();
|
||||
let body = Arc::new(CircuitBody::from_ast(&scope, circuit, asg_circuit.clone())?);
|
||||
asg_circuit.body.replace(Arc::downgrade(&body));
|
||||
let asg_circuit = *scope.circuits.borrow().get(&name.name).unwrap();
|
||||
|
||||
circuits.insert(name.name.clone(), body);
|
||||
asg_circuit.fill_from_ast(circuit)?;
|
||||
|
||||
circuits.insert(name.name.clone(), asg_circuit);
|
||||
}
|
||||
|
||||
Ok(Arc::new(RefCell::new(InternalProgram {
|
||||
id: Uuid::new_v4(),
|
||||
Ok(InternalProgram {
|
||||
context,
|
||||
id: context.get_id(),
|
||||
name: program.name.clone(),
|
||||
test_functions,
|
||||
functions,
|
||||
@ -323,12 +306,12 @@ impl InternalProgram {
|
||||
.map(|(package, program)| (package.join("."), program))
|
||||
.collect(),
|
||||
scope,
|
||||
})))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_core_mapping(&self, mapping: &str) {
|
||||
for (_, circuit) in self.circuits.iter() {
|
||||
circuit.circuit.core_mapping.replace(Some(mapping.to_string()));
|
||||
circuit.core_mapping.replace(Some(mapping.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,15 +330,15 @@ impl Iterator for InternalIdentifierGenerator {
|
||||
}
|
||||
}
|
||||
/// Returns an AST from the given ASG program.
|
||||
pub fn reform_ast(program: &Program) -> leo_ast::Program {
|
||||
pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
|
||||
let mut all_programs: IndexMap<String, Program> = IndexMap::new();
|
||||
let mut program_stack = program.borrow().imported_modules.clone();
|
||||
let mut program_stack = program.imported_modules.clone();
|
||||
while let Some((module, program)) = program_stack.pop() {
|
||||
if all_programs.contains_key(&module) {
|
||||
continue;
|
||||
}
|
||||
all_programs.insert(module, program.clone());
|
||||
program_stack.extend(program.borrow().imported_modules.clone());
|
||||
program_stack.extend(program.imported_modules.clone());
|
||||
}
|
||||
all_programs.insert("".to_string(), program.clone());
|
||||
let core_programs: Vec<_> = all_programs
|
||||
@ -365,16 +348,15 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program {
|
||||
.collect();
|
||||
all_programs.retain(|module, _| !module.starts_with("core."));
|
||||
|
||||
let mut all_circuits: IndexMap<String, Arc<CircuitBody>> = IndexMap::new();
|
||||
let mut all_functions: IndexMap<String, Arc<FunctionBody>> = IndexMap::new();
|
||||
let mut all_test_functions: IndexMap<String, (Arc<FunctionBody>, Option<Identifier>)> = IndexMap::new();
|
||||
let mut all_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
|
||||
let mut all_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
|
||||
let mut all_test_functions: IndexMap<String, (&'a Function<'a>, Option<Identifier>)> = IndexMap::new();
|
||||
let mut identifiers = InternalIdentifierGenerator { next: 0 };
|
||||
for (_, program) in all_programs.into_iter() {
|
||||
let program = program.borrow();
|
||||
for (name, circuit) in program.circuits.iter() {
|
||||
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
|
||||
circuit.circuit.name.borrow_mut().name = identifier.clone();
|
||||
all_circuits.insert(identifier, circuit.clone());
|
||||
circuit.name.borrow_mut().name = identifier.clone();
|
||||
all_circuits.insert(identifier, *circuit);
|
||||
}
|
||||
for (name, function) in program.functions.iter() {
|
||||
let identifier = if name == "main" {
|
||||
@ -382,12 +364,12 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program {
|
||||
} else {
|
||||
format!("{}{}", identifiers.next().unwrap(), name)
|
||||
};
|
||||
function.function.name.borrow_mut().name = identifier.clone();
|
||||
all_functions.insert(identifier, function.clone());
|
||||
function.name.borrow_mut().name = identifier.clone();
|
||||
all_functions.insert(identifier, *function);
|
||||
}
|
||||
for (name, function) in program.test_functions.iter() {
|
||||
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
|
||||
function.0.function.name.borrow_mut().name = identifier.clone();
|
||||
function.0.name.borrow_mut().name = identifier.clone();
|
||||
all_test_functions.insert(identifier, function.clone());
|
||||
}
|
||||
}
|
||||
@ -409,29 +391,24 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program {
|
||||
tests: all_test_functions
|
||||
.into_iter()
|
||||
.map(|(_, (function, ident))| {
|
||||
(function.function.name.borrow().clone(), leo_ast::TestFunction {
|
||||
function: function.function.as_ref().into(),
|
||||
(function.name.borrow().clone(), leo_ast::TestFunction {
|
||||
function: function.into(),
|
||||
input_file: ident,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
functions: all_functions
|
||||
.into_iter()
|
||||
.map(|(_, function)| {
|
||||
(
|
||||
function.function.name.borrow().clone(),
|
||||
function.function.as_ref().into(),
|
||||
)
|
||||
})
|
||||
.map(|(_, function)| (function.name.borrow().clone(), function.into()))
|
||||
.collect(),
|
||||
circuits: all_circuits
|
||||
.into_iter()
|
||||
.map(|(_, circuit)| (circuit.circuit.name.borrow().clone(), circuit.circuit.as_ref().into()))
|
||||
.map(|(_, circuit)| (circuit.name.borrow().clone(), circuit.into()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Program> for &InternalProgram {
|
||||
impl<'a> Into<leo_ast::Program> for &InternalProgram<'a> {
|
||||
fn into(self) -> leo_ast::Program {
|
||||
leo_ast::Program {
|
||||
name: self.name.clone(),
|
||||
@ -440,24 +417,19 @@ impl Into<leo_ast::Program> for &InternalProgram {
|
||||
circuits: self
|
||||
.circuits
|
||||
.iter()
|
||||
.map(|(_, circuit)| (circuit.circuit.name.borrow().clone(), circuit.circuit.as_ref().into()))
|
||||
.map(|(_, circuit)| (circuit.name.borrow().clone(), (*circuit).into()))
|
||||
.collect(),
|
||||
functions: self
|
||||
.functions
|
||||
.iter()
|
||||
.map(|(_, function)| {
|
||||
(
|
||||
function.function.name.borrow().clone(),
|
||||
function.function.as_ref().into(),
|
||||
)
|
||||
})
|
||||
.map(|(_, function)| (function.name.borrow().clone(), (*function).into()))
|
||||
.collect(),
|
||||
tests: self
|
||||
.test_functions
|
||||
.iter()
|
||||
.map(|(_, function)| {
|
||||
(function.0.function.name.borrow().clone(), leo_ast::TestFunction {
|
||||
function: function.0.function.as_ref().into(),
|
||||
(function.0.name.borrow().clone(), leo_ast::TestFunction {
|
||||
function: function.0.into(),
|
||||
input_file: function.1.clone(),
|
||||
})
|
||||
})
|
||||
|
@ -25,3 +25,9 @@ pub use monoidal_director::*;
|
||||
|
||||
mod monoidal_reducer;
|
||||
pub use monoidal_reducer::*;
|
||||
|
||||
mod visitor;
|
||||
pub use visitor::*;
|
||||
|
||||
mod visitor_director;
|
||||
pub use visitor_director::*;
|
||||
|
@ -17,14 +17,14 @@
|
||||
use super::*;
|
||||
use crate::{expression::*, program::*, statement::*};
|
||||
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct MonoidalDirector<T: Monoid, R: MonoidalReducerExpression<T>> {
|
||||
pub struct MonoidalDirector<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> {
|
||||
reducer: R,
|
||||
_monoid: PhantomData<T>,
|
||||
_monoid: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<T: Monoid, R: MonoidalReducerExpression<T>> MonoidalDirector<T, R> {
|
||||
impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T, R> {
|
||||
pub fn new(reducer: R) -> Self {
|
||||
Self {
|
||||
reducer,
|
||||
@ -36,8 +36,8 @@ impl<T: Monoid, R: MonoidalReducerExpression<T>> MonoidalDirector<T, R> {
|
||||
self.reducer
|
||||
}
|
||||
|
||||
pub fn reduce_expression(&mut self, input: &Arc<Expression>) -> T {
|
||||
match &**input {
|
||||
pub fn reduce_expression(&mut self, input: &'a Expression<'a>) -> T {
|
||||
let value = match input {
|
||||
Expression::ArrayAccess(e) => self.reduce_array_access(e),
|
||||
Expression::ArrayInit(e) => self.reduce_array_init(e),
|
||||
Expression::ArrayInline(e) => self.reduce_array_inline(e),
|
||||
@ -52,101 +52,115 @@ impl<T: Monoid, R: MonoidalReducerExpression<T>> MonoidalDirector<T, R> {
|
||||
Expression::TupleInit(e) => self.reduce_tuple_init(e),
|
||||
Expression::Unary(e) => self.reduce_unary(e),
|
||||
Expression::VariableRef(e) => self.reduce_variable_ref(e),
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer.reduce_expression(input, value)
|
||||
}
|
||||
|
||||
pub fn reduce_array_access(&mut self, input: &ArrayAccessExpression) -> T {
|
||||
let array = self.reduce_expression(&input.array);
|
||||
let index = self.reduce_expression(&input.index);
|
||||
pub fn reduce_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> T {
|
||||
let array = self.reduce_expression(input.array.get());
|
||||
let index = self.reduce_expression(input.index.get());
|
||||
|
||||
self.reducer.reduce_array_access(input, array, index)
|
||||
}
|
||||
|
||||
pub fn reduce_array_init(&mut self, input: &ArrayInitExpression) -> T {
|
||||
let element = self.reduce_expression(&input.element);
|
||||
pub fn reduce_array_init(&mut self, input: &ArrayInitExpression<'a>) -> T {
|
||||
let element = self.reduce_expression(input.element.get());
|
||||
|
||||
self.reducer.reduce_array_init(input, element)
|
||||
}
|
||||
|
||||
pub fn reduce_array_inline(&mut self, input: &ArrayInlineExpression) -> T {
|
||||
let elements = input.elements.iter().map(|(x, _)| self.reduce_expression(x)).collect();
|
||||
pub fn reduce_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> T {
|
||||
let elements = input
|
||||
.elements
|
||||
.iter()
|
||||
.map(|(x, _)| self.reduce_expression(x.get()))
|
||||
.collect();
|
||||
|
||||
self.reducer.reduce_array_inline(input, elements)
|
||||
}
|
||||
|
||||
pub fn reduce_array_range_access(&mut self, input: &ArrayRangeAccessExpression) -> T {
|
||||
let array = self.reduce_expression(&input.array);
|
||||
let left = input.left.as_ref().map(|e| self.reduce_expression(e));
|
||||
let right = input.right.as_ref().map(|e| self.reduce_expression(e));
|
||||
pub fn reduce_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> T {
|
||||
let array = self.reduce_expression(input.array.get());
|
||||
let left = input.left.get().map(|e| self.reduce_expression(e));
|
||||
let right = input.right.get().map(|e| self.reduce_expression(e));
|
||||
|
||||
self.reducer.reduce_array_range_access(input, array, left, right)
|
||||
}
|
||||
|
||||
pub fn reduce_binary(&mut self, input: &BinaryExpression) -> T {
|
||||
let left = self.reduce_expression(&input.left);
|
||||
let right = self.reduce_expression(&input.right);
|
||||
pub fn reduce_binary(&mut self, input: &BinaryExpression<'a>) -> T {
|
||||
let left = self.reduce_expression(input.left.get());
|
||||
let right = self.reduce_expression(input.right.get());
|
||||
|
||||
self.reducer.reduce_binary(input, left, right)
|
||||
}
|
||||
|
||||
pub fn reduce_call(&mut self, input: &CallExpression) -> T {
|
||||
let target = input.target.as_ref().map(|e| self.reduce_expression(e));
|
||||
let arguments = input.arguments.iter().map(|e| self.reduce_expression(e)).collect();
|
||||
pub fn reduce_call(&mut self, input: &CallExpression<'a>) -> T {
|
||||
let target = input.target.get().map(|e| self.reduce_expression(e));
|
||||
let arguments = input
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|e| self.reduce_expression(e.get()))
|
||||
.collect();
|
||||
|
||||
self.reducer.reduce_call(input, target, arguments)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression) -> T {
|
||||
let target = input.target.as_ref().map(|e| self.reduce_expression(e));
|
||||
pub fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> T {
|
||||
let target = input.target.get().map(|e| self.reduce_expression(e));
|
||||
|
||||
self.reducer.reduce_circuit_access(input, target)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_init(&mut self, input: &CircuitInitExpression) -> T {
|
||||
let values = input.values.iter().map(|(_, e)| self.reduce_expression(e)).collect();
|
||||
pub fn reduce_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> T {
|
||||
let values = input
|
||||
.values
|
||||
.iter()
|
||||
.map(|(_, e)| self.reduce_expression(e.get()))
|
||||
.collect();
|
||||
|
||||
self.reducer.reduce_circuit_init(input, values)
|
||||
}
|
||||
|
||||
pub fn reduce_ternary_expression(&mut self, input: &TernaryExpression) -> T {
|
||||
let condition = self.reduce_expression(&input.condition);
|
||||
let if_true = self.reduce_expression(&input.if_true);
|
||||
let if_false = self.reduce_expression(&input.if_false);
|
||||
pub fn reduce_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> T {
|
||||
let condition = self.reduce_expression(input.condition.get());
|
||||
let if_true = self.reduce_expression(input.if_true.get());
|
||||
let if_false = self.reduce_expression(input.if_false.get());
|
||||
|
||||
self.reducer
|
||||
.reduce_ternary_expression(input, condition, if_true, if_false)
|
||||
}
|
||||
|
||||
pub fn reduce_constant(&mut self, input: &Constant) -> T {
|
||||
pub fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
|
||||
self.reducer.reduce_constant(input)
|
||||
}
|
||||
|
||||
pub fn reduce_tuple_access(&mut self, input: &TupleAccessExpression) -> T {
|
||||
let tuple_ref = self.reduce_expression(&input.tuple_ref);
|
||||
pub fn reduce_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> T {
|
||||
let tuple_ref = self.reduce_expression(input.tuple_ref.get());
|
||||
|
||||
self.reducer.reduce_tuple_access(input, tuple_ref)
|
||||
}
|
||||
|
||||
pub fn reduce_tuple_init(&mut self, input: &TupleInitExpression) -> T {
|
||||
let values = input.elements.iter().map(|e| self.reduce_expression(e)).collect();
|
||||
pub fn reduce_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> T {
|
||||
let values = input.elements.iter().map(|e| self.reduce_expression(e.get())).collect();
|
||||
|
||||
self.reducer.reduce_tuple_init(input, values)
|
||||
}
|
||||
|
||||
pub fn reduce_unary(&mut self, input: &UnaryExpression) -> T {
|
||||
let inner = self.reduce_expression(&input.inner);
|
||||
pub fn reduce_unary(&mut self, input: &UnaryExpression<'a>) -> T {
|
||||
let inner = self.reduce_expression(input.inner.get());
|
||||
|
||||
self.reducer.reduce_unary(input, inner)
|
||||
}
|
||||
|
||||
pub fn reduce_variable_ref(&mut self, input: &VariableRef) -> T {
|
||||
pub fn reduce_variable_ref(&mut self, input: &VariableRef<'a>) -> T {
|
||||
self.reducer.reduce_variable_ref(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Monoid, R: MonoidalReducerStatement<T>> MonoidalDirector<T, R> {
|
||||
pub fn reduce_statement(&mut self, input: &Arc<Statement>) -> T {
|
||||
match &**input {
|
||||
impl<'a, T: Monoid, R: MonoidalReducerStatement<'a, T>> MonoidalDirector<'a, T, R> {
|
||||
pub fn reduce_statement(&mut self, input: &'a Statement<'a>) -> T {
|
||||
let value = match input {
|
||||
Statement::Assign(s) => self.reduce_assign(s),
|
||||
Statement::Block(s) => self.reduce_block(s),
|
||||
Statement::Conditional(s) => self.reduce_conditional_statement(s),
|
||||
@ -155,57 +169,67 @@ impl<T: Monoid, R: MonoidalReducerStatement<T>> MonoidalDirector<T, R> {
|
||||
Statement::Expression(s) => self.reduce_expression_statement(s),
|
||||
Statement::Iteration(s) => self.reduce_iteration(s),
|
||||
Statement::Return(s) => self.reduce_return(s),
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer.reduce_statement(input, value)
|
||||
}
|
||||
|
||||
pub fn reduce_assign_access(&mut self, input: &AssignAccess) -> T {
|
||||
pub fn reduce_assign_access(&mut self, input: &AssignAccess<'a>) -> T {
|
||||
let (left, right) = match input {
|
||||
AssignAccess::ArrayRange(left, right) => (
|
||||
left.as_ref().map(|e| self.reduce_expression(e)),
|
||||
right.as_ref().map(|e| self.reduce_expression(e)),
|
||||
left.get().map(|e| self.reduce_expression(e)),
|
||||
right.get().map(|e| self.reduce_expression(e)),
|
||||
),
|
||||
AssignAccess::ArrayIndex(index) => (Some(self.reduce_expression(index)), None),
|
||||
AssignAccess::ArrayIndex(index) => (Some(self.reduce_expression(index.get())), None),
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
self.reducer.reduce_assign_access(input, left, right)
|
||||
}
|
||||
|
||||
pub fn reduce_assign(&mut self, input: &AssignStatement) -> T {
|
||||
pub fn reduce_assign(&mut self, input: &AssignStatement<'a>) -> T {
|
||||
let accesses = input
|
||||
.target_accesses
|
||||
.iter()
|
||||
.map(|x| self.reduce_assign_access(x))
|
||||
.collect();
|
||||
let value = self.reduce_expression(&input.value);
|
||||
let value = self.reduce_expression(input.value.get());
|
||||
|
||||
self.reducer.reduce_assign(input, accesses, value)
|
||||
}
|
||||
|
||||
pub fn reduce_block(&mut self, input: &BlockStatement) -> T {
|
||||
let statements = input.statements.iter().map(|x| self.reduce_statement(x)).collect();
|
||||
pub fn reduce_block(&mut self, input: &BlockStatement<'a>) -> T {
|
||||
let statements = input
|
||||
.statements
|
||||
.iter()
|
||||
.map(|x| self.reduce_statement(x.get()))
|
||||
.collect();
|
||||
|
||||
self.reducer.reduce_block(input, statements)
|
||||
}
|
||||
|
||||
pub fn reduce_conditional_statement(&mut self, input: &ConditionalStatement) -> T {
|
||||
let condition = self.reduce_expression(&input.condition);
|
||||
let if_true = self.reduce_statement(&input.result);
|
||||
let if_false = input.next.as_ref().map(|s| self.reduce_statement(s));
|
||||
pub fn reduce_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> T {
|
||||
let condition = self.reduce_expression(input.condition.get());
|
||||
let if_true = self.reduce_statement(input.result.get());
|
||||
let if_false = input.next.get().map(|s| self.reduce_statement(s));
|
||||
|
||||
self.reducer
|
||||
.reduce_conditional_statement(input, condition, if_true, if_false)
|
||||
}
|
||||
|
||||
pub fn reduce_formatted_string(&mut self, input: &FormattedString) -> T {
|
||||
let parameters = input.parameters.iter().map(|e| self.reduce_expression(e)).collect();
|
||||
pub fn reduce_formatted_string(&mut self, input: &FormattedString<'a>) -> T {
|
||||
let parameters = input
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|e| self.reduce_expression(e.get()))
|
||||
.collect();
|
||||
|
||||
self.reducer.reduce_formatted_string(input, parameters)
|
||||
}
|
||||
|
||||
pub fn reduce_console(&mut self, input: &ConsoleStatement) -> T {
|
||||
pub fn reduce_console(&mut self, input: &ConsoleStatement<'a>) -> T {
|
||||
let argument = match &input.function {
|
||||
ConsoleFunction::Assert(e) => self.reduce_expression(e),
|
||||
ConsoleFunction::Assert(e) => self.reduce_expression(e.get()),
|
||||
ConsoleFunction::Debug(f) | ConsoleFunction::Error(f) | ConsoleFunction::Log(f) => {
|
||||
self.reduce_formatted_string(f)
|
||||
}
|
||||
@ -214,51 +238,51 @@ impl<T: Monoid, R: MonoidalReducerStatement<T>> MonoidalDirector<T, R> {
|
||||
self.reducer.reduce_console(input, argument)
|
||||
}
|
||||
|
||||
pub fn reduce_definition(&mut self, input: &DefinitionStatement) -> T {
|
||||
let value = self.reduce_expression(&input.value);
|
||||
pub fn reduce_definition(&mut self, input: &DefinitionStatement<'a>) -> T {
|
||||
let value = self.reduce_expression(input.value.get());
|
||||
|
||||
self.reducer.reduce_definition(input, value)
|
||||
}
|
||||
|
||||
pub fn reduce_expression_statement(&mut self, input: &ExpressionStatement) -> T {
|
||||
let value = self.reduce_expression(&input.expression);
|
||||
pub fn reduce_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> T {
|
||||
let value = self.reduce_expression(input.expression.get());
|
||||
|
||||
self.reducer.reduce_expression_statement(input, value)
|
||||
}
|
||||
|
||||
pub fn reduce_iteration(&mut self, input: &IterationStatement) -> T {
|
||||
let start = self.reduce_expression(&input.start);
|
||||
let stop = self.reduce_expression(&input.stop);
|
||||
let body = self.reduce_statement(&input.body);
|
||||
pub fn reduce_iteration(&mut self, input: &IterationStatement<'a>) -> T {
|
||||
let start = self.reduce_expression(input.start.get());
|
||||
let stop = self.reduce_expression(input.stop.get());
|
||||
let body = self.reduce_statement(input.body.get());
|
||||
|
||||
self.reducer.reduce_iteration(input, start, stop, body)
|
||||
}
|
||||
|
||||
pub fn reduce_return(&mut self, input: &ReturnStatement) -> T {
|
||||
let value = self.reduce_expression(&input.expression);
|
||||
pub fn reduce_return(&mut self, input: &ReturnStatement<'a>) -> T {
|
||||
let value = self.reduce_expression(input.expression.get());
|
||||
|
||||
self.reducer.reduce_return(input, value)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T: Monoid, R: MonoidalReducerProgram<T>> MonoidalDirector<T, R> {
|
||||
fn reduce_function(&mut self, input: &Arc<FunctionBody>) -> T {
|
||||
let body = self.reduce_statement(&input.body);
|
||||
impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R> {
|
||||
fn reduce_function(&mut self, input: &'a Function<'a>) -> T {
|
||||
let body = input.body.get().map(|s| self.reduce_statement(s)).unwrap_or_default();
|
||||
|
||||
self.reducer.reduce_function(input, body)
|
||||
}
|
||||
|
||||
fn reduce_circuit_member(&mut self, input: &CircuitMemberBody) -> T {
|
||||
fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>) -> T {
|
||||
let function = match input {
|
||||
CircuitMemberBody::Function(f) => Some(self.reduce_function(f)),
|
||||
CircuitMember::Function(f) => Some(self.reduce_function(f)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
self.reducer.reduce_circuit_member(input, function)
|
||||
}
|
||||
|
||||
fn reduce_circuit(&mut self, input: &Arc<CircuitBody>) -> T {
|
||||
fn reduce_circuit(&mut self, input: &'a Circuit<'a>) -> T {
|
||||
let members = input
|
||||
.members
|
||||
.borrow()
|
||||
@ -269,8 +293,7 @@ impl<T: Monoid, R: MonoidalReducerProgram<T>> MonoidalDirector<T, R> {
|
||||
self.reducer.reduce_circuit(input, members)
|
||||
}
|
||||
|
||||
fn reduce_program(&mut self, input: &Program) -> T {
|
||||
let input = input.borrow();
|
||||
fn reduce_program(&mut self, input: &Program<'a>) -> T {
|
||||
let imported_modules = input
|
||||
.imported_modules
|
||||
.iter()
|
||||
|
@ -16,29 +16,27 @@
|
||||
|
||||
use crate::{expression::*, program::*, statement::*, Monoid};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait MonoidalReducerExpression<T: Monoid> {
|
||||
fn reduce_expression(&mut self, input: &Arc<Expression>, value: T) -> T {
|
||||
pub trait MonoidalReducerExpression<'a, T: Monoid> {
|
||||
fn reduce_expression(&mut self, input: &'a Expression<'a>, value: T) -> T {
|
||||
value
|
||||
}
|
||||
|
||||
fn reduce_array_access(&mut self, input: &ArrayAccessExpression, array: T, index: T) -> T {
|
||||
fn reduce_array_access(&mut self, input: &ArrayAccessExpression<'a>, array: T, index: T) -> T {
|
||||
array.append(index)
|
||||
}
|
||||
|
||||
fn reduce_array_init(&mut self, input: &ArrayInitExpression, element: T) -> T {
|
||||
fn reduce_array_init(&mut self, input: &ArrayInitExpression<'a>, element: T) -> T {
|
||||
element
|
||||
}
|
||||
|
||||
fn reduce_array_inline(&mut self, input: &ArrayInlineExpression, elements: Vec<T>) -> T {
|
||||
fn reduce_array_inline(&mut self, input: &ArrayInlineExpression<'a>, elements: Vec<T>) -> T {
|
||||
T::default().append_all(elements.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_array_range_access(
|
||||
&mut self,
|
||||
input: &ArrayRangeAccessExpression,
|
||||
input: &ArrayRangeAccessExpression<'a>,
|
||||
array: T,
|
||||
left: Option<T>,
|
||||
right: Option<T>,
|
||||
@ -46,69 +44,69 @@ pub trait MonoidalReducerExpression<T: Monoid> {
|
||||
array.append_option(left).append_option(right)
|
||||
}
|
||||
|
||||
fn reduce_binary(&mut self, input: &BinaryExpression, left: T, right: T) -> T {
|
||||
fn reduce_binary(&mut self, input: &BinaryExpression<'a>, left: T, right: T) -> T {
|
||||
left.append(right)
|
||||
}
|
||||
|
||||
fn reduce_call(&mut self, input: &CallExpression, target: Option<T>, arguments: Vec<T>) -> T {
|
||||
fn reduce_call(&mut self, input: &CallExpression<'a>, target: Option<T>, arguments: Vec<T>) -> T {
|
||||
target.unwrap_or_default().append_all(arguments.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression, target: Option<T>) -> T {
|
||||
fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression<'a>, target: Option<T>) -> T {
|
||||
target.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn reduce_circuit_init(&mut self, input: &CircuitInitExpression, values: Vec<T>) -> T {
|
||||
fn reduce_circuit_init(&mut self, input: &CircuitInitExpression<'a>, values: Vec<T>) -> T {
|
||||
T::default().append_all(values.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_ternary_expression(&mut self, input: &TernaryExpression, condition: T, if_true: T, if_false: T) -> T {
|
||||
fn reduce_ternary_expression(&mut self, input: &TernaryExpression<'a>, condition: T, if_true: T, if_false: T) -> T {
|
||||
condition.append(if_true).append(if_false)
|
||||
}
|
||||
|
||||
fn reduce_constant(&mut self, input: &Constant) -> T {
|
||||
fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
|
||||
T::default()
|
||||
}
|
||||
|
||||
fn reduce_tuple_access(&mut self, input: &TupleAccessExpression, tuple_ref: T) -> T {
|
||||
fn reduce_tuple_access(&mut self, input: &TupleAccessExpression<'a>, tuple_ref: T) -> T {
|
||||
tuple_ref
|
||||
}
|
||||
|
||||
fn reduce_tuple_init(&mut self, input: &TupleInitExpression, values: Vec<T>) -> T {
|
||||
fn reduce_tuple_init(&mut self, input: &TupleInitExpression<'a>, values: Vec<T>) -> T {
|
||||
T::default().append_all(values.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_unary(&mut self, input: &UnaryExpression, inner: T) -> T {
|
||||
fn reduce_unary(&mut self, input: &UnaryExpression<'a>, inner: T) -> T {
|
||||
inner
|
||||
}
|
||||
|
||||
fn reduce_variable_ref(&mut self, input: &VariableRef) -> T {
|
||||
fn reduce_variable_ref(&mut self, input: &VariableRef<'a>) -> T {
|
||||
T::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait MonoidalReducerStatement<T: Monoid>: MonoidalReducerExpression<T> {
|
||||
fn reduce_statement(&mut self, input: &Arc<Statement>, value: T) -> T {
|
||||
pub trait MonoidalReducerStatement<'a, T: Monoid>: MonoidalReducerExpression<'a, T> {
|
||||
fn reduce_statement(&mut self, input: &'a Statement<'a>, value: T) -> T {
|
||||
value
|
||||
}
|
||||
|
||||
// left = Some(ArrayIndex.0) always if AssignAccess::ArrayIndex. if member/tuple, always None
|
||||
fn reduce_assign_access(&mut self, input: &AssignAccess, left: Option<T>, right: Option<T>) -> T {
|
||||
fn reduce_assign_access(&mut self, input: &AssignAccess<'a>, left: Option<T>, right: Option<T>) -> T {
|
||||
left.unwrap_or_default().append_option(right)
|
||||
}
|
||||
|
||||
fn reduce_assign(&mut self, input: &AssignStatement, accesses: Vec<T>, value: T) -> T {
|
||||
fn reduce_assign(&mut self, input: &AssignStatement<'a>, accesses: Vec<T>, value: T) -> T {
|
||||
T::default().append_all(accesses.into_iter()).append(value)
|
||||
}
|
||||
|
||||
fn reduce_block(&mut self, input: &BlockStatement, statements: Vec<T>) -> T {
|
||||
fn reduce_block(&mut self, input: &BlockStatement<'a>, statements: Vec<T>) -> T {
|
||||
T::default().append_all(statements.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_conditional_statement(
|
||||
&mut self,
|
||||
input: &ConditionalStatement,
|
||||
input: &ConditionalStatement<'a>,
|
||||
condition: T,
|
||||
if_true: T,
|
||||
if_false: Option<T>,
|
||||
@ -116,42 +114,42 @@ pub trait MonoidalReducerStatement<T: Monoid>: MonoidalReducerExpression<T> {
|
||||
condition.append(if_true).append_option(if_false)
|
||||
}
|
||||
|
||||
fn reduce_formatted_string(&mut self, input: &FormattedString, parameters: Vec<T>) -> T {
|
||||
fn reduce_formatted_string(&mut self, input: &FormattedString<'a>, parameters: Vec<T>) -> T {
|
||||
T::default().append_all(parameters.into_iter())
|
||||
}
|
||||
|
||||
fn reduce_console(&mut self, input: &ConsoleStatement, argument: T) -> T {
|
||||
fn reduce_console(&mut self, input: &ConsoleStatement<'a>, argument: T) -> T {
|
||||
argument
|
||||
}
|
||||
|
||||
fn reduce_definition(&mut self, input: &DefinitionStatement, value: T) -> T {
|
||||
fn reduce_definition(&mut self, input: &DefinitionStatement<'a>, value: T) -> T {
|
||||
value
|
||||
}
|
||||
|
||||
fn reduce_expression_statement(&mut self, input: &ExpressionStatement, expression: T) -> T {
|
||||
fn reduce_expression_statement(&mut self, input: &ExpressionStatement<'a>, expression: T) -> T {
|
||||
expression
|
||||
}
|
||||
|
||||
fn reduce_iteration(&mut self, input: &IterationStatement, start: T, stop: T, body: T) -> T {
|
||||
fn reduce_iteration(&mut self, input: &IterationStatement<'a>, start: T, stop: T, body: T) -> T {
|
||||
start.append(stop).append(body)
|
||||
}
|
||||
|
||||
fn reduce_return(&mut self, input: &ReturnStatement, value: T) -> T {
|
||||
fn reduce_return(&mut self, input: &ReturnStatement<'a>, value: T) -> T {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait MonoidalReducerProgram<T: Monoid>: MonoidalReducerStatement<T> {
|
||||
fn reduce_function(&mut self, input: &Arc<FunctionBody>, body: T) -> T {
|
||||
pub trait MonoidalReducerProgram<'a, T: Monoid>: MonoidalReducerStatement<'a, T> {
|
||||
fn reduce_function(&mut self, input: &'a Function<'a>, body: T) -> T {
|
||||
body
|
||||
}
|
||||
|
||||
fn reduce_circuit_member(&mut self, input: &CircuitMemberBody, function: Option<T>) -> T {
|
||||
fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>, function: Option<T>) -> T {
|
||||
function.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn reduce_circuit(&mut self, input: &Arc<CircuitBody>, members: Vec<T>) -> T {
|
||||
fn reduce_circuit(&mut self, input: &'a Circuit<'a>, members: Vec<T>) -> T {
|
||||
T::default().append_all(members.into_iter())
|
||||
}
|
||||
|
||||
|
161
asg/src/reducer/visitor.rs
Normal file
161
asg/src/reducer/visitor.rs
Normal file
@ -0,0 +1,161 @@
|
||||
// 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 std::cell::Cell;
|
||||
|
||||
use crate::{expression::*, program::*, statement::*};
|
||||
|
||||
pub enum VisitResult {
|
||||
VisitChildren,
|
||||
SkipChildren,
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl Default for VisitResult {
|
||||
fn default() -> Self {
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait ExpressionVisitor<'a> {
|
||||
fn visit_expression(&mut self, input: &Cell<&'a Expression<'a>>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_array_init(&mut self, input: &ArrayInitExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_binary(&mut self, input: &BinaryExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, input: &CallExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, input: &Constant<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, input: &UnaryExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_variable_ref(&mut self, input: &VariableRef<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
|
||||
fn visit_statement(&mut self, input: &Cell<&'a Statement<'a>>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
// left = Some(ArrayIndex.0) always if AssignAccess::ArrayIndex. if member/tuple, always None
|
||||
fn visit_assign_access(&mut self, input: &AssignAccess<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, input: &AssignStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, input: &BlockStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_formatted_string(&mut self, input: &FormattedString<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_console(&mut self, input: &ConsoleStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_definition(&mut self, input: &DefinitionStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_iteration(&mut self, input: &IterationStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_return(&mut self, input: &ReturnStatement<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_circuit_member(&mut self, input: &CircuitMember<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_program(&mut self, input: &Program<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
}
|
442
asg/src/reducer/visitor_director.rs
Normal file
442
asg/src/reducer/visitor_director.rs
Normal file
@ -0,0 +1,442 @@
|
||||
// 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 super::*;
|
||||
use crate::{expression::*, program::*, statement::*};
|
||||
|
||||
use std::{cell::Cell, marker::PhantomData};
|
||||
|
||||
pub struct VisitorDirector<'a, R: ExpressionVisitor<'a>> {
|
||||
visitor: R,
|
||||
lifetime: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
pub type ConcreteVisitResult = Result<(), ()>;
|
||||
|
||||
impl Into<ConcreteVisitResult> for VisitResult {
|
||||
fn into(self) -> ConcreteVisitResult {
|
||||
match self {
|
||||
VisitResult::VisitChildren => Ok(()),
|
||||
VisitResult::SkipChildren => Ok(()),
|
||||
VisitResult::Exit => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
|
||||
pub fn new(visitor: R) -> Self {
|
||||
Self {
|
||||
visitor,
|
||||
lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visitor(self) -> R {
|
||||
self.visitor
|
||||
}
|
||||
|
||||
pub fn visit_expression(&mut self, input: &Cell<&'a Expression<'a>>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_expression(input) {
|
||||
VisitResult::VisitChildren => match input.get() {
|
||||
Expression::ArrayAccess(e) => self.visit_array_access(e),
|
||||
Expression::ArrayInit(e) => self.visit_array_init(e),
|
||||
Expression::ArrayInline(e) => self.visit_array_inline(e),
|
||||
Expression::ArrayRangeAccess(e) => self.visit_array_range_access(e),
|
||||
Expression::Binary(e) => self.visit_binary(e),
|
||||
Expression::Call(e) => self.visit_call(e),
|
||||
Expression::CircuitAccess(e) => self.visit_circuit_access(e),
|
||||
Expression::CircuitInit(e) => self.visit_circuit_init(e),
|
||||
Expression::Ternary(e) => self.visit_ternary_expression(e),
|
||||
Expression::Constant(e) => self.visit_constant(e),
|
||||
Expression::TupleAccess(e) => self.visit_tuple_access(e),
|
||||
Expression::TupleInit(e) => self.visit_tuple_init(e),
|
||||
Expression::Unary(e) => self.visit_unary(e),
|
||||
Expression::VariableRef(e) => self.visit_variable_ref(e),
|
||||
},
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_opt_expression(&mut self, input: &Cell<Option<&'a Expression<'a>>>) -> ConcreteVisitResult {
|
||||
let interior = match input.get() {
|
||||
Some(expr) => Some(Cell::new(expr)),
|
||||
None => None,
|
||||
};
|
||||
if let Some(interior) = interior.as_ref() {
|
||||
let result = self.visit_expression(interior);
|
||||
input.replace(Some(interior.get()));
|
||||
result
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_array_access(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.array)?;
|
||||
self.visit_expression(&input.index)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_array_init(&mut self, input: &ArrayInitExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_array_init(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.element)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_array_inline(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for (element, _) in input.elements.iter() {
|
||||
self.visit_expression(element)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_array_range_access(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.array)?;
|
||||
self.visit_opt_expression(&input.left)?;
|
||||
self.visit_opt_expression(&input.right)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_binary(&mut self, input: &BinaryExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_binary(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.left)?;
|
||||
self.visit_expression(&input.right)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_call(&mut self, input: &CallExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_call(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_opt_expression(&input.target)?;
|
||||
for argument in input.arguments.iter() {
|
||||
self.visit_expression(argument)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_circuit_access(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_opt_expression(&input.target)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_circuit_init(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for (_, argument) in input.values.iter() {
|
||||
self.visit_expression(argument)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_ternary_expression(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.condition)?;
|
||||
self.visit_expression(&input.if_true)?;
|
||||
self.visit_expression(&input.if_false)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_constant(&mut self, input: &Constant<'a>) -> ConcreteVisitResult {
|
||||
self.visitor.visit_constant(input).into()
|
||||
}
|
||||
|
||||
pub fn visit_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_tuple_access(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.tuple_ref)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_tuple_init(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for argument in input.elements.iter() {
|
||||
self.visit_expression(argument)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_unary(&mut self, input: &UnaryExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_unary(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.inner)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_variable_ref(&mut self, input: &VariableRef<'a>) -> ConcreteVisitResult {
|
||||
self.visitor.visit_variable_ref(input).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: StatementVisitor<'a>> VisitorDirector<'a, R> {
|
||||
pub fn visit_statement(&mut self, input: &Cell<&'a Statement<'a>>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_statement(input) {
|
||||
VisitResult::VisitChildren => match input.get() {
|
||||
Statement::Assign(s) => self.visit_assign(s),
|
||||
Statement::Block(s) => self.visit_block(s),
|
||||
Statement::Conditional(s) => self.visit_conditional_statement(s),
|
||||
Statement::Console(s) => self.visit_console(s),
|
||||
Statement::Definition(s) => self.visit_definition(s),
|
||||
Statement::Expression(s) => self.visit_expression_statement(s),
|
||||
Statement::Iteration(s) => self.visit_iteration(s),
|
||||
Statement::Return(s) => self.visit_return(s),
|
||||
},
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_opt_statement(&mut self, input: &Cell<Option<&'a Statement<'a>>>) -> ConcreteVisitResult {
|
||||
let interior = match input.get() {
|
||||
Some(expr) => Some(Cell::new(expr)),
|
||||
None => None,
|
||||
};
|
||||
if let Some(interior) = interior.as_ref() {
|
||||
let result = self.visit_statement(interior);
|
||||
input.replace(Some(interior.get()));
|
||||
result
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_assign_access(&mut self, input: &AssignAccess<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_assign_access(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
match input {
|
||||
AssignAccess::ArrayRange(left, right) => {
|
||||
self.visit_opt_expression(left)?;
|
||||
self.visit_opt_expression(right)?;
|
||||
}
|
||||
AssignAccess::ArrayIndex(index) => self.visit_expression(index)?,
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_assign(&mut self, input: &AssignStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_assign(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for access in input.target_accesses.iter() {
|
||||
self.visit_assign_access(access)?;
|
||||
}
|
||||
self.visit_expression(&input.value)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_block(&mut self, input: &BlockStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_block(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for statement in input.statements.iter() {
|
||||
self.visit_statement(statement)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_conditional_statement(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.condition)?;
|
||||
self.visit_statement(&input.result)?;
|
||||
self.visit_opt_statement(&input.next)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_formatted_string(&mut self, input: &FormattedString<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_formatted_string(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for parameter in input.parameters.iter() {
|
||||
self.visit_expression(parameter)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_console(&mut self, input: &ConsoleStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_console(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
match &input.function {
|
||||
ConsoleFunction::Assert(e) => self.visit_expression(e)?,
|
||||
ConsoleFunction::Debug(f) | ConsoleFunction::Error(f) | ConsoleFunction::Log(f) => {
|
||||
self.visit_formatted_string(f)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_definition(&mut self, input: &DefinitionStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_definition(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.value)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_expression_statement(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.expression)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_iteration(&mut self, input: &IterationStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_iteration(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.start)?;
|
||||
self.visit_expression(&input.stop)?;
|
||||
self.visit_statement(&input.body)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_return(&mut self, input: &ReturnStatement<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_return(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_expression(&input.expression)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a, R: ProgramVisitor<'a>> VisitorDirector<'a, R> {
|
||||
fn visit_function(&mut self, input: &'a Function<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_function(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
self.visit_opt_statement(&input.body)?;
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit_member(&mut self, input: &CircuitMember<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_circuit_member(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
if let CircuitMember::Function(f) = input {
|
||||
self.visit_function(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_circuit(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for (_, member) in input.members.borrow().iter() {
|
||||
self.visit_circuit_member(member)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_program(&mut self, input: &Program<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_program(input) {
|
||||
VisitResult::VisitChildren => {
|
||||
for (_, import) in input.imported_modules.iter() {
|
||||
self.visit_program(import)?;
|
||||
}
|
||||
for (_, (function, _)) in input.test_functions.iter() {
|
||||
self.visit_function(function)?;
|
||||
}
|
||||
for (_, function) in input.functions.iter() {
|
||||
self.visit_function(function)?;
|
||||
}
|
||||
for (_, circuit) in input.circuits.iter() {
|
||||
self.visit_circuit(circuit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
x => x.into(),
|
||||
}
|
||||
}
|
||||
}
|
185
asg/src/scope.rs
185
asg/src/scope.rs
@ -14,58 +14,96 @@
|
||||
// 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::{AsgConvertError, Circuit, Function, Input, Type, Variable};
|
||||
use crate::{ArenaNode, AsgContext, AsgConvertError, Circuit, Expression, Function, Input, Statement, Type, Variable};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
use uuid::Uuid;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
/// An abstract data type that track the current bindings for variables, functions, and circuits.
|
||||
#[derive(Debug)]
|
||||
pub struct InnerScope {
|
||||
#[derive(Clone)]
|
||||
pub struct Scope<'a> {
|
||||
pub context: AsgContext<'a>,
|
||||
|
||||
/// The unique id of the scope.
|
||||
pub id: Uuid,
|
||||
pub id: u32,
|
||||
|
||||
/// The parent scope that this scope inherits.
|
||||
pub parent_scope: Option<Scope>,
|
||||
pub parent_scope: Cell<Option<&'a Scope<'a>>>,
|
||||
|
||||
/// The function definition that this scope occurs in.
|
||||
pub function: Option<Arc<Function>>,
|
||||
pub function: Cell<Option<&'a Function<'a>>>,
|
||||
|
||||
/// The circuit definition that this scope occurs in.
|
||||
pub circuit_self: Option<Arc<Circuit>>,
|
||||
pub circuit_self: Cell<Option<&'a Circuit<'a>>>,
|
||||
|
||||
/// Maps variable name => variable.
|
||||
pub variables: IndexMap<String, Variable>,
|
||||
pub variables: RefCell<IndexMap<String, &'a Variable<'a>>>,
|
||||
|
||||
/// Maps function name => function.
|
||||
pub functions: IndexMap<String, Arc<Function>>,
|
||||
pub functions: RefCell<IndexMap<String, &'a Function<'a>>>,
|
||||
|
||||
/// Maps circuit name => circuit.
|
||||
pub circuits: IndexMap<String, Arc<Circuit>>,
|
||||
pub circuits: RefCell<IndexMap<String, &'a Circuit<'a>>>,
|
||||
|
||||
/// The main input to the program.
|
||||
pub input: Option<Input>,
|
||||
pub input: Cell<Option<Input<'a>>>,
|
||||
}
|
||||
|
||||
pub type Scope = Arc<RefCell<InnerScope>>;
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
impl<'a> Scope<'a> {
|
||||
pub fn alloc_expression(&'a self, expr: Expression<'a>) -> &'a mut Expression<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Expression(expr)) {
|
||||
ArenaNode::Expression(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_statement(&'a self, statement: Statement<'a>) -> &'a mut Statement<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Statement(statement)) {
|
||||
ArenaNode::Statement(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_variable(&'a self, variable: Variable<'a>) -> &'a mut Variable<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Variable(variable)) {
|
||||
ArenaNode::Variable(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_scope(&'a self, scope: Scope<'a>) -> &'a mut Scope<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Scope(scope)) {
|
||||
ArenaNode::Scope(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_circuit(&'a self, circuit: Circuit<'a>) -> &'a mut Circuit<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Circuit(circuit)) {
|
||||
ArenaNode::Circuit(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_function(&'a self, function: Function<'a>) -> &'a mut Function<'a> {
|
||||
match self.context.arena.alloc(ArenaNode::Function(function)) {
|
||||
ArenaNode::Function(e) => e,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerScope {
|
||||
///
|
||||
/// Returns a reference to the variable corresponding to the name.
|
||||
///
|
||||
/// If the current scope did not have this name present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_variable(&self, name: &str) -> Option<Variable> {
|
||||
if let Some(resolved) = self.variables.get(name) {
|
||||
Some(resolved.clone())
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_variable(name) {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_variable(&self, name: &str) -> Option<&'a Variable<'a>> {
|
||||
if let Some(resolved) = self.variables.borrow().get(name) {
|
||||
Some(*resolved)
|
||||
} else if let Some(scope) = self.parent_scope.get() {
|
||||
scope.resolve_variable(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -77,15 +115,11 @@ impl InnerScope {
|
||||
/// If the current scope did not have a function present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_current_function(&self) -> Option<Arc<Function>> {
|
||||
if let Some(resolved) = self.function.as_ref() {
|
||||
Some(resolved.clone())
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_current_function() {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_current_function(&self) -> Option<&'a Function> {
|
||||
if let Some(resolved) = self.function.get() {
|
||||
Some(resolved)
|
||||
} else if let Some(scope) = self.parent_scope.get() {
|
||||
scope.resolve_current_function()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -97,15 +131,11 @@ impl InnerScope {
|
||||
/// If the current scope did not have an input present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_input(&self) -> Option<Input> {
|
||||
if let Some(input) = self.input.as_ref() {
|
||||
Some(input.clone())
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_input() {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_input(&self) -> Option<Input<'a>> {
|
||||
if let Some(input) = self.input.get() {
|
||||
Some(input)
|
||||
} else if let Some(resolved) = self.parent_scope.get() {
|
||||
resolved.resolve_input()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -117,15 +147,11 @@ impl InnerScope {
|
||||
/// If the current scope did not have this name present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_function(&self, name: &str) -> Option<Arc<Function>> {
|
||||
if let Some(resolved) = self.functions.get(name) {
|
||||
Some(resolved.clone())
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_function(name) {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_function(&self, name: &str) -> Option<&'a Function<'a>> {
|
||||
if let Some(resolved) = self.functions.borrow().get(name) {
|
||||
Some(*resolved)
|
||||
} else if let Some(resolved) = self.parent_scope.get() {
|
||||
resolved.resolve_function(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -137,17 +163,13 @@ impl InnerScope {
|
||||
/// If the current scope did not have this name present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_circuit(&self, name: &str) -> Option<Arc<Circuit>> {
|
||||
if let Some(resolved) = self.circuits.get(name) {
|
||||
Some(resolved.clone())
|
||||
} else if name == "Self" && self.circuit_self.is_some() {
|
||||
self.circuit_self.clone()
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_circuit(name) {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_circuit(&self, name: &str) -> Option<&'a Circuit<'a>> {
|
||||
if let Some(resolved) = self.circuits.borrow().get(name) {
|
||||
Some(*resolved)
|
||||
} else if name == "Self" && self.circuit_self.get().is_some() {
|
||||
self.circuit_self.get()
|
||||
} else if let Some(resolved) = self.parent_scope.get() {
|
||||
resolved.resolve_circuit(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -159,15 +181,11 @@ impl InnerScope {
|
||||
/// If the current scope did not have a circuit self present, then the parent scope is checked.
|
||||
/// If there is no parent scope, then `None` is returned.
|
||||
///
|
||||
pub fn resolve_circuit_self(&self) -> Option<Arc<Circuit>> {
|
||||
if let Some(resolved) = self.circuit_self.as_ref() {
|
||||
Some(resolved.clone())
|
||||
} else if let Some(resolved) = self.parent_scope.as_ref() {
|
||||
if let Some(resolved) = resolved.borrow().resolve_circuit_self() {
|
||||
Some(resolved)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn resolve_circuit_self(&self) -> Option<&'a Circuit<'a>> {
|
||||
if let Some(resolved) = self.circuit_self.get() {
|
||||
Some(resolved)
|
||||
} else if let Some(resolved) = self.parent_scope.get() {
|
||||
resolved.resolve_circuit_self()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -176,23 +194,24 @@ impl InnerScope {
|
||||
///
|
||||
/// Returns a new scope given a parent scope.
|
||||
///
|
||||
pub fn make_subscope(scope: &Scope) -> Scope {
|
||||
Arc::new(RefCell::new(InnerScope {
|
||||
id: Uuid::new_v4(),
|
||||
parent_scope: Some(scope.clone()),
|
||||
circuit_self: None,
|
||||
variables: IndexMap::new(),
|
||||
functions: IndexMap::new(),
|
||||
circuits: IndexMap::new(),
|
||||
function: None,
|
||||
input: None,
|
||||
}))
|
||||
pub fn make_subscope(self: &'a Scope<'a>) -> &'a Scope<'a> {
|
||||
self.alloc_scope(Scope::<'a> {
|
||||
context: self.context,
|
||||
id: self.context.get_id(),
|
||||
parent_scope: Cell::new(Some(self)),
|
||||
circuit_self: Cell::new(None),
|
||||
variables: RefCell::new(IndexMap::new()),
|
||||
functions: RefCell::new(IndexMap::new()),
|
||||
circuits: RefCell::new(IndexMap::new()),
|
||||
function: Cell::new(None),
|
||||
input: Cell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the type returned by the current scope.
|
||||
///
|
||||
pub fn resolve_ast_type(&self, type_: &leo_ast::Type) -> Result<Type, AsgConvertError> {
|
||||
pub fn resolve_ast_type(&self, type_: &leo_ast::Type) -> Result<Type<'a>, AsgConvertError> {
|
||||
use leo_ast::Type::*;
|
||||
Ok(match type_ {
|
||||
Address => Type::Address,
|
||||
|
@ -35,49 +35,49 @@ use crate::{
|
||||
pub use leo_ast::AssignOperation;
|
||||
use leo_ast::AssigneeAccess as AstAssigneeAccess;
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AssignAccess {
|
||||
ArrayRange(Option<Arc<Expression>>, Option<Arc<Expression>>),
|
||||
ArrayIndex(Arc<Expression>),
|
||||
#[derive(Clone)]
|
||||
pub enum AssignAccess<'a> {
|
||||
ArrayRange(Cell<Option<&'a Expression<'a>>>, Cell<Option<&'a Expression<'a>>>),
|
||||
ArrayIndex(Cell<&'a Expression<'a>>),
|
||||
Tuple(usize),
|
||||
Member(Identifier),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AssignStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct AssignStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub operation: AssignOperation,
|
||||
pub target_variable: Variable,
|
||||
pub target_accesses: Vec<AssignAccess>,
|
||||
pub value: Arc<Expression>,
|
||||
pub target_variable: Cell<&'a Variable<'a>>,
|
||||
pub target_accesses: Vec<AssignAccess<'a>>,
|
||||
pub value: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for AssignStatement {
|
||||
impl<'a> Node for AssignStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::AssignStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
) -> Result<Arc<Statement>, AsgConvertError> {
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let (name, span) = (&statement.assignee.identifier.name, &statement.assignee.identifier.span);
|
||||
|
||||
let variable = if name == "input" {
|
||||
if let Some(function) = scope.borrow().resolve_current_function() {
|
||||
if let Some(function) = scope.resolve_current_function() {
|
||||
if !function.has_input {
|
||||
return Err(AsgConvertError::unresolved_reference(name, span));
|
||||
}
|
||||
} else {
|
||||
return Err(AsgConvertError::unresolved_reference(name, span));
|
||||
}
|
||||
if let Some(input) = scope.borrow().resolve_input() {
|
||||
if let Some(input) = scope.resolve_input() {
|
||||
input.container
|
||||
} else {
|
||||
return Err(AsgConvertError::InternalError(
|
||||
@ -86,7 +86,6 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
}
|
||||
} else {
|
||||
scope
|
||||
.borrow()
|
||||
.resolve_variable(&name)
|
||||
.ok_or_else(|| AsgConvertError::unresolved_reference(name, span))?
|
||||
};
|
||||
@ -94,7 +93,7 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
if !variable.borrow().mutable {
|
||||
return Err(AsgConvertError::immutable_assignment(&name, &statement.span));
|
||||
}
|
||||
let mut target_type: Option<PartialType> = Some(variable.borrow().type_.clone().strong().into());
|
||||
let mut target_type: Option<PartialType> = Some(variable.borrow().type_.clone().into());
|
||||
|
||||
let mut target_accesses = vec![];
|
||||
for access in statement.assignee.accesses.iter() {
|
||||
@ -104,16 +103,16 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
let left = left
|
||||
.as_ref()
|
||||
.map(
|
||||
|left: &leo_ast::Expression| -> Result<Arc<Expression>, AsgConvertError> {
|
||||
Arc::<Expression>::from_ast(scope, left, index_type.clone())
|
||||
|left: &leo_ast::Expression| -> Result<&'a Expression<'a>, AsgConvertError> {
|
||||
<&Expression<'a>>::from_ast(scope, left, index_type.clone())
|
||||
},
|
||||
)
|
||||
.transpose()?;
|
||||
let right = right
|
||||
.as_ref()
|
||||
.map(
|
||||
|right: &leo_ast::Expression| -> Result<Arc<Expression>, AsgConvertError> {
|
||||
Arc::<Expression>::from_ast(scope, right, index_type)
|
||||
|right: &leo_ast::Expression| -> Result<&'a Expression<'a>, AsgConvertError> {
|
||||
<&Expression<'a>>::from_ast(scope, right, index_type)
|
||||
},
|
||||
)
|
||||
.transpose()?;
|
||||
@ -156,18 +155,18 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
_ => return Err(AsgConvertError::index_into_non_array(&name, &statement.span)),
|
||||
}
|
||||
|
||||
AssignAccess::ArrayRange(left, right)
|
||||
AssignAccess::ArrayRange(Cell::new(left), Cell::new(right))
|
||||
}
|
||||
AstAssigneeAccess::ArrayIndex(index) => {
|
||||
target_type = match target_type.clone() {
|
||||
Some(PartialType::Array(item, _)) => item.map(|x| *x),
|
||||
_ => return Err(AsgConvertError::index_into_non_array(&name, &statement.span)),
|
||||
};
|
||||
AssignAccess::ArrayIndex(Arc::<Expression>::from_ast(
|
||||
AssignAccess::ArrayIndex(Cell::new(<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
index,
|
||||
Some(PartialType::Integer(None, Some(IntegerType::U32))),
|
||||
)?)
|
||||
)?))
|
||||
}
|
||||
AstAssigneeAccess::Tuple(index, _) => {
|
||||
let index = index
|
||||
@ -203,7 +202,7 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
return Err(AsgConvertError::illegal_function_assign(&name.name, &statement.span));
|
||||
}
|
||||
};
|
||||
Some(x.strong().partial())
|
||||
Some(x.partial())
|
||||
}
|
||||
_ => {
|
||||
return Err(AsgConvertError::index_into_non_tuple(
|
||||
@ -216,41 +215,40 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
|
||||
}
|
||||
});
|
||||
}
|
||||
let value = Arc::<Expression>::from_ast(scope, &statement.value, target_type)?;
|
||||
let value = <&Expression<'a>>::from_ast(scope, &statement.value, target_type)?;
|
||||
|
||||
let statement = Arc::new(Statement::Assign(AssignStatement {
|
||||
parent: None,
|
||||
let statement = scope.alloc_statement(Statement::Assign(AssignStatement {
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
operation: statement.operation.clone(),
|
||||
target_variable: variable.clone(),
|
||||
target_variable: Cell::new(variable),
|
||||
target_accesses,
|
||||
value,
|
||||
value: Cell::new(value),
|
||||
}));
|
||||
|
||||
{
|
||||
let mut variable = variable.borrow_mut();
|
||||
variable.assignments.push(Arc::downgrade(&statement));
|
||||
variable.assignments.push(statement);
|
||||
}
|
||||
|
||||
Ok(statement)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::AssignStatement> for &AssignStatement {
|
||||
impl<'a> Into<leo_ast::AssignStatement> for &AssignStatement<'a> {
|
||||
fn into(self) -> leo_ast::AssignStatement {
|
||||
leo_ast::AssignStatement {
|
||||
operation: self.operation.clone(),
|
||||
assignee: leo_ast::Assignee {
|
||||
identifier: self.target_variable.borrow().name.clone(),
|
||||
identifier: self.target_variable.get().borrow().name.clone(),
|
||||
accesses: self
|
||||
.target_accesses
|
||||
.iter()
|
||||
.map(|access| match access {
|
||||
AssignAccess::ArrayRange(left, right) => AstAssigneeAccess::ArrayRange(
|
||||
left.as_ref().map(|e| e.as_ref().into()),
|
||||
right.as_ref().map(|e| e.as_ref().into()),
|
||||
),
|
||||
AssignAccess::ArrayIndex(index) => AstAssigneeAccess::ArrayIndex(index.as_ref().into()),
|
||||
AssignAccess::ArrayRange(left, right) => {
|
||||
AstAssigneeAccess::ArrayRange(left.get().map(|e| e.into()), right.get().map(|e| e.into()))
|
||||
}
|
||||
AssignAccess::ArrayIndex(index) => AstAssigneeAccess::ArrayIndex(index.get().into()),
|
||||
AssignAccess::Tuple(index) => AstAssigneeAccess::Tuple(
|
||||
leo_ast::PositiveNumber {
|
||||
value: index.to_string(),
|
||||
@ -262,7 +260,7 @@ impl Into<leo_ast::AssignStatement> for &AssignStatement {
|
||||
.collect(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
},
|
||||
value: self.value.as_ref().into(),
|
||||
value: self.value.get().into(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -14,38 +14,38 @@
|
||||
// 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::{AsgConvertError, FromAst, InnerScope, Node, PartialType, Scope, Span, Statement};
|
||||
use crate::{AsgConvertError, FromAst, Node, PartialType, Scope, Span, Statement};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlockStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct BlockStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub statements: Vec<Arc<Statement>>,
|
||||
pub scope: Scope,
|
||||
pub statements: Vec<Cell<&'a Statement<'a>>>,
|
||||
pub scope: &'a Scope<'a>,
|
||||
}
|
||||
|
||||
impl Node for BlockStatement {
|
||||
impl<'a> Node for BlockStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::Block> for BlockStatement {
|
||||
impl<'a> FromAst<'a, leo_ast::Block> for BlockStatement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::Block,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let new_scope = InnerScope::make_subscope(scope);
|
||||
let new_scope = scope.make_subscope();
|
||||
|
||||
let mut output = vec![];
|
||||
for item in statement.statements.iter() {
|
||||
output.push(Arc::<Statement>::from_ast(&new_scope, item, None)?);
|
||||
output.push(Cell::new(<&'a Statement<'a>>::from_ast(&new_scope, item, None)?));
|
||||
}
|
||||
Ok(BlockStatement {
|
||||
parent: None,
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
statements: output,
|
||||
scope: new_scope,
|
||||
@ -53,14 +53,10 @@ impl FromAst<leo_ast::Block> for BlockStatement {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Block> for &BlockStatement {
|
||||
impl<'a> Into<leo_ast::Block> for &BlockStatement<'a> {
|
||||
fn into(self) -> leo_ast::Block {
|
||||
leo_ast::Block {
|
||||
statements: self
|
||||
.statements
|
||||
.iter()
|
||||
.map(|statement| statement.as_ref().into())
|
||||
.collect(),
|
||||
statements: self.statements.iter().map(|statement| statement.get().into()).collect(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -16,31 +16,31 @@
|
||||
|
||||
use crate::{AsgConvertError, BlockStatement, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConditionalStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ConditionalStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub condition: Arc<Expression>,
|
||||
pub result: Arc<Statement>,
|
||||
pub next: Option<Arc<Statement>>,
|
||||
pub condition: Cell<&'a Expression<'a>>,
|
||||
pub result: Cell<&'a Statement<'a>>,
|
||||
pub next: Cell<Option<&'a Statement<'a>>>,
|
||||
}
|
||||
|
||||
impl Node for ConditionalStatement {
|
||||
impl<'a> Node for ConditionalStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ConditionalStatement> for ConditionalStatement {
|
||||
impl<'a> FromAst<'a, leo_ast::ConditionalStatement> for ConditionalStatement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::ConditionalStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let condition = Arc::<Expression>::from_ast(scope, &statement.condition, Some(Type::Boolean.into()))?;
|
||||
let result = Arc::new(Statement::Block(BlockStatement::from_ast(
|
||||
let condition = <&Expression<'a>>::from_ast(scope, &statement.condition, Some(Type::Boolean.into()))?;
|
||||
let result = scope.alloc_statement(Statement::Block(BlockStatement::from_ast(
|
||||
scope,
|
||||
&statement.block,
|
||||
None,
|
||||
@ -48,28 +48,30 @@ impl FromAst<leo_ast::ConditionalStatement> for ConditionalStatement {
|
||||
let next = statement
|
||||
.next
|
||||
.as_deref()
|
||||
.map(|next| -> Result<Arc<Statement>, AsgConvertError> { Arc::<Statement>::from_ast(scope, next, None) })
|
||||
.map(|next| -> Result<&'a Statement<'a>, AsgConvertError> {
|
||||
<&'a Statement<'a>>::from_ast(scope, next, None)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Ok(ConditionalStatement {
|
||||
parent: None,
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
condition,
|
||||
result,
|
||||
next,
|
||||
condition: Cell::new(condition),
|
||||
result: Cell::new(result),
|
||||
next: Cell::new(next),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ConditionalStatement> for &ConditionalStatement {
|
||||
impl<'a> Into<leo_ast::ConditionalStatement> for &ConditionalStatement<'a> {
|
||||
fn into(self) -> leo_ast::ConditionalStatement {
|
||||
leo_ast::ConditionalStatement {
|
||||
condition: self.condition.as_ref().into(),
|
||||
block: match self.result.as_ref() {
|
||||
condition: self.condition.get().into(),
|
||||
block: match self.result.get() {
|
||||
Statement::Block(block) => block.into(),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
next: self.next.as_deref().map(|e| Box::new(e.into())),
|
||||
next: self.next.get().as_deref().map(|e| Box::new(e.into())),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -17,43 +17,43 @@
|
||||
use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
|
||||
use leo_ast::ConsoleFunction as AstConsoleFunction;
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::cell::Cell;
|
||||
|
||||
// TODO (protryon): Refactor to not require/depend on span
|
||||
#[derive(Debug)]
|
||||
pub struct FormattedString {
|
||||
#[derive(Clone)]
|
||||
pub struct FormattedString<'a> {
|
||||
pub string: String,
|
||||
pub containers: Vec<Span>,
|
||||
pub parameters: Vec<Arc<Expression>>,
|
||||
pub parameters: Vec<Cell<&'a Expression<'a>>>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConsoleFunction {
|
||||
Assert(Arc<Expression>),
|
||||
Debug(FormattedString),
|
||||
Error(FormattedString),
|
||||
Log(FormattedString),
|
||||
#[derive(Clone)]
|
||||
pub enum ConsoleFunction<'a> {
|
||||
Assert(Cell<&'a Expression<'a>>),
|
||||
Debug(FormattedString<'a>),
|
||||
Error(FormattedString<'a>),
|
||||
Log(FormattedString<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConsoleStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ConsoleStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub function: ConsoleFunction,
|
||||
pub function: ConsoleFunction<'a>,
|
||||
}
|
||||
|
||||
impl Node for ConsoleStatement {
|
||||
impl<'a> Node for ConsoleStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::FormattedString> for FormattedString {
|
||||
impl<'a> FromAst<'a, leo_ast::FormattedString> for FormattedString<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::FormattedString,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
if value.parameters.len() != value.containers.len() {
|
||||
// + 1 for formatting string as to not confuse user
|
||||
@ -65,7 +65,7 @@ impl FromAst<leo_ast::FormattedString> for FormattedString {
|
||||
}
|
||||
let mut parameters = vec![];
|
||||
for parameter in value.parameters.iter() {
|
||||
parameters.push(Arc::<Expression>::from_ast(scope, parameter, None)?);
|
||||
parameters.push(Cell::new(<&Expression<'a>>::from_ast(scope, parameter, None)?));
|
||||
}
|
||||
Ok(FormattedString {
|
||||
string: value.string.clone(),
|
||||
@ -76,7 +76,7 @@ impl FromAst<leo_ast::FormattedString> for FormattedString {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::FormattedString> for &FormattedString {
|
||||
impl<'a> Into<leo_ast::FormattedString> for &FormattedString<'a> {
|
||||
fn into(self) -> leo_ast::FormattedString {
|
||||
leo_ast::FormattedString {
|
||||
string: self.string.clone(),
|
||||
@ -85,27 +85,25 @@ impl Into<leo_ast::FormattedString> for &FormattedString {
|
||||
.iter()
|
||||
.map(|span| leo_ast::FormattedContainer { span: span.clone() })
|
||||
.collect(),
|
||||
parameters: self.parameters.iter().map(|e| e.as_ref().into()).collect(),
|
||||
parameters: self.parameters.iter().map(|e| e.get().into()).collect(),
|
||||
span: self.span.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ConsoleStatement> for ConsoleStatement {
|
||||
impl<'a> FromAst<'a, leo_ast::ConsoleStatement> for ConsoleStatement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::ConsoleStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
Ok(ConsoleStatement {
|
||||
parent: None,
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
function: match &statement.function {
|
||||
AstConsoleFunction::Assert(expression) => ConsoleFunction::Assert(Arc::<Expression>::from_ast(
|
||||
scope,
|
||||
expression,
|
||||
Some(Type::Boolean.into()),
|
||||
)?),
|
||||
AstConsoleFunction::Assert(expression) => ConsoleFunction::Assert(Cell::new(
|
||||
<&Expression<'a>>::from_ast(scope, expression, Some(Type::Boolean.into()))?,
|
||||
)),
|
||||
AstConsoleFunction::Debug(formatted_string) => {
|
||||
ConsoleFunction::Debug(FormattedString::from_ast(scope, formatted_string, None)?)
|
||||
}
|
||||
@ -120,12 +118,12 @@ impl FromAst<leo_ast::ConsoleStatement> for ConsoleStatement {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ConsoleStatement> for &ConsoleStatement {
|
||||
impl<'a> Into<leo_ast::ConsoleStatement> for &ConsoleStatement<'a> {
|
||||
fn into(self) -> leo_ast::ConsoleStatement {
|
||||
use ConsoleFunction::*;
|
||||
leo_ast::ConsoleStatement {
|
||||
function: match &self.function {
|
||||
Assert(e) => AstConsoleFunction::Assert(e.as_ref().into()),
|
||||
Assert(e) => AstConsoleFunction::Assert(e.get().into()),
|
||||
Debug(formatted_string) => AstConsoleFunction::Debug(formatted_string.into()),
|
||||
Error(formatted_string) => AstConsoleFunction::Error(formatted_string.into()),
|
||||
Log(formatted_string) => AstConsoleFunction::Log(formatted_string.into()),
|
||||
|
@ -28,39 +28,37 @@ use crate::{
|
||||
Type,
|
||||
Variable,
|
||||
};
|
||||
use leo_ast::{AstError, DeprecatedError};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DefinitionStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct DefinitionStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub variables: Vec<Variable>,
|
||||
pub value: Arc<Expression>,
|
||||
pub variables: Vec<&'a Variable<'a>>,
|
||||
pub value: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for DefinitionStatement {
|
||||
impl<'a> Node for DefinitionStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::DefinitionStatement> for Arc<Statement> {
|
||||
impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::DefinitionStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
) -> Result<Arc<Statement>, AsgConvertError> {
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let type_ = statement
|
||||
.type_
|
||||
.as_ref()
|
||||
.map(|x| scope.borrow().resolve_ast_type(&x))
|
||||
.map(|x| scope.resolve_ast_type(&x))
|
||||
.transpose()?;
|
||||
|
||||
let value = Arc::<Expression>::from_ast(scope, &statement.value, type_.clone().map(Into::into))?;
|
||||
let value = <&Expression<'a>>::from_ast(scope, &statement.value, type_.clone().map(Into::into))?;
|
||||
|
||||
let type_ = type_.or_else(|| value.get_type());
|
||||
|
||||
@ -92,15 +90,16 @@ impl FromAst<leo_ast::DefinitionStatement> for Arc<Statement> {
|
||||
}
|
||||
|
||||
for (variable, type_) in statement.variable_names.iter().zip(output_types.into_iter()) {
|
||||
if statement.declaration_type == leo_ast::Declare::Const && variable.mutable {
|
||||
return Err(AsgConvertError::illegal_ast_structure("cannot have const mut"));
|
||||
if statement.declaration_type == leo_ast::Declare::Const {
|
||||
return Err(AsgConvertError::AstError(AstError::DeprecatedError(
|
||||
DeprecatedError::const_statement(&statement.span),
|
||||
)));
|
||||
}
|
||||
variables.push(Arc::new(RefCell::new(InnerVariable {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
variables.push(&*scope.alloc_variable(RefCell::new(InnerVariable {
|
||||
id: scope.context.get_id(),
|
||||
name: variable.identifier.clone(),
|
||||
type_: type_
|
||||
.ok_or_else(|| AsgConvertError::unresolved_type(&variable.identifier.name, &statement.span))?
|
||||
.weak(),
|
||||
type_:
|
||||
type_.ok_or_else(|| AsgConvertError::unresolved_type(&variable.identifier.name, &statement.span))?,
|
||||
mutable: variable.mutable,
|
||||
const_: false,
|
||||
declaration: crate::VariableDeclaration::Definition,
|
||||
@ -109,31 +108,29 @@ impl FromAst<leo_ast::DefinitionStatement> for Arc<Statement> {
|
||||
})));
|
||||
}
|
||||
|
||||
{
|
||||
let mut scope_borrow = scope.borrow_mut();
|
||||
for variable in variables.iter() {
|
||||
scope_borrow
|
||||
.variables
|
||||
.insert(variable.borrow().name.name.clone(), variable.clone());
|
||||
}
|
||||
for variable in variables.iter() {
|
||||
scope
|
||||
.variables
|
||||
.borrow_mut()
|
||||
.insert(variable.borrow().name.name.clone(), *variable);
|
||||
}
|
||||
|
||||
let statement = Arc::new(Statement::Definition(DefinitionStatement {
|
||||
parent: None,
|
||||
let statement = scope.alloc_statement(Statement::Definition(DefinitionStatement {
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
variables: variables.clone(),
|
||||
value,
|
||||
value: Cell::new(value),
|
||||
}));
|
||||
|
||||
variables.iter().for_each(|variable| {
|
||||
variable.borrow_mut().assignments.push(Arc::downgrade(&statement));
|
||||
});
|
||||
for variable in variables {
|
||||
variable.borrow_mut().assignments.push(statement);
|
||||
}
|
||||
|
||||
Ok(statement)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::DefinitionStatement> for &DefinitionStatement {
|
||||
impl<'a> Into<leo_ast::DefinitionStatement> for &DefinitionStatement<'a> {
|
||||
fn into(self) -> leo_ast::DefinitionStatement {
|
||||
assert!(!self.variables.is_empty());
|
||||
|
||||
@ -147,7 +144,7 @@ impl Into<leo_ast::DefinitionStatement> for &DefinitionStatement {
|
||||
span: variable.name.span.clone(),
|
||||
});
|
||||
if type_.is_none() {
|
||||
type_ = Some((&variable.type_.clone().strong()).into());
|
||||
type_ = Some((&variable.type_.clone()).into());
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +152,7 @@ impl Into<leo_ast::DefinitionStatement> for &DefinitionStatement {
|
||||
declaration_type: leo_ast::Declare::Let,
|
||||
variable_names,
|
||||
type_,
|
||||
value: self.value.as_ref().into(),
|
||||
value: self.value.get().into(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -16,41 +16,41 @@
|
||||
|
||||
use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span, Statement};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExpressionStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct ExpressionStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub expression: Arc<Expression>,
|
||||
pub expression: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for ExpressionStatement {
|
||||
impl<'a> Node for ExpressionStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ExpressionStatement> for ExpressionStatement {
|
||||
impl<'a> FromAst<'a, leo_ast::ExpressionStatement> for ExpressionStatement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::ExpressionStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let expression = Arc::<Expression>::from_ast(scope, &statement.expression, None)?;
|
||||
let expression = <&Expression<'a>>::from_ast(scope, &statement.expression, None)?;
|
||||
|
||||
Ok(ExpressionStatement {
|
||||
parent: None,
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
expression,
|
||||
expression: Cell::new(expression),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ExpressionStatement> for &ExpressionStatement {
|
||||
impl<'a> Into<leo_ast::ExpressionStatement> for &ExpressionStatement<'a> {
|
||||
fn into(self) -> leo_ast::ExpressionStatement {
|
||||
leo_ast::ExpressionStatement {
|
||||
expression: self.expression.as_ref().into(),
|
||||
expression: self.expression.get().into(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -30,43 +30,39 @@ use crate::{
|
||||
Variable,
|
||||
};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IterationStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
#[derive(Clone)]
|
||||
pub struct IterationStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub variable: Variable,
|
||||
pub start: Arc<Expression>,
|
||||
pub stop: Arc<Expression>,
|
||||
pub body: Arc<Statement>,
|
||||
pub variable: &'a Variable<'a>,
|
||||
pub start: Cell<&'a Expression<'a>>,
|
||||
pub stop: Cell<&'a Expression<'a>>,
|
||||
pub body: Cell<&'a Statement<'a>>,
|
||||
}
|
||||
|
||||
impl Node for IterationStatement {
|
||||
impl<'a> Node for IterationStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::IterationStatement> for Arc<Statement> {
|
||||
impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::IterationStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
) -> Result<Arc<Statement>, AsgConvertError> {
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let expected_index_type = Some(PartialType::Integer(None, Some(IntegerType::U32)));
|
||||
let start = Arc::<Expression>::from_ast(scope, &statement.start, expected_index_type.clone())?;
|
||||
let stop = Arc::<Expression>::from_ast(scope, &statement.stop, expected_index_type)?;
|
||||
let variable = Arc::new(RefCell::new(InnerVariable {
|
||||
id: uuid::Uuid::new_v4(),
|
||||
let start = <&Expression<'a>>::from_ast(scope, &statement.start, expected_index_type.clone())?;
|
||||
let stop = <&Expression<'a>>::from_ast(scope, &statement.stop, expected_index_type)?;
|
||||
let variable = scope.alloc_variable(RefCell::new(InnerVariable {
|
||||
id: scope.context.get_id(),
|
||||
name: statement.variable.clone(),
|
||||
type_: start
|
||||
.get_type()
|
||||
.ok_or_else(|| AsgConvertError::unresolved_type(&statement.variable.name, &statement.span))?
|
||||
.weak(),
|
||||
.ok_or_else(|| AsgConvertError::unresolved_type(&statement.variable.name, &statement.span))?,
|
||||
mutable: false,
|
||||
const_: true,
|
||||
declaration: crate::VariableDeclaration::IterationDefinition,
|
||||
@ -74,34 +70,34 @@ impl FromAst<leo_ast::IterationStatement> for Arc<Statement> {
|
||||
assignments: vec![],
|
||||
}));
|
||||
scope
|
||||
.borrow_mut()
|
||||
.variables
|
||||
.insert(statement.variable.name.clone(), variable.clone());
|
||||
.borrow_mut()
|
||||
.insert(statement.variable.name.clone(), variable);
|
||||
|
||||
let statement = Arc::new(Statement::Iteration(IterationStatement {
|
||||
parent: None,
|
||||
let statement = scope.alloc_statement(Statement::Iteration(IterationStatement {
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
variable: variable.clone(),
|
||||
stop,
|
||||
start,
|
||||
body: Arc::new(Statement::Block(crate::BlockStatement::from_ast(
|
||||
variable,
|
||||
stop: Cell::new(stop),
|
||||
start: Cell::new(start),
|
||||
body: Cell::new(scope.alloc_statement(Statement::Block(crate::BlockStatement::from_ast(
|
||||
scope,
|
||||
&statement.block,
|
||||
None,
|
||||
)?)),
|
||||
)?))),
|
||||
}));
|
||||
variable.borrow_mut().assignments.push(Arc::downgrade(&statement));
|
||||
variable.borrow_mut().assignments.push(statement);
|
||||
Ok(statement)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::IterationStatement> for &IterationStatement {
|
||||
impl<'a> Into<leo_ast::IterationStatement> for &IterationStatement<'a> {
|
||||
fn into(self) -> leo_ast::IterationStatement {
|
||||
leo_ast::IterationStatement {
|
||||
variable: self.variable.borrow().name.clone(),
|
||||
start: self.start.as_ref().into(),
|
||||
stop: self.stop.as_ref().into(),
|
||||
block: match self.body.as_ref() {
|
||||
start: self.start.get().into(),
|
||||
stop: self.stop.get().into(),
|
||||
block: match self.body.get() {
|
||||
Statement::Block(block) => block.into(),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
|
@ -44,21 +44,19 @@ pub use return_::*;
|
||||
|
||||
use crate::{AsgConvertError, FromAst, Node, PartialType, Scope, Span};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Statement {
|
||||
Return(ReturnStatement),
|
||||
Definition(DefinitionStatement),
|
||||
Assign(AssignStatement),
|
||||
Conditional(ConditionalStatement),
|
||||
Iteration(IterationStatement),
|
||||
Console(ConsoleStatement),
|
||||
Expression(ExpressionStatement),
|
||||
Block(BlockStatement),
|
||||
#[derive(Clone)]
|
||||
pub enum Statement<'a> {
|
||||
Return(ReturnStatement<'a>),
|
||||
Definition(DefinitionStatement<'a>),
|
||||
Assign(AssignStatement<'a>),
|
||||
Conditional(ConditionalStatement<'a>),
|
||||
Iteration(IterationStatement<'a>),
|
||||
Console(ConsoleStatement<'a>),
|
||||
Expression(ExpressionStatement<'a>),
|
||||
Block(BlockStatement<'a>),
|
||||
}
|
||||
|
||||
impl Node for Statement {
|
||||
impl<'a> Node for Statement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
use Statement::*;
|
||||
match self {
|
||||
@ -74,31 +72,37 @@ impl Node for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::Statement> for Arc<Statement> {
|
||||
impl<'a> FromAst<'a, leo_ast::Statement> for &'a Statement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::Statement,
|
||||
_expected_type: Option<PartialType>,
|
||||
) -> Result<Arc<Statement>, AsgConvertError> {
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<&'a Statement<'a>, AsgConvertError> {
|
||||
use leo_ast::Statement::*;
|
||||
Ok(match value {
|
||||
Return(statement) => Arc::new(Statement::Return(ReturnStatement::from_ast(scope, statement, None)?)),
|
||||
Definition(statement) => Arc::<Statement>::from_ast(scope, statement, None)?,
|
||||
Assign(statement) => Arc::<Statement>::from_ast(scope, statement, None)?,
|
||||
Conditional(statement) => Arc::new(Statement::Conditional(ConditionalStatement::from_ast(
|
||||
Return(statement) => {
|
||||
scope.alloc_statement(Statement::Return(ReturnStatement::from_ast(scope, statement, None)?))
|
||||
}
|
||||
Definition(statement) => Self::from_ast(scope, statement, None)?,
|
||||
Assign(statement) => Self::from_ast(scope, statement, None)?,
|
||||
Conditional(statement) => scope.alloc_statement(Statement::Conditional(ConditionalStatement::from_ast(
|
||||
scope, statement, None,
|
||||
)?)),
|
||||
Iteration(statement) => Arc::<Statement>::from_ast(scope, statement, None)?,
|
||||
Console(statement) => Arc::new(Statement::Console(ConsoleStatement::from_ast(scope, statement, None)?)),
|
||||
Expression(statement) => Arc::new(Statement::Expression(ExpressionStatement::from_ast(
|
||||
Iteration(statement) => Self::from_ast(scope, statement, None)?,
|
||||
Console(statement) => {
|
||||
scope.alloc_statement(Statement::Console(ConsoleStatement::from_ast(scope, statement, None)?))
|
||||
}
|
||||
Expression(statement) => scope.alloc_statement(Statement::Expression(ExpressionStatement::from_ast(
|
||||
scope, statement, None,
|
||||
)?)),
|
||||
Block(statement) => Arc::new(Statement::Block(BlockStatement::from_ast(scope, statement, None)?)),
|
||||
Block(statement) => {
|
||||
scope.alloc_statement(Statement::Block(BlockStatement::from_ast(scope, statement, None)?))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Statement> for &Statement {
|
||||
impl<'a> Into<leo_ast::Statement> for &Statement<'a> {
|
||||
fn into(self) -> leo_ast::Statement {
|
||||
use Statement::*;
|
||||
match self {
|
||||
|
@ -16,44 +16,46 @@
|
||||
|
||||
use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReturnStatement {
|
||||
pub parent: Option<Weak<Statement>>,
|
||||
use std::cell::Cell;
|
||||
#[derive(Clone)]
|
||||
pub struct ReturnStatement<'a> {
|
||||
pub parent: Cell<Option<&'a Statement<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub expression: Arc<Expression>,
|
||||
pub expression: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl Node for ReturnStatement {
|
||||
impl<'a> Node for ReturnStatement<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromAst<leo_ast::ReturnStatement> for ReturnStatement {
|
||||
impl<'a> FromAst<'a, leo_ast::ReturnStatement> for ReturnStatement<'a> {
|
||||
fn from_ast(
|
||||
scope: &Scope,
|
||||
scope: &'a Scope<'a>,
|
||||
statement: &leo_ast::ReturnStatement,
|
||||
_expected_type: Option<PartialType>,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<Self, AsgConvertError> {
|
||||
let return_type: Option<Type> = scope
|
||||
.borrow()
|
||||
.resolve_current_function()
|
||||
.map(|x| x.output.clone())
|
||||
.map(Into::into);
|
||||
Ok(ReturnStatement {
|
||||
parent: None,
|
||||
parent: Cell::new(None),
|
||||
span: Some(statement.span.clone()),
|
||||
expression: Arc::<Expression>::from_ast(scope, &statement.expression, return_type.map(Into::into))?,
|
||||
expression: Cell::new(<&Expression<'a>>::from_ast(
|
||||
scope,
|
||||
&statement.expression,
|
||||
return_type.map(Into::into),
|
||||
)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::ReturnStatement> for &ReturnStatement {
|
||||
impl<'a> Into<leo_ast::ReturnStatement> for &ReturnStatement<'a> {
|
||||
fn into(self) -> leo_ast::ReturnStatement {
|
||||
leo_ast::ReturnStatement {
|
||||
expression: self.expression.as_ref().into(),
|
||||
expression: self.expression.get().into(),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
@ -17,14 +17,11 @@
|
||||
use crate::Circuit;
|
||||
pub use leo_ast::IntegerType;
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// A type in an ASG.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
/// A type in an asg.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Type<'a> {
|
||||
// Data types
|
||||
Address,
|
||||
Boolean,
|
||||
@ -33,55 +30,21 @@ pub enum Type {
|
||||
Integer(IntegerType),
|
||||
|
||||
// Data type wrappers
|
||||
Array(Box<Type>, usize),
|
||||
Tuple(Vec<Type>),
|
||||
Circuit(Arc<Circuit>),
|
||||
Array(Box<Type<'a>>, usize),
|
||||
Tuple(Vec<Type<'a>>),
|
||||
Circuit(&'a Circuit<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum WeakType {
|
||||
Type(Type), // circuit not allowed
|
||||
Circuit(Weak<Circuit>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PartialType {
|
||||
Type(Type), // non-array or tuple
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum PartialType<'a> {
|
||||
Type(Type<'a>), // non-array or tuple
|
||||
Integer(Option<IntegerType>, Option<IntegerType>), // specific, context-specific
|
||||
Array(Option<Box<PartialType>>, Option<usize>),
|
||||
Tuple(Vec<Option<PartialType>>),
|
||||
Array(Option<Box<PartialType<'a>>>, Option<usize>),
|
||||
Tuple(Vec<Option<PartialType<'a>>>),
|
||||
}
|
||||
|
||||
impl Into<Type> for WeakType {
|
||||
fn into(self) -> Type {
|
||||
match self {
|
||||
WeakType::Type(t) => t,
|
||||
WeakType::Circuit(circuit) => Type::Circuit(circuit.upgrade().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WeakType {
|
||||
pub fn strong(self) -> Type {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn is_unit(&self) -> bool {
|
||||
matches!(self, WeakType::Type(Type::Tuple(t)) if t.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<WeakType> for Type {
|
||||
fn into(self) -> WeakType {
|
||||
match self {
|
||||
Type::Circuit(circuit) => WeakType::Circuit(Arc::downgrade(&circuit)),
|
||||
t => WeakType::Type(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Option<Type>> for PartialType {
|
||||
fn into(self) -> Option<Type> {
|
||||
impl<'a> Into<Option<Type<'a>>> for PartialType<'a> {
|
||||
fn into(self) -> Option<Type<'a>> {
|
||||
match self {
|
||||
PartialType::Type(t) => Some(t),
|
||||
PartialType::Integer(sub_type, contextual_type) => Some(Type::Integer(sub_type.or(contextual_type)?)),
|
||||
@ -96,12 +59,12 @@ impl Into<Option<Type>> for PartialType {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialType {
|
||||
pub fn full(self) -> Option<Type> {
|
||||
impl<'a> PartialType<'a> {
|
||||
pub fn full(self) -> Option<Type<'a>> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn matches(&self, other: &Type) -> bool {
|
||||
pub fn matches(&self, other: &Type<'a>) -> bool {
|
||||
match (self, other) {
|
||||
(PartialType::Type(t), other) => t.is_assignable_from(other),
|
||||
(PartialType::Integer(self_sub_type, _), Type::Integer(sub_type)) => {
|
||||
@ -137,8 +100,8 @@ impl PartialType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<PartialType> for Type {
|
||||
fn into(self) -> PartialType {
|
||||
impl<'a> Into<PartialType<'a>> for Type<'a> {
|
||||
fn into(self) -> PartialType<'a> {
|
||||
match self {
|
||||
Type::Integer(sub_type) => PartialType::Integer(Some(sub_type), None),
|
||||
Type::Array(element, len) => PartialType::Array(Some(Box::new((*element).into())), Some(len)),
|
||||
@ -148,16 +111,12 @@ impl Into<PartialType> for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn is_assignable_from(&self, from: &Type) -> bool {
|
||||
impl<'a> Type<'a> {
|
||||
pub fn is_assignable_from(&self, from: &Type<'a>) -> bool {
|
||||
self == from
|
||||
}
|
||||
|
||||
pub fn partial(self) -> PartialType {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn weak(self) -> WeakType {
|
||||
pub fn partial(self) -> PartialType<'a> {
|
||||
self.into()
|
||||
}
|
||||
|
||||
@ -166,7 +125,7 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Type {
|
||||
impl<'a> fmt::Display for Type<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Type::Address => write!(f, "address"),
|
||||
@ -190,7 +149,7 @@ impl fmt::Display for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PartialType {
|
||||
impl<'a> fmt::Display for PartialType<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
PartialType::Type(t) => t.fmt(f),
|
||||
@ -230,7 +189,7 @@ impl fmt::Display for PartialType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<leo_ast::Type> for &Type {
|
||||
impl<'a> Into<leo_ast::Type> for &Type<'a> {
|
||||
fn into(self) -> leo_ast::Type {
|
||||
use Type::*;
|
||||
match self {
|
||||
|
@ -14,17 +14,13 @@
|
||||
// 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::{Expression, Statement, WeakType};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use crate::{Expression, Statement, Type};
|
||||
use leo_ast::Identifier;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Specifies how a program variable was declared.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum VariableDeclaration {
|
||||
Definition,
|
||||
IterationDefinition,
|
||||
@ -33,17 +29,16 @@ pub enum VariableDeclaration {
|
||||
}
|
||||
|
||||
/// Stores information on a program variable.
|
||||
#[derive(Debug)]
|
||||
pub struct InnerVariable {
|
||||
pub id: Uuid,
|
||||
#[derive(Clone)]
|
||||
pub struct InnerVariable<'a> {
|
||||
pub id: u32,
|
||||
pub name: Identifier,
|
||||
pub type_: WeakType,
|
||||
pub type_: Type<'a>,
|
||||
pub mutable: bool,
|
||||
pub const_: bool, // only function arguments, const var definitions NOT included
|
||||
pub declaration: VariableDeclaration,
|
||||
pub references: Vec<Weak<Expression>>, // all Expression::VariableRef or panic
|
||||
pub assignments: Vec<Weak<Statement>>, // all Statement::Assign or panic -- must be 1 if not mutable, or 0 if declaration == input | parameter
|
||||
pub references: Vec<&'a Expression<'a>>, // all Expression::VariableRef or panic
|
||||
pub assignments: Vec<&'a Statement<'a>>, // all Statement::Assign or panic -- must be 1 if not mutable, or 0 if declaration == input | parameter
|
||||
}
|
||||
|
||||
pub type Variable = Arc<RefCell<InnerVariable>>;
|
||||
pub type WeakVariable = Weak<RefCell<InnerVariable>>;
|
||||
pub type Variable<'a> = RefCell<InnerVariable<'a>>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Multidimensional array syntax in leo
|
||||
function main() {
|
||||
const a: [u32; (3, 2)] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
let a: [u32; (3, 2)] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Multidimensional array syntax in leo
|
||||
function main() {
|
||||
const a: [u32; (3, 2)] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
|
||||
let a: [u32; (3, 2)] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [[u8; 2]; 3] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
let b: [[u8; 2]; 3] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [[[u8; 2]; 3]; 4] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
let b: [[[u8; 2]; 3]; 4] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [[u8; 2]; 3] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
|
||||
let b: [[u8; 2]; 3] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [[[u8; 2]; 3]; 4] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)
|
||||
let b: [[[u8; 2]; 3]; 4] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [u8; (2, 3)] = [[0; 2]; 3]; // initializer (incorrectly reversed ordering)
|
||||
let b: [u8; (2, 3)] = [[0; 2]; 3]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [u8; (2, 3)] = [[0; 3]; 2]; // initializer
|
||||
let b: [u8; (2, 3)] = [[0; 3]; 2]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [u8; (4, 3, 2)] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
let b: [u8; (4, 3, 2)] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [u8; (2, 3)] = [0; (3, 2)]; // initializer (incorrectly reversed ordering)
|
||||
let b: [u8; (2, 3)] = [0; (3, 2)]; // initializer (incorrectly reversed ordering)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [u8; (2, 3)] = [0; (2, 3)]; // initializer
|
||||
let b: [u8; (2, 3)] = [0; (2, 3)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
const b: [u8; (4, 3, 2)] = [0; (2, 3, 4)]; // initializer (incorrectly reversed order)
|
||||
let b: [u8; (4, 3, 2)] = [0; (2, 3, 4)]; // initializer (incorrectly reversed order)
|
||||
}
|
@ -3,6 +3,6 @@ function foo() -> field {
|
||||
}
|
||||
|
||||
function main() {
|
||||
const myGlobal = 42field;
|
||||
let myGlobal = 42field;
|
||||
let err = foo();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
// Constant variables are immutable by default.
|
||||
// Let variables are immutable by default.
|
||||
function main() {
|
||||
const a = 1u32;
|
||||
let a = 1u32;
|
||||
a = 0;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// Adding the `mut` keyword to a constant variable is illegal
|
||||
function main() {
|
||||
const mut a = 1u32;
|
||||
}
|
@ -28,12 +28,6 @@ fn test_const_fail() {
|
||||
load_asg(program_string).err().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_mut_fail() {
|
||||
let program_string = include_str!("const_mut.leo");
|
||||
load_asg(program_string).err().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array() {
|
||||
let program_string = include_str!("array.leo");
|
||||
|
3
asg/tests/fail/statements/const_declaration_fail.leo
Normal file
3
asg/tests/fail/statements/const_declaration_fail.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
const x = 1u32;
|
||||
}
|
@ -21,3 +21,9 @@ fn test_num_returns_fail() {
|
||||
let program_string = include_str!("num_returns_fail.leo");
|
||||
load_asg(program_string).err().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_declaration_fail() {
|
||||
let program_string = include_str!("const_declaration_fail.leo");
|
||||
load_asg(program_string).err().unwrap();
|
||||
}
|
||||
|
@ -26,20 +26,27 @@ mod pass;
|
||||
const TESTING_FILEPATH: &str = "input.leo";
|
||||
const TESTING_PROGRAM_NAME: &str = "test_program";
|
||||
|
||||
fn load_asg(program_string: &str) -> Result<Program, AsgConvertError> {
|
||||
load_asg_imports(program_string, &mut NullImportResolver)
|
||||
fn load_asg(program_string: &str) -> Result<Program<'static>, AsgConvertError> {
|
||||
load_asg_imports(make_test_context(), program_string, &mut NullImportResolver)
|
||||
}
|
||||
|
||||
fn load_asg_imports<T: ImportResolver + 'static>(
|
||||
fn load_asg_imports<'a, T: ImportResolver<'a>>(
|
||||
context: AsgContext<'a>,
|
||||
program_string: &str,
|
||||
imports: &mut T,
|
||||
) -> Result<Program, AsgConvertError> {
|
||||
) -> Result<Program<'a>, AsgConvertError> {
|
||||
let grammar = Grammar::new(Path::new(&TESTING_FILEPATH), program_string)?;
|
||||
let ast = Ast::new(TESTING_PROGRAM_NAME, &grammar)?;
|
||||
InternalProgram::new(&ast.as_repr(), imports)
|
||||
InternalProgram::new(context, &ast.as_repr(), imports)
|
||||
}
|
||||
|
||||
fn mocked_resolver() -> MockedImportResolver {
|
||||
fn mocked_resolver<'a>(_context: AsgContext<'a>) -> MockedImportResolver<'a> {
|
||||
let packages = indexmap::IndexMap::new();
|
||||
MockedImportResolver { packages }
|
||||
}
|
||||
|
||||
//convenience function for tests, leaks memory
|
||||
pub(crate) fn make_test_context() -> AsgContext<'static> {
|
||||
let allocator = Box::leak(Box::new(new_alloc_context()));
|
||||
new_context(allocator)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a: [u8; (2, 2, 2)] = [1u8; (2, 2, 2)];
|
||||
let a: [u8; (2, 2, 2)] = [1u8; (2, 2, 2)];
|
||||
|
||||
const b: [u8; (2, 2, 2)] = [[[1u8; 2]; 2]; 2];
|
||||
let b: [u8; (2, 2, 2)] = [[[1u8; 2]; 2]; 2];
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
// Multidimensional array syntax in leo
|
||||
function main() {
|
||||
const a = [[0u32, 0u32], [0u32, 0u32], [0u32, 0u32]]; // inline
|
||||
let a = [[0u32, 0u32], [0u32, 0u32], [0u32, 0u32]]; // inline
|
||||
|
||||
const b: [u32; (3, 2)] = [[0; 2]; 3]; // initializer
|
||||
let b: [u32; (3, 2)] = [[0; 2]; 3]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
// Multidimensional array syntax in leo
|
||||
function main() {
|
||||
const a = [[0u32, 0u32], [0u32, 0u32], [0u32, 0u32]]; // inline
|
||||
let a = [[0u32, 0u32], [0u32, 0u32], [0u32, 0u32]]; // inline
|
||||
|
||||
const b: [u32; (3, 2)] = [0; (3, 2)]; // initializer
|
||||
let b: [u32; (3, 2)] = [0; (3, 2)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
function main(a: [[u8; 2]; 3]) {
|
||||
const b = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let b = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
function main(a: [[[u8; 2]; 3]; 4]) {
|
||||
const b = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
let b = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
|
||||
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [[u8; 2]; 3] = [[0; 2]; 3]; // initializer
|
||||
let b: [[u8; 2]; 3] = [[0; 2]; 3]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
function main() {
|
||||
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
let a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
|
||||
|
||||
const b: [[[u8; 2]; 3]; 4] = [[[0; 2]; 3]; 4]; // initializer
|
||||
let b: [[[u8; 2]; 3]; 4] = [[[0; 2]; 3]; 4]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [[u8; 2]; 3] = [0; (3, 2)]; // initializer
|
||||
let b: [[u8; 2]; 3] = [0; (3, 2)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
function main() {
|
||||
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
let a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
|
||||
|
||||
const b: [[[u8; 2]; 3]; 4] = [0; (4, 3, 2)]; // initializer
|
||||
let b: [[[u8; 2]; 3]; 4] = [0; (4, 3, 2)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [u8; (3, 2)] = [[0; 2]; 3]; // initializer
|
||||
let b: [u8; (3, 2)] = [[0; 2]; 3]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
function main() {
|
||||
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
let a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
|
||||
|
||||
const b: [u8; (4, 3, 2)] = [[[0; 2]; 3]; 4]; // initializer
|
||||
let b: [u8; (4, 3, 2)] = [[[0; 2]; 3]; 4]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function main() {
|
||||
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
let a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
|
||||
|
||||
const b: [u8; (3, 2)] = [0; (3, 2)]; // initializer
|
||||
let b: [u8; (3, 2)] = [0; (3, 2)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
function main() {
|
||||
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
let a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
|
||||
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
|
||||
|
||||
const b: [u8; (4, 3, 2)] = [0; (4, 3, 2)]; // initializer
|
||||
let b: [u8; (4, 3, 2)] = [0; (4, 3, 2)]; // initializer
|
||||
|
||||
console.assert(a == b);
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
// !(true && (false || true))
|
||||
function main() {
|
||||
const a = true;
|
||||
const b = false || a;
|
||||
const c = !(true && b);
|
||||
let a = true;
|
||||
let b = false || a;
|
||||
let c = !(true && b);
|
||||
|
||||
console.assert(c == false);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user