constraints inline array

This commit is contained in:
collin 2020-04-14 16:48:24 -07:00
parent 2f9e4b31e0
commit 83763a6817
6 changed files with 256 additions and 41 deletions

View File

@ -1,7 +1,3 @@
struct Foo {
field a
bool b
}
def main() -> (field) :
a = 1 + 1
return a
field[3] a = [1, 2, 3]
//b = 2 + 2
return a

View File

@ -1,5 +1,6 @@
use crate::aleo_program::{
BooleanExpression, Expression, FieldExpression, Function, Program, Statement, Struct, Variable,
BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression,
FieldSpreadOrExpression, Function, Program, Statement, Struct, Variable,
};
use snarkos_models::curves::{Field, PrimeField};
@ -9,15 +10,37 @@ use snarkos_models::gadgets::{
utilities::{alloc::AllocGadget, boolean::Boolean, eq::ConditionalEqGadget, uint32::UInt32},
};
use std::collections::HashMap;
use std::fmt;
#[derive(Clone)]
pub enum ResolvedValue {
Boolean(Boolean),
BooleanArray(Vec<Boolean>),
FieldElement(UInt32),
FieldElementArray(Vec<UInt32>),
Struct(Struct),
Function(Function),
}
impl fmt::Display for ResolvedValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ResolvedValue::FieldElement(ref value) => write!(f, "{}", value.value.unwrap()),
ResolvedValue::FieldElementArray(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, "]")
}
_ => unimplemented!("resolve values not finished"),
}
}
}
pub struct ResolvedProgram {
pub resolved_variables: HashMap<Variable, ResolvedValue>,
}
@ -101,7 +124,10 @@ impl ResolvedProgram {
match expression {
FieldExpression::Variable(variable) => self.u32_from_variable(cs, variable),
FieldExpression::Number(number) => UInt32::constant(number),
field => self.enforce_field_expression(cs, field),
field => match self.enforce_field_expression(cs, field) {
ResolvedValue::FieldElement(value) => value,
_ => unimplemented!("value not resolved"),
},
}
}
@ -295,15 +321,29 @@ impl ResolvedProgram {
&mut self,
cs: &mut CS,
expression: FieldExpression,
) -> UInt32 {
) -> ResolvedValue {
match expression {
FieldExpression::Variable(variable) => self.u32_from_variable(cs, variable),
FieldExpression::Number(number) => UInt32::constant(number),
FieldExpression::Add(left, right) => self.enforce_add(cs, *left, *right),
FieldExpression::Sub(left, right) => self.enforce_sub(cs, *left, *right),
FieldExpression::Mul(left, right) => self.enforce_mul(cs, *left, *right),
FieldExpression::Div(left, right) => self.enforce_div(cs, *left, *right),
FieldExpression::Pow(left, right) => self.enforce_pow(cs, *left, *right),
FieldExpression::Variable(variable) => {
ResolvedValue::FieldElement(self.u32_from_variable(cs, variable))
}
FieldExpression::Number(number) => {
ResolvedValue::FieldElement(UInt32::constant(number))
}
FieldExpression::Add(left, right) => {
ResolvedValue::FieldElement(self.enforce_add(cs, *left, *right))
}
FieldExpression::Sub(left, right) => {
ResolvedValue::FieldElement(self.enforce_sub(cs, *left, *right))
}
FieldExpression::Mul(left, right) => {
ResolvedValue::FieldElement(self.enforce_mul(cs, *left, *right))
}
FieldExpression::Div(left, right) => {
ResolvedValue::FieldElement(self.enforce_div(cs, *left, *right))
}
FieldExpression::Pow(left, right) => {
ResolvedValue::FieldElement(self.enforce_pow(cs, *left, *right))
}
FieldExpression::IfElse(first, second, third) => {
if self
.enforce_boolean_expression(cs, *first)
@ -314,6 +354,23 @@ impl ResolvedProgram {
self.enforce_field_expression(cs, *third)
}
}
FieldExpression::Array(array) => ResolvedValue::FieldElementArray(
array
.into_iter()
.map(|element| match *element {
FieldSpreadOrExpression::Spread(spread) => {
unimplemented!("spreads not enforced yet")
}
FieldSpreadOrExpression::FieldExpression(expression) => {
let resolved = self.enforce_field_expression(cs, expression);
match resolved {
ResolvedValue::FieldElement(value) => value,
_ => unimplemented!("cannot resolve field"),
}
}
})
.collect::<Vec<UInt32>>(),
),
}
}
@ -335,12 +392,8 @@ impl ResolvedProgram {
}
Expression::FieldElement(field_expression) => {
let res = self.enforce_field_expression(cs, field_expression);
println!(
" variable field result: {} = {}",
variable.0,
res.value.unwrap()
);
self.insert(variable, ResolvedValue::FieldElement(res));
println!(" variable field result: {} = {}", variable.0, res);
self.insert(variable, res);
}
Expression::Variable(unresolved_variable) => {
if self.resolved_variables.contains_key(&unresolved_variable) {
@ -392,7 +445,7 @@ impl ResolvedProgram {
}
Expression::FieldElement(field_expression) => {
let res = self.enforce_field_expression(cs, field_expression);
println!("\n Field result = {}", res.value.unwrap());
println!("\n Field result = {}", res);
}
Expression::Variable(variable) => {
match self.resolved_variables.get_mut(&variable).unwrap().clone() {
@ -435,18 +488,19 @@ impl ResolvedProgram {
.insert(variable, ResolvedValue::Function(function));
});
let main = resolved_program
.resolved_variables
.get_mut(&Variable("main".into()))
.expect("main function not defined");
match main {
ResolvedValue::Function(function) => function
.statements
.clone()
.into_iter()
.for_each(|statement| resolved_program.enforce_statement(cs, statement)),
_ => unimplemented!("main must be a function"),
}
// let main = resolved_program
// .resolved_variables
// .get_mut(&Variable("main".into()))
// .expect("main function not defined");
//
// match main {
// ResolvedValue::Function(function) => function
// .statements
// .clone()
// .into_iter()
// .for_each(|statement| resolved_program.enforce_statement(cs, statement)),
// _ => unimplemented!("main must be a function"),
// }
program
.statements

View File

@ -10,6 +10,17 @@ use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Variable(pub String);
/// Spread operator
#[derive(Debug, Clone)]
pub struct FieldSpread(pub FieldExpression);
/// Spread or field expression enum
#[derive(Debug, Clone)]
pub enum FieldSpreadOrExpression {
Spread(FieldSpread),
FieldExpression(FieldExpression),
}
/// Expression that evaluates to a field value
#[derive(Debug, Clone)]
pub enum FieldExpression {
@ -27,6 +38,19 @@ pub enum FieldExpression {
Box<FieldExpression>,
Box<FieldExpression>,
),
// Arrays
Array(Vec<Box<FieldSpreadOrExpression>>),
}
/// Spread operator
#[derive(Debug, Clone)]
pub struct BooleanSpread(pub BooleanExpression);
/// Spread or field expression enum
#[derive(Debug, Clone)]
pub enum BooleanSpreadOrExpression {
Spread(BooleanSpread),
BooleanExpression(BooleanExpression),
}
/// Expression that evaluates to a boolean value
@ -51,6 +75,8 @@ pub enum BooleanExpression {
Box<BooleanExpression>,
Box<BooleanExpression>,
),
// Arrays
Array(Vec<Box<BooleanSpreadOrExpression>>),
}
/// Expression that evaluates to a value

View File

@ -5,7 +5,8 @@
//! @date 2020
use crate::aleo_program::{
BooleanExpression, Expression, FieldExpression, Statement, Struct, StructField, Type, Variable,
BooleanExpression, Expression, FieldExpression, FieldSpread, FieldSpreadOrExpression,
Statement, Struct, StructField, Type, Variable,
};
use std::fmt;
@ -16,6 +17,21 @@ impl fmt::Display for Variable {
}
}
impl fmt::Display for FieldSpread {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "...{}", self.0)
}
}
impl fmt::Display for FieldSpreadOrExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldSpreadOrExpression::Spread(ref spread) => write!(f, "{}", spread),
FieldSpreadOrExpression::FieldExpression(ref expression) => write!(f, "{}", expression),
}
}
}
impl<'ast> fmt::Display for FieldExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
@ -29,6 +45,16 @@ impl<'ast> fmt::Display for FieldExpression {
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, "]")
}
}
}
}
@ -51,6 +77,7 @@ impl<'ast> fmt::Display for BooleanExpression {
BooleanExpression::IfElse(ref a, ref b, ref c) => {
write!(f, "if {} then {} else {} fi", a, b, c)
}
_ => unimplemented!(),
}
}
}

