constraints inline structs

This commit is contained in:
collin 2020-04-14 22:55:38 -07:00
parent 3f83786871
commit c14ed231ea
5 changed files with 224 additions and 120 deletions

View File

@ -1,7 +1,14 @@
bool[2] a = [true, false]
bool[2] b = [true; 2]
struct Point {
field x
field y
}
field[4] c = [1, 2, 3, 4]
field[3] d = [1; 3]
Point p = Point {x: 1, y: 0}
return a
//bool[2] a = [true, false]
//bool[2] b = [true; 2]
//field[4] c = [1, 2, 3, 4]
//field[3] d = [1; 3]
return p

View File

@ -1,6 +1,6 @@
use crate::aleo_program::{
BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression,
FieldSpreadOrExpression, Function, Program, Statement, Struct, Variable,
FieldSpreadOrExpression, Function, Program, Statement, Struct, StructMember, Type, Variable,
};
use snarkos_models::curves::{Field, PrimeField};
@ -18,7 +18,8 @@ pub enum ResolvedValue {
BooleanArray(Vec<Boolean>),
FieldElement(UInt32),
FieldElementArray(Vec<UInt32>),
Struct(Struct),
StructDefinition(Struct),
StructExpression(Variable, Vec<StructMember>),
Function(Function),
}
@ -47,6 +48,16 @@ impl fmt::Display for ResolvedValue {
}
write!(f, "]")
}
ResolvedValue::StructExpression(ref variable, ref members) => {
write!(f, "{} {{", variable)?;
for (i, member) in members.iter().enumerate() {
write!(f, "{}: {}", member.variable, member.expression)?;
if i < members.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
_ => unimplemented!("resolve values not finished"),
}
}
@ -416,63 +427,154 @@ impl ResolvedProgram {
}
}
fn enforce_struct_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
variable: Variable,
members: Vec<StructMember>,
) -> ResolvedValue {
if let Some(resolved_value) = self.resolved_variables.get_mut(&variable) {
match resolved_value {
ResolvedValue::StructDefinition(struct_definition) => {
// for (field, member) in struct_definition.fields.iter().zip(members.into_iter()) {
// self.enforce_expression(cs, member.expression);
// }
struct_definition
.fields
.clone()
.iter()
.zip(members.clone().into_iter())
.for_each(|(field, member)| {
if field.variable != member.variable {
unimplemented!("struct field variables do not match")
}
// Resolve and possibly enforce struct fields
// do we need to store the results here?
let _result = self.enforce_expression(cs, member.expression);
});
ResolvedValue::StructExpression(variable, members)
}
_ => unimplemented!("Inline struct type is not defined as a struct"),
}
} else {
unimplemented!("Struct must be declared before it is used in an inline expression")
}
}
fn enforce_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
expression: Expression,
) -> ResolvedValue {
match expression {
Expression::Boolean(boolean_expression) => {
self.enforce_boolean_expression(cs, boolean_expression)
}
Expression::FieldElement(field_expression) => {
self.enforce_field_expression(cs, field_expression)
}
Expression::Variable(unresolved_variable) => {
if self.resolved_variables.contains_key(&unresolved_variable) {
// Reassigning variable to another variable
self.resolved_variables
.get_mut(&unresolved_variable)
.unwrap()
.clone()
} else {
// The type of the unassigned variable depends on what is passed in
if std::env::args()
.nth(1)
.expect("variable declaration not passed in")
.parse::<bool>()
.is_ok()
{
ResolvedValue::Boolean(self.bool_from_variable(cs, unresolved_variable))
} else {
ResolvedValue::FieldElement(self.u32_from_variable(cs, unresolved_variable))
}
}
}
Expression::Struct(struct_name, members) => {
self.enforce_struct_expression(cs, struct_name, members)
}
}
}
fn enforce_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
statement: Statement,
) {
match statement {
Statement::Definition(variable, expression) => match expression {
Expression::Boolean(boolean_expression) => {
let res = self.enforce_boolean_expression(cs, boolean_expression);
println!(" variable boolean result: {} = {}", variable.0, res);
self.insert(variable, res);
}
Expression::FieldElement(field_expression) => {
let res = self.enforce_field_expression(cs, field_expression);
println!(" variable field result: {} = {}", variable.0, res);
self.insert(variable, res);
}
Expression::Variable(unresolved_variable) => {
if self.resolved_variables.contains_key(&unresolved_variable) {
// Reassigning variable to another variable
let already_assigned = self
.resolved_variables
.get_mut(&unresolved_variable)
.unwrap()
.clone();
self.insert(variable, already_assigned);
} else {
// The type of the unassigned variable depends on what is passed in
if std::env::args()
.nth(1)
.expect("variable declaration not passed in")
.parse::<bool>()
.is_ok()
{
let resolved_boolean = self.bool_from_variable(cs, unresolved_variable);
println!(
"variable boolean result: {} = {}",
variable.0,
resolved_boolean.get_value().unwrap()
);
self.insert(variable, ResolvedValue::Boolean(resolved_boolean));
} else {
let resolved_field_element =
self.u32_from_variable(cs, unresolved_variable);
println!(
" variable field result: {} = {}",
variable.0,
resolved_field_element.value.unwrap()
);
self.insert(
variable,
ResolvedValue::FieldElement(resolved_field_element),
);
}
}
}
},
Statement::Definition(variable, expression) => {
let result = self.enforce_expression(cs, expression);
println!(" statement result: {} = {}", variable.0, result);
self.insert(variable, result);
}
// Expression::Boolean(boolean_expression) => {
// let res = self.enforce_boolean_expression(cs, boolean_expression);
// println!(" variable boolean result: {} = {}", variable.0, res);
// self.insert(variable, res);
// }
// Expression::FieldElement(field_expression) => {
// let res = self.enforce_field_expression(cs, field_expression);
// println!(" variable field result: {} = {}", variable.0, res);
// self.insert(variable, res);
// }
// Expression::Variable(unresolved_variable) => {
// if self.resolved_variables.contains_key(&unresolved_variable) {
// // Reassigning variable to another variable
// let already_assigned = self
// .resolved_variables
// .get_mut(&unresolved_variable)
// .unwrap()
// .clone();
// self.insert(variable, already_assigned);
// } else {
// // The type of the unassigned variable depends on what is passed in
// if std::env::args()
// .nth(1)
// .expect("variable declaration not passed in")
// .parse::<bool>()
// .is_ok()
// {
// let resolved_boolean = self.bool_from_variable(cs, unresolved_variable);
// println!(
// "variable boolean result: {} = {}",
// variable.0,
// resolved_boolean.get_value().unwrap()
// );
// self.insert(variable, ResolvedValue::Boolean(resolved_boolean));
// } else {
// let resolved_field_element =
// self.u32_from_variable(cs, unresolved_variable);
// println!(
// " variable field result: {} = {}",
// variable.0,
// resolved_field_element.value.unwrap()
// );
// self.insert(
// variable,
// ResolvedValue::FieldElement(resolved_field_element),
// );
// }
// }
// }
// Expression::Struct(struct_name, members) => {
// let resolved_struct = self.enforce_struct_expression(cs, struct_name, members);
// println!(
// " inline struct declared: {} = {}",
// variable.0,
// resolved_struct
// );
// self.insert(
// variable,
// resolved_struct
// );
// }
// },
Statement::Return(statements) => {
statements
.into_iter()
@ -491,6 +593,9 @@ impl ResolvedProgram {
self.resolved_variables.get_mut(&variable).unwrap().clone()
);
}
Expression::Struct(_v, _m) => {
unimplemented!("return struct not impl");
}
});
}
};
@ -508,7 +613,7 @@ impl ResolvedProgram {
.for_each(|(variable, struct_def)| {
resolved_program
.resolved_variables
.insert(variable, ResolvedValue::Struct(struct_def));
.insert(variable, ResolvedValue::StructDefinition(struct_def));
});
program
.functions

View File

@ -85,6 +85,7 @@ pub enum Expression {
Boolean(BooleanExpression),
FieldElement(FieldExpression),
Variable(Variable),
Struct(Variable, Vec<StructMember>),
}
/// Program statement that defines some action (or expression) to be carried out.
@ -103,6 +104,18 @@ pub enum Type {
Struct(Variable),
}
#[derive(Clone, Debug)]
pub struct StructMember {
pub variable: Variable,
pub expression: Expression,
}
// #[derive(Clone, Debug)]
// pub struct StructExpression {
// pub variable: Variable,
// pub members: Vec<StructMember>
// }
#[derive(Clone)]
pub struct StructField {
pub variable: Variable,
@ -157,63 +170,4 @@ mod tests {
println!("{:#?}", variable);
}
// #[test]
// fn test_linear_combination() {
// let variable_0 = Variable { id: 0, value: "1".into() };
// let variable_1 = Variable { id: 0, value: "1".into() };
// let linear_combination = LinearCombination(vec![variable_0, variable_1]);
//
// println!("{:#?}", linear_combination);
// }
// #[test]
// fn test_statement_linear() {
// let linear_combination = LinearCombination(vec![Variable { id: 0 }, Variable { id: 1 }]);
// let statement_linear = Statement::Linear(linear_combination);
//
// println!("{:#?}", statement_linear);
// }
//
// #[test]
// fn test_statement_quadratic() {
// let linear_combination_0 = LinearCombination(vec![Variable { id: 0 }]);
// let linear_combination_1 = LinearCombination(vec![Variable { id: 1 }]);
// let statement_quadratic = Statement::Quadratic(linear_combination_0, linear_combination_1);
//
// println!("{:#?}", statement_quadratic);
// }
//
// #[test]
// fn test_program() {
// let variable_0 = Variable{ id: 0};
// let linear_combination = LinearCombination(vec![variable_0.clone()]);
// let statement_linear = Statement::Linear(linear_combination.clone());
// let statement_quadratic = Statement::Quadratic(linear_combination.clone(), linear_combination);
// let program = Program{
// id: "main".into(),
// statements: vec![statement_linear, statement_quadratic],
// arguments: vec![variable_0.clone()],
// returns: vec![variable_0.clone()]
// };
//
// println!("{:#?}", program);
// }
// #[test]
// fn test_basic_prog() {
// // return 1 == 1
// let prog = Program {
// id: "main".into(),
// statements: vec![Statement::Return(vec![Expression::Boolean(
// BooleanExpression::FieldEq(
// Box::new(FieldExpression::Number(1)),
// Box::new(FieldExpression::Number(1)),
// ),
// )])],
// arguments: vec![],
// returns: vec![],
// };
//
// println!("{:#?}", prog);
// }
}

View File

@ -114,6 +114,16 @@ impl<'ast> fmt::Display for Expression {
Expression::Boolean(ref boolean_expression) => write!(f, "{}", boolean_expression),
Expression::FieldElement(ref field_expression) => write!(f, "{}", field_expression),
Expression::Variable(ref variable) => write!(f, "{}", variable),
Expression::Struct(ref var, ref members) => {
write!(f, "{} {{", var)?;
for (i, member) in members.iter().enumerate() {
write!(f, "{}: {}", member.variable, member.expression)?;
if i < members.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
}
}
}

