Merge branch 'console-assert-error' of https://github.com/AleoHQ/leo into console-assert-error

This commit is contained in:
collin 2021-03-08 17:30:13 -08:00
commit c8d1125ad9
918 changed files with 9783 additions and 10801 deletions

View File

@ -1,5 +1,2 @@
[build]
[target.'cfg(not(target_arch = "wasm32"))']
rustflags = ["-C", "target-cpu=native"]
[net]
git-fetch-with-cli = true

View File

@ -138,6 +138,32 @@ jobs:
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:
@ -160,4 +186,10 @@ workflows:
- rust-stable
- leo-login-logout:
requires:
- rust-stable
- rust-stable
- leo-clone:
requires:
- rust-stable
- leo-publish:
requires:
- rust-stable

18
.circleci/leo-clone.sh Executable file
View 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

56
.circleci/leo-publish.sh Executable file
View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1 +1 @@
v1.2.2
v1.2.3

View File

@ -1,70 +0,0 @@
language: rust
before_install:
- set -e
- export SCCACHE_CACHE_SIZE=200M
- export SCCACHE_DIR="$TRAVIS_HOME/.cache/sccache"
- mkdir "$TRAVIS_HOME/.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 "$TRAVIS_HOME/.bin" -xvf sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz
- mv $TRAVIS_HOME/.bin/sccache-0.2.13-x86_64-unknown-linux-musl/sccache $TRAVIS_HOME/.bin/sccache
- export PATH="$PATH:$TRAVIS_HOME/.bin"
- export RUSTC_WRAPPER="sccache"
- |
declare -r SSH_FILE="$(mktemp -u $HOME/.ssh/XXXXX)"
openssl aes-256-cbc -K $encrypted_beefc4a47cdc_key -iv $encrypted_beefc4a47cdc_iv -in .travis/travis-snarkvm.enc -out $SSH_FILE -d
chmod 600 "$SSH_FILE" \
&& printf "%s\n" \
"Host github.com" \
" IdentityFile $SSH_FILE" \
" LogLevel ERROR" >> ~/.ssh/config
- git clone --progress --verbose git@github.com:AleoHQ/snarkOS.git
- mv snarkOS ..
cache:
directories:
- $TRAVIS_HOME/.cache/sccache
- $TRAVIS_HOME/.cargo
# See https://levans.fr/rust_travis_cache.html
before_cache:
- rm -rf "$TRAVIS_HOME/.cargo/registry"
after_script:
- (sccache -s||true)
- set +e
matrix:
fast_finish: true
include:
- rust: stable
env: TEST_COVERAGE=1
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- cmake
- gcc
- binutils-dev
- libiberty-dev
script:
- cargo test --all
after_success:
- wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz
- tar xzf master.tar.gz && cd kcov-master
- mkdir build && cd build && cmake .. && make && sudo make install
- cd ../.. && rm -rf kcov-master
- for file in target/debug/deps/*-*; do if [[ "$file" != *\.* ]]; then mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; fi done
- bash <(curl -s https://codecov.io/bash)
- echo "Uploaded code coverage"
- rust: nightly-2020-03-18
install:
- rustup component add rustfmt
script:
- cargo fmt -- --check
- cargo test --all
script:
- echo "leo"

Binary file not shown.

853
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "leo-lang"
version = "1.2.2"
version = "1.2.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
@ -30,64 +30,65 @@ members = [
"ast",
"compiler",
"gadgets",
"grammar",
"imports",
"input",
"linter",
"package",
"parser",
"state",
"synthesizer",
]
[dependencies.leo-ast]
path = "./ast"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-compiler]
path = "./compiler"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-gadgets]
path = "./gadgets"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-imports]
path = "./imports"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-input]
path = "./input"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-package]
path = "./package"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-state]
path = "./state"
version = "1.2.2"
version = "1.2.3"
[dependencies.leo-synthesizer]
path = "./synthesizer"
version = "1.2.3"
[dependencies.snarkvm-algorithms]
version = "0.0.4"
default-features = false
version = "0.2.0"
#default-features = false
[dependencies.snarkvm-curves]
version = "0.0.4"
default-features = false
[dependencies.snarkvm-errors]
version = "0.0.4"
version = "0.2.0"
default-features = false
[dependencies.snarkvm-gadgets]
version = "0.0.4"
version = "0.2.0"
default-features = false
[dependencies.snarkvm-models]
version = "0.0.4"
[dependencies.snarkvm-r1cs]
version = "0.2.0"
default-features = false
[dependencies.snarkvm-utilities]
version = "0.0.4"
version = "0.2.0"
[dependencies.anyhow]
version = "1.0"
@ -116,11 +117,8 @@ version = "1.4.0"
[dependencies.notify]
version = "4.0.15"
[dependencies.num-bigint]
version = "0.3"
[dependencies.rand]
version = "0.7"
version = "0.8"
[dependencies.rand_core]
version = "0.6.2"

View File

@ -1,5 +1,5 @@
<p align="center">
<img width="1412" src=".resources/banner.png">
<img width="1412" src="https://cdn.aleo.org/leo/banner.png">
</p>
<h1 align="center">The Leo Programming Language</h1>

View File

@ -1,6 +1,6 @@
[package]
name = "leo-asg"
version = "1.2.2"
version = "1.2.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "ASG of the Leo programming language"
homepage = "https://aleo.org"
@ -30,12 +30,12 @@ version = "1.6"
version = "1.0"
[dependencies.leo-ast]
version = "1.2.2"
version = "1.2.3"
path = "../ast"
[dependencies.leo-grammar]
version = "1.2.2"
path = "../grammar"
[dependencies.leo-parser]
version = "1.2.3"
path = "../parser"
[dependencies.num-bigint]
version = "0.3"

View File

@ -188,8 +188,30 @@ impl ConstInt {
const_int_map!(value_negate, x, x.checked_neg()?);
const_int_map!(value_bit_negate, x, !x);
const_int_op!(to_usize, Option<usize>, x, (*x).try_into().ok());
const_int_op!(to_u128, u128, x, *x as u128);
const_int_op!(to_u64, u64, x, *x as u64);
const_int_op!(to_u32, u32, x, *x as u32);
const_int_op!(to_u16, u16, x, *x as u16);
const_int_op!(to_u8, u8, x, *x as u8);
const_int_op!(to_i128, i128, x, *x as i128);
const_int_op!(to_i64, i64, x, *x as i64);
const_int_op!(to_i32, i32, x, *x as i32);
const_int_op!(to_i16, i16, x, *x as i16);
const_int_op!(to_i8, i8, x, *x as i8);
const_int_op!(to_string, String, x, (*x).to_string());
const_int_bimap!(value_add, x, y, x.checked_add(*y)?);
@ -226,6 +248,21 @@ impl ConstInt {
}
}
pub fn cast_to(&self, target: &IntegerType) -> ConstInt {
match target {
IntegerType::I8 => ConstInt::I8(self.to_i8()),
IntegerType::I16 => ConstInt::I16(self.to_i16()),
IntegerType::I32 => ConstInt::I32(self.to_i32()),
IntegerType::I64 => ConstInt::I64(self.to_i64()),
IntegerType::I128 => ConstInt::I128(self.to_i128()),
IntegerType::U8 => ConstInt::U8(self.to_u8()),
IntegerType::U16 => ConstInt::U16(self.to_u16()),
IntegerType::U32 => ConstInt::U32(self.to_u32()),
IntegerType::U64 => ConstInt::U64(self.to_u64()),
IntegerType::U128 => ConstInt::U128(self.to_u128()),
}
}
pub fn get_type<'a>(&self) -> Type<'a> {
Type::Integer(self.get_int_type())
}

View File

@ -17,14 +17,11 @@
//! Errors encountered when attempting to convert to an asg from an ast.
use crate::Span;
use leo_ast::{AstError, Error as FormattedError};
use leo_grammar::ParserError;
use leo_ast::{FormattedError, LeoError};
use leo_parser::SyntaxError;
#[derive(Debug, Error)]
pub enum AsgConvertError {
#[error("{}", _0)]
AstError(#[from] AstError),
#[error("{}", _0)]
Error(#[from] FormattedError),
@ -35,12 +32,32 @@ pub enum AsgConvertError {
InternalError(String),
#[error("{}", _0)]
ParserError(#[from] ParserError),
SyntaxError(#[from] SyntaxError),
}
impl LeoError for AsgConvertError {
fn get_path(&self) -> Option<&str> {
match self {
AsgConvertError::Error(error) => error.get_path(),
AsgConvertError::SyntaxError(error) => error.get_path(),
AsgConvertError::ImportError(error) => error.get_path(),
AsgConvertError::InternalError(_) => None,
}
}
fn set_path(&mut self, path: &str, contents: &[String]) {
match self {
AsgConvertError::Error(error) => error.set_path(path, contents),
AsgConvertError::SyntaxError(error) => error.set_path(path, contents),
AsgConvertError::ImportError(error) => error.set_path(path, contents),
AsgConvertError::InternalError(_) => {}
}
}
}
impl AsgConvertError {
fn new_from_span(message: String, span: &Span) -> Self {
AsgConvertError::Error(FormattedError::new_from_span(message, span.clone()))
AsgConvertError::Error(FormattedError::new_from_span(message, span))
}
pub fn unresolved_circuit(name: &str, span: &Span) -> Self {
@ -227,6 +244,10 @@ impl AsgConvertError {
Self::new_from_span(format!("failed to parse int value '{}'", value), span)
}
pub fn unsigned_negation(span: &Span) -> Self {
Self::new_from_span("cannot negate unsigned integer".to_string(), span)
}
pub fn immutable_assignment(name: &str, span: &Span) -> Self {
Self::new_from_span(format!("illegal assignment to immutable variable '{}'", name), span)
}
@ -256,6 +277,14 @@ impl AsgConvertError {
)
}
pub fn call_test_function(span: &Span) -> Self {
Self::new_from_span("cannot call test function".to_string(), span)
}
pub fn circuit_test_function(span: &Span) -> Self {
Self::new_from_span("cannot have test function as member of circuit".to_string(), span)
}
pub fn parse_index_error() -> Self {
AsgConvertError::InternalError("failed to parse index".to_string())
}

View File

@ -114,7 +114,28 @@ impl<'a> FromAst<'a, leo_ast::ArrayInlineExpression> for ArrayInlineExpression<'
}
};
// 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 <&Expression<'a>>::from_ast(scope, e, expected_item.clone()) {
Ok(expr) => expr.get_type().map(Type::partial),
Err(_) => continue,
}
}
_ => None,
};
if expected_item.is_some() {
break;
}
}
}
let mut len = 0;
let output = ArrayInlineExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),

View File

@ -109,7 +109,7 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
return Err(AsgConvertError::unexpected_type(
"circuit",
type_.map(|x| x.to_string()).as_deref(),
&span,
span,
));
}
};
@ -117,26 +117,26 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
let member = circuit.members.borrow();
let member = member
.get(&name.name)
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, &span))?;
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {
if body.qualifier == FunctionQualifier::Static {
return Err(AsgConvertError::circuit_static_call_invalid(
&circuit_name,
&name.name,
&span,
span,
));
} else if body.qualifier == FunctionQualifier::MutSelfRef && !target.is_mut_ref() {
return Err(AsgConvertError::circuit_member_mut_call_invalid(
&circuit_name,
&name.name,
&span,
span,
));
}
(Some(target), *body)
}
CircuitMember::Variable(_) => {
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span));
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, span));
}
}
}
@ -150,27 +150,27 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
.resolve_circuit(&circuit_name.name)
.ok_or_else(|| AsgConvertError::unresolved_circuit(&circuit_name.name, &circuit_name.span))?
} else {
return Err(AsgConvertError::unexpected_type("circuit", None, &span));
return Err(AsgConvertError::unexpected_type("circuit", None, span));
};
let circuit_name = circuit.name.borrow().name.clone();
let member = circuit.members.borrow();
let member = member
.get(&name.name)
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, &span))?;
.ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {
if body.qualifier != FunctionQualifier::Static {
return Err(AsgConvertError::circuit_member_call_invalid(
&circuit_name,
&name.name,
&span,
span,
));
}
(None, *body)
}
CircuitMember::Variable(_) => {
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, &span));
return Err(AsgConvertError::circuit_variable_call(&circuit_name, &name.name, span));
}
}
}
@ -206,12 +206,15 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
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()));
return Err(AsgConvertError::unexpected_nonconst(expr.span()));
}
Ok(Cell::new(converted))
})
.collect::<Result<Vec<_>, AsgConvertError>>()?;
if function.is_test() {
return Err(AsgConvertError::call_test_function(&value.span));
}
Ok(CallExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),

109
asg/src/expression/cast.rs Normal file
View File

@ -0,0 +1,109 @@
// 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::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
pub use leo_ast::UnaryOperation;
use std::cell::Cell;
#[derive(Clone)]
pub struct CastExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub inner: Cell<&'a Expression<'a>>,
pub target_type: Type<'a>,
}
impl<'a> Node for CastExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for CastExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.inner.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
Some(self.target_type.clone())
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue> {
let value = self.inner.get().const_value()?;
match value {
ConstValue::Int(int) => match &self.target_type {
Type::Integer(target) => Some(ConstValue::Int(int.cast_to(target))),
_ => None,
},
_ => None,
}
}
fn is_consty(&self) -> bool {
self.inner.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::CastExpression> for CastExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::CastExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<CastExpression<'a>, AsgConvertError> {
let target_type = scope.resolve_ast_type(&value.target_type)?;
if let Some(expected_type) = &expected_type {
if !expected_type.matches(&target_type) {
return Err(AsgConvertError::unexpected_type(
&expected_type.to_string(),
Some(&target_type.to_string()),
&value.span,
));
}
}
let inner = <&Expression<'a>>::from_ast(scope, &*value.inner, None)?;
Ok(CastExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
inner: Cell::new(inner),
target_type,
})
}
}
impl<'a> Into<leo_ast::CastExpression> for &CastExpression<'a> {
fn into(self) -> leo_ast::CastExpression {
leo_ast::CastExpression {
target_type: (&self.target_type).into(),
inner: Box::new(self.inner.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -99,10 +99,10 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'
));
}
}
let members: IndexMap<&String, (&Identifier, &leo_ast::Expression)> = value
let members: IndexMap<&String, (&Identifier, Option<&leo_ast::Expression>)> = value
.members
.iter()
.map(|x| (&x.identifier.name, (&x.identifier, &x.expression)))
.map(|x| (&x.identifier.name, (&x.identifier, x.expression.as_ref())))
.collect();
let mut values: Vec<(Identifier, Cell<&'a Expression<'a>>)> = vec![];
@ -125,7 +125,15 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'
continue;
};
if let Some((identifier, receiver)) = members.get(&name) {
let received = <&Expression<'a>>::from_ast(scope, *receiver, Some(type_.partial()))?;
let received = if let Some(receiver) = *receiver {
<&Expression<'a>>::from_ast(scope, receiver, Some(type_.partial()))?
} else {
<&Expression<'a>>::from_ast(
scope,
&leo_ast::Expression::Identifier((*identifier).clone()),
Some(type_.partial()),
)?
};
values.push(((*identifier).clone(), Cell::new(received)));
} else {
return Err(AsgConvertError::missing_circuit_member(
@ -165,7 +173,7 @@ impl<'a> Into<leo_ast::CircuitInitExpression> for &CircuitInitExpression<'a> {
.iter()
.map(|(name, value)| leo_ast::CircuitImpliedVariableDefinition {
identifier: name.clone(),
expression: value.get().into(),
expression: Some(value.get().into()),
})
.collect(),
span: self.span.clone().unwrap_or_default(),

View File

@ -62,6 +62,9 @@ pub use unary::*;
mod variable_ref;
pub use variable_ref::*;
mod cast;
pub use cast::*;
use crate::{AsgConvertError, ConstValue, FromAst, Node, PartialType, Scope, Span, Type};
#[derive(Clone)]
@ -71,6 +74,7 @@ pub enum Expression<'a> {
Binary(BinaryExpression<'a>),
Unary(UnaryExpression<'a>),
Ternary(TernaryExpression<'a>),
Cast(CastExpression<'a>),
ArrayInline(ArrayInlineExpression<'a>),
ArrayInit(ArrayInitExpression<'a>),
@ -95,6 +99,7 @@ impl<'a> Node for Expression<'a> {
Binary(x) => x.span(),
Unary(x) => x.span(),
Ternary(x) => x.span(),
Cast(x) => x.span(),
ArrayInline(x) => x.span(),
ArrayInit(x) => x.span(),
ArrayAccess(x) => x.span(),
@ -128,6 +133,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.set_parent(parent),
Unary(x) => x.set_parent(parent),
Ternary(x) => x.set_parent(parent),
Cast(x) => x.set_parent(parent),
ArrayInline(x) => x.set_parent(parent),
ArrayInit(x) => x.set_parent(parent),
ArrayAccess(x) => x.set_parent(parent),
@ -148,6 +154,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.get_parent(),
Unary(x) => x.get_parent(),
Ternary(x) => x.get_parent(),
Cast(x) => x.get_parent(),
ArrayInline(x) => x.get_parent(),
ArrayInit(x) => x.get_parent(),
ArrayAccess(x) => x.get_parent(),
@ -168,6 +175,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.enforce_parents(expr),
Unary(x) => x.enforce_parents(expr),
Ternary(x) => x.enforce_parents(expr),
Cast(x) => x.enforce_parents(expr),
ArrayInline(x) => x.enforce_parents(expr),
ArrayInit(x) => x.enforce_parents(expr),
ArrayAccess(x) => x.enforce_parents(expr),
@ -188,6 +196,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.get_type(),
Unary(x) => x.get_type(),
Ternary(x) => x.get_type(),
Cast(x) => x.get_type(),
ArrayInline(x) => x.get_type(),
ArrayInit(x) => x.get_type(),
ArrayAccess(x) => x.get_type(),
@ -208,6 +217,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.is_mut_ref(),
Unary(x) => x.is_mut_ref(),
Ternary(x) => x.is_mut_ref(),
Cast(x) => x.is_mut_ref(),
ArrayInline(x) => x.is_mut_ref(),
ArrayInit(x) => x.is_mut_ref(),
ArrayAccess(x) => x.is_mut_ref(),
@ -228,6 +238,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.const_value(),
Unary(x) => x.const_value(),
Ternary(x) => x.const_value(),
Cast(x) => x.const_value(),
ArrayInline(x) => x.const_value(),
ArrayInit(x) => x.const_value(),
ArrayAccess(x) => x.const_value(),
@ -248,6 +259,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Binary(x) => x.is_consty(),
Unary(x) => x.is_consty(),
Ternary(x) => x.is_consty(),
Cast(x) => x.is_consty(),
ArrayInline(x) => x.is_consty(),
ArrayInit(x) => x.is_consty(),
ArrayAccess(x) => x.is_consty(),
@ -281,6 +293,9 @@ impl<'a> FromAst<'a, leo_ast::Expression> for &'a Expression<'a> {
Ternary(conditional) => scope.alloc_expression(
TernaryExpression::from_ast(scope, conditional, expected_type).map(Expression::Ternary)?,
),
Cast(cast) => {
scope.alloc_expression(CastExpression::from_ast(scope, cast, expected_type).map(Expression::Cast)?)
}
ArrayInline(array_inline) => scope.alloc_expression(
ArrayInlineExpression::from_ast(scope, array_inline, expected_type).map(Expression::ArrayInline)?,
@ -333,6 +348,7 @@ impl<'a> Into<leo_ast::Expression> for &Expression<'a> {
Binary(x) => leo_ast::Expression::Binary(x.into()),
Unary(x) => leo_ast::Expression::Unary(x.into()),
Ternary(x) => leo_ast::Expression::Ternary(x.into()),
Cast(x) => leo_ast::Expression::Cast(x.into()),
ArrayInline(x) => leo_ast::Expression::ArrayInline(x.into()),
ArrayInit(x) => leo_ast::Expression::ArrayInit(x.into()),
ArrayAccess(x) => leo_ast::Expression::ArrayAccess(x.into()),

View File

@ -69,6 +69,10 @@ impl<'a> ExpressionNode<'a> for UnaryExpression<'a> {
_ => None,
}
}
UnaryOperation::BitNot => match inner {
ConstValue::Int(value) => Some(ConstValue::Int(value.value_bit_negate()?)),
_ => None,
},
}
} else {
None
@ -110,16 +114,37 @@ impl<'a> FromAst<'a, leo_ast::UnaryExpression> for UnaryExpression<'a> {
));
}
},
UnaryOperation::BitNot => match expected_type.map(|x| x.full()).flatten() {
Some(type_ @ Type::Integer(_)) => Some(type_),
None => None,
Some(type_) => {
return Err(AsgConvertError::unexpected_type(
&type_.to_string(),
Some("integer"),
&value.span,
));
}
},
};
let expr = <&Expression<'a>>::from_ast(scope, &*value.inner, expected_type.map(Into::into))?;
if matches!(value.op, UnaryOperation::Negate) {
let is_expr_unsigned = expr
.get_type()
.map(|x| match x {
Type::Integer(x) => !x.is_signed(),
_ => false,
})
.unwrap_or(false);
if is_expr_unsigned {
return Err(AsgConvertError::unsigned_negation(&value.span));
}
}
Ok(UnaryExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
operation: value.op.clone(),
inner: Cell::new(<&Expression<'a>>::from_ast(
scope,
&*value.inner,
expected_type.map(Into::into),
)?),
inner: Cell::new(expr),
})
}
}

View File

@ -76,8 +76,6 @@ pub use context::*;
pub use leo_ast::{Ast, Identifier, Span};
use std::path::Path;
/// The abstract semantic graph (ASG) for a Leo program.
///
/// The [`Asg`] type represents a Leo program as a series of recursive data types.
@ -92,14 +90,14 @@ pub struct Asg<'a> {
impl<'a> Asg<'a> {
/// Creates a new ASG from a given AST and import resolver.
pub fn new<T: ImportResolver<'a>>(
pub fn new<T: ImportResolver<'a>, Y: AsRef<leo_ast::Program>>(
context: AsgContext<'a>,
ast: &Ast,
ast: Y,
resolver: &mut T,
) -> Result<Self, AsgConvertError> {
Ok(Self {
context,
asg: InternalProgram::new(context, &ast.as_repr(), resolver)?,
asg: InternalProgram::new(context, ast.as_ref(), resolver)?,
})
}
@ -127,10 +125,9 @@ pub fn load_asg<'a, T: ImportResolver<'a>>(
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)))?;
let ast = leo_parser::parse_ast("input.leo", content)?;
InternalProgram::new(context, leo_ast::Ast::new("load_ast", &ast)?.as_repr(), resolver)
InternalProgram::new(context, ast.as_repr(), resolver)
}
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::Program;
pub use leo_ast::Error as FormattedError;
pub use leo_ast::FormattedError;
pub trait AsgPass {
fn do_pass(asg: &Program) -> Result<(), FormattedError>;

View File

@ -92,6 +92,9 @@ impl<'a> Circuit<'a> {
}
let asg_function = Function::init(new_scope, function)?;
asg_function.circuit.replace(Some(circuit));
if asg_function.is_test() {
return Err(AsgConvertError::circuit_test_function(&function.identifier.span));
}
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
}
}

View File

@ -29,6 +29,7 @@ use crate::{
Variable,
};
use indexmap::IndexMap;
pub use leo_ast::Annotation;
use leo_ast::FunctionInput;
use std::cell::{Cell, RefCell};
@ -52,6 +53,7 @@ pub struct Function<'a> {
pub body: Cell<Option<&'a Statement<'a>>>,
pub scope: &'a Scope<'a>,
pub qualifier: FunctionQualifier,
pub annotations: Vec<Annotation>,
}
impl<'a> PartialEq for Function<'a> {
@ -126,6 +128,7 @@ impl<'a> Function<'a> {
qualifier,
scope: new_scope,
span: Some(value.span.clone()),
annotations: value.annotations.clone(),
});
function.scope.function.replace(Some(function));
@ -177,6 +180,10 @@ impl<'a> Function<'a> {
Ok(())
}
pub fn is_test(&self) -> bool {
self.annotations.iter().any(|x| x.name.name == "test")
}
}
impl<'a> Into<leo_ast::Function> for &Function<'a> {
@ -213,6 +220,7 @@ impl<'a> Into<leo_ast::Function> for &Function<'a> {
block: body,
output: Some((&output).into()),
span,
annotations: self.annotations.clone(),
}
}
}

View File

@ -45,9 +45,6 @@ pub struct InternalProgram<'a> {
/// these should generally not be accessed directly, but through scoped imports
pub imported_modules: IndexMap<String, Program<'a>>,
/// Maps test name => test code block.
pub test_functions: IndexMap<String, (&'a Function<'a>, Option<Identifier>)>, // identifier = test input file
/// Maps function name => function code block.
pub functions: IndexMap<String, &'a Function<'a>>,
@ -248,14 +245,6 @@ impl<'a> InternalProgram<'a> {
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 = Function::init(scope, &test_function.function)?;
proto_test_functions.insert(name.name.clone(), function);
}
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let function = Function::init(scope, function)?;
@ -264,16 +253,6 @@ impl<'a> InternalProgram<'a> {
}
// Load concrete definitions.
let mut test_functions = IndexMap::new();
for (name, test_function) in program.tests.iter() {
assert_eq!(name.name, test_function.function.identifier.name);
let function = proto_test_functions.get(&name.name).unwrap();
function.fill_from_ast(&test_function.function)?;
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);
@ -298,7 +277,6 @@ impl<'a> InternalProgram<'a> {
context,
id: context.get_id(),
name: program.name.clone(),
test_functions,
functions,
circuits,
imported_modules: resolved_packages
@ -350,7 +328,6 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
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() {
for (name, circuit) in program.circuits.iter() {
@ -367,11 +344,6 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
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.name.borrow_mut().name = identifier.clone();
all_test_functions.insert(identifier, function.clone());
}
}
leo_ast::Program {
@ -388,15 +360,6 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
})
.collect(),
expected_input: vec![],
tests: all_test_functions
.into_iter()
.map(|(_, (function, ident))| {
(function.name.borrow().clone(), leo_ast::TestFunction {
function: function.into(),
input_file: ident,
})
})
.collect(),
functions: all_functions
.into_iter()
.map(|(_, function)| (function.name.borrow().clone(), function.into()))
@ -424,16 +387,6 @@ impl<'a> Into<leo_ast::Program> for &InternalProgram<'a> {
.iter()
.map(|(_, function)| (function.name.borrow().clone(), (*function).into()))
.collect(),
tests: self
.test_functions
.iter()
.map(|(_, function)| {
(function.0.name.borrow().clone(), leo_ast::TestFunction {
function: function.0.into(),
input_file: function.1.clone(),
})
})
.collect(),
}
}
}

View File

@ -47,6 +47,7 @@ impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T,
Expression::CircuitAccess(e) => self.reduce_circuit_access(e),
Expression::CircuitInit(e) => self.reduce_circuit_init(e),
Expression::Ternary(e) => self.reduce_ternary_expression(e),
Expression::Cast(e) => self.reduce_cast_expression(e),
Expression::Constant(e) => self.reduce_constant(e),
Expression::TupleAccess(e) => self.reduce_tuple_access(e),
Expression::TupleInit(e) => self.reduce_tuple_init(e),
@ -131,6 +132,12 @@ impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T,
.reduce_ternary_expression(input, condition, if_true, if_false)
}
pub fn reduce_cast_expression(&mut self, input: &CastExpression<'a>) -> T {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_cast_expression(input, inner)
}
pub fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
self.reducer.reduce_constant(input)
}
@ -299,15 +306,10 @@ impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R>
.iter()
.map(|(_, import)| self.reduce_program(import))
.collect();
let test_functions = input
.test_functions
.iter()
.map(|(_, (f, _))| self.reduce_function(f))
.collect();
let functions = input.functions.iter().map(|(_, f)| self.reduce_function(f)).collect();
let circuits = input.circuits.iter().map(|(_, c)| self.reduce_circuit(c)).collect();
self.reducer
.reduce_program(&input, imported_modules, test_functions, functions, circuits)
.reduce_program(&input, imported_modules, functions, circuits)
}
}

View File

@ -64,6 +64,10 @@ pub trait MonoidalReducerExpression<'a, T: Monoid> {
condition.append(if_true).append(if_false)
}
fn reduce_cast_expression(&mut self, input: &CastExpression<'a>, inner: T) -> T {
inner
}
fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
T::default()
}
@ -157,13 +161,11 @@ pub trait MonoidalReducerProgram<'a, T: Monoid>: MonoidalReducerStatement<'a, T>
&mut self,
input: &InternalProgram,
imported_modules: Vec<T>,
test_functions: Vec<T>,
functions: Vec<T>,
circuits: Vec<T>,
) -> T {
T::default()
.append_all(imported_modules.into_iter())
.append_all(test_functions.into_iter())
.append_all(functions.into_iter())
.append_all(circuits.into_iter())
}

View File

@ -72,6 +72,10 @@ pub trait ExpressionVisitor<'a> {
Default::default()
}
fn visit_cast_expression(&mut self, input: &CastExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_constant(&mut self, input: &Constant<'a>) -> VisitResult {
Default::default()
}

View File

@ -60,6 +60,7 @@ impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
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::Cast(e) => self.visit_cast_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),
@ -71,10 +72,7 @@ impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
}
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,
};
let interior = input.get().map(Cell::new);
if let Some(interior) = interior.as_ref() {
let result = self.visit_expression(interior);
input.replace(Some(interior.get()));
@ -187,6 +185,16 @@ impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
}
}
pub fn visit_cast_expression(&mut self, input: &CastExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_cast_expression(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.inner)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_constant(&mut self, input: &Constant<'a>) -> ConcreteVisitResult {
self.visitor.visit_constant(input).into()
}
@ -246,10 +254,7 @@ impl<'a, R: StatementVisitor<'a>> VisitorDirector<'a, R> {
}
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,
};
let interior = input.get().map(Cell::new);
if let Some(interior) = interior.as_ref() {
let result = self.visit_statement(interior);
input.replace(Some(interior.get()));
@ -425,9 +430,6 @@ impl<'a, R: ProgramVisitor<'a>> VisitorDirector<'a, R> {
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)?;
}

View File

@ -72,10 +72,10 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
let variable = if name == "input" {
if let Some(function) = scope.resolve_current_function() {
if !function.has_input {
return Err(AsgConvertError::unresolved_reference(name, span));
return Err(AsgConvertError::unresolved_reference(name, &span));
}
} else {
return Err(AsgConvertError::unresolved_reference(name, span));
return Err(AsgConvertError::unresolved_reference(name, &span));
}
if let Some(input) = scope.resolve_input() {
input.container
@ -87,7 +87,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
} else {
scope
.resolve_variable(&name)
.ok_or_else(|| AsgConvertError::unresolved_reference(name, span))?
.ok_or_else(|| AsgConvertError::unresolved_reference(name, &span))?
};
if !variable.borrow().mutable {

View File

@ -15,15 +15,14 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{AsgConvertError, Expression, FromAst, Node, PartialType, Scope, Span, Statement, Type};
use leo_ast::ConsoleFunction as AstConsoleFunction;
use leo_ast::{ConsoleFunction as AstConsoleFunction, FormattedStringPart};
use std::cell::Cell;
// TODO (protryon): Refactor to not require/depend on span
#[derive(Clone)]
pub struct FormattedString<'a> {
pub string: String,
pub containers: Vec<Span>,
pub parts: Vec<FormattedStringPart>,
pub parameters: Vec<Cell<&'a Expression<'a>>>,
pub span: Span,
}
@ -55,10 +54,15 @@ impl<'a> FromAst<'a, leo_ast::FormattedString> for FormattedString<'a> {
value: &leo_ast::FormattedString,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self, AsgConvertError> {
if value.parameters.len() != value.containers.len() {
let expected_param_len = value
.parts
.iter()
.filter(|x| matches!(x, FormattedStringPart::Container))
.count();
if value.parameters.len() != expected_param_len {
// + 1 for formatting string as to not confuse user
return Err(AsgConvertError::unexpected_call_argument_count(
value.containers.len() + 1,
expected_param_len + 1,
value.parameters.len() + 1,
&value.span,
));
@ -68,8 +72,7 @@ impl<'a> FromAst<'a, leo_ast::FormattedString> for FormattedString<'a> {
parameters.push(Cell::new(<&Expression<'a>>::from_ast(scope, parameter, None)?));
}
Ok(FormattedString {
string: value.string.clone(),
containers: value.containers.iter().map(|x| x.span.clone()).collect(),
parts: value.parts.clone(),
parameters,
span: value.span.clone(),
})
@ -79,12 +82,7 @@ impl<'a> FromAst<'a, leo_ast::FormattedString> for FormattedString<'a> {
impl<'a> Into<leo_ast::FormattedString> for &FormattedString<'a> {
fn into(self) -> leo_ast::FormattedString {
leo_ast::FormattedString {
string: self.string.clone(),
containers: self
.containers
.iter()
.map(|span| leo_ast::FormattedContainer { span: span.clone() })
.collect(),
parts: self.parts.clone(),
parameters: self.parameters.iter().map(|e| e.get().into()).collect(),
span: self.span.clone(),
}

View File

@ -28,7 +28,6 @@ use crate::{
Type,
Variable,
};
use leo_ast::{AstError, DeprecatedError};
use std::cell::{Cell, RefCell};
@ -90,11 +89,6 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
}
for (variable, type_) in statement.variable_names.iter().zip(output_types.into_iter()) {
if statement.declaration_type == leo_ast::Declare::Const {
return Err(AsgConvertError::AstError(AstError::DeprecatedError(
DeprecatedError::const_statement(&statement.span),
)));
}
variables.push(&*scope.alloc_variable(RefCell::new(InnerVariable {
id: scope.context.get_id(),
name: variable.identifier.clone(),

View File

@ -123,6 +123,10 @@ impl<'a> Type<'a> {
pub fn is_unit(&self) -> bool {
matches!(self, Type::Tuple(t) if t.is_empty())
}
pub fn can_cast_to(&self, to: &Type<'a>) -> bool {
matches!(self, Type::Integer(_)) && matches!(to, Type::Integer(_))
}
}
impl<'a> fmt::Display for Type<'a> {

View File

@ -15,16 +15,12 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_asg::*;
use leo_ast::Ast;
use leo_grammar::Grammar;
use std::path::Path;
use leo_parser::parse_ast;
mod fail;
mod pass;
const TESTING_FILEPATH: &str = "input.leo";
const TESTING_PROGRAM_NAME: &str = "test_program";
fn load_asg(program_string: &str) -> Result<Program<'static>, AsgConvertError> {
load_asg_imports(make_test_context(), program_string, &mut NullImportResolver)
@ -35,8 +31,7 @@ fn load_asg_imports<'a, T: ImportResolver<'a>>(
program_string: &str,
imports: &mut T,
) -> Result<Program<'a>, AsgConvertError> {
let grammar = Grammar::new(Path::new(&TESTING_FILEPATH), program_string)?;
let ast = Ast::new(TESTING_PROGRAM_NAME, &grammar)?;
let ast = parse_ast(&TESTING_FILEPATH, program_string)?;
InternalProgram::new(context, &ast.as_repr(), imports)
}

View File

@ -2,7 +2,7 @@ function main(s: bool, c: address) {
let a = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
let b = address(aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r);
let r = if s? a: b;
let r = s? a: b;
console.assert(r == c);
}

View File

@ -0,0 +1,6 @@
function main(){
let a = [1u8, 2u8, 3u8, 4];
let b = [1u8, 2u8, 3, 4u8];
let c = [1u8, 2, 3u8, 4u8];
let d = [1, 2u8, 3u8, 4u8];
}

View File

@ -104,6 +104,12 @@ fn test_slice_lower() {
load_asg(program_string).unwrap();
}
#[test]
fn test_implicit() {
let program_string = include_str!("implicit.leo");
load_asg(program_string).unwrap();
}
#[test]
fn test_type_nested_value_nested_3x2() {
let program_string = include_str!("type_nested_value_nested_3x2.leo");

View File

@ -8,7 +8,7 @@ circuit PedersenHash {
function hash(self, bits: [bool; 512]) -> u32 {
let mut digest: u32 = 0;
for i in 0..512 {
let base = if bits[i] ? self.parameters[i] : 0u32;
let base = bits[i] ? self.parameters[i] : 0u32;
digest += base;
}
return digest

View File

@ -1,5 +1,5 @@
function main(s: bool, a: field, b: field, c: field) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -15,10 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{load_asg, make_test_context};
use leo_ast::Ast;
use leo_grammar::Grammar;
use std::path::Path;
use leo_parser::parse_ast;
#[test]
fn test_basic() {
@ -56,6 +53,7 @@ fn test_function_rename() {
#[test]
fn test_imports() {
let import_name = "test-import".to_string();
let context = make_test_context();
let mut imports = crate::mocked_resolver(&context);
let test_import = r#"
@ -70,7 +68,7 @@ fn test_imports() {
"#;
imports
.packages
.insert("test-import".to_string(), load_asg(test_import).unwrap());
.insert(import_name.clone(), load_asg(test_import).unwrap());
let program_string = r#"
import test-import.foo;
@ -79,17 +77,11 @@ fn test_imports() {
}
"#;
let test_import_grammar = Grammar::new(Path::new("test-import.leo"), test_import).unwrap();
println!(
"{}",
serde_json::to_string(Ast::new("test-import", &test_import_grammar).unwrap().as_repr()).unwrap()
);
let test_import_ast = parse_ast(&import_name, test_import).unwrap();
println!("{}", serde_json::to_string(test_import_ast.as_repr()).unwrap());
let test_grammar = Grammar::new(Path::new("test.leo"), program_string).unwrap();
println!(
"{}",
serde_json::to_string(Ast::new("test", &test_grammar).unwrap().as_repr()).unwrap()
);
let test_ast = parse_ast("test.leo", program_string).unwrap();
println!("{}", serde_json::to_string(test_ast.as_repr()).unwrap());
let asg = crate::load_asg_imports(&context, program_string, &mut imports).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);

View File

@ -1,5 +1,5 @@
function main(s: bool, a: group, b: group, c: group) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: i128, b: i128, c: i128) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: i16, b: i16, c: i16) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: i32, b: i32, c: i32) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: i64, b: i64, c: i64) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: i8, b: i8, c: i8) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: u128, b: u128, c: u128) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: u16, b: u16, c: u16) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: u32, b: u32, c: u32) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: u64, b: u64, c: u64) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -1,5 +1,5 @@
function main(s: bool, a: u8, b: u8, c: u8) {
let r = if s ? a : b;
let r = s ? a : b;
console.assert(r == c);
}

View File

@ -7,7 +7,7 @@ function main(a: bool) {
}
}
let r: u32 = if a ? 6 : 0;
let r: u32 = a ? 6 : 0;
console.assert(r == b);
}

View File

@ -1,5 +1,5 @@
function main(a: bool, b: bool) {
let c = if a ? true : false;
let c = a ? true : false;
let d = c == b;
}

View File

@ -1,6 +1,6 @@
[package]
name = "leo-ast"
version = "1.2.2"
version = "1.2.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Core AST of the Leo programming language"
homepage = "https://aleo.org"
@ -17,22 +17,9 @@ include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
[[bin]]
name = "leo_ast"
path = "src/main.rs"
[[bench]]
name = "leo_ast"
path = "benches/leo_ast.rs"
harness = false
[dependencies.leo-grammar]
path = "../grammar"
version = "1.2.2"
[dependencies.leo-input]
path = "../input"
version = "1.2.2"
version = "1.2.3"
[dependencies.indexmap]
version = "1.6.1"
@ -43,6 +30,7 @@ version = "2.0"
[dependencies.serde]
version = "1.0"
features = ["derive", "rc"]
[dependencies.serde_json]
version = "1.0"
@ -55,4 +43,4 @@ version = "0.3"
[features]
default = [ ]
ci_skip = [ "leo-grammar/ci_skip" ]
ci_skip = [ ]

View File

@ -14,84 +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::{Circuit, DeprecatedError, Function, FunctionInput, Identifier, ImportStatement, TestFunction};
use leo_grammar::{
annotations::{Annotation, AnnotationArguments, AnnotationName},
definitions::{AnnotatedDefinition, Definition},
};
use crate::{Identifier, Span};
use std::convert::TryFrom;
use serde::{Deserialize, Serialize};
use indexmap::IndexMap;
pub fn load_annotation(
annotated_definition: AnnotatedDefinition,
_imports: &mut Vec<ImportStatement>,
_circuits: &mut IndexMap<Identifier, Circuit>,
_functions: &mut IndexMap<Identifier, Function>,
tests: &mut IndexMap<Identifier, TestFunction>,
_expected: &mut Vec<FunctionInput>,
) -> Result<(), DeprecatedError> {
let ast_annotation = annotated_definition.annotation;
let ast_definition = *annotated_definition.definition;
match ast_definition {
Definition::Import(_) => {
unimplemented!("annotated imports are not supported yet");
}
Definition::Circuit(_) => {
unimplemented!("annotated circuits are not supported yet");
}
Definition::Function(function) => match ast_annotation.name {
// If it's deprecated for more than one type of syntax,
// we could just call it before the match on ast_definition.
AnnotationName::Context(_) => Err(DeprecatedError::try_from(ast_annotation.name).unwrap()),
AnnotationName::Test(_) => {
let ident = Identifier::from(function.identifier.clone());
_functions.remove(&ident);
let test_function = leo_grammar::functions::TestFunction::from(function);
let test = TestFunction::from(test_function);
tests.insert(ident, test.clone());
load_annotated_test(test, ast_annotation, tests);
Ok(())
}
},
Definition::Deprecated(_) => Ok(()),
Definition::Annotated(_) => {
unimplemented!("nested annotations are not supported yet");
}
}
}
pub fn load_annotated_test(test: TestFunction, annotation: Annotation, tests: &mut IndexMap<Identifier, TestFunction>) {
let name = annotation.name;
let ast_arguments = annotation.arguments;
match name {
AnnotationName::Test(_) if ast_arguments.is_some() => {
load_annotated_test_context(test, ast_arguments.unwrap(), tests)
}
_ => (),
}
}
pub fn load_annotated_test_context(
mut test: TestFunction,
ast_arguments: AnnotationArguments,
tests: &mut IndexMap<Identifier, TestFunction>,
) {
let arguments = ast_arguments.arguments;
if arguments.len() != 1 {
panic!("text context annotation must have one argument identifier")
}
let ast_input_file = arguments[0].to_owned();
let input_file = Identifier::from(ast_input_file);
test.input_file = Some(input_file);
tests.insert(test.function.identifier.clone(), test);
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Annotation {
pub span: Span,
pub name: Identifier,
pub arguments: Vec<String>,
}

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{CircuitMember, Identifier};
use leo_grammar::circuits::Circuit as GrammarCircuit;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -26,15 +25,6 @@ pub struct Circuit {
pub members: Vec<CircuitMember>,
}
impl<'ast> From<GrammarCircuit<'ast>> for Circuit {
fn from(circuit: GrammarCircuit<'ast>) -> Self {
let circuit_name = Identifier::from(circuit.identifier);
let members = circuit.members.into_iter().map(CircuitMember::from).collect();
Self { circuit_name, members }
}
}
impl Circuit {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "circuit {} {{ ", self.circuit_name)?;

View File

@ -15,27 +15,11 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Identifier};
use leo_grammar::circuits::CircuitImpliedVariable;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitImpliedVariableDefinition {
pub identifier: Identifier,
pub expression: Expression,
}
impl<'ast> From<CircuitImpliedVariable<'ast>> for CircuitImpliedVariableDefinition {
fn from(member: CircuitImpliedVariable<'ast>) -> Self {
match member {
CircuitImpliedVariable::CircuitVariable(circuit_variable) => Self {
identifier: Identifier::from(circuit_variable.identifier),
expression: Expression::from(circuit_variable.expression),
},
CircuitImpliedVariable::Identifier(identifier) => Self {
identifier: Identifier::from(identifier.clone()),
expression: Expression::from(identifier),
},
}
}
pub expression: Option<Expression>,
}

View File

@ -15,10 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Function, Identifier, Type};
use leo_grammar::{
circuits::{CircuitMember as GrammarCircuitMember, CircuitVariableDefinition as GrammarCircuitVariableDefinition},
functions::Function as GrammarFunction,
};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -31,30 +27,6 @@ pub enum CircuitMember {
CircuitFunction(Function),
}
impl<'ast> From<GrammarCircuitVariableDefinition<'ast>> for CircuitMember {
fn from(circuit_value: GrammarCircuitVariableDefinition<'ast>) -> Self {
CircuitMember::CircuitVariable(
Identifier::from(circuit_value.identifier),
Type::from(circuit_value.type_),
)
}
}
impl<'ast> From<GrammarFunction<'ast>> for CircuitMember {
fn from(circuit_function: GrammarFunction<'ast>) -> Self {
CircuitMember::CircuitFunction(Function::from(circuit_function))
}
}
impl<'ast> From<GrammarCircuitMember<'ast>> for CircuitMember {
fn from(object: GrammarCircuitMember<'ast>) -> Self {
match object {
GrammarCircuitMember::CircuitVariableDefinition(circuit_value) => CircuitMember::from(circuit_value),
GrammarCircuitMember::CircuitFunction(circuit_function) => CircuitMember::from(circuit_function),
}
}
}
impl fmt::Display for CircuitMember {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Identifier};
use leo_grammar::circuits::CircuitVariable;
use serde::{Deserialize, Serialize};
@ -24,12 +23,3 @@ pub struct CircuitVariableDefinition {
pub identifier: Identifier,
pub expression: Expression,
}
impl<'ast> From<CircuitVariable<'ast>> for CircuitVariableDefinition {
fn from(member: CircuitVariable<'ast>) -> Self {
CircuitVariableDefinition {
identifier: Identifier::from(member.identifier),
expression: Expression::from(member.expression),
}
}
}

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::PositiveNumber;
use leo_grammar::types::ArrayDimensions as GrammarArrayDimensions;
use leo_input::types::ArrayDimensions as InputArrayDimensions;
use serde::{Deserialize, Serialize};
@ -104,18 +103,6 @@ impl ArrayDimensions {
}
}
/// Create a new [`ArrayDimensions`] from a [`GrammarArrayDimensions`] in a Leo program file.
impl<'ast> From<GrammarArrayDimensions<'ast>> for ArrayDimensions {
fn from(dimensions: GrammarArrayDimensions<'ast>) -> Self {
Self(match dimensions {
GrammarArrayDimensions::Single(single) => vec![PositiveNumber::from(single.number)],
GrammarArrayDimensions::Multiple(multiple) => {
multiple.numbers.into_iter().map(PositiveNumber::from).collect()
}
})
}
}
/// Create a new [`ArrayDimensions`] from a [`InputArrayDimensions`] in a Leo program file.
impl<'ast> From<InputArrayDimensions<'ast>> for ArrayDimensions {
fn from(dimensions: InputArrayDimensions<'ast>) -> Self {

View File

@ -14,26 +14,15 @@
// 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::{InputKeyword, MutSelfKeyword, SelfKeyword, Span};
use leo_grammar::{
annotations::AnnotationArgument,
common::{
Identifier as GrammarIdentifier,
KeywordOrIdentifier,
MutSelfKeyword as GrammarMutSelfKeyword,
SelfKeyword as GrammarSelfKeyword,
SelfKeywordOrIdentifier,
},
expressions::CircuitName,
functions::InputKeyword as GrammarInputKeyword,
imports::PackageName as GrammarPackageName,
types::SelfType,
};
use crate::Span;
use leo_input::common::Identifier as InputIdentifier;
use crate::Node;
use serde::{
de::{self, Visitor},
de::{
Visitor,
{self},
},
Deserialize,
Deserializer,
Serialize,
@ -74,10 +63,10 @@ impl Identifier {
}
}
pub fn new_with_span(name: &str, span: &Span) -> Self {
pub fn new_with_span(name: &str, span: Span) -> Self {
Self {
name: name.to_owned(),
span: span.to_owned(),
span,
}
}
@ -90,24 +79,6 @@ impl Identifier {
}
}
impl<'ast> From<GrammarIdentifier<'ast>> for Identifier {
fn from(identifier: GrammarIdentifier<'ast>) -> Self {
Self {
name: identifier.value,
span: Span::from(identifier.span),
}
}
}
impl<'ast> From<GrammarPackageName<'ast>> for Identifier {
fn from(name: GrammarPackageName<'ast>) -> Self {
Self {
name: name.value,
span: Span::from(name.span),
}
}
}
impl<'ast> From<InputIdentifier<'ast>> for Identifier {
fn from(identifier: InputIdentifier<'ast>) -> Self {
Self {
@ -117,106 +88,6 @@ impl<'ast> From<InputIdentifier<'ast>> for Identifier {
}
}
impl<'ast> From<AnnotationArgument<'ast>> for Identifier {
fn from(argument: AnnotationArgument<'ast>) -> Self {
Self {
name: argument.value,
span: Span::from(argument.span),
}
}
}
impl<'ast> From<KeywordOrIdentifier<'ast>> for Identifier {
fn from(name: KeywordOrIdentifier<'ast>) -> Self {
match name {
KeywordOrIdentifier::Identifier(keyword) => Identifier::from(keyword),
KeywordOrIdentifier::SelfType(self_type) => Identifier::from(self_type),
KeywordOrIdentifier::Input(keyword) => Identifier::from(keyword),
}
}
}
impl<'ast> From<SelfKeywordOrIdentifier<'ast>> for Identifier {
fn from(name: SelfKeywordOrIdentifier<'ast>) -> Self {
match name {
SelfKeywordOrIdentifier::Identifier(identifier) => Identifier::from(identifier),
SelfKeywordOrIdentifier::SelfKeyword(keyword) => Identifier::from(keyword),
}
}
}
impl<'ast> From<GrammarSelfKeyword<'ast>> for Identifier {
fn from(grammar: GrammarSelfKeyword<'ast>) -> Self {
Self {
name: grammar.keyword,
span: Span::from(grammar.span),
}
}
}
impl From<SelfKeyword> for Identifier {
fn from(keyword: SelfKeyword) -> Self {
Self {
name: keyword.to_string(),
span: keyword.span,
}
}
}
impl<'ast> From<GrammarMutSelfKeyword<'ast>> for Identifier {
fn from(grammar: GrammarMutSelfKeyword<'ast>) -> Self {
Self {
name: grammar.to_string(),
span: Span::from(grammar.span),
}
}
}
impl From<MutSelfKeyword> for Identifier {
fn from(keyword: MutSelfKeyword) -> Self {
Self {
name: keyword.to_string(),
span: keyword.span,
}
}
}
impl<'ast> From<GrammarInputKeyword<'ast>> for Identifier {
fn from(grammar: GrammarInputKeyword<'ast>) -> Self {
Self {
name: grammar.keyword,
span: Span::from(grammar.span),
}
}
}
impl From<InputKeyword> for Identifier {
fn from(keyword: InputKeyword) -> Self {
Self {
name: keyword.to_string(),
span: keyword.span,
}
}
}
impl<'ast> From<CircuitName<'ast>> for Identifier {
fn from(name: CircuitName<'ast>) -> Self {
match name {
CircuitName::SelfType(self_type) => Identifier::from(self_type),
CircuitName::Identifier(identifier) => Identifier::from(identifier),
}
}
}
impl<'ast> From<SelfType<'ast>> for Identifier {
fn from(self_type: SelfType<'ast>) -> Self {
Self {
name: self_type.keyword,
span: Span::from(self_type.span),
}
}
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name)

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span};
use leo_grammar::functions::InputKeyword as GrammarInputKeyword;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -27,14 +26,6 @@ pub struct InputKeyword {
pub span: Span,
}
impl<'ast> From<GrammarInputKeyword<'ast>> for InputKeyword {
fn from(grammar: GrammarInputKeyword<'ast>) -> Self {
Self {
span: Span::from(grammar.span),
}
}
}
impl fmt::Display for InputKeyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "input")

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span};
use leo_grammar::common::MutSelfKeyword as GrammarMutSelfKeyword;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -26,14 +25,6 @@ pub struct MutSelfKeyword {
pub span: Span,
}
impl<'ast> From<GrammarMutSelfKeyword<'ast>> for MutSelfKeyword {
fn from(grammar: GrammarMutSelfKeyword<'ast>) -> Self {
Self {
span: Span::from(grammar.span),
}
}
}
impl fmt::Display for MutSelfKeyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "mut self")

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_grammar::values::PositiveNumber as GrammarPositiveNumber;
use leo_input::values::PositiveNumber as InputPositiveNumber;
use serde::{Deserialize, Serialize};
@ -35,13 +34,6 @@ impl PositiveNumber {
}
}
/// Create a new [`PositiveNumber`] from a [`GrammarPositiveNumber`] in a Leo program file.
impl<'ast> From<GrammarPositiveNumber<'ast>> for PositiveNumber {
fn from(array: GrammarPositiveNumber<'ast>) -> Self {
Self { value: array.value }
}
}
/// Create a new [`PositiveNumber`] from an [`InputPositiveNumber`] in a Leo input file.
impl<'ast> From<InputPositiveNumber<'ast>> for PositiveNumber {
fn from(array: InputPositiveNumber<'ast>) -> Self {

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span};
use leo_grammar::common::SelfKeyword as GrammarSelfKeyword;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -27,14 +26,6 @@ pub struct SelfKeyword {
pub span: Span,
}
impl<'ast> From<GrammarSelfKeyword<'ast>> for SelfKeyword {
fn from(grammar: GrammarSelfKeyword<'ast>) -> Self {
Self {
span: Span::from(grammar.span),
}
}
}
impl fmt::Display for SelfKeyword {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "self")

View File

@ -14,62 +14,85 @@
// 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 pest::Span as GrammarSpan;
use std::{fmt, rc::Rc};
use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Span {
/// text of input string
pub text: String,
/// program line
pub line: usize,
/// start column
pub start: usize,
/// end column
pub end: usize,
pub line_start: usize,
pub line_stop: usize,
pub col_start: usize,
pub col_stop: usize,
pub path: Rc<String>,
}
impl PartialEq for Span {
fn eq(&self, other: &Self) -> bool {
self.line == other.line && self.start == other.start && self.end == other.end
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.line_start == self.line_stop {
write!(f, "{}:{}-{}", self.line_start, self.col_start, self.col_stop)
} else {
write!(
f,
"{}:{}-{}:{}",
self.line_start, self.col_start, self.line_stop, self.col_stop
)
}
}
}
impl Eq for Span {}
impl<'ast> From<pest::Span<'ast>> for Span {
fn from(span: pest::Span) -> Self {
let start = span.start_pos().line_col();
let end = span.end_pos().line_col();
impl Hash for Span {
fn hash<H: Hasher>(&self, state: &mut H) {
self.line.hash(state);
self.start.hash(state);
self.end.hash(state);
}
}
impl Span {
pub fn from_internal_string(value: &str) -> Span {
Span {
text: value.to_string(),
line: 0,
start: 0,
end: 0,
line_start: start.0,
line_stop: end.0,
col_start: start.1,
col_stop: end.1,
path: Rc::new(String::new()),
}
}
}
impl<'ast> From<GrammarSpan<'ast>> for Span {
fn from(span: GrammarSpan<'ast>) -> Self {
let mut text = " ".to_string();
let line_col = span.start_pos().line_col();
let end = span.end_pos().line_col().1;
impl std::ops::Add for &Span {
type Output = Span;
text.push_str(span.start_pos().line_of().trim_end());
fn add(self, other: &Span) -> Span {
self.clone() + other.clone()
}
}
Self {
text,
line: line_col.0,
start: line_col.1,
end,
impl std::ops::Add for Span {
type Output = Self;
#[allow(clippy::comparison_chain)]
fn add(self, other: Self) -> Self {
if self.line_start == other.line_stop {
Span {
line_start: self.line_start,
line_stop: self.line_stop,
col_start: self.col_start.min(other.col_start),
col_stop: self.col_stop.max(other.col_stop),
path: self.path,
}
} else if self.line_start < other.line_stop {
Span {
line_start: self.line_start,
line_stop: other.line_stop,
col_start: self.col_start,
col_stop: other.col_stop,
path: self.path,
}
} else {
Span {
line_start: other.line_start,
line_stop: self.line_stop,
col_start: other.col_start,
col_stop: self.col_stop,
path: self.path,
}
}
}
}

View File

@ -15,10 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Node, Span};
use leo_grammar::{
common::SpreadOrExpression as GrammarSpreadOrExpression,
expressions::Expression as GrammarExpression,
};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -30,25 +26,6 @@ pub enum SpreadOrExpression {
Expression(Expression),
}
impl<'ast> From<GrammarSpreadOrExpression<'ast>> for SpreadOrExpression {
fn from(s_or_e: GrammarSpreadOrExpression<'ast>) -> Self {
match s_or_e {
GrammarSpreadOrExpression::Spread(spread) => {
SpreadOrExpression::Spread(Expression::from(spread.expression))
}
GrammarSpreadOrExpression::Expression(expression) => {
SpreadOrExpression::Expression(Expression::from(expression))
}
}
}
}
impl<'ast> From<GrammarExpression<'ast>> for SpreadOrExpression {
fn from(expression: GrammarExpression<'ast>) -> Self {
SpreadOrExpression::Expression(Expression::from(expression))
}
}
impl fmt::Display for SpreadOrExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {

View File

@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::Span;
use crate::{LeoError, Span};
use std::{fmt, path::Path};
use std::fmt;
pub const INDENT: &str = " ";
@ -28,68 +28,59 @@ pub const INDENT: &str = " ";
/// |
/// = undefined value `x`
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error {
pub struct FormattedError {
/// File path where error occurred
pub path: Option<String>,
/// Line number
pub line: usize,
/// Line start number
pub line_start: usize,
/// Line end number
pub line_stop: usize,
/// Starting column
pub start: usize,
/// Ending column
pub end: usize,
/// Text of errored line
pub text: String,
/// Text of errored lines
pub text: Option<Vec<String>>,
/// Error explanation
pub message: String,
}
impl Error {
pub fn new_from_span(message: String, span: Span) -> Self {
impl FormattedError {
pub fn new_from_span(message: String, span: &Span) -> Self {
Self {
path: None,
line: span.line,
start: span.start,
end: span.end,
text: span.text,
line_start: span.line_start,
line_stop: span.line_stop,
start: span.col_start,
end: span.col_stop,
text: None,
message,
}
}
}
pub fn new_from_span_with_path(message: String, span: Span, path: &Path) -> Self {
Self {
path: Some(format!("{:?}", path)),
line: span.line,
start: span.start,
end: span.end,
text: span.text,
message,
impl LeoError for FormattedError {
fn set_path(&mut self, path: &str, content: &[String]) {
self.path = Some(path.to_string());
if self.line_stop - 1 > content.len() {
self.text = Some(vec!["corrupt file".to_string()]);
return;
}
assert!(self.line_stop >= self.line_start);
// if self.line_stop == self.line_start {
// self.text = Some(vec![content[self.line_start - 1][self.start - 1..self.end - 1].to_string()]);
// } else {
self.text = Some(
content[self.line_start - 1..self.line_stop]
.iter()
.map(|x| x.to_string())
.collect(),
);
// }
}
pub fn set_path(&mut self, path: &Path) {
self.path = Some(format!("{:?}", path));
}
pub fn format(&self) -> String {
let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default();
let underline = underline(self.start, self.end);
format!(
"{indent }--> {path} {line}:{start}\n\
{indent } |\n\
{line:width$} | {text}\n\
{indent } | {underline}\n\
{indent } |\n\
{indent } = {message}",
indent = INDENT,
width = INDENT.len(),
path = path,
line = self.line,
start = self.start,
text = self.text,
underline = underline,
message = self.message,
)
fn get_path(&self) -> Option<&str> {
self.path.as_deref()
}
}
@ -112,13 +103,46 @@ fn underline(mut start: usize, mut end: usize) -> String {
underline
}
impl fmt::Display for Error {
impl fmt::Display for FormattedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.format())
let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default();
let underline = underline(self.start - 1, self.end - 1);
write!(
f,
"{indent }--> {path} {line_start}:{start}\n\
{indent } |\n",
indent = INDENT,
path = path,
line_start = self.line_start,
start = self.start,
)?;
if let Some(lines) = &self.text {
for (line_no, line) in lines.iter().enumerate() {
writeln!(
f,
"{line_no:width$} | {text}",
width = INDENT.len(),
line_no = self.line_start + line_no,
text = line,
)?;
}
}
write!(
f,
"{indent } | {underline}\n\
{indent } |\n\
{indent } = {message}",
indent = INDENT,
underline = underline,
message = self.message,
)
}
}
impl std::error::Error for Error {
impl std::error::Error for FormattedError {
fn description(&self) -> &str {
&self.message
}
@ -126,12 +150,13 @@ impl std::error::Error for Error {
#[test]
fn test_error() {
let err = Error {
let err = FormattedError {
path: Some("file.leo".to_string()),
line: 2,
line_start: 2,
line_stop: 2,
start: 8,
end: 9,
text: "let a = x;".to_string(),
text: Some(vec!["let a = x;".to_string()]),
message: "undefined value `x`".to_string(),
};

View File

@ -14,30 +14,11 @@
// 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/>.
pub mod deprecated;
pub use deprecated::*;
pub mod error;
pub use error::*;
use error::Error as FormattedError;
pub trait LeoError {
fn get_path(&self) -> Option<&str>;
use leo_grammar::ParserError;
#[derive(Debug, Error)]
pub enum AstError {
#[error("{}", _0)]
DeprecatedError(#[from] DeprecatedError),
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("{}", _0)]
IoError(#[from] std::io::Error),
#[error("{}", _0)]
ParserError(#[from] ParserError),
#[error("{}", _0)]
JsonError(#[from] serde_json::error::Error),
fn set_path(&mut self, path: &str, contents: &[String]);
}

View File

@ -31,6 +31,13 @@ pub enum BinaryOperation {
Gt,
Le,
Lt,
BitOr,
BitAnd,
BitXor,
Shr,
ShrSigned,
Shl,
Mod,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -55,6 +62,13 @@ impl AsRef<str> for BinaryOperation {
BinaryOperation::Gt => ">",
BinaryOperation::Le => "<=",
BinaryOperation::Lt => "<",
BinaryOperation::BitOr => "|",
BinaryOperation::BitAnd => "&",
BinaryOperation::BitXor => "^",
BinaryOperation::Shr => ">>",
BinaryOperation::ShrSigned => ">>>",
BinaryOperation::Shl => "<<",
BinaryOperation::Mod => "%",
}
}
}
@ -66,6 +80,13 @@ impl BinaryOperation {
| BinaryOperation::Sub
| BinaryOperation::Mul
| BinaryOperation::Div
| BinaryOperation::BitOr
| BinaryOperation::BitAnd
| BinaryOperation::BitXor
| BinaryOperation::Shr
| BinaryOperation::ShrSigned
| BinaryOperation::Shl
| BinaryOperation::Mod
| BinaryOperation::Pow => BinaryOperationClass::Numeric,
BinaryOperation::Or
| BinaryOperation::And

View File

@ -14,24 +14,29 @@
// 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::{ast::Rule, expressions::Expression, SpanDef};
use crate::Type;
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
use super::*;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::spread))]
pub struct Spread<'ast> {
pub expression: Expression<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CastExpression {
pub inner: Box<Expression>,
pub target_type: Type,
pub span: Span,
}
impl<'ast> fmt::Display for Spread<'ast> {
impl fmt::Display for CastExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "...{}", self.expression)
write!(f, "{} as {}", self.inner, self.target_type)
}
}
impl Node for CastExpression {
fn span(&self) -> &Span {
&self.span
}
fn set_span(&mut self, span: Span) {
self.span = span;
}
}

View File

@ -27,7 +27,11 @@ impl fmt::Display for CircuitInitExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {{", self.name)?;
for (i, member) in self.members.iter().enumerate() {
write!(f, "{}: {}", member.identifier, member.expression)?;
if let Some(expression) = &member.expression {
write!(f, "{}: {}", member.identifier, expression)?;
} else {
write!(f, "{}", member.identifier)?;
}
if i < self.members.len() - 1 {
write!(f, ", ")?;

View File

@ -24,33 +24,7 @@ use crate::{
Span,
SpreadOrExpression,
};
use leo_grammar::{
access::{Access, AssigneeAccess, SelfAccess},
common::{Assignee, Identifier as GrammarIdentifier, RangeOrExpression as GrammarRangeOrExpression},
expressions::{
ArrayInitializerExpression,
ArrayInlineExpression as GrammarArrayInlineExpression,
BinaryExpression as GrammarBinaryExpression,
CircuitInlineExpression,
Expression as GrammarExpression,
PostfixExpression,
SelfPostfixExpression,
TernaryExpression as GrammarTernaryExpression,
UnaryExpression as GrammarUnaryExpression,
},
operations::{BinaryOperation as GrammarBinaryOperation, UnaryOperation as GrammarUnaryOperation},
values::{
AddressValue,
BooleanValue,
FieldValue,
GroupValue as GrammarGroupValue,
IntegerValue,
NumberValue as GrammarNumber,
Value,
},
};
use leo_grammar::{access::TupleAccess, expressions::TupleExpression};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -84,6 +58,8 @@ mod value;
pub use value::*;
mod call;
pub use call::*;
mod cast;
pub use cast::*;
/// Expression that evaluates to a value
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -93,6 +69,7 @@ pub enum Expression {
Binary(BinaryExpression),
Unary(UnaryExpression),
Ternary(TernaryExpression),
Cast(CastExpression),
ArrayInline(ArrayInlineExpression),
ArrayInit(ArrayInitExpression),
@ -128,6 +105,7 @@ impl Node for Expression {
CircuitMemberAccess(n) => n.span(),
CircuitStaticFunctionAccess(n) => n.span(),
Call(n) => n.span(),
Cast(n) => n.span(),
}
}
@ -149,11 +127,12 @@ impl Node for Expression {
CircuitMemberAccess(n) => n.set_span(span),
CircuitStaticFunctionAccess(n) => n.set_span(span),
Call(n) => n.set_span(span),
Cast(n) => n.set_span(span),
}
}
}
impl<'ast> fmt::Display for Expression {
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Expression::*;
match &self {
@ -172,404 +151,7 @@ impl<'ast> fmt::Display for Expression {
CircuitMemberAccess(n) => n.fmt(f),
CircuitStaticFunctionAccess(n) => n.fmt(f),
Call(n) => n.fmt(f),
Cast(n) => n.fmt(f),
}
}
}
impl<'ast> From<CircuitInlineExpression<'ast>> for Expression {
fn from(expression: CircuitInlineExpression<'ast>) -> Self {
let circuit_name = Identifier::from(expression.name);
let members = expression
.members
.into_iter()
.map(CircuitImpliedVariableDefinition::from)
.collect::<Vec<CircuitImpliedVariableDefinition>>();
Expression::CircuitInit(CircuitInitExpression {
name: circuit_name,
members,
span: Span::from(expression.span),
})
}
}
impl<'ast> From<PostfixExpression<'ast>> for Expression {
fn from(expression: PostfixExpression<'ast>) -> Self {
let variable = Expression::Identifier(Identifier::from(expression.name));
// ast::PostFixExpression contains an array of "accesses": `a(34)[42]` is represented as `[a, [Call(34), Select(42)]]`, but Access call expressions
// are recursive, so it is `Select(Call(a, 34), 42)`. We apply this transformation here
// we start with the id, and we fold the array of accesses by wrapping the current value
expression
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
// Handle array accesses
Access::Array(array) => match array.expression {
GrammarRangeOrExpression::Expression(expression) => {
Expression::ArrayAccess(ArrayAccessExpression {
array: Box::new(acc),
index: Box::new(Expression::from(expression)),
span: Span::from(array.span),
})
}
GrammarRangeOrExpression::Range(range) => {
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
array: Box::new(acc),
left: range.from.map(Expression::from).map(Box::new),
right: range.to.map(Expression::from).map(Box::new),
span: Span::from(array.span),
})
}
},
// Handle tuple access
Access::Tuple(tuple) => Expression::TupleAccess(TupleAccessExpression {
tuple: Box::new(acc),
index: PositiveNumber::from(tuple.number),
span: Span::from(tuple.span),
}),
// Handle function calls
Access::Call(function) => Expression::Call(CallExpression {
function: Box::new(acc),
arguments: function.expressions.into_iter().map(Expression::from).collect(),
span: Span::from(function.span),
}),
// Handle circuit member accesses
Access::Object(circuit_object) => Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
circuit: Box::new(acc),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
}),
Access::StaticObject(circuit_object) => {
Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression {
circuit: Box::new(acc),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
})
}
})
}
}
impl<'ast> From<SelfPostfixExpression<'ast>> for Expression {
fn from(expression: SelfPostfixExpression<'ast>) -> Self {
let variable = Expression::Identifier(Identifier::from(expression.name));
// Handle self expression access.
let self_expression = match expression.self_access {
// Handle circuit member accesses
SelfAccess::Object(circuit_object) => Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
circuit: Box::new(variable),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
}),
// Handle static access
SelfAccess::StaticObject(circuit_object) => {
Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression {
circuit: Box::new(variable),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
})
}
};
// ast::SelfPostFixExpression contains an array of "accesses": `a(34)[42]` is represented as `[a, [Call(34), Select(42)]]`, but Access call expressions
// are recursive, so it is `Select(Call(a, 34), 42)`. We apply this transformation here
// we start with the id, and we fold the array of accesses by wrapping the current value
expression
.accesses
.into_iter()
.fold(self_expression, |acc, access| match access {
// Handle array accesses
Access::Array(array) => match array.expression {
GrammarRangeOrExpression::Expression(expression) => {
Expression::ArrayAccess(ArrayAccessExpression {
array: Box::new(acc),
index: Box::new(Expression::from(expression)),
span: Span::from(array.span),
})
}
GrammarRangeOrExpression::Range(range) => {
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
array: Box::new(acc),
left: range.from.map(Expression::from).map(Box::new),
right: range.to.map(Expression::from).map(Box::new),
span: Span::from(array.span),
})
}
},
// Handle tuple access
Access::Tuple(tuple) => Expression::TupleAccess(TupleAccessExpression {
tuple: Box::new(acc),
index: PositiveNumber::from(tuple.number),
span: Span::from(tuple.span),
}),
// Handle function calls
Access::Call(function) => Expression::Call(CallExpression {
function: Box::new(acc),
arguments: function.expressions.into_iter().map(Expression::from).collect(),
span: Span::from(function.span),
}),
// Handle circuit member accesses
Access::Object(circuit_object) => Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
circuit: Box::new(acc),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
}),
Access::StaticObject(circuit_object) => {
Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression {
circuit: Box::new(acc),
name: Identifier::from(circuit_object.identifier),
span: Span::from(circuit_object.span),
})
}
})
}
}
impl<'ast> From<GrammarExpression<'ast>> for Expression {
fn from(expression: GrammarExpression<'ast>) -> Self {
match expression {
GrammarExpression::Value(value) => Expression::from(value),
GrammarExpression::Identifier(variable) => Expression::from(variable),
GrammarExpression::Unary(expression) => Expression::from(*expression),
GrammarExpression::Binary(expression) => Expression::from(*expression),
GrammarExpression::Ternary(expression) => Expression::from(*expression),
GrammarExpression::ArrayInline(expression) => Expression::from(expression),
GrammarExpression::ArrayInitializer(expression) => Expression::from(*expression),
GrammarExpression::Tuple(expression) => Expression::from(expression),
GrammarExpression::CircuitInline(expression) => Expression::from(expression),
GrammarExpression::Postfix(expression) => Expression::from(expression),
GrammarExpression::SelfPostfix(expression) => Expression::from(expression),
}
}
}
// Assignee -> Expression for operator assign statements
impl<'ast> From<Assignee<'ast>> for Expression {
fn from(assignee: Assignee<'ast>) -> Self {
let variable = Expression::Identifier(Identifier::from(assignee.name));
// we start with the id, and we fold the array of accesses by wrapping the current value
assignee
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
AssigneeAccess::Member(circuit_member) => {
Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
circuit: Box::new(acc),
name: Identifier::from(circuit_member.identifier),
span: Span::from(circuit_member.span),
})
}
AssigneeAccess::Array(array) => match array.expression {
GrammarRangeOrExpression::Expression(expression) => {
Expression::ArrayAccess(ArrayAccessExpression {
array: Box::new(acc),
index: Box::new(Expression::from(expression)),
span: Span::from(array.span),
})
}
GrammarRangeOrExpression::Range(range) => {
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
array: Box::new(acc),
left: range.from.map(Expression::from).map(Box::new),
right: range.to.map(Expression::from).map(Box::new),
span: Span::from(array.span),
})
}
},
AssigneeAccess::Tuple(tuple) => Expression::TupleAccess(TupleAccessExpression {
tuple: Box::new(acc),
index: PositiveNumber::from(tuple.number),
span: Span::from(tuple.span.clone()),
}),
})
}
}
impl<'ast> From<GrammarBinaryExpression<'ast>> for Expression {
fn from(expression: GrammarBinaryExpression<'ast>) -> Self {
use GrammarBinaryOperation::*;
let operator = match expression.operation {
Or => BinaryOperation::Or,
And => BinaryOperation::And,
Eq => BinaryOperation::Eq,
Ne => BinaryOperation::Ne,
Ge => BinaryOperation::Ge,
Gt => BinaryOperation::Gt,
Le => BinaryOperation::Le,
Lt => BinaryOperation::Lt,
Add => BinaryOperation::Add,
Sub => BinaryOperation::Sub,
Mul => BinaryOperation::Mul,
Div => BinaryOperation::Div,
Pow => BinaryOperation::Pow,
};
Expression::Binary(BinaryExpression {
left: Box::new(Expression::from(expression.left)),
right: Box::new(Expression::from(expression.right)),
op: operator,
span: Span::from(expression.span),
})
}
}
impl<'ast> From<GrammarTernaryExpression<'ast>> for Expression {
fn from(expression: GrammarTernaryExpression<'ast>) -> Self {
Expression::Ternary(TernaryExpression {
condition: Box::new(Expression::from(expression.first)),
if_true: Box::new(Expression::from(expression.second)),
if_false: Box::new(Expression::from(expression.third)),
span: Span::from(expression.span),
})
}
}
impl<'ast> From<GrammarArrayInlineExpression<'ast>> for Expression {
fn from(array: GrammarArrayInlineExpression<'ast>) -> Self {
Expression::ArrayInline(ArrayInlineExpression {
elements: array.expressions.into_iter().map(SpreadOrExpression::from).collect(),
span: Span::from(array.span),
})
}
}
impl<'ast> From<ArrayInitializerExpression<'ast>> for Expression {
fn from(array: ArrayInitializerExpression<'ast>) -> Self {
Expression::ArrayInit(ArrayInitExpression {
element: Box::new(Expression::from(array.expression)),
dimensions: ArrayDimensions::from(array.dimensions),
span: Span::from(array.span),
})
}
}
impl<'ast> From<TupleExpression<'ast>> for Expression {
fn from(tuple: TupleExpression<'ast>) -> Self {
Expression::TupleInit(TupleInitExpression {
elements: tuple.expressions.into_iter().map(Expression::from).collect(),
span: Span::from(tuple.span),
})
}
}
impl<'ast> From<Value<'ast>> for Expression {
fn from(value: Value<'ast>) -> Self {
match value {
Value::Address(address) => Expression::from(address),
Value::Boolean(boolean) => Expression::from(boolean),
Value::Field(field) => Expression::from(field),
Value::Group(group) => Expression::from(group),
Value::Implicit(number) => Expression::from(number),
Value::Integer(integer) => Expression::from(integer),
}
}
}
impl<'ast> From<GrammarUnaryExpression<'ast>> for Expression {
fn from(expression: GrammarUnaryExpression<'ast>) -> Self {
use GrammarUnaryOperation::*;
let operator = match expression.operation {
Not(_) => UnaryOperation::Not,
Negate(_) => UnaryOperation::Negate,
};
Expression::Unary(UnaryExpression {
inner: Box::new(Expression::from(expression.expression)),
op: operator,
span: Span::from(expression.span),
})
}
}
impl<'ast> From<AddressValue<'ast>> for Expression {
fn from(address: AddressValue<'ast>) -> Self {
Expression::Value(ValueExpression::Address(
address.address.value,
Span::from(address.span),
))
}
}
impl<'ast> From<BooleanValue<'ast>> for Expression {
fn from(boolean: BooleanValue<'ast>) -> Self {
Expression::Value(ValueExpression::Boolean(boolean.value, Span::from(boolean.span)))
}
}
impl<'ast> From<FieldValue<'ast>> for Expression {
fn from(field: FieldValue<'ast>) -> Self {
Expression::Value(ValueExpression::Field(field.number.to_string(), Span::from(field.span)))
}
}
impl<'ast> From<GrammarGroupValue<'ast>> for Expression {
fn from(ast_group: GrammarGroupValue<'ast>) -> Self {
Expression::Value(ValueExpression::Group(Box::new(GroupValue::from(ast_group))))
}
}
impl<'ast> From<GrammarNumber<'ast>> for Expression {
fn from(number: GrammarNumber<'ast>) -> Self {
let (value, span) = match number {
GrammarNumber::Positive(number) => (number.value, number.span),
GrammarNumber::Negative(number) => (number.value, number.span),
};
Expression::Value(ValueExpression::Implicit(value, Span::from(span)))
}
}
impl<'ast> From<IntegerValue<'ast>> for Expression {
fn from(integer: IntegerValue<'ast>) -> Self {
let span = Span::from(integer.span().clone());
let (type_, value) = match integer {
IntegerValue::Signed(integer) => {
let type_ = IntegerType::from(integer.type_);
let number = match integer.number {
GrammarNumber::Negative(number) => number.value,
GrammarNumber::Positive(number) => number.value,
};
(type_, number)
}
IntegerValue::Unsigned(integer) => {
let type_ = IntegerType::from(integer.type_);
let number = integer.number.value;
(type_, number)
}
};
Expression::Value(ValueExpression::Integer(type_, value, span))
}
}
impl<'ast> From<TupleAccess<'ast>> for Expression {
fn from(tuple: TupleAccess<'ast>) -> Self {
Expression::Value(ValueExpression::Implicit(
tuple.number.to_string(),
Span::from(tuple.span),
))
}
}
impl<'ast> From<GrammarIdentifier<'ast>> for Expression {
fn from(identifier: GrammarIdentifier<'ast>) -> Self {
Expression::Identifier(Identifier::from(identifier))
}
}
impl From<Identifier> for Expression {
fn from(identifier: Identifier) -> Self {
Expression::Identifier(identifier)
}
}

View File

@ -20,6 +20,7 @@ use super::*;
pub enum UnaryOperation {
Not,
Negate,
BitNot,
}
impl AsRef<str> for UnaryOperation {
@ -27,6 +28,7 @@ impl AsRef<str> for UnaryOperation {
match self {
UnaryOperation::Not => "!",
UnaryOperation::Negate => "-",
UnaryOperation::BitNot => "~",
}
}
}

View File

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Block, FunctionInput, Identifier, Node, Span, Type};
use leo_grammar::functions::Function as GrammarFunction;
use crate::{Annotation, Block, FunctionInput, Identifier, Node, Span, Type};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Serialize, Deserialize)]
pub struct Function {
pub annotations: Vec<Annotation>,
pub identifier: Identifier,
pub input: Vec<FunctionInput>,
pub output: Option<Type>,
@ -37,24 +37,6 @@ impl PartialEq for Function {
impl Eq for Function {}
impl<'ast> From<GrammarFunction<'ast>> for Function {
fn from(function: GrammarFunction<'ast>) -> Self {
let function_name = Identifier::from(function.identifier);
let parameters = function.parameters.into_iter().map(FunctionInput::from).collect();
let returns = function.returns.map(Type::from);
let block = Block::from(function.block);
Function {
identifier: function_name,
input: parameters,
output: returns,
block,
span: Span::from(function.span),
}
}
}
impl Function {
pub fn get_name(&self) -> &str {
&self.identifier.name

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Identifier, Node, Span, Type};
use leo_grammar::functions::FunctionInput as GrammarFunctionInput;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -29,18 +28,6 @@ pub struct FunctionInputVariable {
pub span: Span,
}
impl<'ast> From<GrammarFunctionInput<'ast>> for FunctionInputVariable {
fn from(parameter: GrammarFunctionInput<'ast>) -> Self {
FunctionInputVariable {
identifier: Identifier::from(parameter.identifier),
const_: parameter.const_.is_some(),
mutable: parameter.mutable.is_some(),
type_: Type::from(parameter.type_),
span: Span::from(parameter.span),
}
}
}
impl FunctionInputVariable {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
// mut var: bool

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{FunctionInputVariable, InputKeyword, MutSelfKeyword, Node, SelfKeyword, Span};
use leo_grammar::functions::input::Input as GrammarInput;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -29,19 +28,6 @@ pub enum FunctionInput {
Variable(FunctionInputVariable),
}
impl<'ast> From<GrammarInput<'ast>> for FunctionInput {
fn from(input: GrammarInput<'ast>) -> Self {
match input {
GrammarInput::InputKeyword(keyword) => FunctionInput::InputKeyword(InputKeyword::from(keyword)),
GrammarInput::SelfKeyword(keyword) => FunctionInput::SelfKeyword(SelfKeyword::from(keyword)),
GrammarInput::MutSelfKeyword(keyword) => FunctionInput::MutSelfKeyword(MutSelfKeyword::from(keyword)),
GrammarInput::FunctionInput(function_input) => {
FunctionInput::Variable(FunctionInputVariable::from(function_input))
}
}
}
}
impl FunctionInput {
///
/// Returns `true` if the function input is the `self` or `mut self` keyword.

View File

@ -19,6 +19,3 @@ pub use function::*;
pub mod input;
pub use input::*;
pub mod test_function;
pub use test_function::*;

View File

@ -1,35 +0,0 @@
// 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::{Function, Identifier};
use leo_grammar::functions::TestFunction as GrammarTestFunction;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TestFunction {
pub function: Function,
pub input_file: Option<Identifier>,
}
impl<'ast> From<GrammarTestFunction<'ast>> for TestFunction {
fn from(test: GrammarTestFunction) -> Self {
TestFunction {
function: Function::from(test.function),
input_file: None, // pass custom input file with `@context` annotation
}
}
}

View File

@ -15,13 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::common::span::Span;
use leo_grammar::values::{
GroupCoordinate as GrammarGroupCoordinate,
Inferred as GrammarInferred,
NumberValue as GrammarNumberValue,
SignHigh as GrammarSignHigh,
SignLow as GrammarSignLow,
};
use leo_input::values::{
GroupCoordinate as InputGroupCoordinate,
Inferred as InputInferred,
@ -41,17 +34,6 @@ pub enum GroupCoordinate {
Inferred,
}
impl<'ast> From<GrammarGroupCoordinate<'ast>> for GroupCoordinate {
fn from(coordinate: GrammarGroupCoordinate<'ast>) -> Self {
match coordinate {
GrammarGroupCoordinate::Number(number) => GroupCoordinate::from(number),
GrammarGroupCoordinate::SignHigh(sign_high) => GroupCoordinate::from(sign_high),
GrammarGroupCoordinate::SignLow(sign_low) => GroupCoordinate::from(sign_low),
GrammarGroupCoordinate::Inferred(inferred) => GroupCoordinate::from(inferred),
}
}
}
impl<'ast> From<InputGroupCoordinate<'ast>> for GroupCoordinate {
fn from(coordinate: InputGroupCoordinate<'ast>) -> Self {
match coordinate {
@ -74,33 +56,6 @@ impl fmt::Display for GroupCoordinate {
}
}
impl<'ast> From<GrammarNumberValue<'ast>> for GroupCoordinate {
fn from(number: GrammarNumberValue<'ast>) -> Self {
let value = number.to_string();
let span = Span::from(number.span().clone());
GroupCoordinate::Number(value, span)
}
}
impl<'ast> From<GrammarSignHigh<'ast>> for GroupCoordinate {
fn from(_sign: GrammarSignHigh<'ast>) -> Self {
GroupCoordinate::SignHigh
}
}
impl<'ast> From<GrammarSignLow<'ast>> for GroupCoordinate {
fn from(_sign: GrammarSignLow<'ast>) -> Self {
GroupCoordinate::SignLow
}
}
impl<'ast> From<GrammarInferred<'ast>> for GroupCoordinate {
fn from(_sign: GrammarInferred<'ast>) -> Self {
GroupCoordinate::Inferred
}
}
impl<'ast> From<InputNumberValue<'ast>> for GroupCoordinate {
fn from(number: InputNumberValue<'ast>) -> Self {
let value = number.to_string();

View File

@ -15,11 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{common::span::Span, groups::GroupCoordinate};
use leo_grammar::values::{
GroupRepresentation as GrammarGroupRepresentation,
GroupTuple as GrammarGroupTuple,
GroupValue as GrammarGroupValue,
};
use leo_input::values::{
GroupRepresentation as InputGroupRepresentation,
GroupTuple as InputGroupTuple,
@ -51,17 +46,6 @@ impl GroupValue {
}
}
impl<'ast> From<GrammarGroupValue<'ast>> for GroupValue {
fn from(ast_group: GrammarGroupValue) -> Self {
let span = Span::from(ast_group.span);
match ast_group.value {
GrammarGroupRepresentation::Single(number) => GroupValue::Single(number.to_string(), span),
GrammarGroupRepresentation::Tuple(tuple) => GroupValue::Tuple(GroupTuple::from(tuple)),
}
}
}
impl<'ast> From<InputGroupValue<'ast>> for GroupValue {
fn from(ast_group: InputGroupValue) -> Self {
let span = Span::from(ast_group.span);
@ -89,19 +73,6 @@ pub struct GroupTuple {
pub span: Span,
}
impl<'ast> From<GrammarGroupTuple<'ast>> for GroupTuple {
fn from(ast_group: GrammarGroupTuple<'ast>) -> Self {
let ast_x = ast_group.x;
let ast_y = ast_group.y;
Self {
x: GroupCoordinate::from(ast_x),
y: GroupCoordinate::from(ast_y),
span: Span::from(ast_group.span),
}
}
}
impl<'ast> From<InputGroupTuple<'ast>> for GroupTuple {
fn from(ast_group: InputGroupTuple<'ast>) -> Self {
let ast_x = ast_group.x;

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{PackageOrPackages, Span};
use leo_grammar::imports::Import as GrammarImport;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -39,15 +38,6 @@ impl ImportStatement {
}
}
impl<'ast> From<GrammarImport<'ast>> for ImportStatement {
fn from(import: GrammarImport<'ast>) -> Self {
ImportStatement {
package_or_packages: PackageOrPackages::from(import.package_or_packages),
span: Span::from(import.span),
}
}
}
impl ImportStatement {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "import {};", self.package_or_packages)

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Identifier, Span};
use leo_grammar::imports::ImportSymbol as GrammarImportSymbol;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -27,16 +26,6 @@ pub struct ImportSymbol {
pub span: Span,
}
impl<'ast> From<GrammarImportSymbol<'ast>> for ImportSymbol {
fn from(symbol: GrammarImportSymbol<'ast>) -> Self {
ImportSymbol {
symbol: Identifier::from(symbol.value),
alias: symbol.alias.map(Identifier::from),
span: Span::from(symbol.span),
}
}
}
impl fmt::Display for ImportSymbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.alias.is_some() {

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{common::Identifier, PackageAccess, Span};
use leo_grammar::imports::Package as GrammarPackage;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -27,16 +26,6 @@ pub struct Package {
pub span: Span,
}
impl<'ast> From<GrammarPackage<'ast>> for Package {
fn from(package: GrammarPackage<'ast>) -> Self {
Package {
name: Identifier::from(package.name),
access: PackageAccess::from(package.access),
span: Span::from(package.span),
}
}
}
impl Package {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.{}", self.name, self.access)

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ImportSymbol, Package, Packages, Span};
use leo_grammar::imports::PackageAccess as GrammarPackageAccess;
use crate::{ImportSymbol, Node, Package, Packages, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -28,13 +27,22 @@ pub enum PackageAccess {
Multiple(Packages),
}
impl<'ast> From<GrammarPackageAccess<'ast>> for PackageAccess {
fn from(access: GrammarPackageAccess<'ast>) -> Self {
match access {
GrammarPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)),
GrammarPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))),
GrammarPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)),
GrammarPackageAccess::Multiple(packages) => PackageAccess::Multiple(Packages::from(packages)),
impl Node for PackageAccess {
fn span(&self) -> &Span {
match self {
PackageAccess::Star(span) => span,
PackageAccess::SubPackage(package) => &package.span,
PackageAccess::Symbol(package) => &package.span,
PackageAccess::Multiple(package) => &package.span,
}
}
fn set_span(&mut self, span: Span) {
match self {
PackageAccess::Star(package) => *package = span,
PackageAccess::SubPackage(package) => package.span = span,
PackageAccess::Symbol(package) => package.span = span,
PackageAccess::Multiple(package) => package.span = span,
}
}
}

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Package, Packages};
use leo_grammar::imports::PackageOrPackages as GrammarPackageOrPackages;
use crate::{Node, Package, Packages, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -26,15 +25,6 @@ pub enum PackageOrPackages {
Packages(Packages),
}
impl<'ast> From<GrammarPackageOrPackages<'ast>> for PackageOrPackages {
fn from(package_or_packages: GrammarPackageOrPackages<'ast>) -> Self {
match package_or_packages {
GrammarPackageOrPackages::Package(package) => PackageOrPackages::Package(Package::from(package)),
GrammarPackageOrPackages::Packages(packages) => PackageOrPackages::Packages(Packages::from(packages)),
}
}
}
impl PackageOrPackages {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@ -64,3 +54,19 @@ impl fmt::Display for PackageOrPackages {
self.format(f)
}
}
impl Node for PackageOrPackages {
fn span(&self) -> &Span {
match self {
PackageOrPackages::Package(package) => &package.span,
PackageOrPackages::Packages(packages) => &packages.span,
}
}
fn set_span(&mut self, span: Span) {
match self {
PackageOrPackages::Package(package) => package.span = span,
PackageOrPackages::Packages(packages) => packages.span = span,
}
}
}

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{common::Identifier, PackageAccess, Span};
use leo_grammar::imports::Packages as GrammarPackages;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -27,16 +26,6 @@ pub struct Packages {
pub span: Span,
}
impl<'ast> From<GrammarPackages<'ast>> for Packages {
fn from(packages: GrammarPackages<'ast>) -> Self {
Packages {
name: Identifier::from(packages.name),
accesses: packages.accesses.into_iter().map(PackageAccess::from).collect(),
span: Span::from(packages.span),
}
}
}
impl Packages {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.(", self.name)?;

View File

@ -114,7 +114,7 @@ impl InputValue {
let array_dimensions_type = ArrayDimensions::from(array_type.dimensions.clone());
// Convert the array dimensions to usize.
let array_dimensions = parse_array_dimensions(array_dimensions_type, array_type.span.clone())?;
let array_dimensions = parse_array_dimensions(array_dimensions_type, &array_type.span)?;
// Return an error if the outer array dimension does not equal the number of array elements.
if array_dimensions[0] != inline.expressions.len() {
@ -146,7 +146,7 @@ impl InputValue {
initializer: ArrayInitializerExpression,
) -> Result<Self, InputParserError> {
let array_dimensions_type = ArrayDimensions::from(initializer.dimensions.clone());
let array_dimensions = parse_array_dimensions(array_dimensions_type, array_type.span.clone())?;
let array_dimensions = parse_array_dimensions(array_dimensions_type, &array_type.span)?;
if array_dimensions.len() > 1 {
// The expression is an array initializer with tuple syntax
@ -169,7 +169,7 @@ impl InputValue {
return Err(InputParserError::array_init_length(
array_dimensions,
initializer_dimensions,
initializer.span,
&initializer.span,
));
}
@ -199,7 +199,7 @@ impl InputValue {
let array_dimensions_type = ArrayDimensions::from(array_type.dimensions.clone());
// Convert the array dimensions to usize.
let array_dimensions = parse_array_dimensions(array_dimensions_type, array_type.span.clone())?;
let array_dimensions = parse_array_dimensions(array_dimensions_type, &array_type.span)?;
let current_array_dimension = array_dimensions[0];
let current_initializer_dimension = initializer_dimensions[0];
@ -209,7 +209,7 @@ impl InputValue {
return Err(InputParserError::array_init_length(
array_dimensions,
initializer_dimensions,
initializer.span,
&initializer.span,
));
}
@ -235,11 +235,7 @@ impl InputValue {
let num_values = tuple.expressions.len();
if num_types != num_values {
return Err(InputParserError::tuple_length(
num_types,
num_values,
tuple_type.span.clone(),
));
return Err(InputParserError::tuple_length(num_types, num_values, &tuple_type.span));
}
let mut values = Vec::with_capacity(tuple_type.types_.len());
@ -260,7 +256,7 @@ impl InputValue {
/// is successful, the `usize` value is appended to the return vector. If parsing fails, an error
/// is returned.
///
fn parse_array_dimensions(array_dimensions_type: ArrayDimensions, span: Span) -> Result<Vec<usize>, InputParserError> {
fn parse_array_dimensions(array_dimensions_type: ArrayDimensions, span: &Span) -> Result<Vec<usize>, InputParserError> {
// Convert the array dimensions to usize.
let mut array_dimensions = Vec::with_capacity(array_dimensions_type.0.len());
@ -271,7 +267,7 @@ fn parse_array_dimensions(array_dimensions_type: ArrayDimensions, span: Span) ->
// Convert the string to usize.
let dimension_usize = match dimension_string.parse::<usize>() {
Ok(dimension_usize) => dimension_usize,
Err(_) => return Err(InputParserError::array_index(dimension_string, span.clone())),
Err(_) => return Err(InputParserError::array_index(dimension_string, span)),
};
// Collect dimension usize values.
@ -292,7 +288,7 @@ fn fetch_nested_array_type_dimensions(
let array_dimensions_type = ArrayDimensions::from(array_type.dimensions.clone());
// Convert the array dimensions to usize.
let mut current_dimension = parse_array_dimensions(array_dimensions_type, array_type.span.clone())?;
let mut current_dimension = parse_array_dimensions(array_dimensions_type, &array_type.span)?;
array_dimensions.append(&mut current_dimension);

View File

@ -19,9 +19,6 @@
//! This module contains the [`Ast`] type, a wrapper around the [`Program`] type.
//! The [`Ast`] type is intended to be parsed and modified by different passes
//! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`Ast`].
#[macro_use]
extern crate thiserror;
pub mod annotation;
pub use self::annotation::*;
@ -61,8 +58,6 @@ pub use self::types::*;
mod node;
pub use node::*;
use leo_grammar::Grammar;
/// The abstract syntax tree (AST) for a Leo program.
///
/// The [`Ast`] type represents a Leo program as a series of recursive data types.
@ -75,11 +70,9 @@ pub struct Ast {
}
impl Ast {
/// Creates a new AST from a given program name and grammar tree.
pub fn new<'ast>(program_name: &str, grammar: &Grammar<'ast>) -> Result<Self, AstError> {
Ok(Self {
ast: Program::from(program_name, grammar.as_repr())?,
})
/// Creates a new AST from a given program tree.
pub fn new(program: Program) -> Self {
Self { ast: program }
}
/// Returns a reference to the inner program AST representation.
@ -87,6 +80,10 @@ impl Ast {
&self.ast
}
pub fn into_repr(self) -> Program {
self.ast
}
/// Serializes the ast into a JSON string.
pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(&self.ast)
@ -98,3 +95,9 @@ impl Ast {
Ok(Self { ast })
}
}
impl AsRef<Program> for Ast {
fn as_ref(&self) -> &Program {
&self.ast
}
}

View File

@ -1,71 +0,0 @@
// 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 leo_ast::{Ast, AstError};
use leo_grammar::Grammar;
use std::{env, fs, path::Path};
fn to_leo_tree(filepath: &Path) -> Result<String, AstError> {
// Loads the Leo code as a string from the given file path.
let program_filepath = filepath.to_path_buf();
let program_string = Grammar::load_file(&program_filepath)?;
// Parses the Leo file and constructs a pest ast.
let ast = Grammar::new(&program_filepath, &program_string)?;
// Parse the pest ast and constructs a ast.
let leo_ast = Ast::new("leo_tree", &ast)?;
let serialized_leo_ast = Ast::to_json_string(&leo_ast)?;
Ok(serialized_leo_ast)
}
fn main() -> Result<(), AstError> {
// Parse the command-line arguments as strings.
let cli_arguments = env::args().collect::<Vec<String>>();
// Check that the correct number of command-line arguments were passed in.
if cli_arguments.len() < 2 || cli_arguments.len() > 3 {
eprintln!("Warning - an invalid number of command-line arguments were provided.");
println!(
"\nCommand-line usage:\n\n\tleo_ast {{PATH/TO/INPUT_FILENAME}}.leo {{PATH/TO/OUTPUT_DIRECTORY (optional)}}\n"
);
return Ok(()); // Exit innocently
}
// Construct the input filepath.
let input_filepath = Path::new(&cli_arguments[1]);
// Construct the serialized syntax tree.
let serialized_leo_tree = to_leo_tree(&input_filepath)?;
println!("{}", serialized_leo_tree);
// Determine the output directory.
let output_directory = match cli_arguments.len() == 3 {
true => format!(
"{}/{}.json",
cli_arguments[2],
input_filepath.file_stem().unwrap().to_str().unwrap()
),
false => format!("./{}.json", input_filepath.file_stem().unwrap().to_str().unwrap()),
};
// Write the serialized syntax tree to the output directory.
fs::write(Path::new(&output_directory), serialized_leo_tree)?;
Ok(())
}

View File

@ -17,17 +17,7 @@
//! A Leo program consists of import, circuit, and function definitions.
//! Each defined type consists of ast statements and expressions.
use crate::{
load_annotation,
Circuit,
DeprecatedError,
Function,
FunctionInput,
Identifier,
ImportStatement,
TestFunction,
};
use leo_grammar::{definitions::Definition, files::File};
use crate::{Circuit, Function, FunctionInput, Identifier, ImportStatement};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
@ -41,7 +31,12 @@ pub struct Program {
pub imports: Vec<ImportStatement>,
pub circuits: IndexMap<Identifier, Circuit>,
pub functions: IndexMap<Identifier, Function>,
pub tests: IndexMap<Identifier, TestFunction>,
}
impl AsRef<Program> for Program {
fn as_ref(&self) -> &Program {
self
}
}
impl fmt::Display for Program {
@ -60,80 +55,10 @@ impl fmt::Display for Program {
function.fmt(f)?;
writeln!(f,)?;
}
for (_, test) in self.tests.iter() {
write!(f, "test ")?;
test.function.fmt(f)?;
writeln!(f,)?;
}
write!(f, "")
}
}
const MAIN_FUNCTION_NAME: &str = "main";
impl<'ast> Program {
//! Logic to convert from an abstract syntax tree (ast) representation to a Leo program.
pub fn from(program_name: &str, program_ast: &File<'ast>) -> Result<Self, DeprecatedError> {
let mut imports = vec![];
let mut circuits = IndexMap::new();
let mut functions = IndexMap::new();
let mut tests = IndexMap::new();
let mut expected_input = vec![];
program_ast
.definitions
.to_owned()
.into_iter()
// Use of Infallible to say we never expect an Some(Ok(...))
.find_map::<Result<std::convert::Infallible, _>, _>(|definition| match definition {
Definition::Import(import) => {
imports.push(ImportStatement::from(import));
None
}
Definition::Circuit(circuit) => {
circuits.insert(Identifier::from(circuit.identifier.clone()), Circuit::from(circuit));
None
}
Definition::Function(function_def) => {
let function = Function::from(function_def);
if function.identifier.name.eq(MAIN_FUNCTION_NAME) {
expected_input = function.input.clone();
}
functions.insert(function.identifier.clone(), function);
None
}
Definition::Deprecated(deprecated) => {
Some(Err(DeprecatedError::from(deprecated)))
}
Definition::Annotated(annotated_definition) => {
let loaded_annotation = load_annotation(
annotated_definition,
&mut imports,
&mut circuits,
&mut functions,
&mut tests,
&mut expected_input,
);
match loaded_annotation {
Ok(_) => None,
Err(deprecated_err) => Some(Err(deprecated_err))
}
}
})
.transpose()?;
Ok(Self {
name: program_name.to_string(),
expected_input,
imports,
circuits,
functions,
tests,
})
}
}
impl Program {
pub fn new(name: String) -> Self {
Self {
@ -142,7 +67,6 @@ impl Program {
imports: vec![],
circuits: IndexMap::new(),
functions: IndexMap::new(),
tests: IndexMap::new(),
}
}

View File

@ -15,10 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Identifier, PositiveNumber, Span};
use leo_grammar::{
access::{ArrayAccess, AssigneeAccess as GrammarAssigneeAccess},
common::{Assignee as GrammarAssignee, Range, RangeOrExpression},
};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -31,25 +27,6 @@ pub enum AssigneeAccess {
Member(Identifier),
}
impl<'ast> From<GrammarAssigneeAccess<'ast>> for AssigneeAccess {
fn from(access: GrammarAssigneeAccess<'ast>) -> Self {
match access {
GrammarAssigneeAccess::Array(ArrayAccess {
expression: RangeOrExpression::Range(Range { from, to, .. }),
..
}) => AssigneeAccess::ArrayRange(from.map(Expression::from), to.map(Expression::from)),
GrammarAssigneeAccess::Array(ArrayAccess {
expression: RangeOrExpression::Expression(index),
..
}) => AssigneeAccess::ArrayIndex(Expression::from(index)),
GrammarAssigneeAccess::Tuple(tuple) => {
AssigneeAccess::Tuple(PositiveNumber::from(tuple.number), Span::from(tuple.span))
}
GrammarAssigneeAccess::Member(member) => AssigneeAccess::Member(Identifier::from(member.identifier)),
}
}
}
/// Definition assignee: v, arr[0..2], Point p.x
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Assignee {
@ -65,20 +42,6 @@ impl Assignee {
}
}
impl<'ast> From<GrammarAssignee<'ast>> for Assignee {
fn from(assignee: GrammarAssignee<'ast>) -> Self {
Assignee {
identifier: Identifier::from(assignee.name),
accesses: assignee
.accesses
.into_iter()
.map(AssigneeAccess::from)
.collect::<Vec<_>>(),
span: Span::from(assignee.span),
}
}
}
impl fmt::Display for Assignee {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.identifier)?;

View File

@ -16,8 +16,6 @@
use crate::{Expression, Node, Span};
pub use leo_grammar::operations::AssignOperation as GrammarAssignOperation;
use leo_grammar::statements::AssignStatement as GrammarAssignStatement;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -32,6 +30,15 @@ pub enum AssignOperation {
Mul,
Div,
Pow,
Or,
And,
BitOr,
BitAnd,
BitXor,
Shr,
ShrSigned,
Shl,
Mod,
}
impl AsRef<str> for AssignOperation {
@ -43,6 +50,15 @@ impl AsRef<str> for AssignOperation {
AssignOperation::Mul => "*=",
AssignOperation::Div => "/=",
AssignOperation::Pow => "**=",
AssignOperation::Or => "||=",
AssignOperation::And => "&&=",
AssignOperation::BitOr => "|=",
AssignOperation::BitAnd => "&=",
AssignOperation::BitXor => "^=",
AssignOperation::Shr => ">>=",
AssignOperation::ShrSigned => ">>>=",
AssignOperation::Shl => "<<=",
AssignOperation::Mod => "%=",
}
}
}
@ -61,24 +77,6 @@ impl fmt::Display for AssignStatement {
}
}
impl<'ast> From<GrammarAssignStatement<'ast>> for AssignStatement {
fn from(statement: GrammarAssignStatement<'ast>) -> Self {
AssignStatement {
operation: match statement.assign {
GrammarAssignOperation::Assign(_) => AssignOperation::Assign,
GrammarAssignOperation::AddAssign(_) => AssignOperation::Add,
GrammarAssignOperation::SubAssign(_) => AssignOperation::Sub,
GrammarAssignOperation::MulAssign(_) => AssignOperation::Mul,
GrammarAssignOperation::DivAssign(_) => AssignOperation::Div,
GrammarAssignOperation::PowAssign(_) => AssignOperation::Pow,
},
assignee: Assignee::from(statement.assignee),
value: Expression::from(statement.expression),
span: Span::from(statement.span),
}
}
}
impl Node for AssignStatement {
fn span(&self) -> &Span {
&self.span

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span, Statement};
use leo_grammar::statements::Block as GrammarBlock;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -26,15 +25,6 @@ pub struct Block {
pub span: Span,
}
impl<'ast> From<GrammarBlock<'ast>> for Block {
fn from(block: GrammarBlock<'ast>) -> Self {
Block {
statements: block.statements.into_iter().map(Statement::from).collect(),
span: Span::from(block.span),
}
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{{")?;

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Block, Expression, Node, Span, Statement};
use leo_grammar::statements::{ConditionalNestedOrEndStatement, ConditionalStatement as GrammarConditionalStatement};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -28,25 +27,6 @@ pub struct ConditionalStatement {
pub span: Span,
}
impl<'ast> From<GrammarConditionalStatement<'ast>> for ConditionalStatement {
fn from(statement: GrammarConditionalStatement<'ast>) -> Self {
ConditionalStatement {
condition: Expression::from(statement.condition),
block: Block::from(statement.block),
next: statement
.next
.map(|nested_statement| match nested_statement {
ConditionalNestedOrEndStatement::Nested(conditional_statement) => {
Statement::Conditional(ConditionalStatement::from(*conditional_statement))
}
ConditionalNestedOrEndStatement::End(block) => Statement::Block(Block::from(block)),
})
.map(Box::new),
span: Span::from(statement.span),
}
}
}
impl fmt::Display for ConditionalStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "if ({}) {}", self.condition, self.block)?;

View File

@ -14,19 +14,12 @@
// 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, FormattedString};
use leo_grammar::console::{
ConsoleAssert as GrammarConsoleAssert,
ConsoleDebug as GrammarConsoleDebug,
ConsoleError as GrammarConsoleError,
ConsoleFunction as GrammarConsoleFunction,
ConsoleLog as GrammarConsoleLog,
};
use crate::{Expression, FormattedString, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum ConsoleFunction {
Assert(Expression),
Debug(FormattedString),
@ -34,41 +27,6 @@ pub enum ConsoleFunction {
Log(FormattedString),
}
impl<'ast> From<GrammarConsoleFunction<'ast>> for ConsoleFunction {
fn from(console_function: GrammarConsoleFunction<'ast>) -> Self {
match console_function {
GrammarConsoleFunction::Assert(assert) => ConsoleFunction::from(assert),
GrammarConsoleFunction::Debug(debug) => ConsoleFunction::from(debug),
GrammarConsoleFunction::Error(error) => ConsoleFunction::from(error),
GrammarConsoleFunction::Log(log) => ConsoleFunction::from(log),
}
}
}
impl<'ast> From<GrammarConsoleAssert<'ast>> for ConsoleFunction {
fn from(assert: GrammarConsoleAssert<'ast>) -> Self {
ConsoleFunction::Assert(Expression::from(assert.expression))
}
}
impl<'ast> From<GrammarConsoleDebug<'ast>> for ConsoleFunction {
fn from(debug: GrammarConsoleDebug<'ast>) -> Self {
ConsoleFunction::Debug(FormattedString::from(debug.string))
}
}
impl<'ast> From<GrammarConsoleError<'ast>> for ConsoleFunction {
fn from(error: GrammarConsoleError<'ast>) -> Self {
ConsoleFunction::Error(FormattedString::from(error.string))
}
}
impl<'ast> From<GrammarConsoleLog<'ast>> for ConsoleFunction {
fn from(log: GrammarConsoleLog<'ast>) -> Self {
ConsoleFunction::Log(FormattedString::from(log.string))
}
}
impl fmt::Display for ConsoleFunction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@ -79,3 +37,23 @@ impl fmt::Display for ConsoleFunction {
}
}
}
impl Node for ConsoleFunction {
fn span(&self) -> &Span {
match self {
ConsoleFunction::Assert(assert) => assert.span(),
ConsoleFunction::Debug(formatted) | ConsoleFunction::Error(formatted) | ConsoleFunction::Log(formatted) => {
&formatted.span
}
}
}
fn set_span(&mut self, span: Span) {
match self {
ConsoleFunction::Assert(assert) => assert.set_span(span),
ConsoleFunction::Debug(formatted) | ConsoleFunction::Error(formatted) | ConsoleFunction::Log(formatted) => {
formatted.set_span(span)
}
}
}
}

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ConsoleFunction, Node, Span};
use leo_grammar::console::ConsoleFunctionCall as GrammarConsoleFunctionCall;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -26,15 +25,6 @@ pub struct ConsoleStatement {
pub span: Span,
}
impl<'ast> From<GrammarConsoleFunctionCall<'ast>> for ConsoleStatement {
fn from(console: GrammarConsoleFunctionCall<'ast>) -> Self {
ConsoleStatement {
function: ConsoleFunction::from(console.function),
span: Span::from(console.span),
}
}
}
impl fmt::Display for ConsoleStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "console.{};", self.function)

View File

@ -15,7 +15,6 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Node, Span};
use leo_grammar::console::FormattedContainer as GrammarFormattedContainer;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -25,14 +24,6 @@ pub struct FormattedContainer {
pub span: Span,
}
impl<'ast> From<GrammarFormattedContainer<'ast>> for FormattedContainer {
fn from(container: GrammarFormattedContainer<'ast>) -> Self {
Self {
span: Span::from(container.span),
}
}
}
impl fmt::Display for FormattedContainer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{}}")

View File

@ -14,39 +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::{Expression, FormattedContainer, Node, Span};
use leo_grammar::console::FormattedString as GrammarFormattedString;
use crate::{Expression, Node, Span};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum FormattedStringPart {
Const(String),
Container,
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct FormattedString {
pub string: String,
pub containers: Vec<FormattedContainer>,
pub parts: Vec<FormattedStringPart>,
pub parameters: Vec<Expression>,
pub span: Span,
}
impl<'ast> From<GrammarFormattedString<'ast>> for FormattedString {
fn from(formatted: GrammarFormattedString<'ast>) -> Self {
let string = formatted.string;
let span = Span::from(formatted.span);
let containers = formatted.containers.into_iter().map(FormattedContainer::from).collect();
let parameters = formatted.parameters.into_iter().map(Expression::from).collect();
Self {
string,
containers,
parameters,
span,
}
}
}
impl fmt::Display for FormattedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.string)
write!(
f,
"{}",
self.parts
.iter()
.map(|x| match x {
FormattedStringPart::Const(x) => x,
FormattedStringPart::Container => "{}",
})
.collect::<Vec<_>>()
.join("")
)
}
}

View File

@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_grammar::common::Declare as GrammarDeclare;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -25,15 +23,6 @@ pub enum Declare {
Let,
}
impl<'ast> From<GrammarDeclare> for Declare {
fn from(declare: GrammarDeclare) -> Self {
match declare {
GrammarDeclare::Const(_) => Declare::Const,
GrammarDeclare::Let(_) => Declare::Let,
}
}
}
impl fmt::Display for Declare {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {

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