mirror of
https://github.com/AleoHQ/leo.git
synced 2024-09-22 12:39:52 +03:00
merge master
This commit is contained in:
commit
ab32aeb342
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -52,9 +52,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.38"
|
version = "1.0.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
|
checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
@ -2354,9 +2354,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.124"
|
version = "1.0.125"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
|
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@ -2373,9 +2373,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.124"
|
version = "1.0.125"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
|
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
@ -3103,9 +3103,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.1"
|
version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
|
@ -31,7 +31,7 @@ impl<'a, 'b> ExpressionVisitor<'a> for ConstantFolding<'a, 'b> {
|
|||||||
span: expr.span().cloned(),
|
span: expr.span().cloned(),
|
||||||
value: const_value,
|
value: const_value,
|
||||||
});
|
});
|
||||||
let folded_expr = self.program.scope.alloc_expression(folded_expr);
|
let folded_expr = self.program.context.alloc_expression(folded_expr);
|
||||||
input.set(folded_expr);
|
input.set(folded_expr);
|
||||||
VisitResult::SkipChildren
|
VisitResult::SkipChildren
|
||||||
} else {
|
} else {
|
||||||
@ -45,10 +45,10 @@ impl<'a, 'b> StatementVisitor<'a> for ConstantFolding<'a, 'b> {}
|
|||||||
impl<'a, 'b> ProgramVisitor<'a> for ConstantFolding<'a, 'b> {}
|
impl<'a, 'b> ProgramVisitor<'a> for ConstantFolding<'a, 'b> {}
|
||||||
|
|
||||||
impl<'a, 'b> AsgPass<'a> for ConstantFolding<'a, 'b> {
|
impl<'a, 'b> AsgPass<'a> for ConstantFolding<'a, 'b> {
|
||||||
fn do_pass(asg: &Program<'a>) -> Result<(), FormattedError> {
|
fn do_pass(asg: Program<'a>) -> Result<Program<'a>, FormattedError> {
|
||||||
let pass = ConstantFolding { program: asg };
|
let pass = ConstantFolding { program: &asg };
|
||||||
let mut director = VisitorDirector::new(pass);
|
let mut director = VisitorDirector::new(pass);
|
||||||
director.visit_program(asg).ok();
|
director.visit_program(&asg).ok();
|
||||||
Ok(())
|
Ok(asg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
73
asg-passes/src/dead_code_elimination/mod.rs
Normal file
73
asg-passes/src/dead_code_elimination/mod.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// 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::*;
|
||||||
|
|
||||||
|
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>, FormattedError> {
|
||||||
|
let pass = DeadCodeElimination {};
|
||||||
|
let mut director = ReconstructingDirector::new(asg.context, pass);
|
||||||
|
Ok(director.reduce_program(asg))
|
||||||
|
}
|
||||||
|
}
|
@ -16,3 +16,6 @@
|
|||||||
|
|
||||||
pub mod constant_folding;
|
pub mod constant_folding;
|
||||||
pub use constant_folding::*;
|
pub use constant_folding::*;
|
||||||
|
|
||||||
|
pub mod dead_code_elimination;
|
||||||
|
pub use dead_code_elimination::*;
|
||||||
|
@ -91,6 +91,16 @@ pub enum GroupValue {
|
|||||||
Tuple(GroupCoordinate, GroupCoordinate),
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ConstValue {
|
pub enum ConstValue {
|
||||||
Int(ConstInt),
|
Int(ConstInt),
|
||||||
|
@ -18,7 +18,7 @@ use std::{cell::Cell, unimplemented};
|
|||||||
|
|
||||||
use typed_arena::Arena;
|
use typed_arena::Arena;
|
||||||
|
|
||||||
use crate::ArenaNode;
|
use crate::{ArenaNode, Circuit, Expression, Function, Scope, Statement, Variable};
|
||||||
|
|
||||||
pub struct AsgContextInner<'a> {
|
pub struct AsgContextInner<'a> {
|
||||||
pub arena: &'a Arena<ArenaNode<'a>>,
|
pub arena: &'a Arena<ArenaNode<'a>>,
|
||||||
@ -41,6 +41,54 @@ impl<'a> AsgContextInner<'a> {
|
|||||||
self.next_id.replace(next_id + 1);
|
self.next_id.replace(next_id + 1);
|
||||||
next_id
|
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(scope)) {
|
||||||
|
ArenaNode::Scope(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>;
|
pub type AsgContext<'a> = &'a AsgContextInner<'a>;
|
||||||
|
@ -143,7 +143,7 @@ impl<'a> FromAst<'a, leo_ast::ArrayInitExpression> for ArrayInitExpression<'a> {
|
|||||||
element: Cell::new(
|
element: Cell::new(
|
||||||
output
|
output
|
||||||
.map(Expression::ArrayInit)
|
.map(Expression::ArrayInit)
|
||||||
.map(|expr| &*scope.alloc_expression(expr))
|
.map(|expr| &*scope.context.alloc_expression(expr))
|
||||||
.unwrap_or_else(|| element.take().unwrap()),
|
.unwrap_or_else(|| element.take().unwrap()),
|
||||||
),
|
),
|
||||||
len: dimension,
|
len: dimension,
|
||||||
|
@ -90,6 +90,12 @@ pub enum Expression<'a> {
|
|||||||
Call(CallExpression<'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> {
|
impl<'a> Node for Expression<'a> {
|
||||||
fn span(&self) -> Option<&Span> {
|
fn span(&self) -> Option<&Span> {
|
||||||
use Expression::*;
|
use Expression::*;
|
||||||
@ -283,63 +289,63 @@ impl<'a> FromAst<'a, leo_ast::Expression> for &'a Expression<'a> {
|
|||||||
use leo_ast::Expression::*;
|
use leo_ast::Expression::*;
|
||||||
let expression = match value {
|
let expression = match value {
|
||||||
Identifier(identifier) => Self::from_ast(scope, identifier, expected_type, circuit_name)?,
|
Identifier(identifier) => Self::from_ast(scope, identifier, expected_type, circuit_name)?,
|
||||||
Value(value) => scope.alloc_expression(
|
Value(value) => scope.context.alloc_expression(
|
||||||
Constant::from_ast(scope, value, expected_type, circuit_name).map(Expression::Constant)?,
|
Constant::from_ast(scope, value, expected_type, circuit_name).map(Expression::Constant)?,
|
||||||
),
|
),
|
||||||
Binary(binary) => scope.alloc_expression(
|
Binary(binary) => scope.context.alloc_expression(
|
||||||
BinaryExpression::from_ast(scope, binary, expected_type, circuit_name).map(Expression::Binary)?,
|
BinaryExpression::from_ast(scope, binary, expected_type, circuit_name).map(Expression::Binary)?,
|
||||||
),
|
),
|
||||||
Unary(unary) => scope.alloc_expression(
|
Unary(unary) => scope.context.alloc_expression(
|
||||||
UnaryExpression::from_ast(scope, unary, expected_type, circuit_name).map(Expression::Unary)?,
|
UnaryExpression::from_ast(scope, unary, expected_type, circuit_name).map(Expression::Unary)?,
|
||||||
),
|
),
|
||||||
Ternary(conditional) => scope.alloc_expression(
|
Ternary(conditional) => scope.context.alloc_expression(
|
||||||
TernaryExpression::from_ast(scope, conditional, expected_type, circuit_name)
|
TernaryExpression::from_ast(scope, conditional, expected_type, circuit_name)
|
||||||
.map(Expression::Ternary)?,
|
.map(Expression::Ternary)?,
|
||||||
),
|
),
|
||||||
Cast(cast) => scope.alloc_expression(
|
Cast(cast) => scope.context.alloc_expression(
|
||||||
CastExpression::from_ast(scope, cast, expected_type, circuit_name).map(Expression::Cast)?,
|
CastExpression::from_ast(scope, cast, expected_type, circuit_name).map(Expression::Cast)?,
|
||||||
),
|
),
|
||||||
|
|
||||||
ArrayInline(array_inline) => scope.alloc_expression(
|
ArrayInline(array_inline) => scope.context.alloc_expression(
|
||||||
ArrayInlineExpression::from_ast(scope, array_inline, expected_type, circuit_name)
|
ArrayInlineExpression::from_ast(scope, array_inline, expected_type, circuit_name)
|
||||||
.map(Expression::ArrayInline)?,
|
.map(Expression::ArrayInline)?,
|
||||||
),
|
),
|
||||||
ArrayInit(array_init) => scope.alloc_expression(
|
ArrayInit(array_init) => scope.context.alloc_expression(
|
||||||
ArrayInitExpression::from_ast(scope, array_init, expected_type, circuit_name)
|
ArrayInitExpression::from_ast(scope, array_init, expected_type, circuit_name)
|
||||||
.map(Expression::ArrayInit)?,
|
.map(Expression::ArrayInit)?,
|
||||||
),
|
),
|
||||||
ArrayAccess(array_access) => scope.alloc_expression(
|
ArrayAccess(array_access) => scope.context.alloc_expression(
|
||||||
ArrayAccessExpression::from_ast(scope, array_access, expected_type, circuit_name)
|
ArrayAccessExpression::from_ast(scope, array_access, expected_type, circuit_name)
|
||||||
.map(Expression::ArrayAccess)?,
|
.map(Expression::ArrayAccess)?,
|
||||||
),
|
),
|
||||||
ArrayRangeAccess(array_range_access) => scope.alloc_expression(
|
ArrayRangeAccess(array_range_access) => scope.context.alloc_expression(
|
||||||
ArrayRangeAccessExpression::from_ast(scope, array_range_access, expected_type, circuit_name)
|
ArrayRangeAccessExpression::from_ast(scope, array_range_access, expected_type, circuit_name)
|
||||||
.map(Expression::ArrayRangeAccess)?,
|
.map(Expression::ArrayRangeAccess)?,
|
||||||
),
|
),
|
||||||
|
|
||||||
TupleInit(tuple_init) => scope.alloc_expression(
|
TupleInit(tuple_init) => scope.context.alloc_expression(
|
||||||
TupleInitExpression::from_ast(scope, tuple_init, expected_type, circuit_name)
|
TupleInitExpression::from_ast(scope, tuple_init, expected_type, circuit_name)
|
||||||
.map(Expression::TupleInit)?,
|
.map(Expression::TupleInit)?,
|
||||||
),
|
),
|
||||||
TupleAccess(tuple_access) => scope.alloc_expression(
|
TupleAccess(tuple_access) => scope.context.alloc_expression(
|
||||||
TupleAccessExpression::from_ast(scope, tuple_access, expected_type, circuit_name)
|
TupleAccessExpression::from_ast(scope, tuple_access, expected_type, circuit_name)
|
||||||
.map(Expression::TupleAccess)?,
|
.map(Expression::TupleAccess)?,
|
||||||
),
|
),
|
||||||
|
|
||||||
CircuitInit(circuit_init) => scope.alloc_expression(
|
CircuitInit(circuit_init) => scope.context.alloc_expression(
|
||||||
CircuitInitExpression::from_ast(scope, circuit_init, expected_type, circuit_name)
|
CircuitInitExpression::from_ast(scope, circuit_init, expected_type, circuit_name)
|
||||||
.map(Expression::CircuitInit)?,
|
.map(Expression::CircuitInit)?,
|
||||||
),
|
),
|
||||||
CircuitMemberAccess(circuit_member) => scope.alloc_expression(
|
CircuitMemberAccess(circuit_member) => scope.context.alloc_expression(
|
||||||
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type, circuit_name)
|
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type, circuit_name)
|
||||||
.map(Expression::CircuitAccess)?,
|
.map(Expression::CircuitAccess)?,
|
||||||
),
|
),
|
||||||
CircuitStaticFunctionAccess(circuit_member) => scope.alloc_expression(
|
CircuitStaticFunctionAccess(circuit_member) => scope.context.alloc_expression(
|
||||||
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type, circuit_name)
|
CircuitAccessExpression::from_ast(scope, circuit_member, expected_type, circuit_name)
|
||||||
.map(Expression::CircuitAccess)?,
|
.map(Expression::CircuitAccess)?,
|
||||||
),
|
),
|
||||||
|
|
||||||
Call(call) => scope.alloc_expression(
|
Call(call) => scope.context.alloc_expression(
|
||||||
CallExpression::from_ast(scope, call, expected_type, circuit_name).map(Expression::Call)?,
|
CallExpression::from_ast(scope, call, expected_type, circuit_name).map(Expression::Call)?,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -157,7 +157,7 @@ impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> {
|
|||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
if value.name.starts_with("aleo1") {
|
if value.name.starts_with("aleo1") {
|
||||||
return Ok(scope.alloc_expression(Expression::Constant(Constant {
|
return Ok(scope.context.alloc_expression(Expression::Constant(Constant {
|
||||||
parent: Cell::new(None),
|
parent: Cell::new(None),
|
||||||
span: Some(value.span.clone()),
|
span: Some(value.span.clone()),
|
||||||
value: ConstValue::Address(value.name.clone()),
|
value: ConstValue::Address(value.name.clone()),
|
||||||
@ -173,7 +173,7 @@ impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> {
|
|||||||
span: Some(value.span.clone()),
|
span: Some(value.span.clone()),
|
||||||
variable,
|
variable,
|
||||||
};
|
};
|
||||||
let expression = scope.alloc_expression(Expression::VariableRef(variable_ref));
|
let expression = scope.context.alloc_expression(Expression::VariableRef(variable_ref));
|
||||||
|
|
||||||
if let Some(expected_type) = expected_type {
|
if let Some(expected_type) = expected_type {
|
||||||
let type_ = expression
|
let type_ = expression
|
||||||
|
@ -38,7 +38,7 @@ pub const STATE_LEAF_PSEUDO_CIRCUIT: &str = "$InputStateLeaf";
|
|||||||
|
|
||||||
impl<'a> Input<'a> {
|
impl<'a> Input<'a> {
|
||||||
fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> {
|
fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> {
|
||||||
scope.alloc_circuit(Circuit {
|
scope.context.alloc_circuit(Circuit {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: RefCell::new(Identifier::new(name.to_string())),
|
name: RefCell::new(Identifier::new(name.to_string())),
|
||||||
members: RefCell::new(IndexMap::new()),
|
members: RefCell::new(IndexMap::new()),
|
||||||
@ -67,7 +67,7 @@ impl<'a> Input<'a> {
|
|||||||
CircuitMember::Variable(Type::Circuit(state_leaf)),
|
CircuitMember::Variable(Type::Circuit(state_leaf)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let container_circuit = input_scope.alloc_circuit(Circuit {
|
let container_circuit = input_scope.context.alloc_circuit(Circuit {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.to_string())),
|
name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.to_string())),
|
||||||
members: RefCell::new(container_members),
|
members: RefCell::new(container_members),
|
||||||
@ -82,7 +82,7 @@ impl<'a> Input<'a> {
|
|||||||
state,
|
state,
|
||||||
state_leaf,
|
state_leaf,
|
||||||
container_circuit,
|
container_circuit,
|
||||||
container: input_scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
container: input_scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: Identifier::new("input".to_string()),
|
name: Identifier::new("input".to_string()),
|
||||||
type_: Type::Circuit(container_circuit),
|
type_: Type::Circuit(container_circuit),
|
||||||
|
@ -97,7 +97,7 @@ impl<'a> Asg<'a> {
|
|||||||
) -> Result<Self, AsgConvertError> {
|
) -> Result<Self, AsgConvertError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
context,
|
context,
|
||||||
asg: InternalProgram::new(context, ast.as_ref(), resolver)?,
|
asg: Program::new(context, ast.as_ref(), resolver)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +106,10 @@ impl<'a> Asg<'a> {
|
|||||||
&self.asg
|
&self.asg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_repr(self) -> Program<'a> {
|
||||||
|
self.asg
|
||||||
|
}
|
||||||
|
|
||||||
// /// Serializes the ast into a JSON string.
|
// /// Serializes the ast into a JSON string.
|
||||||
// pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
|
// pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
|
||||||
// serde_json::to_string_pretty(&self.asg)
|
// serde_json::to_string_pretty(&self.asg)
|
||||||
@ -127,7 +131,7 @@ pub fn load_asg<'a, T: ImportResolver<'a>>(
|
|||||||
// Parses the Leo file and constructs a grammar ast.
|
// Parses the Leo file and constructs a grammar ast.
|
||||||
let ast = leo_parser::parse_ast("input.leo", content)?;
|
let ast = leo_parser::parse_ast("input.leo", content)?;
|
||||||
|
|
||||||
InternalProgram::new(context, ast.as_repr(), resolver)
|
Program::new(context, ast.as_repr(), resolver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {
|
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {
|
||||||
|
@ -18,5 +18,5 @@ use crate::Program;
|
|||||||
pub use leo_ast::FormattedError;
|
pub use leo_ast::FormattedError;
|
||||||
|
|
||||||
pub trait AsgPass<'a> {
|
pub trait AsgPass<'a> {
|
||||||
fn do_pass(asg: &Program<'a>) -> Result<(), FormattedError>;
|
fn do_pass(asg: Program<'a>) -> Result<Program<'a>, FormattedError>;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ impl<'a> Circuit<'a> {
|
|||||||
pub(super) fn init(scope: &'a Scope<'a>, value: &leo_ast::Circuit) -> Result<&'a Circuit<'a>, AsgConvertError> {
|
pub(super) fn init(scope: &'a Scope<'a>, value: &leo_ast::Circuit) -> Result<&'a Circuit<'a>, AsgConvertError> {
|
||||||
let new_scope = scope.make_subscope();
|
let new_scope = scope.make_subscope();
|
||||||
|
|
||||||
let circuit = scope.alloc_circuit(Circuit {
|
let circuit = scope.context.alloc_circuit(Circuit {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: RefCell::new(value.circuit_name.clone()),
|
name: RefCell::new(value.circuit_name.clone()),
|
||||||
members: RefCell::new(IndexMap::new()),
|
members: RefCell::new(IndexMap::new()),
|
||||||
|
@ -103,7 +103,7 @@ impl<'a> Function<'a> {
|
|||||||
mutable,
|
mutable,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let variable = scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
let variable = scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: identifier.clone(),
|
name: identifier.clone(),
|
||||||
type_: scope.resolve_ast_type(&type_, circuit_name)?,
|
type_: scope.resolve_ast_type(&type_, circuit_name)?,
|
||||||
@ -121,7 +121,7 @@ impl<'a> Function<'a> {
|
|||||||
if qualifier != FunctionQualifier::Static && scope.circuit_self.get().is_none() {
|
if qualifier != FunctionQualifier::Static && scope.circuit_self.get().is_none() {
|
||||||
return Err(AsgConvertError::invalid_self_in_global(&value.span));
|
return Err(AsgConvertError::invalid_self_in_global(&value.span));
|
||||||
}
|
}
|
||||||
let function = scope.alloc_function(Function {
|
let function = scope.context.alloc_function(Function {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: RefCell::new(value.identifier.clone()),
|
name: RefCell::new(value.identifier.clone()),
|
||||||
output,
|
output,
|
||||||
@ -146,7 +146,7 @@ impl<'a> Function<'a> {
|
|||||||
) -> Result<(), AsgConvertError> {
|
) -> Result<(), AsgConvertError> {
|
||||||
if self.qualifier != FunctionQualifier::Static {
|
if self.qualifier != FunctionQualifier::Static {
|
||||||
let circuit = self.circuit.get();
|
let circuit = self.circuit.get();
|
||||||
let self_variable = self.scope.alloc_variable(RefCell::new(crate::InnerVariable {
|
let self_variable = self.scope.context.alloc_variable(RefCell::new(crate::InnerVariable {
|
||||||
id: self.scope.context.get_id(),
|
id: self.scope.context.get_id(),
|
||||||
name: Identifier::new("self".to_string()),
|
name: Identifier::new("self".to_string()),
|
||||||
type_: Type::Circuit(circuit.as_ref().unwrap()),
|
type_: Type::Circuit(circuit.as_ref().unwrap()),
|
||||||
@ -184,7 +184,7 @@ impl<'a> Function<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.body
|
self.body
|
||||||
.replace(Some(self.scope.alloc_statement(Statement::Block(main_block))));
|
.replace(Some(self.scope.context.alloc_statement(Statement::Block(main_block))));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ use std::cell::{Cell, RefCell};
|
|||||||
|
|
||||||
/// Stores the Leo program abstract semantic graph (ASG).
|
/// Stores the Leo program abstract semantic graph (ASG).
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct InternalProgram<'a> {
|
pub struct Program<'a> {
|
||||||
pub context: AsgContext<'a>,
|
pub context: AsgContext<'a>,
|
||||||
|
|
||||||
/// The unique id of the program.
|
/// The unique id of the program.
|
||||||
@ -55,8 +55,6 @@ pub struct InternalProgram<'a> {
|
|||||||
pub scope: &'a Scope<'a>,
|
pub scope: &'a Scope<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Program<'a> = InternalProgram<'a>;
|
|
||||||
|
|
||||||
/// Enumerates what names are imported from a package.
|
/// Enumerates what names are imported from a package.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum ImportSymbol {
|
enum ImportSymbol {
|
||||||
@ -123,7 +121,7 @@ fn resolve_import_package_access(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InternalProgram<'a> {
|
impl<'a> Program<'a> {
|
||||||
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
|
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
|
||||||
///
|
///
|
||||||
/// Stages:
|
/// Stages:
|
||||||
@ -225,7 +223,7 @@ impl<'a> InternalProgram<'a> {
|
|||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope = import_scope.alloc_scope(Scope {
|
let scope = import_scope.context.alloc_scope(Scope {
|
||||||
context,
|
context,
|
||||||
input: Cell::new(Some(Input::new(import_scope))), // we use import_scope to avoid recursive scope ref here
|
input: Cell::new(Some(Input::new(import_scope))), // we use import_scope to avoid recursive scope ref here
|
||||||
id: context.get_id(),
|
id: context.get_id(),
|
||||||
@ -273,7 +271,7 @@ impl<'a> InternalProgram<'a> {
|
|||||||
circuits.insert(name.name.clone(), asg_circuit);
|
circuits.insert(name.name.clone(), asg_circuit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InternalProgram {
|
Ok(Program {
|
||||||
context,
|
context,
|
||||||
id: context.get_id(),
|
id: context.get_id(),
|
||||||
name: program.name.clone(),
|
name: program.name.clone(),
|
||||||
@ -371,7 +369,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Into<leo_ast::Program> for &InternalProgram<'a> {
|
impl<'a> Into<leo_ast::Program> for &Program<'a> {
|
||||||
fn into(self) -> leo_ast::Program {
|
fn into(self) -> leo_ast::Program {
|
||||||
leo_ast::Program {
|
leo_ast::Program {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
|
@ -26,6 +26,12 @@ pub use monoidal_director::*;
|
|||||||
mod monoidal_reducer;
|
mod monoidal_reducer;
|
||||||
pub use monoidal_reducer::*;
|
pub use monoidal_reducer::*;
|
||||||
|
|
||||||
|
mod reconstructing_reducer;
|
||||||
|
pub use reconstructing_reducer::*;
|
||||||
|
|
||||||
|
mod reconstructing_director;
|
||||||
|
pub use reconstructing_director::*;
|
||||||
|
|
||||||
mod visitor;
|
mod visitor;
|
||||||
pub use visitor::*;
|
pub use visitor::*;
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ impl<'a, T: Monoid, R: MonoidalReducerStatement<'a, T>> MonoidalDirector<'a, T,
|
|||||||
Statement::Expression(s) => self.reduce_expression_statement(s),
|
Statement::Expression(s) => self.reduce_expression_statement(s),
|
||||||
Statement::Iteration(s) => self.reduce_iteration(s),
|
Statement::Iteration(s) => self.reduce_iteration(s),
|
||||||
Statement::Return(s) => self.reduce_return(s),
|
Statement::Return(s) => self.reduce_return(s),
|
||||||
|
Statement::Empty(_) => T::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.reducer.reduce_statement(input, value)
|
self.reducer.reduce_statement(input, value)
|
||||||
@ -272,15 +273,14 @@ impl<'a, T: Monoid, R: MonoidalReducerStatement<'a, T>> MonoidalDirector<'a, T,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R> {
|
impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R> {
|
||||||
fn reduce_function(&mut self, input: &'a Function<'a>) -> T {
|
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();
|
let body = input.body.get().map(|s| self.reduce_statement(s)).unwrap_or_default();
|
||||||
|
|
||||||
self.reducer.reduce_function(input, body)
|
self.reducer.reduce_function(input, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>) -> T {
|
pub fn reduce_circuit_member(&mut self, input: &CircuitMember<'a>) -> T {
|
||||||
let function = match input {
|
let function = match input {
|
||||||
CircuitMember::Function(f) => Some(self.reduce_function(f)),
|
CircuitMember::Function(f) => Some(self.reduce_function(f)),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -289,7 +289,7 @@ impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R>
|
|||||||
self.reducer.reduce_circuit_member(input, function)
|
self.reducer.reduce_circuit_member(input, function)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_circuit(&mut self, input: &'a Circuit<'a>) -> T {
|
pub fn reduce_circuit(&mut self, input: &'a Circuit<'a>) -> T {
|
||||||
let members = input
|
let members = input
|
||||||
.members
|
.members
|
||||||
.borrow()
|
.borrow()
|
||||||
@ -300,7 +300,7 @@ impl<'a, T: Monoid, R: MonoidalReducerProgram<'a, T>> MonoidalDirector<'a, T, R>
|
|||||||
self.reducer.reduce_circuit(input, members)
|
self.reducer.reduce_circuit(input, members)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_program(&mut self, input: &Program<'a>) -> T {
|
pub fn reduce_program(&mut self, input: &Program<'a>) -> T {
|
||||||
let imported_modules = input
|
let imported_modules = input
|
||||||
.imported_modules
|
.imported_modules
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -157,13 +157,7 @@ pub trait MonoidalReducerProgram<'a, T: Monoid>: MonoidalReducerStatement<'a, T>
|
|||||||
T::default().append_all(members.into_iter())
|
T::default().append_all(members.into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_program(
|
fn reduce_program(&mut self, input: &Program, imported_modules: Vec<T>, functions: Vec<T>, circuits: Vec<T>) -> T {
|
||||||
&mut self,
|
|
||||||
input: &InternalProgram,
|
|
||||||
imported_modules: Vec<T>,
|
|
||||||
functions: Vec<T>,
|
|
||||||
circuits: Vec<T>,
|
|
||||||
) -> T {
|
|
||||||
T::default()
|
T::default()
|
||||||
.append_all(imported_modules.into_iter())
|
.append_all(imported_modules.into_iter())
|
||||||
.append_all(functions.into_iter())
|
.append_all(functions.into_iter())
|
||||||
|
345
asg/src/reducer/reconstructing_director.rs
Normal file
345
asg/src/reducer/reconstructing_director.rs
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
// 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::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: FormattedString<'a>) -> FormattedString<'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::Debug(f) | 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_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 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();
|
||||||
|
|
||||||
|
self.reducer
|
||||||
|
.reduce_program(input, imported_modules, functions, circuits)
|
||||||
|
}
|
||||||
|
}
|
402
asg/src/reducer/reconstructing_reducer.rs
Normal file
402
asg/src/reducer/reconstructing_reducer.rs
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
// 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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: FormattedString<'a>,
|
||||||
|
parameters: Vec<&'a Expression<'a>>,
|
||||||
|
) -> FormattedString<'a> {
|
||||||
|
FormattedString {
|
||||||
|
span: input.span,
|
||||||
|
parts: input.parts,
|
||||||
|
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: FormattedString<'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::Debug(_) => ConsoleFunction::Debug(argument),
|
||||||
|
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),
|
||||||
|
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_program(
|
||||||
|
&mut self,
|
||||||
|
input: Program<'a>,
|
||||||
|
imported_modules: Vec<(String, Program<'a>)>,
|
||||||
|
functions: Vec<(String, &'a Function<'a>)>,
|
||||||
|
circuits: Vec<(String, &'a Circuit<'a>)>,
|
||||||
|
) -> Program<'a> {
|
||||||
|
Program {
|
||||||
|
context: input.context,
|
||||||
|
id: input.id,
|
||||||
|
name: input.name,
|
||||||
|
imported_modules: imported_modules.into_iter().collect(),
|
||||||
|
functions: functions.into_iter().collect(),
|
||||||
|
circuits: circuits.into_iter().collect(),
|
||||||
|
scope: input.scope,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -248,6 +248,7 @@ impl<'a, R: StatementVisitor<'a>> VisitorDirector<'a, R> {
|
|||||||
Statement::Expression(s) => self.visit_expression_statement(s),
|
Statement::Expression(s) => self.visit_expression_statement(s),
|
||||||
Statement::Iteration(s) => self.visit_iteration(s),
|
Statement::Iteration(s) => self.visit_iteration(s),
|
||||||
Statement::Return(s) => self.visit_return(s),
|
Statement::Return(s) => self.visit_return(s),
|
||||||
|
Statement::Empty(_) => Ok(()),
|
||||||
},
|
},
|
||||||
x => x.into(),
|
x => x.into(),
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{ArenaNode, AsgContext, AsgConvertError, Circuit, Expression, Function, Input, Statement, Type, Variable};
|
use crate::{AsgContext, AsgConvertError, Circuit, Function, Input, Type, Variable};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -51,48 +51,6 @@ pub struct Scope<'a> {
|
|||||||
|
|
||||||
#[allow(clippy::mut_from_ref)]
|
#[allow(clippy::mut_from_ref)]
|
||||||
impl<'a> Scope<'a> {
|
impl<'a> Scope<'a> {
|
||||||
pub fn alloc_expression(&'a self, expr: Expression<'a>) -> &'a mut Expression<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Expression(expr)) {
|
|
||||||
ArenaNode::Expression(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_statement(&'a self, statement: Statement<'a>) -> &'a mut Statement<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Statement(statement)) {
|
|
||||||
ArenaNode::Statement(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_variable(&'a self, variable: Variable<'a>) -> &'a mut Variable<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Variable(variable)) {
|
|
||||||
ArenaNode::Variable(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_scope(&'a self, scope: Scope<'a>) -> &'a mut Scope<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Scope(scope)) {
|
|
||||||
ArenaNode::Scope(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_circuit(&'a self, circuit: Circuit<'a>) -> &'a mut Circuit<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Circuit(circuit)) {
|
|
||||||
ArenaNode::Circuit(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_function(&'a self, function: Function<'a>) -> &'a mut Function<'a> {
|
|
||||||
match self.context.arena.alloc(ArenaNode::Function(function)) {
|
|
||||||
ArenaNode::Function(e) => e,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Returns a reference to the variable corresponding to the name.
|
/// Returns a reference to the variable corresponding to the name.
|
||||||
///
|
///
|
||||||
@ -195,7 +153,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// Returns a new scope given a parent scope.
|
/// Returns a new scope given a parent scope.
|
||||||
///
|
///
|
||||||
pub fn make_subscope(self: &'a Scope<'a>) -> &'a Scope<'a> {
|
pub fn make_subscope(self: &'a Scope<'a>) -> &'a Scope<'a> {
|
||||||
self.alloc_scope(Scope::<'a> {
|
self.context.alloc_scope(Scope::<'a> {
|
||||||
context: self.context,
|
context: self.context,
|
||||||
id: self.context.get_id(),
|
id: self.context.get_id(),
|
||||||
parent_scope: Cell::new(Some(self)),
|
parent_scope: Cell::new(Some(self)),
|
||||||
|
@ -219,7 +219,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> {
|
|||||||
}
|
}
|
||||||
let value = <&Expression<'a>>::from_ast(scope, &statement.value, target_type, circuit_name)?;
|
let value = <&Expression<'a>>::from_ast(scope, &statement.value, target_type, circuit_name)?;
|
||||||
|
|
||||||
let statement = scope.alloc_statement(Statement::Assign(AssignStatement {
|
let statement = scope.context.alloc_statement(Statement::Assign(AssignStatement {
|
||||||
parent: Cell::new(None),
|
parent: Cell::new(None),
|
||||||
span: Some(statement.span.clone()),
|
span: Some(statement.span.clone()),
|
||||||
operation: statement.operation.clone(),
|
operation: statement.operation.clone(),
|
||||||
|
@ -42,7 +42,7 @@ impl<'a> FromAst<'a, leo_ast::ConditionalStatement> for ConditionalStatement<'a>
|
|||||||
) -> Result<Self, AsgConvertError> {
|
) -> Result<Self, AsgConvertError> {
|
||||||
let condition =
|
let condition =
|
||||||
<&Expression<'a>>::from_ast(scope, &statement.condition, Some(Type::Boolean.into()), circuit_name)?;
|
<&Expression<'a>>::from_ast(scope, &statement.condition, Some(Type::Boolean.into()), circuit_name)?;
|
||||||
let result = scope.alloc_statement(Statement::Block(BlockStatement::from_ast(
|
let result = scope.context.alloc_statement(Statement::Block(BlockStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
&statement.block,
|
&statement.block,
|
||||||
None,
|
None,
|
||||||
|
@ -90,7 +90,7 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (variable, type_) in statement.variable_names.iter().zip(output_types.into_iter()) {
|
for (variable, type_) in statement.variable_names.iter().zip(output_types.into_iter()) {
|
||||||
variables.push(&*scope.alloc_variable(RefCell::new(InnerVariable {
|
variables.push(&*scope.context.alloc_variable(RefCell::new(InnerVariable {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: variable.identifier.clone(),
|
name: variable.identifier.clone(),
|
||||||
type_:
|
type_:
|
||||||
@ -110,7 +110,9 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> {
|
|||||||
.insert(variable.borrow().name.name.clone(), *variable);
|
.insert(variable.borrow().name.name.clone(), *variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
let statement = scope.alloc_statement(Statement::Definition(DefinitionStatement {
|
let statement = scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Definition(DefinitionStatement {
|
||||||
parent: Cell::new(None),
|
parent: Cell::new(None),
|
||||||
span: Some(statement.span.clone()),
|
span: Some(statement.span.clone()),
|
||||||
variables: variables.clone(),
|
variables: variables.clone(),
|
||||||
|
@ -71,7 +71,7 @@ impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let variable = scope.alloc_variable(RefCell::new(InnerVariable {
|
let variable = scope.context.alloc_variable(RefCell::new(InnerVariable {
|
||||||
id: scope.context.get_id(),
|
id: scope.context.get_id(),
|
||||||
name: statement.variable.clone(),
|
name: statement.variable.clone(),
|
||||||
type_: start
|
type_: start
|
||||||
@ -88,18 +88,22 @@ impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(statement.variable.name.clone(), variable);
|
.insert(statement.variable.name.clone(), variable);
|
||||||
|
|
||||||
let statement = scope.alloc_statement(Statement::Iteration(IterationStatement {
|
let statement = scope.context.alloc_statement(Statement::Iteration(IterationStatement {
|
||||||
parent: Cell::new(None),
|
parent: Cell::new(None),
|
||||||
span: Some(statement.span.clone()),
|
span: Some(statement.span.clone()),
|
||||||
variable,
|
variable,
|
||||||
stop: Cell::new(stop),
|
stop: Cell::new(stop),
|
||||||
start: Cell::new(start),
|
start: Cell::new(start),
|
||||||
body: Cell::new(scope.alloc_statement(Statement::Block(crate::BlockStatement::from_ast(
|
body: Cell::new(
|
||||||
|
scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Block(crate::BlockStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
&statement.block,
|
&statement.block,
|
||||||
None,
|
None,
|
||||||
circuit_name,
|
circuit_name,
|
||||||
)?))),
|
)?)),
|
||||||
|
),
|
||||||
}));
|
}));
|
||||||
variable.borrow_mut().assignments.push(statement);
|
variable.borrow_mut().assignments.push(statement);
|
||||||
Ok(statement)
|
Ok(statement)
|
||||||
|
@ -54,6 +54,7 @@ pub enum Statement<'a> {
|
|||||||
Console(ConsoleStatement<'a>),
|
Console(ConsoleStatement<'a>),
|
||||||
Expression(ExpressionStatement<'a>),
|
Expression(ExpressionStatement<'a>),
|
||||||
Block(BlockStatement<'a>),
|
Block(BlockStatement<'a>),
|
||||||
|
Empty(Option<Span>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Node for Statement<'a> {
|
impl<'a> Node for Statement<'a> {
|
||||||
@ -68,6 +69,7 @@ impl<'a> Node for Statement<'a> {
|
|||||||
Console(s) => s.span(),
|
Console(s) => s.span(),
|
||||||
Expression(s) => s.span(),
|
Expression(s) => s.span(),
|
||||||
Block(s) => s.span(),
|
Block(s) => s.span(),
|
||||||
|
Empty(s) => s.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +83,9 @@ impl<'a> FromAst<'a, leo_ast::Statement> for &'a Statement<'a> {
|
|||||||
) -> Result<&'a Statement<'a>, AsgConvertError> {
|
) -> Result<&'a Statement<'a>, AsgConvertError> {
|
||||||
use leo_ast::Statement::*;
|
use leo_ast::Statement::*;
|
||||||
Ok(match value {
|
Ok(match value {
|
||||||
Return(statement) => scope.alloc_statement(Statement::Return(ReturnStatement::from_ast(
|
Return(statement) => scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Return(ReturnStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
statement,
|
statement,
|
||||||
None,
|
None,
|
||||||
@ -89,26 +93,36 @@ impl<'a> FromAst<'a, leo_ast::Statement> for &'a Statement<'a> {
|
|||||||
)?)),
|
)?)),
|
||||||
Definition(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
Definition(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
||||||
Assign(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
Assign(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
||||||
Conditional(statement) => scope.alloc_statement(Statement::Conditional(ConditionalStatement::from_ast(
|
Conditional(statement) => {
|
||||||
|
scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Conditional(ConditionalStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
statement,
|
statement,
|
||||||
None,
|
None,
|
||||||
circuit_name,
|
circuit_name,
|
||||||
)?)),
|
)?))
|
||||||
|
}
|
||||||
Iteration(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
Iteration(statement) => Self::from_ast(scope, statement, None, circuit_name)?,
|
||||||
Console(statement) => scope.alloc_statement(Statement::Console(ConsoleStatement::from_ast(
|
Console(statement) => scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Console(ConsoleStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
statement,
|
statement,
|
||||||
None,
|
None,
|
||||||
circuit_name,
|
circuit_name,
|
||||||
)?)),
|
)?)),
|
||||||
Expression(statement) => scope.alloc_statement(Statement::Expression(ExpressionStatement::from_ast(
|
Expression(statement) => {
|
||||||
|
scope
|
||||||
|
.context
|
||||||
|
.alloc_statement(Statement::Expression(ExpressionStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
statement,
|
statement,
|
||||||
None,
|
None,
|
||||||
circuit_name,
|
circuit_name,
|
||||||
)?)),
|
)?))
|
||||||
Block(statement) => scope.alloc_statement(Statement::Block(BlockStatement::from_ast(
|
}
|
||||||
|
Block(statement) => scope.context.alloc_statement(Statement::Block(BlockStatement::from_ast(
|
||||||
scope,
|
scope,
|
||||||
statement,
|
statement,
|
||||||
None,
|
None,
|
||||||
@ -130,6 +144,7 @@ impl<'a> Into<leo_ast::Statement> for &Statement<'a> {
|
|||||||
Console(statement) => leo_ast::Statement::Console(statement.into()),
|
Console(statement) => leo_ast::Statement::Console(statement.into()),
|
||||||
Expression(statement) => leo_ast::Statement::Expression(statement.into()),
|
Expression(statement) => leo_ast::Statement::Expression(statement.into()),
|
||||||
Block(statement) => leo_ast::Statement::Block(statement.into()),
|
Block(statement) => leo_ast::Statement::Block(statement.into()),
|
||||||
|
Empty(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ fn load_asg_imports<'a, T: ImportResolver<'a>>(
|
|||||||
imports: &mut T,
|
imports: &mut T,
|
||||||
) -> Result<Program<'a>, AsgConvertError> {
|
) -> Result<Program<'a>, AsgConvertError> {
|
||||||
let ast = parse_ast(&TESTING_FILEPATH, program_string)?;
|
let ast = parse_ast(&TESTING_FILEPATH, program_string)?;
|
||||||
InternalProgram::new(context, &ast.as_repr(), imports)
|
Program::new(context, &ast.as_repr(), imports)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mocked_resolver(_context: AsgContext<'_>) -> MockedImportResolver<'_> {
|
fn mocked_resolver(_context: AsgContext<'_>) -> MockedImportResolver<'_> {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{Node, Span};
|
use crate::{Identifier, Node, Span};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -22,8 +22,9 @@ use std::fmt;
|
|||||||
/// The `input` keyword can view program register, record, and state values.
|
/// The `input` keyword can view program register, record, and state values.
|
||||||
/// Values cannot be modified. The `input` keyword cannot be made mutable.
|
/// Values cannot be modified. The `input` keyword cannot be made mutable.
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct InputKeyword {
|
pub struct InputKeyword {
|
||||||
pub span: Span,
|
pub identifier: Identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InputKeyword {
|
impl fmt::Display for InputKeyword {
|
||||||
@ -34,10 +35,10 @@ impl fmt::Display for InputKeyword {
|
|||||||
|
|
||||||
impl Node for InputKeyword {
|
impl Node for InputKeyword {
|
||||||
fn span(&self) -> &Span {
|
fn span(&self) -> &Span {
|
||||||
&self.span
|
&self.identifier.span
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_span(&mut self, span: Span) {
|
fn set_span(&mut self, span: Span) {
|
||||||
self.span = span;
|
self.identifier.span = span;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,16 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{Node, Span};
|
use crate::{Identifier, Node, Span};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// The `mut self` keyword can view and modify circuit values inside of a circuit function.
|
/// The `mut self` keyword can view and modify circuit values inside of a circuit function.
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct MutSelfKeyword {
|
pub struct MutSelfKeyword {
|
||||||
pub span: Span,
|
pub identifier: Identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for MutSelfKeyword {
|
impl fmt::Display for MutSelfKeyword {
|
||||||
@ -33,10 +34,10 @@ impl fmt::Display for MutSelfKeyword {
|
|||||||
|
|
||||||
impl Node for MutSelfKeyword {
|
impl Node for MutSelfKeyword {
|
||||||
fn span(&self) -> &Span {
|
fn span(&self) -> &Span {
|
||||||
&self.span
|
&self.identifier.span
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_span(&mut self, span: Span) {
|
fn set_span(&mut self, span: Span) {
|
||||||
self.span = span;
|
self.identifier.span = span;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{Node, Span};
|
use crate::{Identifier, Node, Span};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -22,8 +22,9 @@ use std::fmt;
|
|||||||
/// The `self` keyword can view circuit values inside of a circuit function.
|
/// The `self` keyword can view circuit values inside of a circuit function.
|
||||||
/// Circuit values cannot be modified. To modify values use the `mut self` [MutSelfKeyword].
|
/// Circuit values cannot be modified. To modify values use the `mut self` [MutSelfKeyword].
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct SelfKeyword {
|
pub struct SelfKeyword {
|
||||||
pub span: Span,
|
pub identifier: Identifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SelfKeyword {
|
impl fmt::Display for SelfKeyword {
|
||||||
@ -34,10 +35,10 @@ impl fmt::Display for SelfKeyword {
|
|||||||
|
|
||||||
impl Node for SelfKeyword {
|
impl Node for SelfKeyword {
|
||||||
fn span(&self) -> &Span {
|
fn span(&self) -> &Span {
|
||||||
&self.span
|
&self.identifier.span
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_span(&mut self, span: Span) {
|
fn set_span(&mut self, span: Span) {
|
||||||
self.span = span;
|
self.identifier.span = span;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,9 +96,9 @@ impl Node for FunctionInput {
|
|||||||
fn span(&self) -> &Span {
|
fn span(&self) -> &Span {
|
||||||
use FunctionInput::*;
|
use FunctionInput::*;
|
||||||
match self {
|
match self {
|
||||||
InputKeyword(keyword) => &keyword.span,
|
InputKeyword(keyword) => &keyword.identifier.span,
|
||||||
SelfKeyword(keyword) => &keyword.span,
|
SelfKeyword(keyword) => &keyword.identifier.span,
|
||||||
MutSelfKeyword(keyword) => &keyword.span,
|
MutSelfKeyword(keyword) => &keyword.identifier.span,
|
||||||
Variable(variable) => &variable.span,
|
Variable(variable) => &variable.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,9 +106,9 @@ impl Node for FunctionInput {
|
|||||||
fn set_span(&mut self, span: Span) {
|
fn set_span(&mut self, span: Span) {
|
||||||
use FunctionInput::*;
|
use FunctionInput::*;
|
||||||
match self {
|
match self {
|
||||||
InputKeyword(keyword) => keyword.span = span,
|
InputKeyword(keyword) => keyword.identifier.span = span,
|
||||||
SelfKeyword(keyword) => keyword.span = span,
|
SelfKeyword(keyword) => keyword.identifier.span = span,
|
||||||
MutSelfKeyword(keyword) => keyword.span = span,
|
MutSelfKeyword(keyword) => keyword.identifier.span = span,
|
||||||
Variable(variable) => variable.span = span,
|
Variable(variable) => variable.span = span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,12 +94,18 @@ impl Input {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the main function input value with the given `name`
|
/// Returns the main function input value with the given `name`.
|
||||||
#[allow(clippy::ptr_arg)]
|
#[allow(clippy::ptr_arg)]
|
||||||
pub fn get(&self, name: &String) -> Option<Option<InputValue>> {
|
pub fn get(&self, name: &String) -> Option<Option<InputValue>> {
|
||||||
self.program_input.get(name)
|
self.program_input.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the constant input value with the given `name`.
|
||||||
|
#[allow(clippy::ptr_arg)]
|
||||||
|
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
|
||||||
|
self.program_input.get_constant(name)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the runtime register input values
|
/// Returns the runtime register input values
|
||||||
pub fn get_registers(&self) -> &Registers {
|
pub fn get_registers(&self) -> &Registers {
|
||||||
self.program_input.get_registers()
|
self.program_input.get_registers()
|
||||||
|
@ -14,11 +14,13 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/// Constructs an input section to store data parsed from a Leo input file.
|
||||||
|
/// Constructs sections that pass variables to the main function through the input keyword.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! input_section_impl {
|
macro_rules! record_input_section {
|
||||||
($($name: ident), *) => ($(
|
($($name: ident), *) => ($(
|
||||||
|
|
||||||
/// An input section declared in an input file with `[$name]`
|
/// An input section declared in an input file with `[$name]`.
|
||||||
#[derive(Clone, PartialEq, Eq, Default)]
|
#[derive(Clone, PartialEq, Eq, Default)]
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
is_present: bool,
|
is_present: bool,
|
||||||
@ -63,10 +65,68 @@ macro_rules! input_section_impl {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this section's [IndexMap] of values
|
/// Returns this section's [IndexMap] of values.
|
||||||
pub fn values(&self) -> IndexMap<Parameter, Option<InputValue>> {
|
pub fn values(&self) -> IndexMap<Parameter, Option<InputValue>> {
|
||||||
self.values.clone()
|
self.values.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*)
|
)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs an input section to store data parsed from a Leo input file.
|
||||||
|
/// Constructs sections that pass variables directly to the main function.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! main_input_section {
|
||||||
|
($($name: ident), *) => ($(
|
||||||
|
|
||||||
|
/// `[$name]` program input section.
|
||||||
|
#[derive(Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct $name {
|
||||||
|
input: IndexMap<String, Option<InputValue>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
impl $name {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an empty version of this struct with `None` values.
|
||||||
|
/// Called during constraint synthesis to provide private input variables.
|
||||||
|
pub fn empty(&self) -> Self {
|
||||||
|
let mut input = self.input.clone();
|
||||||
|
|
||||||
|
input.iter_mut().for_each(|(_name, value)| {
|
||||||
|
*value = None;
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { input }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.input.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, key: String, value: Option<InputValue>) {
|
||||||
|
self.input.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses main input definitions and stores them in `self`.
|
||||||
|
pub fn parse(&mut self, definitions: Vec<Definition>) -> Result<(), InputParserError> {
|
||||||
|
for definition in definitions {
|
||||||
|
let name = definition.parameter.variable.value;
|
||||||
|
let value = InputValue::from_expression(definition.parameter.type_, definition.expression)?;
|
||||||
|
|
||||||
|
self.insert(name, Some(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an `Option` of the main function input at `name`.
|
||||||
|
pub fn get(&self, name: &str) -> Option<Option<InputValue>> {
|
||||||
|
self.input.get(name).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
22
ast/src/input/program_input/constant_input.rs
Normal file
22
ast/src/input/program_input/constant_input.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||||
|
// This file is part of the Leo library.
|
||||||
|
|
||||||
|
// The Leo library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// The Leo library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use crate::InputValue;
|
||||||
|
use leo_input::{definitions::Definition, InputParserError};
|
||||||
|
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
main_input_section!(ConstantInput);
|
@ -19,51 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Default)]
|
main_input_section!(MainInput);
|
||||||
pub struct MainInput {
|
|
||||||
input: IndexMap<String, Option<InputValue>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::len_without_is_empty)]
|
|
||||||
impl MainInput {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an empty version of this struct with `None` values.
|
|
||||||
/// Called during constraint synthesis to provide private input variables.
|
|
||||||
pub fn empty(&self) -> Self {
|
|
||||||
let mut input = self.input.clone();
|
|
||||||
|
|
||||||
input.iter_mut().for_each(|(_name, value)| {
|
|
||||||
*value = None;
|
|
||||||
});
|
|
||||||
|
|
||||||
Self { input }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.input.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, key: String, value: Option<InputValue>) {
|
|
||||||
self.input.insert(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses main input definitions and stores them in `self`.
|
|
||||||
pub fn parse(&mut self, definitions: Vec<Definition>) -> Result<(), InputParserError> {
|
|
||||||
for definition in definitions {
|
|
||||||
let name = definition.parameter.variable.value;
|
|
||||||
let value = InputValue::from_expression(definition.parameter.type_, definition.expression)?;
|
|
||||||
|
|
||||||
self.insert(name, Some(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an `Option` of the main function input at `name`
|
|
||||||
pub fn get(&self, name: &str) -> Option<Option<InputValue>> {
|
|
||||||
self.input.get(name).cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
#![allow(clippy::module_inception)]
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
|
pub mod constant_input;
|
||||||
|
pub use constant_input::*;
|
||||||
|
|
||||||
pub mod main_input;
|
pub mod main_input;
|
||||||
pub use main_input::*;
|
pub use main_input::*;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{InputValue, MainInput, Registers};
|
use crate::{ConstantInput, InputValue, MainInput, Registers};
|
||||||
use leo_input::{
|
use leo_input::{
|
||||||
sections::{Header, Section},
|
sections::{Header, Section},
|
||||||
InputParserError,
|
InputParserError,
|
||||||
@ -23,6 +23,7 @@ use leo_input::{
|
|||||||
#[derive(Clone, PartialEq, Eq, Default)]
|
#[derive(Clone, PartialEq, Eq, Default)]
|
||||||
pub struct ProgramInput {
|
pub struct ProgramInput {
|
||||||
pub main: MainInput,
|
pub main: MainInput,
|
||||||
|
pub constants: ConstantInput,
|
||||||
registers: Registers,
|
registers: Registers,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,18 +37,24 @@ impl ProgramInput {
|
|||||||
/// Called during constraint synthesis to provide private input values.
|
/// Called during constraint synthesis to provide private input values.
|
||||||
pub fn empty(&self) -> Self {
|
pub fn empty(&self) -> Self {
|
||||||
let main = self.main.empty();
|
let main = self.main.empty();
|
||||||
|
let constants = self.constants.empty();
|
||||||
let registers = self.registers.empty();
|
let registers = self.registers.empty();
|
||||||
|
|
||||||
Self { main, registers }
|
Self {
|
||||||
|
main,
|
||||||
|
constants,
|
||||||
|
registers,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
|
|
||||||
// add main input variables
|
// Add main input variables and constants.
|
||||||
len += self.main.len();
|
len += self.main.len();
|
||||||
|
len += self.constants.len();
|
||||||
|
|
||||||
// add registers
|
// Add registers.
|
||||||
if self.registers.is_present() {
|
if self.registers.is_present() {
|
||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
@ -58,6 +65,7 @@ impl ProgramInput {
|
|||||||
/// Parse each input included in a file and store them in `self`.
|
/// Parse each input included in a file and store them in `self`.
|
||||||
pub fn parse(&mut self, section: Section) -> Result<(), InputParserError> {
|
pub fn parse(&mut self, section: Section) -> Result<(), InputParserError> {
|
||||||
match section.header {
|
match section.header {
|
||||||
|
Header::Constants(_constants) => self.constants.parse(section.definitions),
|
||||||
Header::Main(_main) => self.main.parse(section.definitions),
|
Header::Main(_main) => self.main.parse(section.definitions),
|
||||||
Header::Registers(_registers) => self.registers.parse(section.definitions),
|
Header::Registers(_registers) => self.registers.parse(section.definitions),
|
||||||
header => Err(InputParserError::input_section_header(header)),
|
header => Err(InputParserError::input_section_header(header)),
|
||||||
@ -70,6 +78,11 @@ impl ProgramInput {
|
|||||||
self.main.get(name)
|
self.main.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::ptr_arg)]
|
||||||
|
pub fn get_constant(&self, name: &String) -> Option<Option<InputValue>> {
|
||||||
|
self.constants.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the runtime register input values
|
/// Returns the runtime register input values
|
||||||
pub fn get_registers(&self) -> &Registers {
|
pub fn get_registers(&self) -> &Registers {
|
||||||
&self.registers
|
&self.registers
|
||||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
input_section_impl!(Registers);
|
record_input_section!(Registers);
|
||||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
input_section_impl!(Record);
|
record_input_section!(Record);
|
||||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
input_section_impl!(StateLeaf);
|
record_input_section!(StateLeaf);
|
||||||
|
@ -19,4 +19,4 @@ use leo_input::{definitions::Definition, InputParserError};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
input_section_impl!(State);
|
record_input_section!(State);
|
||||||
|
@ -23,7 +23,7 @@ use leo_input::types::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// Explicit integer type
|
/// Explicit integer type.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub enum IntegerType {
|
pub enum IntegerType {
|
||||||
U8,
|
U8,
|
||||||
|
@ -26,8 +26,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
pub use leo_asg::{new_context, AsgContext as Context, AsgContext};
|
pub use leo_asg::{new_context, AsgContext as Context, AsgContext};
|
||||||
use leo_asg::{Asg, AsgPass, FormattedError};
|
use leo_asg::{Asg, AsgPass, FormattedError, Program as AsgProgram};
|
||||||
use leo_ast::{Input, LeoError, MainInput, Program};
|
use leo_ast::{Input, LeoError, MainInput, Program as AstProgram};
|
||||||
use leo_input::LeoInputParser;
|
use leo_input::LeoInputParser;
|
||||||
use leo_package::inputs::InputPairs;
|
use leo_package::inputs::InputPairs;
|
||||||
use leo_parser::parse_ast;
|
use leo_parser::parse_ast;
|
||||||
@ -64,10 +64,10 @@ pub struct Compiler<'a, F: PrimeField, G: GroupType<F>> {
|
|||||||
program_name: String,
|
program_name: String,
|
||||||
main_file_path: PathBuf,
|
main_file_path: PathBuf,
|
||||||
output_directory: PathBuf,
|
output_directory: PathBuf,
|
||||||
program: Program,
|
program: AstProgram,
|
||||||
program_input: Input,
|
program_input: Input,
|
||||||
context: AsgContext<'a>,
|
context: AsgContext<'a>,
|
||||||
asg: Option<Asg<'a>>,
|
asg: Option<AsgProgram<'a>>,
|
||||||
file_contents: RefCell<IndexMap<String, Rc<Vec<String>>>>,
|
file_contents: RefCell<IndexMap<String, Rc<Vec<String>>>>,
|
||||||
options: CompilerOptions,
|
options: CompilerOptions,
|
||||||
_engine: PhantomData<F>,
|
_engine: PhantomData<F>,
|
||||||
@ -88,7 +88,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
|
|||||||
program_name: package_name.clone(),
|
program_name: package_name.clone(),
|
||||||
main_file_path,
|
main_file_path,
|
||||||
output_directory,
|
output_directory,
|
||||||
program: Program::new(package_name),
|
program: AstProgram::new(package_name),
|
||||||
program_input: Input::new(),
|
program_input: Input::new(),
|
||||||
asg: None,
|
asg: None,
|
||||||
context,
|
context,
|
||||||
@ -278,15 +278,29 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
|
|||||||
tracing::debug!("ASG generation complete");
|
tracing::debug!("ASG generation complete");
|
||||||
|
|
||||||
// Store the ASG.
|
// Store the ASG.
|
||||||
self.asg = Some(asg);
|
self.asg = Some(asg.into_repr());
|
||||||
|
|
||||||
|
self.do_asg_passes().map_err(CompilerError::AsgPassError)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_asg_passes(&self) -> Result<(), FormattedError> {
|
///
|
||||||
|
/// Run compiler optimization passes on the program in asg format.
|
||||||
|
///
|
||||||
|
fn do_asg_passes(&mut self) -> Result<(), FormattedError> {
|
||||||
assert!(self.asg.is_some());
|
assert!(self.asg.is_some());
|
||||||
|
|
||||||
|
// Do constant folding.
|
||||||
if self.options.constant_folding_enabled {
|
if self.options.constant_folding_enabled {
|
||||||
leo_asg_passes::ConstantFolding::do_pass(self.asg.as_ref().unwrap().as_repr())?;
|
let asg = self.asg.take().unwrap();
|
||||||
|
self.asg = Some(leo_asg_passes::ConstantFolding::do_pass(asg)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do dead code elimination.
|
||||||
|
if self.options.dead_code_elimination_enabled {
|
||||||
|
let asg = self.asg.take().unwrap();
|
||||||
|
self.asg = Some(leo_asg_passes::DeadCodeElimination::do_pass(asg)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -296,8 +310,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
|
|||||||
/// Synthesizes the circuit with program input to verify correctness.
|
/// Synthesizes the circuit with program input to verify correctness.
|
||||||
///
|
///
|
||||||
pub fn compile_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
|
pub fn compile_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
|
||||||
self.do_asg_passes().map_err(CompilerError::AsgPassError)?;
|
|
||||||
|
|
||||||
generate_constraints::<F, G, CS>(cs, &self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
|
generate_constraints::<F, G, CS>(cs, &self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| {
|
||||||
if let Some(path) = error.get_path().map(|x| x.to_string()) {
|
if let Some(path) = error.get_path().map(|x| x.to_string()) {
|
||||||
let content = match self.resolve_content(&path) {
|
let content = match self.resolve_content(&path) {
|
||||||
@ -314,8 +326,6 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
|
|||||||
/// Synthesizes the circuit for test functions with program input.
|
/// Synthesizes the circuit for test functions with program input.
|
||||||
///
|
///
|
||||||
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
|
pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> {
|
||||||
self.do_asg_passes().map_err(CompilerError::AsgPassError)?;
|
|
||||||
|
|
||||||
generate_test_constraints::<F, G>(
|
generate_test_constraints::<F, G>(
|
||||||
&self.asg.as_ref().unwrap(),
|
&self.asg.as_ref().unwrap(),
|
||||||
input_pairs,
|
input_pairs,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Generates R1CS constraints for a compiled Leo program.
|
//! Generates R1CS constraints for a compiled Leo program.
|
||||||
|
|
||||||
use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile};
|
use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile};
|
||||||
use leo_asg::Asg;
|
use leo_asg::Program;
|
||||||
use leo_ast::{Input, LeoError};
|
use leo_ast::{Input, LeoError};
|
||||||
use leo_input::LeoInputParser;
|
use leo_input::LeoInputParser;
|
||||||
use leo_package::inputs::InputPairs;
|
use leo_package::inputs::InputPairs;
|
||||||
@ -28,10 +28,9 @@ use std::path::Path;
|
|||||||
|
|
||||||
pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
asg: &Asg<'a>,
|
program: &Program<'a>,
|
||||||
input: &Input,
|
input: &Input,
|
||||||
) -> Result<OutputBytes, CompilerError> {
|
) -> Result<OutputBytes, CompilerError> {
|
||||||
let program = asg.as_repr();
|
|
||||||
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
||||||
|
|
||||||
let main = {
|
let main = {
|
||||||
@ -49,12 +48,11 @@ pub fn generate_constraints<'a, F: PrimeField, G: GroupType<F>, CS: ConstraintSy
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
|
pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType<F>>(
|
||||||
asg: &Asg<'a>,
|
program: &Program<'a>,
|
||||||
input: InputPairs,
|
input: InputPairs,
|
||||||
main_file_path: &Path,
|
main_file_path: &Path,
|
||||||
output_directory: &Path,
|
output_directory: &Path,
|
||||||
) -> Result<(u32, u32), CompilerError> {
|
) -> Result<(u32, u32), CompilerError> {
|
||||||
let program = asg.as_repr();
|
|
||||||
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
let mut resolved_program = ConstrainedProgram::<F, G>::new(program.clone());
|
||||||
let program_name = program.name.clone();
|
let program_name = program.name.clone();
|
||||||
|
|
||||||
|
@ -103,6 +103,33 @@ impl FunctionError {
|
|||||||
FunctionError::Error(FormattedError::new_from_span(message, span))
|
FunctionError::Error(FormattedError::new_from_span(message, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn input_type_mismatch(expected: String, actual: String, variable: String, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Expected input variable `{}` to be type `{}`, found type `{}`",
|
||||||
|
variable, expected, actual
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expected_const_input(variable: String, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Expected input variable `{}` to be constant. Move input variable `{}` to [constants] section of input file",
|
||||||
|
variable, variable
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expected_non_const_input(variable: String, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Expected input variable `{}` to be non-constant. Move input variable `{}` to [main] section of input file",
|
||||||
|
variable, variable
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn invalid_array(actual: String, span: &Span) -> Self {
|
pub fn invalid_array(actual: String, span: &Span) -> Self {
|
||||||
let message = format!("Expected function input array, found `{}`", actual);
|
let message = format!("Expected function input array, found `{}`", actual);
|
||||||
|
|
||||||
@ -118,6 +145,15 @@ impl FunctionError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tuple_size_mismatch(expected: usize, actual: usize, span: &Span) -> Self {
|
||||||
|
let message = format!(
|
||||||
|
"Input tuple size mismatch expected {}, found tuple with length {}",
|
||||||
|
expected, actual
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn invalid_tuple(actual: String, span: &Span) -> Self {
|
pub fn invalid_tuple(actual: String, span: &Span) -> Self {
|
||||||
let message = format!("Expected function input tuple, found `{}`", actual);
|
let message = format!("Expected function input tuple, found `{}`", actual);
|
||||||
|
|
||||||
@ -141,4 +177,10 @@ impl FunctionError {
|
|||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn double_input_declaration(input_name: String, span: &Span) -> Self {
|
||||||
|
let message = format!("Input variable {} declared twice", input_name);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,5 @@ pub fn evaluate_bit_not<'a, F: PrimeField, G: GroupType<F>>(
|
|||||||
value: ConstrainedValue<'a, F, G>,
|
value: ConstrainedValue<'a, F, G>,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
) -> Result<ConstrainedValue<'a, F, G>, IntegerError> {
|
) -> Result<ConstrainedValue<'a, F, G>, IntegerError> {
|
||||||
match value {
|
Err(IntegerError::cannot_evaluate(format!("!{}", value), span))
|
||||||
// ConstrainedValue::Integer(i) => Ok(ConstrainedValue::Integer(i.not())),
|
|
||||||
value => Err(IntegerError::cannot_evaluate(format!("~{}", value), span)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,15 @@ use crate::{
|
|||||||
group::input::group_from_input,
|
group::input::group_from_input,
|
||||||
ConstrainedValue,
|
ConstrainedValue,
|
||||||
},
|
},
|
||||||
|
FieldType,
|
||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
Integer,
|
||||||
};
|
};
|
||||||
|
use leo_asg::{ConstInt, Type};
|
||||||
use leo_asg::Type;
|
|
||||||
use leo_ast::{InputValue, Span};
|
use leo_ast::{InputValue, Span};
|
||||||
|
|
||||||
use snarkvm_fields::PrimeField;
|
use snarkvm_fields::PrimeField;
|
||||||
|
use snarkvm_gadgets::traits::utilities::boolean::Boolean;
|
||||||
use snarkvm_r1cs::ConstraintSystem;
|
use snarkvm_r1cs::ConstraintSystem;
|
||||||
|
|
||||||
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||||
@ -58,7 +60,68 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
|||||||
)?)),
|
)?)),
|
||||||
Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span),
|
Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span),
|
||||||
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
||||||
_ => unimplemented!("main function input not implemented for type"),
|
_ => unimplemented!("main function input not implemented for type {}", type_), // Should not happen.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process constant inputs and return ConstrainedValue with constant value in it.
|
||||||
|
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||||
|
pub fn constant_main_function_input<CS: ConstraintSystem<F>>(
|
||||||
|
&mut self,
|
||||||
|
_cs: &mut CS,
|
||||||
|
type_: &Type,
|
||||||
|
name: &str,
|
||||||
|
input_option: Option<InputValue>,
|
||||||
|
span: &Span,
|
||||||
|
) -> Result<ConstrainedValue<'a, F, G>, FunctionError> {
|
||||||
|
let input = input_option.ok_or_else(|| FunctionError::input_not_found(name.to_string(), span))?;
|
||||||
|
|
||||||
|
match (type_, input) {
|
||||||
|
(Type::Address, InputValue::Address(addr)) => Ok(ConstrainedValue::Address(Address::constant(addr, span)?)),
|
||||||
|
(Type::Boolean, InputValue::Boolean(value)) => Ok(ConstrainedValue::Boolean(Boolean::constant(value))),
|
||||||
|
(Type::Field, InputValue::Field(value)) => Ok(ConstrainedValue::Field(FieldType::constant(value, span)?)),
|
||||||
|
(Type::Group, InputValue::Group(value)) => Ok(ConstrainedValue::Group(G::constant(&value.into(), span)?)),
|
||||||
|
(Type::Integer(integer_type), InputValue::Integer(_, value)) => Ok(ConstrainedValue::Integer(
|
||||||
|
Integer::new(&ConstInt::parse(integer_type, &value, span)?),
|
||||||
|
)),
|
||||||
|
(Type::Array(type_, arr_len), InputValue::Array(values)) => {
|
||||||
|
if *arr_len != values.len() {
|
||||||
|
return Err(FunctionError::invalid_input_array_dimensions(
|
||||||
|
*arr_len,
|
||||||
|
values.len(),
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ConstrainedValue::Array(
|
||||||
|
values
|
||||||
|
.iter()
|
||||||
|
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(Type::Tuple(types), InputValue::Tuple(values)) => {
|
||||||
|
if values.len() != types.len() {
|
||||||
|
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ConstrainedValue::Tuple(
|
||||||
|
values
|
||||||
|
.iter()
|
||||||
|
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(Type::Circuit(_), _) => unimplemented!("main function input not implemented for type {}", type_), // Should not happen.
|
||||||
|
|
||||||
|
// Return an error if the input type and input value do not match.
|
||||||
|
(_, input) => Err(FunctionError::input_type_mismatch(
|
||||||
|
type_.to_string(),
|
||||||
|
input.to_string(),
|
||||||
|
name.to_string(),
|
||||||
|
span,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,11 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
|||||||
|
|
||||||
match input_value {
|
match input_value {
|
||||||
Some(InputValue::Tuple(values)) => {
|
Some(InputValue::Tuple(values)) => {
|
||||||
// Allocate each value in the tuple
|
if values.len() != types.len() {
|
||||||
|
return Err(FunctionError::tuple_size_mismatch(types.len(), values.len(), span));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate each value in the tuple.
|
||||||
for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() {
|
for (i, (value, type_)) in values.into_iter().zip(types.iter()).enumerate() {
|
||||||
let value_name = format!("{}_{}", &name, &i.to_string());
|
let value_name = format!("{}_{}", &name, &i.to_string());
|
||||||
|
|
||||||
|
@ -61,27 +61,64 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
|||||||
{
|
{
|
||||||
let input_variable = input_variable.get().borrow();
|
let input_variable = input_variable.get().borrow();
|
||||||
let name = input_variable.name.name.clone();
|
let name = input_variable.name.name.clone();
|
||||||
let input_option = input.get(&name).ok_or_else(|| {
|
|
||||||
FunctionError::input_not_found(name.clone(), &function.span.clone().unwrap_or_default())
|
let input_value = match (input_variable.const_, input.get(&name), input.get_constant(&name)) {
|
||||||
})?;
|
// If variable is in both [main] and [constants] sections - error.
|
||||||
let input_value = self.allocate_main_function_input(
|
(_, Some(_), Some(_)) => {
|
||||||
|
return Err(FunctionError::double_input_declaration(
|
||||||
|
name.clone(),
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// If input option is found in [main] section and input is not const.
|
||||||
|
(false, Some(input_option), _) => self.allocate_main_function_input(
|
||||||
cs,
|
cs,
|
||||||
&input_variable.type_.clone(),
|
&input_variable.type_.clone(),
|
||||||
&name,
|
&name,
|
||||||
input_option,
|
input_option,
|
||||||
&function.span.clone().unwrap_or_default(),
|
&function.span.clone().unwrap_or_default(),
|
||||||
)?;
|
)?,
|
||||||
|
// If input option is found in [constants] section and function argument is const.
|
||||||
|
(true, _, Some(input_option)) => self.constant_main_function_input(
|
||||||
|
cs,
|
||||||
|
&input_variable.type_.clone(),
|
||||||
|
&name,
|
||||||
|
input_option,
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
)?,
|
||||||
|
// Function argument is const, input is not.
|
||||||
|
(true, Some(_), None) => {
|
||||||
|
return Err(FunctionError::expected_const_input(
|
||||||
|
name.clone(),
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// Input is const, function argument is not.
|
||||||
|
(false, None, Some(_)) => {
|
||||||
|
return Err(FunctionError::expected_non_const_input(
|
||||||
|
name.clone(),
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// When not found - Error out.
|
||||||
|
(_, _, _) => {
|
||||||
|
return Err(FunctionError::input_not_found(
|
||||||
|
name.clone(),
|
||||||
|
&function.span.clone().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Store a new variable for every allocated main function input
|
// Store a new variable for every function input.
|
||||||
self.store(input_variable.id, input_value);
|
self.store(input_variable.id, input_value);
|
||||||
}
|
}
|
||||||
arguments.push(Cell::new(&*function.scope.alloc_expression(Expression::VariableRef(
|
arguments.push(Cell::new(&*function.scope.context.alloc_expression(
|
||||||
leo_asg::VariableRef {
|
Expression::VariableRef(leo_asg::VariableRef {
|
||||||
parent: Cell::new(None),
|
parent: Cell::new(None),
|
||||||
span: Some(input_variable.get().borrow().name.span.clone()),
|
span: Some(input_variable.get().borrow().name.span.clone()),
|
||||||
variable: input_variable.get(),
|
variable: input_variable.get(),
|
||||||
},
|
}),
|
||||||
))));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = function.span.clone().unwrap_or_default();
|
let span = function.span.clone().unwrap_or_default();
|
||||||
|
@ -14,15 +14,23 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Toggles compiler optimizations on the program.
|
||||||
|
///
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CompilerOptions {
|
pub struct CompilerOptions {
|
||||||
pub constant_folding_enabled: bool,
|
pub constant_folding_enabled: bool,
|
||||||
|
pub dead_code_elimination_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CompilerOptions {
|
impl Default for CompilerOptions {
|
||||||
|
///
|
||||||
|
/// All compiler optimizations are enabled by default.
|
||||||
|
///
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CompilerOptions {
|
CompilerOptions {
|
||||||
constant_folding_enabled: true,
|
constant_folding_enabled: true,
|
||||||
|
dead_code_elimination_enabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
|||||||
|
|
||||||
results.extend(result);
|
results.extend(result);
|
||||||
}
|
}
|
||||||
|
Statement::Empty(_) => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
|
@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
mod program_input;
|
mod program_input;
|
||||||
mod program_input_and_program_state;
|
mod program_input_and_program_state;
|
||||||
|
mod program_input_constants;
|
||||||
mod program_registers;
|
mod program_registers;
|
||||||
mod program_state;
|
mod program_state;
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
[main]
|
||||||
|
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)
|
@ -0,0 +1,3 @@
|
|||||||
|
function main(x: (u8, bool, u8)) {
|
||||||
|
console.log("x: {}", x);
|
||||||
|
}
|
@ -94,6 +94,16 @@ fn test_input_array_dimensions_mismatch() {
|
|||||||
expect_fail(program);
|
expect_fail(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_size_mismatch() {
|
||||||
|
let program_string = include_str!("main_tuple_fail.leo");
|
||||||
|
let input_string = include_str!("input/main_tuple_fail.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_field_input() {
|
fn test_field_input() {
|
||||||
let program_string = include_str!("main_field.leo");
|
let program_string = include_str!("main_field.leo");
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
a: bool = true;
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
x: [i16; 1] = [0i16; 1];
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
x: [i16; 1] = [0i16; 1];
|
@ -0,0 +1,5 @@
|
|||||||
|
[main]
|
||||||
|
a: bool = true;
|
||||||
|
|
||||||
|
[constants]
|
||||||
|
a: bool = false;
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
bad_name: bool = true;
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
a: u8 = 1;
|
@ -0,0 +1,3 @@
|
|||||||
|
[constants]
|
||||||
|
a: field = 1;
|
||||||
|
b: field = -1;
|
@ -0,0 +1,4 @@
|
|||||||
|
[constants]
|
||||||
|
a: group = 1group;
|
||||||
|
b: group = -1group;
|
||||||
|
c: group = (0, -1)group;
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
x: [i16; (2, 2, 3)] = [0i16; (2, 2, 3)];
|
@ -0,0 +1,3 @@
|
|||||||
|
[constants]
|
||||||
|
a: bool = true;
|
||||||
|
b: bool = false;
|
@ -0,0 +1,2 @@
|
|||||||
|
[main]
|
||||||
|
a: bool = true; // expecting const a, not main a
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)
|
@ -0,0 +1,2 @@
|
|||||||
|
[constants]
|
||||||
|
a: u8 = 10;
|
@ -0,0 +1,3 @@
|
|||||||
|
function main(const a: bool) {
|
||||||
|
console.assert(a == true);
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
function main (const x: [i16; 1]) {
|
||||||
|
console.log("{}", x);
|
||||||
|
console.assert(x[0] == 0);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
function main(const x: [i16; 2]){
|
||||||
|
console.log("x: {}", x);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
function main(const a: field, const b: field) {
|
||||||
|
// Change to assert when == is implemented for field.
|
||||||
|
console.log("a: {}", a);
|
||||||
|
console.log("b: {}", b);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
function main(const a: group, const b: group, const c: group) {
|
||||||
|
// Change to assert when == is implemented for group.
|
||||||
|
console.log("a: {}", a);
|
||||||
|
console.log("b: {}", b);
|
||||||
|
console.log("c: {}", c);
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
function main(const x: [i16; (2, 2, 3)]){
|
||||||
|
console.log("x: {}", x);
|
||||||
|
|
||||||
|
let y: [i16; (2, 2, 3)] = [0i16; (2, 2, 3)];
|
||||||
|
console.log("y: {}", y);
|
||||||
|
|
||||||
|
console.assert(x[0][0][0] == y[0][0][0]);
|
||||||
|
console.assert(x[1][1][2] == y[1][1][2]);
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
function main(const a: bool, const b: bool) {
|
||||||
|
console.assert(a == true);
|
||||||
|
console.assert(b == false);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
function main(const x: (u8, bool, u8)) {
|
||||||
|
console.log("x: {}", x);
|
||||||
|
}
|
145
compiler/tests/input_files/program_input_constants/mod.rs
Normal file
145
compiler/tests/input_files/program_input_constants/mod.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// 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::{assert_satisfied, expect_compiler_error, parse_program_with_input, EdwardsTestCompiler};
|
||||||
|
use leo_compiler::errors::CompilerError;
|
||||||
|
|
||||||
|
fn expect_fail(program: EdwardsTestCompiler) {
|
||||||
|
match expect_compiler_error(program) {
|
||||||
|
CompilerError::FunctionError(_) => {}
|
||||||
|
err => panic!("expected input parser error, got {:?}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_pass() {
|
||||||
|
let program_string = include_str!("main.leo");
|
||||||
|
let input_string = include_str!("input/main.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_array_fail() {
|
||||||
|
let program_string = include_str!("main_array.leo");
|
||||||
|
let input_string = include_str!("input/main_array.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_multi_dimension_array() {
|
||||||
|
let program_string = include_str!("main_multi_dimension_array.leo");
|
||||||
|
let input_string = include_str!("input/main_multi_dimension_array.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_fail_name() {
|
||||||
|
let program_string = include_str!("main.leo");
|
||||||
|
let input_string = include_str!("input/main_fail_name.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_fail_type() {
|
||||||
|
let program_string = include_str!("main.leo");
|
||||||
|
let input_string = include_str!("input/main_fail_type.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_multiple() {
|
||||||
|
let program_string = include_str!("main_multiple.leo");
|
||||||
|
let input_string = include_str!("input/main_multiple.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_array_dimensions_mismatch() {
|
||||||
|
let program_string = include_str!("main_array_fail.leo");
|
||||||
|
let input_string = include_str!("input/main_array_fail.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_double_declaration() {
|
||||||
|
let program_string = include_str!("main.leo");
|
||||||
|
let input_string = include_str!("input/main_double_declaration_fail.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_constant_input() {
|
||||||
|
let program_string = include_str!("main.leo");
|
||||||
|
let input_string = include_str!("input/main_not_const_input_fail.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_size_mismatch() {
|
||||||
|
let program_string = include_str!("main_tuple_fail.leo");
|
||||||
|
let input_string = include_str!("input/main_tuple_fail.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
expect_fail(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_field_input() {
|
||||||
|
let program_string = include_str!("main_field.leo");
|
||||||
|
let input_string = include_str!("input/main_field.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_group_input() {
|
||||||
|
let program_string = include_str!("main_group.leo");
|
||||||
|
let input_string = include_str!("input/main_group.in");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
7
compiler/tests/mutability/cond_mut.leo
Normal file
7
compiler/tests/mutability/cond_mut.leo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function main () {
|
||||||
|
let mut x = 100i8;
|
||||||
|
if false {
|
||||||
|
x = 1i8;
|
||||||
|
x *= 100i8;
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,14 @@ fn test_const_fail() {
|
|||||||
expect_asg_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cond_mut() {
|
||||||
|
let program_string = include_str!("cond_mut.leo");
|
||||||
|
let program = parse_program(program_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_array() {
|
fn test_array() {
|
||||||
let program_string = include_str!("array.leo");
|
let program_string = include_str!("array.leo");
|
||||||
|
9
compiler/tests/statements/conditional/cond_switch.leo
Normal file
9
compiler/tests/statements/conditional/cond_switch.leo
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
function main (x: bool) -> bool {
|
||||||
|
if false {
|
||||||
|
return x
|
||||||
|
} else if x {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
[main]
|
||||||
|
x: bool = true;
|
||||||
|
|
||||||
|
[registers]
|
||||||
|
r: bool = false;
|
@ -221,3 +221,16 @@ fn test_multiple_returns() {
|
|||||||
|
|
||||||
output_zero(program);
|
output_zero(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cond_switch() {
|
||||||
|
let input_string = include_str!("input/cond_switch.in");
|
||||||
|
let program_string = include_str!("cond_switch.leo");
|
||||||
|
let expect_output = include_bytes!("output/cond_switch.out");
|
||||||
|
|
||||||
|
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||||
|
|
||||||
|
let actual_output = get_output(program);
|
||||||
|
|
||||||
|
assert_eq!(expect_output, actual_output.bytes().as_slice());
|
||||||
|
}
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
[registers]
|
||||||
|
r: bool = false;
|
7
compiler/tests/statements/iteration_variable.leo
Normal file
7
compiler/tests/statements/iteration_variable.leo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function main() {
|
||||||
|
let x: u32 = 5;
|
||||||
|
|
||||||
|
for i in 0..x {
|
||||||
|
console.log("{}", i);
|
||||||
|
}
|
||||||
|
}
|
@ -81,3 +81,11 @@ fn test_iteration_input() {
|
|||||||
|
|
||||||
expect_asg_error(error);
|
expect_asg_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_iteration_variable() {
|
||||||
|
let program_string = include_str!("iteration_variable.leo");
|
||||||
|
let program = parse_program(program_string).unwrap();
|
||||||
|
|
||||||
|
assert_satisfied(program);
|
||||||
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
[main]
|
[main]
|
||||||
|
hash_input: [bool; 256] = [true; 256];
|
||||||
|
|
||||||
|
[constants]
|
||||||
|
parameters: [group; 256] = [1group; 256];
|
||||||
|
|
||||||
[registers]
|
[registers]
|
||||||
r0: group = (1, 0)group;
|
r0: group = (1, 0)group;
|
@ -18,10 +18,8 @@ circuit PedersenHash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The 'pedersen-hash' main function.
|
// The 'pedersen-hash' main function.
|
||||||
function main() -> group {
|
function main(hash_input: [bool; 256], const parameters: [group; 256]) -> group {
|
||||||
let parameters = [1group; 256];
|
|
||||||
let pedersen = PedersenHash::new(parameters);
|
let pedersen = PedersenHash::new(parameters);
|
||||||
let hash_input: [bool; 256] = [true; 256];
|
|
||||||
return pedersen.hash(hash_input)
|
return pedersen.hash(hash_input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl<'a> ImportParser<'a> {
|
|||||||
return self.parse_package(context, package.path(), remaining_segments, span);
|
return self.parse_package(context, package.path(), remaining_segments, span);
|
||||||
}
|
}
|
||||||
let program = Self::parse_import_file(package, span)?;
|
let program = Self::parse_import_file(package, span)?;
|
||||||
let asg = leo_asg::InternalProgram::new(context, &program, self)?;
|
let asg = leo_asg::Program::new(context, &program, self)?;
|
||||||
|
|
||||||
Ok(asg)
|
Ok(asg)
|
||||||
}
|
}
|
||||||
|
@ -210,11 +210,14 @@ registers = { "registers" }
|
|||||||
// Declared in sections/state.rs
|
// Declared in sections/state.rs
|
||||||
state = { "state" }
|
state = { "state" }
|
||||||
|
|
||||||
|
// Declared in sections/constants.rs
|
||||||
|
constants = { "constants" }
|
||||||
|
|
||||||
// Declared in sections/state_leaf.rs
|
// Declared in sections/state_leaf.rs
|
||||||
state_leaf = { "state_leaf" }
|
state_leaf = { "state_leaf" }
|
||||||
|
|
||||||
// Declared in sections/header.rs
|
// Declared in sections/header.rs
|
||||||
header = { main | record | registers | state_leaf | state | identifier }
|
header = { main | constants | record | registers | state_leaf | state | identifier }
|
||||||
|
|
||||||
/// Definitions
|
/// Definitions
|
||||||
|
|
||||||
|
27
input/src/sections/constants.rs
Normal file
27
input/src/sections/constants.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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::ast::Rule;
|
||||||
|
|
||||||
|
use pest::Span;
|
||||||
|
use pest_ast::FromPest;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
|
#[pest_ast(rule(Rule::constants))]
|
||||||
|
pub struct Constants<'ast> {
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::Rule,
|
ast::Rule,
|
||||||
common::Identifier,
|
common::Identifier,
|
||||||
sections::{Main, Record, Registers, State, StateLeaf},
|
sections::{Constants, Main, Record, Registers, State, StateLeaf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use pest::Span;
|
use pest::Span;
|
||||||
@ -27,6 +27,7 @@ use std::fmt;
|
|||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
#[pest_ast(rule(Rule::header))]
|
#[pest_ast(rule(Rule::header))]
|
||||||
pub enum Header<'ast> {
|
pub enum Header<'ast> {
|
||||||
|
Constants(Constants<'ast>),
|
||||||
Main(Main<'ast>),
|
Main(Main<'ast>),
|
||||||
Record(Record<'ast>),
|
Record(Record<'ast>),
|
||||||
Registers(Registers<'ast>),
|
Registers(Registers<'ast>),
|
||||||
@ -38,6 +39,7 @@ pub enum Header<'ast> {
|
|||||||
impl<'ast> Header<'ast> {
|
impl<'ast> Header<'ast> {
|
||||||
pub fn span(self) -> Span<'ast> {
|
pub fn span(self) -> Span<'ast> {
|
||||||
match self {
|
match self {
|
||||||
|
Header::Constants(constants) => constants.span,
|
||||||
Header::Main(main) => main.span,
|
Header::Main(main) => main.span,
|
||||||
Header::Record(record) => record.span,
|
Header::Record(record) => record.span,
|
||||||
Header::Registers(registers) => registers.span,
|
Header::Registers(registers) => registers.span,
|
||||||
@ -51,6 +53,7 @@ impl<'ast> Header<'ast> {
|
|||||||
impl<'ast> fmt::Display for Header<'ast> {
|
impl<'ast> fmt::Display for Header<'ast> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Header::Constants(_constants) => write!(f, "constants"),
|
||||||
Header::Main(_main) => write!(f, "main"),
|
Header::Main(_main) => write!(f, "main"),
|
||||||
Header::Record(_record) => write!(f, "record"),
|
Header::Record(_record) => write!(f, "record"),
|
||||||
Header::Registers(_registers) => write!(f, "registers"),
|
Header::Registers(_registers) => write!(f, "registers"),
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
pub mod constants;
|
||||||
|
pub use constants::*;
|
||||||
|
|
||||||
pub mod header;
|
pub mod header;
|
||||||
pub use header::*;
|
pub use header::*;
|
||||||
|
|
||||||
|
@ -507,7 +507,7 @@ impl ParserContext {
|
|||||||
/// Returns an [`Expression`] AST node if the next tokens represent an
|
/// Returns an [`Expression`] AST node if the next tokens represent an
|
||||||
/// circuit initialization expression.
|
/// circuit initialization expression.
|
||||||
///
|
///
|
||||||
pub fn parse_circuit_init(&mut self, ident: Identifier) -> SyntaxResult<Expression> {
|
pub fn parse_circuit_init(&mut self, identifier: Identifier) -> SyntaxResult<Expression> {
|
||||||
self.expect(Token::LeftCurly)?;
|
self.expect(Token::LeftCurly)?;
|
||||||
let mut members = vec![];
|
let mut members = vec![];
|
||||||
let end_span;
|
let end_span;
|
||||||
@ -535,8 +535,8 @@ impl ParserContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Expression::CircuitInit(CircuitInitExpression {
|
Ok(Expression::CircuitInit(CircuitInitExpression {
|
||||||
span: &ident.span + &end_span,
|
span: &identifier.span + &end_span,
|
||||||
name: ident,
|
name: identifier,
|
||||||
members,
|
members,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -309,11 +309,16 @@ impl ParserContext {
|
|||||||
///
|
///
|
||||||
pub fn parse_function_input(&mut self) -> SyntaxResult<FunctionInput> {
|
pub fn parse_function_input(&mut self) -> SyntaxResult<FunctionInput> {
|
||||||
if let Some(token) = self.eat(Token::Input) {
|
if let Some(token) = self.eat(Token::Input) {
|
||||||
return Ok(FunctionInput::InputKeyword(InputKeyword { span: token.span }));
|
return Ok(FunctionInput::InputKeyword(InputKeyword {
|
||||||
|
identifier: Identifier {
|
||||||
|
name: token.token.to_string(),
|
||||||
|
span: token.span,
|
||||||
|
},
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
let const_ = self.eat(Token::Const);
|
let const_ = self.eat(Token::Const);
|
||||||
let mutable = self.eat(Token::Mut);
|
let mutable = self.eat(Token::Mut);
|
||||||
let name = if let Some(token) = self.eat(Token::LittleSelf) {
|
let mut name = if let Some(token) = self.eat(Token::LittleSelf) {
|
||||||
Identifier {
|
Identifier {
|
||||||
name: token.token.to_string(),
|
name: token.token.to_string(),
|
||||||
span: token.span,
|
span: token.span,
|
||||||
@ -326,11 +331,11 @@ impl ParserContext {
|
|||||||
//error
|
//error
|
||||||
}
|
}
|
||||||
if let Some(mutable) = &mutable {
|
if let Some(mutable) = &mutable {
|
||||||
return Ok(FunctionInput::MutSelfKeyword(MutSelfKeyword {
|
name.span = &mutable.span + &name.span;
|
||||||
span: &mutable.span + &name.span,
|
name.name = "mut self".to_string();
|
||||||
}));
|
return Ok(FunctionInput::MutSelfKeyword(MutSelfKeyword { identifier: name }));
|
||||||
}
|
}
|
||||||
return Ok(FunctionInput::SelfKeyword(SelfKeyword { span: name.span }));
|
return Ok(FunctionInput::SelfKeyword(SelfKeyword { identifier: name }));
|
||||||
}
|
}
|
||||||
self.expect(Token::Colon)?;
|
self.expect(Token::Colon)?;
|
||||||
let type_ = self.parse_type()?.0;
|
let type_ = self.parse_type()?.0;
|
||||||
|
@ -113,19 +113,20 @@ impl<E: PairingEngine> ConstraintSystem<E::Fr> for CircuitSynthesizer<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pop_namespace(&mut self) {
|
fn pop_namespace(&mut self) {
|
||||||
if let Some(ns) = self.namespaces.pop() {
|
// Todo @ljedrz: Fix constraint system optimizations.
|
||||||
for idx in ns.constraint_indices {
|
// if let Some(ns) = self.namespaces.pop() {
|
||||||
self.constraints.remove(idx);
|
// for idx in ns.constraint_indices {
|
||||||
}
|
// self.constraints.remove(idx);
|
||||||
|
// }
|
||||||
for idx in ns.private_var_indices {
|
//
|
||||||
self.private_variables.remove(idx);
|
// for idx in ns.private_var_indices {
|
||||||
}
|
// self.private_variables.remove(idx);
|
||||||
|
// }
|
||||||
for idx in ns.public_var_indices {
|
//
|
||||||
self.public_variables.remove(idx);
|
// for idx in ns.public_var_indices {
|
||||||
}
|
// self.public_variables.remove(idx);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_root(&mut self) -> &mut Self::Root {
|
fn get_root(&mut self) -> &mut Self::Root {
|
||||||
|
Loading…
Reference in New Issue
Block a user