mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-29 22:36:05 +03:00
add array expression module
This commit is contained in:
parent
c989061ab1
commit
5d1b242eb4
89
compiler/src/expression/array/array.rs
Normal file
89
compiler/src/expression/array/array.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! Enforces constraints on array expressions in a compiled Leo program.
|
||||
|
||||
use crate::{
|
||||
errors::ExpressionError,
|
||||
program::{new_scope, ConstrainedProgram},
|
||||
value::ConstrainedValue,
|
||||
GroupType,
|
||||
};
|
||||
use leo_types::{Expression, Span, SpreadOrExpression, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Enforce array expressions
|
||||
pub fn enforce_array_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expected_types: &Vec<Type>,
|
||||
array: Vec<Box<SpreadOrExpression>>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Check explicit array type dimension if given
|
||||
let mut expected_types = expected_types.clone();
|
||||
let expected_dimensions = vec![];
|
||||
|
||||
if !expected_types.is_empty() {
|
||||
match expected_types[0] {
|
||||
Type::Array(ref _type, ref dimensions) => {
|
||||
expected_types = vec![expected_types[0].inner_dimension(dimensions)];
|
||||
}
|
||||
ref _type => {
|
||||
return Err(ExpressionError::unexpected_array(
|
||||
expected_types[0].to_string(),
|
||||
_type.to_string(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
for element in array.into_iter() {
|
||||
match *element {
|
||||
SpreadOrExpression::Spread(spread) => match spread {
|
||||
Expression::Identifier(identifier) => {
|
||||
let array_name = new_scope(function_scope.clone(), identifier.to_string());
|
||||
match self.get(&array_name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Array(array) => result.extend(array.clone()),
|
||||
value => {
|
||||
return Err(ExpressionError::invalid_spread(value.to_string(), span));
|
||||
}
|
||||
},
|
||||
None => return Err(ExpressionError::undefined_array(identifier.name, span)),
|
||||
}
|
||||
}
|
||||
value => return Err(ExpressionError::invalid_spread(value.to_string(), span)),
|
||||
},
|
||||
SpreadOrExpression::Expression(expression) => {
|
||||
result.push(self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_types,
|
||||
expression,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check expected_dimensions if given
|
||||
if !expected_dimensions.is_empty() {
|
||||
if expected_dimensions[expected_dimensions.len() - 1] != result.len() {
|
||||
return Err(ExpressionError::invalid_length(
|
||||
expected_dimensions[expected_dimensions.len() - 1],
|
||||
result.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Array(result))
|
||||
}
|
||||
}
|
56
compiler/src/expression/array/array_access.rs
Normal file
56
compiler/src/expression/array/array_access.rs
Normal file
@ -0,0 +1,56 @@
|
||||
//! Enforces constraints on array access expressions in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_types::{Expression, RangeOrExpression, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_array_access_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expected_types: &Vec<Type>,
|
||||
array: Box<Expression>,
|
||||
index: RangeOrExpression,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let array = match self.enforce_expression_value(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_types,
|
||||
*array,
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span)),
|
||||
};
|
||||
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
Some(from_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), from_index, span.clone())?
|
||||
}
|
||||
None => 0usize, // Array slice starts at index 0
|
||||
};
|
||||
let to_resolved = match to {
|
||||
Some(to_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), to_index, span.clone())?
|
||||
}
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
|
||||
}
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index_resolved = self.enforce_index(cs, file_scope, function_scope, index, span)?;
|
||||
Ok(array[index_resolved].to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
compiler/src/expression/array/index.rs
Normal file
33
compiler/src/expression/array/index.rs
Normal file
@ -0,0 +1,33 @@
|
||||
//! Enforces constraints on an array index expression in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_types::{Expression, IntegerType, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn enforce_index<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
index: Expression,
|
||||
span: Span,
|
||||
) -> Result<usize, ExpressionError> {
|
||||
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
|
||||
match self.enforce_expression_value(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_types,
|
||||
index,
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span.clone())?),
|
||||
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||
}
|
||||
}
|
||||
}
|
8
compiler/src/expression/array/mod.rs
Normal file
8
compiler/src/expression/array/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
pub mod array;
|
||||
pub use self::array::*;
|
||||
|
||||
pub mod array_access;
|
||||
pub use self::array_access::*;
|
||||
|
||||
pub mod index;
|
||||
pub use self::index::*;
|
@ -12,17 +12,7 @@ use crate::{
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::{
|
||||
CircuitFieldDefinition,
|
||||
CircuitMember,
|
||||
Expression,
|
||||
Identifier,
|
||||
IntegerType,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
SpreadOrExpression,
|
||||
Type,
|
||||
};
|
||||
use leo_types::{CircuitFieldDefinition, CircuitMember, Expression, Identifier, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -67,146 +57,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Ok(result_value)
|
||||
}
|
||||
|
||||
/// Enforce array expressions
|
||||
fn enforce_array_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expected_types: &Vec<Type>,
|
||||
array: Vec<Box<SpreadOrExpression>>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Check explicit array type dimension if given
|
||||
let mut expected_types = expected_types.clone();
|
||||
let expected_dimensions = vec![];
|
||||
|
||||
if !expected_types.is_empty() {
|
||||
match expected_types[0] {
|
||||
Type::Array(ref _type, ref dimensions) => {
|
||||
expected_types = vec![expected_types[0].inner_dimension(dimensions)];
|
||||
}
|
||||
ref _type => {
|
||||
return Err(ExpressionError::unexpected_array(
|
||||
expected_types[0].to_string(),
|
||||
_type.to_string(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
for element in array.into_iter() {
|
||||
match *element {
|
||||
SpreadOrExpression::Spread(spread) => match spread {
|
||||
Expression::Identifier(identifier) => {
|
||||
let array_name = new_scope(function_scope.clone(), identifier.to_string());
|
||||
match self.get(&array_name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Array(array) => result.extend(array.clone()),
|
||||
value => {
|
||||
return Err(ExpressionError::invalid_spread(value.to_string(), span));
|
||||
}
|
||||
},
|
||||
None => return Err(ExpressionError::undefined_array(identifier.name, span)),
|
||||
}
|
||||
}
|
||||
value => return Err(ExpressionError::invalid_spread(value.to_string(), span)),
|
||||
},
|
||||
SpreadOrExpression::Expression(expression) => {
|
||||
result.push(self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_types,
|
||||
expression,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check expected_dimensions if given
|
||||
if !expected_dimensions.is_empty() {
|
||||
if expected_dimensions[expected_dimensions.len() - 1] != result.len() {
|
||||
return Err(ExpressionError::invalid_length(
|
||||
expected_dimensions[expected_dimensions.len() - 1],
|
||||
result.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Array(result))
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_index<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
index: Expression,
|
||||
span: Span,
|
||||
) -> Result<usize, ExpressionError> {
|
||||
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
|
||||
match self.enforce_expression_value(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
&expected_types,
|
||||
index,
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span.clone())?),
|
||||
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_array_access_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expected_types: &Vec<Type>,
|
||||
array: Box<Expression>,
|
||||
index: RangeOrExpression,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let array = match self.enforce_expression_value(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_types,
|
||||
*array,
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span)),
|
||||
};
|
||||
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
Some(from_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), from_index, span.clone())?
|
||||
}
|
||||
None => 0usize, // Array slice starts at index 0
|
||||
};
|
||||
let to_resolved = match to {
|
||||
Some(to_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), to_index, span.clone())?
|
||||
}
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
|
||||
}
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index_resolved = self.enforce_index(cs, file_scope, function_scope, index, span)?;
|
||||
Ok(array[index_resolved].to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_circuit_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
|
@ -3,6 +3,9 @@
|
||||
pub mod arithmetic;
|
||||
pub use self::arithmetic::*;
|
||||
|
||||
pub mod array;
|
||||
pub use self::array::*;
|
||||
|
||||
pub mod conditional;
|
||||
pub use self::conditional::*;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user