restructure compiler and delete unused code

This commit is contained in:
collin 2022-02-22 15:12:52 -08:00
parent 1312c5d036
commit e263e64279
1019 changed files with 35 additions and 28142 deletions

2
Cargo.lock generated
View File

@ -1187,11 +1187,9 @@ dependencies = [
"from-pest",
"indexmap",
"lazy_static",
"leo-ast",
"leo-compiler",
"leo-errors",
"leo-package",
"leo-parser",
"notify",
"rand 0.8.4",
"rand_core 0.6.3",

View File

@ -27,81 +27,24 @@ path = "leo/main.rs"
[workspace]
members = [
# "asg",
# "asg-passes",
"ast",
"ast-passes",
"compiler",
"errors",
"grammar",
# "imports",
# "input",
# "linter",
"package",
"parser",
"span",
# "state",
# "stdlib",
# "synthesizer",
# "test-framework",
# "wasm"
"compiler/compiler",
"docs/grammar",
"leo/errors",
"leo/package",
]
[dependencies.leo-ast]
path = "./ast"
version = "1.5.3"
[dependencies.leo-compiler]
path = "./compiler"
path = "./compiler/compiler"
version = "1.5.3"
[dependencies.leo-errors]
path = "./errors"
path = "./leo/errors"
version = "1.5.3"
#[dependencies.leo-imports]
#path = "./imports"
#version = "1.5.3"
#
#[dependencies.leo-input]
#path = "./input"
#version = "1.5.3"
[dependencies.leo-package]
path = "./package"
path = "./leo/package"
version = "1.5.3"
[dependencies.leo-parser]
path = "./parser"
version = "1.5.3"
#[dependencies.leo-state]
#path = "./state"
#version = "1.5.3"
#[dependencies.leo-stdlib]
#path = "./stdlib"
#version = "1.5.3"
#[dependencies.snarkvm-algorithms]
#git = "https://github.com/AleoHQ/snarkVM.git"
#rev = "51633e2"
#
#[dependencies.snarkvm-curves]
#git = "https://github.com/AleoHQ/snarkVM.git"
#rev = "51633e2"
#default-features = false
#
#[dependencies.snarkvm-gadgets]
#git = "https://github.com/AleoHQ/snarkVM.git"
#rev = "51633e2"
#default-features = false
#
#[dependencies.snarkvm-r1cs]
#git = "https://github.com/AleoHQ/snarkVM.git"
#rev = "51633e2"
#default-features = false
#
[dependencies.snarkvm-utilities]
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "51633e2"

View File

@ -1,30 +0,0 @@
[package]
name = "leo-asg-passes"
version = "1.5.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
repository = "https://github.com/AleoHQ/leo"
keywords = [
"aleo",
"cryptography",
"leo",
"programming-language",
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2021"
rust-version = "1.56.1"
[lib]
path = "src/lib.rs"
[dependencies.leo-asg]
path = "../asg"
version = "1.5.3"
[dependencies.leo-errors]
path = "../errors"
version = "1.5.3"

View File

@ -1,55 +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 std::cell::Cell;
use leo_asg::*;
use leo_errors::Result;
pub struct ConstantFolding<'a, 'b> {
program: &'b Program<'a>,
}
impl<'a, 'b> ExpressionVisitor<'a> for ConstantFolding<'a, 'b> {
fn visit_expression(&mut self, input: &Cell<&'a Expression<'a>>) -> VisitResult {
let expr = input.get();
if let Some(const_value) = expr.const_value() {
let folded_expr = Expression::Constant(Constant {
parent: Cell::new(expr.get_parent()),
span: expr.span().cloned(),
value: const_value,
});
let folded_expr = self.program.context.alloc_expression(folded_expr);
input.set(folded_expr);
VisitResult::SkipChildren
} else {
VisitResult::VisitChildren
}
}
}
impl<'a, 'b> StatementVisitor<'a> for ConstantFolding<'a, 'b> {}
impl<'a, 'b> ProgramVisitor<'a> for ConstantFolding<'a, 'b> {}
impl<'a, 'b> AsgPass<'a> for ConstantFolding<'a, 'b> {
fn do_pass(asg: Program<'a>) -> Result<Program<'a>> {
let pass = ConstantFolding { program: &asg };
let mut director = VisitorDirector::new(pass);
director.visit_program(&asg).ok();
Ok(asg)
}
}

View File

@ -1,74 +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 std::cell::Cell;
use leo_asg::*;
use leo_errors::Result;
pub struct DeadCodeElimination {}
impl<'a> ReconstructingReducerExpression<'a> for DeadCodeElimination {}
impl<'a> ReconstructingReducerProgram<'a> for DeadCodeElimination {}
impl<'a> ReconstructingReducerStatement<'a> for DeadCodeElimination {
///
/// Removes dead code inside a false conditional statement block.
///
fn reduce_statement_alloc(
&mut self,
context: AsgContext<'a>,
_input: &'a Statement<'a>,
value: Statement<'a>,
) -> &'a Statement<'a> {
match &value {
Statement::Conditional(conditional) => match conditional.condition.get().const_value() {
Some(ConstValue::Boolean(true)) => conditional.result.get(),
Some(ConstValue::Boolean(false)) => {
if let Some(if_false) = conditional.next.get() {
if_false
} else {
context.alloc_statement(Statement::Empty(conditional.span.clone()))
}
}
_ => context.alloc_statement(value),
},
_ => context.alloc_statement(value),
}
}
fn reduce_block(&mut self, input: BlockStatement<'a>, mut statements: Vec<&'a Statement<'a>>) -> Statement<'a> {
let first_return = statements.iter().position(|x| matches!(x, Statement::Return(_)));
if let Some(first_return) = first_return {
statements.truncate(first_return + 1);
}
Statement::Block(BlockStatement {
parent: input.parent,
span: input.span,
statements: statements.into_iter().map(Cell::new).collect(),
scope: input.scope,
})
}
}
impl<'a> AsgPass<'a> for DeadCodeElimination {
fn do_pass(asg: Program<'a>) -> Result<Program<'a>> {
let pass = DeadCodeElimination {};
let mut director = ReconstructingDirector::new(asg.context, pass);
Ok(director.reduce_program(asg))
}
}

View File

@ -1,23 +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/>.
#![doc = include_str!("../README.md")]
pub mod constant_folding;
pub use constant_folding::*;
pub mod dead_code_elimination;
pub use dead_code_elimination::*;

View File

@ -1,56 +0,0 @@
[package]
name = "leo-asg"
version = "1.5.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "ASG of the Leo programming language"
homepage = "https://aleo.org"
repository = "https://github.com/AleoHQ/leo"
keywords = [
"aleo",
"cryptography",
"leo",
"programming-language",
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2021"
rust-version = "1.56.1"
[dependencies.leo-ast]
version = "1.5.3"
path = "../ast"
[dependencies.leo-ast-passes]
path = "../ast-passes"
version = "1.5.3"
[dependencies.leo-errors]
path = "../errors"
version = "1.5.3"
[dependencies.leo-parser]
version = "1.5.3"
path = "../parser"
[dependencies.indexmap]
version = "1.7"
[dependencies.num-bigint]
version = "0.4"
[dependencies.serde]
version = "1.0"
[dependencies.serde_json]
version = "1.0"
[dependencies.tendril]
version = "0.4"
[dependencies.typed-arena]
version = "2.0"
[dev-dependencies.criterion]
version = "0.3"

View File

@ -1,5 +0,0 @@
# leo-asg
[![Crates.io](https://img.shields.io/crates/v/leo-asg.svg?color=neon)](https://crates.io/crates/leo-asg)
[![Authors](https://img.shields.io/badge/authors-Aleo-orange.svg)](../AUTHORS)
[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.md)

View File

@ -1,20 +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/>.
//! Helper methods to determine the correct return value path in an asg.
mod return_path;
pub use return_path::*;

View File

@ -1,118 +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::{statement::*, BoolAnd, Expression, Monoid, MonoidalReducerExpression, MonoidalReducerStatement, Node};
use leo_errors::Span;
pub struct ReturnPathReducer {
pub errors: Vec<(Span, String)>,
}
impl ReturnPathReducer {
fn record_error(&mut self, span: Option<&Span>, error: String) {
self.errors.push((span.cloned().unwrap_or_default(), error));
}
pub fn new() -> ReturnPathReducer {
ReturnPathReducer { errors: vec![] }
}
}
impl Default for ReturnPathReducer {
fn default() -> Self {
Self::new()
}
}
#[allow(unused_variables)]
impl<'a> MonoidalReducerExpression<'a, BoolAnd> for ReturnPathReducer {
fn reduce_expression(&mut self, input: &'a Expression<'a>, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
}
#[allow(unused_variables)]
impl<'a> MonoidalReducerStatement<'a, BoolAnd> for ReturnPathReducer {
fn reduce_assign_access(&mut self, input: &AssignAccess, left: Option<BoolAnd>, right: Option<BoolAnd>) -> BoolAnd {
BoolAnd(false)
}
fn reduce_assign(&mut self, input: &AssignStatement, accesses: Vec<BoolAnd>, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
fn reduce_block(&mut self, input: &BlockStatement, statements: Vec<BoolAnd>) -> BoolAnd {
if statements.is_empty() {
BoolAnd(false)
} else if let Some(index) = statements[..statements.len() - 1].iter().map(|x| x.0).position(|x| x) {
self.record_error(
input.statements[index].get().span(),
"dead code due to unconditional early return".to_string(),
);
BoolAnd(true)
} else {
BoolAnd(statements[statements.len() - 1].0)
}
}
fn reduce_conditional_statement(
&mut self,
input: &ConditionalStatement,
condition: BoolAnd,
if_true: BoolAnd,
if_false: Option<BoolAnd>,
) -> BoolAnd {
if if_false.as_ref().map(|x| x.0).unwrap_or(false) != if_true.0 {
self.record_error(
input.span(),
"cannot have asymmetrical return in if statement".to_string(),
);
}
if_true.append(if_false.unwrap_or(BoolAnd(false)))
}
fn reduce_formatted_string(&mut self, input: &ConsoleArgs, parameters: Vec<BoolAnd>) -> BoolAnd {
BoolAnd(false)
}
fn reduce_console(&mut self, input: &ConsoleStatement, argument: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
fn reduce_definition(&mut self, input: &DefinitionStatement, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
fn reduce_expression_statement(&mut self, input: &ExpressionStatement, expression: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
fn reduce_iteration(
&mut self,
input: &IterationStatement,
start: BoolAnd,
stop: BoolAnd,
body: BoolAnd,
) -> BoolAnd {
// loops are const defined ranges, so we could probably check if they run one and emit here
BoolAnd(false)
}
fn reduce_return(&mut self, input: &ReturnStatement, value: BoolAnd) -> BoolAnd {
BoolAnd(true)
}
}

View File

@ -1,363 +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::{Circuit, Identifier, IntegerType, Type};
use leo_errors::{AsgError, Result, Span};
use indexmap::IndexMap;
use num_bigint::BigInt;
use std::{convert::TryInto, fmt};
use tendril::StrTendril;
/// Constant integer values in a program.
#[derive(Clone, Debug, PartialEq)]
pub enum ConstInt {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
}
/// Specifies how to calculate a group coordinate in a program.
#[derive(Clone, Debug, PartialEq)]
pub enum GroupCoordinate {
/// Explicit field element number string.
Number(StrTendril),
/// Attempt to recover with a sign high bit.
SignHigh,
/// Attempt to recover with a sign low bit.
SignLow,
/// Try recovering with a sign low - upon failure try sign high.
Inferred,
}
impl fmt::Display for GroupCoordinate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GroupCoordinate::Number(number) => write!(f, "{}", number),
GroupCoordinate::SignHigh => write!(f, "+"),
GroupCoordinate::SignLow => write!(f, "-"),
GroupCoordinate::Inferred => write!(f, "_"),
}
}
}
impl From<&leo_ast::GroupCoordinate> for GroupCoordinate {
fn from(other: &leo_ast::GroupCoordinate) -> GroupCoordinate {
use leo_ast::GroupCoordinate::*;
match other {
Number(value, _) => GroupCoordinate::Number(value.clone()),
SignHigh => GroupCoordinate::SignHigh,
SignLow => GroupCoordinate::SignLow,
Inferred => GroupCoordinate::Inferred,
}
}
}
impl Into<leo_ast::GroupCoordinate> for &GroupCoordinate {
fn into(self) -> leo_ast::GroupCoordinate {
use GroupCoordinate::*;
match self {
Number(value) => leo_ast::GroupCoordinate::Number(value.clone(), Default::default()),
SignHigh => leo_ast::GroupCoordinate::SignHigh,
SignLow => leo_ast::GroupCoordinate::SignLow,
Inferred => leo_ast::GroupCoordinate::Inferred,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum GroupValue {
Single(StrTendril),
Tuple(GroupCoordinate, GroupCoordinate),
}
impl From<leo_ast::GroupValue> for GroupValue {
fn from(other: leo_ast::GroupValue) -> Self {
use leo_ast::GroupValue::*;
match other {
Single(value, _) => GroupValue::Single(value),
Tuple(value) => GroupValue::Tuple(GroupCoordinate::from(&value.x), GroupCoordinate::from(&value.y)),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum CharValue {
Scalar(char),
NonScalar(u32),
}
impl From<&leo_ast::Char> for CharValue {
fn from(other: &leo_ast::Char) -> Self {
use leo_ast::Char::*;
match other {
Scalar(value) => CharValue::Scalar(*value),
NonScalar(value) => CharValue::NonScalar(*value),
}
}
}
impl Into<leo_ast::Char> for &CharValue {
fn into(self) -> leo_ast::Char {
use leo_ast::Char::*;
match self {
CharValue::Scalar(value) => Scalar(*value),
CharValue::NonScalar(value) => NonScalar(*value),
}
}
}
impl From<leo_ast::CharValue> for CharValue {
fn from(other: leo_ast::CharValue) -> Self {
Self::from(&other.character)
}
}
#[derive(Clone, PartialEq)]
pub enum ConstValue<'a> {
Int(ConstInt),
Group(GroupValue),
Field(BigInt),
Address(StrTendril),
Boolean(bool),
Char(CharValue),
// compounds
Tuple(Vec<ConstValue<'a>>),
Array(Vec<ConstValue<'a>>),
Circuit(&'a Circuit<'a>, IndexMap<String, (Identifier, ConstValue<'a>)>),
}
macro_rules! const_int_op {
($name: ident, $retType: ty, $x: ident, $transform: expr) => {
pub fn $name(&self) -> $retType {
match self {
ConstInt::I8($x) => $transform,
ConstInt::I16($x) => $transform,
ConstInt::I32($x) => $transform,
ConstInt::I64($x) => $transform,
ConstInt::I128($x) => $transform,
ConstInt::U8($x) => $transform,
ConstInt::U16($x) => $transform,
ConstInt::U32($x) => $transform,
ConstInt::U64($x) => $transform,
ConstInt::U128($x) => $transform,
}
}
};
}
macro_rules! const_int_biop {
($name: ident, $retType: ty, $x: ident, $y: ident, $transform: expr) => {
pub fn $name(&self, other: &ConstInt) -> Option<$retType> {
match (self, other) {
(ConstInt::I8($x), ConstInt::I8($y)) => $transform,
(ConstInt::I16($x), ConstInt::I16($y)) => $transform,
(ConstInt::I32($x), ConstInt::I32($y)) => $transform,
(ConstInt::I64($x), ConstInt::I64($y)) => $transform,
(ConstInt::I128($x), ConstInt::I128($y)) => $transform,
(ConstInt::U8($x), ConstInt::U8($y)) => $transform,
(ConstInt::U16($x), ConstInt::U16($y)) => $transform,
(ConstInt::U32($x), ConstInt::U32($y)) => $transform,
(ConstInt::U64($x), ConstInt::U64($y)) => $transform,
(ConstInt::U128($x), ConstInt::U128($y)) => $transform,
_ => None,
}
}
};
}
macro_rules! const_int_map {
($name: ident, $x: ident, $transform: expr) => {
pub fn $name(&self) -> Option<ConstInt> {
Some(match self {
ConstInt::I8($x) => ConstInt::I8($transform),
ConstInt::I16($x) => ConstInt::I16($transform),
ConstInt::I32($x) => ConstInt::I32($transform),
ConstInt::I64($x) => ConstInt::I64($transform),
ConstInt::I128($x) => ConstInt::I128($transform),
ConstInt::U8($x) => ConstInt::U8($transform),
ConstInt::U16($x) => ConstInt::U16($transform),
ConstInt::U32($x) => ConstInt::U32($transform),
ConstInt::U64($x) => ConstInt::U64($transform),
ConstInt::U128($x) => ConstInt::U128($transform),
})
}
};
}
macro_rules! const_int_bimap {
($name: ident, $x: ident, $y: ident, $transform: expr) => {
pub fn $name(&self, other: &ConstInt) -> Option<ConstInt> {
Some(match (self, other) {
(ConstInt::I8($x), ConstInt::I8($y)) => ConstInt::I8($transform),
(ConstInt::I16($x), ConstInt::I16($y)) => ConstInt::I16($transform),
(ConstInt::I32($x), ConstInt::I32($y)) => ConstInt::I32($transform),
(ConstInt::I64($x), ConstInt::I64($y)) => ConstInt::I64($transform),
(ConstInt::I128($x), ConstInt::I128($y)) => ConstInt::I128($transform),
(ConstInt::U8($x), ConstInt::U8($y)) => ConstInt::U8($transform),
(ConstInt::U16($x), ConstInt::U16($y)) => ConstInt::U16($transform),
(ConstInt::U32($x), ConstInt::U32($y)) => ConstInt::U32($transform),
(ConstInt::U64($x), ConstInt::U64($y)) => ConstInt::U64($transform),
(ConstInt::U128($x), ConstInt::U128($y)) => ConstInt::U128($transform),
_ => return None,
})
}
};
}
#[allow(clippy::useless_conversion)]
impl ConstInt {
const_int_op!(raw_value, String, x, format!("{}", x));
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)?);
const_int_bimap!(value_sub, x, y, x.checked_sub(*y)?);
const_int_bimap!(value_mul, x, y, x.checked_mul(*y)?);
const_int_bimap!(value_div, x, y, x.checked_div(*y)?);
// TODO: limited to 32 bit exponents
const_int_bimap!(value_pow, x, y, x.checked_pow((*y).try_into().ok()?)?);
const_int_biop!(value_lt, bool, x, y, Some(x < y));
const_int_biop!(value_le, bool, x, y, Some(x <= y));
const_int_biop!(value_gt, bool, x, y, Some(x > y));
const_int_biop!(value_ge, bool, x, y, Some(x >= y));
pub fn get_int_type(&self) -> IntegerType {
match self {
ConstInt::I8(_) => IntegerType::I8,
ConstInt::I16(_) => IntegerType::I16,
ConstInt::I32(_) => IntegerType::I32,
ConstInt::I64(_) => IntegerType::I64,
ConstInt::I128(_) => IntegerType::I128,
ConstInt::U8(_) => IntegerType::U8,
ConstInt::U16(_) => IntegerType::U16,
ConstInt::U32(_) => IntegerType::U32,
ConstInt::U64(_) => IntegerType::U64,
ConstInt::U128(_) => IntegerType::U128,
}
}
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())
}
pub fn parse(int_type: &IntegerType, value: &str, span: &Span) -> Result<ConstInt> {
Ok(match int_type {
IntegerType::I8 => ConstInt::I8(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::I16 => ConstInt::I16(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::I32 => ConstInt::I32(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::I64 => ConstInt::I64(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::I128 => ConstInt::I128(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::U8 => ConstInt::U8(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::U16 => ConstInt::U16(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::U32 => ConstInt::U32(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::U64 => ConstInt::U64(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
IntegerType::U128 => ConstInt::U128(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
})
}
}
impl<'a> ConstValue<'a> {
pub fn get_type(&'a self) -> Option<Type<'a>> {
Some(match self {
ConstValue::Int(i) => i.get_type(),
ConstValue::Group(_) => Type::Group,
ConstValue::Field(_) => Type::Field,
ConstValue::Address(_) => Type::Address,
ConstValue::Boolean(_) => Type::Boolean,
ConstValue::Char(_) => Type::Char,
ConstValue::Tuple(sub_consts) => {
Type::Tuple(sub_consts.iter().map(|x| x.get_type()).collect::<Option<Vec<Type>>>()?)
}
ConstValue::Array(values) => Type::Array(Box::new(values.get(0)?.get_type()?), values.len()),
ConstValue::Circuit(circuit, _) => Type::Circuit(circuit),
})
}
pub fn int(&self) -> Option<&ConstInt> {
match self {
ConstValue::Int(x) => Some(x),
_ => None,
}
}
pub fn field(&self) -> Option<&BigInt> {
match self {
ConstValue::Field(x) => Some(x),
_ => None,
}
}
}

View File

@ -1,102 +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 std::{cell::Cell, unimplemented};
use typed_arena::Arena;
use crate::{Alias, ArenaNode, Circuit, Expression, Function, Scope, Statement, Variable};
pub struct AsgContextInner<'a> {
pub arena: &'a Arena<ArenaNode<'a>>,
pub next_id: Cell<u32>,
}
impl<'a> AsgContextInner<'a> {
pub fn new(arena: &'a Arena<ArenaNode<'a>>) -> &'a Self {
match arena.alloc(ArenaNode::Inner(AsgContextInner {
arena,
next_id: Cell::new(0),
})) {
ArenaNode::Inner(x) => x,
_ => unimplemented!(),
}
}
pub fn get_id(&self) -> u32 {
let next_id = self.next_id.get();
self.next_id.replace(next_id + 1);
next_id
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_expression(&'a self, expr: Expression<'a>) -> &'a Expression<'a> {
match self.arena.alloc(ArenaNode::Expression(expr)) {
ArenaNode::Expression(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_statement(&'a self, statement: Statement<'a>) -> &'a Statement<'a> {
match self.arena.alloc(ArenaNode::Statement(statement)) {
ArenaNode::Statement(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_variable(&'a self, variable: Variable<'a>) -> &'a Variable<'a> {
match self.arena.alloc(ArenaNode::Variable(variable)) {
ArenaNode::Variable(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_scope(&'a self, scope: Scope<'a>) -> &'a Scope<'a> {
match self.arena.alloc(ArenaNode::Scope(Box::new(scope))) {
ArenaNode::Scope(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_alias(&'a self, expr: Alias<'a>) -> &'a Alias<'a> {
match self.arena.alloc(ArenaNode::Alias(expr)) {
ArenaNode::Alias(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_circuit(&'a self, circuit: Circuit<'a>) -> &'a Circuit<'a> {
match self.arena.alloc(ArenaNode::Circuit(circuit)) {
ArenaNode::Circuit(e) => e,
_ => unimplemented!(),
}
}
#[allow(clippy::mut_from_ref)]
pub fn alloc_function(&'a self, function: Function<'a>) -> &'a Function<'a> {
match self.arena.alloc(ArenaNode::Function(function)) {
ArenaNode::Function(e) => e,
_ => unimplemented!(),
}
}
}
pub type AsgContext<'a> = &'a AsgContextInner<'a>;

View File

@ -1,145 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_ast::IntegerType;
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ArrayAccessExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub array: Cell<&'a Expression<'a>>,
pub index: Cell<&'a Expression<'a>>,
}
impl<'a> Node for ArrayAccessExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for ArrayAccessExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.array.get().set_parent(expr);
self.index.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
match self.array.get().get_type() {
Some(Type::Array(element, _)) => Some(*element),
_ => None,
}
}
fn is_mut_ref(&self) -> bool {
self.array.get().is_mut_ref()
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let mut array = match self.array.get().const_value()? {
ConstValue::Array(values) => values,
_ => return None,
};
let const_index = match self.index.get().const_value()? {
ConstValue::Int(x) => x.to_usize()?,
_ => return None,
};
if const_index >= array.len() {
return None;
}
Some(array.remove(const_index))
}
fn is_consty(&self) -> bool {
self.array.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::ArrayAccessExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<ArrayAccessExpression<'a>> {
let array = <&Expression<'a>>::from_ast(
scope,
&*value.array,
Some(PartialType::Array(expected_type.map(Box::new), None)),
)?;
let array_len = match array.get_type() {
Some(Type::Array(_, len)) => Some(len),
Some(Type::ArrayWithoutSize(_)) => None,
type_ => {
return Err(AsgError::unexpected_type(
"array",
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
};
let index = <&Expression<'a>>::from_ast(
scope,
&*value.index,
Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?;
if let Some(index) = index
.const_value()
.map(|x| x.int().map(|x| x.to_usize()).flatten())
.flatten()
{
// Only check index if array size is known.
// Array out of bounds will be caught later if it really happens.
if let Some(array_len) = array_len {
if index >= array_len {
return Err(
AsgError::array_index_out_of_bounds(index, &array.span().cloned().unwrap_or_default()).into(),
);
}
}
}
Ok(ArrayAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
array: Cell::new(array),
index: Cell::new(index),
})
}
}
impl<'a> Into<leo_ast::ArrayAccessExpression> for &ArrayAccessExpression<'a> {
fn into(self) -> leo_ast::ArrayAccessExpression {
leo_ast::ArrayAccessExpression {
array: Box::new(self.array.get().into()),
index: Box::new(self.index.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,157 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ArrayInitExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub element: Cell<&'a Expression<'a>>,
pub len: usize,
}
impl<'a> Node for ArrayInitExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for ArrayInitExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.element.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
Some(Type::Array(Box::new(self.element.get().get_type()?), self.len))
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let element = self.element.get().const_value()?;
Some(ConstValue::Array(vec![element; self.len]))
}
fn is_consty(&self) -> bool {
self.element.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::ArrayInitExpression> for ArrayInitExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::ArrayInitExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<ArrayInitExpression<'a>> {
let (mut expected_item, expected_len) = match expected_type {
Some(PartialType::Array(item, dims)) => (item.map(|x| *x), dims),
None => (None, None),
Some(type_) => {
return Err(AsgError::unexpected_type("array", type_, &value.span).into());
}
};
let dimensions = value
.dimensions
.0
.iter()
.map(|x| {
Ok(x.value
.parse::<usize>()
.map_err(|_| AsgError::parse_dimension_error(&value.span))?)
})
.collect::<Result<Vec<_>>>()?;
let len = *dimensions
.get(0)
.ok_or_else(|| AsgError::parse_dimension_error(&value.span))?;
if let Some(expected_len) = expected_len {
if expected_len != len {
return Err(AsgError::unexpected_type(
format!("array of length {}", expected_len),
format!("array of length {}", len),
&value.span,
)
.into());
}
}
for dimension in (&dimensions[1..]).iter().copied() {
expected_item = match expected_item {
Some(PartialType::Array(item, len)) => {
if let Some(len) = len {
if len != dimension {
return Err(AsgError::unexpected_type(
format!("array of length {}", dimension),
format!("array of length {}", len),
&value.span,
)
.into());
}
}
item.map(|x| *x)
}
None => None,
Some(type_) => {
return Err(AsgError::unexpected_type("array", type_, &value.span).into());
}
}
}
let mut element = Some(<&'a Expression<'a>>::from_ast(scope, &*value.element, expected_item)?);
let mut output = None;
for dimension in dimensions.iter().rev().copied() {
output = Some(ArrayInitExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
element: Cell::new(
output
.map(Expression::ArrayInit)
.map(|expr| &*scope.context.alloc_expression(expr))
.unwrap_or_else(|| element.take().unwrap()),
),
len: dimension,
});
}
Ok(output.unwrap())
}
}
impl<'a> Into<leo_ast::ArrayInitExpression> for &ArrayInitExpression<'a> {
fn into(self) -> leo_ast::ArrayInitExpression {
leo_ast::ArrayInitExpression {
element: Box::new(self.element.get().into()),
dimensions: leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber {
value: self.len.to_string().into(),
}]),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,219 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_ast::SpreadOrExpression;
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ArrayInlineExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub elements: Vec<(Cell<&'a Expression<'a>>, bool)>, // bool = if spread
}
impl<'a> ArrayInlineExpression<'a> {
pub fn expanded_length(&self) -> usize {
self.elements
.iter()
.map(|(expr, is_spread)| {
if *is_spread {
match expr.get().get_type() {
Some(Type::Array(_item, len)) => len,
_ => 0,
}
} else {
1
}
})
.sum()
}
}
impl<'a> Node for ArrayInlineExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for ArrayInlineExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.elements.iter().for_each(|(element, _)| {
element.get().set_parent(expr);
})
}
fn get_type(&self) -> Option<Type<'a>> {
let first = self.elements.first()?;
let inner_type = match first.0.get().get_type()? {
Type::Array(inner, _) if first.1 => *inner,
_ => first.0.get().get_type()?,
};
Some(Type::Array(Box::new(inner_type), self.expanded_length()))
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let mut const_values = vec![];
for (expr, spread) in self.elements.iter() {
if *spread {
match expr.get().const_value()? {
ConstValue::Array(items) => const_values.extend(items),
_ => return None,
}
} else {
const_values.push(expr.get().const_value()?);
}
}
Some(ConstValue::Array(const_values))
}
fn is_consty(&self) -> bool {
self.elements.iter().all(|x| x.0.get().is_consty())
}
}
impl<'a> FromAst<'a, leo_ast::ArrayInlineExpression> for ArrayInlineExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::ArrayInlineExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<ArrayInlineExpression<'a>> {
let (mut expected_item, expected_len) = match expected_type {
Some(PartialType::Array(item, dims)) => (item.map(|x| *x), dims),
Some(PartialType::Type(Type::ArrayWithoutSize(item))) => (Some(item.partial()), None),
None => (None, None),
Some(type_) => {
return Err(AsgError::unexpected_type("array", type_, &value.span).into());
}
};
// 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()),
elements: value
.elements
.iter()
.map(|e| match e {
SpreadOrExpression::Expression(e) => {
let expr = <&Expression<'a>>::from_ast(scope, e, expected_item.clone())?;
if expected_item.is_none() {
expected_item = expr.get_type().map(Type::partial);
}
len += 1;
Ok((Cell::new(expr), false))
}
SpreadOrExpression::Spread(e) => {
let expr = <&Expression<'a>>::from_ast(
scope,
e,
Some(PartialType::Array(expected_item.clone().map(Box::new), None)),
)?;
match expr.get_type() {
Some(Type::Array(item, spread_len)) => {
if expected_item.is_none() {
expected_item = Some((*item).partial());
}
len += spread_len;
}
type_ => {
return Err(AsgError::unexpected_type(
expected_item
.as_ref()
.map(|x| x.to_string())
.as_deref()
.unwrap_or("unknown"),
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
}
Ok((Cell::new(expr), true))
}
})
.collect::<Result<Vec<_>>>()?,
};
if let Some(expected_len) = expected_len {
if len != expected_len {
return Err(AsgError::unexpected_type(
format!("array of length {}", expected_len),
format!("array of length {}", len),
&value.span,
)
.into());
}
}
Ok(output)
}
}
impl<'a> Into<leo_ast::ArrayInlineExpression> for &ArrayInlineExpression<'a> {
fn into(self) -> leo_ast::ArrayInlineExpression {
leo_ast::ArrayInlineExpression {
elements: self
.elements
.iter()
.map(|(element, spread)| {
let element = element.get().into();
if *spread {
SpreadOrExpression::Spread(element)
} else {
SpreadOrExpression::Expression(element)
}
})
.collect(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,227 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_ast::IntegerType;
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ArrayRangeAccessExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub array: Cell<&'a Expression<'a>>,
pub left: Cell<Option<&'a Expression<'a>>>,
pub right: Cell<Option<&'a Expression<'a>>>,
// this is either const(right) - const(left) OR the length inferred by type checking
// special attention must be made to update this if semantic-altering changes are made to left or right.
pub length: usize,
}
impl<'a> Node for ArrayRangeAccessExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for ArrayRangeAccessExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.array.get().set_parent(expr);
self.array.get().enforce_parents(self.array.get());
if let Some(left) = self.left.get() {
left.set_parent(expr);
}
if let Some(right) = self.right.get() {
right.set_parent(expr);
}
}
fn get_type(&self) -> Option<Type<'a>> {
let element = match self.array.get().get_type() {
Some(Type::Array(element, _)) => element,
_ => return None,
};
Some(Type::Array(element, self.length))
}
fn is_mut_ref(&self) -> bool {
self.array.get().is_mut_ref()
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let mut array = match self.array.get().const_value()? {
ConstValue::Array(values) => values,
_ => return None,
};
let const_left = match self.left.get().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => 0,
_ => return None,
};
let const_right = match self.right.get().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array.len(),
_ => return None,
};
if const_left > const_right || const_right as usize > array.len() {
return None;
}
Some(ConstValue::Array(array.drain(const_left..const_right).collect()))
}
fn is_consty(&self) -> bool {
self.array.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::ArrayRangeAccessExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<ArrayRangeAccessExpression<'a>> {
let (expected_array, expected_len) = match expected_type.clone() {
Some(PartialType::Array(element, len)) => (Some(PartialType::Array(element, None)), len),
None => (None, None),
Some(x) => {
return Err(AsgError::unexpected_type("array", x, &value.span).into());
}
};
let array = <&Expression<'a>>::from_ast(scope, &*value.array, expected_array)?;
let array_type = array.get_type();
let (parent_element, parent_size) = match array_type {
Some(Type::Array(inner, size)) => (inner, size),
type_ => {
return Err(AsgError::unexpected_type(
"array",
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
};
let left = value
.left
.as_deref()
.map(|left| {
<&Expression<'a>>::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?;
let right = value
.right
.as_deref()
.map(|right| {
<&Expression<'a>>::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?;
let const_left = match left.map(|x| x.const_value()) {
Some(Some(ConstValue::Int(x))) => x.to_usize(),
None => Some(0),
_ => None,
};
let const_right = match right.map(|x| x.const_value()) {
Some(Some(ConstValue::Int(inner_value))) => {
let usize_value = inner_value.to_usize();
if let Some(inner_value) = usize_value {
if inner_value > parent_size {
let error_span = if let Some(right) = right {
right.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgError::array_index_out_of_bounds(inner_value, &error_span).into());
} else if let Some(left) = const_left {
if left > inner_value {
let error_span = if let Some(right) = right {
right.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgError::array_index_out_of_bounds(inner_value, &error_span).into());
}
}
}
usize_value
}
None => Some(parent_size),
_ => None,
};
let mut length = if let (Some(left), Some(right)) = (const_left, const_right) {
Some(right - left)
} else {
None
};
if let Some(expected_len) = expected_len {
if let Some(length) = length {
if length != expected_len {
let concrete_type = Type::Array(parent_element, length);
return Err(
AsgError::unexpected_type(expected_type.as_ref().unwrap(), concrete_type, &value.span).into(),
);
}
}
if let Some(left_value) = const_left {
if left_value + expected_len > parent_size {
let error_span = if let Some(left) = left {
left.span().cloned().unwrap_or_default()
} else {
value.span.clone()
};
return Err(AsgError::array_index_out_of_bounds(left_value, &error_span).into());
}
}
length = Some(expected_len);
}
if length.is_none() {
return Err(AsgError::unknown_array_size(&value.span).into());
}
Ok(ArrayRangeAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
array: Cell::new(array),
left: Cell::new(left),
right: Cell::new(right),
length: length.unwrap(),
})
}
}
impl<'a> Into<leo_ast::ArrayRangeAccessExpression> for &ArrayRangeAccessExpression<'a> {
fn into(self) -> leo_ast::ArrayRangeAccessExpression {
leo_ast::ArrayRangeAccessExpression {
array: Box::new(self.array.get().into()),
left: self.left.get().map(|left| Box::new(left.into())),
right: self.right.get().map(|right| Box::new(right.into())),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,242 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
pub use leo_ast::{BinaryOperation, BinaryOperationClass};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct BinaryExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub operation: BinaryOperation,
pub left: Cell<&'a Expression<'a>>,
pub right: Cell<&'a Expression<'a>>,
}
impl<'a> Node for BinaryExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for BinaryExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.left.get().set_parent(expr);
self.right.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
match self.operation.class() {
BinaryOperationClass::Boolean => Some(Type::Boolean),
BinaryOperationClass::Numeric => self.left.get().get_type(),
}
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue> {
use BinaryOperation::*;
let left = self.left.get().const_value()?;
let right = self.right.get().const_value()?;
match (left, right) {
(ConstValue::Int(left), ConstValue::Int(right)) => Some(match self.operation {
Add => ConstValue::Int(left.value_add(&right)?),
Sub => ConstValue::Int(left.value_sub(&right)?),
Mul => ConstValue::Int(left.value_mul(&right)?),
Div => ConstValue::Int(left.value_div(&right)?),
Pow => ConstValue::Int(left.value_pow(&right)?),
Eq => ConstValue::Boolean(left == right),
Ne => ConstValue::Boolean(left != right),
Ge => ConstValue::Boolean(left.value_ge(&right)?),
Gt => ConstValue::Boolean(left.value_gt(&right)?),
Le => ConstValue::Boolean(left.value_le(&right)?),
Lt => ConstValue::Boolean(left.value_lt(&right)?),
_ => return None,
}),
// (ConstValue::Field(left), ConstValue::Field(right)) => {
// Some(match self.operation {
// Add => ConstValue::Field(left.checked_add(&right)?),
// Sub => ConstValue::Field(left.checked_sub(&right)?),
// Mul => ConstValue::Field(left.checked_mul(&right)?),
// Div => ConstValue::Field(left.checked_div(&right)?),
// Eq => ConstValue::Boolean(left == right),
// Ne => ConstValue::Boolean(left != right),
// _ => return None,
// })
// },
(ConstValue::Boolean(left), ConstValue::Boolean(right)) => Some(match self.operation {
Eq => ConstValue::Boolean(left == right),
Ne => ConstValue::Boolean(left != right),
And => ConstValue::Boolean(left && right),
Or => ConstValue::Boolean(left || right),
_ => return None,
}),
//todo: group?
(left, right) => Some(match self.operation {
Eq => ConstValue::Boolean(left == right),
Ne => ConstValue::Boolean(left != right),
_ => return None,
}),
}
}
fn is_consty(&self) -> bool {
self.left.get().is_consty() && self.right.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::BinaryExpression> for BinaryExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::BinaryExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<BinaryExpression<'a>> {
let class = value.op.class();
let expected_type = match class {
BinaryOperationClass::Boolean => match expected_type {
Some(PartialType::Type(Type::Boolean)) | None => None,
Some(x) => {
return Err(AsgError::unexpected_type(Type::Boolean, x, &value.span).into());
}
},
BinaryOperationClass::Numeric => match expected_type {
Some(x @ PartialType::Integer(_, _)) => Some(x),
Some(x @ PartialType::Type(Type::Field)) => Some(x),
Some(x @ PartialType::Type(Type::Group)) => Some(x),
Some(x) => {
return Err(AsgError::unexpected_type("integer, field, or group", x, &value.span).into());
}
None => None,
},
};
// left
let (left, right) = match <&Expression<'a>>::from_ast(scope, &*value.left, expected_type.clone()) {
Ok(left) => {
if let Some(left_type) = left.get_type() {
let right = <&Expression<'a>>::from_ast(scope, &*value.right, Some(left_type.partial()))?;
(left, right)
} else {
let right = <&Expression<'a>>::from_ast(scope, &*value.right, expected_type)?;
if let Some(right_type) = right.get_type() {
(
<&Expression<'a>>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
right,
)
} else {
(left, right)
}
}
}
Err(e) => {
let right = <&Expression<'a>>::from_ast(scope, &*value.right, expected_type)?;
if let Some(right_type) = right.get_type() {
(
<&Expression<'a>>::from_ast(scope, &*value.left, Some(right_type.partial()))?,
right,
)
} else {
return Err(e);
}
}
};
let left_type = left.get_type();
#[allow(clippy::unused_unit)]
match class {
BinaryOperationClass::Numeric => match left_type {
Some(Type::Integer(_)) => (),
Some(Type::Group) | Some(Type::Field)
if value.op == BinaryOperation::Add || value.op == BinaryOperation::Sub =>
{
()
}
Some(Type::Field) if value.op == BinaryOperation::Mul || value.op == BinaryOperation::Div => (),
type_ => {
return Err(AsgError::unexpected_type(
"integer",
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
},
BinaryOperationClass::Boolean => match &value.op {
BinaryOperation::And | BinaryOperation::Or => match left_type {
Some(Type::Boolean) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(Type::Boolean, x, &value.span).into());
}
},
BinaryOperation::Eq | BinaryOperation::Ne => (), // all types allowed
op => match left_type {
Some(Type::Integer(_)) | None => (),
Some(x) => {
return Err(
AsgError::operator_allowed_only_for_type(op.as_ref(), "integer", x, &value.span).into(),
);
}
},
},
}
let right_type = right.get_type();
match (left_type, right_type) {
(Some(left_type), Some(right_type)) => {
if !left_type.is_assignable_from(&right_type) {
return Err(AsgError::unexpected_type(left_type, right_type, &value.span).into());
}
}
(None, None) => {
return Err(AsgError::unexpected_type("any type", "unknown type", &value.span).into());
}
(_, _) => (),
}
Ok(BinaryExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
operation: value.op.clone(),
left: Cell::new(left),
right: Cell::new(right),
})
}
}
impl<'a> Into<leo_ast::BinaryExpression> for &BinaryExpression<'a> {
fn into(self) -> leo_ast::BinaryExpression {
leo_ast::BinaryExpression {
op: self.operation.clone(),
left: Box::new(self.left.get().into()),
right: Box::new(self.right.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,231 +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::{
CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Function, FunctionQualifier, Node, PartialType,
Scope, Type,
};
pub use leo_ast::{BinaryOperation, Node as AstNode};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct CallExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub function: Cell<&'a Function<'a>>,
pub target: Cell<Option<&'a Expression<'a>>>,
pub arguments: Vec<Cell<&'a Expression<'a>>>,
}
impl<'a> Node for CallExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for CallExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
if let Some(target) = self.target.get() {
target.set_parent(expr);
}
self.arguments.iter().for_each(|element| {
element.get().set_parent(expr);
})
}
fn get_type(&self) -> Option<Type<'a>> {
Some(self.function.get().output.clone())
}
fn is_mut_ref(&self) -> bool {
true
}
fn const_value(&self) -> Option<ConstValue> {
// static function const evaluation
None
}
fn is_consty(&self) -> bool {
self.target.get().map(|x| x.is_consty()).unwrap_or(true) && self.arguments.iter().all(|x| x.get().is_consty())
}
}
impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::CallExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<CallExpression<'a>> {
let (target, function) = match &*value.function {
leo_ast::Expression::Identifier(name) => (
None,
scope
.resolve_function(&name.name)
.ok_or_else(|| AsgError::unresolved_function(&name.name, &name.span))?,
),
leo_ast::Expression::CircuitMemberAccess(leo_ast::CircuitMemberAccessExpression {
circuit: ast_circuit,
name,
span,
..
}) => {
let target = <&Expression<'a>>::from_ast(scope, &**ast_circuit, None)?;
let circuit = match target.get_type() {
Some(Type::Circuit(circuit)) => circuit,
type_ => {
return Err(AsgError::unexpected_type(
"circuit",
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
span,
)
.into());
}
};
let circuit_name = circuit.name.borrow().name.clone();
let member = circuit.members.borrow();
let member = member
.get(name.name.as_ref())
.ok_or_else(|| AsgError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {
if body.qualifier == FunctionQualifier::Static {
return Err(AsgError::circuit_static_call_invalid(&circuit_name, &name.name, span).into());
} else if body.qualifier == FunctionQualifier::MutSelfRef && !target.is_mut_ref() {
return Err(
AsgError::circuit_member_mut_call_invalid(circuit_name, &name.name, span).into(),
);
}
(Some(target), *body)
}
CircuitMember::Variable(_) => {
return Err(AsgError::circuit_variable_call(circuit_name, &name.name, span).into());
}
}
}
leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression {
circuit: ast_circuit,
name,
span,
}) => {
let circuit = if let leo_ast::Expression::Identifier(circuit_name) = &**ast_circuit {
scope
.resolve_circuit(&circuit_name.name)
.ok_or_else(|| AsgError::unresolved_circuit(&circuit_name.name, &circuit_name.span))?
} else {
return Err(AsgError::unexpected_type("circuit", "unknown", span).into());
};
let circuit_name = circuit.name.borrow().name.clone();
let member = circuit.members.borrow();
let member = member
.get(name.name.as_ref())
.ok_or_else(|| AsgError::unresolved_circuit_member(&circuit_name, &name.name, span))?;
match member {
CircuitMember::Function(body) => {
if body.qualifier != FunctionQualifier::Static {
return Err(AsgError::circuit_member_call_invalid(circuit_name, &name.name, span).into());
}
(None, *body)
}
CircuitMember::Variable(_) => {
return Err(AsgError::circuit_variable_call(circuit_name, &name.name, span).into());
}
}
}
_ => {
return Err(AsgError::illegal_ast_structure(
"non Identifier/CircuitMemberAccess/CircuitStaticFunctionAccess as call target",
&value.span,
)
.into());
}
};
if let Some(expected) = expected_type {
let output: Type = function.output.clone();
if !expected.matches(&output) {
return Err(AsgError::unexpected_type(expected, output, &value.span).into());
}
}
if value.arguments.len() != function.arguments.len() {
return Err(AsgError::unexpected_call_argument_count(
function.arguments.len(),
value.arguments.len(),
&value.span,
)
.into());
}
let arguments = value
.arguments
.iter()
.zip(function.arguments.iter())
.map(|(expr, (_, argument))| {
let argument = argument.get().borrow();
let converted = <&Expression<'a>>::from_ast(scope, expr, Some(argument.type_.clone().partial()))?;
if argument.const_ && !converted.is_consty() {
return Err(AsgError::unexpected_nonconst(expr.span()).into());
}
Ok(Cell::new(converted))
})
.collect::<Result<Vec<_>>>()?;
if function.is_test() {
return Err(AsgError::call_test_function(&value.span).into());
}
Ok(CallExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
arguments,
function: Cell::new(function),
target: Cell::new(target),
})
}
}
impl<'a> Into<leo_ast::CallExpression> for &CallExpression<'a> {
fn into(self) -> leo_ast::CallExpression {
let target_function = if let Some(target) = self.target.get() {
target.into()
} else {
let circuit = self.function.get().circuit.get();
if let Some(circuit) = circuit {
leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression {
circuit: Box::new(leo_ast::Expression::Identifier(circuit.name.borrow().clone())),
name: self.function.get().name.borrow().clone(),
span: self.span.clone().unwrap_or_default(),
})
} else {
leo_ast::Expression::Identifier(self.function.get().name.borrow().clone())
}
};
leo_ast::CallExpression {
function: Box::new(target_function),
arguments: self.arguments.iter().map(|arg| arg.get().into()).collect(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,106 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
pub use leo_ast::UnaryOperation;
use leo_errors::{AsgError, Result, Span};
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>> {
let target_type = scope.resolve_ast_type(&value.target_type, &value.span)?;
if let Some(expected_type) = &expected_type {
if !expected_type.matches(&target_type) {
return Err(AsgError::unexpected_type(expected_type, target_type, &value.span).into());
}
}
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

@ -1,218 +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::{
Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, PartialType, Scope, Type,
};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct CircuitAccessExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub circuit: Cell<&'a Circuit<'a>>,
pub target: Cell<Option<&'a Expression<'a>>>,
pub member: Identifier,
}
impl<'a> Node for CircuitAccessExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for CircuitAccessExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
if let Some(target) = self.target.get() {
target.set_parent(expr);
}
}
fn get_type(&self) -> Option<Type<'a>> {
if self.target.get().is_none() {
None // function target only for static
} else {
let members = self.circuit.get().members.borrow();
let member = members.get(self.member.name.as_ref())?;
match member {
CircuitMember::Variable(type_) => Some(type_.clone()),
CircuitMember::Function(_) => None,
}
}
}
fn is_mut_ref(&self) -> bool {
if let Some(target) = self.target.get() {
target.is_mut_ref()
} else {
false
}
}
fn const_value(&self) -> Option<ConstValue<'a>> {
match self.target.get()?.const_value()? {
ConstValue::Circuit(_, members) => {
let (_, const_value) = members.get(&self.member.name.to_string())?.clone();
Some(const_value)
}
_ => None,
}
}
fn is_consty(&self) -> bool {
self.target.get().map(|x| x.is_consty()).unwrap_or(true)
}
}
impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::CircuitMemberAccessExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<CircuitAccessExpression<'a>> {
let target = <&'a Expression<'a>>::from_ast(scope, &*value.circuit, None)?;
let circuit = match target.get_type() {
Some(Type::Circuit(circuit)) => circuit,
x => {
return Err(AsgError::unexpected_type(
"circuit",
x.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
};
// scoping refcell reference
let found_member = {
if let Some(member) = circuit.members.borrow().get(value.name.name.as_ref()) {
if let Some(expected_type) = &expected_type {
if let CircuitMember::Variable(type_) = &member {
let type_: Type = type_.clone();
if !expected_type.matches(&type_) {
return Err(AsgError::unexpected_type(expected_type, type_, &value.span).into());
}
} // used by call expression
}
true
} else {
false
}
};
if found_member {
// skip
} else if circuit.is_input_pseudo_circuit() {
// add new member to implicit input
if let Some(expected_type) = expected_type.map(PartialType::full).flatten() {
circuit.members.borrow_mut().insert(
value.name.name.to_string(),
CircuitMember::Variable(expected_type.clone()),
);
} else {
return Err(
AsgError::input_ref_needs_type(&circuit.name.borrow().name, &value.name.name, &value.span).into(),
);
}
} else {
return Err(AsgError::unresolved_circuit_member(
&circuit.name.borrow().name,
&value.name.name,
&value.span,
)
.into());
}
Ok(CircuitAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
target: Cell::new(Some(target)),
circuit: Cell::new(circuit),
member: value.name.clone(),
})
}
}
impl<'a> FromAst<'a, leo_ast::CircuitStaticFunctionAccessExpression> for CircuitAccessExpression<'a> {
fn from_ast(
scope: &Scope<'a>,
value: &leo_ast::CircuitStaticFunctionAccessExpression,
expected_type: Option<PartialType>,
) -> Result<CircuitAccessExpression<'a>> {
let circuit = match &*value.circuit {
leo_ast::Expression::Identifier(name) => scope
.resolve_circuit(&name.name)
.ok_or_else(|| AsgError::unresolved_circuit(&name.name, &name.span))?,
_ => {
return Err(AsgError::unexpected_type("circuit", "unknown", &value.span).into());
}
};
if let Some(expected_type) = expected_type {
return Err(AsgError::unexpected_type("none", expected_type, &value.span).into());
}
if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(value.name.name.as_ref()) {
// okay
} else {
return Err(AsgError::unresolved_circuit_member(
&circuit.name.borrow().name,
&value.name.name,
&value.span,
)
.into());
}
Ok(CircuitAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
target: Cell::new(None),
circuit: Cell::new(circuit),
member: value.name.clone(),
})
}
}
impl<'a> Into<leo_ast::Expression> for &CircuitAccessExpression<'a> {
fn into(self) -> leo_ast::Expression {
if let Some(target) = self.target.get() {
leo_ast::Expression::CircuitMemberAccess(leo_ast::CircuitMemberAccessExpression {
circuit: Box::new(target.into()),
name: self.member.clone(),
span: self.span.clone().unwrap_or_default(),
type_: None,
})
} else {
leo_ast::Expression::CircuitStaticFunctionAccess(leo_ast::CircuitStaticFunctionAccessExpression {
circuit: Box::new(leo_ast::Expression::Identifier(
self.circuit.get().name.borrow().clone(),
)),
name: self.member.clone(),
span: self.span.clone().unwrap_or_default(),
})
}
}
}

View File

@ -1,171 +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::{
Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, PartialType, Scope, Type,
};
use leo_errors::{AsgError, Result, Span};
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
#[derive(Clone)]
pub struct CircuitInitExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub circuit: Cell<&'a Circuit<'a>>,
pub values: Vec<(Identifier, Cell<&'a Expression<'a>>)>,
}
impl<'a> Node for CircuitInitExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for CircuitInitExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.values.iter().for_each(|(_, element)| {
element.get().set_parent(expr);
})
}
fn get_type(&self) -> Option<Type<'a>> {
Some(Type::Circuit(self.circuit.get()))
}
fn is_mut_ref(&self) -> bool {
true
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let mut members = IndexMap::new();
for (identifier, member) in self.values.iter() {
// insert by name because accessmembers identifiers are different.
members.insert(
identifier.name.to_string(),
(identifier.clone(), member.get().const_value()?),
);
}
// Store circuit as well for get_type.
Some(ConstValue::Circuit(self.circuit.get(), members))
}
fn is_consty(&self) -> bool {
self.values.iter().all(|(_, value)| value.get().is_consty())
}
}
impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::CircuitInitExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<CircuitInitExpression<'a>> {
let circuit = scope
.resolve_circuit(&value.name.name)
.ok_or_else(|| AsgError::unresolved_circuit(&value.name.name, &value.name.span))?;
match expected_type {
Some(PartialType::Type(Type::Circuit(expected_circuit))) if expected_circuit == circuit => (),
None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, circuit.name.borrow().name.to_string(), &value.span).into());
}
}
let members: IndexMap<&str, (&Identifier, Option<&leo_ast::Expression>)> = value
.members
.iter()
.map(|x| (x.identifier.name.as_ref(), (&x.identifier, x.expression.as_ref())))
.collect();
let mut values: Vec<(Identifier, Cell<&'a Expression<'a>>)> = vec![];
let mut defined_variables = IndexSet::<String>::new();
{
let circuit_members = circuit.members.borrow();
for (name, member) in circuit_members.iter() {
if defined_variables.contains(name) {
return Err(
AsgError::overridden_circuit_member(&circuit.name.borrow().name, name, &value.span).into(),
);
}
defined_variables.insert(name.clone());
let type_: Type = if let CircuitMember::Variable(type_) = &member {
type_.clone()
} else {
continue;
};
if let Some((identifier, receiver)) = members.get(&**name) {
let received = if let Some(receiver) = *receiver {
<&Expression<'a>>::from_ast(scope, receiver, Some(type_.partial()))?
} else {
<&Expression<'a>>::from_ast(
scope,
&leo_ast::Expression::Identifier((*identifier).clone()),
Some(type_.partial()),
)?
};
values.push(((*identifier).clone(), Cell::new(received)));
} else {
return Err(
AsgError::missing_circuit_member(&circuit.name.borrow().name, name, &value.span).into(),
);
}
}
for (name, (identifier, _expression)) in members.iter() {
if circuit_members.get(*name).is_none() {
return Err(
AsgError::extra_circuit_member(&circuit.name.borrow().name, name, &identifier.span).into(),
);
}
}
}
Ok(CircuitInitExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
circuit: Cell::new(circuit),
values,
})
}
}
impl<'a> Into<leo_ast::CircuitInitExpression> for &CircuitInitExpression<'a> {
fn into(self) -> leo_ast::CircuitInitExpression {
leo_ast::CircuitInitExpression {
name: self.circuit.get().name.borrow().clone(),
members: self
.values
.iter()
.map(|(name, value)| leo_ast::CircuitImpliedVariableDefinition {
identifier: name.clone(),
expression: Some(value.get().into()),
})
.collect(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,241 +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::{
CharValue, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, GroupValue, Node, PartialType, Scope, Type,
};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct Constant<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub value: ConstValue<'a>, // should not be compound constants
}
impl<'a> Node for Constant<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for Constant<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, _expr: &'a Expression<'a>) {}
fn get_type(&'a self) -> Option<Type<'a>> {
self.value.get_type()
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue<'a>> {
Some(self.value.clone())
}
fn is_consty(&self) -> bool {
true
}
}
impl<'a> FromAst<'a, leo_ast::ValueExpression> for Constant<'a> {
fn from_ast(
_scope: &'a Scope<'a>,
value: &leo_ast::ValueExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<Constant<'a>> {
use leo_ast::ValueExpression::*;
Ok(match value {
Address(value, span) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Address) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, Type::Address, span).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Address(value.clone()),
}
}
Boolean(value, span) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Boolean) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, Type::Boolean, span).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Boolean(
value
.parse::<bool>()
.map_err(|_| AsgError::invalid_boolean(value, span))?,
),
}
}
Char(value) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Char) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, Type::Char, value.span()).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(value.span().clone()),
value: ConstValue::Char(CharValue::from(value.clone())),
}
}
Field(value, span) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Field) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, Type::Field, span).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Field(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
}
}
Group(value) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Group) | None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, Type::Group, value.span()).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(value.span().clone()),
value: ConstValue::Group(match &**value {
leo_ast::GroupValue::Single(value, _) => GroupValue::Single(value.clone()),
leo_ast::GroupValue::Tuple(leo_ast::GroupTuple { x, y, .. }) => {
GroupValue::Tuple(x.into(), y.into())
}
}),
}
}
Implicit(value, span) => match expected_type {
None => return Err(AsgError::unresolved_type("unknown", span).into()),
Some(PartialType::Integer(Some(sub_type), _)) | Some(PartialType::Integer(None, Some(sub_type))) => {
Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Int(ConstInt::parse(&sub_type, value, span)?),
}
}
Some(PartialType::Type(Type::Field)) => Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Field(value.parse().map_err(|_| AsgError::invalid_int(value, span))?),
},
Some(PartialType::Type(Type::Group)) => Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Group(GroupValue::Single(value.clone())),
},
Some(PartialType::Type(Type::Address)) => Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Address(value.clone()),
},
Some(x) => {
return Err(AsgError::unexpected_type(x, "unknown", span).into());
}
},
Integer(int_type, value, span) => {
match expected_type {
Some(PartialType::Integer(Some(sub_type), _)) if &sub_type == int_type => (),
Some(PartialType::Integer(None, Some(_))) => (),
None => (),
Some(x) => {
return Err(AsgError::unexpected_type(x, int_type, span).into());
}
}
Constant {
parent: Cell::new(None),
span: Some(span.clone()),
value: ConstValue::Int(ConstInt::parse(int_type, value, span)?),
}
}
String(_str_type, _value) => {
unimplemented!("strings do not exist on ASG level")
}
})
}
}
impl<'a> Into<leo_ast::ValueExpression> for &Constant<'a> {
fn into(self) -> leo_ast::ValueExpression {
match &self.value {
ConstValue::Address(value) => {
leo_ast::ValueExpression::Address(value.clone(), self.span.clone().unwrap_or_default())
}
ConstValue::Boolean(value) => {
leo_ast::ValueExpression::Boolean(value.to_string().into(), self.span.clone().unwrap_or_default())
}
ConstValue::Char(value) => match value {
CharValue::Scalar(scalar) => leo_ast::ValueExpression::Char(leo_ast::CharValue {
character: leo_ast::Char::Scalar(*scalar),
span: self.span.clone().unwrap_or_default(),
}),
CharValue::NonScalar(non_scalar) => leo_ast::ValueExpression::Char(leo_ast::CharValue {
character: leo_ast::Char::NonScalar(*non_scalar),
span: self.span.clone().unwrap_or_default(),
}),
},
ConstValue::Field(value) => {
leo_ast::ValueExpression::Field(value.to_string().into(), self.span.clone().unwrap_or_default())
}
ConstValue::Group(value) => leo_ast::ValueExpression::Group(Box::new(match value {
GroupValue::Single(single) => {
leo_ast::GroupValue::Single(single.clone(), self.span.clone().unwrap_or_default())
}
GroupValue::Tuple(left, right) => leo_ast::GroupValue::Tuple(leo_ast::GroupTuple {
x: left.into(),
y: right.into(),
span: self.span.clone().unwrap_or_default(),
}),
})),
ConstValue::Int(int) => leo_ast::ValueExpression::Integer(
int.get_int_type(),
int.raw_value().into(),
self.span.clone().unwrap_or_default(),
),
ConstValue::Tuple(_) => unimplemented!(),
ConstValue::Array(_) => unimplemented!(),
ConstValue::Circuit(_, _) => unimplemented!(),
}
}
}

