mirror of
https://github.com/AleoHQ/leo.git
synced 2025-01-04 07:59:02 +03:00
Merge branch 'master' of github.com:AleoHQ/leo into feature/mutable-circuit-variables
This commit is contained in:
commit
c84227f69a
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{ast::Rule, expressions::Expression, values::PositiveNumber, SpanDef};
|
use crate::{ast::Rule, expressions::Expression, types::ArrayDimensions, SpanDef};
|
||||||
|
|
||||||
use pest::Span;
|
use pest::Span;
|
||||||
use pest_ast::FromPest;
|
use pest_ast::FromPest;
|
||||||
@ -24,7 +24,7 @@ use serde::Serialize;
|
|||||||
#[pest_ast(rule(Rule::expression_array_initializer))]
|
#[pest_ast(rule(Rule::expression_array_initializer))]
|
||||||
pub struct ArrayInitializerExpression<'ast> {
|
pub struct ArrayInitializerExpression<'ast> {
|
||||||
pub expression: Box<Expression<'ast>>,
|
pub expression: Box<Expression<'ast>>,
|
||||||
pub count: PositiveNumber<'ast>,
|
pub dimensions: ArrayDimensions<'ast>,
|
||||||
#[pest_ast(outer())]
|
#[pest_ast(outer())]
|
||||||
#[serde(with = "SpanDef")]
|
#[serde(with = "SpanDef")]
|
||||||
pub span: Span<'ast>,
|
pub span: Span<'ast>,
|
||||||
|
@ -101,7 +101,7 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
|||||||
write!(f, "")
|
write!(f, "")
|
||||||
}
|
}
|
||||||
Expression::ArrayInitializer(ref expression) => {
|
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::CircuitInline(ref expression) => write!(f, "{}", expression.span.as_str()),
|
||||||
Expression::Postfix(ref expression) => write!(f, "{}", expression.span.as_str()),
|
Expression::Postfix(ref expression) => write!(f, "{}", expression.span.as_str()),
|
||||||
|
@ -346,7 +346,7 @@ expression = { expression_term ~ (operation_binary ~ expression_term)* }
|
|||||||
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
|
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
|
||||||
|
|
||||||
// Declared in expressions/array_initializer_expression.rs
|
// 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
|
// Declared in expressions/array_inline_expression.rs
|
||||||
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
|
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
|
||||||
|
@ -44,3 +44,12 @@ pub struct Multiple<'ast> {
|
|||||||
#[serde(with = "SpanDef")]
|
#[serde(with = "SpanDef")]
|
||||||
pub span: Span<'ast>,
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3
compiler/tests/array/initializer_input.leo
Normal file
3
compiler/tests/array/initializer_input.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: [u8; (3, 2)]) {
|
||||||
|
console.assert(a == [0u8; (3, 2)]);
|
||||||
|
}
|
2
compiler/tests/array/input/initializer_fail.in
Normal file
2
compiler/tests/array/input/initializer_fail.in
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[main]
|
||||||
|
a: [u8; (3, 2)] = [0; (2, 2)];
|
@ -1,2 +1,2 @@
|
|||||||
[main]
|
[main]
|
||||||
a: [u8; (3, 2)] = [[0; 3]; 2];
|
a: [u8; (3, 2)] = [0; (3, 2)];
|
@ -18,6 +18,7 @@ use crate::{
|
|||||||
assert_satisfied,
|
assert_satisfied,
|
||||||
expect_compiler_error,
|
expect_compiler_error,
|
||||||
get_output,
|
get_output,
|
||||||
|
integers::{expect_computation_error, expect_parsing_error},
|
||||||
parse_program,
|
parse_program,
|
||||||
parse_program_with_input,
|
parse_program_with_input,
|
||||||
EdwardsTestCompiler,
|
EdwardsTestCompiler,
|
||||||
@ -101,6 +102,24 @@ fn test_initializer_fail() {
|
|||||||
assert!(syntax_error);
|
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]
|
#[test]
|
||||||
fn test_spread() {
|
fn test_spread() {
|
||||||
let program_bytes = include_bytes!("spread.leo");
|
let program_bytes = include_bytes!("spread.leo");
|
||||||
@ -128,7 +147,7 @@ fn test_multi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multi_initializer_fail() {
|
fn test_multi_fail() {
|
||||||
let program_bytes = include_bytes!("multi_fail_initializer.leo");
|
let program_bytes = include_bytes!("multi_fail_initializer.leo");
|
||||||
let program = parse_program(program_bytes).unwrap();
|
let program = parse_program(program_bytes).unwrap();
|
||||||
|
|
||||||
@ -142,3 +161,19 @@ fn test_multi_inline_fail() {
|
|||||||
|
|
||||||
expect_compiler_error(program);
|
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);
|
||||||
|
}
|
||||||
|
7
compiler/tests/array/multi_initializer.leo
Normal file
7
compiler/tests/array/multi_initializer.leo
Normal file
@ -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);
|
||||||
|
}
|
3
compiler/tests/array/multi_initializer_fail.leo
Normal file
3
compiler/tests/array/multi_initializer_fail.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main() {
|
||||||
|
let arr: [u8; (2, 2)] = [1u8; (2, 1)]; // incorrect dimensions
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::Rule,
|
ast::Rule,
|
||||||
errors::SyntaxError as InputSyntaxError,
|
errors::SyntaxError as InputSyntaxError,
|
||||||
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression},
|
expressions::{ArrayInlineExpression, Expression},
|
||||||
sections::Header,
|
sections::Header,
|
||||||
tables::Table,
|
tables::Table,
|
||||||
types::{DataType, Type},
|
types::{DataType, Type},
|
||||||
@ -71,14 +71,22 @@ impl InputParserError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_type_mismatch(data_type: DataType, value: Value) -> Self {
|
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();
|
let span = value.span().to_owned();
|
||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expression_type_mismatch(type_: Type, expression: Expression) -> Self {
|
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();
|
let span = expression.span().to_owned();
|
||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
@ -95,12 +103,11 @@ impl InputParserError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn array_init_length(number: usize, array: ArrayInitializerExpression) -> Self {
|
pub fn array_init_length(expected: Vec<usize>, actual: Vec<usize>, span: Span) -> Self {
|
||||||
let message = format!(
|
let message = format!(
|
||||||
"expected an array with a fixed size of {} elements, found one with {} elements",
|
"expected an array with a fixed size of {:?} elements, found one with {:?} elements",
|
||||||
number, array.count
|
expected, actual
|
||||||
);
|
);
|
||||||
let span = array.span.to_owned();
|
|
||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::{ast::Rule, expressions::Expression, values::PositiveNumber};
|
use crate::{ast::Rule, expressions::Expression, types::ArrayDimensions};
|
||||||
|
|
||||||
use pest::Span;
|
use pest::Span;
|
||||||
use pest_ast::FromPest;
|
use pest_ast::FromPest;
|
||||||
@ -23,7 +23,7 @@ use pest_ast::FromPest;
|
|||||||
#[pest_ast(rule(Rule::expression_array_initializer))]
|
#[pest_ast(rule(Rule::expression_array_initializer))]
|
||||||
pub struct ArrayInitializerExpression<'ast> {
|
pub struct ArrayInitializerExpression<'ast> {
|
||||||
pub expression: Box<Expression<'ast>>,
|
pub expression: Box<Expression<'ast>>,
|
||||||
pub count: PositiveNumber<'ast>,
|
pub dimensions: ArrayDimensions<'ast>,
|
||||||
#[pest_ast(outer())]
|
#[pest_ast(outer())]
|
||||||
pub span: Span<'ast>,
|
pub span: Span<'ast>,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Expression::ArrayInitializer(ref expression) => {
|
Expression::ArrayInitializer(ref expression) => {
|
||||||
write!(f, "array [{} ; {}]", expression.expression, expression.count)
|
write!(f, "array [{} ; {}]", expression.expression, expression.dimensions)
|
||||||
}
|
}
|
||||||
Expression::ArrayInline(ref array) => {
|
Expression::ArrayInline(ref array) => {
|
||||||
let values = array
|
let values = array
|
||||||
|
@ -179,7 +179,7 @@ value_address = {address | address_typed}
|
|||||||
/// Expressions
|
/// Expressions
|
||||||
|
|
||||||
// Declared in expressions/array_initializer_expression.rs
|
// 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
|
// Declared in expressions/array_inline_expression.rs
|
||||||
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
|
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
|
||||||
|
@ -53,7 +53,7 @@ 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() - 2].to_vec(),
|
numbers: old_dimension[..old_dimension.len() - 1].to_vec(),
|
||||||
span: multiple.span.clone(),
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ArrayDimensions::Single(ref single) => write!(f, "{}", single.number),
|
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::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
write!(f, "{}", string)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,6 @@ pub struct ArrayType<'ast> {
|
|||||||
|
|
||||||
impl<'ast> std::fmt::Display for ArrayType<'ast> {
|
impl<'ast> std::fmt::Display for ArrayType<'ast> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "[{}; {}]", self.type_, self.dimensions)
|
write!(f, "[{}; ({})]", self.type_, self.dimensions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,10 +493,28 @@ impl<'ast> From<ArrayInlineExpression<'ast>> for Expression {
|
|||||||
|
|
||||||
impl<'ast> From<ArrayInitializerExpression<'ast>> for Expression {
|
impl<'ast> From<ArrayInitializerExpression<'ast>> for Expression {
|
||||||
fn from(array: ArrayInitializerExpression<'ast>) -> Self {
|
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));
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,40 +139,40 @@ impl InputValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_array_initializer(
|
pub(crate) fn from_array_initializer(
|
||||||
mut array_type: ArrayType,
|
array_type: ArrayType,
|
||||||
initializer: ArrayInitializerExpression,
|
initializer: ArrayInitializerExpression,
|
||||||
) -> 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());
|
||||||
let initializer_count = initializer.count.to_string().parse::<usize>()?;
|
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
|
// Return an error if the array type does not equal the array expression
|
||||||
if let Some(outer_dimension) = array_dimensions.pop() {
|
if array_dimensions.ne(&initializer_dimensions) {
|
||||||
array_type.dimensions = array_type.dimensions.next_dimension();
|
return Err(InputParserError::array_init_length(
|
||||||
|
array_dimensions,
|
||||||
if outer_dimension != initializer_count {
|
initializer_dimensions,
|
||||||
return Err(InputParserError::array_init_length(outer_dimension, initializer));
|
initializer.span,
|
||||||
}
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner_array_type = if array_dimensions.len() == 0 {
|
let type_ = match array_type.type_ {
|
||||||
// this is a single array
|
ArrayElement::Basic(basic) => Type::Basic(basic),
|
||||||
match array_type.type_ {
|
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
|
||||||
ArrayElement::Basic(basic) => Type::Basic(basic),
|
|
||||||
ArrayElement::Tuple(tuple) => Type::Tuple(tuple),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// this is a multi-dimensional array
|
|
||||||
Type::Array(array_type)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut values = vec![];
|
let value = InputValue::from_expression(type_, *initializer.expression.clone())?;
|
||||||
for _ in 0..initializer_count {
|
let mut elements = vec![];
|
||||||
let value = InputValue::from_expression(inner_array_type.clone(), *initializer.expression.clone())?;
|
|
||||||
|
|
||||||
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<Self, InputParserError> {
|
pub(crate) fn from_tuple(tuple_type: TupleType, tuple: TupleExpression) -> Result<Self, InputParserError> {
|
||||||
|
Loading…
Reference in New Issue
Block a user