mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-28 01:01:53 +03:00
refactor type resolution
This commit is contained in:
parent
1e5c2a7ef9
commit
34d8a552e7
@ -1,5 +1,6 @@
|
|||||||
def foo() -> (fe):
|
|
||||||
return 3fe
|
|
||||||
|
|
||||||
def main() -> (fe):
|
def main() -> (fe):
|
||||||
return foo()
|
a = 1fe
|
||||||
|
for i in 0..4 do
|
||||||
|
a = a + 1fe
|
||||||
|
endfor
|
||||||
|
return a
|
@ -4,10 +4,8 @@
|
|||||||
//! @author Collin Chin <collin@aleo.org>
|
//! @author Collin Chin <collin@aleo.org>
|
||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::program::constraints::{ResolvedProgram, ResolvedValue};
|
||||||
use crate::program::{
|
use crate::program::{new_variable_from_variable, Parameter, Variable};
|
||||||
new_variable_from_variable, BooleanExpression, BooleanSpreadOrExpression, Parameter, Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::{
|
use snarkos_models::gadgets::{
|
||||||
@ -95,181 +93,177 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
// parameter_variable
|
// parameter_variable
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bool_from_variable(
|
pub(crate) fn get_boolean_constant(bool: bool) -> ResolvedValue<F> {
|
||||||
|
ResolvedValue::Boolean(Boolean::Constant(bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub(crate) fn bool_from_variable(&mut self, scope: String, variable: Variable<F>) -> Boolean {
|
||||||
|
// // Evaluate variable name in current function scope
|
||||||
|
// let variable_name = new_scope_from_variable(scope, &variable);
|
||||||
|
//
|
||||||
|
// match self.get(&variable_name) {
|
||||||
|
// Some(value) => match value {
|
||||||
|
// ResolvedValue::Boolean(boolean) => boolean.clone(),
|
||||||
|
// value => unimplemented!(
|
||||||
|
// "expected boolean for variable {}, got {}",
|
||||||
|
// variable_name,
|
||||||
|
// value
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// None => unimplemented!("cannot resolve variable {} in program", variable_name),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn get_bool_value(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// expression: BooleanExpression<F>,
|
||||||
|
// ) -> Boolean {
|
||||||
|
// match expression {
|
||||||
|
// BooleanExpression::Variable(variable) => self.bool_from_variable(scope, variable),
|
||||||
|
// BooleanExpression::Value(value) => Boolean::Constant(value),
|
||||||
|
// expression => match self.enforce_boolean_expression(cs, scope, expression) {
|
||||||
|
// ResolvedValue::Boolean(value) => value,
|
||||||
|
// _ => unimplemented!("boolean expression did not resolve to boolean"),
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub(crate) fn enforce_not(value: ResolvedValue<F>) -> ResolvedValue<F> {
|
||||||
|
match value {
|
||||||
|
ResolvedValue::Boolean(boolean) => ResolvedValue::Boolean(boolean.not()),
|
||||||
|
value => unimplemented!("cannot enforce not on non-boolean value {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enforce_or(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
left: ResolvedValue<F>,
|
||||||
variable: Variable<F>,
|
right: ResolvedValue<F>,
|
||||||
) -> Boolean {
|
) -> ResolvedValue<F> {
|
||||||
// Evaluate variable name in current function scope
|
match (left, right) {
|
||||||
let variable_name = new_scope_from_variable(scope, &variable);
|
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
|
||||||
|
ResolvedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool).unwrap())
|
||||||
if self.contains_name(&variable_name) {
|
|
||||||
// TODO: return synthesis error: "assignment missing" here
|
|
||||||
match self.get(&variable_name).unwrap() {
|
|
||||||
ResolvedValue::Boolean(boolean) => boolean.clone(),
|
|
||||||
_ => panic!("expected a boolean, got field"),
|
|
||||||
}
|
}
|
||||||
} else {
|
(left_value, right_value) => unimplemented!(
|
||||||
let argument = std::env::args()
|
"cannot enforce or on non-boolean values {} || {}",
|
||||||
.nth(1)
|
left_value,
|
||||||
.unwrap_or("true".into())
|
right_value
|
||||||
.parse::<bool>()
|
),
|
||||||
.unwrap();
|
|
||||||
println!(" argument passed to command line a = {:?}\n", argument);
|
|
||||||
// let a = true;
|
|
||||||
Boolean::alloc(cs.ns(|| variable.name), || Ok(argument)).unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bool_value(
|
pub(crate) fn enforce_and(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
left: ResolvedValue<F>,
|
||||||
expression: BooleanExpression<F>,
|
right: ResolvedValue<F>,
|
||||||
) -> Boolean {
|
) -> ResolvedValue<F> {
|
||||||
match expression {
|
match (left, right) {
|
||||||
BooleanExpression::Variable(variable) => self.bool_from_variable(cs, scope, variable),
|
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
|
||||||
BooleanExpression::Value(value) => Boolean::Constant(value),
|
ResolvedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool).unwrap())
|
||||||
expression => match self.enforce_boolean_expression(cs, scope, expression) {
|
}
|
||||||
ResolvedValue::Boolean(value) => value,
|
(left_value, right_value) => unimplemented!(
|
||||||
_ => unimplemented!("boolean expression did not resolve to boolean"),
|
"cannot enforce and on non-boolean values {} && {}",
|
||||||
},
|
left_value,
|
||||||
|
right_value
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_not(
|
pub(crate) fn enforce_boolean_eq(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
left: Boolean,
|
||||||
expression: BooleanExpression<F>,
|
right: Boolean,
|
||||||
) -> Boolean {
|
) -> ResolvedValue<F> {
|
||||||
let expression = self.get_bool_value(cs, scope, expression);
|
|
||||||
|
|
||||||
expression.not()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_or(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: BooleanExpression<F>,
|
|
||||||
right: BooleanExpression<F>,
|
|
||||||
) -> Boolean {
|
|
||||||
let left = self.get_bool_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_bool_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
Boolean::or(cs, &left, &right).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_and(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: BooleanExpression<F>,
|
|
||||||
right: BooleanExpression<F>,
|
|
||||||
) -> Boolean {
|
|
||||||
let left = self.get_bool_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_bool_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
Boolean::and(cs, &left, &right).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_bool_equality(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: BooleanExpression<F>,
|
|
||||||
right: BooleanExpression<F>,
|
|
||||||
) -> Boolean {
|
|
||||||
let left = self.get_bool_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_bool_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)
|
left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Boolean::Constant(true)
|
ResolvedValue::Boolean(Boolean::Constant(true))
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_boolean_expression(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
expression: BooleanExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
match expression {
|
|
||||||
BooleanExpression::Variable(variable) => {
|
|
||||||
ResolvedValue::Boolean(self.bool_from_variable(cs, scope, variable))
|
|
||||||
}
|
|
||||||
BooleanExpression::Value(value) => ResolvedValue::Boolean(Boolean::Constant(value)),
|
|
||||||
BooleanExpression::Not(expression) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_not(cs, scope, *expression))
|
|
||||||
}
|
|
||||||
BooleanExpression::Or(left, right) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_or(cs, scope, *left, *right))
|
|
||||||
}
|
|
||||||
BooleanExpression::And(left, right) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_and(cs, scope, *left, *right))
|
|
||||||
}
|
|
||||||
BooleanExpression::IntegerEq(left, right) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_integer_equality(cs, scope, *left, *right))
|
|
||||||
}
|
|
||||||
BooleanExpression::FieldEq(left, right) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_field_equality(cs, scope, *left, *right))
|
|
||||||
}
|
|
||||||
BooleanExpression::BoolEq(left, right) => {
|
|
||||||
ResolvedValue::Boolean(self.enforce_bool_equality(cs, scope, *left, *right))
|
|
||||||
}
|
|
||||||
BooleanExpression::IfElse(first, second, third) => {
|
|
||||||
let resolved_first =
|
|
||||||
match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
|
||||||
ResolvedValue::Boolean(resolved) => resolved,
|
|
||||||
_ => unimplemented!("if else conditional must resolve to boolean"),
|
|
||||||
};
|
|
||||||
if resolved_first.eq(&Boolean::Constant(true)) {
|
|
||||||
self.enforce_boolean_expression(cs, scope, *second)
|
|
||||||
} else {
|
|
||||||
self.enforce_boolean_expression(cs, scope, *third)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BooleanExpression::Array(array) => {
|
|
||||||
let mut result = vec![];
|
|
||||||
array.into_iter().for_each(|element| match *element {
|
|
||||||
BooleanSpreadOrExpression::Spread(spread) => match spread {
|
|
||||||
BooleanExpression::Variable(variable) => {
|
|
||||||
let array_name = new_scope_from_variable(scope.clone(), &variable);
|
|
||||||
match self.get(&array_name) {
|
|
||||||
Some(value) => match value {
|
|
||||||
ResolvedValue::BooleanArray(array) => {
|
|
||||||
result.extend(array.clone())
|
|
||||||
}
|
|
||||||
value => unimplemented!(
|
|
||||||
"spreads only implemented for arrays, got {}",
|
|
||||||
value
|
|
||||||
),
|
|
||||||
},
|
|
||||||
None => unimplemented!(
|
|
||||||
"cannot copy elements from array that does not exist {}",
|
|
||||||
variable.name
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value => {
|
|
||||||
unimplemented!("spreads only implemented for arrays, got {}", value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BooleanSpreadOrExpression::Expression(expression) => {
|
|
||||||
match self.enforce_boolean_expression(cs, scope.clone(), expression) {
|
|
||||||
ResolvedValue::Boolean(value) => result.push(value),
|
|
||||||
value => {
|
|
||||||
unimplemented!("expected boolean for boolean array, got {}", value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ResolvedValue::BooleanArray(result)
|
|
||||||
}
|
|
||||||
expression => unimplemented!("boolean expression {}", expression),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// pub(crate) fn enforce_boolean_expression(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// expression: BooleanExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// match expression {
|
||||||
|
// BooleanExpression::Variable(variable) => {
|
||||||
|
// ResolvedValue::Boolean(self.bool_from_variable(cs, scope, variable))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::Value(value) => ResolvedValue::Boolean(Boolean::Constant(value)),
|
||||||
|
// BooleanExpression::Not(expression) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_not(cs, scope, *expression))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::Or(left, right) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_or(cs, scope, *left, *right))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::And(left, right) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_and(cs, scope, *left, *right))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::IntegerEq(left, right) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_integer_equality(cs, scope, *left, *right))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::FieldEq(left, right) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_field_equality(cs, scope, *left, *right))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::BoolEq(left, right) => {
|
||||||
|
// ResolvedValue::Boolean(self.enforce_bool_equality(cs, scope, *left, *right))
|
||||||
|
// }
|
||||||
|
// BooleanExpression::IfElse(first, second, third) => {
|
||||||
|
// let resolved_first =
|
||||||
|
// match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
||||||
|
// ResolvedValue::Boolean(resolved) => resolved,
|
||||||
|
// _ => unimplemented!("if else conditional must resolve to boolean"),
|
||||||
|
// };
|
||||||
|
// if resolved_first.eq(&Boolean::Constant(true)) {
|
||||||
|
// self.enforce_boolean_expression(cs, scope, *second)
|
||||||
|
// } else {
|
||||||
|
// self.enforce_boolean_expression(cs, scope, *third)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// BooleanExpression::Array(array) => {
|
||||||
|
// let mut result = vec![];
|
||||||
|
// array.into_iter().for_each(|element| match *element {
|
||||||
|
// BooleanSpreadOrExpression::Spread(spread) => match spread {
|
||||||
|
// BooleanExpression::Variable(variable) => {
|
||||||
|
// let array_name = new_scope_from_variable(scope.clone(), &variable);
|
||||||
|
// match self.get(&array_name) {
|
||||||
|
// Some(value) => match value {
|
||||||
|
// ResolvedValue::BooleanArray(array) => {
|
||||||
|
// result.extend(array.clone())
|
||||||
|
// }
|
||||||
|
// value => unimplemented!(
|
||||||
|
// "spreads only implemented for arrays, got {}",
|
||||||
|
// value
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// None => unimplemented!(
|
||||||
|
// "cannot copy elements from array that does not exist {}",
|
||||||
|
// variable.name
|
||||||
|
// ),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// value => {
|
||||||
|
// unimplemented!("spreads only implemented for arrays, got {}", value)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// BooleanSpreadOrExpression::Expression(expression) => {
|
||||||
|
// match self.enforce_boolean_expression(cs, scope.clone(), expression) {
|
||||||
|
// ResolvedValue::Boolean(value) => result.push(value),
|
||||||
|
// value => {
|
||||||
|
// unimplemented!("expected boolean for boolean array, got {}", value)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// ResolvedValue::BooleanArray(result)
|
||||||
|
// }
|
||||||
|
// expression => unimplemented!("boolean expression {}", expression),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,256 @@
|
|||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
||||||
use crate::program::{
|
use crate::program::{Expression, RangeOrExpression, SpreadOrExpression, StructMember, Variable};
|
||||||
Expression, IntegerExpression, IntegerRangeOrExpression, StructMember, Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
||||||
|
use snarkos_models::gadgets::utilities::boolean::Boolean;
|
||||||
|
|
||||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||||
|
/// Enforce a variable expression by getting the resolved value
|
||||||
|
fn enforce_variable(
|
||||||
|
&mut self,
|
||||||
|
scope: String,
|
||||||
|
unresolved_variable: Variable<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
// Evaluate the variable name in the current function scope
|
||||||
|
let variable_name = new_scope_from_variable(scope, &unresolved_variable);
|
||||||
|
|
||||||
|
if self.contains_name(&variable_name) {
|
||||||
|
// Reassigning variable to another variable
|
||||||
|
self.get_mut(&variable_name).unwrap().clone()
|
||||||
|
} else if self.contains_variable(&unresolved_variable) {
|
||||||
|
// Check global scope (function and struct names)
|
||||||
|
self.get_mut_variable(&unresolved_variable).unwrap().clone()
|
||||||
|
} else {
|
||||||
|
unimplemented!("variable declaration {} not found", variable_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enforce numerical operations
|
||||||
|
fn enforce_add_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_add(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_add(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot add {} + {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_sub_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_sub(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_sub(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot subtract {} - {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_mul_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_mul(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_mul(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot multiply {} * {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_div_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_div(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_div(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot multiply {} * {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn enforce_pow_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_pow(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_pow(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot multiply {} * {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enforce Boolean operations
|
||||||
|
fn enforce_eq_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
left: ResolvedValue<F>,
|
||||||
|
right: ResolvedValue<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match (left, right) {
|
||||||
|
(ResolvedValue::Boolean(bool1), ResolvedValue::Boolean(bool2)) => {
|
||||||
|
self.enforce_boolean_eq(cs, bool1, bool2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||||
|
Self::enforce_u32_eq(cs, num1, num2)
|
||||||
|
}
|
||||||
|
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||||
|
self.enforce_field_eq(fe1, fe2)
|
||||||
|
}
|
||||||
|
(val1, val2) => unimplemented!("cannot enforce equality between {} == {}", val1, val2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enforce array expressions
|
||||||
|
fn enforce_array_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
scope: String,
|
||||||
|
array: Vec<Box<SpreadOrExpression<F>>>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
let mut result = vec![];
|
||||||
|
array.into_iter().for_each(|element| match *element {
|
||||||
|
SpreadOrExpression::Spread(spread) => match spread {
|
||||||
|
Expression::Variable(variable) => {
|
||||||
|
let array_name = new_scope_from_variable(scope.clone(), &variable);
|
||||||
|
match self.get(&array_name) {
|
||||||
|
Some(value) => match value {
|
||||||
|
ResolvedValue::Array(array) => result.extend(array.clone()),
|
||||||
|
value => {
|
||||||
|
unimplemented!("spreads only implemented for arrays, got {}", value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => unimplemented!(
|
||||||
|
"cannot copy elements from array that does not exist {}",
|
||||||
|
variable.name
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value => unimplemented!("spreads only implemented for arrays, got {}", value),
|
||||||
|
},
|
||||||
|
SpreadOrExpression::Expression(expression) => {
|
||||||
|
result.push(self.enforce_expression(cs, scope.clone(), expression));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ResolvedValue::Array(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enforce_index(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
scope: String,
|
||||||
|
index: Expression<F>,
|
||||||
|
) -> usize {
|
||||||
|
match self.enforce_expression(cs, scope.clone(), index) {
|
||||||
|
ResolvedValue::U32(number) => number.value.unwrap() as usize,
|
||||||
|
value => unimplemented!("From index must resolve to an integer, got {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_array_access_expression(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
scope: String,
|
||||||
|
array: Box<Expression<F>>,
|
||||||
|
index: RangeOrExpression<F>,
|
||||||
|
) -> ResolvedValue<F> {
|
||||||
|
match self.enforce_expression(cs, scope.clone(), *array) {
|
||||||
|
ResolvedValue::Array(array) => {
|
||||||
|
match index {
|
||||||
|
RangeOrExpression::Range(from, to) => {
|
||||||
|
let from_resolved = match from {
|
||||||
|
Some(from_index) => from_index.to_usize(),
|
||||||
|
None => 0usize, // Array slice starts at index 0
|
||||||
|
};
|
||||||
|
let to_resolved = match to {
|
||||||
|
Some(to_index) => to_index.to_usize(),
|
||||||
|
None => array.len(), // Array slice ends at array length
|
||||||
|
};
|
||||||
|
ResolvedValue::Array(array[from_resolved..to_resolved].to_owned())
|
||||||
|
}
|
||||||
|
RangeOrExpression::Expression(index) => {
|
||||||
|
let index_resolved = self.enforce_index(cs, scope.clone(), index);
|
||||||
|
array[index_resolved].to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ResolvedValue::U32Array(field_array) => {
|
||||||
|
// match index {
|
||||||
|
// RangeOrExpression::Range(from, to) => {
|
||||||
|
// let from_resolved = match from {
|
||||||
|
// Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
|
||||||
|
// None => 0usize, // Array slice starts at index 0
|
||||||
|
// };
|
||||||
|
// let to_resolved = match to {
|
||||||
|
// Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
|
||||||
|
// None => field_array.len(), // Array slice ends at array length
|
||||||
|
// };
|
||||||
|
// ResolvedValue::U32Array(field_array[from_resolved..to_resolved].to_owned())
|
||||||
|
// }
|
||||||
|
// RangeOrExpression::Expression(index) => {
|
||||||
|
// let index_resolved = self.enforce_index(cs, scope.clone(), index);
|
||||||
|
// ResolvedValue::U32(field_array[index_resolved].to_owned())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ResolvedValue::BooleanArray(bool_array) => {
|
||||||
|
// match index {
|
||||||
|
// RangeOrExpression::Range(from, to) => {
|
||||||
|
// let from_resolved = match from {
|
||||||
|
// Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
|
||||||
|
// None => 0usize, // Array slice starts at index 0
|
||||||
|
// };
|
||||||
|
// let to_resolved = match to {
|
||||||
|
// Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
|
||||||
|
// None => bool_array.len(), // Array slice ends at array length
|
||||||
|
// };
|
||||||
|
// ResolvedValue::BooleanArray(
|
||||||
|
// bool_array[from_resolved..to_resolved].to_owned(),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// RangeOrExpression::Expression(index) => {
|
||||||
|
// let index_resolved = self.enforce_index(cs, scope.clone(), index);
|
||||||
|
// ResolvedValue::Boolean(bool_array[index_resolved].to_owned())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
value => unimplemented!("Cannot access element of untyped array {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn enforce_struct_expression(
|
fn enforce_struct_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
@ -47,70 +289,6 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_index(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
index: IntegerExpression<F>,
|
|
||||||
) -> usize {
|
|
||||||
match self.enforce_integer_expression(cs, scope.clone(), index) {
|
|
||||||
ResolvedValue::U32(number) => number.value.unwrap() as usize,
|
|
||||||
value => unimplemented!("From index must resolve to a uint32, got {}", value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_array_access_expression(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
array: Box<Expression<F>>,
|
|
||||||
index: IntegerRangeOrExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
match self.enforce_expression(cs, scope.clone(), *array) {
|
|
||||||
ResolvedValue::U32Array(field_array) => {
|
|
||||||
match index {
|
|
||||||
IntegerRangeOrExpression::Range(from, to) => {
|
|
||||||
let from_resolved = match from {
|
|
||||||
Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
|
|
||||||
None => 0usize, // Array slice starts at index 0
|
|
||||||
};
|
|
||||||
let to_resolved = match to {
|
|
||||||
Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
|
|
||||||
None => field_array.len(), // Array slice ends at array length
|
|
||||||
};
|
|
||||||
ResolvedValue::U32Array(field_array[from_resolved..to_resolved].to_owned())
|
|
||||||
}
|
|
||||||
IntegerRangeOrExpression::Expression(index) => {
|
|
||||||
let index_resolved = self.enforce_index(cs, scope.clone(), index);
|
|
||||||
ResolvedValue::U32(field_array[index_resolved].to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ResolvedValue::BooleanArray(bool_array) => {
|
|
||||||
match index {
|
|
||||||
IntegerRangeOrExpression::Range(from, to) => {
|
|
||||||
let from_resolved = match from {
|
|
||||||
Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
|
|
||||||
None => 0usize, // Array slice starts at index 0
|
|
||||||
};
|
|
||||||
let to_resolved = match to {
|
|
||||||
Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
|
|
||||||
None => bool_array.len(), // Array slice ends at array length
|
|
||||||
};
|
|
||||||
ResolvedValue::BooleanArray(
|
|
||||||
bool_array[from_resolved..to_resolved].to_owned(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
IntegerRangeOrExpression::Expression(index) => {
|
|
||||||
let index_resolved = self.enforce_index(cs, scope.clone(), index);
|
|
||||||
ResolvedValue::Boolean(bool_array[index_resolved].to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value => unimplemented!("Cannot access element of untyped array {}", value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_struct_access_expression(
|
fn enforce_struct_access_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
@ -152,55 +330,125 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
expression: Expression<F>,
|
expression: Expression<F>,
|
||||||
) -> ResolvedValue<F> {
|
) -> ResolvedValue<F> {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Boolean(boolean_expression) => {
|
// Variables
|
||||||
self.enforce_boolean_expression(cs, scope, boolean_expression)
|
|
||||||
}
|
|
||||||
Expression::Integer(integer_expression) => {
|
|
||||||
self.enforce_integer_expression(cs, scope, integer_expression)
|
|
||||||
}
|
|
||||||
Expression::FieldElement(field_expression) => {
|
|
||||||
self.enforce_field_expression(cs, scope, field_expression)
|
|
||||||
}
|
|
||||||
Expression::Variable(unresolved_variable) => {
|
Expression::Variable(unresolved_variable) => {
|
||||||
let variable_name = new_scope_from_variable(scope, &unresolved_variable);
|
self.enforce_variable(scope, unresolved_variable)
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluate the variable name in the current function scope
|
// Values
|
||||||
if self.contains_name(&variable_name) {
|
Expression::Integer(integer) => Self::get_integer_constant(integer),
|
||||||
// Reassigning variable to another variable
|
Expression::FieldElement(fe) => ResolvedValue::FieldElement(fe),
|
||||||
self.get_mut(&variable_name).unwrap().clone()
|
Expression::Boolean(bool) => Self::get_boolean_constant(bool),
|
||||||
} else if self.contains_variable(&unresolved_variable) {
|
|
||||||
// Check global scope (function and struct names)
|
// Binary operations
|
||||||
self.get_mut_variable(&unresolved_variable).unwrap().clone()
|
Expression::Add(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_add_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Sub(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_sub_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Mul(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_mul_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Div(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_div_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Pow(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_pow_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean operations
|
||||||
|
Expression::Not(expression) => {
|
||||||
|
Self::enforce_not(self.enforce_expression(cs, scope, *expression))
|
||||||
|
}
|
||||||
|
Expression::Or(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_or(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::And(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_and(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Eq(left, right) => {
|
||||||
|
let resolved_left = self.enforce_expression(cs, scope.clone(), *left);
|
||||||
|
let resolved_right = self.enforce_expression(cs, scope.clone(), *right);
|
||||||
|
|
||||||
|
self.enforce_eq_expression(cs, resolved_left, resolved_right)
|
||||||
|
}
|
||||||
|
Expression::Geq(left, right) => {
|
||||||
|
unimplemented!("expression {} >= {} unimplemented", left, right)
|
||||||
|
}
|
||||||
|
Expression::Gt(left, right) => {
|
||||||
|
unimplemented!("expression {} > {} unimplemented", left, right)
|
||||||
|
}
|
||||||
|
Expression::Leq(left, right) => {
|
||||||
|
unimplemented!("expression {} <= {} unimplemented", left, right)
|
||||||
|
}
|
||||||
|
Expression::Lt(left, right) => {
|
||||||
|
unimplemented!("expression {} < {} unimplemented", left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditionals
|
||||||
|
Expression::IfElse(first, second, third) => {
|
||||||
|
let resolved_first = match self.enforce_expression(cs, scope.clone(), *first) {
|
||||||
|
ResolvedValue::Boolean(resolved) => resolved,
|
||||||
|
_ => unimplemented!("if else conditional must resolve to boolean"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if resolved_first.eq(&Boolean::Constant(true)) {
|
||||||
|
self.enforce_expression(cs, scope, *second)
|
||||||
} else {
|
} else {
|
||||||
// The type of the unassigned variable depends on what is passed in
|
self.enforce_expression(cs, scope, *third)
|
||||||
if std::env::args()
|
|
||||||
.nth(1)
|
|
||||||
.expect("variable declaration not passed in")
|
|
||||||
.parse::<bool>()
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
ResolvedValue::Boolean(self.bool_from_variable(
|
|
||||||
cs,
|
|
||||||
variable_name,
|
|
||||||
unresolved_variable,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
self.integer_from_variable(variable_name, unresolved_variable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
Expression::Array(array) => self.enforce_array_expression(cs, scope, array),
|
||||||
|
Expression::ArrayAccess(array, index) => {
|
||||||
|
self.enforce_array_access_expression(cs, scope, array, *index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structs
|
||||||
Expression::Struct(struct_name, members) => {
|
Expression::Struct(struct_name, members) => {
|
||||||
self.enforce_struct_expression(cs, scope, struct_name, members)
|
self.enforce_struct_expression(cs, scope, struct_name, members)
|
||||||
}
|
}
|
||||||
Expression::ArrayAccess(array, index) => {
|
|
||||||
self.enforce_array_access_expression(cs, scope, array, index)
|
|
||||||
}
|
|
||||||
Expression::StructMemberAccess(struct_variable, struct_member) => {
|
Expression::StructMemberAccess(struct_variable, struct_member) => {
|
||||||
self.enforce_struct_access_expression(cs, scope, struct_variable, struct_member)
|
self.enforce_struct_access_expression(cs, scope, struct_variable, struct_member)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions
|
||||||
Expression::FunctionCall(function, arguments) => {
|
Expression::FunctionCall(function, arguments) => {
|
||||||
self.enforce_function_access_expression(cs, scope, function, arguments)
|
self.enforce_function_access_expression(cs, scope, function, arguments)
|
||||||
} // expression => unimplemented!("expression not impl {}", expression),
|
}
|
||||||
|
// Expression::BooleanExp(boolean_expression) => {
|
||||||
|
// self.enforce_boolean_expression(cs, scope, boolean_expression)
|
||||||
|
// }
|
||||||
|
// Expression::IntegerExp(integer_expression) => {
|
||||||
|
// self.enforce_integer_expression(cs, scope, integer_expression)
|
||||||
|
// }
|
||||||
|
// Expression::FieldElementExp(field_expression) => {
|
||||||
|
// self.enforce_field_expression(cs, scope, field_expression)
|
||||||
|
// }
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
//! @author Collin Chin <collin@aleo.org>
|
//! @author Collin Chin <collin@aleo.org>
|
||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::program::constraints::{ResolvedProgram, ResolvedValue};
|
||||||
use crate::program::{
|
use crate::program::{new_variable_from_variable, Parameter, Variable};
|
||||||
new_variable_from_variable, FieldExpression, FieldSpreadOrExpression, Parameter, Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean};
|
use snarkos_models::gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean};
|
||||||
@ -92,181 +90,188 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
// parameter_variable
|
// parameter_variable
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_element_from_variable(&mut self, scope: String, variable: Variable<F>) -> F {
|
// fn field_element_from_variable(&mut self, scope: String, variable: Variable<F>) -> F {
|
||||||
// Evaluate variable name in current function scope
|
// // Evaluate variable name in current function scope
|
||||||
let variable_name = new_scope_from_variable(scope, &variable);
|
// let variable_name = new_scope_from_variable(scope, &variable);
|
||||||
|
//
|
||||||
|
// match self.get(&variable_name) {
|
||||||
|
// Some(value) => match value {
|
||||||
|
// ResolvedValue::FieldElement(fe) => fe.clone(),
|
||||||
|
// value => unimplemented!(
|
||||||
|
// "expected field element for variable {}, got {}",
|
||||||
|
// variable_name,
|
||||||
|
// value
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// None => unimplemented!("cannot resolve variable {} in program", variable_name),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if self.contains_name(&variable_name) {
|
// fn get_field_value(&mut self, cs: &mut CS, scope: String, expression: FieldExpression<F>) -> F {
|
||||||
// TODO: return synthesis error: "assignment missing" here
|
// match expression {
|
||||||
match self.get(&variable_name).unwrap().clone() {
|
// FieldExpression::Variable(variable) => {
|
||||||
ResolvedValue::FieldElement(fe) => fe,
|
// self.field_element_from_variable(scope, variable)
|
||||||
value => unimplemented!(
|
// }
|
||||||
"expected field element for variable {}, got {}",
|
// FieldExpression::Number(element) => element,
|
||||||
variable_name,
|
// }
|
||||||
value
|
// }
|
||||||
),
|
|
||||||
}
|
pub(crate) fn enforce_field_eq(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||||
} else {
|
ResolvedValue::Boolean(Boolean::Constant(fe1.eq(&fe2)))
|
||||||
unimplemented!("cannot resolve variable {} in program", variable_name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_field_value(&mut self, cs: &mut CS, scope: String, expression: FieldExpression<F>) -> F {
|
pub(crate) fn enforce_field_add(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||||
match expression {
|
ResolvedValue::FieldElement(fe1.add(&fe2))
|
||||||
FieldExpression::Variable(variable) => {
|
|
||||||
self.field_element_from_variable(scope, variable)
|
|
||||||
}
|
|
||||||
FieldExpression::Number(element) => element,
|
|
||||||
expression => match self.enforce_field_expression(cs, scope, expression) {
|
|
||||||
ResolvedValue::FieldElement(element) => element,
|
|
||||||
value => unimplemented!("expected field element, got {}", value),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_field_equality(
|
pub(crate) fn enforce_field_sub(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||||
&mut self,
|
ResolvedValue::FieldElement(fe1.sub(&fe2))
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: FieldExpression<F>,
|
|
||||||
right: FieldExpression<F>,
|
|
||||||
) -> Boolean {
|
|
||||||
let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_field_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
Boolean::Constant(left.eq(&right))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_field_add(
|
pub(crate) fn enforce_field_mul(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||||
&mut self,
|
ResolvedValue::FieldElement(fe1.mul(&fe2))
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: FieldExpression<F>,
|
|
||||||
right: FieldExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_field_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
ResolvedValue::FieldElement(left.add(&right))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_field_sub(
|
pub(crate) fn enforce_field_div(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||||
&mut self,
|
ResolvedValue::FieldElement(fe1.div(&fe2))
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: FieldExpression<F>,
|
|
||||||
right: FieldExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_field_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
ResolvedValue::FieldElement(left.sub(&right))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_field_mul(
|
pub(crate) fn enforce_field_pow(&mut self, _fe1: F, _fe2: F) -> ResolvedValue<F> {
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: FieldExpression<F>,
|
|
||||||
right: FieldExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_field_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
ResolvedValue::FieldElement(left.mul(&right))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_field_div(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: FieldExpression<F>,
|
|
||||||
right: FieldExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_field_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
ResolvedValue::FieldElement(left.div(&right))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_field_pow(
|
|
||||||
&mut self,
|
|
||||||
_cs: &mut CS,
|
|
||||||
_scope: String,
|
|
||||||
_left: FieldExpression<F>,
|
|
||||||
_right: FieldExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
unimplemented!("field element exponentiation not supported")
|
unimplemented!("field element exponentiation not supported")
|
||||||
// let left = self.get_field_value(cs, scope.clone(), left);
|
|
||||||
// let right = self.get_field_value(cs, scope.clone(), right);
|
// ResolvedValue::FieldElement(fe1.pow(&fe2))
|
||||||
//
|
|
||||||
// ResolvedValue::FieldElement(left.pow(&right))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_field_expression(
|
// fn enforce_field_add_old(
|
||||||
&mut self,
|
// &mut self,
|
||||||
cs: &mut CS,
|
// cs: &mut CS,
|
||||||
scope: String,
|
// scope: String,
|
||||||
expression: FieldExpression<F>,
|
// left: FieldExpression<F>,
|
||||||
) -> ResolvedValue<F> {
|
// right: FieldExpression<F>,
|
||||||
match expression {
|
// ) -> ResolvedValue<F> {
|
||||||
FieldExpression::Variable(variable) => {
|
// let left = self.get_field_value(cs, scope.clone(), left);
|
||||||
ResolvedValue::FieldElement(self.field_element_from_variable(scope, variable))
|
// let right = self.get_field_value(cs, scope.clone(), right);
|
||||||
}
|
//
|
||||||
FieldExpression::Number(field) => ResolvedValue::FieldElement(field),
|
// ResolvedValue::FieldElement(left.add(&right))
|
||||||
FieldExpression::Add(left, right) => self.enforce_field_add(cs, scope, *left, *right),
|
// }
|
||||||
FieldExpression::Sub(left, right) => self.enforce_field_sub(cs, scope, *left, *right),
|
//
|
||||||
FieldExpression::Mul(left, right) => self.enforce_field_mul(cs, scope, *left, *right),
|
// fn enforce_field_sub_old(
|
||||||
FieldExpression::Div(left, right) => self.enforce_field_div(cs, scope, *left, *right),
|
// &mut self,
|
||||||
FieldExpression::Pow(left, right) => self.enforce_field_pow(cs, scope, *left, *right),
|
// cs: &mut CS,
|
||||||
FieldExpression::IfElse(first, second, third) => {
|
// scope: String,
|
||||||
let resolved_first =
|
// left: FieldExpression<F>,
|
||||||
match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
// right: FieldExpression<F>,
|
||||||
ResolvedValue::Boolean(resolved) => resolved,
|
// ) -> ResolvedValue<F> {
|
||||||
_ => unimplemented!("if else conditional must resolve to boolean"),
|
// let left = self.get_field_value(cs, scope.clone(), left);
|
||||||
};
|
// let right = self.get_field_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// ResolvedValue::FieldElement(left.sub(&right))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_field_mul_old(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// left: FieldExpression<F>,
|
||||||
|
// right: FieldExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// let left = self.get_field_value(cs, scope.clone(), left);
|
||||||
|
// let right = self.get_field_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// ResolvedValue::FieldElement(left.mul(&right))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_field_div_old(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// left: FieldExpression<F>,
|
||||||
|
// right: FieldExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// let left = self.get_field_value(cs, scope.clone(), left);
|
||||||
|
// let right = self.get_field_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// ResolvedValue::FieldElement(left.div(&right))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_field_pow_old(
|
||||||
|
// &mut self,
|
||||||
|
// _cs: &mut CS,
|
||||||
|
// _scope: String,
|
||||||
|
// _left: FieldExpression<F>,
|
||||||
|
// _right: FieldExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// unimplemented!("field element exponentiation not supported")
|
||||||
|
// // let left = self.get_field_value(cs, scope.clone(), left);
|
||||||
|
// // let right = self.get_field_value(cs, scope.clone(), right);
|
||||||
|
// //
|
||||||
|
// // ResolvedValue::FieldElement(left.pow(&right))
|
||||||
|
// }
|
||||||
|
|
||||||
if resolved_first.eq(&Boolean::Constant(true)) {
|
// pub(crate) fn enforce_field_expression(
|
||||||
self.enforce_field_expression(cs, scope, *second)
|
// &mut self,
|
||||||
} else {
|
// cs: &mut CS,
|
||||||
self.enforce_field_expression(cs, scope, *third)
|
// scope: String,
|
||||||
}
|
// expression: FieldExpression<F>,
|
||||||
}
|
// ) -> ResolvedValue<F> {
|
||||||
FieldExpression::Array(array) => {
|
// match expression {
|
||||||
let mut result = vec![];
|
// FieldExpression::Variable(variable) => {
|
||||||
array.into_iter().for_each(|element| match *element {
|
// ResolvedValue::FieldElement(self.field_element_from_variable(scope, variable))
|
||||||
FieldSpreadOrExpression::Spread(spread) => match spread {
|
// }
|
||||||
FieldExpression::Variable(variable) => {
|
// FieldExpression::Number(field) => ResolvedValue::FieldElement(field),
|
||||||
let array_name = new_scope_from_variable(scope.clone(), &variable);
|
// FieldExpression::Add(left, right) => self.enforce_field_add_old(cs, scope, *left, *right),
|
||||||
match self.get(&array_name) {
|
// FieldExpression::Sub(left, right) => self.enforce_field_sub_old(cs, scope, *left, *right),
|
||||||
Some(value) => match value {
|
// FieldExpression::Mul(left, right) => self.enforce_field_mul_old(cs, scope, *left, *right),
|
||||||
ResolvedValue::FieldElementArray(array) => {
|
// FieldExpression::Div(left, right) => self.enforce_field_div_old(cs, scope, *left, *right),
|
||||||
result.extend(array.clone())
|
// FieldExpression::Pow(left, right) => self.enforce_field_pow_old(cs, scope, *left, *right),
|
||||||
}
|
// FieldExpression::IfElse(first, second, third) => {
|
||||||
value => unimplemented!(
|
// let resolved_first =
|
||||||
"spreads only implemented for arrays, got {}",
|
// match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
||||||
value
|
// ResolvedValue::Boolean(resolved) => resolved,
|
||||||
),
|
// _ => unimplemented!("if else conditional must resolve to boolean"),
|
||||||
},
|
// };
|
||||||
None => unimplemented!(
|
//
|
||||||
"cannot copy elements from array that does not exist {}",
|
// if resolved_first.eq(&Boolean::Constant(true)) {
|
||||||
variable.name
|
// self.enforce_field_expression(cs, scope, *second)
|
||||||
),
|
// } else {
|
||||||
}
|
// self.enforce_field_expression(cs, scope, *third)
|
||||||
}
|
// }
|
||||||
value => {
|
// }
|
||||||
unimplemented!("spreads only implemented for arrays, got {}", value)
|
// FieldExpression::Array(array) => {
|
||||||
}
|
// let mut result = vec![];
|
||||||
},
|
// array.into_iter().for_each(|element| match *element {
|
||||||
FieldSpreadOrExpression::Expression(expression) => {
|
// FieldSpreadOrExpression::Spread(spread) => match spread {
|
||||||
match self.enforce_field_expression(cs, scope.clone(), expression) {
|
// FieldExpression::Variable(variable) => {
|
||||||
ResolvedValue::FieldElement(value) => result.push(value),
|
// let array_name = new_scope_from_variable(scope.clone(), &variable);
|
||||||
_ => unimplemented!("cannot resolve field"),
|
// match self.get(&array_name) {
|
||||||
}
|
// Some(value) => match value {
|
||||||
}
|
// ResolvedValue::FieldElementArray(array) => {
|
||||||
});
|
// result.extend(array.clone())
|
||||||
ResolvedValue::FieldElementArray(result)
|
// }
|
||||||
}
|
// value => unimplemented!(
|
||||||
}
|
// "spreads only implemented for arrays, got {}",
|
||||||
}
|
// value
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// None => unimplemented!(
|
||||||
|
// "cannot copy elements from array that does not exist {}",
|
||||||
|
// variable.name
|
||||||
|
// ),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// value => {
|
||||||
|
// unimplemented!("spreads only implemented for arrays, got {}", value)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// FieldSpreadOrExpression::Expression(expression) => {
|
||||||
|
// match self.enforce_field_expression(cs, scope.clone(), expression) {
|
||||||
|
// ResolvedValue::FieldElement(value) => result.push(value),
|
||||||
|
// _ => unimplemented!("cannot resolve field"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// ResolvedValue::FieldElementArray(result)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,8 @@
|
|||||||
//! @author Collin Chin <collin@aleo.org>
|
//! @author Collin Chin <collin@aleo.org>
|
||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::program::constraints::{ResolvedProgram, ResolvedValue};
|
||||||
use crate::program::{
|
use crate::program::{new_variable_from_variable, Integer, Parameter, Variable};
|
||||||
new_variable_from_variable, Integer, IntegerExpression, IntegerSpreadOrExpression, Parameter,
|
|
||||||
Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::{
|
use snarkos_models::gadgets::{
|
||||||
@ -96,42 +93,36 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
// parameter_variable
|
// parameter_variable
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn integer_from_variable(
|
// pub(crate) fn integer_from_variable(
|
||||||
&mut self,
|
// &mut self,
|
||||||
scope: String,
|
// scope: String,
|
||||||
variable: Variable<F>,
|
// variable: Variable<F>,
|
||||||
) -> ResolvedValue<F> {
|
// ) -> ResolvedValue<F> {
|
||||||
// Evaluate variable name in current function scope
|
// // Evaluate variable name in current function scope
|
||||||
let variable_name = new_scope_from_variable(scope, &variable);
|
// let variable_name = new_scope_from_variable(scope, &variable);
|
||||||
|
//
|
||||||
|
// match self.get(&variable_name) {
|
||||||
|
// Some(value) => value.clone(),
|
||||||
|
// None => unimplemented!("cannot resolve variable {} in program", variable_name),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if self.contains_name(&variable_name) {
|
pub(crate) fn get_integer_constant(integer: Integer) -> ResolvedValue<F> {
|
||||||
// TODO: return synthesis error: "assignment missing" here
|
|
||||||
self.get(&variable_name).unwrap().clone()
|
|
||||||
} else {
|
|
||||||
unimplemented!("cannot resolve variable {} in program", variable_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_integer_constant(integer: Integer) -> ResolvedValue<F> {
|
|
||||||
match integer {
|
match integer {
|
||||||
Integer::U32(u32_value) => ResolvedValue::U32(UInt32::constant(u32_value)),
|
Integer::U32(u32_value) => ResolvedValue::U32(UInt32::constant(u32_value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// pub(crate) fn get_integer_value(
|
||||||
|
// integer: Integer
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// match expression {
|
||||||
|
// IntegerExpression::Variable(variable) => self.integer_from_variable(scope, variable),
|
||||||
|
// IntegerExpression::Number(number) => Self::get_integer_constant(number),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
fn get_integer_value(
|
pub(crate) fn enforce_u32_eq(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
expression: IntegerExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
match expression {
|
|
||||||
IntegerExpression::Variable(variable) => self.integer_from_variable(scope, variable),
|
|
||||||
IntegerExpression::Number(number) => Self::get_integer_constant(number),
|
|
||||||
expression => self.enforce_integer_expression(cs, scope, expression),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_equality(cs: &mut CS, left: UInt32, right: UInt32) -> Boolean {
|
|
||||||
left.conditional_enforce_equal(
|
left.conditional_enforce_equal(
|
||||||
cs.ns(|| format!("enforce field equal")),
|
cs.ns(|| format!("enforce field equal")),
|
||||||
&right,
|
&right,
|
||||||
@ -139,30 +130,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Boolean::Constant(true)
|
ResolvedValue::Boolean(Boolean::Constant(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_integer_equality(
|
pub(crate) fn enforce_u32_add(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: IntegerExpression<F>,
|
|
||||||
right: IntegerExpression<F>,
|
|
||||||
) -> Boolean {
|
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
|
||||||
Self::enforce_u32_equality(cs, left_u32, right_u32)
|
|
||||||
}
|
|
||||||
(left_int, right_int) => {
|
|
||||||
unimplemented!("equality not impl between {} == {}", left_int, right_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_add(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
|
||||||
ResolvedValue::U32(
|
ResolvedValue::U32(
|
||||||
UInt32::addmany(
|
UInt32::addmany(
|
||||||
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
|
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
@ -172,27 +143,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_integer_add(
|
pub(crate) fn enforce_u32_sub(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: IntegerExpression<F>,
|
|
||||||
right: IntegerExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
|
||||||
Self::enforce_u32_add(cs, left_u32, right_u32)
|
|
||||||
}
|
|
||||||
(left_int, right_int) => {
|
|
||||||
unimplemented!("add not impl between {} + {}", left_int, right_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_sub(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
|
||||||
ResolvedValue::U32(
|
ResolvedValue::U32(
|
||||||
left.sub(
|
left.sub(
|
||||||
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
@ -202,27 +153,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_integer_sub(
|
pub(crate) fn enforce_u32_mul(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: IntegerExpression<F>,
|
|
||||||
right: IntegerExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
|
||||||
Self::enforce_u32_sub(cs, left_u32, right_u32)
|
|
||||||
}
|
|
||||||
(left_int, right_int) => {
|
|
||||||
unimplemented!("add not impl between {} + {}", left_int, right_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_mul(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
|
||||||
ResolvedValue::U32(
|
ResolvedValue::U32(
|
||||||
left.mul(
|
left.mul(
|
||||||
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
@ -231,28 +162,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
pub(crate) fn enforce_u32_div(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
fn enforce_integer_mul(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: IntegerExpression<F>,
|
|
||||||
right: IntegerExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
|
||||||
Self::enforce_u32_mul(cs, left_u32, right_u32)
|
|
||||||
}
|
|
||||||
(left_int, right_int) => {
|
|
||||||
unimplemented!("add not impl between {} + {}", left_int, right_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_div(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
|
||||||
ResolvedValue::U32(
|
ResolvedValue::U32(
|
||||||
left.div(
|
left.div(
|
||||||
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
@ -261,28 +171,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
pub(crate) fn enforce_u32_pow(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
fn enforce_integer_div(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
scope: String,
|
|
||||||
left: IntegerExpression<F>,
|
|
||||||
right: IntegerExpression<F>,
|
|
||||||
) -> ResolvedValue<F> {
|
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
|
||||||
Self::enforce_u32_div(cs, left_u32, right_u32)
|
|
||||||
}
|
|
||||||
(left_int, right_int) => {
|
|
||||||
unimplemented!("add not impl between {} + {}", left_int, right_int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enforce_u32_pow(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
|
||||||
ResolvedValue::U32(
|
ResolvedValue::U32(
|
||||||
left.pow(
|
left.pow(
|
||||||
cs.ns(|| {
|
cs.ns(|| {
|
||||||
@ -298,96 +187,242 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_integer_pow(
|
// pub(crate) fn enforce_integer_equality(
|
||||||
&mut self,
|
// &mut self,
|
||||||
cs: &mut CS,
|
// cs: &mut CS,
|
||||||
scope: String,
|
// scope: String,
|
||||||
left: IntegerExpression<F>,
|
// left: UInt32,
|
||||||
right: IntegerExpression<F>,
|
// right: UInt32,
|
||||||
) -> ResolvedValue<F> {
|
// ) -> Boolean {
|
||||||
let left = self.get_integer_value(cs, scope.clone(), left);
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
let right = self.get_integer_value(cs, scope.clone(), right);
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// match (left, right) {
|
||||||
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
|
// Self::enforce_u32_equality(cs, left_u32, right_u32)
|
||||||
|
// }
|
||||||
|
// (left_int, right_int) => {
|
||||||
|
// unimplemented!("equality not impl between {} == {}", left_int, right_int)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
match (left, right) {
|
// fn enforce_integer_add_old(
|
||||||
(ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
// &mut self,
|
||||||
Self::enforce_u32_pow(cs, left_u32, right_u32)
|
// cs: &mut CS,
|
||||||
}
|
// scope: String,
|
||||||
(left_int, right_int) => {
|
// left: IntegerExpression<F>,
|
||||||
unimplemented!("add not impl between {} + {}", left_int, right_int)
|
// right: IntegerExpression<F>,
|
||||||
}
|
// ) -> ResolvedValue<F> {
|
||||||
}
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
}
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// match (left, right) {
|
||||||
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
|
// Self::enforce_u32_add(cs, left_u32, right_u32)
|
||||||
|
// }
|
||||||
|
// (left_int, right_int) => {
|
||||||
|
// unimplemented!("add not impl between {} + {}", left_int, right_int)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub(crate) fn enforce_integer_expression(
|
// fn enforce_u32_sub_old(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
&mut self,
|
// ResolvedValue::U32(
|
||||||
cs: &mut CS,
|
// left.sub(
|
||||||
scope: String,
|
// cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
expression: IntegerExpression<F>,
|
// &right,
|
||||||
) -> ResolvedValue<F> {
|
// )
|
||||||
match expression {
|
// .unwrap(),
|
||||||
IntegerExpression::Variable(variable) => self.integer_from_variable(scope, variable),
|
// )
|
||||||
IntegerExpression::Number(number) => Self::get_integer_constant(number),
|
// }
|
||||||
IntegerExpression::Add(left, right) => {
|
|
||||||
self.enforce_integer_add(cs, scope, *left, *right)
|
|
||||||
}
|
|
||||||
IntegerExpression::Sub(left, right) => {
|
|
||||||
self.enforce_integer_sub(cs, scope, *left, *right)
|
|
||||||
}
|
|
||||||
IntegerExpression::Mul(left, right) => {
|
|
||||||
self.enforce_integer_mul(cs, scope, *left, *right)
|
|
||||||
}
|
|
||||||
IntegerExpression::Div(left, right) => {
|
|
||||||
self.enforce_integer_div(cs, scope, *left, *right)
|
|
||||||
}
|
|
||||||
IntegerExpression::Pow(left, right) => {
|
|
||||||
self.enforce_integer_pow(cs, scope, *left, *right)
|
|
||||||
}
|
|
||||||
IntegerExpression::IfElse(first, second, third) => {
|
|
||||||
let resolved_first =
|
|
||||||
match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
|
||||||
ResolvedValue::Boolean(resolved) => resolved,
|
|
||||||
_ => unimplemented!("if else conditional must resolve to boolean"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if resolved_first.eq(&Boolean::Constant(true)) {
|
// fn enforce_integer_sub(
|
||||||
self.enforce_integer_expression(cs, scope, *second)
|
// &mut self,
|
||||||
} else {
|
// cs: &mut CS,
|
||||||
self.enforce_integer_expression(cs, scope, *third)
|
// scope: String,
|
||||||
}
|
// left: IntegerExpression<F>,
|
||||||
}
|
// right: IntegerExpression<F>,
|
||||||
IntegerExpression::Array(array) => {
|
// ) -> ResolvedValue<F> {
|
||||||
let mut result = vec![];
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
array.into_iter().for_each(|element| match *element {
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
IntegerSpreadOrExpression::Spread(spread) => match spread {
|
//
|
||||||
IntegerExpression::Variable(variable) => {
|
// match (left, right) {
|
||||||
let array_name = new_scope_from_variable(scope.clone(), &variable);
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
match self.get(&array_name) {
|
// Self::enforce_u32_sub_old(cs, left_u32, right_u32)
|
||||||
Some(value) => match value {
|
// }
|
||||||
ResolvedValue::U32Array(array) => result.extend(array.clone()),
|
// (left_int, right_int) => {
|
||||||
value => unimplemented!(
|
// unimplemented!("add not impl between {} + {}", left_int, right_int)
|
||||||
"spreads only implemented for arrays, got {}",
|
// }
|
||||||
value
|
// }
|
||||||
),
|
// }
|
||||||
},
|
|
||||||
None => unimplemented!(
|
// fn enforce_u32_mul_old(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
"cannot copy elements from array that does not exist {}",
|
// ResolvedValue::U32(
|
||||||
variable.name
|
// left.mul(
|
||||||
),
|
// cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
}
|
// &right,
|
||||||
}
|
// )
|
||||||
value => {
|
// .unwrap(),
|
||||||
unimplemented!("spreads only implemented for arrays, got {}", value)
|
// )
|
||||||
}
|
// }
|
||||||
},
|
//
|
||||||
IntegerSpreadOrExpression::Expression(expression) => {
|
// fn enforce_integer_mul(
|
||||||
match self.enforce_integer_expression(cs, scope.clone(), expression) {
|
// &mut self,
|
||||||
ResolvedValue::U32(value) => result.push(value),
|
// cs: &mut CS,
|
||||||
_ => unimplemented!("cannot resolve field"),
|
// scope: String,
|
||||||
}
|
// left: IntegerExpression<F>,
|
||||||
}
|
// right: IntegerExpression<F>,
|
||||||
});
|
// ) -> ResolvedValue<F> {
|
||||||
ResolvedValue::U32Array(result)
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
}
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
}
|
//
|
||||||
}
|
// match (left, right) {
|
||||||
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
|
// Self::enforce_u32_mul_old(cs, left_u32, right_u32)
|
||||||
|
// }
|
||||||
|
// (left_int, right_int) => {
|
||||||
|
// unimplemented!("add not impl between {} + {}", left_int, right_int)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_u32_div_old(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
|
// ResolvedValue::U32(
|
||||||
|
// left.div(
|
||||||
|
// cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
||||||
|
// &right,
|
||||||
|
// )
|
||||||
|
// .unwrap(),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_integer_div(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// left: IntegerExpression<F>,
|
||||||
|
// right: IntegerExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// match (left, right) {
|
||||||
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
|
// Self::enforce_u32_div_old(cs, left_u32, right_u32)
|
||||||
|
// }
|
||||||
|
// (left_int, right_int) => {
|
||||||
|
// unimplemented!("add not impl between {} + {}", left_int, right_int)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_u32_pow_old(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||||
|
// ResolvedValue::U32(
|
||||||
|
// left.pow(
|
||||||
|
// cs.ns(|| {
|
||||||
|
// format!(
|
||||||
|
// "enforce {} ** {}",
|
||||||
|
// left.value.unwrap(),
|
||||||
|
// right.value.unwrap()
|
||||||
|
// )
|
||||||
|
// }),
|
||||||
|
// &right,
|
||||||
|
// )
|
||||||
|
// .unwrap(),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fn enforce_integer_pow(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// left: IntegerExpression<F>,
|
||||||
|
// right: IntegerExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// let left = self.get_integer_value(cs, scope.clone(), left);
|
||||||
|
// let right = self.get_integer_value(cs, scope.clone(), right);
|
||||||
|
//
|
||||||
|
// match (left, right) {
|
||||||
|
// (ResolvedValue::U32(left_u32), ResolvedValue::U32(right_u32)) => {
|
||||||
|
// Self::enforce_u32_pow_old(cs, left_u32, right_u32)
|
||||||
|
// }
|
||||||
|
// (left_int, right_int) => {
|
||||||
|
// unimplemented!("add not impl between {} + {}", left_int, right_int)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub(crate) fn enforce_integer_expression(
|
||||||
|
// &mut self,
|
||||||
|
// cs: &mut CS,
|
||||||
|
// scope: String,
|
||||||
|
// expression: IntegerExpression<F>,
|
||||||
|
// ) -> ResolvedValue<F> {
|
||||||
|
// match expression {
|
||||||
|
// IntegerExpression::Variable(variable) => self.integer_from_variable(scope, variable),
|
||||||
|
// IntegerExpression::Number(number) => Self::get_integer_constant(number),
|
||||||
|
// IntegerExpression::Add(left, right) => {
|
||||||
|
// self.enforce_integer_add_old(cs, scope, *left, *right)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Sub(left, right) => {
|
||||||
|
// self.enforce_integer_sub(cs, scope, *left, *right)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Mul(left, right) => {
|
||||||
|
// self.enforce_integer_mul(cs, scope, *left, *right)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Div(left, right) => {
|
||||||
|
// self.enforce_integer_div(cs, scope, *left, *right)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Pow(left, right) => {
|
||||||
|
// self.enforce_integer_pow(cs, scope, *left, *right)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::IfElse(first, second, third) => {
|
||||||
|
// let resolved_first =
|
||||||
|
// match self.enforce_boolean_expression(cs, scope.clone(), *first) {
|
||||||
|
// ResolvedValue::Boolean(resolved) => resolved,
|
||||||
|
// _ => unimplemented!("if else conditional must resolve to boolean"),
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// if resolved_first.eq(&Boolean::Constant(true)) {
|
||||||
|
// self.enforce_integer_expression(cs, scope, *second)
|
||||||
|
// } else {
|
||||||
|
// self.enforce_integer_expression(cs, scope, *third)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Array(array) => {
|
||||||
|
// let mut result = vec![];
|
||||||
|
// array.into_iter().for_each(|element| match *element {
|
||||||
|
// IntegerSpreadOrExpression::Spread(spread) => match spread {
|
||||||
|
// IntegerExpression::Variable(variable) => {
|
||||||
|
// let array_name = new_scope_from_variable(scope.clone(), &variable);
|
||||||
|
// match self.get(&array_name) {
|
||||||
|
// Some(value) => match value {
|
||||||
|
// ResolvedValue::U32Array(array) => result.extend(array.clone()),
|
||||||
|
// value => unimplemented!(
|
||||||
|
// "spreads only implemented for arrays, got {}",
|
||||||
|
// value
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// None => unimplemented!(
|
||||||
|
// "cannot copy elements from array that does not exist {}",
|
||||||
|
// variable.name
|
||||||
|
// ),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// value => {
|
||||||
|
// unimplemented!("spreads only implemented for arrays, got {}", value)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// IntegerSpreadOrExpression::Expression(expression) => {
|
||||||
|
// match self.enforce_integer_expression(cs, scope.clone(), expression) {
|
||||||
|
// ResolvedValue::U32(value) => result.push(value),
|
||||||
|
// _ => unimplemented!("cannot resolve field"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// ResolvedValue::U32Array(result)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,9 @@ use std::fmt;
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ResolvedValue<F: Field + PrimeField> {
|
pub enum ResolvedValue<F: Field + PrimeField> {
|
||||||
U32(UInt32),
|
U32(UInt32),
|
||||||
U32Array(Vec<UInt32>),
|
|
||||||
FieldElement(F),
|
FieldElement(F),
|
||||||
FieldElementArray(Vec<F>),
|
|
||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
BooleanArray(Vec<Boolean>),
|
Array(Vec<ResolvedValue<F>>),
|
||||||
StructDefinition(Struct<F>),
|
StructDefinition(Struct<F>),
|
||||||
StructExpression(Variable<F>, Vec<StructMember<F>>),
|
StructExpression(Variable<F>, Vec<StructMember<F>>),
|
||||||
Function(Function<F>),
|
Function(Function<F>),
|
||||||
@ -28,17 +26,22 @@ impl<F: Field + PrimeField> ResolvedValue<F> {
|
|||||||
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
||||||
match (self, ty) {
|
match (self, ty) {
|
||||||
(ResolvedValue::U32(ref _a), Type::U32) => true,
|
(ResolvedValue::U32(ref _a), Type::U32) => true,
|
||||||
(ResolvedValue::U32Array(ref arr), Type::Array(ref arr_type, ref len)) => {
|
|
||||||
(arr.len() == *len) & (**arr_type == Type::U32)
|
|
||||||
}
|
|
||||||
(ResolvedValue::FieldElement(ref _a), Type::FieldElement) => true,
|
(ResolvedValue::FieldElement(ref _a), Type::FieldElement) => true,
|
||||||
(ResolvedValue::FieldElementArray(ref arr), Type::Array(ref arr_type, ref len)) => {
|
|
||||||
(arr.len() == *len) & (**arr_type == Type::FieldElement)
|
|
||||||
}
|
|
||||||
(ResolvedValue::Boolean(ref _a), Type::Boolean) => true,
|
(ResolvedValue::Boolean(ref _a), Type::Boolean) => true,
|
||||||
(ResolvedValue::BooleanArray(ref arr), Type::Array(ref arr_type, ref len)) => {
|
(ResolvedValue::Array(ref _arr), Type::Array(ref _ty, ref _len)) => true, // todo: add array types
|
||||||
(arr.len() == *len) & (**arr_type == Type::Boolean)
|
// (ResolvedValue::U32Array(ref arr), Type::Array(ref arr_type, ref len)) => {
|
||||||
}
|
// (arr.len() == *len) & (**arr_type == Type::U32)
|
||||||
|
// }
|
||||||
|
// (ResolvedValue::FieldElementArray(ref arr), Type::Array(ref arr_type, ref len)) => {
|
||||||
|
// (arr.len() == *len) & (**arr_type == Type::FieldElement)
|
||||||
|
// }
|
||||||
|
// (ResolvedValue::BooleanArray(ref arr), Type::Array(ref arr_type, ref len)) => {
|
||||||
|
// (arr.len() == *len) & (**arr_type == Type::Boolean)
|
||||||
|
// }
|
||||||
|
(
|
||||||
|
ResolvedValue::StructExpression(ref actual_name, ref _members),
|
||||||
|
Type::Struct(ref expected_name),
|
||||||
|
) => actual_name == expected_name,
|
||||||
(ResolvedValue::Return(ref values), ty) => {
|
(ResolvedValue::Return(ref values), ty) => {
|
||||||
let mut res = true;
|
let mut res = true;
|
||||||
for value in values {
|
for value in values {
|
||||||
@ -55,18 +58,9 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ResolvedValue::U32(ref value) => write!(f, "{}", value.value.unwrap()),
|
ResolvedValue::U32(ref value) => write!(f, "{}", value.value.unwrap()),
|
||||||
ResolvedValue::U32Array(ref array) => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
for (i, e) in array.iter().enumerate() {
|
|
||||||
write!(f, "{}", e.value.unwrap())?;
|
|
||||||
if i < array.len() - 1 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
ResolvedValue::FieldElement(ref value) => write!(f, "{}", value),
|
ResolvedValue::FieldElement(ref value) => write!(f, "{}", value),
|
||||||
ResolvedValue::FieldElementArray(ref array) => {
|
ResolvedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
||||||
|
ResolvedValue::Array(ref array) => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
for (i, e) in array.iter().enumerate() {
|
for (i, e) in array.iter().enumerate() {
|
||||||
write!(f, "{}", e)?;
|
write!(f, "{}", e)?;
|
||||||
@ -76,17 +70,36 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
|||||||
}
|
}
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
ResolvedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
// ResolvedValue::U32Array(ref array) => {
|
||||||
ResolvedValue::BooleanArray(ref array) => {
|
// write!(f, "[")?;
|
||||||
write!(f, "[")?;
|
// for (i, e) in array.iter().enumerate() {
|
||||||
for (i, e) in array.iter().enumerate() {
|
// write!(f, "{}", e.value.unwrap())?;
|
||||||
write!(f, "{}", e.get_value().unwrap())?;
|
// if i < array.len() - 1 {
|
||||||
if i < array.len() - 1 {
|
// write!(f, ", ")?;
|
||||||
write!(f, ", ")?;
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// write!(f, "]")
|
||||||
write!(f, "]")
|
// }
|
||||||
}
|
// ResolvedValue::FieldElementArray(ref array) => {
|
||||||
|
// write!(f, "[")?;
|
||||||
|
// for (i, e) in array.iter().enumerate() {
|
||||||
|
// write!(f, "{}", e)?;
|
||||||
|
// if i < array.len() - 1 {
|
||||||
|
// write!(f, ", ")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// write!(f, "]")
|
||||||
|
// }
|
||||||
|
// ResolvedValue::BooleanArray(ref array) => {
|
||||||
|
// write!(f, "[")?;
|
||||||
|
// for (i, e) in array.iter().enumerate() {
|
||||||
|
// write!(f, "{}", e.get_value().unwrap())?;
|
||||||
|
// if i < array.len() - 1 {
|
||||||
|
// write!(f, ", ")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// write!(f, "]")
|
||||||
|
// }
|
||||||
ResolvedValue::StructExpression(ref variable, ref members) => {
|
ResolvedValue::StructExpression(ref variable, ref members) => {
|
||||||
write!(f, "{} {{", variable)?;
|
write!(f, "{} {{", variable)?;
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
use crate::program::constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue};
|
||||||
use crate::program::{
|
use crate::program::{Assignee, Expression, Integer, RangeOrExpression, Statement, Type, Variable};
|
||||||
Assignee, Expression, IntegerExpression, IntegerRangeOrExpression, Statement, Type, Variable,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
use snarkos_models::gadgets::{r1cs::ConstraintSystem, utilities::uint32::UInt32};
|
use snarkos_models::gadgets::{r1cs::ConstraintSystem, utilities::uint32::UInt32};
|
||||||
@ -50,17 +48,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
|
|
||||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||||
match index_expression {
|
match index_expression {
|
||||||
IntegerRangeOrExpression::Expression(index) => {
|
RangeOrExpression::Expression(index) => {
|
||||||
let index = self.enforce_index(cs, scope.clone(), index);
|
let index = self.enforce_index(cs, scope.clone(), index);
|
||||||
|
|
||||||
// Modify the single value of the array in place
|
// Modify the single value of the array in place
|
||||||
match self.get_mut(&expected_array_name) {
|
match self.get_mut(&expected_array_name) {
|
||||||
Some(value) => match (value, result) {
|
Some(value) => match value {
|
||||||
(ResolvedValue::U32Array(old), ResolvedValue::U32(new)) => {
|
ResolvedValue::Array(old) => {
|
||||||
old[index] = new.to_owned();
|
old[index] = result.to_owned();
|
||||||
}
|
|
||||||
(ResolvedValue::BooleanArray(old), ResolvedValue::Boolean(new)) => {
|
|
||||||
old[index] = new.to_owned();
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unimplemented!("Cannot assign single index to array of values ")
|
unimplemented!("Cannot assign single index to array of values ")
|
||||||
@ -72,29 +67,20 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IntegerRangeOrExpression::Range(from, to) => {
|
RangeOrExpression::Range(from, to) => {
|
||||||
let from_index = match from {
|
let from_index = match from {
|
||||||
Some(expression) => self.enforce_index(cs, scope.clone(), expression),
|
Some(integer) => integer.to_usize(),
|
||||||
None => 0usize,
|
None => 0usize,
|
||||||
};
|
};
|
||||||
let to_index_option = match to {
|
let to_index_option = match to {
|
||||||
Some(expression) => {
|
Some(integer) => Some(integer.to_usize()),
|
||||||
Some(self.enforce_index(cs, scope.clone(), expression))
|
|
||||||
}
|
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Modify the range of values of the array in place
|
// Modify the range of values of the array in place
|
||||||
match self.get_mut(&expected_array_name) {
|
match self.get_mut(&expected_array_name) {
|
||||||
Some(value) => match (value, result) {
|
Some(value) => match (value, result) {
|
||||||
(ResolvedValue::U32Array(old), ResolvedValue::U32Array(new)) => {
|
(ResolvedValue::Array(old), ResolvedValue::Array(new)) => {
|
||||||
let to_index = to_index_option.unwrap_or(old.len());
|
|
||||||
old.splice(from_index..to_index, new.iter().cloned());
|
|
||||||
}
|
|
||||||
(
|
|
||||||
ResolvedValue::BooleanArray(old),
|
|
||||||
ResolvedValue::BooleanArray(new),
|
|
||||||
) => {
|
|
||||||
let to_index = to_index_option.unwrap_or(old.len());
|
let to_index = to_index_option.unwrap_or(old.len());
|
||||||
old.splice(from_index..to_index, new.iter().cloned());
|
old.splice(from_index..to_index, new.iter().cloned());
|
||||||
}
|
}
|
||||||
@ -192,14 +178,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
scope: String,
|
||||||
index: Variable<F>,
|
index: Variable<F>,
|
||||||
start: IntegerExpression<F>,
|
start: Integer,
|
||||||
stop: IntegerExpression<F>,
|
stop: Integer,
|
||||||
statements: Vec<Statement<F>>,
|
statements: Vec<Statement<F>>,
|
||||||
) {
|
) {
|
||||||
let start_index = self.enforce_index(cs, scope.clone(), start);
|
for i in start.to_usize()..stop.to_usize() {
|
||||||
let stop_index = self.enforce_index(cs, scope.clone(), stop);
|
|
||||||
|
|
||||||
for i in start_index..stop_index {
|
|
||||||
// Store index in current function scope.
|
// Store index in current function scope.
|
||||||
// For loop scope is not implemented.
|
// For loop scope is not implemented.
|
||||||
let index_name = new_scope_from_variable(scope.clone(), &index);
|
let index_name = new_scope_from_variable(scope.clone(), &index);
|
||||||
|
@ -26,122 +26,80 @@ pub enum Integer {
|
|||||||
// U64(u64),
|
// U64(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spread operator or u32 expression enum
|
impl Integer {
|
||||||
#[derive(Debug, Clone)]
|
pub fn to_usize(&self) -> usize {
|
||||||
pub enum IntegerSpreadOrExpression<F: Field + PrimeField> {
|
match *self {
|
||||||
Spread(IntegerExpression<F>),
|
// U8(u8)
|
||||||
Expression(IntegerExpression<F>),
|
Integer::U32(num) => num as usize, // U64(u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Range or integer expression enum
|
/// Range or expression enum
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum IntegerRangeOrExpression<F: Field + PrimeField> {
|
pub enum RangeOrExpression<F: Field + PrimeField> {
|
||||||
Range(Option<IntegerExpression<F>>, Option<IntegerExpression<F>>),
|
Range(Option<Integer>, Option<Integer>),
|
||||||
Expression(IntegerExpression<F>),
|
Expression(Expression<F>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expression that evaluates to a u32 value
|
/// Spread or expression
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum IntegerExpression<F: Field + PrimeField> {
|
pub enum SpreadOrExpression<F: Field + PrimeField> {
|
||||||
Variable(Variable<F>),
|
Spread(Expression<F>),
|
||||||
Number(Integer),
|
Expression(Expression<F>),
|
||||||
// Operators
|
|
||||||
Add(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Sub(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Mul(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Div(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Pow(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
// Conditionals
|
|
||||||
IfElse(
|
|
||||||
Box<BooleanExpression<F>>,
|
|
||||||
Box<IntegerExpression<F>>,
|
|
||||||
Box<IntegerExpression<F>>,
|
|
||||||
),
|
|
||||||
// Arrays
|
|
||||||
Array(Vec<Box<IntegerSpreadOrExpression<F>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spread or field expression enum
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum FieldSpreadOrExpression<F: Field + PrimeField> {
|
|
||||||
Spread(FieldExpression<F>),
|
|
||||||
Expression(FieldExpression<F>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expression that evaluates to a field value
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum FieldExpression<F: Field + PrimeField> {
|
|
||||||
Variable(Variable<F>),
|
|
||||||
Number(F),
|
|
||||||
// Operators
|
|
||||||
Add(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
Sub(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
Mul(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
Div(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
Pow(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
// Conditionals
|
|
||||||
IfElse(
|
|
||||||
Box<BooleanExpression<F>>,
|
|
||||||
Box<FieldExpression<F>>,
|
|
||||||
Box<FieldExpression<F>>,
|
|
||||||
),
|
|
||||||
// Arrays
|
|
||||||
Array(Vec<Box<FieldSpreadOrExpression<F>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spread or field expression enum
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum BooleanSpreadOrExpression<F: Field + PrimeField> {
|
|
||||||
Spread(BooleanExpression<F>),
|
|
||||||
Expression(BooleanExpression<F>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expression that evaluates to a boolean value
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum BooleanExpression<F: Field + PrimeField> {
|
|
||||||
Variable(Variable<F>),
|
|
||||||
Value(bool),
|
|
||||||
// Boolean operators
|
|
||||||
Not(Box<BooleanExpression<F>>),
|
|
||||||
Or(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
|
||||||
And(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
|
||||||
BoolEq(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
|
||||||
// Integer operators
|
|
||||||
IntegerEq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Geq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Gt(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Leq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
Lt(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
|
||||||
// Field operators
|
|
||||||
FieldEq(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
|
||||||
// Conditionals
|
|
||||||
IfElse(
|
|
||||||
Box<BooleanExpression<F>>,
|
|
||||||
Box<BooleanExpression<F>>,
|
|
||||||
Box<BooleanExpression<F>>,
|
|
||||||
),
|
|
||||||
// Arrays
|
|
||||||
Array(Vec<Box<BooleanSpreadOrExpression<F>>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expression that evaluates to a value
|
/// Expression that evaluates to a value
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expression<F: Field + PrimeField> {
|
pub enum Expression<F: Field + PrimeField> {
|
||||||
Integer(IntegerExpression<F>),
|
// Variable
|
||||||
FieldElement(FieldExpression<F>),
|
|
||||||
Boolean(BooleanExpression<F>),
|
|
||||||
Variable(Variable<F>),
|
Variable(Variable<F>),
|
||||||
|
|
||||||
|
// Values
|
||||||
|
Integer(Integer),
|
||||||
|
FieldElement(F),
|
||||||
|
Boolean(bool),
|
||||||
|
|
||||||
|
// Number operations
|
||||||
|
Add(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Sub(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Mul(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Div(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Pow(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
|
||||||
|
// Boolean operations
|
||||||
|
Not(Box<Expression<F>>),
|
||||||
|
Or(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
And(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Eq(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Geq(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Gt(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Leq(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
Lt(Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
|
||||||
|
// Conditionals
|
||||||
|
IfElse(Box<Expression<F>>, Box<Expression<F>>, Box<Expression<F>>),
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
Array(Vec<Box<SpreadOrExpression<F>>>),
|
||||||
|
ArrayAccess(Box<Expression<F>>, Box<RangeOrExpression<F>>),
|
||||||
|
|
||||||
|
// Structs
|
||||||
Struct(Variable<F>, Vec<StructMember<F>>),
|
Struct(Variable<F>, Vec<StructMember<F>>),
|
||||||
ArrayAccess(Box<Expression<F>>, IntegerRangeOrExpression<F>),
|
|
||||||
StructMemberAccess(Box<Expression<F>>, Variable<F>), // (struct name, struct member name)
|
StructMemberAccess(Box<Expression<F>>, Variable<F>), // (struct name, struct member name)
|
||||||
|
|
||||||
|
// Functions
|
||||||
FunctionCall(Box<Expression<F>>, Vec<Expression<F>>),
|
FunctionCall(Box<Expression<F>>, Vec<Expression<F>>),
|
||||||
|
// IntegerExp(IntegerExpression<F>),
|
||||||
|
// FieldElementExp(FieldExpression<F>),
|
||||||
|
// BooleanExp(BooleanExpression<F>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Definition assignee: v, arr[0..2], Point p.x
|
/// Definition assignee: v, arr[0..2], Point p.x
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Assignee<F: Field + PrimeField> {
|
pub enum Assignee<F: Field + PrimeField> {
|
||||||
Variable(Variable<F>),
|
Variable(Variable<F>),
|
||||||
Array(Box<Assignee<F>>, IntegerRangeOrExpression<F>),
|
Array(Box<Assignee<F>>, RangeOrExpression<F>),
|
||||||
StructMember(Box<Assignee<F>>, Variable<F>),
|
StructMember(Box<Assignee<F>>, Variable<F>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,12 +108,7 @@ pub enum Assignee<F: Field + PrimeField> {
|
|||||||
pub enum Statement<F: Field + PrimeField> {
|
pub enum Statement<F: Field + PrimeField> {
|
||||||
// Declaration(Variable),
|
// Declaration(Variable),
|
||||||
Definition(Assignee<F>, Expression<F>),
|
Definition(Assignee<F>, Expression<F>),
|
||||||
For(
|
For(Variable<F>, Integer, Integer, Vec<Statement<F>>),
|
||||||
Variable<F>,
|
|
||||||
IntegerExpression<F>,
|
|
||||||
IntegerExpression<F>,
|
|
||||||
Vec<Statement<F>>,
|
|
||||||
),
|
|
||||||
Return(Vec<Expression<F>>),
|
Return(Vec<Expression<F>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,3 +185,95 @@ impl<'ast, F: Field + PrimeField> Program<'ast, F> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// Spread operator or u32 expression enum
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum IntegerSpreadOrExpression<F: Field + PrimeField> {
|
||||||
|
// Spread(IntegerExpression<F>),
|
||||||
|
// Expression(IntegerExpression<F>),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Expression that evaluates to a u32 value
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum IntegerExpression<F: Field + PrimeField> {
|
||||||
|
// Variable(Variable<F>),
|
||||||
|
// Number(Integer),
|
||||||
|
// Operators
|
||||||
|
// Add(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Sub(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Mul(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Div(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Pow(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Conditionals
|
||||||
|
// IfElse(
|
||||||
|
// Box<BooleanExpression<F>>,
|
||||||
|
// Box<IntegerExpression<F>>,
|
||||||
|
// Box<IntegerExpression<F>>,
|
||||||
|
// ),
|
||||||
|
// Arrays
|
||||||
|
// Array(Vec<Box<IntegerSpreadOrExpression<F>>>),
|
||||||
|
// // Unresolved
|
||||||
|
// Unresolved(Box<Expression<F>>) // placeholder for array/struct access, function calls
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Spread or field expression enum
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum FieldSpreadOrExpression<F: Field + PrimeField> {
|
||||||
|
// Spread(FieldExpression<F>),
|
||||||
|
// Expression(FieldExpression<F>),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Expression that evaluates to a field value
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum FieldExpression<F: Field + PrimeField> {
|
||||||
|
// Variable(Variable<F>),
|
||||||
|
// Number(F),
|
||||||
|
// Operators
|
||||||
|
// Add(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Sub(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Mul(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Div(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Pow(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Conditionals
|
||||||
|
// IfElse(
|
||||||
|
// Box<BooleanExpression<F>>,
|
||||||
|
// Box<FieldExpression<F>>,
|
||||||
|
// Box<FieldExpression<F>>,
|
||||||
|
// ),
|
||||||
|
// Arrays
|
||||||
|
// Array(Vec<Box<FieldSpreadOrExpression<F>>>),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Spread or field expression enum
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum BooleanSpreadOrExpression<F: Field + PrimeField> {
|
||||||
|
// Spread(BooleanExpression<F>),
|
||||||
|
// Expression(BooleanExpression<F>),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Expression that evaluates to a boolean value
|
||||||
|
// #[derive(Debug, Clone)]
|
||||||
|
// pub enum BooleanExpression<F: Field + PrimeField> {
|
||||||
|
// Variable(Variable<F>),
|
||||||
|
// Value(bool),
|
||||||
|
// Boolean operators
|
||||||
|
// Or(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
||||||
|
// And(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
||||||
|
// BoolEq(Box<BooleanExpression<F>>, Box<BooleanExpression<F>>),
|
||||||
|
// // Integer operators
|
||||||
|
// IntegerEq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Geq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Gt(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Leq(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// Lt(Box<IntegerExpression<F>>, Box<IntegerExpression<F>>),
|
||||||
|
// // Field operators
|
||||||
|
// FieldEq(Box<FieldExpression<F>>, Box<FieldExpression<F>>),
|
||||||
|
// Conditionals
|
||||||
|
// IfElse(
|
||||||
|
// Box<BooleanExpression<F>>,
|
||||||
|
// Box<BooleanExpression<F>>,
|
||||||
|
// Box<BooleanExpression<F>>,
|
||||||
|
// ),
|
||||||
|
// Arrays
|
||||||
|
// Array(Vec<Box<BooleanSpreadOrExpression<F>>>),
|
||||||
|
// }
|
||||||
|
@ -5,10 +5,8 @@
|
|||||||
//! @date 2020
|
//! @date 2020
|
||||||
|
|
||||||
use crate::program::{
|
use crate::program::{
|
||||||
Assignee, BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression,
|
Assignee, Expression, Function, FunctionName, Integer, Parameter, RangeOrExpression,
|
||||||
FieldSpreadOrExpression, Function, FunctionName, Integer, IntegerExpression,
|
SpreadOrExpression, Statement, Struct, StructField, Type, Variable,
|
||||||
IntegerRangeOrExpression, IntegerSpreadOrExpression, Parameter, Statement, Struct, StructField,
|
|
||||||
Type, Variable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
@ -33,132 +31,29 @@ impl fmt::Display for Integer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for IntegerSpreadOrExpression<F> {
|
impl<'ast, F: Field + PrimeField> fmt::Display for RangeOrExpression<F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
IntegerSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
RangeOrExpression::Range(ref from, ref to) => write!(
|
||||||
IntegerSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for IntegerRangeOrExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
IntegerRangeOrExpression::Range(ref from, ref to) => write!(
|
|
||||||
f,
|
f,
|
||||||
"{}..{}",
|
"{}..{}",
|
||||||
from.as_ref()
|
from.as_ref()
|
||||||
.map(|e| e.to_string())
|
.map(|e| format!("{}", e))
|
||||||
.unwrap_or("".to_string()),
|
.unwrap_or("".to_string()),
|
||||||
to.as_ref().map(|e| e.to_string()).unwrap_or("".to_string())
|
to.as_ref()
|
||||||
|
.map(|e| format!("{}", e))
|
||||||
|
.unwrap_or("".to_string())
|
||||||
),
|
),
|
||||||
IntegerRangeOrExpression::Expression(ref e) => write!(f, "{}", e),
|
RangeOrExpression::Expression(ref e) => write!(f, "{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for IntegerExpression<F> {
|
impl<F: Field + PrimeField> fmt::Display for SpreadOrExpression<F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
IntegerExpression::Variable(ref variable) => write!(f, "{}", variable),
|
SpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
||||||
IntegerExpression::Number(ref number) => write!(f, "{}", number),
|
SpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
||||||
IntegerExpression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
|
|
||||||
IntegerExpression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
|
|
||||||
IntegerExpression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
|
|
||||||
IntegerExpression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
|
|
||||||
IntegerExpression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
|
|
||||||
IntegerExpression::IfElse(ref a, ref b, ref c) => {
|
|
||||||
write!(f, "if {} then {} else {} fi", a, b, c)
|
|
||||||
}
|
|
||||||
IntegerExpression::Array(ref array) => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
for (i, e) in array.iter().enumerate() {
|
|
||||||
write!(f, "{}", e)?;
|
|
||||||
if i < array.len() - 1 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for FieldSpreadOrExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
FieldSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
|
||||||
FieldSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for FieldExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
FieldExpression::Variable(ref variable) => write!(f, "{}", variable),
|
|
||||||
FieldExpression::Number(ref number) => write!(f, "{}", number),
|
|
||||||
FieldExpression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
|
|
||||||
FieldExpression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
|
|
||||||
FieldExpression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
|
|
||||||
FieldExpression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
|
|
||||||
FieldExpression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
|
|
||||||
FieldExpression::IfElse(ref a, ref b, ref c) => {
|
|
||||||
write!(f, "if {} then {} else {} fi", a, b, c)
|
|
||||||
}
|
|
||||||
FieldExpression::Array(ref array) => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
for (i, e) in array.iter().enumerate() {
|
|
||||||
write!(f, "{}", e)?;
|
|
||||||
if i < array.len() - 1 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
} // _ => unimplemented!("not all field expressions can be displayed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for BooleanSpreadOrExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
BooleanSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
|
||||||
BooleanSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for BooleanExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
BooleanExpression::Variable(ref variable) => write!(f, "{}", variable),
|
|
||||||
BooleanExpression::Value(ref value) => write!(f, "{}", value),
|
|
||||||
BooleanExpression::Not(ref expression) => write!(f, "!{}", expression),
|
|
||||||
BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
|
||||||
BooleanExpression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
|
|
||||||
BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
|
||||||
BooleanExpression::IntegerEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
|
||||||
BooleanExpression::FieldEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
|
||||||
// BooleanExpression::Neq(ref lhs, ref rhs) => write!(f, "{} != {}", lhs, rhs),
|
|
||||||
BooleanExpression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
|
||||||
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
|
||||||
BooleanExpression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
|
||||||
BooleanExpression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
|
||||||
BooleanExpression::IfElse(ref a, ref b, ref c) => {
|
|
||||||
write!(f, "if {} then {} else {} fi", a, b, c)
|
|
||||||
}
|
|
||||||
BooleanExpression::Array(ref array) => {
|
|
||||||
write!(f, "[")?;
|
|
||||||
for (i, e) in array.iter().enumerate() {
|
|
||||||
write!(f, "{}", e)?;
|
|
||||||
if i < array.len() - 1 {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,10 +61,48 @@ impl<'ast, F: Field + PrimeField> fmt::Display for BooleanExpression<F> {
|
|||||||
impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Expression::Integer(ref integer_expression) => write!(f, "{}", integer_expression),
|
// Variables
|
||||||
Expression::FieldElement(ref field_expression) => write!(f, "{}", field_expression),
|
|
||||||
Expression::Boolean(ref boolean_expression) => write!(f, "{}", boolean_expression),
|
|
||||||
Expression::Variable(ref variable) => write!(f, "{}", variable),
|
Expression::Variable(ref variable) => write!(f, "{}", variable),
|
||||||
|
|
||||||
|
// Values
|
||||||
|
Expression::Integer(ref integer) => write!(f, "{}", integer),
|
||||||
|
Expression::FieldElement(ref fe) => write!(f, "{}", fe),
|
||||||
|
Expression::Boolean(ref bool) => write!(f, "{}", bool),
|
||||||
|
|
||||||
|
// Number operations
|
||||||
|
Expression::Add(ref left, ref right) => write!(f, "{} + {}", left, right),
|
||||||
|
Expression::Sub(ref left, ref right) => write!(f, "{} - {}", left, right),
|
||||||
|
Expression::Mul(ref left, ref right) => write!(f, "{} * {}", left, right),
|
||||||
|
Expression::Div(ref left, ref right) => write!(f, "{} / {}", left, right),
|
||||||
|
Expression::Pow(ref left, ref right) => write!(f, "{} ** {}", left, right),
|
||||||
|
|
||||||
|
// Boolean operations
|
||||||
|
Expression::Not(ref expression) => write!(f, "!{}", expression),
|
||||||
|
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
||||||
|
Expression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
|
||||||
|
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||||
|
Expression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
||||||
|
Expression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
||||||
|
Expression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||||
|
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||||
|
|
||||||
|
// Conditionals
|
||||||
|
Expression::IfElse(ref first, ref second, ref third) => {
|
||||||
|
write!(f, "if {} then {} else {} fi", first, second, third)
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression::Array(ref array) => {
|
||||||
|
write!(f, "[")?;
|
||||||
|
for (i, e) in array.iter().enumerate() {
|
||||||
|
write!(f, "{}", e)?;
|
||||||
|
if i < array.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
Expression::ArrayAccess(ref array, ref index) => write!(f, "{}[{}]", array, index),
|
||||||
|
|
||||||
Expression::Struct(ref var, ref members) => {
|
Expression::Struct(ref var, ref members) => {
|
||||||
write!(f, "{} {{", var)?;
|
write!(f, "{} {{", var)?;
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
@ -180,7 +113,6 @@ impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
|||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
Expression::ArrayAccess(ref array, ref index) => write!(f, "{}[{}]", array, index),
|
|
||||||
Expression::StructMemberAccess(ref struct_variable, ref member) => {
|
Expression::StructMemberAccess(ref struct_variable, ref member) => {
|
||||||
write!(f, "{}.{}", struct_variable, member)
|
write!(f, "{}.{}", struct_variable, member)
|
||||||
}
|
}
|
||||||
@ -350,3 +282,117 @@ impl<F: Field + PrimeField> fmt::Debug for Function<F> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// impl<F: Field + PrimeField> fmt::Display for IntegerSpreadOrExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// IntegerSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
||||||
|
// IntegerSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<'ast, F: Field + PrimeField> fmt::Display for IntegerExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// IntegerExpression::Variable(ref variable) => write!(f, "{}", variable),
|
||||||
|
// IntegerExpression::Number(ref number) => write!(f, "{}", number),
|
||||||
|
// IntegerExpression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
|
||||||
|
// IntegerExpression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
|
||||||
|
// IntegerExpression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
|
||||||
|
// IntegerExpression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
|
||||||
|
// IntegerExpression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
|
||||||
|
// IntegerExpression::IfElse(ref a, ref b, ref c) => {
|
||||||
|
// write!(f, "if {} then {} else {} fi", a, b, c)
|
||||||
|
// }
|
||||||
|
// IntegerExpression::Array(ref array) => {
|
||||||
|
// write!(f, "[")?;
|
||||||
|
// for (i, e) in array.iter().enumerate() {
|
||||||
|
// write!(f, "{}", e)?;
|
||||||
|
// if i < array.len() - 1 {
|
||||||
|
// write!(f, ", ")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// write!(f, "]")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<F: Field + PrimeField> fmt::Display for FieldSpreadOrExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// FieldSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
||||||
|
// FieldSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl<'ast, F: Field + PrimeField> fmt::Display for FieldExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// FieldExpression::Variable(ref variable) => write!(f, "{}", variable),
|
||||||
|
// FieldExpression::Number(ref number) => write!(f, "{}", number),
|
||||||
|
// FieldExpression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
|
||||||
|
// FieldExpression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
|
||||||
|
// FieldExpression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
|
||||||
|
// FieldExpression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
|
||||||
|
// FieldExpression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
|
||||||
|
// FieldExpression::IfElse(ref a, ref b, ref c) => {
|
||||||
|
// write!(f, "if {} then {} else {} fi", a, b, c)
|
||||||
|
// }
|
||||||
|
// FieldExpression::Array(ref array) => {
|
||||||
|
// write!(f, "[")?;
|
||||||
|
// for (i, e) in array.iter().enumerate() {
|
||||||
|
// write!(f, "{}", e)?;
|
||||||
|
// if i < array.len() - 1 {
|
||||||
|
// write!(f, ", ")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// write!(f, "]")
|
||||||
|
// } // _ => unimplemented!("not all field expressions can be displayed")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<F: Field + PrimeField> fmt::Display for BooleanSpreadOrExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// BooleanSpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
||||||
|
// BooleanSpreadOrExpression::Expression(ref expression) => write!(f, "{}", expression),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<'ast, F: Field + PrimeField> fmt::Display for BooleanExpression<F> {
|
||||||
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// match *self {
|
||||||
|
// BooleanExpression::Variable(ref variable) => write!(f, "{}", variable),
|
||||||
|
// BooleanExpression::Value(ref value) => write!(f, "{}", value),
|
||||||
|
// BooleanExpression::Not(ref expression) => write!(f, "!{}", expression),
|
||||||
|
// BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
||||||
|
// BooleanExpression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
|
||||||
|
// BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||||
|
// BooleanExpression::IntegerEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||||
|
// BooleanExpression::FieldEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||||
|
// // BooleanExpression::Neq(ref lhs, ref rhs) => write!(f, "{} != {}", lhs, rhs),
|
||||||
|
// BooleanExpression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
||||||
|
// BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
||||||
|
// BooleanExpression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||||
|
// BooleanExpression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||||
|
// BooleanExpression::IfElse(ref a, ref b, ref c) => {
|
||||||
|
// write!(f, "if {} then {} else {} fi", a, b, c)
|
||||||
|
// }
|
||||||
|
// BooleanExpression::Array(ref array) => {
|
||||||
|
// write!(f, "[")?;
|
||||||
|
// for (i, e) in array.iter().enumerate() {
|
||||||
|
// write!(f, "{}", e)?;
|
||||||
|
// if i < array.len() - 1 {
|
||||||
|
// write!(f, ", ")?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// write!(f, "]")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user