View File

@ -1,89 +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::{ConstValue, Expression, ExpressionNode, FromAst, IntegerType, Node, PartialType, Scope, Type};
pub use leo_ast::UnaryOperation;
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct LengthOfExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub inner: Cell<&'a Expression<'a>>,
}
impl<'a> Node for LengthOfExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for LengthOfExpression<'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(Type::Integer(IntegerType::U32)) // For now we stick to U32 value type
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue> {
None
}
fn is_consty(&self) -> bool {
true
}
}
impl<'a> FromAst<'a, leo_ast::LengthOfExpression> for LengthOfExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::LengthOfExpression,
_expected_type: Option<PartialType<'a>>,
) -> Result<LengthOfExpression<'a>> {
let inner = <&Expression<'a>>::from_ast(scope, &*value.inner, None)?;
Ok(LengthOfExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
inner: Cell::new(inner),
})
}
}
impl<'a> Into<leo_ast::LengthOfExpression> for &LengthOfExpression<'a> {
fn into(self) -> leo_ast::LengthOfExpression {
leo_ast::LengthOfExpression {
inner: Box::new(self.inner.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,388 +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/>.
//! This module defines an expression node in an asg.
//!
//! Notable differences after conversion from an ast expression include:
//! 1. Storing variable references instead of variable identifiers - better history tracking and mutability
//! 2. Resolving constant values - optimizes execution of program circuit.
mod array_access;
pub use array_access::*;
mod array_inline;
pub use array_inline::*;
mod array_init;
pub use array_init::*;
mod array_range_access;
pub use array_range_access::*;
mod binary;
pub use binary::*;
mod call;
pub use call::*;
mod circuit_access;
pub use circuit_access::*;
mod circuit_init;
pub use circuit_init::*;
mod constant;
pub use constant::*;
mod ternary;
pub use ternary::*;
mod tuple_access;
pub use tuple_access::*;
mod tuple_init;
pub use tuple_init::*;
mod unary;
pub use unary::*;
mod variable_ref;
pub use variable_ref::*;
mod cast;
pub use cast::*;
mod lengthof;
pub use lengthof::*;
use crate::{ConstValue, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{Result, Span};
#[derive(Clone)]
pub enum Expression<'a> {
VariableRef(VariableRef<'a>),
Constant(Constant<'a>),
Binary(BinaryExpression<'a>),
Unary(UnaryExpression<'a>),
Ternary(TernaryExpression<'a>),
Cast(CastExpression<'a>),
LengthOf(LengthOfExpression<'a>),
ArrayInline(ArrayInlineExpression<'a>),
ArrayInit(ArrayInitExpression<'a>),
ArrayAccess(ArrayAccessExpression<'a>),
ArrayRangeAccess(ArrayRangeAccessExpression<'a>),
TupleInit(TupleInitExpression<'a>),
TupleAccess(TupleAccessExpression<'a>),
CircuitInit(CircuitInitExpression<'a>),
CircuitAccess(CircuitAccessExpression<'a>),
Call(CallExpression<'a>),
}
impl<'a> Expression<'a> {
pub fn ptr_eq(&self, other: &Expression<'a>) -> bool {
std::ptr::eq(self as *const Expression<'a>, other as *const Expression<'a>)
}
}
impl<'a> Node for Expression<'a> {
fn span(&self) -> Option<&Span> {
use Expression::*;
match self {
VariableRef(x) => x.span(),
Constant(x) => x.span(),
Binary(x) => x.span(),
Unary(x) => x.span(),
Ternary(x) => x.span(),
Cast(x) => x.span(),
LengthOf(x) => x.span(),
ArrayInline(x) => x.span(),
ArrayInit(x) => x.span(),
ArrayAccess(x) => x.span(),
ArrayRangeAccess(x) => x.span(),
TupleInit(x) => x.span(),
TupleAccess(x) => x.span(),
CircuitInit(x) => x.span(),
CircuitAccess(x) => x.span(),
Call(x) => x.span(),
}
}
}
pub trait ExpressionNode<'a>: Node {
fn set_parent(&self, parent: &'a Expression<'a>);
fn get_parent(&self) -> Option<&'a Expression<'a>>;
fn enforce_parents(&self, expr: &'a Expression<'a>);
fn get_type(&'a self) -> Option<Type<'a>>;
fn is_mut_ref(&self) -> bool;
fn const_value(&'a self) -> Option<ConstValue>; // todo: memoize
fn is_consty(&self) -> bool;
}
impl<'a> ExpressionNode<'a> for Expression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
use Expression::*;
match self {
VariableRef(x) => x.set_parent(parent),
Constant(x) => x.set_parent(parent),
Binary(x) => x.set_parent(parent),
Unary(x) => x.set_parent(parent),
Ternary(x) => x.set_parent(parent),
Cast(x) => x.set_parent(parent),
LengthOf(x) => x.set_parent(parent),
ArrayInline(x) => x.set_parent(parent),
ArrayInit(x) => x.set_parent(parent),
ArrayAccess(x) => x.set_parent(parent),
ArrayRangeAccess(x) => x.set_parent(parent),
TupleInit(x) => x.set_parent(parent),
TupleAccess(x) => x.set_parent(parent),
CircuitInit(x) => x.set_parent(parent),
CircuitAccess(x) => x.set_parent(parent),
Call(x) => x.set_parent(parent),
}
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
use Expression::*;
match self {
VariableRef(x) => x.get_parent(),
Constant(x) => x.get_parent(),
Binary(x) => x.get_parent(),
Unary(x) => x.get_parent(),
Ternary(x) => x.get_parent(),
Cast(x) => x.get_parent(),
LengthOf(x) => x.get_parent(),
ArrayInline(x) => x.get_parent(),
ArrayInit(x) => x.get_parent(),
ArrayAccess(x) => x.get_parent(),
ArrayRangeAccess(x) => x.get_parent(),
TupleInit(x) => x.get_parent(),
TupleAccess(x) => x.get_parent(),
CircuitInit(x) => x.get_parent(),
CircuitAccess(x) => x.get_parent(),
Call(x) => x.get_parent(),
}
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
use Expression::*;
match self {
VariableRef(x) => x.enforce_parents(expr),
Constant(x) => x.enforce_parents(expr),
Binary(x) => x.enforce_parents(expr),
Unary(x) => x.enforce_parents(expr),
Ternary(x) => x.enforce_parents(expr),
Cast(x) => x.enforce_parents(expr),
LengthOf(x) => x.enforce_parents(expr),
ArrayInline(x) => x.enforce_parents(expr),
ArrayInit(x) => x.enforce_parents(expr),
ArrayAccess(x) => x.enforce_parents(expr),
ArrayRangeAccess(x) => x.enforce_parents(expr),
TupleInit(x) => x.enforce_parents(expr),
TupleAccess(x) => x.enforce_parents(expr),
CircuitInit(x) => x.enforce_parents(expr),
CircuitAccess(x) => x.enforce_parents(expr),
Call(x) => x.enforce_parents(expr),
}
}
fn get_type(&'a self) -> Option<Type<'a>> {
use Expression::*;
match self {
VariableRef(x) => x.get_type(),
Constant(x) => x.get_type(),
Binary(x) => x.get_type(),
Unary(x) => x.get_type(),
Ternary(x) => x.get_type(),
Cast(x) => x.get_type(),
LengthOf(x) => x.get_type(),
ArrayInline(x) => x.get_type(),
ArrayInit(x) => x.get_type(),
ArrayAccess(x) => x.get_type(),
ArrayRangeAccess(x) => x.get_type(),
TupleInit(x) => x.get_type(),
TupleAccess(x) => x.get_type(),
CircuitInit(x) => x.get_type(),
CircuitAccess(x) => x.get_type(),
Call(x) => x.get_type(),
}
}
fn is_mut_ref(&self) -> bool {
use Expression::*;
match self {
VariableRef(x) => x.is_mut_ref(),
Constant(x) => x.is_mut_ref(),
Binary(x) => x.is_mut_ref(),
Unary(x) => x.is_mut_ref(),
Ternary(x) => x.is_mut_ref(),
Cast(x) => x.is_mut_ref(),
LengthOf(x) => x.is_mut_ref(),
ArrayInline(x) => x.is_mut_ref(),
ArrayInit(x) => x.is_mut_ref(),
ArrayAccess(x) => x.is_mut_ref(),
ArrayRangeAccess(x) => x.is_mut_ref(),
TupleInit(x) => x.is_mut_ref(),
TupleAccess(x) => x.is_mut_ref(),
CircuitInit(x) => x.is_mut_ref(),
CircuitAccess(x) => x.is_mut_ref(),
Call(x) => x.is_mut_ref(),
}
}
fn const_value(&'a self) -> Option<ConstValue<'a>> {
use Expression::*;
match self {
VariableRef(x) => x.const_value(),
Constant(x) => x.const_value(),
Binary(x) => x.const_value(),
Unary(x) => x.const_value(),
Ternary(x) => x.const_value(),
Cast(x) => x.const_value(),
LengthOf(x) => x.const_value(),
ArrayInline(x) => x.const_value(),
ArrayInit(x) => x.const_value(),
ArrayAccess(x) => x.const_value(),
ArrayRangeAccess(x) => x.const_value(),
TupleInit(x) => x.const_value(),
TupleAccess(x) => x.const_value(),
CircuitInit(x) => x.const_value(),
CircuitAccess(x) => x.const_value(),
Call(x) => x.const_value(),
}
}
fn is_consty(&self) -> bool {
use Expression::*;
match self {
VariableRef(x) => x.is_consty(),
Constant(x) => x.is_consty(),
Binary(x) => x.is_consty(),
Unary(x) => x.is_consty(),
Ternary(x) => x.is_consty(),
Cast(x) => x.is_consty(),
LengthOf(x) => x.is_consty(),
ArrayInline(x) => x.is_consty(),
ArrayInit(x) => x.is_consty(),
ArrayAccess(x) => x.is_consty(),
ArrayRangeAccess(x) => x.is_consty(),
TupleInit(x) => x.is_consty(),
TupleAccess(x) => x.is_consty(),
CircuitInit(x) => x.is_consty(),
CircuitAccess(x) => x.is_consty(),
Call(x) => x.is_consty(),
}
}
}
impl<'a> FromAst<'a, leo_ast::Expression> for &'a Expression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::Expression,
expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
use leo_ast::Expression::*;
let expression = match value {
Identifier(identifier) => Self::from_ast(scope, identifier, expected_type)?,
Value(value) => scope
.context
.alloc_expression(Constant::from_ast(scope, value, expected_type).map(Expression::Constant)?),
Binary(binary) => scope
.context
.alloc_expression(BinaryExpression::from_ast(scope, binary, expected_type).map(Expression::Binary)?),
Unary(unary) => scope
.context
.alloc_expression(UnaryExpression::from_ast(scope, unary, expected_type).map(Expression::Unary)?),
Ternary(conditional) => scope.context.alloc_expression(
TernaryExpression::from_ast(scope, conditional, expected_type).map(Expression::Ternary)?,
),
Cast(cast) => scope
.context
.alloc_expression(CastExpression::from_ast(scope, cast, expected_type).map(Expression::Cast)?),
LengthOf(lengthof) => scope.context.alloc_expression(
LengthOfExpression::from_ast(scope, lengthof, expected_type).map(Expression::LengthOf)?,
),
ArrayInline(array_inline) => scope.context.alloc_expression(
ArrayInlineExpression::from_ast(scope, array_inline, expected_type).map(Expression::ArrayInline)?,
),
ArrayInit(array_init) => scope.context.alloc_expression(
ArrayInitExpression::from_ast(scope, array_init, expected_type).map(Expression::ArrayInit)?,
),
ArrayAccess(array_access) => scope.context.alloc_expression(
ArrayAccessExpression::from_ast(scope, array_access, expected_type).map(Expression::ArrayAccess)?,
),
ArrayRangeAccess(array_range_access) => scope.context.alloc_expression(
ArrayRangeAccessExpression::from_ast(scope, array_range_access, expected_type)
.map(Expression::ArrayRangeAccess)?,
),
TupleInit(tuple_init) => scope.context.alloc_expression(
TupleInitExpression::from_ast(scope, tuple_init, expected_type).map(Expression::TupleInit)?,
),
TupleAccess(tuple_access) => scope.context.alloc_expression(
TupleAccessExpression::from_ast(scope, tuple_access, expected_type).map(Expression::TupleAccess)?,
),
CircuitInit(circuit_init) => scope.context.alloc_expression(
CircuitInitExpression::from_ast(scope, circuit_init, expected_type).map(Expression::CircuitInit)?,
),
CircuitMemberAccess(circuit_member) => scope.context.alloc_expression(
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type)
.map(Expression::CircuitAccess)?,
),
CircuitStaticFunctionAccess(circuit_member) => scope.context.alloc_expression(
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type)
.map(Expression::CircuitAccess)?,
),
Call(call) => scope
.context
.alloc_expression(CallExpression::from_ast(scope, call, expected_type).map(Expression::Call)?),
};
expression.enforce_parents(expression);
Ok(expression)
}
}
impl<'a> Into<leo_ast::Expression> for &Expression<'a> {
fn into(self) -> leo_ast::Expression {
use Expression::*;
match self {
VariableRef(x) => leo_ast::Expression::Identifier(x.into()),
Constant(x) => leo_ast::Expression::Value(x.into()),
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()),
LengthOf(x) => leo_ast::Expression::LengthOf(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()),
ArrayRangeAccess(x) => leo_ast::Expression::ArrayRangeAccess(x.into()),
TupleInit(x) => leo_ast::Expression::TupleInit(x.into()),
TupleAccess(x) => leo_ast::Expression::TupleAccess(x.into()),
CircuitInit(x) => leo_ast::Expression::CircuitInit(x.into()),
CircuitAccess(x) => x.into(),
Call(x) => leo_ast::Expression::Call(x.into()),
}
}
}

View File

@ -1,128 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct TernaryExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub condition: Cell<&'a Expression<'a>>,
pub if_true: Cell<&'a Expression<'a>>,
pub if_false: Cell<&'a Expression<'a>>,
}
impl<'a> Node for TernaryExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for TernaryExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.condition.get().set_parent(expr);
self.if_true.get().set_parent(expr);
self.if_false.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
self.if_true.get().get_type()
}
fn is_mut_ref(&self) -> bool {
self.if_true.get().is_mut_ref() && self.if_false.get().is_mut_ref()
}
fn const_value(&self) -> Option<ConstValue<'a>> {
if let Some(ConstValue::Boolean(switch)) = self.condition.get().const_value() {
if switch {
self.if_true.get().const_value()
} else {
self.if_false.get().const_value()
}
} else {
None
}
}
fn is_consty(&self) -> bool {
self.condition.get().is_consty() && self.if_true.get().is_consty() && self.if_false.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::TernaryExpression> for TernaryExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::TernaryExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<TernaryExpression<'a>> {
let if_true = Cell::new(<&Expression<'a>>::from_ast(
scope,
&*value.if_true,
expected_type.clone(),
)?);
let left: PartialType = if_true.get().get_type().unwrap().into();
let if_false = if expected_type.is_none() {
Cell::new(<&Expression<'a>>::from_ast(
scope,
&*value.if_false,
Some(left.clone()),
)?)
} else {
Cell::new(<&Expression<'a>>::from_ast(scope, &*value.if_false, expected_type)?)
};
let right = if_false.get().get_type().unwrap().into();
if left != right {
return Err(AsgError::ternary_different_types(left, right, &value.span).into());
}
Ok(TernaryExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
condition: Cell::new(<&Expression<'a>>::from_ast(
scope,
&*value.condition,
Some(Type::Boolean.partial()),
)?),
if_true,
if_false,
})
}
}
impl<'a> Into<leo_ast::TernaryExpression> for &TernaryExpression<'a> {
fn into(self) -> leo_ast::TernaryExpression {
leo_ast::TernaryExpression {
condition: Box::new(self.condition.get().into()),
if_true: Box::new(self.if_true.get().into()),
if_false: Box::new(self.if_false.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,121 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct TupleAccessExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub tuple_ref: Cell<&'a Expression<'a>>,
pub index: usize,
}
impl<'a> Node for TupleAccessExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for TupleAccessExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.tuple_ref.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
match self.tuple_ref.get().get_type()? {
Type::Tuple(subtypes) => subtypes.get(self.index).cloned(),
_ => None,
}
}
fn is_mut_ref(&self) -> bool {
self.tuple_ref.get().is_mut_ref()
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let tuple_const = self.tuple_ref.get().const_value()?;
match tuple_const {
ConstValue::Tuple(sub_consts) => sub_consts.get(self.index).cloned(),
_ => None,
}
}
fn is_consty(&self) -> bool {
self.tuple_ref.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::TupleAccessExpression> for TupleAccessExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::TupleAccessExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<TupleAccessExpression<'a>> {
let index = value
.index
.value
.parse::<usize>()
.map_err(|_| AsgError::parse_index_error(&value.span))?;
let mut expected_tuple = vec![None; index + 1];
expected_tuple[index] = expected_type;
let tuple = <&Expression<'a>>::from_ast(scope, &*value.tuple, Some(PartialType::Tuple(expected_tuple)))?;
let tuple_type = tuple.get_type();
if let Some(Type::Tuple(_items)) = tuple_type {
} else {
return Err(AsgError::unexpected_type(
"tuple",
tuple_type
.map(|x| x.to_string())
.unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
Ok(TupleAccessExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
tuple_ref: Cell::new(tuple),
index,
})
}
}
impl<'a> Into<leo_ast::TupleAccessExpression> for &TupleAccessExpression<'a> {
fn into(self) -> leo_ast::TupleAccessExpression {
leo_ast::TupleAccessExpression {
tuple: Box::new(self.tuple_ref.get().into()),
index: leo_ast::PositiveNumber {
value: self.index.to_string().into(),
},
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,140 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct TupleInitExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub elements: Vec<Cell<&'a Expression<'a>>>,
}
impl<'a> Node for TupleInitExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for TupleInitExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.elements.iter().for_each(|element| {
element.get().set_parent(expr);
})
}
fn get_type(&self) -> Option<Type<'a>> {
let mut output = vec![];
for element in self.elements.iter() {
output.push(element.get().get_type()?);
}
Some(Type::Tuple(output))
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue<'a>> {
let mut consts = vec![];
for element in self.elements.iter() {
if let Some(const_value) = element.get().const_value() {
consts.push(const_value);
} else {
return None;
}
}
Some(ConstValue::Tuple(consts))
}
fn is_consty(&self) -> bool {
self.elements.iter().all(|x| x.get().is_consty())
}
}
impl<'a> FromAst<'a, leo_ast::TupleInitExpression> for TupleInitExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::TupleInitExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<TupleInitExpression<'a>> {
let tuple_types = match expected_type {
Some(PartialType::Tuple(sub_types)) => Some(sub_types),
None => None,
x => {
return Err(AsgError::unexpected_type(
"tuple",
x.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&value.span,
)
.into());
}
};
if let Some(tuple_types) = tuple_types.as_ref() {
// Expected type can be equal or less than actual size of a tuple.
// Size of expected tuple can be based on accessed index.
if tuple_types.len() > value.elements.len() {
return Err(AsgError::unexpected_type(
format!("tuple of length {}", tuple_types.len()),
format!("tuple of length {}", value.elements.len()),
&value.span,
)
.into());
}
}
let elements = value
.elements
.iter()
.enumerate()
.map(|(i, e)| {
<&Expression<'a>>::from_ast(
scope,
e,
tuple_types.as_ref().map(|x| x.get(i)).flatten().cloned().flatten(),
)
.map(Cell::new)
})
.collect::<Result<Vec<_>>>()?;
Ok(TupleInitExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
elements,
})
}
}
impl<'a> Into<leo_ast::TupleInitExpression> for &TupleInitExpression<'a> {
fn into(self) -> leo_ast::TupleInitExpression {
leo_ast::TupleInitExpression {
elements: self.elements.iter().map(|e| e.get().into()).collect(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,149 +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::{ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Type};
pub use leo_ast::UnaryOperation;
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct UnaryExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub operation: UnaryOperation,
pub inner: Cell<&'a Expression<'a>>,
}
impl<'a> Node for UnaryExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for UnaryExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'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>> {
self.inner.get().get_type()
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue> {
if let Some(inner) = self.inner.get().const_value() {
match self.operation {
UnaryOperation::Not => match inner {
ConstValue::Boolean(value) => Some(ConstValue::Boolean(!value)),
_ => None,
},
UnaryOperation::Negate => {
match inner {
ConstValue::Int(value) => Some(ConstValue::Int(value.value_negate()?)),
// ConstValue::Group(value) => Some(ConstValue::Group(value)), TODO: groups
// ConstValue::Field(value) => Some(ConstValue::Field(-value)),
_ => None,
}
}
UnaryOperation::BitNot => match inner {
ConstValue::Int(value) => Some(ConstValue::Int(value.value_bit_negate()?)),
_ => None,
},
}
} else {
None
}
}
fn is_consty(&self) -> bool {
self.inner.get().is_consty()
}
}
impl<'a> FromAst<'a, leo_ast::UnaryExpression> for UnaryExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::UnaryExpression,
expected_type: Option<PartialType<'a>>,
) -> Result<UnaryExpression<'a>> {
let expected_type = match value.op {
UnaryOperation::Not => match expected_type.map(|x| x.full()).flatten() {
Some(Type::Boolean) | None => Some(Type::Boolean),
Some(type_) => {
return Err(AsgError::unexpected_type(Type::Boolean, type_, &value.span).into());
}
},
UnaryOperation::Negate => match expected_type.map(|x| x.full()).flatten() {
Some(type_ @ Type::Integer(_)) => Some(type_),
Some(Type::Group) => Some(Type::Group),
Some(Type::Field) => Some(Type::Field),
None => None,
Some(type_) => {
return Err(AsgError::unexpected_type("integer, group, field", type_, &value.span).into());
}
},
UnaryOperation::BitNot => match expected_type.map(|x| x.full()).flatten() {
Some(type_ @ Type::Integer(_)) => Some(type_),
None => None,
Some(type_) => {
return Err(AsgError::unexpected_type("integer", type_, &value.span).into());
}
},
};
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(AsgError::unsigned_negation(&value.span).into());
}
}
Ok(UnaryExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
operation: value.op.clone(),
inner: Cell::new(expr),
})
}
}
impl<'a> Into<leo_ast::UnaryExpression> for &UnaryExpression<'a> {
fn into(self) -> leo_ast::UnaryExpression {
leo_ast::UnaryExpression {
op: self.operation.clone(),
inner: Box::new(self.inner.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,183 +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::{
ConstValue, Constant, DefinitionStatement, Expression, ExpressionNode, FromAst, Node, PartialType, Scope,
Statement, Type, Variable,
};
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct VariableRef<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub variable: &'a Variable<'a>,
}
impl<'a> Node for VariableRef<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for VariableRef<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, _expr: &'a Expression<'a>) {}
fn get_type(&self) -> Option<Type<'a>> {
Some(self.variable.borrow().type_.clone())
}
fn is_mut_ref(&self) -> bool {
self.variable.borrow().mutable
}
// todo: we can use use hacky ssa here to catch more cases, or just enforce ssa before asg generation finished
fn const_value(&self) -> Option<ConstValue<'a>> {
let variable = self.variable.borrow();
if variable.mutable || variable.assignments.len() != 1 {
return None;
}
let assignment = variable.assignments.get(0).unwrap();
match &*assignment {
Statement::Definition(DefinitionStatement { variables, value, .. }) => {
if variables.len() == 1 {
let defined_variable = variables.get(0).unwrap().borrow();
assert_eq!(variable.id, defined_variable.id);
value.get().const_value()
} else {
for (i, defined_variable) in variables.iter().enumerate() {
let defined_variable = defined_variable.borrow();
if defined_variable.id == variable.id {
match value.get().const_value() {
Some(ConstValue::Tuple(values)) => return values.get(i).cloned(),
None => return None,
_ => (),
}
}
}
panic!("no corresponding tuple variable found during const destructuring (corrupt asg?)");
}
}
_ => None, //todo unroll loops during asg phase
}
}
fn is_consty(&self) -> bool {
let variable = self.variable.borrow();
if variable.const_ {
return true;
}
if variable.mutable || variable.assignments.len() != 1 {
return false;
}
let assignment = variable.assignments.get(0).unwrap();
match &*assignment {
Statement::Definition(DefinitionStatement { variables, value, .. }) => {
if variables.len() == 1 {
let defined_variable = variables.get(0).unwrap().borrow();
assert_eq!(variable.id, defined_variable.id);
value.get().is_consty()
} else {
for defined_variable in variables.iter() {
let defined_variable = defined_variable.borrow();
if defined_variable.id == variable.id {
return value.get().is_consty();
}
}
panic!("no corresponding tuple variable found during const destructuring (corrupt asg?)");
}
}
Statement::Iteration(_) => true,
_ => false,
}
}
}
impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::Identifier,
expected_type: Option<PartialType<'a>>,
) -> Result<&'a Expression<'a>> {
let variable = if value.name.as_ref() == "input" {
if let Some(input) = scope.resolve_input() {
input.container
} else {
return Err(AsgError::illegal_input_variable_reference(&value.span).into());
}
} else if let Some(gc) = scope.resolve_global_const(&value.name) {
gc.variables
.iter()
.find(|&&v| v.borrow().name.name == value.name)
.unwrap()
} else {
match scope.resolve_variable(&value.name) {
Some(v) => v,
None => {
if value.name.starts_with("aleo1") {
return Ok(scope.context.alloc_expression(Expression::Constant(Constant {
parent: Cell::new(None),
span: Some(value.span.clone()),
value: ConstValue::Address(value.name.clone()),
})));
}
return Err(AsgError::unresolved_reference(&value.name, &value.span).into());
}
}
};
let variable_ref = VariableRef {
parent: Cell::new(None),
span: Some(value.span.clone()),
variable,
};
let expression = scope.context.alloc_expression(Expression::VariableRef(variable_ref));
if let Some(expected_type) = expected_type {
let type_ = expression
.get_type()
.ok_or_else(|| AsgError::unresolved_reference(&value.name, &value.span))?;
if !expected_type.matches(&type_) {
return Err(AsgError::unexpected_type(expected_type, type_, &value.span).into());
}
}
let mut variable_ref = variable.borrow_mut();
variable_ref.references.push(expression);
Ok(expression)
}
}
impl<'a> Into<leo_ast::Identifier> for &VariableRef<'a> {
fn into(self) -> leo_ast::Identifier {
self.variable.borrow().name.clone()
}
}

