Merge pull request #347 from AleoHQ/feature/array-type

Feature/array type
This commit is contained in:
Howard Wu 2020-09-07 15:47:23 -07:00 committed by GitHub
commit eff7d9d599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 535 additions and 167 deletions

View File

@ -79,7 +79,7 @@ cd leo
$ cargo build --release $ cargo build --release
``` ```
This will generate an executable under the `./target/release` directory. To run snarkOS, run the following command: This will generate an executable under the `./target/release` directory. To run Leo, run the following command:
```bash ```bash
./target/release/leo ./target/release/leo
``` ```

View File

@ -197,15 +197,7 @@ type_self = { "Self" }
type_circuit = { identifier } type_circuit = { identifier }
// Declared in types/array_type.rs // Declared in types/array_type.rs
type_array = { "[" ~ array_element ~ ";" ~ array_dimensions ~ "]" } type_array = { "[" ~ type_ ~ ";" ~ array_dimensions ~ "]" }
// Declared in types/array_element.rs
array_element = {
type_self
| type_tuple
| type_data
| type_circuit
}
// Declared in types/array_dimensions.rs // Declared in types/array_dimensions.rs
array_dimensions = { array_dimensions = {

View File

@ -1,29 +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;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::array_element))]
pub enum ArrayElement<'ast> {
Basic(DataType),
Tuple(TupleType<'ast>),
Circuit(CircuitType<'ast>),
SelfType(SelfType<'ast>),
}

View File

@ -16,7 +16,7 @@
use crate::{ use crate::{
ast::Rule, ast::Rule,
types::{ArrayDimensions, ArrayElement}, types::{ArrayDimensions, Type},
SpanDef, SpanDef,
}; };
@ -27,7 +27,7 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::type_array))] #[pest_ast(rule(Rule::type_array))]
pub struct ArrayType<'ast> { pub struct ArrayType<'ast> {
pub type_: ArrayElement<'ast>, pub type_: Box<Type<'ast>>,
pub dimensions: ArrayDimensions<'ast>, pub dimensions: ArrayDimensions<'ast>,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]

View File

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

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [[u8; 2]; 3] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [[[u8; 2]; 3]; 4] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [[u8; 2]; 3] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [[[u8; 2]; 3]; 4] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (4, 3, 2)] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (3, 2)] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -0,0 +1,2 @@
[main]
a: [u8; (4, 3, 2)] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)

View File

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

View File

