mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 18:21:38 +03:00
impl tuple ast access
This commit is contained in:
parent
9e422599a0
commit
a7fc19a69f
@ -14,11 +14,14 @@
|
||||
// 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/>.
|
||||
|
||||
mod member_access;
|
||||
pub use member_access::*;
|
||||
mod associated_constant_access;
|
||||
pub use associated_constant_access::*;
|
||||
|
||||
mod associated_function_access;
|
||||
pub use associated_function_access::*;
|
||||
|
||||
mod associated_constant_access;
|
||||
pub use associated_constant_access::*;
|
||||
mod member_access;
|
||||
pub use member_access::*;
|
||||
|
||||
mod tuple_access;
|
||||
pub use tuple_access::*;
|
||||
|
40
compiler/ast/src/access/tuple_access.rs
Normal file
40
compiler/ast/src/access/tuple_access.rs
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2019-2022 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::{Expression, Node, PositiveNumber};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// An tuple access expression, e.g., `tuple.index`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TupleAccess {
|
||||
/// An expression evaluating to some tuple type, e.g., `(5, 2)`.
|
||||
pub tuple: Box<Expression>,
|
||||
/// The index to access in the tuple expression. E.g., `0` for `(5, 2)` would yield `5`.
|
||||
pub index: PositiveNumber,
|
||||
/// The span for the entire expression `tuple.index`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for TupleAccess {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.{}", self.tuple, self.index)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(TupleAccess);
|
@ -27,30 +27,32 @@ pub enum AccessExpression {
|
||||
// Array(ArrayAccess),
|
||||
// /// An expression accessing a range of an array.
|
||||
// ArrayRange(ArrayRangeAccess),
|
||||
/// An expression accessing a field in a structure, e.g., `circuit_var.field`.
|
||||
Member(MemberAccess),
|
||||
// /// Access to a tuple field using its position, e.g., `tuple.1`.
|
||||
// Tuple(TupleAccess),
|
||||
/// Access to an associated variable of a circuit e.g `u8::MAX`.
|
||||
AssociatedConstant(AssociatedConstant),
|
||||
/// Access to an associated function of a circuit e.g `Pedersen64::hash()`.
|
||||
AssociatedFunction(AssociatedFunction),
|
||||
/// An expression accessing a field in a structure, e.g., `circuit_var.field`.
|
||||
Member(MemberAccess),
|
||||
/// Access to a tuple field using its position, e.g., `tuple.1`.
|
||||
Tuple(TupleAccess),
|
||||
}
|
||||
|
||||
impl Node for AccessExpression {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
AccessExpression::Member(n) => n.span(),
|
||||
AccessExpression::AssociatedConstant(n) => n.span(),
|
||||
AccessExpression::AssociatedFunction(n) => n.span(),
|
||||
AccessExpression::Member(n) => n.span(),
|
||||
AccessExpression::Tuple(n) => n.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
AccessExpression::Member(n) => n.set_span(span),
|
||||
AccessExpression::AssociatedConstant(n) => n.set_span(span),
|
||||
AccessExpression::AssociatedFunction(n) => n.set_span(span),
|
||||
AccessExpression::Member(n) => n.set_span(span),
|
||||
AccessExpression::Tuple(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,12 +62,10 @@ impl fmt::Display for AccessExpression {
|
||||
use AccessExpression::*;
|
||||
|
||||
match self {
|
||||
// Array(access) => access.fmt(f),
|
||||
// ArrayRange(access) => access.fmt(f),
|
||||
Member(access) => access.fmt(f),
|
||||
// Tuple(access) => access.fmt(f),
|
||||
AssociatedConstant(access) => access.fmt(f),
|
||||
AssociatedFunction(access) => access.fmt(f),
|
||||
Member(access) => access.fmt(f),
|
||||
Tuple(access) => access.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,34 @@ pub trait ExpressionReconstructor {
|
||||
}
|
||||
|
||||
fn reconstruct_access(&mut self, input: AccessExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Access(input), Default::default())
|
||||
(
|
||||
Expression::Access(match input {
|
||||
AccessExpression::AssociatedFunction(function) => {
|
||||
AccessExpression::AssociatedFunction(AssociatedFunction {
|
||||
ty: function.ty,
|
||||
name: function.name,
|
||||
args: function
|
||||
.args
|
||||
.into_iter()
|
||||
.map(|arg| self.reconstruct_expression(arg).0)
|
||||
.collect(),
|
||||
span: function.span,
|
||||
})
|
||||
}
|
||||
AccessExpression::Member(member) => AccessExpression::Member(MemberAccess {
|
||||
inner: Box::new(self.reconstruct_expression(*member.inner).0),
|
||||
name: member.name,
|
||||
span: member.span,
|
||||
}),
|
||||
AccessExpression::Tuple(tuple) => AccessExpression::Tuple(TupleAccess {
|
||||
tuple: Box::new(self.reconstruct_expression(*tuple.tuple).0),
|
||||
index: tuple.index,
|
||||
span: tuple.span,
|
||||
}),
|
||||
expr => expr,
|
||||
}),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
@ -55,7 +82,6 @@ pub trait ExpressionReconstructor {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Call(CallExpression {
|
||||
|
@ -40,7 +40,22 @@ pub trait ExpressionVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, _input: &'a AccessExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
fn visit_access(&mut self, input: &'a AccessExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
match input {
|
||||
AccessExpression::AssociatedFunction(function) => {
|
||||
function.args.iter().for_each(|arg| {
|
||||
self.visit_expression(arg, &Default::default());
|
||||
});
|
||||
}
|
||||
AccessExpression::Member(member) => {
|
||||
self.visit_expression(&member.inner, additional);
|
||||
}
|
||||
AccessExpression::Tuple(tuple) => {
|
||||
self.visit_expression(&tuple.tuple, additional);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Default::default()
|
||||
}
|
||||
|
||||
@ -69,9 +84,9 @@ pub trait ExpressionVisitor<'a> {
|
||||
}
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
_input: &'a CircuitExpression,
|
||||
_additional: &Self::AdditionalInput,
|
||||
&mut self,
|
||||
_input: &'a CircuitExpression,
|
||||
_additional: &Self::AdditionalInput,
|
||||
) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
@ -384,10 +384,7 @@ impl ParserContext<'_> {
|
||||
if !trailing && tuple.len() == 1 {
|
||||
Ok(tuple.swap_remove(0))
|
||||
} else {
|
||||
Ok(Expression::Tuple(TupleExpression {
|
||||
elements: tuple,
|
||||
span
|
||||
}))
|
||||
Ok(Expression::Tuple(TupleExpression { elements: tuple, span }))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,8 @@ impl ParserContext<'_> {
|
||||
}
|
||||
|
||||
/// Returns a [`(Type, Span)`] where `Type` is a `Type::Tuple` AST node.
|
||||
pub fn parse_tuple_type(&mut self) -> Result<(Type, Span)> { // todo: catch and return error for nested tuple type.
|
||||
pub fn parse_tuple_type(&mut self) -> Result<(Type, Span)> {
|
||||
// todo: catch and return error for nested tuple type.
|
||||
let (types, _, span) = self.parse_paren_comma_list(|p| p.parse_single_type().map(Some))?;
|
||||
let elements = types.into_iter().map(|(type_, _)| type_).collect::<Vec<_>>();
|
||||
|
||||
|
@ -98,7 +98,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.op {
|
||||
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
|
||||
@ -322,7 +321,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
match &*input.function {
|
||||
Expression::Identifier(ident) => {
|
||||
@ -338,7 +336,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
input.arguments.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -361,11 +359,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
input: &'a CircuitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Self::Output {
|
||||
fn visit_circuit_init(&mut self, input: &'a CircuitExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
|
||||
if let Some(circ) = circ {
|
||||
// Check circuit type name.
|
||||
@ -509,8 +503,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
self.visit_expression(&input.condition, &Some(Type::Boolean));
|
||||
|
||||
@ -525,7 +517,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
if let Some(Type::Tuple(expected_types)) = expected {
|
||||
// Check actual length is equal to expected length.
|
||||
if expected_types.len() != input.elements.len() {
|
||||
self.emit_err(TypeCheckerError::incorrect_tuple_length(expected_types.len(), input.elements.len(), input.span()));
|
||||
self.emit_err(TypeCheckerError::incorrect_tuple_length(
|
||||
expected_types.len(),
|
||||
input.elements.len(),
|
||||
input.span(),
|
||||
));
|
||||
}
|
||||
|
||||
expected_types
|
||||
@ -594,5 +590,4 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
10
tests/compiler/tuple/function_return.leo
Normal file
10
tests/compiler/tuple/function_return.leo
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file:
|
||||
- inputs/bool_bool.in
|
||||
*/
|
||||
|
||||
function main(a: bool, b: bool) -> (bool, bool) {
|
||||
return (a, b);
|
||||
}
|
10
tests/compiler/tuple/function_return_single_fail.leo
Normal file
10
tests/compiler/tuple/function_return_single_fail.leo
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
input_file:
|
||||
- inputs/bool_bool.in
|
||||
*/
|
||||
|
||||
function main(a: bool, b: bool) -> (bool) {
|
||||
return (a);
|
||||
}
|
10
tests/compiler/tuple/function_return_zero_fail.leo
Normal file
10
tests/compiler/tuple/function_return_zero_fail.leo
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
input_file:
|
||||
- inputs/bool_bool.in
|
||||
*/
|
||||
|
||||
function main(a: bool, b: bool) -> () {
|
||||
return ();
|
||||
}
|
3
tests/compiler/tuple/inputs/bool_bool.in
Normal file
3
tests/compiler/tuple/inputs/bool_bool.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
a: bool = true;
|
||||
b: bool = false;
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372015]: circuit `Bar` shadowed by\n --> compiler-test:8:5\n |\n 8 | const Bar: u32 = 66u32;\n | ^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
- "Error [EAST0372016]: circuit `Bar` shadowed by\n --> compiler-test:8:5\n |\n 8 | const Bar: u32 = 66u32;\n | ^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
|
@ -4,4 +4,4 @@ expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: 8507cd1753f4d2a835fa34d3d784487d89d595ea415d51145dd7291a839159c2
|
||||
initial_ast: 06b7428058f95519ae12657c24f873f86f43f30f9715ee3f1c0192e632775d32
|
||||
|
@ -4,4 +4,4 @@ expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: 9489ab9b78bd31ac516e1674a83c6b35708238174df88374a7b19cef3d4a8e8a
|
||||
initial_ast: d040a3a4f2be00b8123a1cbdbfe08a651526c76f12b24e0378f4f11fa7ded820
|
||||
|
@ -4,4 +4,4 @@ expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: 29f6139d908d390f890f04d8ee620757d29b7f71cd48c46ff65bc1e70aae840c
|
||||
initial_ast: 630995cc22fb6ec613f02e3aaa18392770158b2bbaf5aa1736c0bf71dd7357ce
|
||||
initial_ast: 9a9a861c36d5b4a6207e542505b8fa338721cd6cb57904577b425c733f0ae480
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372014]: function `main` shadowed by\n --> compiler-test:8:1\n |\n 8 | function main(y: bool) -> bool {\n 9 | console.log(\"{}\", 2u8);\n 10 | return y; \n 11 | }\n | ^\n"
|
||||
- "Error [EAST0372015]: function `main` shadowed by\n --> compiler-test:8:1\n |\n 8 | function main(y: bool) -> bool {\n 9 | console.log(\"{}\", 2u8);\n 10 | return y; \n 11 | }\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372017]: variable `a` shadowed by\n --> compiler-test:3:23\n |\n 3 | function main(a: u32, a: u32) -> u32 {\n | ^\n"
|
||||
- "Error [EAST0372018]: variable `a` shadowed by\n --> compiler-test:3:23\n |\n 3 | function main(a: u32, a: u32) -> u32 {\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372014]: function `hi` shadowed by\n --> compiler-test:7:17\n |\n 7 | function tester(hi: u8) -> u8 {\n | ^^\n"
|
||||
- "Error [EAST0372015]: function `hi` shadowed by\n --> compiler-test:7:17\n |\n 7 | function tester(hi: u8) -> u8 {\n | ^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372016]: record `Token` shadowed by\n --> compiler-test:12:1\n |\n 12 | circuit Token { // This circuit cannot have the same name as the record defined above it.\n 13 | x: u32,\n 14 | }\n | ^\n"
|
||||
- "Error [EAST0372017]: record `Token` shadowed by\n --> compiler-test:12:1\n |\n 12 | circuit Token { // This circuit cannot have the same name as the record defined above it.\n 13 | x: u32,\n 14 | }\n | ^\n"
|
||||
|
@ -4,4 +4,4 @@ expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: cc9fdc5ee476d5c8930260c5fc50c968915434892180f0084f15cd69b905dc20
|
||||
initial_ast: 209ec3cdd48655115bca90839ebe91260044d8ee9edb4c7c4542497427cb1d76
|
||||
|
@ -4,4 +4,4 @@ expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: c765de9e29d4ca9bd9ba2f7a5ee72c2e4c8278948d32a6c9a441f5eacde564ea
|
||||
initial_ast: 73452a5c1cd8fc44277d025eb18a42529e4cc9f97282b508e996912c6b8753d3
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372017]: variable `x` shadowed by\n --> compiler-test:5:4\n |\n 5 | \tlet x: bool = true;\n | ^^^^^^^^^^^^^^^^^^\n"
|
||||
- "Error [EAST0372018]: variable `x` shadowed by\n --> compiler-test:5:4\n |\n 5 | \tlet x: bool = true;\n | ^^^^^^^^^^^^^^^^^^\n"
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: 99be02d0d987d66d7bcac961871997df93d22a28989a08cb71ce2ea65528b6e6
|
||||
initial_ast: 6f8a109c723a892e2b3dc61071a5330fa6827fb15bea0ed6e1f52bf40f60f8cf
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372014]: Tuples of one element are not allowed.\n --> compiler-test:3:36\n |\n 3 | function main(a: bool, b: bool) -> (bool) {\n | ^^^^^^\n |\n = Try defining a single type by removing the parenthesis `( )`"
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EAST0372013]: Tuples of zero elements are not allowed.\n --> compiler-test:3:36\n |\n 3 | function main(a: bool, b: bool) -> () {\n | ^^"
|
@ -2,12 +2,12 @@
|
||||
namespace: ParseExpression
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EPAR0370005]: expected A valid expression. -- got 'A tuple expression.'\n --> test:1:1\n |\n 1 | ()group\n | ^^"
|
||||
- "did not consume all input: 'group' @ 1:3-8\n"
|
||||
- "Error [EPAR0370027]: Could not parse the implicit value: 123.\n --> test:1:2\n |\n 1 | (123)group\n | ^^^"
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'expression', got ','\n --> test:1:2\n |\n 1 | (,)group\n | ^"
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'expression', got '+'\n --> test:1:2\n |\n 1 | (+, -,)group\n | ^"
|
||||
- "Error [EPAR0370009]: unexpected string: expected 'expression', got ','\n --> test:1:2\n |\n 1 | (,+, -)group\n | ^"
|
||||
- "Error [EPAR0370005]: expected A valid expression. -- got 'A tuple expression.'\n --> test:1:1\n |\n 1 | (x,y)group\n | ^^^^^"
|
||||
- "did not consume all input: 'group' @ 1:6-11\n"
|
||||
- "Error [EPAR0370027]: Could not parse the implicit value: 123.\n --> test:1:2\n |\n 1 | (123,456u8)group\n | ^^^"
|
||||
- "Error [EPAR0370027]: Could not parse the implicit value: 123.\n --> test:1:2\n |\n 1 | (123,456field)group\n | ^^^"
|
||||
- "Error [EPAR0370004]: Unexpected white space between terms (123,456) and group\n --> test:1:11\n |\n 1 | (123, 456) group\n | ^"
|
||||
|
Loading…
Reference in New Issue
Block a user