View File

@ -1,107 +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::{Circuit, CircuitMember, Identifier, Scope, Type, Variable};
use leo_errors::Span;
use indexmap::IndexMap;
use std::cell::RefCell;
/// Stores program input values as ASG nodes.
#[derive(Clone, Copy)]
pub struct Input<'a> {
pub registers: &'a Circuit<'a>,
pub state: &'a Circuit<'a>,
pub state_leaf: &'a Circuit<'a>,
pub record: &'a Circuit<'a>,
pub container_circuit: &'a Circuit<'a>,
pub container: &'a Variable<'a>,
}
pub const CONTAINER_PSEUDO_CIRCUIT: &str = "$InputContainer";
pub const REGISTERS_PSEUDO_CIRCUIT: &str = "$InputRegister";
pub const RECORD_PSEUDO_CIRCUIT: &str = "$InputRecord";
pub const STATE_PSEUDO_CIRCUIT: &str = "$InputState";
pub const STATE_LEAF_PSEUDO_CIRCUIT: &str = "$InputStateLeaf";
impl<'a> Input<'a> {
fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> {
scope.context.alloc_circuit(Circuit {
id: scope.context.get_id(),
name: RefCell::new(Identifier::new(name.into())),
members: RefCell::new(IndexMap::new()),
core_mapping: RefCell::new(None),
scope,
span: Some(Span::default()),
})
}
pub fn new(scope: &'a Scope<'a>) -> Self {
let input_scope = scope.make_subscope();
let registers = Self::make_header(input_scope, REGISTERS_PSEUDO_CIRCUIT);
let record = Self::make_header(input_scope, RECORD_PSEUDO_CIRCUIT);
let state = Self::make_header(input_scope, STATE_PSEUDO_CIRCUIT);
let state_leaf = Self::make_header(input_scope, STATE_LEAF_PSEUDO_CIRCUIT);
let mut container_members = IndexMap::new();
container_members.insert(
"registers".to_string(),
CircuitMember::Variable(Type::Circuit(registers)),
);
container_members.insert("record".to_string(), CircuitMember::Variable(Type::Circuit(record)));
container_members.insert("state".to_string(), CircuitMember::Variable(Type::Circuit(state)));
container_members.insert(
"state_leaf".to_string(),
CircuitMember::Variable(Type::Circuit(state_leaf)),
);
let container_circuit = input_scope.context.alloc_circuit(Circuit {
id: scope.context.get_id(),
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.into())),
members: RefCell::new(container_members),
core_mapping: RefCell::new(None),
scope: input_scope,
span: Some(Span::default()),
});
Input {
registers,
record,
state,
state_leaf,
container_circuit,
container: input_scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
id: scope.context.get_id(),
name: Identifier::new("input".into()),
type_: Type::Circuit(container_circuit),
mutable: false,
const_: false,
declaration: crate::VariableDeclaration::Input,
references: vec![],
assignments: vec![],
})),
}
}
}
impl<'a> Circuit<'a> {
pub fn is_input_pseudo_circuit(&self) -> bool {
matches!(
&*self.name.borrow().name,
REGISTERS_PSEUDO_CIRCUIT | RECORD_PSEUDO_CIRCUIT | STATE_PSEUDO_CIRCUIT | STATE_LEAF_PSEUDO_CIRCUIT
)
}
}

