support nested array type in leo inputs

This commit is contained in:
collin 2020-09-03 11:24:23 -07:00
parent de3564b98d
commit b6dc77e112
12 changed files with 83 additions and 95 deletions

View File

@ -1,3 +1,3 @@
function main(a: [u8; (3, 2)]) {
console.assert(a == [[0u8; 2]; 3)]);
console.assert(a == [[0u8; 2]; 3]);
}

View File

@ -74,6 +74,15 @@ fn test_type_tuple() {
assert_satisfied(program);
}
// #[test]
// fn test_type_tuple_input() {
// let program_bytes = include_bytes!("type_tuple_input.leo");
// let input_bytes = include_bytes!("input/input_nested_3x2.in");
// let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
//
// assert_satisfied(program);
// }
#[test]
fn test_type_nested() {
let program_bytes = include_bytes!("type_nested.leo");
@ -136,8 +145,6 @@ fn test_initializer_input_fail() {
}
#[test]
#[ignore]
// TODO (howardwu): Add support for this syntax.
fn test_input_nested_3x2() {
let program_bytes = include_bytes!("input_nested_3x2.leo");
let input_bytes = include_bytes!("input/input_nested_3x2.in");

View File

@ -0,0 +1,5 @@
function main(a: [u8; (2, 3)) {
let b: [u8; (2, 3)] = [[0; 3]; 2];
console.assert(a == b);
}

View File

@ -18,7 +18,7 @@ serial_number_nonce: [u8; 32] = [0u8; 32];
commitment_randomness: [u8; 32] = [0u8; 32];
[state_leaf]
path: [u8; (32, 2)] = [ [0u8; 32], [0u8; 32] ];
path: [u8; 128] = [0u8; 128];
memo: [u8; 32] = [0u8; 32];
network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0u8; 32];

View File

@ -18,7 +18,7 @@ serial_number_nonce: [u8; 32] = [0u8; 32];
commitment_randomness: [u8; 32] = [0u8; 32];
[state_leaf]
path: [u8; (32, 2)] = [ [0u8; 32], [0u8; 32] ];
path: [u8; 128] = [0u8; 128];
memo: [u8; 32] = [0u8; 32];
network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0u8; 32];

View File

@ -89,13 +89,7 @@ type_address = { "address" }
type_data = { type_field | type_group | type_boolean | type_address | type_integer }
// Declared in types/array_type.rs
type_array = { "[" ~ array_element ~ ";" ~ array_dimensions ~ "]" }
// Declared in types/array_element.rs
array_element = {
type_tuple
| type_data
}
type_array = { "[" ~ type_ ~ ";" ~ array_dimensions ~ "]" }
// Declared in types/array_dimensions.rs
array_dimensions = {

View File

@ -53,7 +53,7 @@ impl<'ast> ArrayDimensions<'ast> {
let old_dimension = multiple.numbers.clone();
ArrayDimensions::Multiple(Multiple {
numbers: old_dimension[..old_dimension.len() - 1].to_vec(),
numbers: old_dimension[1..].to_vec(),
span: multiple.span.clone(),
})
}

View File

@ -1,35 +0,0 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ast::Rule, types::*};
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::array_element))]
pub enum ArrayElement<'ast> {
Basic(DataType),
Tuple(TupleType<'ast>),
}
impl<'ast> std::fmt::Display for ArrayElement<'ast> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
ArrayElement::Basic(ref basic) => write!(f, "{}", basic),
ArrayElement::Tuple(ref tuple) => write!(f, "{}", tuple),
}
}
}

View File

@ -16,7 +16,7 @@
use crate::{
ast::Rule,
types::{ArrayDimensions, ArrayElement},
types::{ArrayDimensions, Type},
};
use pest::Span;
@ -25,7 +25,7 @@ use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_array))]
pub struct ArrayType<'ast> {
pub type_: ArrayElement<'ast>,
pub type_: Box<Type<'ast>>,
pub dimensions: ArrayDimensions<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,

View File

@ -20,9 +20,6 @@ pub use address_type::*;
pub mod array_dimensions;
pub use array_dimensions::*;
pub mod array_element;
pub use array_element::*;
pub mod array_type;
pub use array_type::*;

View File

