impl tuple ast access

This commit is contained in:
collin 2022-07-09 13:22:10 -07:00
parent 9e422599a0
commit a7fc19a69f
27 changed files with 177 additions and 50 deletions

View File

@ -14,11 +14,14 @@
// 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/>.
mod member_access; mod associated_constant_access;
pub use member_access::*; pub use associated_constant_access::*;
mod associated_function_access; mod associated_function_access;
pub use associated_function_access::*; pub use associated_function_access::*;
mod associated_constant_access; mod member_access;
pub use associated_constant_access::*; pub use member_access::*;
mod tuple_access;
pub use tuple_access::*;

View 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);

View File

@ -27,30 +27,32 @@ pub enum AccessExpression {
// Array(ArrayAccess), // Array(ArrayAccess),
// /// An expression accessing a range of an array. // /// An expression accessing a range of an array.
// ArrayRange(ArrayRangeAccess), // 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`. /// Access to an associated variable of a circuit e.g `u8::MAX`.
AssociatedConstant(AssociatedConstant), AssociatedConstant(AssociatedConstant),
/// Access to an associated function of a circuit e.g `Pedersen64::hash()`. /// Access to an associated function of a circuit e.g `Pedersen64::hash()`.
AssociatedFunction(AssociatedFunction), 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 { impl Node for AccessExpression {
fn span(&self) -> Span { fn span(&self) -> Span {
match self { match self {
AccessExpression::Member(n) => n.span(),
AccessExpression::AssociatedConstant(n) => n.span(), AccessExpression::AssociatedConstant(n) => n.span(),
AccessExpression::AssociatedFunction(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) { fn set_span(&mut self, span: Span) {
match self { match self {
AccessExpression::Member(n) => n.set_span(span),
AccessExpression::AssociatedConstant(n) => n.set_span(span), AccessExpression::AssociatedConstant(n) => n.set_span(span),
AccessExpression::AssociatedFunction(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::*; use AccessExpression::*;
match self { 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), AssociatedConstant(access) => access.fmt(f),
AssociatedFunction(access) => access.fmt(f), AssociatedFunction(access) => access.fmt(f),
Member(access) => access.fmt(f),
Tuple(access) => access.fmt(f),
} }
} }
} }

View File

@ -40,7 +40,34 @@ pub trait ExpressionReconstructor {
} }
fn reconstruct_access(&mut self, input: AccessExpression) -> (Expression, Self::AdditionalOutput) { 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) { 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) { fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
( (
Expression::Call(CallExpression { Expression::Call(CallExpression {

View File

@ -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() Default::default()
} }
@ -69,9 +84,9 @@ pub trait ExpressionVisitor<'a> {
} }
fn visit_circuit_init( fn visit_circuit_init(
&mut self, &mut self,
_input: &'a CircuitExpression, _input: &'a CircuitExpression,
_additional: &Self::AdditionalInput, _additional: &Self::AdditionalInput,
) -> Self::Output { ) -> Self::Output {
Default::default() Default::default()
} }

View File

@ -384,10 +384,7 @@ impl ParserContext<'_> {
if !trailing && tuple.len() == 1 { if !trailing && tuple.len() == 1 {
Ok(tuple.swap_remove(0)) Ok(tuple.swap_remove(0))
} else { } else {
Ok(Expression::Tuple(TupleExpression { Ok(Expression::Tuple(TupleExpression { elements: tuple, span }))
elements: tuple,
span
}))
} }
} }

View File

@ -84,7 +84,8 @@ impl ParserContext<'_> {
} }
/// Returns a [`(Type, Span)`] where `Type` is a `Type::Tuple` AST node. /// 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 (types, _, span) = self.parse_paren_comma_list(|p| p.parse_single_type().map(Some))?;
let elements = types.into_iter().map(|(type_, _)| type_).collect::<Vec<_>>(); let elements = types.into_iter().map(|(type_, _)| type_).collect::<Vec<_>>();

View File

@ -98,7 +98,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
} }
} }
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output { fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
match input.op { match input.op {
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => { 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 { fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
match &*input.function { match &*input.function {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
@ -338,7 +336,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
input.arguments.len(), input.arguments.len(),
input.span(), input.span(),
) )
.into(), .into(),
); );
} }
@ -361,11 +359,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
} }
} }
fn visit_circuit_init( fn visit_circuit_init(&mut self, input: &'a CircuitExpression, additional: &Self::AdditionalInput) -> Self::Output {
&mut self,
input: &'a CircuitExpression,
additional: &Self::AdditionalInput,
) -> Self::Output {
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned(); let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
if let Some(circ) = circ { if let Some(circ) = circ {
// Check circuit type name. // 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 { fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
self.visit_expression(&input.condition, &Some(Type::Boolean)); 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 { if let Some(Type::Tuple(expected_types)) = expected {
// Check actual length is equal to expected length. // Check actual length is equal to expected length.
if expected_types.len() != input.elements.len() { 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 expected_types
@ -594,5 +590,4 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
} }
} }
} }
} }