View File

@ -286,6 +286,9 @@ impl<'ast> From<ast::Expression<'ast>> for types::Expression {
ast::Expression::Not(expression) => types::Expression::from(expression),
ast::Expression::Binary(expression) => types::Expression::from(expression),
ast::Expression::Ternary(expression) => types::Expression::from(expression),
ast::Expression::ArrayInline(expression) => {
unimplemented!("unknown type for inline array expression")
}
_ => unimplemented!(),
}
}
@ -300,11 +303,120 @@ impl<'ast> From<ast::AssignStatement<'ast>> for types::Statement {
}
}
impl<'ast> From<ast::Spread<'ast>> for types::BooleanSpread {
fn from(spread: ast::Spread<'ast>) -> Self {
let boolean_expression = types::Expression::from(spread.expression);
match boolean_expression {
types::Expression::Boolean(expression) => types::BooleanSpread(expression),
_ => unimplemented!("cannot create boolean spread from field type"),
}
}
}
impl<'ast> From<ast::Spread<'ast>> for types::FieldSpread {
fn from(spread: ast::Spread<'ast>) -> Self {
let field_expression = types::Expression::from(spread.expression);
match field_expression {
types::Expression::FieldElement(expression) => types::FieldSpread(expression),
_ => unimplemented!("cannot create field spread from boolean type"),
}
}
}
impl<'ast> From<ast::SpreadOrExpression<'ast>> for types::BooleanSpreadOrExpression {
fn from(s_or_e: ast::SpreadOrExpression<'ast>) -> Self {
match s_or_e {
ast::SpreadOrExpression::Spread(spread) => {
types::BooleanSpreadOrExpression::Spread(types::BooleanSpread::from(spread))
}
ast::SpreadOrExpression::Expression(expression) => {
let boolean_expression = types::Expression::from(expression);
match boolean_expression {
types::Expression::Boolean(expression) => {
types::BooleanSpreadOrExpression::BooleanExpression(expression)
}
_ => unimplemented!("cannot create boolean expression from field type"),
}
}
}
}
}
impl<'ast> From<ast::SpreadOrExpression<'ast>> for types::FieldSpreadOrExpression {
fn from(s_or_e: ast::SpreadOrExpression<'ast>) -> Self {
match s_or_e {
ast::SpreadOrExpression::Spread(spread) => {
types::FieldSpreadOrExpression::Spread(types::FieldSpread::from(spread))
}
ast::SpreadOrExpression::Expression(expression) => {
let field_expression = types::Expression::from(expression);
match field_expression {
types::Expression::FieldElement(expression) => {
types::FieldSpreadOrExpression::FieldExpression(expression)
}
_ => unimplemented!("cannot create field expression from boolean type"),
}
}
}
}
}
impl<'ast> types::Expression {
fn from_basic(ty: ast::BasicType<'ast>, expression: ast::Expression<'ast>) -> Self {
unimplemented!("from basic not impl");
}
fn from_array(ty: ast::ArrayType<'ast>, expression: ast::Expression<'ast>) -> Self {
match ty.ty {
ast::BasicType::Boolean(_ty) => {
let elements: Vec<Box<types::BooleanSpreadOrExpression>> = match expression {
ast::Expression::ArrayInline(array) => array
.expressions
.into_iter()
.map(|s_or_e| Box::new(types::BooleanSpreadOrExpression::from(s_or_e)))
.collect(),
ast::Expression::ArrayInitializer(expression) => {
unimplemented!("no array init yet")
}
_ => unimplemented!("expected array after array type"),
};
types::Expression::Boolean(types::BooleanExpression::Array(elements))
}
ast::BasicType::Field(_ty) => {
let elements: Vec<Box<types::FieldSpreadOrExpression>> = match expression {
ast::Expression::ArrayInline(array) => array
.expressions
.into_iter()
.map(|s_or_e| Box::new(types::FieldSpreadOrExpression::from(s_or_e)))
.collect(),
ast::Expression::ArrayInitializer(expression) => {
unimplemented!("array init not yet")
}
_ => unimplemented!("expected array after array type"),
};
types::Expression::FieldElement(types::FieldExpression::Array(elements))
}
}
}
fn from_struct(ty: ast::StructType<'ast>, expression: ast::Expression<'ast>) -> Self {
unimplemented!("from struct not impl");
}
fn from_type(ty: ast::Type<'ast>, expression: ast::Expression<'ast>) -> Self {
match ty {
ast::Type::Basic(ty) => Self::from_basic(ty, expression),
ast::Type::Array(ty) => Self::from_array(ty, expression),
ast::Type::Struct(ty) => Self::from_struct(ty, expression),
}
}
}
impl<'ast> From<ast::DefinitionStatement<'ast>> for types::Statement {
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
types::Statement::Definition(
types::Variable::from(statement.variable),
types::Expression::from(statement.expression),
types::Expression::from_type(statement.ty, statement.expression),
)
}
}
@ -333,8 +445,8 @@ impl<'ast> From<ast::Statement<'ast>> for types::Statement {
match statement {
ast::Statement::Assign(statement) => types::Statement::from(statement),
ast::Statement::Definition(statement) => types::Statement::from(statement),
ast::Statement::Return(statement) => types::Statement::from(statement),
ast::Statement::Iteration(statement) => types::Statement::from(statement),
ast::Statement::Return(statement) => types::Statement::from(statement),
}
}
}

View File

@ -54,7 +54,7 @@ ty_bool = {"bool"}
ty_basic = { ty_field | ty_bool }
ty_struct = { variable }
ty_basic_or_struct = {ty_basic | ty_struct }
ty_array = {ty_basic ~ ("[" ~ expression ~ "]")+ }
ty_array = {ty_basic ~ ("[" ~ value ~ "]")+ }
ty = {ty_array | ty_basic | ty_struct}
type_list = _{(ty ~ ("," ~ ty)*)?}
@ -140,8 +140,8 @@ statement_iteration = { "for" ~ ty ~ variable ~ "in" ~ expression ~ ".." ~ expre
statement = {
(statement_return
| (statement_iteration
| statement_assign
| statement_definition
| statement_assign
) ~ NEWLINE
) ~ NEWLINE*
}