View File

@ -5,6 +5,7 @@
//! @author Collin Chin <collin@aleo.org>
//! @date 2020
use crate::aleo_program::StructMember;
use crate::{aleo_program::types, ast};
use std::collections::HashMap;
@ -79,6 +80,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::BooleanExpression {
"cannot compare field expression {} in boolean expression",
field_expression
),
types::Expression::Struct(_v, _m) => unimplemented!("no inline struct yet"),
}
}
}
@ -92,6 +94,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::FieldExpression {
"cannot compare boolean expression {} in field expression",
boolean_expression
),
types::Expression::Struct(_v, _m) => unimplemented!("no inline struct yet"),
}
}
}
@ -379,6 +382,15 @@ impl<'ast> From<ast::SpreadOrExpression<'ast>> for types::FieldSpreadOrExpressio
}
}
impl<'ast> From<ast::InlineStructMember<'ast>> for types::StructMember {
fn from(member: ast::InlineStructMember<'ast>) -> Self {
types::StructMember {
variable: types::Variable::from(member.variable),
expression: types::Expression::from(member.expression),
}
}
}
impl<'ast> types::Expression {
fn from_basic(_ty: ast::BasicType<'ast>, _expression: ast::Expression<'ast>) -> Self {
unimplemented!("from basic not impl");
@ -435,8 +447,24 @@ impl<'ast> types::Expression {
}
}
fn from_struct(_ty: ast::StructType<'ast>, _expression: ast::Expression<'ast>) -> Self {
unimplemented!("from struct not impl");
fn from_struct(ty: ast::StructType<'ast>, expression: ast::Expression<'ast>) -> Self {
let declaration_struct = ty.variable.value;
match expression {
ast::Expression::StructInline(inline_struct) => {
if inline_struct.variable.value != declaration_struct {
unimplemented!("Declared struct type must match inline struct type")
}
let variable = types::Variable::from(inline_struct.variable);
let members = inline_struct
.members
.into_iter()
.map(|member| types::StructMember::from(member))
.collect::<Vec<StructMember>>();
types::Expression::Struct(variable, members)
}
_ => unimplemented!("Struct declaration must be followed by inline struct"),
}
}
fn from_type(ty: ast::Type<'ast>, expression: ast::Expression<'ast>) -> Self {