From b1a886640effe922219c490d28bb344aa0a44153 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 2 Sep 2020 15:01:37 -0700 Subject: [PATCH 1/4] impl parenthesis syntax for array initializer --- .../array_initializer_expression.rs | 4 ++-- ast/src/expressions/expression.rs | 2 +- ast/src/leo.pest | 2 +- ast/src/types/array_dimensions.rs | 9 ++++++++ typed/src/expression.rs | 22 +++++++++++++++++-- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ast/src/expressions/array_initializer_expression.rs b/ast/src/expressions/array_initializer_expression.rs index 87ea73cec3..a003501a93 100644 --- a/ast/src/expressions/array_initializer_expression.rs +++ b/ast/src/expressions/array_initializer_expression.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ast::Rule, expressions::Expression, values::PositiveNumber, SpanDef}; +use crate::{ast::Rule, expressions::Expression, types::ArrayDimensions, SpanDef}; use pest::Span; use pest_ast::FromPest; @@ -24,7 +24,7 @@ use serde::Serialize; #[pest_ast(rule(Rule::expression_array_initializer))] pub struct ArrayInitializerExpression<'ast> { pub expression: Box>, - pub count: PositiveNumber<'ast>, + pub dimensions: ArrayDimensions<'ast>, #[pest_ast(outer())] #[serde(with = "SpanDef")] pub span: Span<'ast>, diff --git a/ast/src/expressions/expression.rs b/ast/src/expressions/expression.rs index 47cb5d92e0..49801461f8 100644 --- a/ast/src/expressions/expression.rs +++ b/ast/src/expressions/expression.rs @@ -101,7 +101,7 @@ impl<'ast> fmt::Display for Expression<'ast> { write!(f, "") } Expression::ArrayInitializer(ref expression) => { - write!(f, "[{} ; {}]", expression.expression, expression.count) + write!(f, "[{} ; ({})]", expression.expression, expression.dimensions) } Expression::CircuitInline(ref expression) => write!(f, "{}", expression.span.as_str()), Expression::Postfix(ref expression) => write!(f, "{}", expression.span.as_str()), diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 9fb9df066f..7b211edfb8 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -346,7 +346,7 @@ expression = { expression_term ~ (operation_binary ~ expression_term)* } expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" } // Declared in expressions/array_initializer_expression.rs -expression_array_initializer = { "[" ~ expression ~ ";" ~ number_positive ~ "]" } +expression_array_initializer = { "[" ~ expression ~ ";" ~ array_dimensions ~ "]" } // Declared in expressions/array_inline_expression.rs expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"} diff --git a/ast/src/types/array_dimensions.rs b/ast/src/types/array_dimensions.rs index f75f141a15..c01a740d35 100644 --- a/ast/src/types/array_dimensions.rs +++ b/ast/src/types/array_dimensions.rs @@ -44,3 +44,12 @@ pub struct Multiple<'ast> { #[serde(with = "SpanDef")] pub span: Span<'ast>, } + +impl<'ast> std::fmt::Display for ArrayDimensions<'ast> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + ArrayDimensions::Single(ref single) => write!(f, "{}", single.number), + ArrayDimensions::Multiple(ref multiple) => write!(f, "{:?}", multiple.numbers), + } + } +} diff --git a/typed/src/expression.rs b/typed/src/expression.rs index 7dbfc71dfa..7faea8fb0a 100644 --- a/typed/src/expression.rs +++ b/typed/src/expression.rs @@ -485,10 +485,28 @@ impl<'ast> From> for Expression { impl<'ast> From> for Expression { fn from(array: ArrayInitializerExpression<'ast>) -> Self { - let count = Expression::get_count_from_ast(array.count); + let dimensions = Expression::get_array_dimensions(array.dimensions); let expression = Box::new(SpreadOrExpression::from(*array.expression)); - Expression::Array(vec![expression; count], Span::from(array.span)) + let mut elements = vec![]; + + // Initializes an arrays elements using the rust `vec!` macro. + // If there are multiple array dimensions, then `elements` is used as the first expression in a `vec!` macro. + // This creates a multi-dimensional array by chaining `vec!` macros. + for (i, dimension) in dimensions.into_iter().enumerate() { + if i == 0 { + elements = vec![expression.clone(); dimension]; + } else { + let element = Box::new(SpreadOrExpression::Expression(Expression::Array( + elements, + Span::from(array.span.clone()), + ))); + + elements = vec![element; dimension]; + } + } + + Expression::Array(elements, Span::from(array.span)) } } From 91350a2ffe011958ca4bdb83d2ad91d807225b1b Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 2 Sep 2020 15:47:05 -0700 Subject: [PATCH 2/4] impl parenthesis syntax for input array initializer --- input/src/errors/parser.rs | 21 ++++++--- .../array_initializer_expression.rs | 4 +- input/src/expressions/expression.rs | 2 +- input/src/leo-input.pest | 2 +- input/src/types/array_dimensions.rs | 13 +++++- input/src/types/array_type.rs | 2 +- typed/src/input/input_value.rs | 46 +++++++++---------- 7 files changed, 53 insertions(+), 37 deletions(-) diff --git a/input/src/errors/parser.rs b/input/src/errors/parser.rs index 7f3f8ad24e..d808b61b51 100644 --- a/input/src/errors/parser.rs +++ b/input/src/errors/parser.rs @@ -17,7 +17,7 @@ use crate::{ ast::Rule, errors::SyntaxError as InputSyntaxError, - expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression}, + expressions::{ArrayInlineExpression, Expression}, sections::Header, tables::Table, types::{DataType, Type}, @@ -71,14 +71,22 @@ impl InputParserError { } pub fn data_type_mismatch(data_type: DataType, value: Value) -> Self { - let message = format!("expected `{}`, found `{}`", data_type.to_string(), value.to_string()); + let message = format!( + "expected data type `{}`, found `{}`", + data_type.to_string(), + value.to_string() + ); let span = value.span().to_owned(); Self::new_from_span(message, span) } pub fn expression_type_mismatch(type_: Type, expression: Expression) -> Self { - let message = format!("expected `{}`, found `{}`", type_.to_string(), expression.to_string()); + let message = format!( + "expected expression type `{}`, found `{}`", + type_.to_string(), + expression.to_string() + ); let span = expression.span().to_owned(); Self::new_from_span(message, span) @@ -95,12 +103,11 @@ impl InputParserError { Self::new_from_span(message, span) } - pub fn array_init_length(number: usize, array: ArrayInitializerExpression) -> Self { + pub fn array_init_length(expected: Vec, actual: Vec, span: Span) -> Self { let message = format!( - "expected an array with a fixed size of {} elements, found one with {} elements", - number, array.count + "expected an array with a fixed size of {:?} elements, found one with {:?} elements", + expected, actual ); - let span = array.span.to_owned(); Self::new_from_span(message, span) } diff --git a/input/src/expressions/array_initializer_expression.rs b/input/src/expressions/array_initializer_expression.rs index b8ba714780..0a01c4e90d 100644 --- a/input/src/expressions/array_initializer_expression.rs +++ b/input/src/expressions/array_initializer_expression.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ast::Rule, expressions::Expression, values::PositiveNumber}; +use crate::{ast::Rule, expressions::Expression, types::ArrayDimensions}; use pest::Span; use pest_ast::FromPest; @@ -23,7 +23,7 @@ use pest_ast::FromPest; #[pest_ast(rule(Rule::expression_array_initializer))] pub struct ArrayInitializerExpression<'ast> { pub expression: Box>, - pub count: PositiveNumber<'ast>, + pub dimensions: ArrayDimensions<'ast>, #[pest_ast(outer())] pub span: Span<'ast>, } diff --git a/input/src/expressions/expression.rs b/input/src/expressions/expression.rs index e533ffc93c..c58bc66490 100644 --- a/input/src/expressions/expression.rs +++ b/input/src/expressions/expression.rs @@ -44,7 +44,7 @@ impl<'ast> fmt::Display for Expression<'ast> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Expression::ArrayInitializer(ref expression) => { - write!(f, "array [{} ; {}]", expression.expression, expression.count) + write!(f, "array [{} ; {}]", expression.expression, expression.dimensions) } Expression::ArrayInline(ref array) => { let values = array diff --git a/input/src/leo-input.pest b/input/src/leo-input.pest index 4a27b1a8b0..ec2574644b 100644 --- a/input/src/leo-input.pest +++ b/input/src/leo-input.pest @@ -179,7 +179,7 @@ value_address = {address | address_typed} /// Expressions // Declared in expressions/array_initializer_expression.rs -expression_array_initializer = { "[" ~ expression ~ ";" ~ number_positive ~ "]" } +expression_array_initializer = { "[" ~ expression ~ ";" ~ array_dimensions ~ "]" } // Declared in expressions/array_inline_expression.rs expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"} diff --git a/input/src/types/array_dimensions.rs b/input/src/types/array_dimensions.rs index 5ddac86af4..3cb19adc1e 100644 --- a/input/src/types/array_dimensions.rs +++ b/input/src/types/array_dimensions.rs @@ -53,7 +53,7 @@ impl<'ast> ArrayDimensions<'ast> { let old_dimension = multiple.numbers.clone(); ArrayDimensions::Multiple(Multiple { - numbers: old_dimension[..old_dimension.len() - 2].to_vec(), + numbers: old_dimension[..old_dimension.len() - 1].to_vec(), span: multiple.span.clone(), }) } @@ -65,7 +65,16 @@ impl<'ast> std::fmt::Display for ArrayDimensions<'ast> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { ArrayDimensions::Single(ref single) => write!(f, "{}", single.number), - ArrayDimensions::Multiple(ref multiple) => write!(f, "{:?}", multiple.numbers), + ArrayDimensions::Multiple(ref multiple) => { + let string = multiple + .numbers + .iter() + .map(|x| x.value.clone()) + .collect::>() + .join(", "); + + write!(f, "{}", string) + } } } } diff --git a/input/src/types/array_type.rs b/input/src/types/array_type.rs index 82e2ec688f..0110d7c030 100644 --- a/input/src/types/array_type.rs +++ b/input/src/types/array_type.rs @@ -33,6 +33,6 @@ pub struct ArrayType<'ast> { impl<'ast> std::fmt::Display for ArrayType<'ast> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "[{}; {}]", self.type_, self.dimensions) + write!(f, "[{}; ({})]", self.type_, self.dimensions) } } diff --git a/typed/src/input/input_value.rs b/typed/src/input/input_value.rs index f1bb3670ad..6f23861860 100644 --- a/typed/src/input/input_value.rs +++ b/typed/src/input/input_value.rs @@ -139,40 +139,40 @@ impl InputValue { } pub(crate) fn from_array_initializer( - mut array_type: ArrayType, + array_type: ArrayType, initializer: ArrayInitializerExpression, ) -> Result { let mut array_dimensions = TypedExpression::get_input_array_dimensions(array_type.dimensions.clone()); - let initializer_count = initializer.count.to_string().parse::()?; + let initializer_dimensions = TypedExpression::get_input_array_dimensions(initializer.dimensions.clone()); - // Return an error if the outer array dimension does not equal the number of array elements - if let Some(outer_dimension) = array_dimensions.pop() { - array_type.dimensions = array_type.dimensions.next_dimension(); - - if outer_dimension != initializer_count { - return Err(InputParserError::array_init_length(outer_dimension, initializer)); - } + // Return an error if the array type does not equal the array expression + if array_dimensions.ne(&initializer_dimensions) { + return Err(InputParserError::array_init_length( + array_dimensions, + initializer_dimensions, + initializer.span, + )); } - let inner_array_type = if array_dimensions.len() == 0 { - // this is a single array - match array_type.type_ { - ArrayElement::Basic(basic) => Type::Basic(basic), - ArrayElement::Tuple(tuple) => Type::Tuple(tuple), - } - } else { - // this is a multi-dimensional array - Type::Array(array_type) + let type_ = match array_type.type_ { + ArrayElement::Basic(basic) => Type::Basic(basic), + ArrayElement::Tuple(tuple) => Type::Tuple(tuple), }; - let mut values = vec![]; - for _ in 0..initializer_count { - let value = InputValue::from_expression(inner_array_type.clone(), *initializer.expression.clone())?; + let value = InputValue::from_expression(type_, *initializer.expression.clone())?; + let mut elements = vec![]; - values.push(value) + for (i, dimension) in initializer_dimensions.into_iter().enumerate() { + if i == 0 { + elements = vec![value.clone(); dimension]; + } else { + let element = InputValue::Array(elements.clone()); + + elements = vec![element; dimension]; + } } - Ok(InputValue::Array(values)) + Ok(InputValue::Array(elements)) } pub(crate) fn from_tuple(tuple_type: TupleType, tuple: TupleExpression) -> Result { From bd3b465a4f6e54a15436385d79488471955d4ad6 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 2 Sep 2020 16:04:41 -0700 Subject: [PATCH 3/4] add tests for input array initializer --- compiler/tests/array/initializer_input.leo | 3 +++ .../tests/array/input/initializer_fail.in | 2 ++ compiler/tests/array/input/six_zeros.in | 2 +- compiler/tests/array/mod.rs | 19 +++++++++++++++++++ typed/src/input/input_value.rs | 2 +- 5 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 compiler/tests/array/initializer_input.leo create mode 100644 compiler/tests/array/input/initializer_fail.in diff --git a/compiler/tests/array/initializer_input.leo b/compiler/tests/array/initializer_input.leo new file mode 100644 index 0000000000..4b886159dc --- /dev/null +++ b/compiler/tests/array/initializer_input.leo @@ -0,0 +1,3 @@ +function main(a: [u8; (3, 2)]) { + console.assert(a == [0u8; (3, 2)]); +} \ No newline at end of file diff --git a/compiler/tests/array/input/initializer_fail.in b/compiler/tests/array/input/initializer_fail.in new file mode 100644 index 0000000000..cf991c79b6 --- /dev/null +++ b/compiler/tests/array/input/initializer_fail.in @@ -0,0 +1,2 @@ +[main] +a: [u8; (3, 2)] = [0; (2, 2)]; \ No newline at end of file diff --git a/compiler/tests/array/input/six_zeros.in b/compiler/tests/array/input/six_zeros.in index b6f6bd4b65..9f9880807c 100644 --- a/compiler/tests/array/input/six_zeros.in +++ b/compiler/tests/array/input/six_zeros.in @@ -1,2 +1,2 @@ [main] -a: [u8; (3, 2)] = [[0; 3]; 2]; \ No newline at end of file +a: [u8; (3, 2)] = [0; (3, 2)]; \ No newline at end of file diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index e97e487047..76db81cfb8 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -18,6 +18,7 @@ use crate::{ assert_satisfied, expect_compiler_error, get_output, + integers::{expect_computation_error, expect_parsing_error}, parse_program, parse_program_with_input, EdwardsTestCompiler, @@ -101,6 +102,24 @@ fn test_initializer_fail() { assert!(syntax_error); } +#[test] +fn test_initializer_input() { + let program_bytes = include_bytes!("initializer_input.leo"); + let input_bytes = include_bytes!("input/six_zeros.in"); + let program = parse_program_with_input(program_bytes, input_bytes).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_initializer_input_fail() { + let program_bytes = include_bytes!("initializer_input.leo"); + let input_bytes = include_bytes!("input/initializer_fail.in"); + let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err(); + + assert!(syntax_error); +} + #[test] fn test_spread() { let program_bytes = include_bytes!("spread.leo"); diff --git a/typed/src/input/input_value.rs b/typed/src/input/input_value.rs index 6f23861860..6f9ad83eee 100644 --- a/typed/src/input/input_value.rs +++ b/typed/src/input/input_value.rs @@ -142,7 +142,7 @@ impl InputValue { array_type: ArrayType, initializer: ArrayInitializerExpression, ) -> Result { - let mut array_dimensions = TypedExpression::get_input_array_dimensions(array_type.dimensions.clone()); + let array_dimensions = TypedExpression::get_input_array_dimensions(array_type.dimensions.clone()); let initializer_dimensions = TypedExpression::get_input_array_dimensions(initializer.dimensions.clone()); // Return an error if the array type does not equal the array expression From 84a874b0ce4e2a5ab66ab1beccc93c245d8669cf Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 2 Sep 2020 16:49:06 -0700 Subject: [PATCH 4/4] add tests for large array initializer --- compiler/tests/array/mod.rs | 18 +++++++++++++++++- compiler/tests/array/multi_initializer.leo | 7 +++++++ .../tests/array/multi_initializer_fail.leo | 3 +++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 compiler/tests/array/multi_initializer.leo create mode 100644 compiler/tests/array/multi_initializer_fail.leo diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index 76db81cfb8..3878ff6703 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -147,7 +147,7 @@ fn test_multi() { } #[test] -fn test_multi_initializer_fail() { +fn test_multi_fail() { let program_bytes = include_bytes!("multi_fail_initializer.leo"); let program = parse_program(program_bytes).unwrap(); @@ -161,3 +161,19 @@ fn test_multi_inline_fail() { expect_compiler_error(program); } + +#[test] +fn test_multi_initializer() { + let program_bytes = include_bytes!("multi_initializer.leo"); + let program = parse_program(program_bytes).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_multi_initializer_fail() { + let program_bytes = include_bytes!("multi_initializer_fail.leo"); + let program = parse_program(program_bytes).unwrap(); + + expect_compiler_error(program); +} diff --git a/compiler/tests/array/multi_initializer.leo b/compiler/tests/array/multi_initializer.leo new file mode 100644 index 0000000000..6133542ef0 --- /dev/null +++ b/compiler/tests/array/multi_initializer.leo @@ -0,0 +1,7 @@ +function main() { + const a: [u8; (2, 2, 2)] = [1u8; (2, 2, 2)]; + + const b: [u8; (2, 2, 2)] = [[[1u8; 2]; 2]; 2]; + + console.assert(a == b); +} \ No newline at end of file diff --git a/compiler/tests/array/multi_initializer_fail.leo b/compiler/tests/array/multi_initializer_fail.leo new file mode 100644 index 0000000000..0bd76acffa --- /dev/null +++ b/compiler/tests/array/multi_initializer_fail.leo @@ -0,0 +1,3 @@ +function main() { + let arr: [u8; (2, 2)] = [1u8; (2, 1)]; // incorrect dimensions +} \ No newline at end of file