View File

@ -1,110 +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/>.
//! The abstract semantic graph (ASG) for a Leo program.
//!
//! This module contains the [`Asg`] type, an abstract data type that represents a Leo program
//! as a series of graph nodes. The [`Asg`] type is at a greater level of abstraction than an [`Ast`].
//!
//! A new [`Asg`] type can be created from an [`Ast`].
//! Converting to an [`Asg`] provides greater type safety by canonicalizing and checking program types.
#![allow(clippy::from_over_into)]
#![allow(clippy::result_unit_err)]
#![doc = include_str!("../README.md")]
pub mod checks;
pub use checks::*;
pub mod const_value;
pub use const_value::*;
pub mod expression;
pub use expression::*;
mod input;
pub use input::*;
pub mod node;
pub use node::*;
pub mod program;
pub use program::*;
pub mod reducer;
pub use reducer::*;
pub mod scope;
pub use scope::*;
pub mod statement;
pub use statement::*;
pub mod type_;
pub use type_::*;
pub mod variable;
use typed_arena::Arena;
pub use variable::*;
pub mod pass;
pub use pass::*;
pub mod context;
pub use context::*;
pub use leo_ast::{Ast, Identifier};
use leo_errors::Result;
/// The abstract semantic graph (ASG) for a Leo program.
///
/// The [`Asg`] type represents a Leo program as a series of recursive data types.
/// These data types form a graph that begins from a [`Program`] type node.
///
/// A new [`Asg`] can be created from an [`Ast`] generated in the `ast` module.
#[derive(Clone)]
pub struct Asg<'a> {
#[allow(dead_code)] // todo: revisit this during asg refactor
context: AsgContext<'a>,
asg: Program<'a>,
}
impl<'a> Asg<'a> {
/// Creates a new ASG from a given AST and import resolver.
pub fn new<Y: AsRef<leo_ast::Program>>(context: AsgContext<'a>, ast: Y) -> Result<Self> {
Ok(Self {
context,
asg: Program::new(context, ast.as_ref())?,
})
}
/// Returns the internal program ASG representation.
pub fn as_repr(&self) -> &Program<'a> {
&self.asg
}
pub fn into_repr(self) -> Program<'a> {
self.asg
}
}
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {
Arena::new()
}
pub fn new_context<'a>(arena: &'a Arena<ArenaNode<'a>>) -> AsgContext<'a> {
AsgContextInner::new(arena)
}

View File

@ -1,41 +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::{Alias, AsgContextInner, Circuit, Expression, Function, PartialType, Scope, Statement, Variable};
use leo_errors::{Result, Span};
/// A node in the abstract semantic graph.
pub trait Node {
fn span(&self) -> Option<&Span>;
}
pub(super) trait FromAst<'a, T: leo_ast::Node + 'static>: Sized {
// expected_type contract: if present, output expression must be of type expected_type.
// type of an element may NEVER be None unless it is functionally a non-expression. (static call targets, function ref call targets are not expressions)
fn from_ast(scope: &'a Scope<'a>, value: &T, expected_type: Option<PartialType<'a>>) -> Result<Self>;
}
pub enum ArenaNode<'a> {
Expression(Expression<'a>),
Scope(Box<Scope<'a>>),
Statement(Statement<'a>),
Variable(Variable<'a>),
Circuit(Circuit<'a>),
Function(Function<'a>),
Inner(AsgContextInner<'a>),
Alias(Alias<'a>),
}

View File

@ -1,22 +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::Program;
use leo_errors::Result;
pub trait AsgPass<'a> {
fn do_pass(asg: Program<'a>) -> Result<Program<'a>>;
}

View File

@ -1,58 +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::{Identifier, Node, Scope, Type};
use leo_errors::{Result, Span};
use std::cell::RefCell;
#[derive(Clone)]
pub struct Alias<'a> {
pub id: u32,
pub name: RefCell<Identifier>,
pub span: Option<Span>,
pub represents: Type<'a>,
}
impl<'a> PartialEq for Alias<'a> {
fn eq(&self, other: &Alias) -> bool {
if self.name != other.name {
return false;
}
self.id == other.id
}
}
impl<'a> Eq for Alias<'a> {}
impl<'a> Node for Alias<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> Alias<'a> {
pub(super) fn init(scope: &'a Scope<'a>, value: &leo_ast::Alias) -> Result<&'a Alias<'a>> {
let alias = scope.context.alloc_alias(Alias {
id: scope.context.get_id(),
name: RefCell::new(value.name.clone()),
span: Some(value.span.clone()),
represents: scope.resolve_ast_type(&value.represents, &value.span)?,
});
Ok(alias)
}
}

View File

@ -1,160 +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, Node, Scope, Type};
use leo_errors::{AsgError, Result, Span};
use indexmap::IndexMap;
use std::cell::RefCell;
#[derive(Clone)]
pub enum CircuitMember<'a> {
Variable(Type<'a>),
Function(&'a Function<'a>),
}
#[derive(Clone)]
pub struct Circuit<'a> {
pub id: u32,
pub name: RefCell<Identifier>,
pub core_mapping: RefCell<Option<String>>,
pub scope: &'a Scope<'a>,
pub span: Option<Span>,
pub members: RefCell<IndexMap<String, CircuitMember<'a>>>,
}
impl<'a> PartialEq for Circuit<'a> {
fn eq(&self, other: &Circuit) -> bool {
if self.name != other.name {
return false;
}
self.id == other.id
}
}
impl<'a> Eq for Circuit<'a> {}
impl<'a> Node for Circuit<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> Circuit<'a> {
pub(super) fn init(scope: &'a Scope<'a>, value: &leo_ast::Circuit) -> Result<&'a Circuit<'a>> {
let new_scope = scope.make_subscope();
let circuit = scope.context.alloc_circuit(Circuit {
id: scope.context.get_id(),
name: RefCell::new(value.circuit_name.clone()),
members: RefCell::new(IndexMap::new()),
core_mapping: value.core_mapping.clone(),
span: Some(value.circuit_name.span.clone()),
scope: new_scope,
});
let mut members = circuit.members.borrow_mut();
for member in value.members.iter() {
if let leo_ast::CircuitMember::CircuitVariable(name, type_) = member {
if members.contains_key(name.name.as_ref()) {
return Err(
AsgError::redefined_circuit_member(&value.circuit_name.name, &name.name, &name.span).into(),
);
}
members.insert(
name.name.to_string(),
CircuitMember::Variable(new_scope.resolve_ast_type(type_, &name.span)?),
);
}
}
Ok(circuit)
}
pub(super) fn init_member(scope: &'a Scope<'a>, value: &leo_ast::Circuit) -> Result<&'a Circuit<'a>> {
let new_scope = scope.make_subscope();
let circuits = scope.circuits.borrow();
let circuit = circuits.get(value.circuit_name.name.as_ref()).unwrap();
let mut members = circuit.members.borrow_mut();
for member in value.members.iter() {
if let leo_ast::CircuitMember::CircuitFunction(function) = member {
if members.contains_key(function.identifier.name.as_ref()) {
return Err(AsgError::redefined_circuit_member(
&value.circuit_name.name,
&function.identifier.name,
&function.identifier.span,
)
.into());
}
let asg_function = Function::init(new_scope, function)?;
asg_function.circuit.replace(Some(circuit));
if asg_function.is_test() {
return Err(AsgError::circuit_test_function(&function.identifier.span).into());
}
members.insert(
function.identifier.name.to_string(),
CircuitMember::Function(asg_function),
);
}
}
Ok(circuit)
}
pub(super) fn fill_from_ast(self: &'a Circuit<'a>, value: &leo_ast::Circuit) -> Result<()> {
for member in value.members.iter() {
match member {
leo_ast::CircuitMember::CircuitVariable(..) => {}
leo_ast::CircuitMember::CircuitFunction(function) => {
let asg_function = match *self
.members
.borrow()
.get(function.identifier.name.as_ref())
.expect("missing header for defined circuit function")
{
CircuitMember::Function(f) => f,
_ => unimplemented!(),
};
Function::fill_from_ast(asg_function, function)?;
}
}
}
Ok(())
}
}
impl<'a> Into<leo_ast::Circuit> for &Circuit<'a> {
fn into(self) -> leo_ast::Circuit {
let members = self
.members
.borrow()
.iter()
.map(|(name, member)| match &member {
CircuitMember::Variable(type_) => {
leo_ast::CircuitMember::CircuitVariable(Identifier::new((&**name).into()), type_.into())
}
CircuitMember::Function(func) => leo_ast::CircuitMember::CircuitFunction((*func).into()),
})
.collect();
leo_ast::Circuit {
circuit_name: self.name.borrow().clone(),
core_mapping: self.core_mapping.clone(),
members,
}
}
}

View File

@ -1,214 +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::{
BlockStatement, Circuit, FromAst, Identifier, MonoidalDirector, ReturnPathReducer, Scope, Statement, Type, Variable,
};
use indexmap::IndexMap;
pub use leo_ast::Annotation;
use leo_ast::FunctionInput;
use leo_errors::{AsgError, Result, Span};
use std::cell::{Cell, RefCell};
#[derive(Clone, Copy, PartialEq)]
pub enum FunctionQualifier {
SelfRef,
ConstSelfRef,
MutSelfRef,
Static,
}
#[derive(Clone)]
pub struct Function<'a> {
pub id: u32,
pub name: RefCell<Identifier>,
pub output: Type<'a>,
pub arguments: IndexMap<String, Cell<&'a Variable<'a>>>,
pub circuit: Cell<Option<&'a Circuit<'a>>>,
pub span: Option<Span>,
pub body: Cell<Option<&'a Statement<'a>>>,
pub scope: &'a Scope<'a>,
pub qualifier: FunctionQualifier,
pub annotations: Vec<Annotation>,
}
impl<'a> PartialEq for Function<'a> {
fn eq(&self, other: &Function<'a>) -> bool {
if self.name.borrow().name != other.name.borrow().name {
return false;
}
self.id == other.id
}
}
impl<'a> Eq for Function<'a> {}
impl<'a> Function<'a> {
pub(crate) fn init(scope: &'a Scope<'a>, value: &leo_ast::Function) -> Result<&'a Function<'a>> {
let output: Type<'a> = value
.output
.as_ref()
.map(|t| scope.resolve_ast_type(t, &value.span))
.transpose()?
.unwrap_or_else(|| Type::Tuple(vec![]));
let mut qualifier = FunctionQualifier::Static;
let new_scope = scope.make_subscope();
let mut arguments = IndexMap::new();
{
for input in value.input.iter() {
match input {
FunctionInput::SelfKeyword(_) => {
qualifier = FunctionQualifier::SelfRef;
}
FunctionInput::ConstSelfKeyword(_) => {
qualifier = FunctionQualifier::ConstSelfRef;
}
FunctionInput::MutSelfKeyword(_) => {
qualifier = FunctionQualifier::MutSelfRef;
}
FunctionInput::Variable(input_variable) => {
if arguments.contains_key(input_variable.identifier.name.as_ref()) {
return Err(AsgError::duplicate_function_input_definition(
input_variable.identifier.name.as_ref(),
&input_variable.identifier.span,
)
.into());
}
let variable = scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
id: scope.context.get_id(),
name: input_variable.identifier.clone(),
type_: scope.resolve_ast_type(&input_variable.type_, &value.span)?,
mutable: input_variable.mutable,
const_: input_variable.const_,
declaration: crate::VariableDeclaration::Parameter,
references: vec![],
assignments: vec![],
}));
arguments.insert(input_variable.identifier.name.to_string(), Cell::new(&*variable));
}
}
}
}
let function = scope.context.alloc_function(Function {
id: scope.context.get_id(),
name: RefCell::new(value.identifier.clone()),
output,
arguments,
circuit: Cell::new(None),
body: Cell::new(None),
qualifier,
scope: new_scope,
span: Some(value.span.clone()),
annotations: value.annotations.clone(),
});
function.scope.function.replace(Some(function));
Ok(function)
}
pub(super) fn fill_from_ast(self: &'a Function<'a>, value: &leo_ast::Function) -> Result<()> {
if self.qualifier != FunctionQualifier::Static {
let circuit = self.circuit.get();
let self_variable = self.scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
id: self.scope.context.get_id(),
name: Identifier::new("self".into()),
type_: Type::Circuit(circuit.as_ref().unwrap()),
mutable: self.qualifier == FunctionQualifier::MutSelfRef,
const_: false,
declaration: crate::VariableDeclaration::Parameter,
references: vec![],
assignments: vec![],
}));
self.scope
.variables
.borrow_mut()
.insert("self".to_string(), self_variable);
}
for (name, argument) in self.arguments.iter() {
if self.scope.resolve_global_const(name).is_some() {
return Err(AsgError::function_input_cannot_shadow_global_const(
name,
&argument.get().borrow().name.span,
)
.into());
}
self.scope.variables.borrow_mut().insert(name.clone(), argument.get());
}
let main_block = BlockStatement::from_ast(self.scope, &value.block, None)?;
let mut director = MonoidalDirector::new(ReturnPathReducer::new());
if !director.reduce_block(&main_block).0 && !self.output.is_unit() {
return Err(AsgError::function_missing_return(&self.name.borrow().name, &value.span).into());
}
#[allow(clippy::never_loop)] // TODO @Protryon: How should we return multiple errors?
for (span, error) in director.reducer().errors {
return Err(AsgError::function_return_validation(&self.name.borrow().name, error, &span).into());
}
self.body
.replace(Some(self.scope.context.alloc_statement(Statement::Block(main_block))));
Ok(())
}
pub fn is_test(&self) -> bool {
self.annotations.iter().any(|x| x.name.name.as_ref() == "test")
}
}
impl<'a> Into<leo_ast::Function> for &Function<'a> {
fn into(self) -> leo_ast::Function {
let input = self
.arguments
.iter()
.map(|(_, variable)| {
let variable = variable.get().borrow();
leo_ast::FunctionInput::Variable(leo_ast::FunctionInputVariable {
identifier: variable.name.clone(),
mutable: variable.mutable,
const_: variable.const_,
type_: (&variable.type_).into(),
span: Span::default(),
})
})
.collect();
let (body, span) = match self.body.get() {
Some(Statement::Block(block)) => (block.into(), block.span.clone().unwrap_or_default()),
Some(_) => unimplemented!(),
None => (
leo_ast::Block {
statements: vec![],
span: Default::default(),
},
Default::default(),
),
};
let output: Type = self.output.clone();
leo_ast::Function {
identifier: self.name.borrow().clone(),
input,
block: body,
output: Some((&output).into()),
span,
annotations: self.annotations.clone(),
}
}
}

View File

