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 }`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CircuitInitExpression {
|
||||
pub struct CircuitExpression {
|
||||
/// The name of the structure type to initialize.
|
||||
pub name: Identifier,
|
||||
/// Initializer expressions for each of the fields in the circuit.
|
||||
@ -50,7 +50,7 @@ pub struct CircuitInitExpression {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for CircuitInitExpression {
|
||||
impl fmt::Display for CircuitExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {{ ", self.name)?;
|
||||
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;
|
||||
pub use ternary::*;
|
||||
|
||||
mod tuple_init;
|
||||
pub use tuple_init::*;
|
||||
|
||||
mod unary;
|
||||
pub use unary::*;
|
||||
|
||||
@ -49,21 +52,23 @@ pub use value::*;
|
||||
pub enum Expression {
|
||||
/// A circuit access expression, e.g., `Foo.bar`.
|
||||
Access(AccessExpression),
|
||||
/// An identifier expression.
|
||||
Identifier(Identifier),
|
||||
/// A literal expression.
|
||||
Literal(LiteralExpression),
|
||||
/// A binary expression, e.g., `42 + 24`.
|
||||
Binary(BinaryExpression),
|
||||
/// A call expression, e.g., `my_fun(args)`.
|
||||
Call(CallExpression),
|
||||
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
|
||||
CircuitInit(CircuitInitExpression),
|
||||
Circuit(CircuitExpression),
|
||||
/// An expression of type "error".
|
||||
/// Will result in a compile error eventually.
|
||||
Err(ErrExpression),
|
||||
/// An identifier.
|
||||
Identifier(Identifier),
|
||||
/// A literal expression.
|
||||
Literal(LiteralExpression),
|
||||
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
||||
Ternary(TernaryExpression),
|
||||
/// A tuple expression e.g., `(foo, 42, true)`.
|
||||
Tuple(TupleExpression),
|
||||
/// An unary expression.
|
||||
Unary(UnaryExpression),
|
||||
}
|
||||
@ -73,13 +78,14 @@ impl Node for Expression {
|
||||
use Expression::*;
|
||||
match self {
|
||||
Access(n) => n.span(),
|
||||
Identifier(n) => n.span(),
|
||||
Literal(n) => n.span(),
|
||||
Binary(n) => n.span(),
|
||||
Call(n) => n.span(),
|
||||
CircuitInit(n) => n.span(),
|
||||
Circuit(n) => n.span(),
|
||||
Err(n) => n.span(),
|
||||
Identifier(n) => n.span(),
|
||||
Literal(n) => n.span(),
|
||||
Ternary(n) => n.span(),
|
||||
Tuple(n) => n.span(),
|
||||
Unary(n) => n.span(),
|
||||
}
|
||||
}
|
||||
@ -88,13 +94,14 @@ impl Node for Expression {
|
||||
use Expression::*;
|
||||
match self {
|
||||
Access(n) => n.set_span(span),
|
||||
Identifier(n) => n.set_span(span),
|
||||
Literal(n) => n.set_span(span),
|
||||
Binary(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),
|
||||
Ternary(n) => n.set_span(span),
|
||||
Tuple(n) => n.set_span(span),
|
||||
Unary(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
@ -105,13 +112,14 @@ impl fmt::Display for Expression {
|
||||
use Expression::*;
|
||||
match &self {
|
||||
Access(n) => n.fmt(f),
|
||||
Identifier(n) => n.fmt(f),
|
||||
Literal(n) => n.fmt(f),
|
||||
Binary(n) => n.fmt(f),
|
||||
Call(n) => n.fmt(f),
|
||||
CircuitInit(n) => n.fmt(f),
|
||||
Circuit(n) => n.fmt(f),
|
||||
Err(n) => n.fmt(f),
|
||||
Identifier(n) => n.fmt(f),
|
||||
Literal(n) => n.fmt(f),
|
||||
Ternary(n) => n.fmt(f),
|
||||
Tuple(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) {
|
||||
match input {
|
||||
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::Call(call) => self.reconstruct_call(call),
|
||||
Expression::CircuitInit(circuit) => self.reconstruct_circuit_init(circuit),
|
||||
Expression::Unary(unary) => self.reconstruct_unary(unary),
|
||||
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
|
||||
Expression::Circuit(circuit) => self.reconstruct_circuit_init(circuit),
|
||||
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) {
|
||||
(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) {
|
||||
(
|
||||
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) {
|
||||
(
|
||||
@ -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) {
|
||||
(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.
|
||||
|
@ -27,15 +27,16 @@ pub trait ExpressionVisitor<'a> {
|
||||
|
||||
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
match input {
|
||||
Expression::Access(expr) => self.visit_access(expr, additional),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
|
||||
Expression::Literal(expr) => self.visit_literal(expr, additional),
|
||||
Expression::Binary(expr) => self.visit_binary(expr, additional),
|
||||
Expression::Unary(expr) => self.visit_unary(expr, additional),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
|
||||
Expression::Call(expr) => self.visit_call(expr, additional),
|
||||
Expression::Err(expr) => self.visit_err(expr, additional),
|
||||
Expression::Access(access) => self.visit_access(access, additional),
|
||||
Expression::Binary(binary) => self.visit_binary(binary, additional),
|
||||
Expression::Call(call) => self.visit_call(call, additional),
|
||||
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, additional),
|
||||
Expression::Err(err) => self.visit_err(err, additional),
|
||||
Expression::Identifier(identifier) => self.visit_identifier(identifier, additional),
|
||||
Expression::Literal(literal) => self.visit_literal(literal, additional),
|
||||
Expression::Ternary(ternary) => self.visit_ternary(ternary, 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()
|
||||
}
|
||||
|
||||
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 {
|
||||
self.visit_expression(&input.left, additional);
|
||||
self.visit_expression(&input.right, additional);
|
||||
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 {
|
||||
input.arguments.iter().for_each(|expr| {
|
||||
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 {
|
||||
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.
|
||||
|
@ -19,10 +19,7 @@ use leo_errors::{AstError, Result};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt,
|
||||
ops::Deref
|
||||
};
|
||||
use std::{fmt, ops::Deref};
|
||||
|
||||
/// A type list of at least two types.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@ -34,7 +31,7 @@ impl Tuple {
|
||||
match elements.len() {
|
||||
0 => Err(AstError::empty_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 {
|
||||
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)
|
||||
})?;
|
||||
|
||||
Ok(Expression::CircuitInit(CircuitInitExpression {
|
||||
Ok(Expression::Circuit(CircuitExpression {
|
||||
span: identifier.span + end,
|
||||
name: identifier,
|
||||
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 {
|
||||
match input {
|
||||
Expression::Access(expr) => self.visit_access(expr, expected),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, expected),
|
||||
Expression::Literal(expr) => self.visit_literal(expr, expected),
|
||||
Expression::Binary(expr) => self.visit_binary(expr, expected),
|
||||
Expression::Call(expr) => self.visit_call(expr, expected),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, expected),
|
||||
Expression::Err(expr) => self.visit_err(expr, expected),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr, expected),
|
||||
Expression::Access(access) => self.visit_access(access, expected),
|
||||
Expression::Binary(binary) => self.visit_binary(binary, expected),
|
||||
Expression::Call(call) => self.visit_call(call, expected),
|
||||
Expression::Circuit(circuit) => self.visit_circuit_init(circuit, expected),
|
||||
Expression::Identifier(identifier) => self.visit_identifier(identifier, expected),
|
||||
Expression::Err(err) => self.visit_err(err, expected),
|
||||
Expression::Literal(literal) => self.visit_literal(literal, 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),
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
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 {
|
||||
match input.op {
|
||||
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);
|
||||
|
||||
if !self.has_return {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||
self.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||
}
|
||||
|
||||
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())
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
||||
self.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
||||
|
||||
None
|
||||
};
|
||||
|
@ -85,7 +85,7 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
|
||||
/// Emits a type checker error.
|
||||
fn emit_err(&self, err: TypeCheckerError) {
|
||||
pub fn emit_err(&self, err: TypeCheckerError) {
|
||||
self.handler.emit_err(err.into());
|
||||
}
|
||||
|
||||
|
@ -271,4 +271,18 @@ create_messages!(
|
||||
msg: format!("Comparison `{operator}` is not supported for the address type."),
|
||||
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