mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-08-15 16:50:22 +03:00
constraints inline structs
This commit is contained in:
parent
3f83786871
commit
c14ed231ea
@ -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
|
@ -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
|
||||
|
@ -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);
|
||||
// }
|
||||
}
|
||||
|
@ -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, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user