@ -1,404 +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/>.
//! This module defines the program node for an asg.
//!
//!
mod alias;
pub use alias::*;
mod circuit;
pub use circuit::*;
mod function;
pub use function::*;
use crate::{node::FromAst, ArenaNode, AsgContext, DefinitionStatement, Input, Scope, Statement};
use leo_ast::{PackageAccess, PackageOrPackages};
use leo_errors::{AsgError, Result, Span};
use indexmap::IndexMap;
use std::cell::{Cell, RefCell};
/// Stores the Leo program abstract semantic graph (ASG).
#[derive(Clone)]
pub struct Program<'a> {
pub context: AsgContext<'a>,
/// The unique id of the program.
pub id: u32,
/// The program file name.
pub name: String,
/// The packages imported by this program.
/// these should generally not be accessed directly, but through scoped imports
pub imported_modules: IndexMap<String, Program<'a>>,
/// Maps alias name => alias definition.
pub aliases: IndexMap<String, &'a Alias<'a>>,
/// Maps function name => function code block.
pub functions: IndexMap<String, &'a Function<'a>>,
/// Maps global constant name => global const code block.
pub global_consts: IndexMap<String, &'a DefinitionStatement<'a>>,
/// Maps circuit name => circuit code block.
pub circuits: IndexMap<String, &'a Circuit<'a>>,
pub scope: &'a Scope<'a>,
}
/// Enumerates what names are imported from a package.
#[derive(Clone)]
enum ImportSymbol {
/// Import the symbol by name.
Direct(String),
/// Import the symbol by name and store it under an alias.
Alias(String, String), // from remote -> to local
/// Import all symbols from the package.
All,
}
fn resolve_import_package(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package_or_packages: &PackageOrPackages,
) {
match package_or_packages {
PackageOrPackages::Package(package) => {
package_segments.push(package.name.name.to_string());
resolve_import_package_access(output, package_segments, &package.access);
}
PackageOrPackages::Packages(packages) => {
package_segments.push(packages.name.name.to_string());
for access in packages.accesses.clone() {
resolve_import_package_access(output, package_segments.clone(), &access);
}
}
}
}
fn resolve_import_package_access(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package: &PackageAccess,
) {
match package {
PackageAccess::Star { span } => {
output.push((package_segments, ImportSymbol::All, span.clone()));
}
PackageAccess::SubPackage(subpackage) => {
resolve_import_package(
output,
package_segments,
&PackageOrPackages::Package(*(*subpackage).clone()),
);
}
PackageAccess::Symbol(symbol) => {
let span = symbol.symbol.span.clone();
let symbol = if let Some(alias) = symbol.alias.as_ref() {
ImportSymbol::Alias(symbol.symbol.name.to_string(), alias.name.to_string())
} else {
ImportSymbol::Direct(symbol.symbol.name.to_string())
};
output.push((package_segments, symbol, span));
}
PackageAccess::Multiple(packages) => {
package_segments.push(packages.name.name.to_string());
for subaccess in packages.accesses.iter() {
resolve_import_package_access(output, package_segments.clone(), subaccess);
}
}
}
}
/// Checks whether a given string is found in any other global namespaces.
/// If it is found it returns an error.
fn check_top_level_namespaces<'a>(
name: &str,
span: &Span,
aliases: &IndexMap<String, &'a Alias<'a>>,
functions: &IndexMap<String, &'a Function<'a>>,
circuits: &IndexMap<String, &'a Circuit<'a>>,
global_consts: &IndexMap<String, &'a DefinitionStatement<'a>>,
) -> Result<()> {
if aliases.contains_key(name) {
Err(AsgError::duplicate_alias_definition(name, span).into())
} else if global_consts.contains_key(name) {
Err(AsgError::duplicate_global_const_definition(name, span).into())
} else if functions.contains_key(name) {
Err(AsgError::duplicate_function_definition(name, span).into())
} else if circuits.contains_key(name) {
Err(AsgError::duplicate_circuit_definition(name, span).into())
} else {
Ok(())
}
}
impl<'a> Program<'a> {
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
///
/// Stages:
/// 1. resolve imports into super scope
/// 2. finalize declared types
/// 3. finalize declared functions
/// 4. resolve all asg nodes
///
pub fn new(context: AsgContext<'a>, program: &leo_ast::Program) -> Result<Program<'a>> {
let mut imported_aliases: IndexMap<String, &'a Alias<'a>> = IndexMap::new();
let mut imported_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut imported_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut imported_global_consts: IndexMap<String, &'a DefinitionStatement<'a>> = IndexMap::new();
// Convert each sub AST.
// Import all prelude symbols on the way.
let mut imported_modules: IndexMap<Vec<String>, Program> = IndexMap::new();
for (package, program) in program.imports.iter() {
let sub_program = Program::new(context, program)?;
imported_modules.insert(package.clone(), sub_program.clone());
let pretty_package = package.join(".");
if pretty_package.contains("std.prelude") {
imported_aliases.extend(sub_program.aliases.clone().into_iter());
imported_functions.extend(sub_program.functions.clone().into_iter());
imported_circuits.extend(sub_program.circuits.clone().into_iter());
imported_global_consts.extend(sub_program.global_consts.clone().into_iter());
}
}
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
for import_statement in program.import_statements.iter() {
resolve_import_package(&mut imported_symbols, vec![], &import_statement.package_or_packages);
}
let mut deduplicated_imports: IndexMap<Vec<String>, Span> = IndexMap::new();
for (package, _symbol, span) in imported_symbols.iter() {
deduplicated_imports.insert(package.clone(), span.clone());
}
for (package, symbol, span) in imported_symbols.into_iter() {
let pretty_package = package.join(".");
let resolved_package = imported_modules
.get_mut(&package)
.expect("could not find preloaded package");
match symbol {
ImportSymbol::All => {
imported_aliases.extend(resolved_package.aliases.clone().into_iter());
imported_functions.extend(resolved_package.functions.clone().into_iter());
imported_circuits.extend(resolved_package.circuits.clone().into_iter());
imported_global_consts.extend(resolved_package.global_consts.clone().into_iter());
}
ImportSymbol::Direct(name) => {
if let Some(alias) = resolved_package.aliases.get(&name) {
imported_aliases.insert(name.clone(), *alias);
} else if let Some(function) = resolved_package.functions.get(&name) {
imported_functions.insert(name.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(name.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(name.clone(), *global_const);
} else {
return Err(AsgError::unresolved_import(pretty_package, &span).into());
}
}
ImportSymbol::Alias(name, alias) => {
if let Some(type_alias) = resolved_package.aliases.get(&name) {
imported_aliases.insert(alias.clone(), *type_alias);
} else if let Some(function) = resolved_package.functions.get(&name) {
imported_functions.insert(alias.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(alias.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(alias.clone(), *global_const);
} else {
return Err(AsgError::unresolved_import(pretty_package, &span).into());
}
}
}
}
let import_scope = match context.arena.alloc(ArenaNode::Scope(Box::new(Scope {
context,
id: context.get_id(),
parent_scope: Cell::new(None),
variables: RefCell::new(IndexMap::new()),
aliases: RefCell::new(imported_aliases),
functions: RefCell::new(imported_functions),
global_consts: RefCell::new(imported_global_consts),
circuits: RefCell::new(imported_circuits),
function: Cell::new(None),
input: Cell::new(None),
}))) {
ArenaNode::Scope(c) => c,
_ => unimplemented!(),
};
let scope = import_scope.context.alloc_scope(Scope {
context,
input: Cell::new(Some(Input::new(import_scope))), // we use import_scope to avoid recursive scope ref here
id: context.get_id(),
parent_scope: Cell::new(Some(import_scope)),
variables: RefCell::new(IndexMap::new()),
aliases: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
global_consts: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
function: Cell::new(None),
});
// Prepare header-like scope entries.
// Have to do aliases first.
for (name, alias) in program.aliases.iter() {
assert_eq!(name.name, alias.name.name);
let asg_alias = Alias::init(scope, alias)?;
scope.aliases.borrow_mut().insert(name.name.to_string(), asg_alias);
}
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = Circuit::init(scope, circuit)?;
scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit);
}
// Second pass for circuit members.
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = Circuit::init_member(scope, circuit)?;
scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit);
}
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let function = Function::init(scope, function)?;
scope.functions.borrow_mut().insert(name.name.to_string(), function);
}
for (names, global_const) in program.global_consts.iter() {
let gc = <&Statement<'a>>::from_ast(scope, global_const, None)?;
if let Statement::Definition(def) = gc {
let name = names
.iter()
.enumerate()
.map(|(i, name)| {
assert_eq!(name.name, def.variables.get(i).unwrap().borrow().name.name);
name.name.to_string()
})
.collect::<Vec<String>>()
.join(",");
scope.global_consts.borrow_mut().insert(name, def);
}
}
// Load concrete definitions.
let mut aliases = IndexMap::new();
let mut functions = IndexMap::new();
let mut circuits = IndexMap::new();
let mut global_consts = IndexMap::new();
for (name, alias) in program.aliases.iter() {
assert_eq!(name.name, alias.name.name);
let asg_alias = *scope.aliases.borrow().get(name.name.as_ref()).unwrap();
let name = name.name.to_string();
check_top_level_namespaces(&name, &alias.span, &aliases, &functions, &circuits, &global_consts)?;
aliases.insert(name, asg_alias);
}
for (name, function) in program.functions.iter() {
assert_eq!(name.name, function.identifier.name);
let asg_function = *scope.functions.borrow().get(name.name.as_ref()).unwrap();
asg_function.fill_from_ast(function)?;
let name = name.name.to_string();
check_top_level_namespaces(&name, &function.span, &aliases, &functions, &circuits, &global_consts)?;
functions.insert(name, asg_function);
}
for (name, circuit) in program.circuits.iter() {
assert_eq!(name.name, circuit.circuit_name.name);
let asg_circuit = *scope.circuits.borrow().get(name.name.as_ref()).unwrap();
asg_circuit.fill_from_ast(circuit)?;
let name = name.name.to_string();
check_top_level_namespaces(
&name,
&circuit.circuit_name.span,
&aliases,
&functions,
&circuits,
&global_consts,
)?;
circuits.insert(name, asg_circuit);
}
for (names, global_const) in program.global_consts.iter() {
let name = names
.iter()
.map(|name| name.name.to_string())
.collect::<Vec<String>>()
.join(",");
let asg_global_const = *scope.global_consts.borrow().get(&name).unwrap();
check_top_level_namespaces(
&name,
&global_const.span,
&aliases,
&functions,
&circuits,
&global_consts,
)?;
global_consts.insert(name.clone(), asg_global_const);
}
Ok(Program {
context,
id: context.get_id(),
name: program.name.clone(),
aliases,
functions,
global_consts,
circuits,
imported_modules: imported_modules
.into_iter()
.map(|(package, program)| (package.join("."), program))
.collect(),
scope,
})
}
}

View File

@ -1,39 +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/>.
//! This module contains the reducer which iterates through ast nodes - converting them into
//! asg nodes and saving relevant information.
mod monoid;
pub use monoid::*;
mod monoidal_director;
pub use monoidal_director::*;
mod monoidal_reducer;
pub use monoidal_reducer::*;
mod reconstructing_reducer;
pub use reconstructing_reducer::*;
mod reconstructing_director;
pub use reconstructing_director::*;
mod visitor;
pub use visitor::*;
mod visitor_director;
pub use visitor_director::*;

View File

@ -1,30 +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 super::*;
#[derive(Default)]
pub struct BoolAnd(pub bool);
impl Monoid for BoolAnd {
fn append(self, other: Self) -> Self {
BoolAnd(self.0 && other.0)
}
fn append_all(self, mut others: impl Iterator<Item = Self>) -> Self {
BoolAnd(others.all(|i| i.0))
}
}

View File

@ -1,43 +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/>.
mod bool_and;
pub use bool_and::*;
mod set_append;
pub use set_append::*;
mod vec_append;
pub use vec_append::*;
pub trait Monoid: Default {
fn append(self, other: Self) -> Self;
fn append_all(self, others: impl Iterator<Item = Self>) -> Self {
let mut current = self;
for item in others {
current = current.append(item);
}
current
}
fn append_option(self, other: Option<Self>) -> Self {
match other {
None => self,
Some(other) => self.append(other),
}
}
}

View File

@ -1,51 +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 super::*;
use indexmap::IndexSet;
use std::hash::Hash;
pub struct SetAppend<T: Hash + Eq + 'static>(IndexSet<T>);
impl<T: Hash + Eq + 'static> Default for SetAppend<T> {
fn default() -> Self {
Self(IndexSet::new())
}
}
impl<T: Hash + Eq + 'static> Monoid for SetAppend<T> {
fn append(mut self, other: Self) -> Self {
self.0.extend(other.0);
SetAppend(self.0)
}
fn append_all(mut self, others: impl Iterator<Item = Self>) -> Self {
let all: Vec<IndexSet<T>> = others.map(|x| x.0).collect();
let total_size = all.iter().fold(0, |acc, v| acc + v.len());
self.0.reserve(total_size);
for item in all.into_iter() {
self.0.extend(item);
}
self
}
}
impl<T: Hash + Eq + 'static> Into<IndexSet<T>> for SetAppend<T> {
fn into(self) -> IndexSet<T> {
self.0
}
}

View File

@ -1,48 +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 super::*;
pub struct VecAppend<T>(Vec<T>);
impl<T> Default for VecAppend<T> {
fn default() -> Self {
Self(vec![])
}
}
impl<T> Monoid for VecAppend<T> {
fn append(mut self, other: Self) -> Self {
self.0.extend(other.0);
VecAppend(self.0)
}
fn append_all(mut self, others: impl Iterator<Item = Self>) -> Self {
let all: Vec<Vec<T>> = others.map(|x| x.0).collect();
let total_size = all.iter().fold(0, |acc, v| acc + v.len());
self.0.reserve(total_size);
for item in all.into_iter() {
self.0.extend(item);
}
self
}
}
impl<T> Into<Vec<T>> for VecAppend<T> {
fn into(self) -> Vec<T> {
self.0
}
}

View File

@ -1,320 +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 super::*;
use crate::{expression::*, program::*, statement::*};
use std::marker::PhantomData;
pub struct MonoidalDirector<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> {
reducer: R,
_monoid: PhantomData<&'a T>,
}
impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T, R> {
pub fn new(reducer: R) -> Self {
Self {
reducer,
_monoid: PhantomData,
}
}
pub fn reducer(self) -> R {
self.reducer
}
pub fn reduce_expression(&mut self, input: &'a Expression<'a>) -> T {
let value = match input {
Expression::ArrayAccess(e) => self.reduce_array_access(e),
Expression::ArrayInit(e) => self.reduce_array_init(e),
Expression::ArrayInline(e) => self.reduce_array_inline(e),
Expression::ArrayRangeAccess(e) => self.reduce_array_range_access(e),
Expression::Binary(e) => self.reduce_binary(e),
Expression::Call(e) => self.reduce_call(e),
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::LengthOf(e) => self.reduce_lengthof_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),
Expression::Unary(e) => self.reduce_unary(e),
Expression::VariableRef(e) => self.reduce_variable_ref(e),
};
self.reducer.reduce_expression(input, value)
}
pub fn reduce_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> T {
let array = self.reduce_expression(input.array.get());
let index = self.reduce_expression(input.index.get());
self.reducer.reduce_array_access(input, array, index)
}
pub fn reduce_array_init(&mut self, input: &ArrayInitExpression<'a>) -> T {
let element = self.reduce_expression(input.element.get());
self.reducer.reduce_array_init(input, element)
}
pub fn reduce_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> T {
let elements = input
.elements
.iter()
.map(|(x, _)| self.reduce_expression(x.get()))
.collect();
self.reducer.reduce_array_inline(input, elements)
}
pub fn reduce_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> T {
let array = self.reduce_expression(input.array.get());
let left = input.left.get().map(|e| self.reduce_expression(e));
let right = input.right.get().map(|e| self.reduce_expression(e));
self.reducer.reduce_array_range_access(input, array, left, right)
}
pub fn reduce_binary(&mut self, input: &BinaryExpression<'a>) -> T {
let left = self.reduce_expression(input.left.get());
let right = self.reduce_expression(input.right.get());
self.reducer.reduce_binary(input, left, right)
}
pub fn reduce_call(&mut self, input: &CallExpression<'a>) -> T {
let target = input.target.get().map(|e| self.reduce_expression(e));
let arguments = input
.arguments
.iter()
.map(|e| self.reduce_expression(e.get()))
.collect();
self.reducer.reduce_call(input, target, arguments)
}
pub fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> T {
let target = input.target.get().map(|e| self.reduce_expression(e));
self.reducer.reduce_circuit_access(input, target)
}
pub fn reduce_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> T {
let values = input
.values
.iter()
.map(|(_, e)| self.reduce_expression(e.get()))
.collect();
self.reducer.reduce_circuit_init(input, values)
}
pub fn reduce_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> T {
let condition = self.reduce_expression(input.condition.get());
let if_true = self.reduce_expression(input.if_true.get());
let if_false = self.reduce_expression(input.if_false.get());
self.reducer
.reduce_ternary_expression(input, condition, if_true, if_false)
}
pub fn reduce_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_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> T {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_lengthof_expression(input, inner)
}
pub fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
self.reducer.reduce_constant(input)
}
pub fn reduce_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> T {
let tuple_ref = self.reduce_expression(input.tuple_ref.get());
self.reducer.reduce_tuple_access(input, tuple_ref)
}
pub fn reduce_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> T {
let values = input.elements.iter().map(|e| self.reduce_expression(e.get())).collect();
self.reducer.reduce_tuple_init(input, values)
}
pub fn reduce_unary(&mut self, input: &UnaryExpression<'a>) -> T {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_unary(input, inner)
}
pub fn reduce_variable_ref(&mut self, input: &VariableRef<'a>) -> T {
self.reducer.reduce_variable_ref(input)
}
}
impl<'a, T: Monoid, R: MonoidalReducerStatement<'a, T>> MonoidalDirector<'a, T, R> {
pub fn reduce_statement(&mut self, input: &'a Statement<'a>) -> T {
let value = match input {
Statement::Assign(s) => self.reduce_assign(s),
Statement::Block(s) => self.reduce_block(s),
Statement::Conditional(s) => self.reduce_conditional_statement(s),
Statement::Console(s) => self.reduce_console(s),
Statement::Definition(s) => self.reduce_definition(s),
Statement::Expression(s) => self.reduce_expression_statement(s),
Statement::Iteration(s) => self.reduce_iteration(s),
Statement::Return(s) => self.reduce_return(s),
Statement::Empty(_) => T::default(),
};
self.reducer.reduce_statement(input, value)
}
pub fn reduce_assign_access(&mut self, input: &AssignAccess<'a>) -> T {
let (left, right) = match input {
AssignAccess::ArrayRange(left, right) => (
left.get().map(|e| self.reduce_expression(e)),
right.get().map(|e| self.reduce_expression(e)),
),
AssignAccess::ArrayIndex(index) => (Some(self.reduce_expression(index.get())), None),
_ => (None, None),
};
self.reducer.reduce_assign_access(input, left, right)
}
pub fn reduce_assign(&mut self, input: &AssignStatement<'a>) -> T {
let accesses = input
.target_accesses
.iter()
.map(|x| self.reduce_assign_access(x))
.collect();
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_assign(input, accesses, value)
}
pub fn reduce_block(&mut self, input: &BlockStatement<'a>) -> T {
let statements = input
.statements
.iter()
.map(|x| self.reduce_statement(x.get()))
.collect();
self.reducer.reduce_block(input, statements)
}
pub fn reduce_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> T {
let condition = self.reduce_expression(input.condition.get());
let if_true = self.reduce_statement(input.result.get());
let if_false = input.next.get().map(|s| self.reduce_statement(s));
self.reducer
.reduce_conditional_statement(input, condition, if_true, if_false)
}
pub fn reduce_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> T {
let parameters = input
.parameters
.iter()
.map(|e| self.reduce_expression(e.get()))
.collect();
self.reducer.reduce_formatted_string(input, parameters)
}
pub fn reduce_console(&mut self, input: &ConsoleStatement<'a>) -> T {
let argument = match &input.function {
ConsoleFunction::Assert(e) => self.reduce_expression(e.get()),
ConsoleFunction::Error(f) | ConsoleFunction::Log(f) => self.reduce_formatted_string(f),
};
self.reducer.reduce_console(input, argument)
}
pub fn reduce_definition(&mut self, input: &DefinitionStatement<'a>) -> T {
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_definition(input, value)
}
pub fn reduce_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> T {
let value = self.reduce_expression(input.expression.get());
self.reducer.reduce_expression_statement(input, value)
}
pub fn reduce_iteration(&mut self, input: &IterationStatement<'a>) -> T {
let start = self.reduce_expression(input.start.get());
let stop = self.reduce_expression(input.stop.get());
let body = self.reduce_statement(input.body.get());
self.reducer.reduce_iteration(input, start, stop, body)
}
pub fn reduce_return(&mut self, input: &ReturnStatement<'a>) -> T {
let value = self.reduce_expression(input.expression.get());
self.reducer.reduce_return(input, value)
}
}
impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R> {
pub fn reduce_function(&mut self, input: &'a Function<'a>) -> T {
let body = input.body.get().map(|s| self.reduce_statement(s)).unwrap_or_default();
self.reducer.reduce_function(input, body)
}
pub fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>) -> T {
let function = match input {
CircuitMember::Function(f) => Some(self.reduce_function(f)),
_ => None,
};
self.reducer.reduce_circuit_member(input, function)
}
pub fn reduce_circuit(&mut self, input: &'a Circuit<'a>) -> T {
let members = input
.members
.borrow()
.iter()
.map(|(_, member)| self.reduce_circuit_member(member))
.collect();
self.reducer.reduce_circuit(input, members)
}
pub fn reduce_program(&mut self, input: &Program<'a>) -> T {
let imported_modules = input
.imported_modules
.iter()
.map(|(_, import)| self.reduce_program(import))
.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, functions, circuits)
}
}

View File

@ -1,170 +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::{expression::*, program::*, statement::*, Monoid};
#[allow(unused_variables)]
pub trait MonoidalReducerExpression<'a, T: Monoid> {
fn reduce_expression(&mut self, input: &'a Expression<'a>, value: T) -> T {
value
}
fn reduce_array_access(&mut self, input: &ArrayAccessExpression<'a>, array: T, index: T) -> T {
array.append(index)
}
fn reduce_array_init(&mut self, input: &ArrayInitExpression<'a>, element: T) -> T {
element
}
fn reduce_array_inline(&mut self, input: &ArrayInlineExpression<'a>, elements: Vec<T>) -> T {
T::default().append_all(elements.into_iter())
}
fn reduce_array_range_access(
&mut self,
input: &ArrayRangeAccessExpression<'a>,
array: T,
left: Option<T>,
right: Option<T>,
) -> T {
array.append_option(left).append_option(right)
}
fn reduce_binary(&mut self, input: &BinaryExpression<'a>, left: T, right: T) -> T {
left.append(right)
}
fn reduce_call(&mut self, input: &CallExpression<'a>, target: Option<T>, arguments: Vec<T>) -> T {
target.unwrap_or_default().append_all(arguments.into_iter())
}
fn reduce_circuit_access(&mut self, input: &CircuitAccessExpression<'a>, target: Option<T>) -> T {
target.unwrap_or_default()
}
fn reduce_circuit_init(&mut self, input: &CircuitInitExpression<'a>, values: Vec<T>) -> T {
T::default().append_all(values.into_iter())
}
fn reduce_ternary_expression(&mut self, input: &TernaryExpression<'a>, condition: T, if_true: T, if_false: T) -> T {
condition.append(if_true).append(if_false)
}
fn reduce_cast_expression(&mut self, input: &CastExpression<'a>, inner: T) -> T {
inner
}
fn reduce_lengthof_expression(&mut self, input: &LengthOfExpression<'a>, inner: T) -> T {
inner
}
fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
T::default()
}
fn reduce_tuple_access(&mut self, input: &TupleAccessExpression<'a>, tuple_ref: T) -> T {
tuple_ref
}
fn reduce_tuple_init(&mut self, input: &TupleInitExpression<'a>, values: Vec<T>) -> T {
T::default().append_all(values.into_iter())
}
fn reduce_unary(&mut self, input: &UnaryExpression<'a>, inner: T) -> T {
inner
}
fn reduce_variable_ref(&mut self, input: &VariableRef<'a>) -> T {
T::default()
}
}
#[allow(unused_variables)]
pub trait MonoidalReducerStatement<'a, T: Monoid>: MonoidalReducerExpression<'a, T> {
fn reduce_statement(&mut self, input: &'a Statement<'a>, value: T) -> T {
value
}
// left = Some(ArrayIndex.0) always if AssignAccess::ArrayIndex. if member/tuple, always None
fn reduce_assign_access(&mut self, input: &AssignAccess<'a>, left: Option<T>, right: Option<T>) -> T {
left.unwrap_or_default().append_option(right)
}
fn reduce_assign(&mut self, input: &AssignStatement<'a>, accesses: Vec<T>, value: T) -> T {
T::default().append_all(accesses.into_iter()).append(value)
}
fn reduce_block(&mut self, input: &BlockStatement<'a>, statements: Vec<T>) -> T {
T::default().append_all(statements.into_iter())
}
fn reduce_conditional_statement(
&mut self,
input: &ConditionalStatement<'a>,
condition: T,
if_true: T,
if_false: Option<T>,
) -> T {
condition.append(if_true).append_option(if_false)
}
fn reduce_formatted_string(&mut self, input: &ConsoleArgs<'a>, parameters: Vec<T>) -> T {
T::default().append_all(parameters.into_iter())
}
fn reduce_console(&mut self, input: &ConsoleStatement<'a>, argument: T) -> T {
argument
}
fn reduce_definition(&mut self, input: &DefinitionStatement<'a>, value: T) -> T {
value
}
fn reduce_expression_statement(&mut self, input: &ExpressionStatement<'a>, expression: T) -> T {
expression
}
fn reduce_iteration(&mut self, input: &IterationStatement<'a>, start: T, stop: T, body: T) -> T {
start.append(stop).append(body)
}
fn reduce_return(&mut self, input: &ReturnStatement<'a>, value: T) -> T {
value
}
}
#[allow(unused_variables)]
pub trait MonoidalReducerProgram<'a, T: Monoid>: MonoidalReducerStatement<'a, T> {
fn reduce_function(&mut self, input: &'a Function<'a>, body: T) -> T {
body
}
fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>, function: Option<T>) -> T {
function.unwrap_or_default()
}
fn reduce_circuit(&mut self, input: &'a Circuit<'a>, members: Vec<T>) -> T {
T::default().append_all(members.into_iter())
}
fn reduce_program(&mut self, input: &Program, imported_modules: Vec<T>, functions: Vec<T>, circuits: Vec<T>) -> T {
T::default()
.append_all(imported_modules.into_iter())
.append_all(functions.into_iter())
.append_all(circuits.into_iter())
}
}

View File

