mirror of
https://github.com/AleoHQ/leo.git
synced 2024-09-21 03:57:39 +03:00
impl tuple type expression
This commit is contained in:
parent
a1c42a8d3f
commit
296c62a280
@ -38,7 +38,7 @@ impl fmt::Display for CircuitVariableInitializer {
|
|||||||
|
|
||||||
/// A circuit initialization expression, e.g., `Foo { bar: 42, baz }`.
|
/// A circuit initialization expression, e.g., `Foo { bar: 42, baz }`.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct CircuitInitExpression {
|
pub struct CircuitExpression {
|
||||||
/// The name of the structure type to initialize.
|
/// The name of the structure type to initialize.
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
/// Initializer expressions for each of the fields in the circuit.
|
/// Initializer expressions for each of the fields in the circuit.
|
||||||
@ -50,7 +50,7 @@ pub struct CircuitInitExpression {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CircuitInitExpression {
|
impl fmt::Display for CircuitExpression {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {{ ", self.name)?;
|
write!(f, "{} {{ ", self.name)?;
|
||||||
for member in self.members.iter() {
|
for member in self.members.iter() {
|
||||||
@ -61,4 +61,4 @@ impl fmt::Display for CircuitInitExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::simple_node_impl!(CircuitInitExpression);
|
crate::simple_node_impl!(CircuitExpression);
|
||||||
|
@ -38,6 +38,9 @@ pub use err::*;
|
|||||||
mod ternary;
|
mod ternary;
|
||||||
pub use ternary::*;
|
pub use ternary::*;
|
||||||
|
|
||||||
|
mod tuple_init;
|
||||||
|
pub use tuple_init::*;
|
||||||
|
|
||||||
mod unary;
|
mod unary;
|
||||||
pub use unary::*;
|
pub use unary::*;
|
||||||
|
|
||||||
@ -49,21 +52,23 @@ pub use value::*;
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
/// A circuit access expression, e.g., `Foo.bar`.
|
/// A circuit access expression, e.g., `Foo.bar`.
|
||||||
Access(AccessExpression),
|
Access(AccessExpression),
|
||||||
/// An identifier expression.
|
|
||||||
Identifier(Identifier),
|
|
||||||
/// A literal expression.
|
|
||||||
Literal(LiteralExpression),
|
|
||||||
/// A binary expression, e.g., `42 + 24`.
|
/// A binary expression, e.g., `42 + 24`.
|
||||||
Binary(BinaryExpression),
|
Binary(BinaryExpression),
|
||||||
/// A call expression, e.g., `my_fun(args)`.
|
/// A call expression, e.g., `my_fun(args)`.
|
||||||
Call(CallExpression),
|
Call(CallExpression),
|
||||||
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
|
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
|
||||||
CircuitInit(CircuitInitExpression),
|
Circuit(CircuitExpression),
|
||||||
/// An expression of type "error".
|
/// An expression of type "error".
|
||||||
/// Will result in a compile error eventually.
|
/// Will result in a compile error eventually.
|
||||||
Err(ErrExpression),
|
Err(ErrExpression),
|
||||||
|
/// An identifier.
|
||||||
|
Identifier(Identifier),
|
||||||
|
/// A literal expression.
|
||||||
|
Literal(LiteralExpression),
|
||||||
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
||||||
Ternary(TernaryExpression),
|
Ternary(TernaryExpression),
|
||||||
|
/// A tuple expression e.g., `(foo, 42, true)`.
|
||||||
|
Tuple(TupleExpression),
|
||||||
/// An unary expression.
|
/// An unary expression.
|
||||||
Unary(UnaryExpression),
|
Unary(UnaryExpression),
|
||||||
}
|
}
|
||||||
@ -73,13 +78,14 @@ impl Node for Expression {
|
|||||||
use Expression::*;
|
use Expression::*;
|
||||||
match self {
|
match self {
|
||||||
Access(n) => n.span(),
|
Access(n) => n.span(),
|
||||||
Identifier(n) => n.span(),
|
|
||||||
Literal(n) => n.span(),
|
|
||||||
Binary(n) => n.span(),
|
Binary(n) => n.span(),
|
||||||
Call(n) => n.span(),
|
Call(n) => n.span(),
|
||||||
CircuitInit(n) => n.span(),
|
Circuit(n) => n.span(),
|
||||||
Err(n) => n.span(),
|
Err(n) => n.span(),
|
||||||
|
Identifier(n) => n.span(),
|
||||||
|
Literal(n) => n.span(),
|
||||||
Ternary(n) => n.span(),
|
Ternary(n) => n.span(),
|
||||||
|
Tuple(n) => n.span(),
|
||||||
Unary(n) => n.span(),
|
Unary(n) => n.span(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,13 +94,14 @@ impl Node for Expression {
|
|||||||
use Expression::*;
|
use Expression::*;
|
||||||
match self {
|
match self {
|
||||||
Access(n) => n.set_span(span),
|
Access(n) => n.set_span(span),
|
||||||
Identifier(n) => n.set_span(span),
|
|
||||||
Literal(n) => n.set_span(span),
|
|
||||||
Binary(n) => n.set_span(span),
|
Binary(n) => n.set_span(span),
|
||||||
Call(n) => n.set_span(span),
|
Call(n) => n.set_span(span),
|
||||||
CircuitInit(n) => n.set_span(span),
|
Circuit(n) => n.set_span(span),
|
||||||
|
Identifier(n) => n.set_span(span),
|
||||||
|
Literal(n) => n.set_span(span),
|
||||||
Err(n) => n.set_span(span),
|
Err(n) => n.set_span(span),
|
||||||
Ternary(n) => n.set_span(span),
|
Ternary(n) => n.set_span(span),
|
||||||
|
Tuple(n) => n.set_span(span),
|
||||||
Unary(n) => n.set_span(span),
|
Unary(n) => n.set_span(span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,13 +112,14 @@ impl fmt::Display for Expression {
|
|||||||
use Expression::*;
|
use Expression::*;
|
||||||
match &self {
|
match &self {
|
||||||
Access(n) => n.fmt(f),
|
Access(n) => n.fmt(f),
|
||||||
Identifier(n) => n.fmt(f),
|
|
||||||
Literal(n) => n.fmt(f),
|
|
||||||
Binary(n) => n.fmt(f),
|
Binary(n) => n.fmt(f),
|
||||||
Call(n) => n.fmt(f),
|
Call(n) => n.fmt(f),
|
||||||
CircuitInit(n) => n.fmt(f),
|
Circuit(n) => n.fmt(f),
|
||||||
Err(n) => n.fmt(f),
|
Err(n) => n.fmt(f),
|
||||||
|
Identifier(n) => n.fmt(f),
|
||||||
|
Literal(n) => n.fmt(f),
|
||||||
Ternary(n) => n.fmt(f),
|
Ternary(n) => n.fmt(f),
|
||||||
|
Tuple(n) => n.fmt(f),
|
||||||
Unary(n) => n.fmt(f),
|
Unary(n) => n.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
compiler/ast/src/expressions/tuple_init.rs
Normal file
43
compiler/ast/src/expressions/tuple_init.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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 super::*;
|
||||||
|
|
||||||
|
/// A tuple construction expression, e.g., `(foo, false, 42)`.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct TupleExpression {
|
||||||
|
/// The elements of the tuple.
|
||||||
|
/// In the example above, it would be `foo`, `false`, and `42`.
|
||||||
|
pub elements: Vec<Expression>,
|
||||||
|
/// The span from `(` to `)`.
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TupleExpression {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"({})",
|
||||||
|
self.elements
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(",")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::simple_node_impl!(TupleExpression);
|
@ -27,33 +27,22 @@ pub trait ExpressionReconstructor {
|
|||||||
fn reconstruct_expression(&mut self, input: Expression) -> (Expression, Self::AdditionalOutput) {
|
fn reconstruct_expression(&mut self, input: Expression) -> (Expression, Self::AdditionalOutput) {
|
||||||
match input {
|
match input {
|
||||||
Expression::Access(access) => self.reconstruct_access(access),
|
Expression::Access(access) => self.reconstruct_access(access),
|
||||||
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
|
|
||||||
Expression::Literal(value) => self.reconstruct_literal(value),
|
|
||||||
Expression::Binary(binary) => self.reconstruct_binary(binary),
|
Expression::Binary(binary) => self.reconstruct_binary(binary),
|
||||||
Expression::Call(call) => self.reconstruct_call(call),
|
Expression::Call(call) => self.reconstruct_call(call),
|
||||||
Expression::CircuitInit(circuit) => self.reconstruct_circuit_init(circuit),
|
Expression::Circuit(circuit) => self.reconstruct_circuit_init(circuit),
|
||||||
Expression::Unary(unary) => self.reconstruct_unary(unary),
|
|
||||||
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
|
|
||||||
Expression::Err(err) => self.reconstruct_err(err),
|
Expression::Err(err) => self.reconstruct_err(err),
|
||||||
|
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
|
||||||
|
Expression::Literal(value) => self.reconstruct_literal(value),
|
||||||
|
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
|
||||||
|
Expression::Tuple(tuple) => self.reconstruct_tuple(tuple),
|
||||||
|
Expression::Unary(unary) => self.reconstruct_unary(unary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
|
|
||||||
(Expression::Identifier(input), Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
|
|
||||||
(Expression::Literal(input), Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
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(input), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_circuit_init(&mut self, input: CircuitInitExpression) -> (Expression, Self::AdditionalOutput) {
|
|
||||||
(Expression::CircuitInit(input), Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
|
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
(
|
(
|
||||||
Expression::Binary(BinaryExpression {
|
Expression::Binary(BinaryExpression {
|
||||||
@ -66,28 +55,6 @@ pub trait ExpressionReconstructor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
|
|
||||||
(
|
|
||||||
Expression::Unary(UnaryExpression {
|
|
||||||
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
|
|
||||||
op: input.op,
|
|
||||||
span: input.span,
|
|
||||||
}),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
|
|
||||||
(
|
|
||||||
Expression::Ternary(TernaryExpression {
|
|
||||||
condition: Box::new(self.reconstruct_expression(*input.condition).0),
|
|
||||||
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
|
|
||||||
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
|
|
||||||
span: input.span,
|
|
||||||
}),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
|
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
(
|
(
|
||||||
@ -104,9 +71,58 @@ pub trait ExpressionReconstructor {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reconstruct_circuit_init(&mut self, input: CircuitExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(Expression::Circuit(input), Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
fn reconstruct_err(&mut self, input: ErrExpression) -> (Expression, Self::AdditionalOutput) {
|
fn reconstruct_err(&mut self, input: ErrExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
(Expression::Err(input), Default::default())
|
(Expression::Err(input), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(Expression::Identifier(input), Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(Expression::Literal(input), Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(
|
||||||
|
Expression::Ternary(TernaryExpression {
|
||||||
|
condition: Box::new(self.reconstruct_expression(*input.condition).0),
|
||||||
|
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
|
||||||
|
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
|
||||||
|
span: input.span,
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstruct_tuple(&mut self, input: TupleExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(
|
||||||
|
Expression::Tuple(TupleExpression {
|
||||||
|
elements: input
|
||||||
|
.elements
|
||||||
|
.into_iter()
|
||||||
|
.map(|element| self.reconstruct_expression(element).0)
|
||||||
|
.collect(),
|
||||||
|
span: input.span,
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||||
|
(
|
||||||
|
Expression::Unary(UnaryExpression {
|
||||||
|
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
|
||||||
|
op: input.op,
|
||||||
|
span: input.span,
|
||||||
|
}),
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Reconstructor trait for statements in the AST.
|
/// A Reconstructor trait for statements in the AST.
|
||||||
|
@ -27,15 +27,16 @@ pub trait ExpressionVisitor<'a> {
|
|||||||
|
|
||||||
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
|
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
match input {
|
match input {
|
||||||
Expression::Access(expr) => self.visit_access(expr, additional),
|
Expression::Access(access) => self.visit_access(access, additional),
|
||||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
|
Expression::Binary(binary) => self.visit_binary(binary, additional),
|
||||||
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
|
Expression::Call(call) => self.visit_call(call, additional),
|
||||||
Expression::Literal(expr) => self.visit_literal(expr, additional),
|
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, additional),
|
||||||
Expression::Binary(expr) => self.visit_binary(expr, additional),
|
Expression::Err(err) => self.visit_err(err, additional),
|
||||||
Expression::Unary(expr) => self.visit_unary(expr, additional),
|
Expression::Identifier(identifier) => self.visit_identifier(identifier, additional),
|
||||||
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
|
Expression::Literal(literal) => self.visit_literal(literal, additional),
|
||||||
Expression::Call(expr) => self.visit_call(expr, additional),
|
Expression::Ternary(ternary) => self.visit_ternary(ternary, additional),
|
||||||
Expression::Err(expr) => self.visit_err(expr, additional),
|
Expression::Tuple(tuple) => self.visit_tuple(tuple, additional),
|
||||||
|
Expression::Unary(unary) => self.visit_unary(unary, additional),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,40 +44,12 @@ pub trait ExpressionVisitor<'a> {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_circuit_init(
|
|
||||||
&mut self,
|
|
||||||
_input: &'a CircuitInitExpression,
|
|
||||||
_additional: &Self::AdditionalInput,
|
|
||||||
) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_binary(&mut self, input: &'a BinaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
fn visit_binary(&mut self, input: &'a BinaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
self.visit_expression(&input.left, additional);
|
self.visit_expression(&input.left, additional);
|
||||||
self.visit_expression(&input.right, additional);
|
self.visit_expression(&input.right, additional);
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
self.visit_expression(&input.receiver, additional);
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
self.visit_expression(&input.condition, additional);
|
|
||||||
self.visit_expression(&input.if_true, additional);
|
|
||||||
self.visit_expression(&input.if_false, additional);
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
input.arguments.iter().for_each(|expr| {
|
input.arguments.iter().for_each(|expr| {
|
||||||
self.visit_expression(expr, additional);
|
self.visit_expression(expr, additional);
|
||||||
@ -87,6 +60,40 @@ pub trait ExpressionVisitor<'a> {
|
|||||||
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_circuit_init(
|
||||||
|
&mut self,
|
||||||
|
_input: &'a CircuitExpression,
|
||||||
|
_additional: &Self::AdditionalInput,
|
||||||
|
) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
self.visit_expression(&input.condition, additional);
|
||||||
|
self.visit_expression(&input.if_true, additional);
|
||||||
|
self.visit_expression(&input.if_false, additional);
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_tuple(&mut self, input: &'a TupleExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
input.elements.iter().for_each(|expr| {
|
||||||
|
self.visit_expression(expr, additional);
|
||||||
|
});
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
self.visit_expression(&input.receiver, additional);
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Visitor trait for statements in the AST.
|
/// A Visitor trait for statements in the AST.
|
||||||
|
@ -19,10 +19,7 @@ use leo_errors::{AstError, Result};
|
|||||||
use leo_span::Span;
|
use leo_span::Span;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{fmt, ops::Deref};
|
||||||
fmt,
|
|
||||||
ops::Deref
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A type list of at least two types.
|
/// A type list of at least two types.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
@ -34,7 +31,7 @@ impl Tuple {
|
|||||||
match elements.len() {
|
match elements.len() {
|
||||||
0 => Err(AstError::empty_tuple(span).into()),
|
0 => Err(AstError::empty_tuple(span).into()),
|
||||||
1 => Err(AstError::one_element_tuple(span).into()),
|
1 => Err(AstError::one_element_tuple(span).into()),
|
||||||
_ => Ok(Type::Tuple(Tuple(elements)))
|
_ => Ok(Type::Tuple(Tuple(elements))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +46,10 @@ impl Deref for Tuple {
|
|||||||
|
|
||||||
impl fmt::Display for Tuple {
|
impl fmt::Display for Tuple {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "({})", self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
|
write!(
|
||||||
|
f,
|
||||||
|
"({})",
|
||||||
|
self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,7 +470,7 @@ impl ParserContext<'_> {
|
|||||||
p.parse_circuit_member().map(Some)
|
p.parse_circuit_member().map(Some)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Expression::CircuitInit(CircuitInitExpression {
|
Ok(Expression::Circuit(CircuitExpression {
|
||||||
span: identifier.span + end,
|
span: identifier.span + end,
|
||||||
name: identifier,
|
name: identifier,
|
||||||
members,
|
members,
|
||||||
|
@ -43,14 +43,15 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
|
|
||||||
fn visit_expression(&mut self, input: &'a Expression, expected: &Self::AdditionalInput) -> Self::Output {
|
fn visit_expression(&mut self, input: &'a Expression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
match input {
|
match input {
|
||||||
Expression::Access(expr) => self.visit_access(expr, expected),
|
Expression::Access(access) => self.visit_access(access, expected),
|
||||||
Expression::Identifier(expr) => self.visit_identifier(expr, expected),
|
Expression::Binary(binary) => self.visit_binary(binary, expected),
|
||||||
Expression::Literal(expr) => self.visit_literal(expr, expected),
|
Expression::Call(call) => self.visit_call(call, expected),
|
||||||
Expression::Binary(expr) => self.visit_binary(expr, expected),
|
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, expected),
|
||||||
Expression::Call(expr) => self.visit_call(expr, expected),
|
Expression::Identifier(identifier) => self.visit_identifier(identifier, expected),
|
||||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, expected),
|
Expression::Err(err) => self.visit_err(err, expected),
|
||||||
Expression::Err(expr) => self.visit_err(expr, expected),
|
Expression::Literal(literal) => self.visit_literal(literal, expected),
|
||||||
Expression::Ternary(expr) => self.visit_ternary(expr, expected),
|
Expression::Ternary(ternary) => self.visit_ternary(ternary, expected),
|
||||||
|
Expression::Tuple(tuple) => self.visit_tuple(tuple, expected),
|
||||||
Expression::Unary(expr) => self.visit_unary(expr, expected),
|
Expression::Unary(expr) => self.visit_unary(expr, expected),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,155 +98,6 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_circuit_init(
|
|
||||||
&mut self,
|
|
||||||
input: &'a CircuitInitExpression,
|
|
||||||
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.
|
|
||||||
let ret = self.check_expected_circuit(circ.identifier, additional, input.name.span());
|
|
||||||
|
|
||||||
// Check number of circuit members.
|
|
||||||
if circ.members.len() != input.members.len() {
|
|
||||||
self.handler.emit_err(
|
|
||||||
TypeCheckerError::incorrect_num_circuit_members(
|
|
||||||
circ.members.len(),
|
|
||||||
input.members.len(),
|
|
||||||
input.span(),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check circuit member types.
|
|
||||||
circ.members
|
|
||||||
.iter()
|
|
||||||
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
|
||||||
// Lookup circuit variable name.
|
|
||||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
|
||||||
if let Some(expr) = &actual.expression {
|
|
||||||
self.visit_expression(expr, &Some(ty.clone()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.handler.emit_err(
|
|
||||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(ret)
|
|
||||||
} else {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(&var.name) {
|
|
||||||
Some(self.assert_and_return_type(Type::Identifier(circuit.identifier), expected, var.span))
|
|
||||||
} else if let Some(var) = self.symbol_table.borrow().lookup_variable(&var.name) {
|
|
||||||
Some(self.assert_and_return_type(var.type_.clone(), expected, var.span))
|
|
||||||
} else {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Some(match input {
|
|
||||||
LiteralExpression::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
|
|
||||||
LiteralExpression::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
|
|
||||||
LiteralExpression::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
|
|
||||||
LiteralExpression::Integer(type_, str_content, _) => {
|
|
||||||
match type_ {
|
|
||||||
IntegerType::I8 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i8>().is_err() {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I16 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i16>().is_err() {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I32 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i32>().is_err() {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I64 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i64>().is_err() {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I128 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i128>().is_err() {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
|
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
|
|
||||||
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
|
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
|
|
||||||
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
|
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
|
|
||||||
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
|
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
|
|
||||||
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
|
|
||||||
.handler
|
|
||||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
self.assert_and_return_type(Type::IntegerType(*type_), expected, input.span())
|
|
||||||
}
|
|
||||||
LiteralExpression::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
|
|
||||||
LiteralExpression::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
|
|
||||||
LiteralExpression::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
@ -470,6 +322,228 @@ 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) => {
|
||||||
|
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
|
||||||
|
if let Some(func) = func {
|
||||||
|
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
||||||
|
|
||||||
|
// Check number of function arguments.
|
||||||
|
if func.input.len() != input.arguments.len() {
|
||||||
|
self.handler.emit_err(
|
||||||
|
TypeCheckerError::incorrect_num_args_to_call(
|
||||||
|
func.input.len(),
|
||||||
|
input.arguments.len(),
|
||||||
|
input.span(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check function argument types.
|
||||||
|
func.input
|
||||||
|
.iter()
|
||||||
|
.zip(input.arguments.iter())
|
||||||
|
.for_each(|(expected, argument)| {
|
||||||
|
self.visit_expression(argument, &Some(expected.get_variable().type_.clone()));
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(ret)
|
||||||
|
} else {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr => self.visit_expression(expr, expected),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
let ret = self.check_expected_circuit(circ.identifier, additional, input.name.span());
|
||||||
|
|
||||||
|
// Check number of circuit members.
|
||||||
|
if circ.members.len() != input.members.len() {
|
||||||
|
self.emit_err(
|
||||||
|
TypeCheckerError::incorrect_num_circuit_members(
|
||||||
|
circ.members.len(),
|
||||||
|
input.members.len(),
|
||||||
|
input.span(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check circuit member types.
|
||||||
|
circ.members
|
||||||
|
.iter()
|
||||||
|
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
||||||
|
// Lookup circuit variable name.
|
||||||
|
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
||||||
|
if let Some(expr) = &actual.expression {
|
||||||
|
self.visit_expression(expr, &Some(ty.clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.handler.emit_err(
|
||||||
|
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(ret)
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(&var.name) {
|
||||||
|
Some(self.assert_and_return_type(Type::Identifier(circuit.identifier), expected, var.span))
|
||||||
|
} else if let Some(var) = self.symbol_table.borrow().lookup_variable(&var.name) {
|
||||||
|
Some(self.assert_and_return_type(var.type_.clone(), expected, var.span))
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Some(match input {
|
||||||
|
LiteralExpression::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
|
||||||
|
LiteralExpression::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
|
||||||
|
LiteralExpression::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
|
||||||
|
LiteralExpression::Integer(type_, str_content, _) => {
|
||||||
|
match type_ {
|
||||||
|
IntegerType::I8 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i8>().is_err() {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I16 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i16>().is_err() {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I32 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i32>().is_err() {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I64 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i64>().is_err() {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I128 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i128>().is_err() {
|
||||||
|
self.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
|
||||||
|
.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
|
||||||
|
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
|
||||||
|
.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
|
||||||
|
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
|
||||||
|
.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
|
||||||
|
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
|
||||||
|
.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
|
||||||
|
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
|
||||||
|
.handler
|
||||||
|
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.assert_and_return_type(Type::IntegerType(*type_), expected, input.span())
|
||||||
|
}
|
||||||
|
LiteralExpression::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
|
||||||
|
LiteralExpression::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
|
||||||
|
LiteralExpression::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
self.visit_expression(&input.condition, &Some(Type::Boolean));
|
||||||
|
|
||||||
|
let t1 = self.visit_expression(&input.if_true, expected);
|
||||||
|
let t2 = self.visit_expression(&input.if_false, expected);
|
||||||
|
|
||||||
|
return_incorrect_type(t1, t2, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_tuple(&mut self, input: &'a TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
// Check the expected tuple types if they are known.
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_types
|
||||||
|
.iter()
|
||||||
|
.zip(input.elements.iter())
|
||||||
|
.for_each(|(expected, expr)| {
|
||||||
|
self.visit_expression(expr, &Some(expected.clone()));
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(Type::Tuple(expected_types.clone()))
|
||||||
|
} else {
|
||||||
|
// Tuples must be explicitly typed in testnet3.
|
||||||
|
self.emit_err(TypeCheckerError::invalid_tuple(input.span()));
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||||
match input.op {
|
match input.op {
|
||||||
UnaryOperation::Abs => {
|
UnaryOperation::Abs => {
|
||||||
@ -521,50 +595,4 @@ 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));
|
|
||||||
|
|
||||||
let t1 = self.visit_expression(&input.if_true, expected);
|
|
||||||
let t2 = self.visit_expression(&input.if_false, expected);
|
|
||||||
|
|
||||||
return_incorrect_type(t1, t2, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
match &*input.function {
|
|
||||||
Expression::Identifier(ident) => {
|
|
||||||
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
|
|
||||||
if let Some(func) = func {
|
|
||||||
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
|
||||||
|
|
||||||
// Check number of function arguments.
|
|
||||||
if func.input.len() != input.arguments.len() {
|
|
||||||
self.handler.emit_err(
|
|
||||||
TypeCheckerError::incorrect_num_args_to_call(
|
|
||||||
func.input.len(),
|
|
||||||
input.arguments.len(),
|
|
||||||
input.span(),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check function argument types.
|
|
||||||
func.input
|
|
||||||
.iter()
|
|
||||||
.zip(input.arguments.iter())
|
|
||||||
.for_each(|(expected, argument)| {
|
|
||||||
self.visit_expression(argument, &Some(expected.get_variable().type_.clone()));
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(ret)
|
|
||||||
} else {
|
|
||||||
self.handler
|
|
||||||
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expr => self.visit_expression(expr, expected),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
|||||||
self.visit_block(&input.block);
|
self.visit_block(&input.block);
|
||||||
|
|
||||||
if !self.has_return {
|
if !self.has_return {
|
||||||
self.handler
|
self.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||||
|
@ -83,8 +83,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
|
|
||||||
Some(var.type_.clone())
|
Some(var.type_.clone())
|
||||||
} else {
|
} else {
|
||||||
self.handler
|
self.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
||||||
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
|
||||||
|
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -85,7 +85,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Emits a type checker error.
|
/// Emits a type checker error.
|
||||||
fn emit_err(&self, err: TypeCheckerError) {
|
pub fn emit_err(&self, err: TypeCheckerError) {
|
||||||
self.handler.emit_err(err.into());
|
self.handler.emit_err(err.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,4 +271,18 @@ create_messages!(
|
|||||||
msg: format!("Comparison `{operator}` is not supported for the address type."),
|
msg: format!("Comparison `{operator}` is not supported for the address type."),
|
||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@formatted
|
||||||
|
incorrect_tuple_length {
|
||||||
|
args: (expected: impl Display, actual: impl Display),
|
||||||
|
msg: format!("Expected a tuple of length `{expected}` got `{actual}`"),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
@formatted
|
||||||
|
invalid_tuple {
|
||||||
|
args: (),
|
||||||
|
msg: format!("Tuples must be explicitly typed in Leo"),
|
||||||
|
help: Some("The function definition must match the function return statement".to_string()),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user