mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-26 19:11:50 +03:00
support tuple access and comparison
This commit is contained in:
parent
e85d6499d0
commit
0e8473658e
@ -113,6 +113,12 @@ impl StatementError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn multiple_definition(value: String, span: Span) -> Self {
|
||||
let message = format!("cannot assign multiple variables to a single value: {}", value,);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn select_fail(first: String, second: String, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Conditional select gadget failed to select between `{}` or `{}`",
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Enforces a definition statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
|
||||
use leo_typed::{Declare, Expression, Span, VariableName, Variables};
|
||||
use leo_typed::{Declare, Expression, Span, Type, VariableName, Variables};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -29,6 +29,82 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enforce_expressions<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
types: Vec<Type>,
|
||||
expressions: Vec<Expression>,
|
||||
) -> Result<Vec<ConstrainedValue<F, G>>, StatementError> {
|
||||
let implicit_types = types.is_empty();
|
||||
let mut expected_types = vec![];
|
||||
|
||||
for i in 0..expressions.len() {
|
||||
let expected_type = if implicit_types { vec![] } else { vec![types[i].clone()] };
|
||||
|
||||
expected_types.push(expected_type);
|
||||
}
|
||||
|
||||
let mut values = vec![];
|
||||
|
||||
for (expression, expected_type) in expressions.into_iter().zip(expected_types.into_iter()) {
|
||||
let value = self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_type,
|
||||
expression,
|
||||
)?;
|
||||
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
fn enforce_tuple_definition<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
is_constant: bool,
|
||||
variables: Variables,
|
||||
expressions: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let values = self.enforce_expressions(cs, file_scope, function_scope.clone(), variables.types, expressions)?;
|
||||
|
||||
let tuple = ConstrainedValue::Tuple(values);
|
||||
let variable = variables.names[0].clone();
|
||||
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, tuple, span)
|
||||
}
|
||||
|
||||
fn enforce_multiple_definition<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
function_scope: String,
|
||||
is_constant: bool,
|
||||
variables: Variables,
|
||||
values: Vec<ConstrainedValue<F, G>>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
if values.len() != variables.names.len() {
|
||||
return Err(StatementError::invalid_number_of_definitions(
|
||||
values.len(),
|
||||
variables.names.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
for (variable, value) in variables.names.into_iter().zip(values.into_iter()) {
|
||||
self.enforce_single_definition(cs, function_scope.clone(), is_constant, variable, value, span.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -39,60 +115,67 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
expressions: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let num_variables = variables.names.len();
|
||||
let num_values = expressions.len();
|
||||
let is_constant = match declare {
|
||||
Declare::Let => false,
|
||||
Declare::Const => true,
|
||||
};
|
||||
|
||||
if variables.names.len() == 1 && expressions.len() == 1 {
|
||||
if num_variables == 1 && num_values == 1 {
|
||||
// Define a single variable with a single value
|
||||
|
||||
let variable = variables.names[0].clone();
|
||||
let expression = self.enforce_expression(
|
||||
let expression = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&variables.types,
|
||||
expressions[0].clone(),
|
||||
)?;
|
||||
)? {
|
||||
ConstrainedValue::Return(values) => ConstrainedValue::Tuple(values),
|
||||
value => value,
|
||||
};
|
||||
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, span)
|
||||
} else if variables.names.len() == 1 && expressions.len() > 1 {
|
||||
} else if num_variables == 1 && num_values > 1 {
|
||||
// Define a tuple (single variable with multiple values)
|
||||
|
||||
let implicit_types = variables.types.is_empty();
|
||||
let mut expected_types = vec![];
|
||||
self.enforce_tuple_definition(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
is_constant,
|
||||
variables,
|
||||
expressions,
|
||||
span,
|
||||
)
|
||||
} else if num_variables > 1 && num_values == 1 {
|
||||
// Define multiple variables for an expression that returns multiple results (multiple definition)
|
||||
|
||||
for i in 0..expressions.len() {
|
||||
let expected_type = if implicit_types {
|
||||
vec![]
|
||||
} else {
|
||||
vec![variables.types[i].clone()]
|
||||
};
|
||||
let values = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&variables.types,
|
||||
expressions[0].clone(),
|
||||
)? {
|
||||
ConstrainedValue::Return(values) => values,
|
||||
value => return Err(StatementError::multiple_definition(value.to_string(), span.clone())),
|
||||
};
|
||||
|
||||
expected_types.push(expected_type);
|
||||
}
|
||||
|
||||
let mut values = vec![];
|
||||
|
||||
for (expression, expected_type) in expressions.into_iter().zip(expected_types.into_iter()) {
|
||||
let value = self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_type,
|
||||
expression,
|
||||
)?;
|
||||
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
let tuple = ConstrainedValue::Tuple(values);
|
||||
let variable = variables.names[0].clone();
|
||||
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, tuple, span)
|
||||
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
|
||||
} else {
|
||||
Ok(())
|
||||
// Define multiple variables for multiple expressions
|
||||
let values = self.enforce_expressions(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope.clone(),
|
||||
variables.types.clone(),
|
||||
expressions,
|
||||
)?;
|
||||
|
||||
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
||||
write!(f, "]")
|
||||
}
|
||||
ConstrainedValue::Tuple(ref tuple) => {
|
||||
let values = tuple.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(",");
|
||||
let values = tuple.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(", ");
|
||||
|
||||
write!(f, "({})", values)
|
||||
}
|
||||
@ -366,6 +366,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConditionalEqGadget<F> for Constrai
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Tuple(tuple_2)) => {
|
||||
for (i, (left, right)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
|
||||
left.conditional_enforce_equal(cs.ns(|| format!("tuple index {}", i)), right, condition)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(_, _) => return Err(SynthesisError::Unsatisfiable),
|
||||
}
|
||||
}
|
||||
@ -412,6 +418,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
||||
|
||||
ConstrainedValue::Array(array)
|
||||
}
|
||||
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Array(tuple_2)) => {
|
||||
let mut array = vec![];
|
||||
|
||||
for (i, (first, second)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
|
||||
array.push(Self::conditionally_select(
|
||||
cs.ns(|| format!("tuple index {}", i)),
|
||||
cond,
|
||||
first,
|
||||
second,
|
||||
)?);
|
||||
}
|
||||
|
||||
ConstrainedValue::Tuple(array)
|
||||
}
|
||||
(ConstrainedValue::Function(identifier_1, function_1), ConstrainedValue::Function(_, _)) => {
|
||||
// This is a no-op. functions cannot hold circuit values
|
||||
// However, we must return a result here
|
||||
|
Loading…
Reference in New Issue
Block a user