@ -1,359 +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 super::*;
use crate::{expression::*, program::*, statement::*, AsgContext};
/*
reconstructing director tries to maintain a normalized ASG but may require renormalization under the following circumstances:
* breaking strict reducer model (i.e. live mutations)
* dropping or duplicating branches
*/
pub struct ReconstructingDirector<'a, R: ReconstructingReducerExpression<'a>> {
context: AsgContext<'a>,
reducer: R,
}
impl<'a, R: ReconstructingReducerExpression<'a>> ReconstructingDirector<'a, R> {
pub fn new(context: AsgContext<'a>, reducer: R) -> Self {
Self { context, reducer }
}
pub fn reducer(self) -> R {
self.reducer
}
pub fn reduce_expression(&mut self, input: &'a Expression<'a>) -> &'a Expression<'a> {
let value = match input.clone() {
Expression::ArrayAccess(e) => self.reduce_array_access(e),
Expression::ArrayInit(e) => self.reduce_array_init(e),
Expression::ArrayInline(e) => self.reduce_array_inline(e),
Expression::ArrayRangeAccess(e) => self.reduce_array_range_access(e),
Expression::Binary(e) => self.reduce_binary(e),
Expression::Call(e) => self.reduce_call(e),
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::LengthOf(e) => Expression::LengthOf(e), // TODO: implement REDUCER
Expression::Constant(e) => self.reduce_constant(e),
Expression::TupleAccess(e) => self.reduce_tuple_access(e),
Expression::TupleInit(e) => self.reduce_tuple_init(e),
Expression::Unary(e) => self.reduce_unary(e),
Expression::VariableRef(e) => {
{
let mut variable = e.variable.borrow_mut();
let index = variable.references.iter().position(|x| (*x).ptr_eq(input));
if let Some(index) = index {
variable.references.remove(index);
}
}
self.reduce_variable_ref(e)
}
};
let allocated = self
.context
.alloc_expression(self.reducer.reduce_expression(input, value));
if let Expression::VariableRef(reference) = allocated {
let mut variable = reference.variable.borrow_mut();
variable.references.push(allocated);
}
allocated
}
pub fn reduce_array_access(&mut self, input: ArrayAccessExpression<'a>) -> Expression<'a> {
let array = self.reduce_expression(input.array.get());
let index = self.reduce_expression(input.index.get());
self.reducer.reduce_array_access(input, array, index)
}
pub fn reduce_array_init(&mut self, input: ArrayInitExpression<'a>) -> Expression<'a> {
let element = self.reduce_expression(input.element.get());
self.reducer.reduce_array_init(input, element)
}
pub fn reduce_array_inline(&mut self, input: ArrayInlineExpression<'a>) -> Expression<'a> {
let elements = input
.elements
.iter()
.map(|(x, spread)| (self.reduce_expression(x.get()), *spread))
.collect();
self.reducer.reduce_array_inline(input, elements)
}
pub fn reduce_array_range_access(&mut self, input: ArrayRangeAccessExpression<'a>) -> Expression<'a> {
let array = self.reduce_expression(input.array.get());
let left = input.left.get().map(|e| self.reduce_expression(e));
let right = input.right.get().map(|e| self.reduce_expression(e));
self.reducer.reduce_array_range_access(input, array, left, right)
}
pub fn reduce_binary(&mut self, input: BinaryExpression<'a>) -> Expression<'a> {
let left = self.reduce_expression(input.left.get());
let right = self.reduce_expression(input.right.get());
self.reducer.reduce_binary(input, left, right)
}
pub fn reduce_call(&mut self, input: CallExpression<'a>) -> Expression<'a> {
let target = input.target.get().map(|e| self.reduce_expression(e));
let arguments = input
.arguments
.iter()
.map(|e| self.reduce_expression(e.get()))
.collect();
self.reducer.reduce_call(input, target, arguments)
}
pub fn reduce_circuit_access(&mut self, input: CircuitAccessExpression<'a>) -> Expression<'a> {
let target = input.target.get().map(|e| self.reduce_expression(e));
self.reducer.reduce_circuit_access(input, target)
}
pub fn reduce_circuit_init(&mut self, input: CircuitInitExpression<'a>) -> Expression<'a> {
let values = input
.values
.iter()
.map(|(ident, e)| (ident.clone(), self.reduce_expression(e.get())))
.collect();
self.reducer.reduce_circuit_init(input, values)
}
pub fn reduce_ternary_expression(&mut self, input: TernaryExpression<'a>) -> Expression<'a> {
let condition = self.reduce_expression(input.condition.get());
let if_true = self.reduce_expression(input.if_true.get());
let if_false = self.reduce_expression(input.if_false.get());
self.reducer
.reduce_ternary_expression(input, condition, if_true, if_false)
}
pub fn reduce_cast_expression(&mut self, input: CastExpression<'a>) -> Expression<'a> {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_cast_expression(input, inner)
}
pub fn reduce_constant(&mut self, input: Constant<'a>) -> Expression<'a> {
self.reducer.reduce_constant(input)
}
pub fn reduce_tuple_access(&mut self, input: TupleAccessExpression<'a>) -> Expression<'a> {
let tuple_ref = self.reduce_expression(input.tuple_ref.get());
self.reducer.reduce_tuple_access(input, tuple_ref)
}
pub fn reduce_tuple_init(&mut self, input: TupleInitExpression<'a>) -> Expression<'a> {
let values = input.elements.iter().map(|e| self.reduce_expression(e.get())).collect();
self.reducer.reduce_tuple_init(input, values)
}
pub fn reduce_unary(&mut self, input: UnaryExpression<'a>) -> Expression<'a> {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_unary(input, inner)
}
pub fn reduce_variable_ref(&mut self, input: VariableRef<'a>) -> Expression<'a> {
self.reducer.reduce_variable_ref(input)
}
}
impl<'a, R: ReconstructingReducerStatement<'a>> ReconstructingDirector<'a, R> {
pub fn reduce_statement(&mut self, input: &'a Statement<'a>) -> &'a Statement<'a> {
let value = match input.clone() {
Statement::Assign(s) => self.reduce_assign(s),
Statement::Block(s) => self.reduce_block(s),
Statement::Conditional(s) => self.reduce_conditional_statement(s),
Statement::Console(s) => self.reduce_console(s),
Statement::Definition(s) => self.reduce_definition(s),
Statement::Expression(s) => self.reduce_expression_statement(s),
Statement::Iteration(s) => self.reduce_iteration(s),
Statement::Return(s) => self.reduce_return(s),
x @ Statement::Empty(_) => x,
};
self.reducer.reduce_statement_alloc(self.context, input, value)
}
pub fn reduce_assign_access(&mut self, input: AssignAccess<'a>) -> AssignAccess<'a> {
match &input {
AssignAccess::ArrayRange(left, right) => {
let left = left.get().map(|e| self.reduce_expression(e));
let right = right.get().map(|e| self.reduce_expression(e));
self.reducer.reduce_assign_access_range(input, left, right)
}
AssignAccess::ArrayIndex(index) => {
let index = self.reduce_expression(index.get());
self.reducer.reduce_assign_access_index(input, index)
}
_ => self.reducer.reduce_assign_access(input),
}
}
pub fn reduce_assign(&mut self, input: AssignStatement<'a>) -> Statement<'a> {
let accesses = input
.target_accesses
.iter()
.map(|x| self.reduce_assign_access(x.clone()))
.collect();
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_assign(input, accesses, value)
}
pub fn reduce_block(&mut self, input: BlockStatement<'a>) -> Statement<'a> {
let statements = input
.statements
.iter()
.map(|x| self.reduce_statement(x.get()))
.collect();
self.reducer.reduce_block(input, statements)
}
pub fn reduce_conditional_statement(&mut self, input: ConditionalStatement<'a>) -> Statement<'a> {
let condition = self.reduce_expression(input.condition.get());
let if_true = self.reduce_statement(input.result.get());
let if_false = input.next.get().map(|s| self.reduce_statement(s));
self.reducer
.reduce_conditional_statement(input, condition, if_true, if_false)
}
pub fn reduce_formatted_string(&mut self, input: ConsoleArgs<'a>) -> ConsoleArgs<'a> {
let parameters = input
.parameters
.iter()
.map(|e| self.reduce_expression(e.get()))
.collect();
self.reducer.reduce_formatted_string(input, parameters)
}
pub fn reduce_console(&mut self, input: ConsoleStatement<'a>) -> Statement<'a> {
match &input.function {
ConsoleFunction::Assert(argument) => {
let argument = self.reduce_expression(argument.get());
self.reducer.reduce_console_assert(input, argument)
}
ConsoleFunction::Error(f) | ConsoleFunction::Log(f) => {
let formatted = self.reduce_formatted_string(f.clone());
self.reducer.reduce_console_log(input, formatted)
}
}
}
pub fn reduce_definition(&mut self, input: DefinitionStatement<'a>) -> Statement<'a> {
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_definition(input, value)
}
pub fn reduce_expression_statement(&mut self, input: ExpressionStatement<'a>) -> Statement<'a> {
let value = self.reduce_expression(input.expression.get());
self.reducer.reduce_expression_statement(input, value)
}
pub fn reduce_iteration(&mut self, input: IterationStatement<'a>) -> Statement<'a> {
let start = self.reduce_expression(input.start.get());
let stop = self.reduce_expression(input.stop.get());
let body = self.reduce_statement(input.body.get());
self.reducer.reduce_iteration(input, start, stop, body)
}
pub fn reduce_return(&mut self, input: ReturnStatement<'a>) -> Statement<'a> {
let value = self.reduce_expression(input.expression.get());
self.reducer.reduce_return(input, value)
}
}
#[allow(dead_code)]
impl<'a, R: ReconstructingReducerProgram<'a>> ReconstructingDirector<'a, R> {
fn reduce_function(&mut self, input: &'a Function<'a>) -> &'a Function<'a> {
let body = input.body.get().map(|s| self.reduce_statement(s));
self.reducer.reduce_function(input, body)
}
pub fn reduce_circuit_member(&mut self, input: CircuitMember<'a>) -> CircuitMember<'a> {
match input {
CircuitMember::Function(function) => {
let function = self.reduce_function(function);
self.reducer.reduce_circuit_member_function(input, function)
}
CircuitMember::Variable(_) => self.reducer.reduce_circuit_member_variable(input),
}
}
pub fn reduce_circuit(&mut self, input: &'a Circuit<'a>) -> &'a Circuit<'a> {
let members = input
.members
.borrow()
.iter()
.map(|(_, member)| self.reduce_circuit_member(member.clone()))
.collect();
self.reducer.reduce_circuit(input, members)
}
pub fn reduce_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> &'a DefinitionStatement<'a> {
let value = self.reduce_expression(input.value.get());
self.reducer.reduce_global_const(input, value)
}
pub fn reduce_program(&mut self, input: Program<'a>) -> Program<'a> {
let imported_modules = input
.imported_modules
.iter()
.map(|(module, import)| (module.clone(), self.reduce_program(import.clone())))
.collect();
let aliases = input.aliases.iter().map(|(name, a)| (name.clone(), *a)).collect();
let functions = input
.functions
.iter()
.map(|(name, f)| (name.clone(), self.reduce_function(f)))
.collect();
let circuits = input
.circuits
.iter()
.map(|(name, c)| (name.clone(), self.reduce_circuit(c)))
.collect();
let global_consts = input
.global_consts
.iter()
.map(|(name, gc)| (name.clone(), self.reduce_global_const(gc)))
.collect();
self.reducer
.reduce_program(input, imported_modules, aliases, functions, circuits, global_consts)
}
}

View File

@ -1,416 +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 std::cell::Cell;
use leo_ast::Identifier;
use crate::{expression::*, program::*, statement::*, AsgContext};
#[allow(unused_variables)]
pub trait ReconstructingReducerExpression<'a> {
fn reduce_expression(&mut self, input: &'a Expression<'a>, value: Expression<'a>) -> Expression<'a> {
value
}
fn reduce_array_access(
&mut self,
input: ArrayAccessExpression<'a>,
array: &'a Expression<'a>,
index: &'a Expression<'a>,
) -> Expression<'a> {
Expression::ArrayAccess(ArrayAccessExpression {
parent: input.parent,
array: Cell::new(array),
index: Cell::new(index),
span: input.span,
})
}
fn reduce_array_init(&mut self, input: ArrayInitExpression<'a>, element: &'a Expression<'a>) -> Expression<'a> {
Expression::ArrayInit(ArrayInitExpression {
parent: input.parent,
element: Cell::new(element),
len: input.len,
span: input.span,
})
}
fn reduce_array_inline(
&mut self,
input: ArrayInlineExpression<'a>,
elements: Vec<(&'a Expression<'a>, bool)>,
) -> Expression<'a> {
Expression::ArrayInline(ArrayInlineExpression {
parent: input.parent,
elements: elements.into_iter().map(|x| (Cell::new(x.0), x.1)).collect(),
span: input.span,
})
}
fn reduce_array_range_access(
&mut self,
input: ArrayRangeAccessExpression<'a>,
array: &'a Expression<'a>,
left: Option<&'a Expression<'a>>,
right: Option<&'a Expression<'a>>,
) -> Expression<'a> {
Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
parent: input.parent,
array: Cell::new(array),
left: Cell::new(left),
right: Cell::new(right),
span: input.span,
length: input.length,
})
}
fn reduce_binary(
&mut self,
input: BinaryExpression<'a>,
left: &'a Expression<'a>,
right: &'a Expression<'a>,
) -> Expression<'a> {
Expression::Binary(BinaryExpression {
parent: input.parent,
left: Cell::new(left),
right: Cell::new(right),
span: input.span,
operation: input.operation,
})
}
fn reduce_call(
&mut self,
input: CallExpression<'a>,
target: Option<&'a Expression<'a>>,
arguments: Vec<&'a Expression<'a>>,
) -> Expression<'a> {
Expression::Call(CallExpression {
parent: input.parent,
function: input.function,
target: Cell::new(target),
arguments: arguments.into_iter().map(Cell::new).collect(),
span: input.span,
})
}
fn reduce_circuit_access(
&mut self,
input: CircuitAccessExpression<'a>,
target: Option<&'a Expression<'a>>,
) -> Expression<'a> {
Expression::CircuitAccess(CircuitAccessExpression {
parent: input.parent,
circuit: input.circuit,
target: Cell::new(target),
member: input.member,
span: input.span,
})
}
fn reduce_circuit_init(
&mut self,
input: CircuitInitExpression<'a>,
values: Vec<(Identifier, &'a Expression<'a>)>,
) -> Expression<'a> {
Expression::CircuitInit(CircuitInitExpression {
parent: input.parent,
circuit: input.circuit,
values: values.into_iter().map(|x| (x.0, Cell::new(x.1))).collect(),
span: input.span,
})
}
fn reduce_ternary_expression(
&mut self,
input: TernaryExpression<'a>,
condition: &'a Expression<'a>,
if_true: &'a Expression<'a>,
if_false: &'a Expression<'a>,
) -> Expression<'a> {
Expression::Ternary(TernaryExpression {
parent: input.parent,
condition: Cell::new(condition),
if_true: Cell::new(if_true),
if_false: Cell::new(if_false),
span: input.span,
})
}
fn reduce_cast_expression(&mut self, input: CastExpression<'a>, inner: &'a Expression<'a>) -> Expression<'a> {
Expression::Cast(CastExpression {
parent: input.parent,
inner: Cell::new(inner),
target_type: input.target_type,
span: input.span,
})
}
fn reduce_constant(&mut self, input: Constant<'a>) -> Expression<'a> {
Expression::Constant(input)
}
fn reduce_tuple_access(
&mut self,
input: TupleAccessExpression<'a>,
tuple_ref: &'a Expression<'a>,
) -> Expression<'a> {
Expression::TupleAccess(TupleAccessExpression {
parent: input.parent,
tuple_ref: Cell::new(tuple_ref),
index: input.index,
span: input.span,
})
}
fn reduce_tuple_init(&mut self, input: TupleInitExpression<'a>, values: Vec<&'a Expression<'a>>) -> Expression<'a> {
Expression::TupleInit(TupleInitExpression {
parent: input.parent,
elements: values.into_iter().map(Cell::new).collect(),
span: input.span,
})
}
fn reduce_unary(&mut self, input: UnaryExpression<'a>, inner: &'a Expression<'a>) -> Expression<'a> {
Expression::Unary(UnaryExpression {
parent: input.parent,
inner: Cell::new(inner),
span: input.span,
operation: input.operation,
})
}
fn reduce_variable_ref(&mut self, input: VariableRef<'a>) -> Expression<'a> {
Expression::VariableRef(input)
}
}
#[allow(unused_variables)]
pub trait ReconstructingReducerStatement<'a>: ReconstructingReducerExpression<'a> {
fn reduce_statement_alloc(
&mut self,
context: AsgContext<'a>,
input: &'a Statement<'a>,
value: Statement<'a>,
) -> &'a Statement<'a> {
context.alloc_statement(value)
}
fn reduce_statement(&mut self, input: &'a Statement<'a>, value: Statement<'a>) -> Statement<'a> {
value
}
fn reduce_assign_access_range(
&mut self,
input: AssignAccess<'a>,
left: Option<&'a Expression<'a>>,
right: Option<&'a Expression<'a>>,
) -> AssignAccess<'a> {
AssignAccess::ArrayRange(Cell::new(left), Cell::new(right))
}
fn reduce_assign_access_index(&mut self, input: AssignAccess<'a>, index: &'a Expression<'a>) -> AssignAccess<'a> {
AssignAccess::ArrayIndex(Cell::new(index))
}
fn reduce_assign_access(&mut self, input: AssignAccess<'a>) -> AssignAccess<'a> {
input
}
fn reduce_assign(
&mut self,
input: AssignStatement<'a>,
accesses: Vec<AssignAccess<'a>>,
value: &'a Expression<'a>,
) -> Statement<'a> {
Statement::Assign(AssignStatement {
parent: input.parent,
span: input.span,
operation: input.operation,
target_accesses: accesses,
target_variable: input.target_variable,
value: Cell::new(value),
})
}
fn reduce_block(&mut self, input: BlockStatement<'a>, statements: Vec<&'a Statement<'a>>) -> Statement<'a> {
Statement::Block(BlockStatement {
parent: input.parent,
span: input.span,
statements: statements.into_iter().map(Cell::new).collect(),
scope: input.scope,
})
}
fn reduce_conditional_statement(
&mut self,
input: ConditionalStatement<'a>,
condition: &'a Expression<'a>,
if_true: &'a Statement<'a>,
if_false: Option<&'a Statement<'a>>,
) -> Statement<'a> {
Statement::Conditional(ConditionalStatement {
parent: input.parent,
span: input.span,
condition: Cell::new(condition),
result: Cell::new(if_true),
next: Cell::new(if_false),
})
}
fn reduce_formatted_string(
&mut self,
input: ConsoleArgs<'a>,
parameters: Vec<&'a Expression<'a>>,
) -> ConsoleArgs<'a> {
ConsoleArgs {
span: input.span,
string: input.string,
parameters: parameters.into_iter().map(Cell::new).collect(),
}
}
fn reduce_console_assert(&mut self, input: ConsoleStatement<'a>, argument: &'a Expression<'a>) -> Statement<'a> {
assert!(matches!(input.function, ConsoleFunction::Assert(_)));
Statement::Console(ConsoleStatement {
parent: input.parent,
span: input.span,
function: ConsoleFunction::Assert(Cell::new(argument)),
})
}
fn reduce_console_log(&mut self, input: ConsoleStatement<'a>, argument: ConsoleArgs<'a>) -> Statement<'a> {
assert!(!matches!(input.function, ConsoleFunction::Assert(_)));
Statement::Console(ConsoleStatement {
parent: input.parent,
span: input.span,
function: match input.function {
ConsoleFunction::Assert(_) => unimplemented!(),
ConsoleFunction::Error(_) => ConsoleFunction::Error(argument),
ConsoleFunction::Log(_) => ConsoleFunction::Log(argument),
},
})
}
fn reduce_definition(&mut self, input: DefinitionStatement<'a>, value: &'a Expression<'a>) -> Statement<'a> {
Statement::Definition(DefinitionStatement {
parent: input.parent,
span: input.span,
variables: input.variables,
value: Cell::new(value),
})
}
fn reduce_expression_statement(
&mut self,
input: ExpressionStatement<'a>,
expression: &'a Expression<'a>,
) -> Statement<'a> {
Statement::Expression(ExpressionStatement {
parent: input.parent,
span: input.span,
expression: Cell::new(expression),
})
}
fn reduce_iteration(
&mut self,
input: IterationStatement<'a>,
start: &'a Expression<'a>,
stop: &'a Expression<'a>,
body: &'a Statement<'a>,
) -> Statement<'a> {
Statement::Iteration(IterationStatement {
parent: input.parent,
span: input.span,
variable: input.variable,
start: Cell::new(start),
stop: Cell::new(stop),
inclusive: input.inclusive,
body: Cell::new(body),
})
}
fn reduce_return(&mut self, input: ReturnStatement<'a>, value: &'a Expression<'a>) -> Statement<'a> {
Statement::Return(ReturnStatement {
parent: input.parent,
span: input.span,
expression: Cell::new(value),
})
}
}
#[allow(unused_variables)]
pub trait ReconstructingReducerProgram<'a>: ReconstructingReducerStatement<'a> {
// todo @protryon: this is kind of hacky
fn reduce_function(&mut self, input: &'a Function<'a>, body: Option<&'a Statement<'a>>) -> &'a Function<'a> {
input.body.set(body);
input
}
fn reduce_circuit_member_variable(&mut self, input: CircuitMember<'a>) -> CircuitMember<'a> {
input
}
fn reduce_circuit_member_function(
&mut self,
input: CircuitMember<'a>,
function: &'a Function<'a>,
) -> CircuitMember<'a> {
CircuitMember::Function(function)
}
// todo @protryon: this is kind of hacky
fn reduce_circuit(&mut self, input: &'a Circuit<'a>, members: Vec<CircuitMember<'a>>) -> &'a Circuit<'a> {
let mut input_members = input.members.borrow_mut();
for ((name, input_member), member) in input_members.iter_mut().zip(members) {
*input_member = member;
}
input
}
fn reduce_global_const(
&mut self,
input: &'a DefinitionStatement<'a>,
value: &'a Expression<'a>,
) -> &'a DefinitionStatement<'a> {
input.value.set(value);
input
}
fn reduce_program(
&mut self,
input: Program<'a>,
imported_modules: Vec<(String, Program<'a>)>,
aliases: Vec<(String, &'a Alias<'a>)>,
functions: Vec<(String, &'a Function<'a>)>,
circuits: Vec<(String, &'a Circuit<'a>)>,
global_consts: Vec<(String, &'a DefinitionStatement<'a>)>,
) -> Program<'a> {
Program {
context: input.context,
id: input.id,
name: input.name,
imported_modules: imported_modules.into_iter().collect(),
aliases: aliases.into_iter().collect(),
functions: functions.into_iter().collect(),
circuits: circuits.into_iter().collect(),
scope: input.scope,
global_consts: global_consts.into_iter().collect(),
}
}
}

View File

@ -1,173 +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 std::cell::Cell;
use crate::{expression::*, program::*, statement::*};
pub enum VisitResult {
VisitChildren,
SkipChildren,
Exit,
}
impl Default for VisitResult {
fn default() -> Self {
VisitResult::VisitChildren
}
}
#[allow(unused_variables)]
pub trait ExpressionVisitor<'a> {
fn visit_expression(&mut self, input: &Cell<&'a Expression<'a>>) -> VisitResult {
Default::default()
}
fn visit_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_array_init(&mut self, input: &ArrayInitExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_binary(&mut self, input: &BinaryExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_call(&mut self, input: &CallExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_cast_expression(&mut self, input: &CastExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_constant(&mut self, input: &Constant<'a>) -> VisitResult {
Default::default()
}
fn visit_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_unary(&mut self, input: &UnaryExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_variable_ref(&mut self, input: &VariableRef<'a>) -> VisitResult {
Default::default()
}
}
#[allow(unused_variables)]
pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
fn visit_statement(&mut self, input: &Cell<&'a Statement<'a>>) -> VisitResult {
Default::default()
}
// left = Some(ArrayIndex.0) always if AssignAccess::ArrayIndex. if member/tuple, always None
fn visit_assign_access(&mut self, input: &AssignAccess<'a>) -> VisitResult {
Default::default()
}
fn visit_assign(&mut self, input: &AssignStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_block(&mut self, input: &BlockStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> VisitResult {
Default::default()
}
fn visit_console(&mut self, input: &ConsoleStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_definition(&mut self, input: &DefinitionStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_iteration(&mut self, input: &IterationStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_return(&mut self, input: &ReturnStatement<'a>) -> VisitResult {
Default::default()
}
}
#[allow(unused_variables)]
pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_function(&mut self, input: &'a Function<'a>) -> VisitResult {
Default::default()
}
fn visit_circuit_member(&mut self, input: &CircuitMember<'a>) -> VisitResult {
Default::default()
}
fn visit_circuit(&mut self, input: &'a Circuit<'a>) -> VisitResult {
Default::default()
}
fn visit_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> VisitResult {
Default::default()
}
fn visit_program(&mut self, input: &Program<'a>) -> VisitResult {
Default::default()
}
}

View File

@ -1,466 +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 super::*;
use crate::{expression::*, program::*, statement::*};
use std::{cell::Cell, marker::PhantomData};
pub struct VisitorDirector<'a, R: ExpressionVisitor<'a>> {
visitor: R,
lifetime: PhantomData<&'a ()>,
}
pub type ConcreteVisitResult = Result<(), ()>;
impl Into<ConcreteVisitResult> for VisitResult {
fn into(self) -> ConcreteVisitResult {
match self {
VisitResult::VisitChildren => Ok(()),
VisitResult::SkipChildren => Ok(()),
VisitResult::Exit => Err(()),
}
}
}
impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
pub fn new(visitor: R) -> Self {
Self {
visitor,
lifetime: PhantomData,
}
}
pub fn visitor(self) -> R {
self.visitor
}
pub fn visit_expression(&mut self, input: &Cell<&'a Expression<'a>>) -> ConcreteVisitResult {
match self.visitor.visit_expression(input) {
VisitResult::VisitChildren => match input.get() {
Expression::ArrayAccess(e) => self.visit_array_access(e),
Expression::ArrayInit(e) => self.visit_array_init(e),
Expression::ArrayInline(e) => self.visit_array_inline(e),
Expression::ArrayRangeAccess(e) => self.visit_array_range_access(e),
Expression::Binary(e) => self.visit_binary(e),
Expression::Call(e) => self.visit_call(e),
Expression::CircuitAccess(e) => self.visit_circuit_access(e),
Expression::CircuitInit(e) => self.visit_circuit_init(e),
Expression::Ternary(e) => self.visit_ternary_expression(e),
Expression::Cast(e) => self.visit_cast_expression(e),
Expression::LengthOf(e) => self.visit_lengthof_expression(e),
Expression::Constant(e) => self.visit_constant(e),
Expression::TupleAccess(e) => self.visit_tuple_access(e),
Expression::TupleInit(e) => self.visit_tuple_init(e),
Expression::Unary(e) => self.visit_unary(e),
Expression::VariableRef(e) => self.visit_variable_ref(e),
},
x => x.into(),
}
}
fn visit_opt_expression(&mut self, input: &Cell<Option<&'a Expression<'a>>>) -> ConcreteVisitResult {
let interior = input.get().map(Cell::new);
if let Some(interior) = interior.as_ref() {
let result = self.visit_expression(interior);
input.replace(Some(interior.get()));
result
} else {
Ok(())
}
}
pub fn visit_array_access(&mut self, input: &ArrayAccessExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_array_access(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.array)?;
self.visit_expression(&input.index)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_array_init(&mut self, input: &ArrayInitExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_array_init(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.element)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_array_inline(&mut self, input: &ArrayInlineExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_array_inline(input) {
VisitResult::VisitChildren => {
for (element, _) in input.elements.iter() {
self.visit_expression(element)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_array_range_access(&mut self, input: &ArrayRangeAccessExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_array_range_access(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.array)?;
self.visit_opt_expression(&input.left)?;
self.visit_opt_expression(&input.right)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_binary(&mut self, input: &BinaryExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_binary(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.left)?;
self.visit_expression(&input.right)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_call(&mut self, input: &CallExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_call(input) {
VisitResult::VisitChildren => {
self.visit_opt_expression(&input.target)?;
for argument in input.arguments.iter() {
self.visit_expression(argument)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_circuit_access(&mut self, input: &CircuitAccessExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_circuit_access(input) {
VisitResult::VisitChildren => {
self.visit_opt_expression(&input.target)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_circuit_init(&mut self, input: &CircuitInitExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_circuit_init(input) {
VisitResult::VisitChildren => {
for (_, argument) in input.values.iter() {
self.visit_expression(argument)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_ternary_expression(&mut self, input: &TernaryExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_ternary_expression(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.condition)?;
self.visit_expression(&input.if_true)?;
self.visit_expression(&input.if_false)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_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_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_lengthof_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()
}
pub fn visit_tuple_access(&mut self, input: &TupleAccessExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_tuple_access(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.tuple_ref)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_tuple_init(&mut self, input: &TupleInitExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_tuple_init(input) {
VisitResult::VisitChildren => {
for argument in input.elements.iter() {
self.visit_expression(argument)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_unary(&mut self, input: &UnaryExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_unary(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.inner)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_variable_ref(&mut self, input: &VariableRef<'a>) -> ConcreteVisitResult {
self.visitor.visit_variable_ref(input).into()
}
}
impl<'a, R: StatementVisitor<'a>> VisitorDirector<'a, R> {
pub fn visit_statement(&mut self, input: &Cell<&'a Statement<'a>>) -> ConcreteVisitResult {
match self.visitor.visit_statement(input) {
VisitResult::VisitChildren => match input.get() {
Statement::Assign(s) => self.visit_assign(s),
Statement::Block(s) => self.visit_block(s),
Statement::Conditional(s) => self.visit_conditional_statement(s),
Statement::Console(s) => self.visit_console(s),
Statement::Definition(s) => self.visit_definition(s),
Statement::Expression(s) => self.visit_expression_statement(s),
Statement::Iteration(s) => self.visit_iteration(s),
Statement::Return(s) => self.visit_return(s),
Statement::Empty(_) => Ok(()),
},
x => x.into(),
}
}
fn visit_opt_statement(&mut self, input: &Cell<Option<&'a Statement<'a>>>) -> ConcreteVisitResult {
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()));
result
} else {
Ok(())
}
}
pub fn visit_assign_access(&mut self, input: &AssignAccess<'a>) -> ConcreteVisitResult {
match self.visitor.visit_assign_access(input) {
VisitResult::VisitChildren => {
match input {
AssignAccess::ArrayRange(left, right) => {
self.visit_opt_expression(left)?;
self.visit_opt_expression(right)?;
}
AssignAccess::ArrayIndex(index) => self.visit_expression(index)?,
_ => (),
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_assign(&mut self, input: &AssignStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_assign(input) {
VisitResult::VisitChildren => {
for access in input.target_accesses.iter() {
self.visit_assign_access(access)?;
}
self.visit_expression(&input.value)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_block(&mut self, input: &BlockStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_block(input) {
VisitResult::VisitChildren => {
for statement in input.statements.iter() {
self.visit_statement(statement)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_conditional_statement(&mut self, input: &ConditionalStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_conditional_statement(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.condition)?;
self.visit_statement(&input.result)?;
self.visit_opt_statement(&input.next)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_formatted_string(&mut self, input: &ConsoleArgs<'a>) -> ConcreteVisitResult {
match self.visitor.visit_formatted_string(input) {
VisitResult::VisitChildren => {
for parameter in input.parameters.iter() {
self.visit_expression(parameter)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_console(&mut self, input: &ConsoleStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_console(input) {
VisitResult::VisitChildren => {
match &input.function {
ConsoleFunction::Assert(e) => self.visit_expression(e)?,
ConsoleFunction::Error(f) | ConsoleFunction::Log(f) => self.visit_formatted_string(f)?,
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_definition(&mut self, input: &DefinitionStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_definition(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.value)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_expression_statement(&mut self, input: &ExpressionStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_expression_statement(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.expression)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_iteration(&mut self, input: &IterationStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_iteration(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.start)?;
self.visit_expression(&input.stop)?;
self.visit_statement(&input.body)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_return(&mut self, input: &ReturnStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_return(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.expression)?;
Ok(())
}
x => x.into(),
}
}
}
impl<'a, R: ProgramVisitor<'a>> VisitorDirector<'a, R> {
pub fn visit_function(&mut self, input: &'a Function<'a>) -> ConcreteVisitResult {
match self.visitor.visit_function(input) {
VisitResult::VisitChildren => {
self.visit_opt_statement(&input.body)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_circuit_member(&mut self, input: &CircuitMember<'a>) -> ConcreteVisitResult {
match self.visitor.visit_circuit_member(input) {
VisitResult::VisitChildren => {
if let CircuitMember::Function(f) = input {
self.visit_function(f)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_circuit(&mut self, input: &'a Circuit<'a>) -> ConcreteVisitResult {
match self.visitor.visit_circuit(input) {
VisitResult::VisitChildren => {
for (_, member) in input.members.borrow().iter() {
self.visit_circuit_member(member)?;
}
Ok(())
}
x => x.into(),
}
}
pub fn visit_global_const(&mut self, input: &'a DefinitionStatement<'a>) -> ConcreteVisitResult {
match self.visitor.visit_global_const(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.value)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_program(&mut self, input: &Program<'a>) -> ConcreteVisitResult {
match self.visitor.visit_program(input) {
VisitResult::VisitChildren => {
for (_, import) in input.imported_modules.iter() {
self.visit_program(import)?;
}
for (_, function) in input.functions.iter() {
self.visit_function(function)?;
}
for (_, circuit) in input.circuits.iter() {
self.visit_circuit(circuit)?;
}
for (_, global_const) in input.global_consts.iter() {
self.visit_global_const(global_const)?;
}
Ok(())
}
x => x.into(),
}
}
}

View File

@ -1,235 +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::{Alias, AsgContext, Circuit, DefinitionStatement, Function, Input, Type, Variable};
use leo_errors::{AsgError, Result, Span};
use indexmap::IndexMap;
use std::cell::{Cell, RefCell};
/// An abstract data type that track the current bindings for variables, functions, and circuits.
#[derive(Clone)]
pub struct Scope<'a> {
pub context: AsgContext<'a>,
/// The unique id of the scope.
pub id: u32,
/// The parent scope that this scope inherits.
pub parent_scope: Cell<Option<&'a Scope<'a>>>,
/// The function definition that this scope occurs in.
pub function: Cell<Option<&'a Function<'a>>>,
/// Maps variable name => variable.
pub variables: RefCell<IndexMap<String, &'a Variable<'a>>>,
/// Maps alias name => alias.
pub aliases: RefCell<IndexMap<String, &'a Alias<'a>>>,
/// Maps function name => function.
pub functions: RefCell<IndexMap<String, &'a Function<'a>>>,
/// Maps global constant name => global const code block.
pub global_consts: RefCell<IndexMap<String, &'a DefinitionStatement<'a>>>,
/// Maps circuit name => circuit.
pub circuits: RefCell<IndexMap<String, &'a Circuit<'a>>>,
/// The main input to the program.
pub input: Cell<Option<Input<'a>>>,
}
#[allow(clippy::mut_from_ref)]
impl<'a> Scope<'a> {
///
/// Returns a reference to the variable corresponding to the name.
///
/// If the current scope did not have this name present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_variable(&self, name: &str) -> Option<&'a Variable<'a>> {
if let Some(resolved) = self.variables.borrow().get(name) {
Some(*resolved)
} else if let Some(scope) = self.parent_scope.get() {
scope.resolve_variable(name)
} else {
None
}
}
///
/// Returns a reference to the current function.
///
/// If the current scope did not have a function present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_current_function(&self) -> Option<&'a Function> {
if let Some(resolved) = self.function.get() {
Some(resolved)
} else if let Some(scope) = self.parent_scope.get() {
scope.resolve_current_function()
} else {
None
}
}
///
/// Returns a reference to the current input.
///
/// If the current scope did not have an input present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_input(&self) -> Option<Input<'a>> {
if let Some(input) = self.input.get() {
Some(input)
} else if let Some(resolved) = self.parent_scope.get() {
resolved.resolve_input()
} else {
None
}
}
///
/// Returns a reference to the alias corresponding to the name.
///
/// If the current scope did not have this name present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_alias(&self, name: &str) -> Option<&'a Alias<'a>> {
if let Some(resolved) = self.aliases.borrow().get(name) {
Some(*resolved)
} else if let Some(resolved) = self.parent_scope.get() {
resolved.resolve_alias(name)
} else {
None
}
}
///
/// Returns a reference to the function corresponding to the name.
///
/// If the current scope did not have this name present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_function(&self, name: &str) -> Option<&'a Function<'a>> {
if let Some(resolved) = self.functions.borrow().get(name) {
Some(*resolved)
} else if let Some(resolved) = self.parent_scope.get() {
resolved.resolve_function(name)
} else {
None
}
}
///
/// Returns a reference to the circuit corresponding to the name.
///
/// If the current scope did not have this name present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_circuit(&self, name: &str) -> Option<&'a Circuit<'a>> {
if let Some(resolved) = self.circuits.borrow().get(name) {
Some(*resolved)
} else if let Some(resolved) = self.parent_scope.get() {
resolved.resolve_circuit(name)
} else {
None
}
}
///
/// Returns a reference to the global const definition statement corresponding to the name.
///
/// If the current scope did not have this name present, then the parent scope is checked.
/// If there is no parent scope, then `None` is returned.
///
pub fn resolve_global_const(&self, name: &str) -> Option<&'a DefinitionStatement<'a>> {
if let Some(resolved) = self.global_consts.borrow().get(name) {
Some(*resolved)
} else if let Some(resolved) = self.parent_scope.get() {
resolved.resolve_global_const(name)
} else {
None
}
}
///
/// Returns a new scope given a parent scope.
///
pub fn make_subscope(self: &'a Scope<'a>) -> &'a Scope<'a> {
self.context.alloc_scope(Scope::<'a> {
context: self.context,
id: self.context.get_id(),
parent_scope: Cell::new(Some(self)),
variables: RefCell::new(IndexMap::new()),
aliases: RefCell::new(IndexMap::new()),
functions: RefCell::new(IndexMap::new()),
circuits: RefCell::new(IndexMap::new()),
global_consts: RefCell::new(IndexMap::new()),
function: Cell::new(None),
input: Cell::new(None),
})
}
///
/// Returns the type returned by the current scope.
///
pub fn resolve_ast_type(&self, type_: &leo_ast::Type, span: &Span) -> Result<Type<'a>> {
use leo_ast::Type::*;
Ok(match type_ {
Address => Type::Address,
Boolean => Type::Boolean,
Char => Type::Char,
Field => Type::Field,
Group => Type::Group,
IntegerType(int_type) => Type::Integer(int_type.clone()),
Array(sub_type, dimensions) => {
let mut item = Box::new(self.resolve_ast_type(&*sub_type, span)?);
if let Some(dimensions) = dimensions {
for dimension in dimensions.0.iter().rev() {
let dimension = dimension
.value
.parse::<usize>()
.map_err(|_| AsgError::parse_index_error(span))?;
item = Box::new(Type::Array(item, dimension));
}
} else {
item = Box::new(Type::ArrayWithoutSize(item));
}
*item
}
Tuple(sub_types) => Type::Tuple(
sub_types
.iter()
.map(|x| self.resolve_ast_type(x, span))
.collect::<Result<Vec<_>>>()?,
),
SelfType => return Err(AsgError::unexpected_big_self(span).into()),
Identifier(name) => {
if let Some(circuit) = self.resolve_circuit(&name.name) {
Type::Circuit(circuit)
} else if let Some(alias) = self.resolve_alias(&name.name) {
alias.represents.clone()
} else {
return Err(AsgError::unresolved_circuit(&name.name, &name.span).into());
}
}
})
}
}

View File

@ -1,246 +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::{
CircuitMember, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, Identifier, IntegerType, Node,
PartialType, Scope, Statement, Type, Variable,
};
pub use leo_ast::AssignOperation;
use leo_ast::AssigneeAccess as AstAssigneeAccess;
use leo_errors::{AsgError, Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub enum AssignAccess<'a> {
ArrayRange(Cell<Option<&'a Expression<'a>>>, Cell<Option<&'a Expression<'a>>>),
ArrayIndex(Cell<&'a Expression<'a>>),
Tuple(usize),
Member(Identifier),
}
#[derive(Clone)]
pub struct AssignStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub operation: AssignOperation,
pub target_variable: Cell<&'a Variable<'a>>,
pub target_accesses: Vec<AssignAccess<'a>>,
pub value: Cell<&'a Expression<'a>>,
}
impl<'a> Node for AssignStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::AssignStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let (name, span) = (
&statement.assignee.identifier.name.clone(),
&statement.assignee.identifier.span,
);
let variable = if name.as_ref() == "input" {
if let Some(input) = scope.resolve_input() {
input.container
} else {
return Err(AsgError::illegal_input_variable_reference(&statement.span).into());
}
} else {
scope
.resolve_variable(name)
.ok_or_else(|| AsgError::unresolved_reference(name, span))?
};
if !variable.borrow().mutable {
return Err(AsgError::immutable_assignment(name, &statement.span).into());
}
let mut target_type: Option<PartialType> = Some(variable.borrow().type_.clone().into());
let mut target_accesses = vec![];
for access in statement.assignee.accesses.iter() {
target_accesses.push(match access {
AstAssigneeAccess::ArrayRange(left, right) => {
let index_type = Some(PartialType::Integer(None, Some(IntegerType::U32)));
let left = left
.as_ref()
.map(|left: &leo_ast::Expression| -> Result<&'a Expression<'a>> {
<&Expression<'a>>::from_ast(scope, left, index_type.clone())
})
.transpose()?;
let right = right
.as_ref()
.map(|right: &leo_ast::Expression| -> Result<&'a Expression<'a>> {
<&Expression<'a>>::from_ast(scope, right, index_type)
})
.transpose()?;
match &target_type {
Some(PartialType::Array(item, len)) => {
if let (Some(left), Some(right)) = (
left.as_ref()
.map(|x| x.const_value())
.unwrap_or_else(|| Some(ConstValue::Int(ConstInt::U32(0)))),
right
.as_ref()
.map(|x| x.const_value())
.unwrap_or_else(|| Some(ConstValue::Int(ConstInt::U32(len.map(|x| x as u32)?)))),
) {
let left = match left {
ConstValue::Int(x) => x.to_usize().ok_or_else(|| {
AsgError::invalid_assign_index(name, x.to_string(), &statement.span)
})?,
_ => unimplemented!(),
};
let right = match right {
ConstValue::Int(x) => x.to_usize().ok_or_else(|| {
AsgError::invalid_assign_index(name, x.to_string(), &statement.span)
})?,
_ => unimplemented!(),
};
if right >= left {
target_type = Some(PartialType::Array(item.clone(), Some((right - left) as usize)))
} else {
return Err(AsgError::invalid_backwards_assignment(
name,
left,
right,
&statement.span,
)
.into());
}
}
}
_ => return Err(AsgError::index_into_non_array(name, &statement.span).into()),
}
AssignAccess::ArrayRange(Cell::new(left), Cell::new(right))
}
AstAssigneeAccess::ArrayIndex(index) => {
target_type = match target_type.clone() {
Some(PartialType::Array(item, _)) => item.map(|x| *x),
_ => return Err(AsgError::index_into_non_array(name, &statement.span).into()),
};
AssignAccess::ArrayIndex(Cell::new(<&Expression<'a>>::from_ast(
scope,
index,
Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?))
}
AstAssigneeAccess::Tuple(index, span) => {
let index = index
.value
.parse::<usize>()
.map_err(|_| AsgError::parse_index_error(span))?;
target_type = match target_type {
Some(PartialType::Tuple(types)) => types
.get(index)
.cloned()
.ok_or_else(|| AsgError::tuple_index_out_of_bounds(index, &statement.span))?,
_ => return Err(AsgError::index_into_non_tuple(name, &statement.span).into()),
};
AssignAccess::Tuple(index)
}
AstAssigneeAccess::Member(name) => {
target_type = match target_type {
Some(PartialType::Type(Type::Circuit(circuit))) => {
let circuit = circuit;
let members = circuit.members.borrow();
let member = members.get(name.name.as_ref()).ok_or_else(|| {
AsgError::unresolved_circuit_member(
&circuit.name.borrow().name,
&name.name,
&statement.span,
)
})?;
let x = match &member {
CircuitMember::Variable(type_) => type_.clone(),
CircuitMember::Function(_) => {
return Err(AsgError::illegal_function_assign(&name.name, &statement.span).into());
}
};
Some(x.partial())
}
_ => {
return Err(AsgError::index_into_non_tuple(
&statement.assignee.identifier.name,
&statement.span,
)
.into());
}
};
AssignAccess::Member(name.clone())
}
});
}
let value = <&Expression<'a>>::from_ast(scope, &statement.value, target_type)?;
let statement = scope.context.alloc_statement(Statement::Assign(AssignStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
operation: statement.operation,
target_variable: Cell::new(variable),
target_accesses,
value: Cell::new(value),
}));
{
let mut variable = variable.borrow_mut();
variable.assignments.push(statement);
}
Ok(statement)
}
}
impl<'a> Into<leo_ast::AssignStatement> for &AssignStatement<'a> {
fn into(self) -> leo_ast::AssignStatement {
leo_ast::AssignStatement {
operation: self.operation,
assignee: leo_ast::Assignee {
identifier: self.target_variable.get().borrow().name.clone(),
accesses: self
.target_accesses
.iter()
.map(|access| match access {
AssignAccess::ArrayRange(left, right) => {
AstAssigneeAccess::ArrayRange(left.get().map(|e| e.into()), right.get().map(|e| e.into()))
}
AssignAccess::ArrayIndex(index) => AstAssigneeAccess::ArrayIndex(index.get().into()),
AssignAccess::Tuple(index) => AstAssigneeAccess::Tuple(
leo_ast::PositiveNumber {
value: index.to_string().into(),
},
self.span.clone().unwrap_or_default(),
),
AssignAccess::Member(name) => AstAssigneeAccess::Member(name.clone()),
})
.collect(),
span: self.span.clone().unwrap_or_default(),
},
value: self.value.get().into(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,64 +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::{FromAst, Node, PartialType, Scope, Statement};
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct BlockStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub statements: Vec<Cell<&'a Statement<'a>>>,
pub scope: &'a Scope<'a>,
}
impl<'a> Node for BlockStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::Block> for BlockStatement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::Block,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let new_scope = scope.make_subscope();
let mut output = vec![];
for item in statement.statements.iter() {
output.push(Cell::new(<&'a Statement<'a>>::from_ast(new_scope, item, None)?));
}
Ok(BlockStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
statements: output,
scope: new_scope,
})
}
}
impl<'a> Into<leo_ast::Block> for &BlockStatement<'a> {
fn into(self) -> leo_ast::Block {
leo_ast::Block {
statements: self.statements.iter().map(|statement| statement.get().into()).collect(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,77 +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::{BlockStatement, Expression, FromAst, Node, PartialType, Scope, Statement, Type};
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ConditionalStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub condition: Cell<&'a Expression<'a>>,
pub result: Cell<&'a Statement<'a>>,
pub next: Cell<Option<&'a Statement<'a>>>,
}
impl<'a> Node for ConditionalStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::ConditionalStatement> for ConditionalStatement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::ConditionalStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let condition = <&Expression<'a>>::from_ast(scope, &statement.condition, Some(Type::Boolean.into()))?;
let result = scope.context.alloc_statement(Statement::Block(BlockStatement::from_ast(
scope,
&statement.block,
None,
)?));
let next = statement
.next
.as_deref()
.map(|next| -> Result<&'a Statement<'a>> { <&'a Statement<'a>>::from_ast(scope, next, None) })
.transpose()?;
Ok(ConditionalStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
condition: Cell::new(condition),
result: Cell::new(result),
next: Cell::new(next),
})
}
}
impl<'a> Into<leo_ast::ConditionalStatement> for &ConditionalStatement<'a> {
fn into(self) -> leo_ast::ConditionalStatement {
leo_ast::ConditionalStatement {
condition: self.condition.get().into(),
block: match self.result.get() {
Statement::Block(block) => block.into(),
_ => unimplemented!(),
},
next: self.next.get().map(|e| Box::new(e.into())),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,111 +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::{CharValue, Expression, FromAst, Node, PartialType, Scope, Statement, Type};
use leo_ast::ConsoleFunction as AstConsoleFunction;
use leo_errors::{Result, Span};
use std::cell::Cell;
// TODO (protryon): Refactor to not require/depend on span
#[derive(Clone)]
pub struct ConsoleArgs<'a> {
pub string: Vec<CharValue>,
pub parameters: Vec<Cell<&'a Expression<'a>>>,
pub span: Span,
}
#[derive(Clone)]
pub enum ConsoleFunction<'a> {
Assert(Cell<&'a Expression<'a>>),
Error(ConsoleArgs<'a>),
Log(ConsoleArgs<'a>),
}
#[derive(Clone)]
pub struct ConsoleStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub function: ConsoleFunction<'a>,
}
impl<'a> Node for ConsoleStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::ConsoleArgs> for ConsoleArgs<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::ConsoleArgs,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let mut parameters = vec![];
for parameter in value.parameters.iter() {
parameters.push(Cell::new(<&Expression<'a>>::from_ast(scope, parameter, None)?));
}
Ok(ConsoleArgs {
string: value.string.iter().map(CharValue::from).collect::<Vec<_>>(),
parameters,
span: value.span.clone(),
})
}
}
impl<'a> Into<leo_ast::ConsoleArgs> for &ConsoleArgs<'a> {
fn into(self) -> leo_ast::ConsoleArgs {
leo_ast::ConsoleArgs {
string: self.string.iter().map(|c| c.into()).collect::<Vec<_>>(),
parameters: self.parameters.iter().map(|e| e.get().into()).collect(),
span: self.span.clone(),
}
}
}
impl<'a> FromAst<'a, leo_ast::ConsoleStatement> for ConsoleStatement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::ConsoleStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
Ok(ConsoleStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
function: match &statement.function {
AstConsoleFunction::Assert(expression) => ConsoleFunction::Assert(Cell::new(
<&Expression<'a>>::from_ast(scope, expression, Some(Type::Boolean.into()))?,
)),
AstConsoleFunction::Error(args) => ConsoleFunction::Error(ConsoleArgs::from_ast(scope, args, None)?),
AstConsoleFunction::Log(args) => ConsoleFunction::Log(ConsoleArgs::from_ast(scope, args, None)?),
},
})
}
}
impl<'a> Into<leo_ast::ConsoleStatement> for &ConsoleStatement<'a> {
fn into(self) -> leo_ast::ConsoleStatement {
use ConsoleFunction::*;
leo_ast::ConsoleStatement {
function: match &self.function {
Assert(e) => AstConsoleFunction::Assert(e.get().into()),
Error(args) => AstConsoleFunction::Error(args.into()),
Log(args) => AstConsoleFunction::Log(args.into()),
},
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,191 +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::{Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Statement, Type, Variable};
use leo_errors::{AsgError, Result, Span};
use std::cell::{Cell, RefCell};
#[derive(Clone)]
pub struct DefinitionStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub variables: Vec<&'a Variable<'a>>,
pub value: Cell<&'a Expression<'a>>,
}
impl<'a> DefinitionStatement<'a> {
pub fn split(&self) -> Vec<(String, Self)> {
self.variables
.iter()
.map(|variable| {
(
variable.borrow().name.name.to_string(),
DefinitionStatement {
parent: self.parent.clone(),
span: self.span.clone(),
variables: vec![variable],
value: self.value.clone(),
},
)
})
.collect()
}
}
impl<'a> Node for DefinitionStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::DefinitionStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let type_ = statement
.type_
.as_ref()
.map(|x| scope.resolve_ast_type(x, &statement.span))
.transpose()?;
let value = <&Expression<'a>>::from_ast(scope, &statement.value, type_.clone().map(Into::into))?;
if matches!(statement.declaration_type, leo_ast::Declare::Const) && !value.is_consty() {
let var_names = statement
.variable_names
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>()
.join(" ,");
return Err(AsgError::invalid_const_assign(var_names, &statement.span).into());
}
let type_ = type_.or_else(|| value.get_type());
let mut output_types = vec![];
let mut variables = vec![];
if statement.variable_names.is_empty() {
return Err(AsgError::illegal_ast_structure(
"cannot have 0 variable names in destructuring tuple",
&statement.span,
)
.into());
}
if statement.variable_names.len() == 1 {
// any return type is fine
output_types.push(type_);
} else {
// tuple destructure
match type_.as_ref() {
Some(Type::Tuple(sub_types)) if sub_types.len() == statement.variable_names.len() => {
output_types.extend(sub_types.clone().into_iter().map(Some).collect::<Vec<_>>());
}
type_ => {
return Err(AsgError::unexpected_type(
format!("{}-ary tuple", statement.variable_names.len()),
type_.map(|x| x.to_string()).unwrap_or_else(|| "unknown".to_string()),
&statement.span,
)
.into());
}
}
}
for (variable, type_) in statement.variable_names.iter().zip(output_types.into_iter()) {
let name = variable.identifier.name.as_ref();
if scope.resolve_global_const(name).is_some() {
return Err(
AsgError::function_variable_cannot_shadow_global_const(name, &variable.identifier.span).into(),
);
} else if scope.resolve_variable(name).is_some() {
return Err(AsgError::function_variable_cannot_shadow_other_function_variable(
name,
&variable.identifier.span,
)
.into());
}
variables.push(&*scope.context.alloc_variable(RefCell::new(InnerVariable {
id: scope.context.get_id(),
name: variable.identifier.clone(),
type_: type_.ok_or_else(|| AsgError::unresolved_type(&variable.identifier.name, &statement.span))?,
mutable: variable.mutable,
const_: false,
declaration: crate::VariableDeclaration::Definition,
references: vec![],
assignments: vec![],
})));
}
for variable in variables.iter() {
let mut variables = scope.variables.borrow_mut();
let var_name = variable.borrow().name.name.to_string();
if variables.contains_key(&var_name) {
return Err(AsgError::duplicate_variable_definition(var_name, &statement.span).into());
}
variables.insert(var_name, *variable);
}
let statement = scope
.context
.alloc_statement(Statement::Definition(DefinitionStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
variables: variables.clone(),
value: Cell::new(value),
}));
for variable in variables {
variable.borrow_mut().assignments.push(statement);
}
Ok(statement)
}
}
impl<'a> Into<leo_ast::DefinitionStatement> for &DefinitionStatement<'a> {
fn into(self) -> leo_ast::DefinitionStatement {
assert!(!self.variables.is_empty());
let mut variable_names = vec![];
let mut type_ = None::<leo_ast::Type>;
for variable in self.variables.iter() {
let variable = variable.borrow();
variable_names.push(leo_ast::VariableName {
mutable: variable.mutable,
identifier: variable.name.clone(),
span: variable.name.span.clone(),
});
if type_.is_none() {
type_ = Some((&variable.type_.clone()).into());
}
}
leo_ast::DefinitionStatement {
declaration_type: leo_ast::Declare::Let,
variable_names,
type_,
value: self.value.get().into(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,58 +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::{Expression, FromAst, Node, PartialType, Scope, Statement};
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ExpressionStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub expression: Cell<&'a Expression<'a>>,
}
impl<'a> Node for ExpressionStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::ExpressionStatement> for ExpressionStatement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::ExpressionStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let expression = <&Expression<'a>>::from_ast(scope, &statement.expression, None)?;
Ok(ExpressionStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
expression: Cell::new(expression),
})
}
}
impl<'a> Into<leo_ast::ExpressionStatement> for &ExpressionStatement<'a> {
fn into(self) -> leo_ast::ExpressionStatement {
leo_ast::ExpressionStatement {
expression: self.expression.get().into(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,112 +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::IntegerType;
use crate::{Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Statement, Variable};
use leo_errors::{AsgError, Result, Span};
use std::cell::{Cell, RefCell};
#[derive(Clone)]
pub struct IterationStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub variable: &'a Variable<'a>,
pub start: Cell<&'a Expression<'a>>,
pub stop: Cell<&'a Expression<'a>>,
pub inclusive: bool,
pub body: Cell<&'a Statement<'a>>,
}
impl<'a> Node for IterationStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::IterationStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let expected_index_type = Some(PartialType::Integer(Some(IntegerType::U32), None));
let start = <&Expression<'a>>::from_ast(scope, &statement.start, expected_index_type.clone())?;
let stop = <&Expression<'a>>::from_ast(scope, &statement.stop, expected_index_type)?;
// Return an error if start or stop is not constant.
if !start.is_consty() {
return Err(AsgError::unexpected_nonconst(&start.span().cloned().unwrap_or_default()).into());
}
if !stop.is_consty() {
return Err(AsgError::unexpected_nonconst(&stop.span().cloned().unwrap_or_default()).into());
}
let variable = scope.context.alloc_variable(RefCell::new(InnerVariable {
id: scope.context.get_id(),
name: statement.variable.clone(),
type_: start
.get_type()
.ok_or_else(|| AsgError::unresolved_type(&statement.variable.name, &statement.span))?,
mutable: false,
const_: true,
declaration: crate::VariableDeclaration::IterationDefinition,
references: vec![],
assignments: vec![],
}));
scope
.variables
.borrow_mut()
.insert(statement.variable.name.to_string(), variable);
let statement = scope.context.alloc_statement(Statement::Iteration(IterationStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
variable,
stop: Cell::new(stop),
start: Cell::new(start),
inclusive: statement.inclusive,
body: Cell::new(
scope
.context
.alloc_statement(Statement::Block(crate::BlockStatement::from_ast(
scope,
&statement.block,
None,
)?)),
),
}));
variable.borrow_mut().assignments.push(statement);
Ok(statement)
}
}
impl<'a> Into<leo_ast::IterationStatement> for &IterationStatement<'a> {
fn into(self) -> leo_ast::IterationStatement {
leo_ast::IterationStatement {
variable: self.variable.borrow().name.clone(),
start: self.start.get().into(),
stop: self.stop.get().into(),
inclusive: self.inclusive,
block: match self.body.get() {
Statement::Block(block) => block.into(),
_ => unimplemented!(),
},
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,131 +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/>.
//! This module defines a statement node in an asg.
//!
//! Ast statement nodes can be directly converted into asg nodes with no major differences.
mod assign;
pub use assign::*;
mod block;
pub use block::*;
mod conditional;
pub use conditional::*;
mod console;
pub use console::*;
mod definition;
pub use definition::*;
mod expression;
pub use expression::*;
mod iteration;
pub use iteration::*;
mod return_;
pub use return_::*;
use crate::{FromAst, Node, PartialType, Scope};
use leo_errors::{Result, Span};
#[derive(Clone)]
pub enum Statement<'a> {
Return(ReturnStatement<'a>),
Definition(DefinitionStatement<'a>),
Assign(AssignStatement<'a>),
Conditional(ConditionalStatement<'a>),
Iteration(IterationStatement<'a>),
Console(ConsoleStatement<'a>),
Expression(ExpressionStatement<'a>),
Block(BlockStatement<'a>),
Empty(Option<Span>),
}
impl<'a> Node for Statement<'a> {
fn span(&self) -> Option<&Span> {
use Statement::*;
match self {
Return(s) => s.span(),
Definition(s) => s.span(),
Assign(s) => s.span(),
Conditional(s) => s.span(),
Iteration(s) => s.span(),
Console(s) => s.span(),
Expression(s) => s.span(),
Block(s) => s.span(),
Empty(s) => s.as_ref(),
}
}
}
impl<'a> FromAst<'a, leo_ast::Statement> for &'a Statement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::Statement,
_expected_type: Option<PartialType<'a>>,
) -> Result<&'a Statement<'a>> {
use leo_ast::Statement::*;
Ok(match value {
Return(statement) => scope
.context
.alloc_statement(Statement::Return(ReturnStatement::from_ast(scope, statement, None)?)),
Definition(statement) => Self::from_ast(scope, statement, None)?,
Assign(statement) => Self::from_ast(scope, &**statement, None)?,
Conditional(statement) => {
scope
.context
.alloc_statement(Statement::Conditional(ConditionalStatement::from_ast(
scope, statement, None,
)?))
}
Iteration(ref statement) => Self::from_ast(scope, &**statement, None)?,
Console(statement) => scope
.context
.alloc_statement(Statement::Console(ConsoleStatement::from_ast(scope, statement, None)?)),
Expression(statement) => {
scope
.context
.alloc_statement(Statement::Expression(ExpressionStatement::from_ast(
scope, statement, None,
)?))
}
Block(statement) => scope
.context
.alloc_statement(Statement::Block(BlockStatement::from_ast(scope, statement, None)?)),
})
}
}
impl<'a> Into<leo_ast::Statement> for &Statement<'a> {
fn into(self) -> leo_ast::Statement {
use Statement::*;
match self {
Return(statement) => leo_ast::Statement::Return(statement.into()),
Definition(statement) => leo_ast::Statement::Definition(statement.into()),
Assign(statement) => leo_ast::Statement::Assign(Box::new(statement.into())),
Conditional(statement) => leo_ast::Statement::Conditional(statement.into()),
Iteration(statement) => leo_ast::Statement::Iteration(Box::new(statement.into())),
Console(statement) => leo_ast::Statement::Console(statement.into()),
Expression(statement) => leo_ast::Statement::Expression(statement.into()),
Block(statement) => leo_ast::Statement::Block(statement.into()),
Empty(_) => unimplemented!(),
}
}
}

View File

@ -1,63 +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::{Expression, FromAst, Node, PartialType, Scope, Statement, Type};
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct ReturnStatement<'a> {
pub parent: Cell<Option<&'a Statement<'a>>>,
pub span: Option<Span>,
pub expression: Cell<&'a Expression<'a>>,
}
impl<'a> Node for ReturnStatement<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> FromAst<'a, leo_ast::ReturnStatement> for ReturnStatement<'a> {
fn from_ast(
scope: &'a Scope<'a>,
statement: &leo_ast::ReturnStatement,
_expected_type: Option<PartialType<'a>>,
) -> Result<Self> {
let return_type: Option<Type> = scope
.resolve_current_function()
.map(|x| x.output.clone())
.map(Into::into);
Ok(ReturnStatement {
parent: Cell::new(None),
span: Some(statement.span.clone()),
expression: Cell::new(<&Expression<'a>>::from_ast(
scope,
&statement.expression,
return_type.map(Into::into),
)?),
})
}
}
impl<'a> Into<leo_ast::ReturnStatement> for &ReturnStatement<'a> {
fn into(self) -> leo_ast::ReturnStatement {
leo_ast::ReturnStatement {
expression: self.expression.get().into(),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -1,233 +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::Circuit;
pub use leo_ast::IntegerType;
use std::fmt;
/// A type in an asg.
#[derive(Clone, PartialEq)]
pub enum Type<'a> {
// Data types
Address,
Boolean,
Char,
Field,
Group,
Integer(IntegerType),
// Data type wrappers
Array(Box<Type<'a>>, usize),
ArrayWithoutSize(Box<Type<'a>>),
Tuple(Vec<Type<'a>>),
Circuit(&'a Circuit<'a>),
}
#[derive(Clone, PartialEq)]
pub enum PartialType<'a> {
Type(Type<'a>), // non-array or tuple
Integer(Option<IntegerType>, Option<IntegerType>), // specific, context-specific
Array(Option<Box<PartialType<'a>>>, Option<usize>),
Tuple(Vec<Option<PartialType<'a>>>),
}
impl<'a> Into<Option<Type<'a>>> for PartialType<'a> {
fn into(self) -> Option<Type<'a>> {
match self {
PartialType::Type(t) => Some(t),
PartialType::Integer(sub_type, contextual_type) => Some(Type::Integer(sub_type.or(contextual_type)?)),
PartialType::Array(element, len) => Some(Type::Array(Box::new((*element?).full()?), len?)),
PartialType::Tuple(sub_types) => Some(Type::Tuple(
sub_types
.into_iter()
.map(|x| x.map(|x| x.full()).flatten())
.collect::<Option<Vec<Type>>>()?,
)),
}
}
}
impl<'a> PartialType<'a> {
pub fn full(self) -> Option<Type<'a>> {
self.into()
}
pub fn matches(&self, other: &Type<'a>) -> bool {
match (self, other) {
(PartialType::Type(t), other) => t.is_assignable_from(other),
(PartialType::Integer(self_sub_type, _), Type::Integer(sub_type)) => {
self_sub_type.as_ref().map(|x| x == sub_type).unwrap_or(true)
}
(PartialType::Array(element, _len), Type::ArrayWithoutSize(other_element)) => {
if let Some(element) = element {
if !element.matches(&*other_element) {
return false;
}
}
true
}
(PartialType::Array(element, len), Type::Array(other_element, other_len)) => {
if let Some(element) = element {
if !element.matches(&*other_element) {
return false;
}
}
if let Some(len) = len {
return len == other_len;
}
true
}
(PartialType::Tuple(sub_types), Type::Tuple(other_sub_types)) => {
// we dont enforce exact length for tuples here (relying on prior type checking) to allow for full-context-free tuple indexing
if sub_types.len() > other_sub_types.len() {
return false;
}
for (sub_type, other_sub_type) in sub_types.iter().zip(other_sub_types.iter()) {
if let Some(sub_type) = sub_type {
if !sub_type.matches(other_sub_type) {
return false;
}
}
}
true
}
_ => false,
}
}
}
impl<'a> Into<PartialType<'a>> for Type<'a> {
fn into(self) -> PartialType<'a> {
match self {
Type::Integer(sub_type) => PartialType::Integer(Some(sub_type), None),
Type::Array(element, len) => PartialType::Array(Some(Box::new((*element).into())), Some(len)),
Type::Tuple(sub_types) => PartialType::Tuple(sub_types.into_iter().map(Into::into).map(Some).collect()),
x => PartialType::Type(x),
}
}
}
impl<'a> Type<'a> {
pub fn is_assignable_from(&self, from: &Type<'a>) -> bool {
match (self, from) {
(Type::Array(_, _), Type::ArrayWithoutSize(_)) => true,
(Type::ArrayWithoutSize(_), Type::Array(_, _)) => true,
_ => self == from,
}
}
pub fn partial(self) -> PartialType<'a> {
self.into()
}
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> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::Address => write!(f, "address"),
Type::Boolean => write!(f, "bool"),
Type::Char => write!(f, "char"),
Type::Field => write!(f, "field"),
Type::Group => write!(f, "group"),
Type::Integer(sub_type) => sub_type.fmt(f),
Type::Array(sub_type, len) => write!(f, "[{}; {}]", sub_type, len),
Type::ArrayWithoutSize(sub_type) => write!(f, "[{}; _]", sub_type),
Type::Tuple(sub_types) => {
write!(f, "(")?;
for (i, sub_type) in sub_types.iter().enumerate() {
write!(f, "{}", sub_type)?;
if i < sub_types.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
Type::Circuit(circuit) => write!(f, "{}", &circuit.name.borrow().name),
}
}
}
impl<'a> fmt::Display for PartialType<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PartialType::Type(t) => t.fmt(f),
PartialType::Integer(Some(sub_type), _) => write!(f, "{}", sub_type),
PartialType::Integer(_, Some(sub_type)) => write!(f, "<{}>", sub_type),
PartialType::Integer(_, _) => write!(f, "integer"),
PartialType::Array(sub_type, len) => {
write!(f, "[")?;
if let Some(sub_type) = sub_type {
write!(f, "{}", *sub_type)?;
} else {
write!(f, "?")?;
}
write!(f, "; ")?;
if let Some(len) = len {
write!(f, "{}", len)?;
} else {
write!(f, "?")?;
}
write!(f, "]")
}
PartialType::Tuple(sub_types) => {
write!(f, "(")?;
for (i, sub_type) in sub_types.iter().enumerate() {
if let Some(sub_type) = sub_type {
write!(f, "{}", *sub_type)?;
} else {
write!(f, "?")?;
}
if i < sub_types.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
}
}
impl<'a> Into<leo_ast::Type> for &Type<'a> {
fn into(self) -> leo_ast::Type {
use Type::*;
match self {
Address => leo_ast::Type::Address,
Boolean => leo_ast::Type::Boolean,
Char => leo_ast::Type::Char,
Field => leo_ast::Type::Field,
Group => leo_ast::Type::Group,
Integer(int_type) => leo_ast::Type::IntegerType(int_type.clone()),
Array(type_, len) => leo_ast::Type::Array(
Box::new(type_.as_ref().into()),
Some(leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber {
value: len.to_string().into(),
}])),
),
ArrayWithoutSize(type_) => leo_ast::Type::Array(Box::new(type_.as_ref().into()), None),
Tuple(subtypes) => leo_ast::Type::Tuple(subtypes.iter().map(Into::into).collect()),
Circuit(circuit) => leo_ast::Type::Identifier(circuit.name.borrow().clone()),
}
}
}

View File

@ -1,44 +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 std::cell::RefCell;
use crate::{Expression, Statement, Type};
use leo_ast::Identifier;
/// Specifies how a program variable was declared.
#[derive(Clone, Copy, PartialEq)]
pub enum VariableDeclaration {
Definition,
IterationDefinition,
Parameter,
Input,
}
/// Stores information on a program variable.
#[derive(Clone)]
pub struct InnerVariable<'a> {
pub id: u32,
pub name: Identifier,
pub type_: Type<'a>,
pub mutable: bool,
pub const_: bool, // only function arguments, const var definitions NOT included
pub declaration: VariableDeclaration,
pub references: Vec<&'a Expression<'a>>, // all Expression::VariableRef or panic
pub assignments: Vec<&'a Statement<'a>>, // all Statement::Assign or panic -- must be 1 if not mutable, or 0 if declaration == input | parameter
}
pub type Variable<'a> = RefCell<InnerVariable<'a>>;

View File

@ -1,3 +0,0 @@
function main() {
const public_key_string: address = zleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
}

View File

@ -1,23 +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::load_asg;
#[test]
fn test_implicit_invalid() {
let program_string = include_str!("implicit_invalid.leo");
load_asg(program_string).err().unwrap();
}

View File

@ -1,3 +0,0 @@
function main(a: [u8; 3]) {
console.assert(a == [1u8; -3]);
}

View File

@ -1,3 +0,0 @@
function main(a: [u8; (3, 2)]) {
console.assert(a == [[0u8; 2]; 3)]); // This should be written the right way as this test is for the input file.
}

View File

@ -1,3 +0,0 @@
function main(a: [u8; (3, 2)]) {
console.assert(a == [0u8; (2, 3)]);
}

View File

@ -1,135 +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::load_asg;
// Expressions
#[test]
fn test_initializer_fail() {
let program_string = include_str!("initializer_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_input_nested_3x2_fail() {
let program_string = include_str!("input_nested_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_input_tuple_3x2_fail() {
let program_string = include_str!("input_tuple_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_multi_fail_initializer() {
let program_string = include_str!("multi_fail_initializer.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_multi_inline_fail() {
let program_string = include_str!("multi_fail_inline.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_multi_initializer_fail() {
let program_string = include_str!("multi_initializer_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_nested_3x2_value_fail() {
let program_string = include_str!("nested_3x2_value_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_tuple_3x2_value_fail() {
let program_string = include_str!("tuple_3x2_value_fail.leo");
load_asg(program_string).err().unwrap();
}
// Array type tests
#[test]
fn test_type_fail() {
let program_string = include_str!("type_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_nested_value_nested_3x2_fail() {
let program_string = include_str!("type_nested_value_nested_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_nested_value_nested_4x3x2_fail() {
let program_string = include_str!("type_nested_value_nested_4x3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_nested_value_tuple_3x2_fail() {
let program_string = include_str!("type_nested_value_tuple_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_nested_value_tuple_4x3x2_fail() {
let program_string = include_str!("type_nested_value_tuple_4x3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_nested_3x2_fail() {
let program_string = include_str!("type_tuple_value_nested_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_nested_3x2_swap_fail() {
let program_string = include_str!("type_tuple_value_nested_3x2_swap_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_nested_4x3x2_fail() {
let program_string = include_str!("type_tuple_value_nested_4x3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_tuple_3x2_fail() {
let program_string = include_str!("type_tuple_value_tuple_3x2_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_tuple_3x2_swap_fail() {
let program_string = include_str!("type_tuple_value_tuple_3x2_swap_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_type_tuple_value_tuple_4x3x2_fail() {
let program_string = include_str!("type_tuple_value_tuple_4x3x2_fail.leo");
load_asg(program_string).err().unwrap();
}

View File

@ -1,3 +0,0 @@
function main() {
const arr: [u8; (2, 2)] = [[1u8; 2]; 1]; // incorrect dimensions
}

View File

@ -1,4 +0,0 @@
function main() {
const arr: [u8; (2, 2)] = [[1u8, 1u8],
[1u8]]; // incorrect dimensions
}

View File

@ -1,3 +0,0 @@
function main() {
const arr: [u8; (2, 2)] = [1u8; (2, 1)]; // incorrect dimensions
}

View File

@ -1,4 +0,0 @@
// Multidimensional array syntax in leo
function main() {
const a: [u32; (3, 2)] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,4 +0,0 @@
// Multidimensional array syntax in leo
function main() {
const a: [u32; (3, 2)] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const a: [u8; -2] = [0u32; 2];
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [[u8; 2]; 3] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [[[u8; 2]; 3]; 4] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [[u8; 2]; 3] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [[[u8; 2]; 3]; 4] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [u8; (2, 3)] = [[0; 2]; 3]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,7 +0,0 @@
function main() {
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
const b: [u8; (2, 3)] = [[0; 3]; 2]; // initializer
console.assert(a == b);
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [u8; (4, 3, 2)] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [u8; (2, 3)] = [0; (3, 2)]; // initializer (incorrectly reversed ordering)
}

View File

@ -1,7 +0,0 @@
function main() {
const a = [[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]; // inline
const b: [u8; (2, 3)] = [0; (2, 3)]; // initializer
console.assert(a == b);
}

View File

@ -1,3 +0,0 @@
function main() {
const b: [u8; (4, 3, 2)] = [0; (2, 3, 4)]; // initializer (incorrectly reversed order)
}

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::load_asg;
#[test]
fn test_not_u32() {
let program_string = include_str!("not_u32.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_true_or_u32() {
let program_string = include_str!("true_or_u32.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_true_and_u32() {
let program_string = include_str!("true_and_u32.leo");
load_asg(program_string).err().unwrap();
}

View File

@ -1,3 +0,0 @@
function main() -> bool {
console.assert(!1u32 == 0u32);
}

View File

@ -1,3 +0,0 @@
function main() {
const a = true && 1u32;
}

View File

@ -1,3 +0,0 @@
function main() {
const a = true || 1u32;
}

View File

@ -1,7 +0,0 @@
circuit Foo {
x: u32;
}
function main() {
const a = Foo { y: 0u32 };
}

View File

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

View File

@ -1,10 +0,0 @@
circuit Foo {
function echo(x: u32) -> u32 {
return x;
}
}
function main() {
const a = Foo { };
const err = a.echoed(1u32);
}

View File

@ -1,10 +0,0 @@
circuit Foo {
function echo(x: u32) -> u32 {
return x;
}
}
function main() {
const a = Foo { };
const err = a.echo(1u32); // echo is a static function and must be accessed using `::`
}

View File

@ -1,9 +0,0 @@
circuit Foo {
function echo(x: u32) -> u32 {
return x;
}
}
function main() {
const err = Foo.echo(1u32); // Invalid, echo is a static function and must be accessed using `::`
}

View File

@ -1,9 +0,0 @@
circuit Foo {
function echo(x: u32) -> u32 {
return x;
}
}
function main() {
const err = Foo::echoed(1u32);
}

View File

@ -1,9 +0,0 @@
circuit Foo {
x: u32;
}
function main() {
const a = Foo { x: 1u32 };
const err = a.y;
}

View File

@ -1,138 +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::load_asg;
// Expressions
#[test]
fn test_inline_fail() {
let program_string = include_str!("inline_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_inline_undefined() {
let program_string = include_str!("inline_undefined.leo");
load_asg(program_string).err().unwrap();
}
// Members
#[test]
fn test_member_variable_fail() {
let program_string = include_str!("member_variable_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_member_function_fail() {
let program_string = include_str!("member_function_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_member_function_invalid() {
let program_string = include_str!("member_function_invalid.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mut_member_function_fail() {
let program_string = r#"
circuit Foo {
function echo(mut self, x: u32) -> u32 {
return x;
}
}
function main() {
const a = Foo { };
console.assert(a.echo(1u32) == 1u32);
}"#;
load_asg(program_string).err().unwrap();
}
#[test]
fn test_member_static_function_invalid() {
let program_string = include_str!("member_static_function_invalid.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_member_static_function_undefined() {
let program_string = include_str!("member_static_function_undefined.leo");
load_asg(program_string).err().unwrap();
}
// Mutability
#[test]
fn test_mutate_function_fail() {
let program_string = include_str!("mut_function_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mutate_self_variable_fail() {
let program_string = include_str!("mut_self_variable_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mutate_self_function_fail() {
let program_string = include_str!("mut_self_function_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mutate_self_static_function_fail() {
let program_string = include_str!("mut_self_static_function_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mutate_static_function_fail() {
let program_string = include_str!("mut_static_function_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_mutate_variable_fail() {
let program_string = include_str!("mut_variable_fail.leo");
load_asg(program_string).err().unwrap();
}
// Self
#[test]
fn test_self_fail() {
let program_string = include_str!("self_fail.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_self_member_invalid() {
let program_string = include_str!("self_member_invalid.leo");
load_asg(program_string).err().unwrap();
}
#[test]
fn test_self_member_undefined() {
let program_string = include_str!("self_member_undefined.leo");
load_asg(program_string).err().unwrap();
}

View File

@ -1,11 +0,0 @@
circuit Foo {
a: u8;
function bar() {}
}
function main() {
let f = Foo { a: 0u8 };
f.bar = 1u8;
}

View File

@ -1,15 +0,0 @@
circuit Foo {
a: u8;
function bar() {}
function set_a(mut self, new: u8) {
self.bar = new;
}
}
function main() {
let f = Foo { a: 0u8 };
f.set_a(1u8);
}

View File

@ -1,15 +0,0 @@
circuit Foo {
a: u8;
function bar() {}
function set_a(mut self, new: u8) {
self.bar = new;
}
}
function main() {
let f = Foo { a: 0u8 };
f.set_a(1u8);
}

View File

@ -1,13 +0,0 @@
circuit Foo {
a: u8;
function set_a(self, new: u8) {
self.a = new;
}
}
function main() {
let f = Foo { a: 0u8 };
f.set_a(1u8);
}

View File

@ -1,9 +0,0 @@
circuit Foo {
function bar() {}
}
function main() {
let f = Foo { a: 0u8 };
f.bar = 1u8;
}

View File

@ -1,9 +0,0 @@
circuit Foo {
a: u8;
}
function main() {
const f = Foo { a: 0u8 };
f.a = 1u8;
}

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