Fixes array indices for both nested and tuple cases

This commit is contained in:
howardwu 2020-09-03 02:40:50 -07:00
parent 40ac13e317
commit 981d272fa6
21 changed files with 116 additions and 32 deletions

View File

@ -52,7 +52,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
};
expected_dimensions.push(number);
expected_type = Some(type_.inner_dimension(dimensions).clone());
expected_type = Some(type_.outer_dimension(dimensions).clone());
}
ref type_ => {
return Err(ExpressionError::unexpected_array(type_.to_string(), span));
@ -69,9 +69,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
match self.get(&array_name) {
Some(value) => match value {
ConstrainedValue::Array(array) => result.extend(array.clone()),
value => {
return Err(ExpressionError::invalid_spread(value.to_string(), span));
}
value => return Err(ExpressionError::invalid_spread(value.to_string(), span)),
},
None => return Err(ExpressionError::undefined_array(identifier.name, span)),
}

View File

@ -112,7 +112,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
let array_type = types[0].to_type(span.clone())?;
let count = types.len();
// nested array type
// Nested array type
if let Type::Array(inner_type, inner_dimensions) = &array_type {
let mut dimensions = inner_dimensions.clone();
dimensions.push(count);

View File

@ -1,2 +1,2 @@
[main]
a: [u8; (3, 2)] = [0; (2, 2)];
a: [u8; (3, 2)] = [0u8; (2, 2)];

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [[0u8; 2]; 3];

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [[0u8; 3]; 2)];

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [0u8; (3, 2)];

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [0u8; (2, 3)];

View File

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

View File

@ -0,0 +1,3 @@
function main(a: [u8; (3, 2)]) {
console.assert(a == [[0u8; 2]; 3)]); // This should be written the right way as this test is for the input file.
}

View File

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

View File

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

View File

@ -120,37 +120,41 @@ fn test_initializer_input_fail() {
}
#[test]
fn test_spread() {
let program_bytes = include_bytes!("spread.leo");
let input_bytes = include_bytes!("input/three_ones.in");
#[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");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_slice() {
let program_bytes = include_bytes!("slice.leo");
let input_bytes = include_bytes!("input/three_ones.in");
fn test_input_nested_3x2_fail() {
let program_bytes = include_bytes!("input_nested_3x2_fail.leo");
let input_bytes = include_bytes!("input/input_nested_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_tuple_3x2() {
let program_bytes = include_bytes!("input_tuple_3x2.leo");
let input_bytes = include_bytes!("input/input_tuple_3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_multi() {
let program_bytes = include_bytes!("multi.leo");
let program = parse_program(program_bytes).unwrap();
fn test_input_tuple_3x2_fail() {
let program_bytes = include_bytes!("input_tuple_3x2_fail.leo");
let input_bytes = include_bytes!("input/input_tuple_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert_satisfied(program);
}
#[test]
fn test_multi_fail() {
let program_bytes = include_bytes!("multi_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
assert!(syntax_error);
}
#[test]
@ -184,3 +188,53 @@ fn test_multi_initializer_fail() {
expect_compiler_error(program);
}
#[test]
fn test_nested_3x2_value() {
let program_bytes = include_bytes!("nested_3x2_value.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_nested_3x2_value_fail() {
let program_bytes = include_bytes!("nested_3x2_value_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_tuple_3x2_value() {
let program_bytes = include_bytes!("tuple_3x2_value.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_tuple_3x2_value_fail() {
let program_bytes = include_bytes!("tuple_3x2_value_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_spread() {
let program_bytes = include_bytes!("spread.leo");
let input_bytes = include_bytes!("input/three_ones.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_slice() {
let program_bytes = include_bytes!("slice.leo");
let input_bytes = include_bytes!("input/three_ones.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}

View File

@ -0,0 +1,8 @@
// Multidimensional array syntax in leo
function main() {
const a = [[0u32, 0u32], [0u32, 0u32], [0u32, 0u32]]; // inline
const b: [u32; (3, 2)] = [0; (3, 2)]; // initializer
console.assert(a == b);
}

View File

@ -0,0 +1,4 @@
// Multidimensional array syntax in leo
function main() {
const a: [u32; (3, 2)] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
}

View File

@ -14,7 +14,7 @@
// 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 pest::{Position, Span as AstSpan};
use pest::Span as AstSpan;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]

View File

@ -501,7 +501,7 @@ impl<'ast> From<ArrayInitializerExpression<'ast>> for Expression {
// 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() {
for (i, dimension) in dimensions.into_iter().rev().enumerate() {
if i == 0 {
elements = vec![expression.clone(); dimension];
} else {

View File

@ -108,7 +108,7 @@ impl InputValue {
) -> Result<Self, InputParserError> {
let mut 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
// 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();
@ -118,13 +118,13 @@ impl InputValue {
};
let inner_array_type = if array_dimensions.len() == 0 {
// this is a single array
// 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
// This is a multi-dimensional array
Type::Array(array_type)
};

View File

@ -64,7 +64,7 @@ impl Type {
if dimensions.len() > 1 {
let mut next = vec![];
next.extend_from_slice(&dimensions[..dimensions.len() - 1]);
next.extend_from_slice(&dimensions[1..]);
return Type::Array(Box::new(type_), next);
}
@ -77,7 +77,7 @@ impl Type {
if dimensions.len() > 1 {
let mut next = vec![];
next.extend_from_slice(&dimensions[1..dimensions.len()]);
next.extend_from_slice(&dimensions[..dimensions.len() - 1]);
return Type::Array(Box::new(type_), next);
}