@ -18,7 +18,7 @@ use crate::{Expression as TypedExpression, GroupValue};
use leo_input::{
errors::InputParserError,
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression, TupleExpression},
types::{ArrayElement, ArrayType, DataType, IntegerType, TupleType, Type},
types::{ArrayType, DataType, IntegerType, TupleType, Type},
values::{Address, AddressValue, BooleanValue, FieldValue, GroupValue as InputGroupValue, NumberValue, Value},
};
@ -106,36 +106,31 @@ impl InputValue {
mut array_type: ArrayType,
inline: ArrayInlineExpression,
) -> Result<Self, InputParserError> {
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());
// 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 array_dimensions[0] != inline.expressions.len() {
return Err(InputParserError::array_inline_length(array_dimensions[0], inline));
}
if outer_dimension != inline.expressions.len() {
return Err(InputParserError::array_inline_length(outer_dimension, inline));
}
};
array_type.dimensions = array_type.dimensions.next_dimension();
let inner_array_type = if array_dimensions.len() == 0 {
let inner_array_type = if array_dimensions.len() == 1 {
// This is a single array
match array_type.type_ {
ArrayElement::Basic(basic) => Type::Basic(basic),
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
}
*array_type.type_
} else {
// This is a multi-dimensional array
Type::Array(array_type)
};
let mut values = vec![];
let mut elements = vec![];
for expression in inline.expressions.into_iter() {
let value = InputValue::from_expression(inner_array_type.clone(), expression)?;
let element = InputValue::from_expression(inner_array_type.clone(), expression)?;
values.push(value)
elements.push(element)
}
Ok(InputValue::Array(values))
Ok(InputValue::Array(elements))
}
pub(crate) fn from_array_initializer(
@ -145,24 +140,24 @@ impl InputValue {
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
if array_dimensions.ne(&initializer_dimensions) {
return Err(InputParserError::array_init_length(
array_dimensions,
initializer_dimensions,
initializer.span,
));
if array_dimensions.eq(&initializer_dimensions) {
// The expression is an array initializer with tuple syntax
Self::from_array_initializer_tuple(array_type, initializer, initializer_dimensions)
} else {
// The expression is an array initializer with nested syntax
Self::from_array_initializer_nested(array_type, initializer, array_dimensions, initializer_dimensions)
}
}
let type_ = match array_type.type_ {
ArrayElement::Basic(basic) => Type::Basic(basic),
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
};
let value = InputValue::from_expression(type_, *initializer.expression.clone())?;
pub(crate) fn from_array_initializer_tuple(
array_type: ArrayType,
initializer: ArrayInitializerExpression,
dimensions: Vec<usize>,
) -> Result<Self, InputParserError> {
let value = InputValue::from_expression(*array_type.type_, *initializer.expression.clone())?;
let mut elements = vec![];
for (i, dimension) in initializer_dimensions.into_iter().enumerate() {
for (i, dimension) in dimensions.into_iter().enumerate() {
if i == 0 {
elements = vec![value.clone(); dimension];
} else {
@ -175,6 +170,41 @@ impl InputValue {
Ok(InputValue::Array(elements))
}
pub(crate) fn from_array_initializer_nested(
mut array_type: ArrayType,
initializer: ArrayInitializerExpression,
array_dimensions: Vec<usize>,
initializer_dimensions: Vec<usize>,
) -> Result<Self, InputParserError> {
let current_array_dimension = array_dimensions[0];
let current_initializer_dimension = initializer_dimensions[0];
// Return an error if the outer array dimension does not equal the number of array elements.
if current_array_dimension.ne(&current_initializer_dimension) {
return Err(InputParserError::array_init_length(
array_dimensions,
initializer_dimensions,
initializer.span,
));
}
array_type.dimensions = array_type.dimensions.next_dimension();
let inner_array_type = if array_dimensions.len() == 1 {
// This is the innermost dimension
*array_type.type_
} else {
// This is an outer dimension of a multi-dimensional array
Type::Array(array_type)
};
// Evaluate the array initializer
let element = InputValue::from_expression(inner_array_type.clone(), *initializer.expression)?;
let elements = vec![element; current_initializer_dimension];
Ok(InputValue::Array(elements))
}
pub(crate) fn from_tuple(tuple_type: TupleType, tuple: TupleExpression) -> Result<Self, InputParserError> {
let num_types = tuple_type.types_.len();
let num_values = tuple.expressions.len();

View File

@ -17,7 +17,6 @@
use crate::{Expression, Identifier, IntegerType};
use leo_ast::types::{ArrayType, CircuitType, DataType, TupleType, Type as AstType};
use leo_input::types::{
ArrayElement as InputArrayElement,
ArrayType as InputArrayType,
DataType as InputDataType,
TupleType as InputTupleType,
@ -151,22 +150,13 @@ impl From<InputDataType> for Type {
impl<'ast> From<InputArrayType<'ast>> for Type {
fn from(array_type: InputArrayType<'ast>) -> Self {
let element_type = Box::new(Type::from(array_type.type_));
let element_type = Box::new(Type::from(*array_type.type_));
let dimensions = Expression::get_input_array_dimensions(array_type.dimensions);
Type::Array(element_type, dimensions)
}
}
impl<'ast> From<InputArrayElement<'ast>> for Type {
fn from(element: InputArrayElement<'ast>) -> Self {
match element {
InputArrayElement::Basic(type_) => Type::from(type_),
InputArrayElement::Tuple(type_) => Type::from(type_),
}
}
}
impl<'ast> From<InputTupleType<'ast>> for Type {
fn from(tuple_type: InputTupleType<'ast>) -> Self {
let types = tuple_type.types_.into_iter().map(|type_| Type::from(type_)).collect();