mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 05:45:30 +03:00
constraints array access
This commit is contained in:
parent
c14ed231ea
commit
025d9ab45d
@ -1,14 +1,5 @@
|
|||||||
struct Point {
|
bool[2] a = [true, false]
|
||||||
field x
|
|
||||||
field y
|
|
||||||
}
|
|
||||||
|
|
||||||
Point p = Point {x: 1, y: 0}
|
p = a[0..2]
|
||||||
|
|
||||||
//bool[2] a = [true, false]
|
|
||||||
//bool[2] b = [true; 2]
|
|
||||||
|
|
||||||
//field[4] c = [1, 2, 3, 4]
|
|
||||||
//field[3] d = [1; 3]
|
|
||||||
|
|
||||||
return p
|
return p
|
@ -1,6 +1,7 @@
|
|||||||
use crate::aleo_program::{
|
use crate::aleo_program::{
|
||||||
BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression,
|
BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression,
|
||||||
FieldSpreadOrExpression, Function, Program, Statement, Struct, StructMember, Type, Variable,
|
FieldRangeOrExpression, FieldSpreadOrExpression, Function, Program, Statement, Struct,
|
||||||
|
StructMember, Type, Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
@ -463,6 +464,70 @@ impl ResolvedProgram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enforce_index<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
index: FieldExpression,
|
||||||
|
) -> usize {
|
||||||
|
match self.enforce_field_expression(cs, index) {
|
||||||
|
ResolvedValue::FieldElement(number) => number.value.unwrap() as usize,
|
||||||
|
value => unimplemented!("From index must resolve to a uint32, got {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_array_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||||
|
&mut self,
|
||||||
|
cs: &mut CS,
|
||||||
|
array: Box<Expression>,
|
||||||
|
index: FieldRangeOrExpression,
|
||||||
|
) -> ResolvedValue {
|
||||||
|
match self.enforce_expression(cs, *array) {
|
||||||
|
ResolvedValue::FieldElementArray(field_array) => {
|
||||||
|
match index {
|
||||||
|
FieldRangeOrExpression::Range(from, to) => {
|
||||||
|
let from_resolved = match from {
|
||||||
|
Some(from_index) => self.enforce_index(cs, from_index),
|
||||||
|
None => 0usize, // Array slice starts at index 0
|
||||||
|
};
|
||||||
|
let to_resolved = match to {
|
||||||
|
Some(to_index) => self.enforce_index(cs, to_index),
|
||||||
|
None => field_array.len(), // Array slice ends at array length
|
||||||
|
};
|
||||||
|
ResolvedValue::FieldElementArray(
|
||||||
|
field_array[from_resolved..to_resolved].to_owned(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FieldRangeOrExpression::FieldExpression(index) => {
|
||||||
|
let index_resolved = self.enforce_index(cs, index);
|
||||||
|
ResolvedValue::FieldElement(field_array[index_resolved].to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResolvedValue::BooleanArray(bool_array) => {
|
||||||
|
match index {
|
||||||
|
FieldRangeOrExpression::Range(from, to) => {
|
||||||
|
let from_resolved = match from {
|
||||||
|
Some(from_index) => self.enforce_index(cs, from_index),
|
||||||
|
None => 0usize, // Array slice starts at index 0
|
||||||
|
};
|
||||||
|
let to_resolved = match to {
|
||||||
|
Some(to_index) => self.enforce_index(cs, to_index),
|
||||||
|
None => bool_array.len(), // Array slice ends at array length
|
||||||
|
};
|
||||||
|
ResolvedValue::BooleanArray(
|
||||||
|
bool_array[from_resolved..to_resolved].to_owned(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FieldRangeOrExpression::FieldExpression(index) => {
|
||||||
|
let index_resolved = self.enforce_index(cs, index);
|
||||||
|
ResolvedValue::Boolean(bool_array[index_resolved].to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value => unimplemented!("Cannot access element of untyped array"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn enforce_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
fn enforce_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
@ -499,6 +564,9 @@ impl ResolvedProgram {
|
|||||||
Expression::Struct(struct_name, members) => {
|
Expression::Struct(struct_name, members) => {
|
||||||
self.enforce_struct_expression(cs, struct_name, members)
|
self.enforce_struct_expression(cs, struct_name, members)
|
||||||
}
|
}
|
||||||
|
Expression::ArrayAccess(array, index) => {
|
||||||
|
self.enforce_array_access_expression(cs, array, index)
|
||||||
|
} // _ => unimplemented!("expression not enforced yet")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,6 +664,7 @@ impl ResolvedProgram {
|
|||||||
Expression::Struct(_v, _m) => {
|
Expression::Struct(_v, _m) => {
|
||||||
unimplemented!("return struct not impl");
|
unimplemented!("return struct not impl");
|
||||||
}
|
}
|
||||||
|
_ => unimplemented!("expression can't be returned yet"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,13 @@ pub enum FieldSpreadOrExpression {
|
|||||||
FieldExpression(FieldExpression),
|
FieldExpression(FieldExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Range or field expression enum
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum FieldRangeOrExpression {
|
||||||
|
Range(Option<FieldExpression>, Option<FieldExpression>),
|
||||||
|
FieldExpression(FieldExpression),
|
||||||
|
}
|
||||||
|
|
||||||
/// Expression that evaluates to a field value
|
/// Expression that evaluates to a field value
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum FieldExpression {
|
pub enum FieldExpression {
|
||||||
@ -85,7 +92,9 @@ pub enum Expression {
|
|||||||
Boolean(BooleanExpression),
|
Boolean(BooleanExpression),
|
||||||
FieldElement(FieldExpression),
|
FieldElement(FieldExpression),
|
||||||
Variable(Variable),
|
Variable(Variable),
|
||||||
|
ArrayAccess(Box<Expression>, FieldRangeOrExpression),
|
||||||
Struct(Variable, Vec<StructMember>),
|
Struct(Variable, Vec<StructMember>),
|
||||||
|
// StructMemberAccess(Variable, Variable)// (struct name, struct member name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Program statement that defines some action (or expression) to be carried out.
|
/// Program statement that defines some action (or expression) to be carried out.
|
||||||
@ -98,8 +107,8 @@ pub enum Statement {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
FieldElement,
|
|
||||||
Boolean,
|
Boolean,
|
||||||
|
FieldElement,
|
||||||
Array(Box<Type>, usize),
|
Array(Box<Type>, usize),
|
||||||
Struct(Variable),
|
Struct(Variable),
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
use crate::aleo_program::{
|
use crate::aleo_program::{
|
||||||
BooleanExpression, BooleanSpread, BooleanSpreadOrExpression, Expression, FieldExpression,
|
BooleanExpression, BooleanSpread, BooleanSpreadOrExpression, Expression, FieldExpression,
|
||||||
FieldSpread, FieldSpreadOrExpression, Statement, Struct, StructField, Type, Variable,
|
FieldRangeOrExpression, FieldSpread, FieldSpreadOrExpression, Statement, Struct, StructField,
|
||||||
|
Type, Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -108,6 +109,22 @@ impl<'ast> fmt::Display for BooleanExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Display for FieldRangeOrExpression {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
FieldRangeOrExpression::Range(ref from, ref to) => write!(
|
||||||
|
f,
|
||||||
|
"{}..{}",
|
||||||
|
from.as_ref()
|
||||||
|
.map(|e| e.to_string())
|
||||||
|
.unwrap_or("".to_string()),
|
||||||
|
to.as_ref().map(|e| e.to_string()).unwrap_or("".to_string())
|
||||||
|
),
|
||||||
|
FieldRangeOrExpression::FieldExpression(ref e) => write!(f, "{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast> fmt::Display for Expression {
|
impl<'ast> fmt::Display for Expression {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
@ -124,6 +141,8 @@ impl<'ast> fmt::Display for Expression {
|
|||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
|
Expression::ArrayAccess(ref array, ref index) => write!(f, "{}[{}]", array, index),
|
||||||
|
_ => unimplemented!("can't display expression yet"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::BooleanExpression {
|
|||||||
match types::Expression::from(expression) {
|
match types::Expression::from(expression) {
|
||||||
types::Expression::Boolean(boolean_expression) => boolean_expression,
|
types::Expression::Boolean(boolean_expression) => boolean_expression,
|
||||||
types::Expression::Variable(variable) => types::BooleanExpression::Variable(variable),
|
types::Expression::Variable(variable) => types::BooleanExpression::Variable(variable),
|
||||||
types::Expression::FieldElement(field_expression) => unimplemented!(
|
_ => unimplemented!("expected boolean in boolean expression"),
|
||||||
"cannot compare field expression {} in boolean expression",
|
|
||||||
field_expression
|
|
||||||
),
|
|
||||||
types::Expression::Struct(_v, _m) => unimplemented!("no inline struct yet"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,11 +86,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::FieldExpression {
|
|||||||
match types::Expression::from(expression) {
|
match types::Expression::from(expression) {
|
||||||
types::Expression::FieldElement(field_expression) => field_expression,
|
types::Expression::FieldElement(field_expression) => field_expression,
|
||||||
types::Expression::Variable(variable) => types::FieldExpression::Variable(variable),
|
types::Expression::Variable(variable) => types::FieldExpression::Variable(variable),
|
||||||
types::Expression::Boolean(boolean_expression) => unimplemented!(
|
_ => unimplemented!("expected field in field expression"),
|
||||||
"cannot compare boolean expression {} in field expression",
|
|
||||||
boolean_expression
|
|
||||||
),
|
|
||||||
types::Expression::Struct(_v, _m) => unimplemented!("no inline struct yet"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,6 +273,71 @@ impl<'ast> From<ast::TernaryExpression<'ast>> for types::Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast> From<ast::RangeOrExpression<'ast>> for types::FieldRangeOrExpression {
|
||||||
|
fn from(range_or_expression: ast::RangeOrExpression<'ast>) -> Self {
|
||||||
|
match range_or_expression {
|
||||||
|
ast::RangeOrExpression::Range(range) => {
|
||||||
|
let from = range
|
||||||
|
.from
|
||||||
|
.map(|from| match types::Expression::from(from.0) {
|
||||||
|
types::Expression::FieldElement(field) => field,
|
||||||
|
expression => {
|
||||||
|
unimplemented!("Range bounds should be numbers, found {}", expression)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let to = range.to.map(|to| match types::Expression::from(to.0) {
|
||||||
|
types::Expression::FieldElement(field) => field,
|
||||||
|
expression => {
|
||||||
|
unimplemented!("Range bounds should be numbers, found {}", expression)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
types::FieldRangeOrExpression::Range(from, to)
|
||||||
|
}
|
||||||
|
ast::RangeOrExpression::Expression(expression) => {
|
||||||
|
match types::Expression::from(expression) {
|
||||||
|
types::Expression::FieldElement(field_expression) => {
|
||||||
|
types::FieldRangeOrExpression::FieldExpression(field_expression)
|
||||||
|
}
|
||||||
|
// types::Expression::ArrayAccess(expression, field), // recursive array access
|
||||||
|
expression => unimplemented!("expression must be field, found {}", expression),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> From<ast::PostfixExpression<'ast>> for types::Expression {
|
||||||
|
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
|
||||||
|
let variable = types::Expression::Variable(types::Variable::from(expression.variable));
|
||||||
|
|
||||||
|
// ast::PostFixExpression contains an array of "accesses": `a(34)[42]` is represented as `[a, [Call(34), Select(42)]]`, but Access call expressions
|
||||||
|
// are recursive, so it is `Select(Call(a, 34), 42)`. We apply this transformation here
|
||||||
|
|
||||||
|
// we start with the id, and we fold the array of accesses by wrapping the current value
|
||||||
|
expression
|
||||||
|
.accesses
|
||||||
|
.into_iter()
|
||||||
|
.fold(variable, |acc, access| match access {
|
||||||
|
ast::Access::Call(a) => match acc {
|
||||||
|
types::Expression::Variable(_) => {
|
||||||
|
unimplemented!("function calls not implemented")
|
||||||
|
}
|
||||||
|
expression => {
|
||||||
|
unimplemented!("only function names are callable, found \"{}\"", expression)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::Access::Member(struct_member) => {
|
||||||
|
unimplemented!("struct calls not implemented")
|
||||||
|
}
|
||||||
|
ast::Access::Select(array) => types::Expression::ArrayAccess(
|
||||||
|
Box::new(acc),
|
||||||
|
types::FieldRangeOrExpression::from(array.expression),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast> From<ast::Expression<'ast>> for types::Expression {
|
impl<'ast> From<ast::Expression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::Expression<'ast>) -> Self {
|
fn from(expression: ast::Expression<'ast>) -> Self {
|
||||||
match expression {
|
match expression {
|
||||||
@ -295,6 +352,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::Expression {
|
|||||||
ast::Expression::ArrayInitializer(_expression) => {
|
ast::Expression::ArrayInitializer(_expression) => {
|
||||||
unimplemented!("unknown type for array initializer expression")
|
unimplemented!("unknown type for array initializer expression")
|
||||||
}
|
}
|
||||||
|
ast::Expression::Postfix(expression) => types::Expression::from(expression),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
src/ast.rs
16
src/ast.rs
@ -392,13 +392,13 @@ pub enum RangeOrExpression<'ast> {
|
|||||||
Expression(Expression<'ast>),
|
Expression(Expression<'ast>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
// #[pest_ast(rule(Rule::call_access))]
|
#[pest_ast(rule(Rule::access_call))]
|
||||||
// pub struct CallAccess<'ast> {
|
pub struct CallAccess<'ast> {
|
||||||
// pub expressions: Vec<Expression<'ast>>,
|
pub expressions: Vec<Expression<'ast>>,
|
||||||
// #[pest_ast(outer())]
|
#[pest_ast(outer())]
|
||||||
// pub span: Span<'ast>,
|
pub span: Span<'ast>,
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
#[pest_ast(rule(Rule::access_array))]
|
#[pest_ast(rule(Rule::access_array))]
|
||||||
@ -419,7 +419,7 @@ pub struct MemberAccess<'ast> {
|
|||||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||||
#[pest_ast(rule(Rule::access))]
|
#[pest_ast(rule(Rule::access))]
|
||||||
pub enum Access<'ast> {
|
pub enum Access<'ast> {
|
||||||
// Call(CallAccess<'ast>),
|
Call(CallAccess<'ast>),
|
||||||
Select(ArrayAccess<'ast>),
|
Select(ArrayAccess<'ast>),
|
||||||
Member(MemberAccess<'ast>),
|
Member(MemberAccess<'ast>),
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ access_array = { "[" ~ range_or_expression ~ "]" }
|
|||||||
access_call = { "(" ~ expression_tuple ~ ")" }
|
access_call = { "(" ~ expression_tuple ~ ")" }
|
||||||
access_member = { "." ~ variable }
|
access_member = { "." ~ variable }
|
||||||
access = { access_array | access_call | access_member }
|
access = { access_array | access_call | access_member }
|
||||||
expression_postfix = { variable ~ access+ } // add ++ and -- operators
|
expression_postfix = { variable ~ access+ }
|
||||||
|
|
||||||
spread = { "..." ~ expression }
|
spread = { "..." ~ expression }
|
||||||
spread_or_expression = { spread | expression }
|
spread_or_expression = { spread | expression }
|
||||||
|
Loading…
Reference in New Issue
Block a user