mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-28 04:35:33 +03:00
Merge pull request #793 from AleoHQ/feature/canonicalization-before-asg
Feature/canonicalization before asg
This commit is contained in:
commit
3e3a63d97b
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -13,9 +13,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
checksum = "bedc89c5c7b5550ffb9372eb5c5ffc7f9f705cc3f4a128bd4669b9745f555093"
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
@ -188,7 +188,7 @@ dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array 0.12.4",
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -577,7 +577,7 @@ version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array 0.12.4",
|
||||
"generic-array 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -846,9 +846,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
|
||||
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
@ -908,9 +908,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d832b01df74254fe364568d6ddc294443f61cbec82816b60904303af87efae78"
|
||||
checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@ -923,6 +923,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1162,9 +1163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.48"
|
||||
version = "0.3.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
|
||||
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@ -1217,6 +1218,7 @@ dependencies = [
|
||||
name = "leo-ast"
|
||||
version = "1.2.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"criterion",
|
||||
"indexmap",
|
||||
"leo-input",
|
||||
@ -1875,9 +1877,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.6"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
@ -2382,9 +2384,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
checksum = "43535db9747a4ba938c0ce0a98cc631a46ebf943c9e1d604e091df6007620bf6"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -2935,6 +2937,16 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.2"
|
||||
@ -3124,9 +3136,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.71"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
|
||||
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"serde",
|
||||
@ -3136,9 +3148,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.71"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
|
||||
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
@ -3151,9 +3163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.21"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e67a5806118af01f0d9045915676b22aaebecf4178ae7021bc171dab0b897ab"
|
||||
checksum = "3de431a2910c86679c34283a33f66f4e4abd7e0aec27b6669060148872aadf94"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
@ -3163,9 +3175,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.71"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
|
||||
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||
dependencies = [
|
||||
"quote 1.0.9",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -3173,9 +3185,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.71"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
|
||||
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.9",
|
||||
@ -3186,15 +3198,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.71"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
|
||||
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.48"
|
||||
version = "0.3.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
|
||||
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@ -3273,9 +3285,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.11"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8264fcea9b7a036a4a5103d7153e988dbc2ebbafb34f68a3c2d404b6b82d74b6"
|
||||
checksum = "5a8977234acab718eb2820494b2f96cbb16004c19dddf88b7445b27381450997"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
|
@ -22,6 +22,9 @@
|
||||
//! A new [`Asg`] type can be created from an [`Ast`].
|
||||
//! Converting to an [`Asg`] provides greater type safety by canonicalizing and checking program types.
|
||||
|
||||
#![allow(clippy::from_over_into)]
|
||||
#![allow(clippy::result_unit_err)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
|
@ -68,35 +68,50 @@ impl<'a> Circuit<'a> {
|
||||
|
||||
let mut members = circuit.members.borrow_mut();
|
||||
for member in value.members.iter() {
|
||||
match member {
|
||||
leo_ast::CircuitMember::CircuitVariable(name, type_) => {
|
||||
if members.contains_key(&name.name) {
|
||||
return Err(AsgConvertError::redefined_circuit_member(
|
||||
&value.circuit_name.name,
|
||||
&name.name,
|
||||
&name.span,
|
||||
));
|
||||
}
|
||||
members.insert(
|
||||
name.name.clone(),
|
||||
CircuitMember::Variable(new_scope.resolve_ast_type(type_)?),
|
||||
);
|
||||
if let leo_ast::CircuitMember::CircuitVariable(name, type_) = member {
|
||||
if members.contains_key(&name.name) {
|
||||
return Err(AsgConvertError::redefined_circuit_member(
|
||||
&value.circuit_name.name,
|
||||
&name.name,
|
||||
&name.span,
|
||||
));
|
||||
}
|
||||
leo_ast::CircuitMember::CircuitFunction(function) => {
|
||||
if members.contains_key(&function.identifier.name) {
|
||||
return Err(AsgConvertError::redefined_circuit_member(
|
||||
&value.circuit_name.name,
|
||||
&function.identifier.name,
|
||||
&function.identifier.span,
|
||||
));
|
||||
}
|
||||
let asg_function = Function::init(new_scope, function)?;
|
||||
asg_function.circuit.replace(Some(circuit));
|
||||
if asg_function.is_test() {
|
||||
return Err(AsgConvertError::circuit_test_function(&function.identifier.span));
|
||||
}
|
||||
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
|
||||
members.insert(
|
||||
name.name.clone(),
|
||||
CircuitMember::Variable(new_scope.resolve_ast_type(type_)?),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(circuit)
|
||||
}
|
||||
|
||||
pub(super) fn init_member(
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::Circuit,
|
||||
) -> Result<&'a Circuit<'a>, AsgConvertError> {
|
||||
let new_scope = scope.make_subscope();
|
||||
let circuits = scope.circuits.borrow();
|
||||
|
||||
let circuit = circuits.get(&value.circuit_name.name).unwrap();
|
||||
new_scope.circuit_self.replace(Some(circuit));
|
||||
|
||||
let mut members = circuit.members.borrow_mut();
|
||||
for member in value.members.iter() {
|
||||
if let leo_ast::CircuitMember::CircuitFunction(function) = member {
|
||||
if members.contains_key(&function.identifier.name) {
|
||||
return Err(AsgConvertError::redefined_circuit_member(
|
||||
&value.circuit_name.name,
|
||||
&function.identifier.name,
|
||||
&function.identifier.span,
|
||||
));
|
||||
}
|
||||
let asg_function = Function::init(new_scope, function)?;
|
||||
asg_function.circuit.replace(Some(circuit));
|
||||
if asg_function.is_test() {
|
||||
return Err(AsgConvertError::circuit_test_function(&function.identifier.span));
|
||||
}
|
||||
members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,6 +243,14 @@ impl<'a> Program<'a> {
|
||||
scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit);
|
||||
}
|
||||
|
||||
// Second pass for circuit members.
|
||||
for (name, circuit) in program.circuits.iter() {
|
||||
assert_eq!(name.name, circuit.circuit_name.name);
|
||||
let asg_circuit = Circuit::init_member(scope, circuit)?;
|
||||
|
||||
scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit);
|
||||
}
|
||||
|
||||
for (name, function) in program.functions.iter() {
|
||||
assert_eq!(name.name, function.identifier.name);
|
||||
let function = Function::init(scope, function)?;
|
||||
|
@ -35,6 +35,9 @@ features = ["derive", "rc"]
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.anyhow]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.thiserror]
|
||||
version = "1.0"
|
||||
|
||||
|
@ -19,6 +19,10 @@
|
||||
//! This module contains the [`Ast`] type, a wrapper around the [`Program`] type.
|
||||
//! The [`Ast`] type is intended to be parsed and modified by different passes
|
||||
//! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`Ast`].
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod annotation;
|
||||
pub use self::annotation::*;
|
||||
|
||||
@ -49,6 +53,9 @@ pub use self::input::*;
|
||||
pub mod program;
|
||||
pub use self::program::*;
|
||||
|
||||
pub mod reducer;
|
||||
pub use self::reducer::*;
|
||||
|
||||
pub mod statements;
|
||||
pub use self::statements::*;
|
||||
|
||||
@ -75,6 +82,12 @@ impl Ast {
|
||||
Self { ast: program }
|
||||
}
|
||||
|
||||
/// Mutates the program ast by preforming canonicalization on it.
|
||||
pub fn canonicalize(&mut self) -> Result<(), CanonicalizeError> {
|
||||
self.ast = ReconstructingDirector::new(Canonicalizer::default()).reduce_program(self.as_repr())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner program AST representation.
|
||||
pub fn as_repr(&self) -> &Program {
|
||||
&self.ast
|
||||
|
554
ast/src/reducer/canonicalization.rs
Normal file
554
ast/src/reducer/canonicalization.rs
Normal file
@ -0,0 +1,554 @@
|
||||
// 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::*;
|
||||
|
||||
/// Replace Self when it is in a enclosing circuit type.
|
||||
/// Error when Self is outside an enclosing circuit type.
|
||||
/// Tuple array types and expressions expand to nested arrays.
|
||||
/// Tuple array types and expressions error if a size of 0 is given.anyhow
|
||||
/// Compound operators become simple assignments.
|
||||
/// Functions missing output type return a empty tuple.
|
||||
pub struct Canonicalizer {
|
||||
// If we are in a circuit keep track of the circuit name.
|
||||
circuit_name: Option<Identifier>,
|
||||
}
|
||||
|
||||
impl Canonicalizer {
|
||||
pub fn default() -> Self {
|
||||
Self { circuit_name: None }
|
||||
}
|
||||
|
||||
fn is_self_type(&mut self, type_option: Option<&Type>) -> bool {
|
||||
matches!(type_option, Some(Type::SelfType))
|
||||
}
|
||||
|
||||
fn canonicalize_expression(&mut self, expression: &Expression) -> Expression {
|
||||
match expression {
|
||||
Expression::Unary(unary) => {
|
||||
let inner = Box::new(self.canonicalize_expression(&unary.inner));
|
||||
|
||||
return Expression::Unary(UnaryExpression {
|
||||
inner,
|
||||
op: unary.op.clone(),
|
||||
span: unary.span.clone(),
|
||||
});
|
||||
}
|
||||
Expression::Binary(binary) => {
|
||||
let left = Box::new(self.canonicalize_expression(&binary.left));
|
||||
let right = Box::new(self.canonicalize_expression(&binary.right));
|
||||
|
||||
return Expression::Binary(BinaryExpression {
|
||||
left,
|
||||
right,
|
||||
op: binary.op.clone(),
|
||||
span: binary.span.clone(),
|
||||
});
|
||||
}
|
||||
Expression::Ternary(ternary) => {
|
||||
let condition = Box::new(self.canonicalize_expression(&ternary.condition));
|
||||
let if_true = Box::new(self.canonicalize_expression(&ternary.if_true));
|
||||
let if_false = Box::new(self.canonicalize_expression(&ternary.if_false));
|
||||
|
||||
return Expression::Ternary(TernaryExpression {
|
||||
condition,
|
||||
if_true,
|
||||
if_false,
|
||||
span: ternary.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::Cast(cast) => {
|
||||
let inner = Box::new(self.canonicalize_expression(&cast.inner));
|
||||
let mut target_type = cast.target_type.clone();
|
||||
|
||||
if matches!(target_type, Type::SelfType) {
|
||||
target_type = Type::Circuit(self.circuit_name.as_ref().unwrap().clone());
|
||||
}
|
||||
|
||||
return Expression::Cast(CastExpression {
|
||||
inner,
|
||||
target_type,
|
||||
span: cast.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::ArrayInline(array_inline) => {
|
||||
let elements = array_inline
|
||||
.elements
|
||||
.iter()
|
||||
.map(|element| match element {
|
||||
SpreadOrExpression::Expression(expression) => {
|
||||
SpreadOrExpression::Expression(self.canonicalize_expression(expression))
|
||||
}
|
||||
SpreadOrExpression::Spread(expression) => {
|
||||
SpreadOrExpression::Spread(self.canonicalize_expression(expression))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
return Expression::ArrayInline(ArrayInlineExpression {
|
||||
elements,
|
||||
span: array_inline.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::ArrayInit(array_init) => {
|
||||
let element = Box::new(self.canonicalize_expression(&array_init.element));
|
||||
|
||||
return Expression::ArrayInit(ArrayInitExpression {
|
||||
dimensions: array_init.dimensions.clone(),
|
||||
element,
|
||||
span: array_init.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::ArrayAccess(array_access) => {
|
||||
let array = Box::new(self.canonicalize_expression(&array_access.array));
|
||||
let index = Box::new(self.canonicalize_expression(&array_access.index));
|
||||
|
||||
return Expression::ArrayAccess(ArrayAccessExpression {
|
||||
array,
|
||||
index,
|
||||
span: array_access.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::ArrayRangeAccess(array_range_access) => {
|
||||
let array = Box::new(self.canonicalize_expression(&array_range_access.array));
|
||||
let left = array_range_access
|
||||
.left
|
||||
.as_ref()
|
||||
.map(|left| Box::new(self.canonicalize_expression(left)));
|
||||
let right = array_range_access
|
||||
.right
|
||||
.as_ref()
|
||||
.map(|right| Box::new(self.canonicalize_expression(right)));
|
||||
|
||||
return Expression::ArrayRangeAccess(ArrayRangeAccessExpression {
|
||||
array,
|
||||
left,
|
||||
right,
|
||||
span: array_range_access.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::TupleInit(tuple_init) => {
|
||||
let elements = tuple_init
|
||||
.elements
|
||||
.iter()
|
||||
.map(|element| self.canonicalize_expression(element))
|
||||
.collect();
|
||||
|
||||
return Expression::TupleInit(TupleInitExpression {
|
||||
elements,
|
||||
span: tuple_init.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::TupleAccess(tuple_access) => {
|
||||
let tuple = Box::new(self.canonicalize_expression(&tuple_access.tuple));
|
||||
|
||||
return Expression::TupleAccess(TupleAccessExpression {
|
||||
tuple,
|
||||
index: tuple_access.index.clone(),
|
||||
span: tuple_access.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
Expression::CircuitInit(circuit_init) => {
|
||||
let mut name = circuit_init.name.clone();
|
||||
if name.name == *"Self" {
|
||||
name = self.circuit_name.as_ref().unwrap().clone();
|
||||
}
|
||||
|
||||
return Expression::CircuitInit(CircuitInitExpression {
|
||||
name,
|
||||
members: circuit_init.members.clone(),
|
||||
span: circuit_init.span.clone(),
|
||||
});
|
||||
}
|
||||
Expression::CircuitMemberAccess(circuit_member_access) => {
|
||||
return Expression::CircuitMemberAccess(CircuitMemberAccessExpression {
|
||||
circuit: Box::new(self.canonicalize_expression(&circuit_member_access.circuit)),
|
||||
name: circuit_member_access.name.clone(),
|
||||
span: circuit_member_access.span.clone(),
|
||||
});
|
||||
}
|
||||
Expression::CircuitStaticFunctionAccess(circuit_static_func_access) => {
|
||||
return Expression::CircuitStaticFunctionAccess(CircuitStaticFunctionAccessExpression {
|
||||
circuit: Box::new(self.canonicalize_expression(&circuit_static_func_access.circuit)),
|
||||
name: circuit_static_func_access.name.clone(),
|
||||
span: circuit_static_func_access.span.clone(),
|
||||
});
|
||||
}
|
||||
Expression::Call(call) => {
|
||||
return Expression::Call(CallExpression {
|
||||
function: Box::new(self.canonicalize_expression(&call.function)),
|
||||
arguments: call.arguments.clone(),
|
||||
span: call.span.clone(),
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
expression.clone()
|
||||
}
|
||||
|
||||
fn canonicalize_assignee_access(&mut self, access: &AssigneeAccess) -> AssigneeAccess {
|
||||
match access {
|
||||
AssigneeAccess::ArrayRange(left, right) => {
|
||||
let left = left.as_ref().map(|left| self.canonicalize_expression(left));
|
||||
let right = right.as_ref().map(|right| self.canonicalize_expression(right));
|
||||
|
||||
AssigneeAccess::ArrayRange(left, right)
|
||||
}
|
||||
AssigneeAccess::ArrayIndex(index) => AssigneeAccess::ArrayIndex(self.canonicalize_expression(&index)),
|
||||
_ => access.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn canonicalize_assignee(&mut self, assignee: &Assignee) -> Assignee {
|
||||
let accesses = assignee
|
||||
.accesses
|
||||
.iter()
|
||||
.map(|access| self.canonicalize_assignee_access(access))
|
||||
.collect();
|
||||
|
||||
Assignee {
|
||||
identifier: assignee.identifier.clone(),
|
||||
accesses,
|
||||
span: assignee.span.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn canonicalize_block(&mut self, block: &Block) -> Block {
|
||||
let statements = block
|
||||
.statements
|
||||
.iter()
|
||||
.map(|block_statement| self.canonicalize_statement(&block_statement))
|
||||
.collect();
|
||||
|
||||
Block {
|
||||
statements,
|
||||
span: block.span.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn canonicalize_statement(&mut self, statement: &Statement) -> Statement {
|
||||
match statement {
|
||||
Statement::Return(return_statement) => {
|
||||
let expression = self.canonicalize_expression(&return_statement.expression);
|
||||
Statement::Return(ReturnStatement {
|
||||
expression,
|
||||
span: return_statement.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Definition(definition) => {
|
||||
let value = self.canonicalize_expression(&definition.value);
|
||||
let mut type_ = definition.type_.clone();
|
||||
|
||||
if self.is_self_type(type_.as_ref()) {
|
||||
type_ = Some(Type::Circuit(self.circuit_name.as_ref().unwrap().clone()));
|
||||
}
|
||||
|
||||
Statement::Definition(DefinitionStatement {
|
||||
declaration_type: definition.declaration_type.clone(),
|
||||
variable_names: definition.variable_names.clone(),
|
||||
type_,
|
||||
value,
|
||||
span: definition.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Assign(assign) => {
|
||||
let assignee = self.canonicalize_assignee(&assign.assignee);
|
||||
let value = self.canonicalize_expression(&assign.value);
|
||||
|
||||
Statement::Assign(AssignStatement {
|
||||
assignee,
|
||||
value,
|
||||
operation: assign.operation.clone(),
|
||||
span: assign.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Conditional(conditional) => {
|
||||
let condition = self.canonicalize_expression(&conditional.condition);
|
||||
let block = self.canonicalize_block(&conditional.block);
|
||||
let next = conditional
|
||||
.next
|
||||
.as_ref()
|
||||
.map(|condition| Box::new(self.canonicalize_statement(condition)));
|
||||
|
||||
Statement::Conditional(ConditionalStatement {
|
||||
condition,
|
||||
block,
|
||||
next,
|
||||
span: conditional.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Iteration(iteration) => {
|
||||
let start = self.canonicalize_expression(&iteration.start);
|
||||
let stop = self.canonicalize_expression(&iteration.stop);
|
||||
let block = self.canonicalize_block(&iteration.block);
|
||||
|
||||
Statement::Iteration(IterationStatement {
|
||||
variable: iteration.variable.clone(),
|
||||
start,
|
||||
stop,
|
||||
block,
|
||||
span: iteration.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Console(console_function_call) => {
|
||||
let function = match &console_function_call.function {
|
||||
ConsoleFunction::Assert(expression) => {
|
||||
ConsoleFunction::Assert(self.canonicalize_expression(expression))
|
||||
}
|
||||
ConsoleFunction::Debug(format) | ConsoleFunction::Error(format) | ConsoleFunction::Log(format) => {
|
||||
let parameters = format
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|parameter| self.canonicalize_expression(parameter))
|
||||
.collect();
|
||||
|
||||
let formatted = FormattedString {
|
||||
parts: format.parts.clone(),
|
||||
parameters,
|
||||
span: format.span.clone(),
|
||||
};
|
||||
|
||||
match &console_function_call.function {
|
||||
ConsoleFunction::Debug(_) => ConsoleFunction::Debug(formatted),
|
||||
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
|
||||
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
|
||||
_ => unimplemented!(), // impossible
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Statement::Console(ConsoleStatement {
|
||||
function,
|
||||
span: console_function_call.span.clone(),
|
||||
})
|
||||
}
|
||||
Statement::Expression(expression) => Statement::Expression(ExpressionStatement {
|
||||
expression: self.canonicalize_expression(&expression.expression),
|
||||
span: expression.span.clone(),
|
||||
}),
|
||||
Statement::Block(block) => Statement::Block(self.canonicalize_block(block)),
|
||||
}
|
||||
}
|
||||
|
||||
fn canonicalize_circuit_member(&mut self, circuit_member: &CircuitMember) -> CircuitMember {
|
||||
match circuit_member {
|
||||
CircuitMember::CircuitVariable(_, _) => {}
|
||||
CircuitMember::CircuitFunction(function) => {
|
||||
let input = function.input.clone();
|
||||
let mut output = function.output.clone();
|
||||
let block = self.canonicalize_block(&function.block);
|
||||
|
||||
if self.is_self_type(output.as_ref()) {
|
||||
output = Some(Type::Circuit(self.circuit_name.as_ref().unwrap().clone()));
|
||||
}
|
||||
|
||||
return CircuitMember::CircuitFunction(Function {
|
||||
annotations: function.annotations.clone(),
|
||||
identifier: function.identifier.clone(),
|
||||
input,
|
||||
output,
|
||||
block,
|
||||
span: function.span.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
circuit_member.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReconstructingReducer for Canonicalizer {
|
||||
fn reduce_type(
|
||||
&mut self,
|
||||
_type_: &Type,
|
||||
new: Type,
|
||||
in_circuit: bool,
|
||||
span: &Span,
|
||||
) -> Result<Type, CanonicalizeError> {
|
||||
match new {
|
||||
Type::Array(type_, mut dimensions) => {
|
||||
if dimensions.is_zero() {
|
||||
return Err(CanonicalizeError::invalid_array_dimension_size(span));
|
||||
}
|
||||
|
||||
let mut next = Type::Array(type_, ArrayDimensions(vec![dimensions.remove_last().unwrap()]));
|
||||
let mut array = next.clone();
|
||||
|
||||
loop {
|
||||
if dimensions.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
array = Type::Array(Box::new(next), ArrayDimensions(vec![dimensions.remove_last().unwrap()]));
|
||||
next = array.clone();
|
||||
}
|
||||
|
||||
Ok(array)
|
||||
}
|
||||
Type::SelfType if !in_circuit => Err(CanonicalizeError::big_self_outside_of_circuit(span)),
|
||||
_ => Ok(new.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce_array_init(
|
||||
&mut self,
|
||||
array_init: &ArrayInitExpression,
|
||||
element: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ArrayInitExpression, CanonicalizeError> {
|
||||
if array_init.dimensions.is_zero() {
|
||||
return Err(CanonicalizeError::invalid_array_dimension_size(&array_init.span));
|
||||
}
|
||||
|
||||
let element = Box::new(element);
|
||||
|
||||
if array_init.dimensions.0.len() == 1 {
|
||||
return Ok(ArrayInitExpression {
|
||||
element,
|
||||
dimensions: array_init.dimensions.clone(),
|
||||
span: array_init.span.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
let mut dimensions = array_init.dimensions.clone();
|
||||
|
||||
let mut next = Expression::ArrayInit(ArrayInitExpression {
|
||||
element,
|
||||
dimensions: ArrayDimensions(vec![dimensions.remove_last().unwrap()]),
|
||||
span: array_init.span.clone(),
|
||||
});
|
||||
|
||||
let mut outer_element = Box::new(next.clone());
|
||||
for (index, dimension) in dimensions.0.iter().rev().enumerate() {
|
||||
if index == dimensions.0.len() - 1 {
|
||||
break;
|
||||
}
|
||||
|
||||
next = Expression::ArrayInit(ArrayInitExpression {
|
||||
element: outer_element,
|
||||
dimensions: ArrayDimensions(vec![dimension.clone()]),
|
||||
span: array_init.span.clone(),
|
||||
});
|
||||
outer_element = Box::new(next.clone());
|
||||
}
|
||||
|
||||
Ok(ArrayInitExpression {
|
||||
element: outer_element,
|
||||
dimensions: ArrayDimensions(vec![dimensions.remove_first().unwrap()]),
|
||||
span: array_init.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_assign(
|
||||
&mut self,
|
||||
assign: &AssignStatement,
|
||||
assignee: Assignee,
|
||||
value: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<AssignStatement, CanonicalizeError> {
|
||||
match value {
|
||||
Expression::Value(value_expr) if assign.operation != AssignOperation::Assign => {
|
||||
let left = Box::new(Expression::Identifier(assignee.identifier.clone()));
|
||||
let right = Box::new(Expression::Value(value_expr));
|
||||
|
||||
let op = match assign.operation {
|
||||
AssignOperation::Assign => unimplemented!(), // Imposible
|
||||
AssignOperation::Add => BinaryOperation::Add,
|
||||
AssignOperation::Sub => BinaryOperation::Sub,
|
||||
AssignOperation::Mul => BinaryOperation::Mul,
|
||||
AssignOperation::Div => BinaryOperation::Div,
|
||||
AssignOperation::Pow => BinaryOperation::Pow,
|
||||
AssignOperation::Or => BinaryOperation::Or,
|
||||
AssignOperation::And => BinaryOperation::And,
|
||||
AssignOperation::BitOr => BinaryOperation::BitOr,
|
||||
AssignOperation::BitAnd => BinaryOperation::BitAnd,
|
||||
AssignOperation::BitXor => BinaryOperation::BitXor,
|
||||
AssignOperation::Shr => BinaryOperation::Shr,
|
||||
AssignOperation::ShrSigned => BinaryOperation::ShrSigned,
|
||||
AssignOperation::Shl => BinaryOperation::Shl,
|
||||
AssignOperation::Mod => BinaryOperation::Mod,
|
||||
};
|
||||
|
||||
let new_value = Expression::Binary(BinaryExpression {
|
||||
left,
|
||||
right,
|
||||
op,
|
||||
span: assign.span.clone(),
|
||||
});
|
||||
|
||||
Ok(AssignStatement {
|
||||
operation: AssignOperation::Assign,
|
||||
assignee,
|
||||
value: new_value,
|
||||
span: assign.span.clone(),
|
||||
})
|
||||
}
|
||||
_ => Ok(assign.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce_function(
|
||||
&mut self,
|
||||
function: &Function,
|
||||
identifier: Identifier,
|
||||
annotations: Vec<Annotation>,
|
||||
input: Vec<FunctionInput>,
|
||||
output: Option<Type>,
|
||||
block: Block,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Function, CanonicalizeError> {
|
||||
let new_output = match output {
|
||||
None => Some(Type::Tuple(vec![])),
|
||||
_ => output,
|
||||
};
|
||||
|
||||
Ok(Function {
|
||||
identifier,
|
||||
annotations,
|
||||
input,
|
||||
output: new_output,
|
||||
block,
|
||||
span: function.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit(
|
||||
&mut self,
|
||||
_circuit: &Circuit,
|
||||
circuit_name: Identifier,
|
||||
members: Vec<CircuitMember>,
|
||||
) -> Result<Circuit, CanonicalizeError> {
|
||||
self.circuit_name = Some(circuit_name.clone());
|
||||
let circ = Circuit {
|
||||
circuit_name,
|
||||
members: members
|
||||
.iter()
|
||||
.map(|member| self.canonicalize_circuit_member(member))
|
||||
.collect(),
|
||||
};
|
||||
self.circuit_name = None;
|
||||
Ok(circ)
|
||||
}
|
||||
}
|
41
ast/src/reducer/errors.rs
Normal file
41
ast/src/reducer/errors.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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::{FormattedError, Span};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CanonicalizeError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
}
|
||||
|
||||
impl CanonicalizeError {
|
||||
fn new_from_span(message: String, span: &Span) -> Self {
|
||||
CanonicalizeError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn big_self_outside_of_circuit(span: &Span) -> Self {
|
||||
let message = "cannot call keyword `Self` outside of a circuit function".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_array_dimension_size(span: &Span) -> Self {
|
||||
let message = "recieved dimension size of 0, expected it to be 1 or larger.".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
27
ast/src/reducer/mod.rs
Normal file
27
ast/src/reducer/mod.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/>.
|
||||
|
||||
mod canonicalization;
|
||||
pub use canonicalization::*;
|
||||
|
||||
mod errors;
|
||||
pub use errors::*;
|
||||
|
||||
mod reconstructing_reducer;
|
||||
pub use reconstructing_reducer::*;
|
||||
|
||||
mod reconstructing_director;
|
||||
pub use reconstructing_director::*;
|
599
ast/src/reducer/reconstructing_director.rs
Normal file
599
ast/src/reducer/reconstructing_director.rs
Normal file
@ -0,0 +1,599 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! This module contains the reducer which iterates through ast nodes - converting them into
|
||||
//! asg nodes and saving relevant information.
|
||||
|
||||
use crate::*;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub struct ReconstructingDirector<R: ReconstructingReducer> {
|
||||
reducer: R,
|
||||
in_circuit: bool,
|
||||
}
|
||||
|
||||
impl<R: ReconstructingReducer> ReconstructingDirector<R> {
|
||||
pub fn new(reducer: R) -> Self {
|
||||
Self {
|
||||
reducer,
|
||||
in_circuit: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reduce_type(&mut self, type_: &Type, span: &Span) -> Result<Type, CanonicalizeError> {
|
||||
let new = match type_ {
|
||||
Type::Array(type_, dimensions) => Type::Array(Box::new(self.reduce_type(type_, span)?), dimensions.clone()),
|
||||
Type::Tuple(types) => {
|
||||
let mut reduced_types = vec![];
|
||||
for type_ in types.iter() {
|
||||
reduced_types.push(self.reduce_type(type_, span)?);
|
||||
}
|
||||
|
||||
Type::Tuple(reduced_types)
|
||||
}
|
||||
Type::Circuit(identifier) => Type::Circuit(self.reduce_identifier(identifier)?),
|
||||
_ => type_.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_type(type_, new, self.in_circuit, span)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
pub fn reduce_expression(&mut self, expression: &Expression) -> Result<Expression, CanonicalizeError> {
|
||||
let new = match expression {
|
||||
Expression::Identifier(identifier) => Expression::Identifier(self.reduce_identifier(&identifier)?),
|
||||
Expression::Value(value) => Expression::Value(self.reduce_value(&value)?),
|
||||
Expression::Binary(binary) => Expression::Binary(self.reduce_binary(&binary)?),
|
||||
Expression::Unary(unary) => Expression::Unary(self.reduce_unary(&unary)?),
|
||||
Expression::Ternary(ternary) => Expression::Ternary(self.reduce_ternary(&ternary)?),
|
||||
Expression::Cast(cast) => Expression::Cast(self.reduce_cast(&cast)?),
|
||||
|
||||
Expression::ArrayInline(array_inline) => Expression::ArrayInline(self.reduce_array_inline(&array_inline)?),
|
||||
Expression::ArrayInit(array_init) => Expression::ArrayInit(self.reduce_array_init(&array_init)?),
|
||||
Expression::ArrayAccess(array_access) => Expression::ArrayAccess(self.reduce_array_access(&array_access)?),
|
||||
Expression::ArrayRangeAccess(array_range_access) => {
|
||||
Expression::ArrayRangeAccess(self.reduce_array_range_access(&array_range_access)?)
|
||||
}
|
||||
|
||||
Expression::TupleInit(tuple_init) => Expression::TupleInit(self.reduce_tuple_init(&tuple_init)?),
|
||||
Expression::TupleAccess(tuple_access) => Expression::TupleAccess(self.reduce_tuple_access(&tuple_access)?),
|
||||
|
||||
Expression::CircuitInit(circuit_init) => Expression::CircuitInit(self.reduce_circuit_init(&circuit_init)?),
|
||||
Expression::CircuitMemberAccess(circuit_member_access) => {
|
||||
Expression::CircuitMemberAccess(self.reduce_circuit_member_access(&circuit_member_access)?)
|
||||
}
|
||||
Expression::CircuitStaticFunctionAccess(circuit_static_fn_access) => {
|
||||
Expression::CircuitStaticFunctionAccess(
|
||||
self.reduce_circuit_static_fn_access(&circuit_static_fn_access)?,
|
||||
)
|
||||
}
|
||||
|
||||
Expression::Call(call) => Expression::Call(self.reduce_call(&call)?),
|
||||
};
|
||||
|
||||
self.reducer.reduce_expression(expression, new, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier, CanonicalizeError> {
|
||||
self.reducer.reduce_identifier(identifier)
|
||||
}
|
||||
|
||||
pub fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple, CanonicalizeError> {
|
||||
self.reducer.reduce_group_tuple(group_tuple)
|
||||
}
|
||||
|
||||
pub fn reduce_group_value(&mut self, group_value: &GroupValue) -> Result<GroupValue, CanonicalizeError> {
|
||||
let new = match group_value {
|
||||
GroupValue::Tuple(group_tuple) => GroupValue::Tuple(self.reduce_group_tuple(&group_tuple)?),
|
||||
_ => group_value.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_group_value(group_value, new)
|
||||
}
|
||||
|
||||
pub fn reduce_value(&mut self, value: &ValueExpression) -> Result<ValueExpression, CanonicalizeError> {
|
||||
let new = match value {
|
||||
ValueExpression::Group(group_value) => {
|
||||
ValueExpression::Group(Box::new(self.reduce_group_value(&group_value)?))
|
||||
}
|
||||
_ => value.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_value(value, new)
|
||||
}
|
||||
|
||||
pub fn reduce_binary(&mut self, binary: &BinaryExpression) -> Result<BinaryExpression, CanonicalizeError> {
|
||||
let left = self.reduce_expression(&binary.left)?;
|
||||
let right = self.reduce_expression(&binary.right)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_binary(binary, left, right, binary.op.clone(), self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_unary(&mut self, unary: &UnaryExpression) -> Result<UnaryExpression, CanonicalizeError> {
|
||||
let inner = self.reduce_expression(&unary.inner)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_unary(unary, inner, unary.op.clone(), self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_ternary(&mut self, ternary: &TernaryExpression) -> Result<TernaryExpression, CanonicalizeError> {
|
||||
let condition = self.reduce_expression(&ternary.condition)?;
|
||||
let if_true = self.reduce_expression(&ternary.if_true)?;
|
||||
let if_false = self.reduce_expression(&ternary.if_false)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_ternary(ternary, condition, if_true, if_false, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_cast(&mut self, cast: &CastExpression) -> Result<CastExpression, CanonicalizeError> {
|
||||
let inner = self.reduce_expression(&cast.inner)?;
|
||||
let target_type = self.reduce_type(&cast.target_type, &cast.span)?;
|
||||
|
||||
self.reducer.reduce_cast(cast, inner, target_type, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_array_inline(
|
||||
&mut self,
|
||||
array_inline: &ArrayInlineExpression,
|
||||
) -> Result<ArrayInlineExpression, CanonicalizeError> {
|
||||
let mut elements = vec![];
|
||||
for element in array_inline.elements.iter() {
|
||||
let reduced_element = match element {
|
||||
SpreadOrExpression::Expression(expression) => {
|
||||
SpreadOrExpression::Expression(self.reduce_expression(expression)?)
|
||||
}
|
||||
SpreadOrExpression::Spread(expression) => {
|
||||
SpreadOrExpression::Spread(self.reduce_expression(expression)?)
|
||||
}
|
||||
};
|
||||
|
||||
elements.push(reduced_element);
|
||||
}
|
||||
|
||||
self.reducer
|
||||
.reduce_array_inline(array_inline, elements, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_array_init(
|
||||
&mut self,
|
||||
array_init: &ArrayInitExpression,
|
||||
) -> Result<ArrayInitExpression, CanonicalizeError> {
|
||||
let element = self.reduce_expression(&array_init.element)?;
|
||||
|
||||
self.reducer.reduce_array_init(array_init, element, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_array_access(
|
||||
&mut self,
|
||||
array_access: &ArrayAccessExpression,
|
||||
) -> Result<ArrayAccessExpression, CanonicalizeError> {
|
||||
let array = self.reduce_expression(&array_access.array)?;
|
||||
let index = self.reduce_expression(&array_access.index)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_array_access(array_access, array, index, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_array_range_access(
|
||||
&mut self,
|
||||
array_range_access: &ArrayRangeAccessExpression,
|
||||
) -> Result<ArrayRangeAccessExpression, CanonicalizeError> {
|
||||
let array = self.reduce_expression(&array_range_access.array)?;
|
||||
let left = array_range_access
|
||||
.left
|
||||
.as_ref()
|
||||
.map(|left| self.reduce_expression(left))
|
||||
.transpose()?;
|
||||
let right = array_range_access
|
||||
.right
|
||||
.as_ref()
|
||||
.map(|right| self.reduce_expression(right))
|
||||
.transpose()?;
|
||||
|
||||
self.reducer
|
||||
.reduce_array_range_access(array_range_access, array, left, right, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_tuple_init(
|
||||
&mut self,
|
||||
tuple_init: &TupleInitExpression,
|
||||
) -> Result<TupleInitExpression, CanonicalizeError> {
|
||||
let mut elements = vec![];
|
||||
for element in tuple_init.elements.iter() {
|
||||
elements.push(self.reduce_expression(element)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_tuple_init(tuple_init, elements, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_tuple_access(
|
||||
&mut self,
|
||||
tuple_access: &TupleAccessExpression,
|
||||
) -> Result<TupleAccessExpression, CanonicalizeError> {
|
||||
let tuple = self.reduce_expression(&tuple_access.tuple)?;
|
||||
|
||||
self.reducer.reduce_tuple_access(tuple_access, tuple, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_implied_variable_definition(
|
||||
&mut self,
|
||||
variable: &CircuitImpliedVariableDefinition,
|
||||
) -> Result<CircuitImpliedVariableDefinition, CanonicalizeError> {
|
||||
let identifier = self.reduce_identifier(&variable.identifier)?;
|
||||
let expression = variable
|
||||
.expression
|
||||
.as_ref()
|
||||
.map(|expr| self.reduce_expression(expr))
|
||||
.transpose()?;
|
||||
|
||||
self.reducer
|
||||
.reduce_circuit_implied_variable_definition(variable, identifier, expression, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_init(
|
||||
&mut self,
|
||||
circuit_init: &CircuitInitExpression,
|
||||
) -> Result<CircuitInitExpression, CanonicalizeError> {
|
||||
let name = self.reduce_identifier(&circuit_init.name)?;
|
||||
|
||||
let mut members = vec![];
|
||||
for member in circuit_init.members.iter() {
|
||||
members.push(self.reduce_circuit_implied_variable_definition(member)?);
|
||||
}
|
||||
|
||||
self.reducer
|
||||
.reduce_circuit_init(circuit_init, name, members, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_member_access(
|
||||
&mut self,
|
||||
circuit_member_access: &CircuitMemberAccessExpression,
|
||||
) -> Result<CircuitMemberAccessExpression, CanonicalizeError> {
|
||||
let circuit = self.reduce_expression(&circuit_member_access.circuit)?;
|
||||
let name = self.reduce_identifier(&circuit_member_access.name)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_circuit_member_access(circuit_member_access, circuit, name, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_static_fn_access(
|
||||
&mut self,
|
||||
circuit_static_fn_access: &CircuitStaticFunctionAccessExpression,
|
||||
) -> Result<CircuitStaticFunctionAccessExpression, CanonicalizeError> {
|
||||
let circuit = self.reduce_expression(&circuit_static_fn_access.circuit)?;
|
||||
let name = self.reduce_identifier(&circuit_static_fn_access.name)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_circuit_static_fn_access(circuit_static_fn_access, circuit, name, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_call(&mut self, call: &CallExpression) -> Result<CallExpression, CanonicalizeError> {
|
||||
let function = self.reduce_expression(&call.function)?;
|
||||
|
||||
let mut arguments = vec![];
|
||||
for argument in call.arguments.iter() {
|
||||
arguments.push(self.reduce_expression(argument)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_call(call, function, arguments, self.in_circuit)
|
||||
}
|
||||
|
||||
// Statements
|
||||
pub fn reduce_statement(&mut self, statement: &Statement) -> Result<Statement, CanonicalizeError> {
|
||||
let new = match statement {
|
||||
Statement::Return(return_statement) => Statement::Return(self.reduce_return(&return_statement)?),
|
||||
Statement::Definition(definition) => Statement::Definition(self.reduce_definition(&definition)?),
|
||||
Statement::Assign(assign) => Statement::Assign(self.reduce_assign(&assign)?),
|
||||
Statement::Conditional(conditional) => Statement::Conditional(self.reduce_conditional(&conditional)?),
|
||||
Statement::Iteration(iteration) => Statement::Iteration(self.reduce_iteration(&iteration)?),
|
||||
Statement::Console(console) => Statement::Console(self.reduce_console(&console)?),
|
||||
Statement::Expression(expression) => Statement::Expression(self.reduce_expression_statement(&expression)?),
|
||||
Statement::Block(block) => Statement::Block(self.reduce_block(&block)?),
|
||||
};
|
||||
|
||||
self.reducer.reduce_statement(statement, new, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_return(&mut self, return_statement: &ReturnStatement) -> Result<ReturnStatement, CanonicalizeError> {
|
||||
let expression = self.reduce_expression(&return_statement.expression)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_return(return_statement, expression, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_variable_name(&mut self, variable_name: &VariableName) -> Result<VariableName, CanonicalizeError> {
|
||||
let identifier = self.reduce_identifier(&variable_name.identifier)?;
|
||||
|
||||
self.reducer.reduce_variable_name(variable_name, identifier)
|
||||
}
|
||||
|
||||
pub fn reduce_definition(
|
||||
&mut self,
|
||||
definition: &DefinitionStatement,
|
||||
) -> Result<DefinitionStatement, CanonicalizeError> {
|
||||
let mut variable_names = vec![];
|
||||
for variable_name in definition.variable_names.iter() {
|
||||
variable_names.push(self.reduce_variable_name(variable_name)?);
|
||||
}
|
||||
|
||||
let type_ = definition
|
||||
.type_
|
||||
.as_ref()
|
||||
.map(|type_| self.reduce_type(type_, &definition.span))
|
||||
.transpose()?;
|
||||
|
||||
let value = self.reduce_expression(&definition.value)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_definition(definition, variable_names, type_, value, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_assignee_access(&mut self, access: &AssigneeAccess) -> Result<AssigneeAccess, CanonicalizeError> {
|
||||
let new = match access {
|
||||
AssigneeAccess::ArrayRange(left, right) => {
|
||||
let left = left.as_ref().map(|left| self.reduce_expression(left)).transpose()?;
|
||||
let right = right.as_ref().map(|right| self.reduce_expression(right)).transpose()?;
|
||||
|
||||
AssigneeAccess::ArrayRange(left, right)
|
||||
}
|
||||
AssigneeAccess::ArrayIndex(index) => AssigneeAccess::ArrayIndex(self.reduce_expression(&index)?),
|
||||
AssigneeAccess::Member(identifier) => AssigneeAccess::Member(self.reduce_identifier(&identifier)?),
|
||||
_ => access.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_assignee_access(access, new, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_assignee(&mut self, assignee: &Assignee) -> Result<Assignee, CanonicalizeError> {
|
||||
let identifier = self.reduce_identifier(&assignee.identifier)?;
|
||||
|
||||
let mut accesses = vec![];
|
||||
for access in assignee.accesses.iter() {
|
||||
accesses.push(self.reduce_assignee_access(access)?);
|
||||
}
|
||||
|
||||
self.reducer
|
||||
.reduce_assignee(assignee, identifier, accesses, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_assign(&mut self, assign: &AssignStatement) -> Result<AssignStatement, CanonicalizeError> {
|
||||
let assignee = self.reduce_assignee(&assign.assignee)?;
|
||||
let value = self.reduce_expression(&assign.value)?;
|
||||
|
||||
self.reducer.reduce_assign(assign, assignee, value, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_conditional(
|
||||
&mut self,
|
||||
conditional: &ConditionalStatement,
|
||||
) -> Result<ConditionalStatement, CanonicalizeError> {
|
||||
let condition = self.reduce_expression(&conditional.condition)?;
|
||||
let block = self.reduce_block(&conditional.block)?;
|
||||
let next = conditional
|
||||
.next
|
||||
.as_ref()
|
||||
.map(|condition| self.reduce_statement(condition))
|
||||
.transpose()?;
|
||||
|
||||
self.reducer
|
||||
.reduce_conditional(conditional, condition, block, next, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_iteration(
|
||||
&mut self,
|
||||
iteration: &IterationStatement,
|
||||
) -> Result<IterationStatement, CanonicalizeError> {
|
||||
let variable = self.reduce_identifier(&iteration.variable)?;
|
||||
let start = self.reduce_expression(&iteration.start)?;
|
||||
let stop = self.reduce_expression(&iteration.stop)?;
|
||||
let block = self.reduce_block(&iteration.block)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_iteration(iteration, variable, start, stop, block, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_console(
|
||||
&mut self,
|
||||
console_function_call: &ConsoleStatement,
|
||||
) -> Result<ConsoleStatement, CanonicalizeError> {
|
||||
let function = match &console_function_call.function {
|
||||
ConsoleFunction::Assert(expression) => ConsoleFunction::Assert(self.reduce_expression(expression)?),
|
||||
ConsoleFunction::Debug(format) | ConsoleFunction::Error(format) | ConsoleFunction::Log(format) => {
|
||||
let mut parameters = vec![];
|
||||
for parameter in format.parameters.iter() {
|
||||
parameters.push(self.reduce_expression(parameter)?);
|
||||
}
|
||||
|
||||
let formatted = FormattedString {
|
||||
parts: format.parts.clone(),
|
||||
parameters,
|
||||
span: format.span.clone(),
|
||||
};
|
||||
|
||||
match &console_function_call.function {
|
||||
ConsoleFunction::Debug(_) => ConsoleFunction::Debug(formatted),
|
||||
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
|
||||
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
|
||||
_ => unimplemented!(), // impossible
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer
|
||||
.reduce_console(console_function_call, function, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_expression_statement(
|
||||
&mut self,
|
||||
expression: &ExpressionStatement,
|
||||
) -> Result<ExpressionStatement, CanonicalizeError> {
|
||||
let inner_expression = self.reduce_expression(&expression.expression)?;
|
||||
self.reducer
|
||||
.reduce_expression_statement(expression, inner_expression, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_block(&mut self, block: &Block) -> Result<Block, CanonicalizeError> {
|
||||
let mut statements = vec![];
|
||||
for statement in block.statements.iter() {
|
||||
statements.push(self.reduce_statement(statement)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_block(block, statements, self.in_circuit)
|
||||
}
|
||||
|
||||
// Program
|
||||
pub fn reduce_program(&mut self, program: &Program) -> Result<Program, CanonicalizeError> {
|
||||
let mut inputs = vec![];
|
||||
for input in program.expected_input.iter() {
|
||||
inputs.push(self.reduce_function_input(input)?);
|
||||
}
|
||||
|
||||
let mut imports = vec![];
|
||||
for import in program.imports.iter() {
|
||||
imports.push(self.reduce_import(import)?);
|
||||
}
|
||||
|
||||
let mut circuits = IndexMap::new();
|
||||
for (identifier, circuit) in program.circuits.iter() {
|
||||
circuits.insert(self.reduce_identifier(identifier)?, self.reduce_circuit(circuit)?);
|
||||
}
|
||||
|
||||
let mut functions = IndexMap::new();
|
||||
for (identifier, function) in program.functions.iter() {
|
||||
functions.insert(self.reduce_identifier(identifier)?, self.reduce_function(function)?);
|
||||
}
|
||||
|
||||
self.reducer
|
||||
.reduce_program(program, inputs, imports, circuits, functions)
|
||||
}
|
||||
|
||||
pub fn reduce_function_input_variable(
|
||||
&mut self,
|
||||
variable: &FunctionInputVariable,
|
||||
) -> Result<FunctionInputVariable, CanonicalizeError> {
|
||||
let identifier = self.reduce_identifier(&variable.identifier)?;
|
||||
let type_ = self.reduce_type(&variable.type_, &variable.span)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_function_input_variable(variable, identifier, type_, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_function_input(&mut self, input: &FunctionInput) -> Result<FunctionInput, CanonicalizeError> {
|
||||
let new = match input {
|
||||
FunctionInput::Variable(function_input_variable) => {
|
||||
FunctionInput::Variable(self.reduce_function_input_variable(function_input_variable)?)
|
||||
}
|
||||
_ => input.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_function_input(input, new, self.in_circuit)
|
||||
}
|
||||
|
||||
pub fn reduce_package_or_packages(
|
||||
&mut self,
|
||||
package_or_packages: &PackageOrPackages,
|
||||
) -> Result<PackageOrPackages, CanonicalizeError> {
|
||||
let new = match package_or_packages {
|
||||
PackageOrPackages::Package(package) => PackageOrPackages::Package(Package {
|
||||
name: self.reduce_identifier(&package.name)?,
|
||||
access: package.access.clone(),
|
||||
span: package.span.clone(),
|
||||
}),
|
||||
PackageOrPackages::Packages(packages) => PackageOrPackages::Packages(Packages {
|
||||
name: self.reduce_identifier(&packages.name)?,
|
||||
accesses: packages.accesses.clone(),
|
||||
span: packages.span.clone(),
|
||||
}),
|
||||
};
|
||||
|
||||
self.reducer.reduce_package_or_packages(package_or_packages, new)
|
||||
}
|
||||
|
||||
pub fn reduce_import(&mut self, import: &ImportStatement) -> Result<ImportStatement, CanonicalizeError> {
|
||||
let package_or_packages = self.reduce_package_or_packages(&import.package_or_packages)?;
|
||||
|
||||
self.reducer.reduce_import(import, package_or_packages)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_member(
|
||||
&mut self,
|
||||
circuit_member: &CircuitMember,
|
||||
) -> Result<CircuitMember, CanonicalizeError> {
|
||||
self.in_circuit = !self.in_circuit;
|
||||
let new = match circuit_member {
|
||||
CircuitMember::CircuitVariable(identifier, type_) => CircuitMember::CircuitVariable(
|
||||
self.reduce_identifier(&identifier)?,
|
||||
self.reduce_type(&type_, &identifier.span)?,
|
||||
),
|
||||
CircuitMember::CircuitFunction(function) => {
|
||||
CircuitMember::CircuitFunction(self.reduce_function(&function)?)
|
||||
}
|
||||
};
|
||||
self.in_circuit = !self.in_circuit;
|
||||
|
||||
self.reducer.reduce_circuit_member(circuit_member, new)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit(&mut self, circuit: &Circuit) -> Result<Circuit, CanonicalizeError> {
|
||||
let circuit_name = self.reduce_identifier(&circuit.circuit_name)?;
|
||||
|
||||
let mut members = vec![];
|
||||
for member in circuit.members.iter() {
|
||||
members.push(self.reduce_circuit_member(member)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_circuit(circuit, circuit_name, members)
|
||||
}
|
||||
|
||||
fn reduce_annotation(&mut self, annotation: &Annotation) -> Result<Annotation, CanonicalizeError> {
|
||||
let name = self.reduce_identifier(&annotation.name)?;
|
||||
|
||||
self.reducer.reduce_annotation(annotation, name)
|
||||
}
|
||||
|
||||
pub fn reduce_function(&mut self, function: &Function) -> Result<Function, CanonicalizeError> {
|
||||
let identifier = self.reduce_identifier(&function.identifier)?;
|
||||
|
||||
let mut annotations = vec![];
|
||||
for annotation in function.annotations.iter() {
|
||||
annotations.push(self.reduce_annotation(annotation)?);
|
||||
}
|
||||
|
||||
let mut inputs = vec![];
|
||||
for input in function.input.iter() {
|
||||
inputs.push(self.reduce_function_input(input)?);
|
||||
}
|
||||
|
||||
let output = function
|
||||
.output
|
||||
.as_ref()
|
||||
.map(|type_| self.reduce_type(type_, &function.span))
|
||||
.transpose()?;
|
||||
|
||||
let block = self.reduce_block(&function.block)?;
|
||||
|
||||
self.reducer.reduce_function(
|
||||
function,
|
||||
identifier,
|
||||
annotations,
|
||||
inputs,
|
||||
output,
|
||||
block,
|
||||
self.in_circuit,
|
||||
)
|
||||
}
|
||||
}
|
550
ast/src/reducer/reconstructing_reducer.rs
Normal file
550
ast/src/reducer/reconstructing_reducer.rs
Normal file
@ -0,0 +1,550 @@
|
||||
// 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::*;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
// Needed to fix clippy bug.
|
||||
#[allow(clippy::redundant_closure)]
|
||||
pub trait ReconstructingReducer {
|
||||
fn reduce_type(
|
||||
&mut self,
|
||||
_type_: &Type,
|
||||
new: Type,
|
||||
_in_circuit: bool,
|
||||
_span: &Span,
|
||||
) -> Result<Type, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
fn reduce_expression(
|
||||
&mut self,
|
||||
_expression: &Expression,
|
||||
new: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Expression, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier, CanonicalizeError> {
|
||||
Ok(Identifier {
|
||||
name: identifier.name.clone(),
|
||||
span: identifier.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple, CanonicalizeError> {
|
||||
Ok(GroupTuple {
|
||||
x: group_tuple.x.clone(),
|
||||
y: group_tuple.y.clone(),
|
||||
span: group_tuple.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_group_value(
|
||||
&mut self,
|
||||
_group_value: &GroupValue,
|
||||
new: GroupValue,
|
||||
) -> Result<GroupValue, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_value(
|
||||
&mut self,
|
||||
_value: &ValueExpression,
|
||||
new: ValueExpression,
|
||||
) -> Result<ValueExpression, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_binary(
|
||||
&mut self,
|
||||
binary: &BinaryExpression,
|
||||
left: Expression,
|
||||
right: Expression,
|
||||
op: BinaryOperation,
|
||||
_in_circuit: bool,
|
||||
) -> Result<BinaryExpression, CanonicalizeError> {
|
||||
Ok(BinaryExpression {
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
op,
|
||||
span: binary.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_unary(
|
||||
&mut self,
|
||||
unary: &UnaryExpression,
|
||||
inner: Expression,
|
||||
op: UnaryOperation,
|
||||
_in_circuit: bool,
|
||||
) -> Result<UnaryExpression, CanonicalizeError> {
|
||||
Ok(UnaryExpression {
|
||||
inner: Box::new(inner),
|
||||
op,
|
||||
span: unary.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_ternary(
|
||||
&mut self,
|
||||
ternary: &TernaryExpression,
|
||||
condition: Expression,
|
||||
if_true: Expression,
|
||||
if_false: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<TernaryExpression, CanonicalizeError> {
|
||||
Ok(TernaryExpression {
|
||||
condition: Box::new(condition),
|
||||
if_true: Box::new(if_true),
|
||||
if_false: Box::new(if_false),
|
||||
span: ternary.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_cast(
|
||||
&mut self,
|
||||
cast: &CastExpression,
|
||||
inner: Expression,
|
||||
target_type: Type,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CastExpression, CanonicalizeError> {
|
||||
Ok(CastExpression {
|
||||
inner: Box::new(inner),
|
||||
target_type,
|
||||
span: cast.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_array_inline(
|
||||
&mut self,
|
||||
array_inline: &ArrayInlineExpression,
|
||||
elements: Vec<SpreadOrExpression>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ArrayInlineExpression, CanonicalizeError> {
|
||||
Ok(ArrayInlineExpression {
|
||||
elements,
|
||||
span: array_inline.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_array_init(
|
||||
&mut self,
|
||||
array_init: &ArrayInitExpression,
|
||||
element: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ArrayInitExpression, CanonicalizeError> {
|
||||
Ok(ArrayInitExpression {
|
||||
element: Box::new(element),
|
||||
dimensions: array_init.dimensions.clone(),
|
||||
span: array_init.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_array_access(
|
||||
&mut self,
|
||||
array_access: &ArrayAccessExpression,
|
||||
array: Expression,
|
||||
index: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ArrayAccessExpression, CanonicalizeError> {
|
||||
Ok(ArrayAccessExpression {
|
||||
array: Box::new(array),
|
||||
index: Box::new(index),
|
||||
span: array_access.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_array_range_access(
|
||||
&mut self,
|
||||
array_rage_access: &ArrayRangeAccessExpression,
|
||||
array: Expression,
|
||||
left: Option<Expression>,
|
||||
right: Option<Expression>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ArrayRangeAccessExpression, CanonicalizeError> {
|
||||
Ok(ArrayRangeAccessExpression {
|
||||
array: Box::new(array),
|
||||
left: left.map(|expr| Box::new(expr)),
|
||||
right: right.map(|expr| Box::new(expr)),
|
||||
span: array_rage_access.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_tuple_init(
|
||||
&mut self,
|
||||
tuple_init: &TupleInitExpression,
|
||||
elements: Vec<Expression>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<TupleInitExpression, CanonicalizeError> {
|
||||
Ok(TupleInitExpression {
|
||||
elements,
|
||||
span: tuple_init.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_tuple_access(
|
||||
&mut self,
|
||||
tuple_access: &TupleAccessExpression,
|
||||
tuple: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<TupleAccessExpression, CanonicalizeError> {
|
||||
Ok(TupleAccessExpression {
|
||||
tuple: Box::new(tuple),
|
||||
index: tuple_access.index.clone(),
|
||||
span: tuple_access.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_implied_variable_definition(
|
||||
&mut self,
|
||||
_variable: &CircuitImpliedVariableDefinition,
|
||||
identifier: Identifier,
|
||||
expression: Option<Expression>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CircuitImpliedVariableDefinition, CanonicalizeError> {
|
||||
Ok(CircuitImpliedVariableDefinition { identifier, expression })
|
||||
}
|
||||
|
||||
fn reduce_circuit_init(
|
||||
&mut self,
|
||||
circuit_init: &CircuitInitExpression,
|
||||
name: Identifier,
|
||||
members: Vec<CircuitImpliedVariableDefinition>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CircuitInitExpression, CanonicalizeError> {
|
||||
Ok(CircuitInitExpression {
|
||||
name,
|
||||
members,
|
||||
span: circuit_init.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_member_access(
|
||||
&mut self,
|
||||
circuit_member_access: &CircuitMemberAccessExpression,
|
||||
circuit: Expression,
|
||||
name: Identifier,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CircuitMemberAccessExpression, CanonicalizeError> {
|
||||
Ok(CircuitMemberAccessExpression {
|
||||
circuit: Box::new(circuit),
|
||||
name,
|
||||
span: circuit_member_access.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_static_fn_access(
|
||||
&mut self,
|
||||
circuit_static_fn_access: &CircuitStaticFunctionAccessExpression,
|
||||
circuit: Expression,
|
||||
name: Identifier,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CircuitStaticFunctionAccessExpression, CanonicalizeError> {
|
||||
Ok(CircuitStaticFunctionAccessExpression {
|
||||
circuit: Box::new(circuit),
|
||||
name,
|
||||
span: circuit_static_fn_access.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_call(
|
||||
&mut self,
|
||||
call: &CallExpression,
|
||||
function: Expression,
|
||||
arguments: Vec<Expression>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<CallExpression, CanonicalizeError> {
|
||||
Ok(CallExpression {
|
||||
function: Box::new(function),
|
||||
arguments,
|
||||
span: call.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
// Statements
|
||||
fn reduce_statement(
|
||||
&mut self,
|
||||
_statement: &Statement,
|
||||
new: Statement,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Statement, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_return(
|
||||
&mut self,
|
||||
return_statement: &ReturnStatement,
|
||||
expression: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ReturnStatement, CanonicalizeError> {
|
||||
Ok(ReturnStatement {
|
||||
expression,
|
||||
span: return_statement.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_variable_name(
|
||||
&mut self,
|
||||
variable_name: &VariableName,
|
||||
identifier: Identifier,
|
||||
) -> Result<VariableName, CanonicalizeError> {
|
||||
Ok(VariableName {
|
||||
mutable: variable_name.mutable,
|
||||
identifier,
|
||||
span: variable_name.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_definition(
|
||||
&mut self,
|
||||
definition: &DefinitionStatement,
|
||||
variable_names: Vec<VariableName>,
|
||||
type_: Option<Type>,
|
||||
value: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<DefinitionStatement, CanonicalizeError> {
|
||||
Ok(DefinitionStatement {
|
||||
declaration_type: definition.declaration_type.clone(),
|
||||
variable_names,
|
||||
type_,
|
||||
value,
|
||||
span: definition.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_assignee_access(
|
||||
&mut self,
|
||||
_access: &AssigneeAccess,
|
||||
new: AssigneeAccess,
|
||||
_in_circuit: bool,
|
||||
) -> Result<AssigneeAccess, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_assignee(
|
||||
&mut self,
|
||||
assignee: &Assignee,
|
||||
identifier: Identifier,
|
||||
accesses: Vec<AssigneeAccess>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Assignee, CanonicalizeError> {
|
||||
Ok(Assignee {
|
||||
identifier,
|
||||
accesses,
|
||||
span: assignee.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_assign(
|
||||
&mut self,
|
||||
assign: &AssignStatement,
|
||||
assignee: Assignee,
|
||||
value: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<AssignStatement, CanonicalizeError> {
|
||||
Ok(AssignStatement {
|
||||
operation: assign.operation.clone(),
|
||||
assignee,
|
||||
value,
|
||||
span: assign.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_conditional(
|
||||
&mut self,
|
||||
conditional: &ConditionalStatement,
|
||||
condition: Expression,
|
||||
block: Block,
|
||||
statement: Option<Statement>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ConditionalStatement, CanonicalizeError> {
|
||||
Ok(ConditionalStatement {
|
||||
condition,
|
||||
block,
|
||||
next: statement.map(|statement| Box::new(statement)),
|
||||
span: conditional.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_iteration(
|
||||
&mut self,
|
||||
iteration: &IterationStatement,
|
||||
variable: Identifier,
|
||||
start: Expression,
|
||||
stop: Expression,
|
||||
block: Block,
|
||||
_in_circuit: bool,
|
||||
) -> Result<IterationStatement, CanonicalizeError> {
|
||||
Ok(IterationStatement {
|
||||
variable,
|
||||
start,
|
||||
stop,
|
||||
block,
|
||||
span: iteration.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_console(
|
||||
&mut self,
|
||||
console: &ConsoleStatement,
|
||||
function: ConsoleFunction,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ConsoleStatement, CanonicalizeError> {
|
||||
Ok(ConsoleStatement {
|
||||
function,
|
||||
span: console.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_expression_statement(
|
||||
&mut self,
|
||||
expression_statement: &ExpressionStatement,
|
||||
expression: Expression,
|
||||
_in_circuit: bool,
|
||||
) -> Result<ExpressionStatement, CanonicalizeError> {
|
||||
Ok(ExpressionStatement {
|
||||
expression,
|
||||
span: expression_statement.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_block(
|
||||
&mut self,
|
||||
block: &Block,
|
||||
statements: Vec<Statement>,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Block, CanonicalizeError> {
|
||||
Ok(Block {
|
||||
statements,
|
||||
span: block.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
// Program
|
||||
fn reduce_program(
|
||||
&mut self,
|
||||
program: &Program,
|
||||
expected_input: Vec<FunctionInput>,
|
||||
imports: Vec<ImportStatement>,
|
||||
circuits: IndexMap<Identifier, Circuit>,
|
||||
functions: IndexMap<Identifier, Function>,
|
||||
) -> Result<Program, CanonicalizeError> {
|
||||
Ok(Program {
|
||||
name: program.name.clone(),
|
||||
expected_input,
|
||||
imports,
|
||||
circuits,
|
||||
functions,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_function_input_variable(
|
||||
&mut self,
|
||||
variable: &FunctionInputVariable,
|
||||
identifier: Identifier,
|
||||
type_: Type,
|
||||
_in_circuit: bool,
|
||||
) -> Result<FunctionInputVariable, CanonicalizeError> {
|
||||
Ok(FunctionInputVariable {
|
||||
identifier,
|
||||
const_: variable.const_,
|
||||
mutable: variable.mutable,
|
||||
type_,
|
||||
span: variable.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_function_input(
|
||||
&mut self,
|
||||
_input: &FunctionInput,
|
||||
new: FunctionInput,
|
||||
_in_circuit: bool,
|
||||
) -> Result<FunctionInput, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_package_or_packages(
|
||||
&mut self,
|
||||
_package_or_packages: &PackageOrPackages,
|
||||
new: PackageOrPackages,
|
||||
) -> Result<PackageOrPackages, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_import(
|
||||
&mut self,
|
||||
import: &ImportStatement,
|
||||
package_or_packages: PackageOrPackages,
|
||||
) -> Result<ImportStatement, CanonicalizeError> {
|
||||
Ok(ImportStatement {
|
||||
package_or_packages,
|
||||
span: import.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_member(
|
||||
&mut self,
|
||||
_circuit_member: &CircuitMember,
|
||||
new: CircuitMember,
|
||||
) -> Result<CircuitMember, CanonicalizeError> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_circuit(
|
||||
&mut self,
|
||||
_circuit: &Circuit,
|
||||
circuit_name: Identifier,
|
||||
members: Vec<CircuitMember>,
|
||||
) -> Result<Circuit, CanonicalizeError> {
|
||||
Ok(Circuit { circuit_name, members })
|
||||
}
|
||||
|
||||
fn reduce_annotation(
|
||||
&mut self,
|
||||
annotation: &Annotation,
|
||||
name: Identifier,
|
||||
) -> Result<Annotation, CanonicalizeError> {
|
||||
Ok(Annotation {
|
||||
span: annotation.span.clone(),
|
||||
name,
|
||||
arguments: annotation.arguments.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn reduce_function(
|
||||
&mut self,
|
||||
function: &Function,
|
||||
identifier: Identifier,
|
||||
annotations: Vec<Annotation>,
|
||||
input: Vec<FunctionInput>,
|
||||
output: Option<Type>,
|
||||
block: Block,
|
||||
_in_circuit: bool,
|
||||
) -> Result<Function, CanonicalizeError> {
|
||||
Ok(Function {
|
||||
identifier,
|
||||
annotations,
|
||||
input,
|
||||
output,
|
||||
block,
|
||||
span: function.span.clone(),
|
||||
})
|
||||
}
|
||||
}
|
@ -263,7 +263,11 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
|
||||
Rc::new(lines),
|
||||
);
|
||||
|
||||
let ast = parse_ast(self.main_file_path.to_str().unwrap_or_default(), program_string)?;
|
||||
let mut ast = parse_ast(self.main_file_path.to_str().unwrap_or_default(), program_string)?;
|
||||
// Preform compiler optimization via canonicalizing AST if its enabled.
|
||||
if self.options.canonicalization_enabled {
|
||||
ast.canonicalize()?;
|
||||
}
|
||||
|
||||
// Store the main program file.
|
||||
self.program = ast.into_repr();
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError};
|
||||
use leo_asg::{AsgConvertError, FormattedError};
|
||||
use leo_ast::LeoError;
|
||||
use leo_ast::{CanonicalizeError, LeoError};
|
||||
use leo_imports::ImportParserError;
|
||||
use leo_input::InputParserError;
|
||||
use leo_parser::SyntaxError;
|
||||
@ -77,6 +77,9 @@ pub enum CompilerError {
|
||||
|
||||
#[error("{}", _0)]
|
||||
AsgConvertError(#[from] AsgConvertError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
CanonicalizeError(#[from] CanonicalizeError),
|
||||
}
|
||||
|
||||
impl LeoError for CompilerError {
|
||||
|
@ -27,6 +27,7 @@ pub const STATE_VARIABLE_NAME: &str = "state";
|
||||
pub const STATE_LEAF_VARIABLE_NAME: &str = "state_leaf";
|
||||
|
||||
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
#[allow(clippy::vec_init_then_push)]
|
||||
pub fn allocate_input_keyword<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
|
@ -19,6 +19,7 @@
|
||||
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
@ -19,6 +19,7 @@
|
||||
///
|
||||
#[derive(Clone)]
|
||||
pub struct CompilerOptions {
|
||||
pub canonicalization_enabled: bool,
|
||||
pub constant_folding_enabled: bool,
|
||||
pub dead_code_elimination_enabled: bool,
|
||||
}
|
||||
@ -29,6 +30,7 @@ impl Default for CompilerOptions {
|
||||
///
|
||||
fn default() -> Self {
|
||||
CompilerOptions {
|
||||
canonicalization_enabled: true,
|
||||
constant_folding_enabled: true,
|
||||
dead_code_elimination_enabled: true,
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ impl OutputBytes {
|
||||
program: &Program<'a>,
|
||||
registers: &Registers,
|
||||
value: ConstrainedValue<'a, F, G>,
|
||||
|
||||
span: &Span,
|
||||
) -> Result<Self, OutputBytesError> {
|
||||
let return_values = match value {
|
||||
|
338
compiler/tests/canonicalization/array_expansion.json
Normal file
338
compiler/tests/canonicalization/array_expansion.json
Normal file
@ -0,0 +1,338 @@
|
||||
{
|
||||
"name": "",
|
||||
"expected_input": [],
|
||||
"imports": [],
|
||||
"circuits": {},
|
||||
"functions": {
|
||||
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
|
||||
"annotations": [],
|
||||
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"input": [
|
||||
{
|
||||
"Variable": {
|
||||
"identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"const_": false,
|
||||
"mutable": false,
|
||||
"type_": {
|
||||
"Array": [
|
||||
{
|
||||
"Array": [
|
||||
"Group",
|
||||
[
|
||||
{
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
[
|
||||
{
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"span": {
|
||||
"line_start": 1,
|
||||
"line_stop": 1,
|
||||
"col_start": 15,
|
||||
"col_stop": 16,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"Tuple": []
|
||||
},
|
||||
"block": {
|
||||
"statements": [
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": false,
|
||||
"identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 7,
|
||||
"col_stop": 8,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": null,
|
||||
"value": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"Value": {
|
||||
"Boolean": [
|
||||
"true",
|
||||
{
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 12,
|
||||
"col_stop": 16,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "2"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 11,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "3"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 11,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "4"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 11,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "5"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 11,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "6"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 11,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 3,
|
||||
"col_stop": 34,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": false,
|
||||
"identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 7,
|
||||
"col_stop": 8,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": {
|
||||
"Array": [
|
||||
{
|
||||
"Array": [
|
||||
{
|
||||
"IntegerType": "U32"
|
||||
},
|
||||
[
|
||||
{
|
||||
"value": "2"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
[
|
||||
{
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"Value": {
|
||||
"Integer": [
|
||||
"U32",
|
||||
"0",
|
||||
{
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 27,
|
||||
"col_stop": 31,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "2"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 26,
|
||||
"col_stop": 40,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "1"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 26,
|
||||
"col_stop": 40,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 3,
|
||||
"col_stop": 40,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": false,
|
||||
"identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 4,
|
||||
"line_stop": 4,
|
||||
"col_start": 7,
|
||||
"col_stop": 8,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": null,
|
||||
"value": {
|
||||
"ArrayInit": {
|
||||
"element": {
|
||||
"Value": {
|
||||
"Integer": [
|
||||
"I8",
|
||||
"0",
|
||||
{
|
||||
"line_start": 4,
|
||||
"line_stop": 4,
|
||||
"col_start": 12,
|
||||
"col_stop": 15,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dimensions": [
|
||||
{
|
||||
"value": "1"
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 4,
|
||||
"line_stop": 4,
|
||||
"col_start": 11,
|
||||
"col_stop": 21,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 4,
|
||||
"line_stop": 4,
|
||||
"col_start": 3,
|
||||
"col_stop": 21,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 1,
|
||||
"line_stop": 5,
|
||||
"col_start": 35,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 1,
|
||||
"line_stop": 5,
|
||||
"col_start": 1,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
compiler/tests/canonicalization/array_expansion.leo
Normal file
7
compiler/tests/canonicalization/array_expansion.leo
Normal file
@ -0,0 +1,7 @@
|
||||
function main(a: [group; (2, 1)]) {
|
||||
let b = [true; (6, 5, 4, 3, 2)];
|
||||
let c: [u32; (1, 2)] = [0u32; (1, 2)];
|
||||
let d = [0i8; (1)];
|
||||
// let d = [true; 0];
|
||||
// let e = [true; (0)];
|
||||
}
|
3
compiler/tests/canonicalization/array_size_zero_fail.leo
Normal file
3
compiler/tests/canonicalization/array_size_zero_fail.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let a = [true; (0)];
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
{
|
||||
"name": "",
|
||||
"expected_input": [],
|
||||
"imports": [],
|
||||
"circuits": {
|
||||
"{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}": {
|
||||
"circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"members": [
|
||||
{
|
||||
"CircuitVariable": [
|
||||
"{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}",
|
||||
{
|
||||
"IntegerType": "U32"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"CircuitFunction": {
|
||||
"annotations": [],
|
||||
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"input": [],
|
||||
"output": {
|
||||
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"block": {
|
||||
"statements": [
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": false,
|
||||
"identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 5,
|
||||
"line_stop": 5,
|
||||
"col_start": 9,
|
||||
"col_stop": 12,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": {
|
||||
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"value": {
|
||||
"CircuitInit": {
|
||||
"name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"members": [
|
||||
{
|
||||
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"expression": {
|
||||
"Value": {
|
||||
"Integer": [
|
||||
"U32",
|
||||
"1",
|
||||
{
|
||||
"line_start": 6,
|
||||
"line_stop": 6,
|
||||
"col_start": 10,
|
||||
"col_stop": 14,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 5,
|
||||
"line_stop": 7,
|
||||
"col_start": 21,
|
||||
"col_stop": 6,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 5,
|
||||
"line_stop": 7,
|
||||
"col_start": 5,
|
||||
"col_stop": 6,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Return": {
|
||||
"expression": {
|
||||
"Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"span": {
|
||||
"line_start": 9,
|
||||
"line_stop": 9,
|
||||
"col_start": 5,
|
||||
"col_stop": 15,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 4,
|
||||
"line_stop": 10,
|
||||
"col_start": 26,
|
||||
"col_stop": 4,
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 4,
|
||||
"line_stop": 10,
|
||||
"col_start": 3,
|
||||
"col_stop": 4,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"functions": {
|
||||
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
|
||||
"annotations": [],
|
||||
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"input": [],
|
||||
"output": {
|
||||
"Tuple": []
|
||||
},
|
||||
"block": {
|
||||
"statements": [
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": false,
|
||||
"identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 14,
|
||||
"line_stop": 14,
|
||||
"col_start": 7,
|
||||
"col_stop": 10,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": {
|
||||
"Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"value": {
|
||||
"Call": {
|
||||
"function": {
|
||||
"CircuitStaticFunctionAccess": {
|
||||
"circuit": {
|
||||
"Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 14,
|
||||
"line_stop": 14,
|
||||
"col_start": 18,
|
||||
"col_stop": 26,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"arguments": [],
|
||||
"span": {
|
||||
"line_start": 14,
|
||||
"line_stop": 14,
|
||||
"col_start": 18,
|
||||
"col_stop": 28,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 14,
|
||||
"line_stop": 14,
|
||||
"col_start": 3,
|
||||
"col_stop": 28,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 13,
|
||||
"line_stop": 15,
|
||||
"col_start": 17,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 13,
|
||||
"line_stop": 15,
|
||||
"col_start": 1,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
circuit Foo {
|
||||
x: u32
|
||||
|
||||
function new() -> Self {
|
||||
let new: Self = Self {
|
||||
x: 1u32
|
||||
};
|
||||
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let foo: Foo = Foo::new();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
circuit Foo {
|
||||
x: u32
|
||||
|
||||
function new() -> Self {
|
||||
let new: Self = Self {
|
||||
x: 1u32
|
||||
};
|
||||
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
let foo: Self = Foo::new();
|
||||
}
|
128
compiler/tests/canonicalization/compound_assignment.json
Normal file
128
compiler/tests/canonicalization/compound_assignment.json
Normal file
@ -0,0 +1,128 @@
|
||||
{
|
||||
"name": "",
|
||||
"expected_input": [],
|
||||
"imports": [],
|
||||
"circuits": {},
|
||||
"functions": {
|
||||
"{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": {
|
||||
"annotations": [],
|
||||
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"input": [],
|
||||
"output": {
|
||||
"Tuple": []
|
||||
},
|
||||
"block": {
|
||||
"statements": [
|
||||
{
|
||||
"Definition": {
|
||||
"declaration_type": "Let",
|
||||
"variable_names": [
|
||||
{
|
||||
"mutable": true,
|
||||
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":11,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 7,
|
||||
"col_stop": 12,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"type_": null,
|
||||
"value": {
|
||||
"Value": {
|
||||
"Integer": [
|
||||
"U32",
|
||||
"10",
|
||||
{
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 15,
|
||||
"col_stop": 20,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 2,
|
||||
"line_stop": 2,
|
||||
"col_start": 3,
|
||||
"col_stop": 20,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Assign": {
|
||||
"operation": "Assign",
|
||||
"assignee": {
|
||||
"identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}",
|
||||
"accesses": [],
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 3,
|
||||
"col_stop": 4,
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"value": {
|
||||
"Binary": {
|
||||
"left": {
|
||||
"Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}"
|
||||
},
|
||||
"right": {
|
||||
"Value": {
|
||||
"Implicit": [
|
||||
"20",
|
||||
{
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 8,
|
||||
"col_stop": 10,
|
||||
"path": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"op": "Add",
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 3,
|
||||
"col_stop": 10,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 3,
|
||||
"line_stop": 3,
|
||||
"col_start": 3,
|
||||
"col_stop": 10,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"span": {
|
||||
"line_start": 1,
|
||||
"line_stop": 4,
|
||||
"col_start": 17,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"line_start": 1,
|
||||
"line_stop": 4,
|
||||
"col_start": 1,
|
||||
"col_stop": 2,
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
compiler/tests/canonicalization/compound_assignment.leo
Normal file
4
compiler/tests/canonicalization/compound_assignment.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
let mut x = 10u32;
|
||||
x += 20;
|
||||
}
|
2
compiler/tests/canonicalization/input/array_expansion.in
Normal file
2
compiler/tests/canonicalization/input/array_expansion.in
Normal file
@ -0,0 +1,2 @@
|
||||
[main]
|
||||
a: [group; (2, 1)] = [1group; (2, 1)];
|
89
compiler/tests/canonicalization/mod.rs
Normal file
89
compiler/tests/canonicalization/mod.rs
Normal file
@ -0,0 +1,89 @@
|
||||
// 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, parse_program, parse_program_with_input};
|
||||
use leo_ast::Ast;
|
||||
use leo_parser::parser;
|
||||
|
||||
pub fn parse_program_ast(file_string: &str) -> Ast {
|
||||
const TEST_PROGRAM_PATH: &str = "";
|
||||
let test_program_file_path = std::path::PathBuf::from(TEST_PROGRAM_PATH);
|
||||
|
||||
let mut ast = Ast::new(
|
||||
parser::parse(test_program_file_path.to_str().expect("unwrap fail"), &file_string)
|
||||
.expect("Failed to parse file."),
|
||||
);
|
||||
ast.canonicalize().expect("Failed to canonicalize program.");
|
||||
|
||||
ast
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_big_self_in_circuit_replacement() {
|
||||
// Check program is valid.
|
||||
let program_string = include_str!("big_self_in_circuit_replacement.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
assert_satisfied(program);
|
||||
|
||||
// Check we get expected ast.
|
||||
let ast = parse_program_ast(program_string);
|
||||
let expected_json = include_str!("big_self_in_circuit_replacement.json");
|
||||
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
|
||||
|
||||
assert_eq!(expected_ast, ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_big_self_outside_circuit_fail() {
|
||||
// Check program is invalid.
|
||||
let program_string = include_str!("big_self_outside_circuit_fail.leo");
|
||||
let program = parse_program(program_string);
|
||||
assert!(program.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_expansion() {
|
||||
let program_string = include_str!("array_expansion.leo");
|
||||
let input_string = include_str!("input/array_expansion.in");
|
||||
let program = parse_program_with_input(program_string, input_string).unwrap();
|
||||
assert_satisfied(program);
|
||||
|
||||
let ast = parse_program_ast(program_string);
|
||||
let expected_json = include_str!("array_expansion.json");
|
||||
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
|
||||
|
||||
assert_eq!(expected_ast, ast);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_size_zero_fail() {
|
||||
let program_string = include_str!("array_size_zero_fail.leo");
|
||||
let program = parse_program(program_string);
|
||||
assert!(program.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compound_assignment() {
|
||||
let program_string = include_str!("compound_assignment.leo");
|
||||
let program = parse_program(program_string).unwrap();
|
||||
assert_satisfied(program);
|
||||
|
||||
let ast = parse_program_ast(program_string);
|
||||
let expected_json = include_str!("compound_assignment.json");
|
||||
let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json.");
|
||||
|
||||
assert_eq!(expected_ast, ast);
|
||||
}
|
@ -15,11 +15,13 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// allow the use of EdwardsTestCompiler::parse_program_from_string for tests
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
pub mod address;
|
||||
pub mod array;
|
||||
pub mod boolean;
|
||||
pub mod canonicalization;
|
||||
pub mod circuits;
|
||||
pub mod compiler;
|
||||
pub mod console;
|
||||
|
@ -14,6 +14,8 @@
|
||||
// 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/>.
|
||||
|
||||
#![allow(clippy::from_over_into)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
|
@ -13,10 +13,10 @@
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
//! Abstract syntax tree (ast) representation from leo-input.pest.
|
||||
use pest::{error::Error, iterators::Pairs, Parser, Span};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "leo-input.pest"]
|
||||
pub struct LanguageParser;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use crate::ast::Rule;
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
#[macro_use]
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use std::io;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum READMEError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
//! The `README.md` file.
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
//! This module contains the [`parse_ast()`] method which calls the underlying [`parse()`]
|
||||
//! method to create a new program ast.
|
||||
|
||||
#![allow(clippy::vec_init_then_push)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
|
@ -309,8 +309,8 @@ impl ParserContext {
|
||||
/// Otherwise, tries to parse the next token using [`parse_cast_expression`].
|
||||
///
|
||||
pub fn parse_exp_expression(&mut self) -> SyntaxResult<Expression> {
|
||||
let mut exprs = vec![];
|
||||
exprs.push(self.parse_cast_expression()?);
|
||||
let mut exprs = vec![self.parse_cast_expression()?];
|
||||
|
||||
while self.eat(Token::Exp).is_some() {
|
||||
exprs.push(self.parse_cast_expression()?);
|
||||
}
|
||||
@ -353,7 +353,7 @@ impl ParserContext {
|
||||
/// Otherwise, tries to parse the next token using [`parse_access_expression`].
|
||||
///
|
||||
pub fn parse_unary_expression(&mut self) -> SyntaxResult<Expression> {
|
||||
let mut ops = vec![];
|
||||
let mut ops = Vec::new();
|
||||
while let Some(token) = self.eat_any(&[Token::Not, Token::Minus, Token::BitNot]) {
|
||||
ops.push(token);
|
||||
}
|
||||
@ -455,7 +455,7 @@ impl ParserContext {
|
||||
}
|
||||
}
|
||||
Token::LeftParen => {
|
||||
let mut arguments = vec![];
|
||||
let mut arguments = Vec::new();
|
||||
let end_span;
|
||||
loop {
|
||||
let end = self.eat(Token::RightParen);
|
||||
@ -509,7 +509,7 @@ impl ParserContext {
|
||||
///
|
||||
pub fn parse_circuit_init(&mut self, identifier: Identifier) -> SyntaxResult<Expression> {
|
||||
self.expect(Token::LeftCurly)?;
|
||||
let mut members = vec![];
|
||||
let mut members = Vec::new();
|
||||
let end_span;
|
||||
loop {
|
||||
if let Some(end) = self.eat(Token::RightCurly) {
|
||||
@ -603,7 +603,7 @@ impl ParserContext {
|
||||
},
|
||||
)))));
|
||||
}
|
||||
let mut args = vec![];
|
||||
let mut args = Vec::new();
|
||||
let end_span;
|
||||
loop {
|
||||
let end = self.eat(Token::RightParen);
|
||||
@ -630,7 +630,7 @@ impl ParserContext {
|
||||
Token::LeftSquare => {
|
||||
if let Some(end) = self.eat(Token::RightSquare) {
|
||||
return Ok(Expression::ArrayInline(ArrayInlineExpression {
|
||||
elements: vec![],
|
||||
elements: Vec::new(),
|
||||
span: span + end.span,
|
||||
}));
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ impl ParserContext {
|
||||
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
|
||||
///
|
||||
pub fn parse_program(&mut self) -> SyntaxResult<Program> {
|
||||
let mut imports = vec![];
|
||||
let mut imports = Vec::new();
|
||||
let mut circuits = IndexMap::new();
|
||||
let mut functions = IndexMap::new();
|
||||
// let mut tests = IndexMap::new();
|
||||
@ -70,7 +70,7 @@ impl ParserContext {
|
||||
}
|
||||
Ok(Program {
|
||||
name: String::new(),
|
||||
expected_input: vec![],
|
||||
expected_input: Vec::new(),
|
||||
imports,
|
||||
circuits,
|
||||
functions,
|
||||
@ -90,7 +90,7 @@ impl ParserContext {
|
||||
}
|
||||
let end_span;
|
||||
let arguments = if self.eat(Token::LeftParen).is_some() {
|
||||
let mut args = vec![];
|
||||
let mut args = Vec::new();
|
||||
loop {
|
||||
if let Some(end) = self.eat(Token::RightParen) {
|
||||
end_span = end.span;
|
||||
@ -112,7 +112,7 @@ impl ParserContext {
|
||||
args
|
||||
} else {
|
||||
end_span = name.span.clone();
|
||||
vec![]
|
||||
Vec::new()
|
||||
};
|
||||
Ok(Annotation {
|
||||
name,
|
||||
@ -126,7 +126,7 @@ impl ParserContext {
|
||||
/// expressions within an import statement.
|
||||
///
|
||||
pub fn parse_package_accesses(&mut self) -> SyntaxResult<Vec<PackageAccess>> {
|
||||
let mut out = vec![];
|
||||
let mut out = Vec::new();
|
||||
self.expect(Token::LeftParen)?;
|
||||
while self.eat(Token::RightParen).is_none() {
|
||||
let access = self.parse_package_access()?;
|
||||
@ -293,7 +293,7 @@ impl ParserContext {
|
||||
self.expect(Token::Circuit)?;
|
||||
let name = self.expect_ident()?;
|
||||
self.expect(Token::LeftCurly)?;
|
||||
let mut members = vec![];
|
||||
let mut members = Vec::new();
|
||||
while self.eat(Token::RightCurly).is_none() {
|
||||
let member = self.parse_circuit_member()?;
|
||||
members.push(member);
|
||||
@ -353,14 +353,14 @@ impl ParserContext {
|
||||
/// and function definition.
|
||||
///
|
||||
pub fn parse_function(&mut self) -> SyntaxResult<(Identifier, Function)> {
|
||||
let mut annotations = vec![];
|
||||
let mut annotations = Vec::new();
|
||||
while self.peek()?.token == Token::At {
|
||||
annotations.push(self.parse_annotation()?);
|
||||
}
|
||||
let start = self.expect(Token::Function)?;
|
||||
let name = self.expect_ident()?;
|
||||
self.expect(Token::LeftParen)?;
|
||||
let mut inputs = vec![];
|
||||
let mut inputs = Vec::new();
|
||||
while self.eat(Token::RightParen).is_none() {
|
||||
let input = self.parse_function_input()?;
|
||||
inputs.push(input);
|
||||
|
@ -72,7 +72,7 @@ impl ParserContext {
|
||||
///
|
||||
pub fn construct_assignee(expr: Expression) -> SyntaxResult<Assignee> {
|
||||
let expr_span = expr.span().clone();
|
||||
let mut accesses = vec![];
|
||||
let mut accesses = Vec::new();
|
||||
let identifier = Self::construct_assignee_access(expr, &mut accesses)?;
|
||||
|
||||
Ok(Assignee {
|
||||
@ -139,7 +139,8 @@ impl ParserContext {
|
||||
///
|
||||
pub fn parse_block(&mut self) -> SyntaxResult<Block> {
|
||||
let start = self.expect(Token::LeftCurly)?;
|
||||
let mut statements = vec![];
|
||||
|
||||
let mut statements = Vec::new();
|
||||
loop {
|
||||
match self.eat(Token::RightCurly) {
|
||||
None => {
|
||||
@ -230,7 +231,7 @@ impl ParserContext {
|
||||
}
|
||||
SpannedToken { token, span } => return Err(SyntaxError::unexpected_str(&token, "formatted string", &span)),
|
||||
};
|
||||
let mut parameters = vec![];
|
||||
let mut parameters = Vec::new();
|
||||
while self.eat(Token::Comma).is_some() {
|
||||
let param = self.parse_expression()?;
|
||||
parameters.push(param);
|
||||
@ -304,7 +305,7 @@ impl ParserContext {
|
||||
///
|
||||
pub fn parse_definition_statement(&mut self) -> SyntaxResult<DefinitionStatement> {
|
||||
let declare = self.expect_oneof(&[Token::Let, Token::Const])?;
|
||||
let mut variable_names = vec![];
|
||||
let mut variable_names = Vec::new();
|
||||
if self.eat(Token::LeftParen).is_some() {
|
||||
variable_names.push(self.parse_variable_name()?);
|
||||
while self.eat(Token::Comma).is_some() {
|
||||
|
@ -61,7 +61,7 @@ impl ParserContext {
|
||||
ArrayDimensions(vec![int])
|
||||
} else {
|
||||
self.expect(Token::LeftParen)?;
|
||||
let mut dimensions = vec![];
|
||||
let mut dimensions = Vec::new();
|
||||
loop {
|
||||
if let Some((int, _)) = self.eat_int() {
|
||||
dimensions.push(int);
|
||||
@ -89,7 +89,7 @@ impl ParserContext {
|
||||
let span = ident.span.clone();
|
||||
(Type::Circuit(ident), span)
|
||||
} else if let Some(token) = self.eat(Token::LeftParen) {
|
||||
let mut types = vec![];
|
||||
let mut types = Vec::new();
|
||||
let end_span;
|
||||
loop {
|
||||
if let Some(end) = self.eat(Token::RightParen) {
|
||||
|
@ -43,8 +43,8 @@ pub fn find_tests<T: AsRef<Path>>(path: T, out: &mut Vec<(String, String)>) {
|
||||
#[test]
|
||||
pub fn parser_pass_tests() {
|
||||
let mut pass = 0;
|
||||
let mut fail = vec![];
|
||||
let mut tests = vec![];
|
||||
let mut fail = Vec::new();
|
||||
let mut tests = Vec::new();
|
||||
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
test_dir.push("../tests/pass/parse/");
|
||||
find_tests(&test_dir, &mut tests);
|
||||
@ -76,8 +76,8 @@ pub fn parser_pass_tests() {
|
||||
#[test]
|
||||
pub fn parser_fail_tests() {
|
||||
let mut pass = 0;
|
||||
let mut fail = vec![];
|
||||
let mut tests = vec![];
|
||||
let mut fail = Vec::new();
|
||||
let mut tests = Vec::new();
|
||||
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
test_dir.push("../tests/fail/parse/");
|
||||
find_tests(&test_dir, &mut tests);
|
||||
|
@ -106,7 +106,7 @@ impl Token {
|
||||
let mut i = 1;
|
||||
let mut in_escape = false;
|
||||
let mut start = 1usize;
|
||||
let mut segments = vec![];
|
||||
let mut segments = Vec::new();
|
||||
while i < input.len() {
|
||||
if !in_escape {
|
||||
if input[i] == b'"' {
|
||||
@ -212,7 +212,7 @@ impl Token {
|
||||
let (input, comment) = if let Some(eol) = eol {
|
||||
(&input[(eol + 1)..], &input[..eol])
|
||||
} else {
|
||||
(&input[input.len()..input.len()], &input[..])
|
||||
(&input[input.len()..input.len()], input)
|
||||
};
|
||||
return (
|
||||
input,
|
||||
@ -226,7 +226,7 @@ impl Token {
|
||||
let (input, comment) = if let Some(eol) = eol {
|
||||
(&input[(eol + 4)..], &input[..eol + 4])
|
||||
} else {
|
||||
(&input[input.len()..input.len()], &input[..])
|
||||
(&input[input.len()..input.len()], input)
|
||||
};
|
||||
return (
|
||||
input,
|
||||
|
@ -34,7 +34,7 @@ use std::rc::Rc;
|
||||
pub(crate) fn tokenize(path: &str, source: &str) -> Result<Vec<SpannedToken>, TokenError> {
|
||||
let path = Rc::new(path.to_string());
|
||||
let mut input = source.as_bytes();
|
||||
let mut tokens = vec![];
|
||||
let mut tokens = Vec::new();
|
||||
let mut index = 0usize;
|
||||
let mut line_no = 1usize;
|
||||
let mut line_start = 0usize;
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
Loading…
Reference in New Issue
Block a user