diff --git a/simple.program b/simple.program index fc22903370..1666f0bbc3 100644 --- a/simple.program +++ b/simple.program @@ -1,7 +1,3 @@ -struct Foo { - field a - bool b -} -def main() -> (field) : - a = 1 + 1 - return a \ No newline at end of file +field[3] a = [1, 2, 3] +//b = 2 + 2 +return a \ No newline at end of file diff --git a/src/aleo_program/constraints.rs b/src/aleo_program/constraints.rs index 1682b9b160..0e098c8768 100644 --- a/src/aleo_program/constraints.rs +++ b/src/aleo_program/constraints.rs @@ -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), FieldElement(UInt32), + FieldElementArray(Vec), 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, } @@ -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::>(), + ), } } @@ -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 diff --git a/src/aleo_program/types.rs b/src/aleo_program/types.rs index f7adc59e34..a682dc41a2 100644 --- a/src/aleo_program/types.rs +++ b/src/aleo_program/types.rs @@ -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, Box, ), + // Arrays + Array(Vec>), +} + +/// 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, Box, ), + // Arrays + Array(Vec>), } /// Expression that evaluates to a value diff --git a/src/aleo_program/types_display.rs b/src/aleo_program/types_display.rs index e273325f18..aead6d9b7d 100644 --- a/src/aleo_program/types_display.rs +++ b/src/aleo_program/types_display.rs @@ -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!(), } } } diff --git a/src/aleo_program/types_from.rs b/src/aleo_program/types_from.rs index 88f67a13eb..3210cdd75a 100644 --- a/src/aleo_program/types_from.rs +++ b/src/aleo_program/types_from.rs @@ -286,6 +286,9 @@ impl<'ast> From> 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> for types::Statement { } } +impl<'ast> From> 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> 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> 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> 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> = 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> = 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> 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> 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), } } } diff --git a/src/language.pest b/src/language.pest index fd4e3308d6..a35589be72 100644 --- a/src/language.pest +++ b/src/language.pest @@ -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* }