View 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);
}

View File

@ -0,0 +1,10 @@
/*
namespace: Compile
expectation: Fail
input_file:
- inputs/bool_bool.in
*/
function main(a: bool, b: bool) -> (bool) {
return (a);
}

View File

@ -0,0 +1,10 @@
/*
namespace: Compile
expectation: Fail
input_file:
- inputs/bool_bool.in
*/
function main(a: bool, b: bool) -> () {
return ();
}

View File

@ -0,0 +1,3 @@
[main]
a: bool = true;
b: bool = false;

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -4,4 +4,4 @@ expectation: Pass
outputs: outputs:
- output: - output:
- initial_input_ast: no input - initial_input_ast: no input
initial_ast: 8507cd1753f4d2a835fa34d3d784487d89d595ea415d51145dd7291a839159c2 initial_ast: 06b7428058f95519ae12657c24f873f86f43f30f9715ee3f1c0192e632775d32

View File

@ -4,4 +4,4 @@ expectation: Pass
outputs: outputs:
- output: - output:
- initial_input_ast: no input - initial_input_ast: no input
initial_ast: 9489ab9b78bd31ac516e1674a83c6b35708238174df88374a7b19cef3d4a8e8a initial_ast: d040a3a4f2be00b8123a1cbdbfe08a651526c76f12b24e0378f4f11fa7ded820

View File

@ -4,4 +4,4 @@ expectation: Pass
outputs: outputs:
- output: - output:
- initial_input_ast: 29f6139d908d390f890f04d8ee620757d29b7f71cd48c46ff65bc1e70aae840c - initial_input_ast: 29f6139d908d390f890f04d8ee620757d29b7f71cd48c46ff65bc1e70aae840c
initial_ast: 630995cc22fb6ec613f02e3aaa18392770158b2bbaf5aa1736c0bf71dd7357ce initial_ast: 9a9a861c36d5b4a6207e542505b8fa338721cd6cb57904577b425c733f0ae480

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -4,4 +4,4 @@ expectation: Pass
outputs: outputs:
- output: - output:
- initial_input_ast: no input - initial_input_ast: no input
initial_ast: cc9fdc5ee476d5c8930260c5fc50c968915434892180f0084f15cd69b905dc20 initial_ast: 209ec3cdd48655115bca90839ebe91260044d8ee9edb4c7c4542497427cb1d76

View File

@ -4,4 +4,4 @@ expectation: Pass
outputs: outputs:
- output: - output:
- initial_input_ast: no input - initial_input_ast: no input
initial_ast: c765de9e29d4ca9bd9ba2f7a5ee72c2e4c8278948d32a6c9a441f5eacde564ea initial_ast: 73452a5c1cd8fc44277d025eb18a42529e4cc9f97282b508e996912c6b8753d3

View File

@ -2,4 +2,4 @@
namespace: Compile namespace: Compile
expectation: Fail expectation: Fail
outputs: 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"

View File

@ -0,0 +1,7 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 99be02d0d987d66d7bcac961871997df93d22a28989a08cb71ce2ea65528b6e6
initial_ast: 6f8a109c723a892e2b3dc61071a5330fa6827fb15bea0ed6e1f52bf40f60f8cf

View File

@ -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 `( )`"

View File

@ -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 | ^^"

View File

@ -2,12 +2,12 @@
namespace: ParseExpression namespace: ParseExpression
expectation: Fail expectation: Fail
outputs: 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 [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 [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,456u8)group\n | ^^^"
- "Error [EPAR0370027]: Could not parse the implicit value: 123.\n --> test:1:2\n |\n 1 | (123,456field)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 | ^" - "Error [EPAR0370004]: Unexpected white space between terms (123,456) and group\n --> test:1:11\n |\n 1 | (123, 456) group\n | ^"