mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-24 07:48:04 +03:00
expressions so far, and clean up, need to appropiately handle binary exprs
This commit is contained in:
parent
5cb4a5d8c0
commit
9c8ac64871
@ -51,10 +51,6 @@ impl Node for Identifier {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Identifier {
|
||||
|
@ -14,8 +14,6 @@
|
||||
// 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 leo_errors::TypeCheckerError;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A binary operator.
|
||||
@ -158,23 +156,4 @@ impl Node for BinaryExpression {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
match self.op.class() {
|
||||
BinaryOperationClass::Boolean => Ok(Some(Type::Boolean)),
|
||||
BinaryOperationClass::Numeric => {
|
||||
let left = self.left.get_type()?;
|
||||
let right = self.right.get_type()?;
|
||||
|
||||
match (left, right) {
|
||||
(Some(t1), Some(t2)) if t1 == t2 => Ok(Some(t1)),
|
||||
(None, None) => Ok(None),
|
||||
(Some(t1), Some(t2)) => Err(TypeCheckerError::types_do_not_match(t1, t2, self.span()).into()),
|
||||
(None, Some(t)) | (Some(t), None) => {
|
||||
Err(TypeCheckerError::type_expected_but_not_found(t, self.span()).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +49,4 @@ impl Node for CallExpression {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,4 @@ impl Node for ErrExpression {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
// 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::{GroupValue, Identifier, IntegerType, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use crate::{GroupValue, Identifier, IntegerType, Node};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -80,19 +79,6 @@ impl Node for Expression {
|
||||
Err(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
use Expression::*;
|
||||
match self {
|
||||
Identifier(n) => n.get_type(),
|
||||
Value(n) => n.get_type(),
|
||||
Binary(n) => n.get_type(),
|
||||
Unary(n) => n.get_type(),
|
||||
Ternary(n) => n.get_type(),
|
||||
Call(n) => n.get_type(),
|
||||
Err(n) => n.get_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Expression {
|
||||
|
@ -43,8 +43,4 @@ impl Node for TernaryExpression {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,6 @@ pub enum UnaryOperation {
|
||||
Not,
|
||||
/// The arithmetic negation operator, i.e., `-`.
|
||||
Negate,
|
||||
/// The bitwise negation operator, i.e., `~`.
|
||||
/// For example, it transforms `1010` to `0101`.
|
||||
BitNot,
|
||||
}
|
||||
|
||||
impl AsRef<str> for UnaryOperation {
|
||||
@ -34,7 +31,6 @@ impl AsRef<str> for UnaryOperation {
|
||||
match self {
|
||||
UnaryOperation::Not => "!",
|
||||
UnaryOperation::Negate => "-",
|
||||
UnaryOperation::BitNot => "~",
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,8 +60,4 @@ impl Node for UnaryExpression {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
self.inner.get_type()
|
||||
}
|
||||
}
|
||||
|
@ -85,17 +85,4 @@ impl Node for ValueExpression {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
use ValueExpression::*;
|
||||
Ok(Some(match &self {
|
||||
Address(_, _) => Type::Address,
|
||||
Boolean(_, _) => Type::Boolean,
|
||||
Char(_) => Type::Char,
|
||||
Field(_, _) => Type::Field,
|
||||
Integer(type_, _, _) => Type::IntegerType(*type_),
|
||||
Group(_) => Type::Group,
|
||||
String(_, _) => return Ok(None),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Block, FunctionInput, Identifier, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use leo_span::{sym, Span, Symbol};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -93,8 +92,4 @@ impl Node for Function {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
Ok(Some(self.output.clone()))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Identifier, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -96,8 +95,4 @@ impl Node for FunctionInputVariable {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
Ok(Some(self.type_.clone()))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{FunctionInputVariable, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -84,11 +83,4 @@ impl Node for FunctionInput {
|
||||
Variable(variable) => variable.span = span,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
use FunctionInput::*;
|
||||
match self {
|
||||
Variable(variable) => variable.get_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,8 @@
|
||||
// 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 leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use crate::Type;
|
||||
|
||||
/// A node in the AST.
|
||||
pub trait Node:
|
||||
std::fmt::Debug + std::fmt::Display + Clone + PartialEq + Eq + serde::Serialize + serde::de::DeserializeOwned
|
||||
@ -28,7 +25,4 @@ pub trait Node:
|
||||
|
||||
/// Sets the span of the node.
|
||||
fn set_span(&mut self, span: Span);
|
||||
|
||||
/// Gets the type of the node if it exists.
|
||||
fn get_type(&self) -> Result<Option<Type>>;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -109,8 +108,4 @@ impl Node for AssignStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
self.value.get_type()
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
// 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::{Node, Statement, Type};
|
||||
use leo_errors::Result;
|
||||
use crate::{Node, Statement};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -52,8 +51,4 @@ impl Node for Block {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Block, Expression, Node, Statement};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -52,8 +51,4 @@ impl Node for ConditionalStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Char, Expression, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -55,8 +54,4 @@ impl Node for ConsoleArgs {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ConsoleArgs, Expression, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -59,8 +58,4 @@ impl Node for ConsoleFunction {
|
||||
ConsoleFunction::Error(formatted) | ConsoleFunction::Log(formatted) => formatted.set_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ConsoleFunction, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -50,8 +49,4 @@ impl Node for ConsoleStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -73,8 +72,4 @@ impl Node for DefinitionStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
Ok(Some(self.type_.clone()))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Identifier, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -46,8 +45,4 @@ impl Node for VariableName {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -44,8 +43,4 @@ impl Node for ExpressionStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
self.expression.get_type()
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Block, Expression, Identifier, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -60,8 +59,4 @@ impl Node for IterationStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
Ok(Some(self.type_.clone()))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Node};
|
||||
use leo_errors::Result;
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -44,8 +43,4 @@ impl Node for ReturnStatement {
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<crate::Type>> {
|
||||
self.expression.get_type()
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
// 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::{ConditionalStatement, Node, Type};
|
||||
use leo_errors::Result;
|
||||
use crate::{ConditionalStatement, Node};
|
||||
use leo_span::Span;
|
||||
|
||||
use super::*;
|
||||
@ -87,18 +86,4 @@ impl Node for Statement {
|
||||
Block(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type(&self) -> Result<Option<Type>> {
|
||||
use Statement::*;
|
||||
match self {
|
||||
Return(n) => n.get_type(),
|
||||
Definition(n) => n.get_type(),
|
||||
Assign(n) => n.get_type(),
|
||||
Conditional(n) => n.get_type(),
|
||||
Iteration(n) => n.get_type(),
|
||||
Console(n) => n.get_type(),
|
||||
Expression(n) => n.get_type(),
|
||||
Block(n) => n.get_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
129
compiler/passes/src/type_checker/check_expressions.rs
Normal file
129
compiler/passes/src/type_checker/check_expressions.rs
Normal file
@ -0,0 +1,129 @@
|
||||
// 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 leo_ast::*;
|
||||
use leo_errors::TypeCheckerError;
|
||||
use leo_span::Span;
|
||||
|
||||
use crate::TypeChecker;
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
pub(crate) fn compare_expr_type(&self, expr: &Expression, expected: Type, span: &Span) {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) {
|
||||
self.assert_type(var.type_.clone(), expected, var.span);
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", ident.name, span).into());
|
||||
}
|
||||
}
|
||||
Expression::Value(value) => match value {
|
||||
ValueExpression::Address(_, _) => self.assert_type(Type::Address, expected, value.span()),
|
||||
ValueExpression::Boolean(_, _) => self.assert_type(Type::Boolean, expected, value.span()),
|
||||
ValueExpression::Char(_) => self.assert_type(Type::Char, expected, value.span()),
|
||||
ValueExpression::Field(_, _) => self.assert_type(Type::Field, expected, value.span()),
|
||||
ValueExpression::Integer(type_, _, _) => {
|
||||
self.assert_type(Type::IntegerType(*type_), expected, value.span())
|
||||
}
|
||||
ValueExpression::Group(_) => self.assert_type(Type::Group, expected, value.span()),
|
||||
ValueExpression::String(_, _) => {}
|
||||
},
|
||||
Expression::Binary(binary) => match binary.op.class() {
|
||||
// some ops support more types than listed here
|
||||
BinaryOperationClass::Boolean => {
|
||||
self.assert_type(Type::Boolean, expected, span);
|
||||
self.compare_expr_type(&binary.left, Type::Boolean, binary.span());
|
||||
self.compare_expr_type(&binary.right, Type::Boolean, binary.span());
|
||||
}
|
||||
BinaryOperationClass::Numeric => {
|
||||
// depending on operation could also be field or group
|
||||
if !matches!(expected, Type::IntegerType(_)) {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be_integer(binary.op, expected.clone(), span).into());
|
||||
}
|
||||
|
||||
self.compare_expr_type(&binary.left, expected.clone(), binary.span());
|
||||
self.compare_expr_type(&binary.right, expected, binary.span());
|
||||
}
|
||||
},
|
||||
Expression::Unary(unary) => match unary.op {
|
||||
UnaryOperation::Not => {
|
||||
self.assert_type(Type::Boolean, expected, unary.span());
|
||||
self.compare_expr_type(&unary.inner, Type::Boolean, unary.inner.span());
|
||||
}
|
||||
UnaryOperation::Negate => {
|
||||
match expected {
|
||||
Type::IntegerType(
|
||||
IntegerType::I8
|
||||
| IntegerType::I16
|
||||
| IntegerType::I32
|
||||
| IntegerType::I64
|
||||
| IntegerType::I128,
|
||||
)
|
||||
| Type::Field
|
||||
| Type::Group => {}
|
||||
_ => self.handler.emit_err(
|
||||
TypeCheckerError::type_is_not_negatable(expected.clone(), unary.inner.span()).into(),
|
||||
),
|
||||
}
|
||||
self.compare_expr_type(&unary.inner, expected, unary.inner.span());
|
||||
}
|
||||
},
|
||||
Expression::Ternary(ternary) => {
|
||||
self.compare_expr_type(&ternary.condition, Type::Boolean, ternary.condition.span());
|
||||
self.compare_expr_type(&ternary.if_true, expected.clone(), ternary.if_true.span());
|
||||
self.compare_expr_type(&ternary.if_false, expected, ternary.if_false.span());
|
||||
}
|
||||
Expression::Call(call) => match &*call.function {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(func) = self.symbol_table.lookup_fn(&ident.name) {
|
||||
self.assert_type(func.output.clone(), expected, ident.span());
|
||||
|
||||
if func.input.len() != call.arguments.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
func.input.len(),
|
||||
call.arguments.len(),
|
||||
call.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
func.input
|
||||
.iter()
|
||||
.zip(call.arguments.iter())
|
||||
.for_each(|(expected, argument)| {
|
||||
self.compare_expr_type(
|
||||
argument,
|
||||
expected.get_variable().type_.clone(),
|
||||
argument.span(),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
|
||||
}
|
||||
}
|
||||
expr => self.compare_expr_type(expr, expected, call.span()),
|
||||
},
|
||||
Expression::Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {}
|
42
compiler/passes/src/type_checker/check_file.rs
Normal file
42
compiler/passes/src/type_checker/check_file.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 leo_ast::*;
|
||||
|
||||
use crate::{Declaration, TypeChecker, VariableSymbol};
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function) -> VisitResult {
|
||||
self.symbol_table.clear_variables();
|
||||
self.parent = Some(input.name());
|
||||
input.input.iter().for_each(|i| {
|
||||
let input_var = i.get_variable();
|
||||
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input_var.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: &input_var.type_,
|
||||
span: input_var.span(),
|
||||
declaration: Declaration::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
}
|
@ -15,73 +15,10 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::{Result, TypeCheckerError};
|
||||
use leo_span::Span;
|
||||
use leo_errors::TypeCheckerError;
|
||||
|
||||
use crate::{Declaration, TypeChecker, VariableSymbol};
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
fn compare_types(&self, t1: Result<Option<Type>>, t2: Result<Option<Type>>, span: &Span) {
|
||||
match (t1, t2) {
|
||||
(Ok(Some(t1)), Ok(Some(t2))) if t1 != t2 => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::types_do_not_match(t1, t2, span).into()),
|
||||
(Ok(Some(t)), Ok(None)) | (Ok(None), Ok(Some(t))) => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_expected_but_not_found(t, span).into()),
|
||||
(Err(err), Ok(None)) | (Ok(None), Err(err)) => self.handler.emit_err(err),
|
||||
(Err(err1), Err(err2)) => {
|
||||
self.handler.emit_err(err1);
|
||||
self.handler.emit_err(err2);
|
||||
}
|
||||
// Types match
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_type(&self, type_: Result<Option<Type>>, expected: Type, span: &Span) {
|
||||
match type_ {
|
||||
Ok(Some(type_)) if type_ != expected => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into()),
|
||||
// Types match
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_expr_type(&self, compare: Result<Option<Type>>, expr: &Expression, span: &Span) {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) {
|
||||
self.assert_type(compare, var.type_.clone(), span);
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_returnee(ident.name, span).into());
|
||||
}
|
||||
}
|
||||
expr => self.compare_types(compare, expr.get_type(), span),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_expr_type(&self, expr: &Expression, expected: Type, span: &Span) {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(var) = self.symbol_table.lookup_variable(&ident.name) {
|
||||
if var.type_ != &expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(var.type_, expected, span).into());
|
||||
}
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_returnee(ident.name, span).into());
|
||||
}
|
||||
}
|
||||
expr => self.assert_type(expr.get_type(), expected, span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {}
|
||||
|
||||
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_return(&mut self, input: &'a ReturnStatement) -> VisitResult {
|
||||
@ -90,7 +27,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
let parent = self.parent.unwrap();
|
||||
|
||||
if let Some(func) = self.symbol_table.lookup_fn(&parent) {
|
||||
self.compare_expr_type(func.get_type(), &input.expression, input.span());
|
||||
self.compare_expr_type(&input.expression, func.output.clone(), input.expression.span());
|
||||
}
|
||||
|
||||
VisitResult::VisitChildren
|
||||
@ -115,7 +52,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
self.compare_types(input.get_type(), input.get_type(), input.span());
|
||||
self.compare_expr_type(&input.value, input.type_.clone(), input.value.span());
|
||||
});
|
||||
|
||||
VisitResult::VisitChildren
|
||||
@ -134,17 +71,18 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.assert_expr_type(&input.value, var.type_.clone(), input.span())
|
||||
self.compare_expr_type(&input.value, var.type_.clone(), input.value.span())
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_assignee(&input.assignee.identifier.name, input.span()).into())
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, &input.assignee.span).into(),
|
||||
)
|
||||
}
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
|
||||
fn visit_conditional(&mut self, input: &'a ConditionalStatement) -> VisitResult {
|
||||
self.assert_expr_type(&input.condition, Type::Boolean, input.span());
|
||||
self.compare_expr_type(&input.condition, Type::Boolean, input.condition.span());
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
@ -161,10 +99,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
let iter_var_type = input.get_type();
|
||||
|
||||
self.compare_expr_type(iter_var_type.clone(), &input.start, input.span());
|
||||
self.compare_expr_type(iter_var_type, &input.stop, input.span());
|
||||
self.compare_expr_type(&input.start, input.type_.clone(), input.start.span());
|
||||
self.compare_expr_type(&input.stop, input.type_.clone(), input.stop.span());
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
@ -172,7 +108,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_console(&mut self, input: &'a ConsoleStatement) -> VisitResult {
|
||||
match &input.function {
|
||||
ConsoleFunction::Assert(expr) => {
|
||||
self.assert_expr_type(expr, Type::Boolean, expr.span());
|
||||
self.compare_expr_type(expr, Type::Boolean, expr.span());
|
||||
}
|
||||
ConsoleFunction::Error(_) | ConsoleFunction::Log(_) => {
|
||||
todo!("need to discuss this");
|
||||
@ -182,6 +118,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
|
||||
fn visit_expression_statement(&mut self, _input: &'a ExpressionStatement) -> VisitResult {
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, input: &'a Block) -> VisitResult {
|
||||
self.symbol_table.push_variable_scope();
|
||||
// have to redo the logic here so we have scoping
|
||||
@ -201,27 +141,4 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function) -> VisitResult {
|
||||
self.symbol_table.clear_variables();
|
||||
self.parent = Some(input.name());
|
||||
input.input.iter().for_each(|i| {
|
||||
let input_var = i.get_variable();
|
||||
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input_var.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: &input_var.type_,
|
||||
span: input_var.span(),
|
||||
declaration: Declaration::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
}
|
||||
}
|
@ -14,8 +14,9 @@
|
||||
// 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 leo_errors::emitter::Handler;
|
||||
use leo_span::Symbol;
|
||||
use leo_ast::Type;
|
||||
use leo_errors::{emitter::Handler, TypeCheckerError};
|
||||
use leo_span::{Symbol, Span};
|
||||
|
||||
use crate::SymbolTable;
|
||||
|
||||
@ -33,4 +34,11 @@ impl<'a> TypeChecker<'a> {
|
||||
parent: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn assert_type(&self, type_: Type, expected: Type, span: &Span) {
|
||||
if type_ != expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
pub mod check;
|
||||
pub use check::*;
|
||||
pub mod check_expressions;
|
||||
pub use check_expressions::*;
|
||||
|
||||
pub mod check_file;
|
||||
pub use check_file::*;
|
||||
|
||||
pub mod check_statements;
|
||||
pub use check_statements::*;
|
||||
|
||||
pub mod checker;
|
||||
pub use checker::*;
|
||||
|
@ -23,36 +23,6 @@ create_messages!(
|
||||
code_mask: 2000i32,
|
||||
code_prefix: "TYC",
|
||||
|
||||
/// For when types do not match.
|
||||
@formatted
|
||||
types_do_not_match {
|
||||
args: (lhs: impl Display, rhs: impl Display),
|
||||
msg: format!(
|
||||
"unexpected type, lhs type is: '{lhs}', but rhs type is: '{rhs}'",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when types do not match.
|
||||
@formatted
|
||||
type_expected_but_not_found {
|
||||
args: (known: impl Display),
|
||||
msg: format!(
|
||||
"One side has type: '{known}', but the other has no type",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries to assign to a unknown variable.
|
||||
@formatted
|
||||
unknown_assignee {
|
||||
args: (var: impl Display),
|
||||
msg: format!(
|
||||
"Unknown assignee `{var}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries to assign to a const input.
|
||||
@formatted
|
||||
cannont_assign_to_const_input {
|
||||
@ -85,10 +55,40 @@ create_messages!(
|
||||
|
||||
/// For when the user tries to return a unknown variable.
|
||||
@formatted
|
||||
unknown_returnee {
|
||||
args: (var: impl Display),
|
||||
unknown_sym {
|
||||
args: (kind: impl Display, sym: impl Display),
|
||||
msg: format!(
|
||||
"Unknown returnee `{var}`",
|
||||
"Unknown {kind} `{sym}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries to expect a non integer type .
|
||||
@formatted
|
||||
type_should_be_integer {
|
||||
args: (op: impl Debug, type_: impl Display),
|
||||
msg: format!(
|
||||
"Binary statement has numeric operation `{op:?}` but has expected type `{type_}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries to negate a non negatable type.
|
||||
@formatted
|
||||
type_is_not_negatable {
|
||||
args: (type_: impl Display),
|
||||
msg: format!(
|
||||
"The type `{type_}` is not negatable",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries calls a function with the incorrect number of args.
|
||||
@formatted
|
||||
incorrect_num_args_to_call {
|
||||
args: (expected: impl Display, received: impl Display),
|
||||
msg: format!(
|
||||
"Call expected `{expected}` args, got `{received}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user