diff --git a/simple.program b/simple.program index c4ab5a5061..b30af8c1d9 100644 --- a/simple.program +++ b/simple.program @@ -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 \ No newline at end of file +//bool[2] a = [true, false] +//bool[2] b = [true; 2] + +//field[4] c = [1, 2, 3, 4] +//field[3] d = [1; 3] + +return p \ No newline at end of file diff --git a/src/aleo_program/constraints.rs b/src/aleo_program/constraints.rs index d81141d9ee..4826a47573 100644 --- a/src/aleo_program/constraints.rs +++ b/src/aleo_program/constraints.rs @@ -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), FieldElement(UInt32), FieldElementArray(Vec), - Struct(Struct), + StructDefinition(Struct), + StructExpression(Variable, Vec), 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>( + &mut self, + cs: &mut CS, + variable: Variable, + members: Vec, + ) -> 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>( + &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::() + .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>( &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::() - .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::() + // .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 diff --git a/src/aleo_program/types.rs b/src/aleo_program/types.rs index e3def75898..81fc40b58d 100644 --- a/src/aleo_program/types.rs +++ b/src/aleo_program/types.rs @@ -85,6 +85,7 @@ pub enum Expression { Boolean(BooleanExpression), FieldElement(FieldExpression), Variable(Variable), + Struct(Variable, Vec), } /// 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 +// } + #[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); - // } } diff --git a/src/aleo_program/types_display.rs b/src/aleo_program/types_display.rs index 23248871d4..36eb76aa30 100644 --- a/src/aleo_program/types_display.rs +++ b/src/aleo_program/types_display.rs @@ -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, "}}") + } } } } diff --git a/src/aleo_program/types_from.rs b/src/aleo_program/types_from.rs index c25dc40966..6c7a52dd8e 100644 --- a/src/aleo_program/types_from.rs +++ b/src/aleo_program/types_from.rs @@ -5,6 +5,7 @@ //! @author Collin Chin //! @date 2020 +use crate::aleo_program::StructMember; use crate::{aleo_program::types, ast}; use std::collections::HashMap; @@ -79,6 +80,7 @@ impl<'ast> From> 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> 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> for types::FieldSpreadOrExpressio } } +impl<'ast> From> 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::>(); + + 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 {