@ -58,14 +58,6 @@ fn test_registers() {
// Expressions // Expressions
#[test]
fn test_type_fail() {
let program_bytes = include_bytes!("type_fail.leo");
let syntax_error = parse_program(program_bytes).is_err();
assert!(syntax_error);
}
#[test] #[test]
fn test_inline() { fn test_inline() {
let program_bytes = include_bytes!("inline.leo"); let program_bytes = include_bytes!("inline.leo");
@ -120,8 +112,6 @@ fn test_initializer_input_fail() {
} }
#[test] #[test]
#[ignore]
// TODO (howardwu): Add support for this syntax.
fn test_input_nested_3x2() { fn test_input_nested_3x2() {
let program_bytes = include_bytes!("input_nested_3x2.leo"); let program_bytes = include_bytes!("input_nested_3x2.leo");
let input_bytes = include_bytes!("input/input_nested_3x2.in"); let input_bytes = include_bytes!("input/input_nested_3x2.in");
@ -238,3 +228,289 @@ fn test_slice() {
assert_satisfied(program); assert_satisfied(program);
} }
// Array type tests
#[test]
fn test_type_fail() {
let program_bytes = include_bytes!("type_fail.leo");
let syntax_error = parse_program(program_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_type_nested_value_nested_3x2() {
let program_bytes = include_bytes!("type_nested_value_nested_3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_nested_value_nested_3x2_fail() {
let program_bytes = include_bytes!("type_nested_value_nested_3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_nested_value_nested_4x3x2() {
let program_bytes = include_bytes!("type_nested_value_nested_4x3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_nested_value_nested_4x3x2_fail() {
let program_bytes = include_bytes!("type_nested_value_nested_4x3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_nested_value_tuple_3x2() {
let program_bytes = include_bytes!("type_nested_value_tuple_3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_nested_value_tuple_3x2_fail() {
let program_bytes = include_bytes!("type_nested_value_tuple_3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_nested_value_tuple_4x3x2() {
let program_bytes = include_bytes!("type_nested_value_tuple_4x3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_nested_value_tuple_4x3x2_fail() {
let program_bytes = include_bytes!("type_nested_value_tuple_4x3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_tuple_value_nested_3x2() {
let program_bytes = include_bytes!("type_tuple_value_nested_3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_tuple_value_nested_3x2_fail() {
let program_bytes = include_bytes!("type_tuple_value_nested_3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_tuple_value_nested_4x3x2() {
let program_bytes = include_bytes!("type_tuple_value_nested_4x3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_tuple_value_nested_4x3x2_fail() {
let program_bytes = include_bytes!("type_tuple_value_nested_4x3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_tuple_value_tuple_3x2() {
let program_bytes = include_bytes!("type_tuple_value_tuple_3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_tuple_value_tuple_3x2_fail() {
let program_bytes = include_bytes!("type_tuple_value_tuple_3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
#[test]
fn test_type_tuple_value_tuple_4x3x2() {
let program_bytes = include_bytes!("type_tuple_value_tuple_4x3x2.leo");
let program = parse_program(program_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_type_tuple_value_tuple_4x3x2_fail() {
let program_bytes = include_bytes!("type_tuple_value_tuple_4x3x2_fail.leo");
let program = parse_program(program_bytes).unwrap();
expect_compiler_error(program);
}
// Tests for nested multi-dimensional arrays as input to the program
#[test]
fn test_input_type_nested_value_nested_3x2() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_nested_3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_nested_value_nested_3x2_fail() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_nested_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_nested_value_nested_4x3x2() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_nested_4x3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_nested_value_nested_4x3x2_fail() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_nested_4x3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_nested_value_tuple_3x2() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_tuple_3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_nested_value_tuple_3x2_fail() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_tuple_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_nested_value_tuple_4x3x2() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_tuple_4x3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program)
}
#[test]
fn test_input_type_nested_value_tuple_4x3x2_fail() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_nested_value_tuple_4x3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
// Tests for multi-dimensional arrays using tuple syntax as input to the program
#[test]
fn test_input_type_tuple_value_nested_3x2() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_nested_3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_tuple_value_nested_3x2_fail() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_nested_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_tuple_value_nested_4x3x2() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_nested_4x3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_tuple_value_nested_4x3x2_fail() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_nested_4x3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_tuple_value_tuple_3x2() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_tuple_3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_tuple_value_tuple_3x2_fail() {
let program_bytes = include_bytes!("type_input_3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_tuple_3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}
#[test]
fn test_input_type_tuple_value_tuple_4x3x2() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_tuple_4x3x2.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_type_tuple_value_tuple_4x3x2_fail() {
let program_bytes = include_bytes!("type_input_4x3x2.leo");
let input_bytes = include_bytes!("input/type_tuple_value_tuple_4x3x2_fail.in");
let syntax_error = parse_program_with_input(program_bytes, input_bytes).is_err();
assert!(syntax_error);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
function main() {
const b: [[u8; 2]; 3] = [[0; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

@ -0,0 +1,10 @@
function main() {
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
const b: [[[u8; 2]; 3]; 4] = [[[0; 2]; 3]; 4]; // initializer
console.assert(a == b);
}

View File

@ -0,0 +1,3 @@
function main() {
const b: [[[u8; 2]; 3]; 4] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

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

View File

@ -0,0 +1,3 @@
function main() {
const b: [[u8; 2]; 3] = [0; (2, 3)]; // initializer (incorrectly reversed ordering)
}

View File

@ -0,0 +1,10 @@
function main() {
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
const b: [[[u8; 2]; 3]; 4] = [0; (4, 3, 2)]; // initializer
console.assert(a == b);
}

View File

@ -0,0 +1,3 @@
function main() {
const b: [[[u8; 2]; 3]; 4] = [0; (2, 3, 4)]; // initializer (incorrectly reversed ordering)
}

View File

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

View File

@ -0,0 +1,3 @@
function main() {
const b: [u8; (2, 3)] = [[0; 2]; 3]; // initializer (incorrectly reversed ordering)
}

View File

@ -0,0 +1,10 @@
function main() {
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
const b: [u8; (4, 3, 2)] = [[[0; 2]; 3]; 4]; // initializer
console.assert(a == b);
}

View File

@ -0,0 +1,3 @@
function main() {
const b: [u8; (4, 3, 2)] = [[[0; 4]; 3]; 2]; // initializer (incorrectly reversed ordering)
}

View File

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

View File

@ -0,0 +1,3 @@
function main() {
const b: [u8; (2, 3)] = [0; (3, 2)]; // initializer (incorrectly reversed ordering)
}

View File

@ -0,0 +1,10 @@
function main() {
const a = [[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]],
[[0u8, 0u8], [0u8, 0u8], [0u8, 0u8]]]; // inline
const b: [u8; (4, 3, 2)] = [0; (4, 3, 2)]; // initializer
console.assert(a == b);
}

View File

@ -0,0 +1,3 @@
function main() {
const b: [u8; (4, 3, 2)] = [0; (2, 3, 4)]; // initializer (incorrectly reversed order)
}

View File

@ -18,7 +18,7 @@ serial_number_nonce: [u8; 32] = [0u8; 32];
commitment_randomness: [u8; 32] = [0u8; 32]; commitment_randomness: [u8; 32] = [0u8; 32];
[state_leaf] [state_leaf]
path: [u8; (32, 2)] = [ [0u8; 32], [0u8; 32] ]; path: [u8; 128] = [0u8; 128];
memo: [u8; 32] = [0u8; 32]; memo: [u8; 32] = [0u8; 32];
network_id: u8 = 0; network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0u8; 32]; 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]; commitment_randomness: [u8; 32] = [0u8; 32];
[state_leaf] [state_leaf]
path: [u8; (32, 2)] = [ [0u8; 32], [0u8; 32] ]; path: [u8; 128] = [0u8; 128];
memo: [u8; 32] = [0u8; 32]; memo: [u8; 32] = [0u8; 32];
network_id: u8 = 0; network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0u8; 32]; 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 } type_data = { type_field | type_group | type_boolean | type_address | type_integer }
// Declared in types/array_type.rs // Declared in types/array_type.rs
type_array = { "[" ~ array_element ~ ";" ~ array_dimensions ~ "]" } type_array = { "[" ~ type_ ~ ";" ~ array_dimensions ~ "]" }
// Declared in types/array_element.rs
array_element = {
type_tuple
| type_data
}
// Declared in types/array_dimensions.rs // Declared in types/array_dimensions.rs
array_dimensions = { array_dimensions = {

View File

@ -53,12 +53,19 @@ impl<'ast> ArrayDimensions<'ast> {
let old_dimension = multiple.numbers.clone(); let old_dimension = multiple.numbers.clone();
ArrayDimensions::Multiple(Multiple { ArrayDimensions::Multiple(Multiple {
numbers: old_dimension[..old_dimension.len() - 1].to_vec(), numbers: old_dimension[1..].to_vec(),
span: multiple.span.clone(), span: multiple.span.clone(),
}) })
} }
} }
} }
pub fn is_empty(&self) -> bool {
match self {
ArrayDimensions::Single(_) => false,
ArrayDimensions::Multiple(multiple) => multiple.numbers.is_empty(),
}
}
} }
impl<'ast> std::fmt::Display for ArrayDimensions<'ast> { impl<'ast> std::fmt::Display for ArrayDimensions<'ast> {

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

View File

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

View File

@ -71,27 +71,27 @@ impl StateFile {
[state] [state]
leaf_index: u32 = 0; leaf_index: u32 = 0;
root: [u8; 32] = [0u8; 32]; root: [u8; 32] = [0; 32];
[[private]] [[private]]
[record] [record]
serial_number: [u8; 64] = [0u8; 64]; serial_number: [u8; 64] = [0; 64];
commitment: [u8; 32] = [0u8; 32]; commitment: [u8; 32] = [0; 32];
owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9; owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9;
is_dummy: bool = false; is_dummy: bool = false;
value: u64 = 5; value: u64 = 0;
payload: [u8; 32] = [0u8; 32]; payload: [u8; 32] = [0; 32];
birth_program_id: [u8; 48] = [0u8; 48]; birth_program_id: [u8; 48] = [0; 48];
death_program_id: [u8; 48] = [0u8; 48]; death_program_id: [u8; 48] = [0; 48];
serial_number_nonce: [u8; 32] = [0u8; 32]; serial_number_nonce: [u8; 32] = [0; 32];
commitment_randomness: [u8; 32] = [0u8; 32]; commitment_randomness: [u8; 32] = [0; 32];
[state_leaf] [state_leaf]
path: [u8; 128] = [0u8; 128]; path: [u8; 128] = [0; 128];
memo: [u8; 32] = [0u8; 32]; memo: [u8; 32] = [0; 32];
network_id: u8 = 0; network_id: u8 = 0;
leaf_randomness: [u8; 32] = [0u8; 32]; leaf_randomness: [u8; 32] = [0; 32];
"#, "#,
self.package_name self.package_name
) )

View File

@ -18,7 +18,7 @@ use crate::{Expression as TypedExpression, GroupValue};
use leo_input::{ use leo_input::{
errors::InputParserError, errors::InputParserError,
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression, TupleExpression}, 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}, values::{Address, AddressValue, BooleanValue, FieldValue, GroupValue as InputGroupValue, NumberValue, Value},
}; };
@ -106,46 +106,56 @@ impl InputValue {
mut array_type: ArrayType, mut array_type: ArrayType,
inline: ArrayInlineExpression, inline: ArrayInlineExpression,
) -> Result<Self, InputParserError> { ) -> 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. // Return an error if the outer array dimension does not equal the number of array elements.
if let Some(outer_dimension) = array_dimensions.pop() { if array_dimensions[0] != inline.expressions.len() {
return Err(InputParserError::array_inline_length(array_dimensions[0], inline));
}
array_type.dimensions = array_type.dimensions.next_dimension(); array_type.dimensions = array_type.dimensions.next_dimension();
if outer_dimension != inline.expressions.len() { let inner_array_type = if array_dimensions.len() == 1 {
return Err(InputParserError::array_inline_length(outer_dimension, inline));
}
};
let inner_array_type = if array_dimensions.len() == 0 {
// This is a single array // This is a single array
match array_type.type_ { *array_type.type_
ArrayElement::Basic(basic) => Type::Basic(basic),
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
}
} else { } else {
// This is a multi-dimensional array // This is a multi-dimensional array
Type::Array(array_type) Type::Array(array_type)
}; };
let mut values = vec![]; let mut elements = vec![];
for expression in inline.expressions.into_iter() { 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( pub(crate) fn from_array_initializer(
array_type: ArrayType, array_type: ArrayType,
initializer: ArrayInitializerExpression, initializer: ArrayInitializerExpression,
) -> Result<Self, InputParserError> { ) -> Result<Self, InputParserError> {
let array_dimensions = TypedExpression::get_input_array_dimensions(array_type.dimensions.clone());
let initializer_dimensions = TypedExpression::get_input_array_dimensions(initializer.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 initializer_dimensions.len() > 1 {
// 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, initializer_dimensions)
}
}
pub(crate) fn from_array_initializer_tuple(
array_type: ArrayType,
initializer: ArrayInitializerExpression,
initializer_dimensions: Vec<usize>,
) -> Result<Self, InputParserError> {
let (array_dimensions, array_element_type) = fetch_nested_array_type_dimensions(array_type.clone(), vec![]);
// Return an error if the dimensions of the array are incorrect.
if array_dimensions.ne(&initializer_dimensions) { if array_dimensions.ne(&initializer_dimensions) {
return Err(InputParserError::array_init_length( return Err(InputParserError::array_init_length(
array_dimensions, array_dimensions,
@ -154,14 +164,10 @@ impl InputValue {
)); ));
} }
let type_ = match array_type.type_ { let value = InputValue::from_expression(array_element_type, *initializer.expression.clone())?;
ArrayElement::Basic(basic) => Type::Basic(basic),
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
};
let value = InputValue::from_expression(type_, *initializer.expression.clone())?;
let mut elements = vec![]; let mut elements = vec![];
// Build the elements of the array using the `vec!` macro
for (i, dimension) in initializer_dimensions.into_iter().enumerate() { for (i, dimension) in initializer_dimensions.into_iter().enumerate() {
if i == 0 { if i == 0 {
elements = vec![value.clone(); dimension]; elements = vec![value.clone(); dimension];
@ -175,6 +181,42 @@ impl InputValue {
Ok(InputValue::Array(elements)) Ok(InputValue::Array(elements))
} }
pub(crate) fn from_array_initializer_nested(
mut array_type: ArrayType,
initializer: ArrayInitializerExpression,
initializer_dimensions: Vec<usize>,
) -> Result<Self, InputParserError> {
let array_dimensions = TypedExpression::get_input_array_dimensions(array_type.dimensions.clone());
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> { pub(crate) fn from_tuple(tuple_type: TupleType, tuple: TupleExpression) -> Result<Self, InputParserError> {
let num_types = tuple_type.types_.len(); let num_types = tuple_type.types_.len();
let num_values = tuple.expressions.len(); let num_values = tuple.expressions.len();
@ -198,6 +240,17 @@ impl InputValue {
} }
} }
// Recursively fetch all dimensions from the array type
fn fetch_nested_array_type_dimensions(array_type: ArrayType, mut array_dimensions: Vec<usize>) -> (Vec<usize>, Type) {
let mut current_dimension = TypedExpression::get_input_array_dimensions(array_type.dimensions);
array_dimensions.append(&mut current_dimension);
match *array_type.type_ {
Type::Array(next_array_type) => fetch_nested_array_type_dimensions(next_array_type, array_dimensions),
type_ => (array_dimensions, type_),
}
}
impl fmt::Display for InputValue { impl fmt::Display for InputValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {

View File

@ -15,9 +15,8 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Expression, Identifier, IntegerType}; use crate::{Expression, Identifier, IntegerType};
use leo_ast::types::{ArrayElement, ArrayType, CircuitType, DataType, TupleType, Type as AstType}; use leo_ast::types::{ArrayType, CircuitType, DataType, TupleType, Type as AstType};
use leo_input::types::{ use leo_input::types::{
ArrayElement as InputArrayElement,
ArrayType as InputArrayType, ArrayType as InputArrayType,
DataType as InputDataType, DataType as InputDataType,
TupleType as InputTupleType, TupleType as InputTupleType,
@ -102,24 +101,13 @@ impl From<DataType> for Type {
impl<'ast> From<ArrayType<'ast>> for Type { impl<'ast> From<ArrayType<'ast>> for Type {
fn from(array_type: ArrayType<'ast>) -> Self { fn from(array_type: ArrayType<'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_array_dimensions(array_type.dimensions); let dimensions = Expression::get_array_dimensions(array_type.dimensions);
Type::Array(element_type, dimensions) Type::Array(element_type, dimensions)
} }
} }
impl<'ast> From<ArrayElement<'ast>> for Type {
fn from(element: ArrayElement<'ast>) -> Self {
match element {
ArrayElement::Basic(type_) => Type::from(type_),
ArrayElement::Tuple(type_) => Type::from(type_),
ArrayElement::Circuit(type_) => Type::from(type_),
ArrayElement::SelfType(_type) => Type::SelfType,
}
}
}
impl<'ast> From<TupleType<'ast>> for Type { impl<'ast> From<TupleType<'ast>> for Type {
fn from(tuple_type: TupleType<'ast>) -> Self { fn from(tuple_type: TupleType<'ast>) -> Self {
let types = tuple_type.types.into_iter().map(|type_| Type::from(type_)).collect(); let types = tuple_type.types.into_iter().map(|type_| Type::from(type_)).collect();
@ -162,22 +150,13 @@ impl From<InputDataType> for Type {
impl<'ast> From<InputArrayType<'ast>> for Type { impl<'ast> From<InputArrayType<'ast>> for Type {
fn from(array_type: InputArrayType<'ast>) -> Self { 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); let dimensions = Expression::get_input_array_dimensions(array_type.dimensions);
Type::Array(element_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 { impl<'ast> From<InputTupleType<'ast>> for Type {
fn from(tuple_type: InputTupleType<'ast>) -> Self { fn from(tuple_type: InputTupleType<'ast>) -> Self {
let types = tuple_type.types_.into_iter().map(|type_| Type::from(type_)).collect(); let types = tuple_type.types_.into_iter().map(|type_| Type::from(type_)).collect();