From ca2eeb9e5033d46974ad76eb28fcec61296be24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vili=20Sinerv=C3=A4?= Date: Tue, 4 Feb 2025 18:45:17 +0200 Subject: [PATCH] Encapsulate expressions in AstNode struct --- src/compiler/ast.rs | 121 ++++++++++++++++------------------- src/compiler/interpreter.rs | 36 +++++------ src/compiler/parser/mod.rs | 87 +++++++++++++------------ src/compiler/parser/tests.rs | 33 ++++++---- src/compiler/type_checker.rs | 33 +++++----- 5 files changed, 153 insertions(+), 157 deletions(-) diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index ea3fe42..8d5e4d4 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -1,4 +1,5 @@ use crate::compiler::token::CodeLocation; +use crate::compiler::variable::Type; use std::fmt; #[derive(Debug, PartialEq)] @@ -7,57 +8,55 @@ pub enum TypeExpression { Bool(CodeLocation), } +#[derive(Debug, PartialEq)] +pub struct AstNode<'source> { + pub loc: CodeLocation, + pub node_type: Type, + pub expr: Expression<'source>, +} + +impl<'source> AstNode<'source> { + pub fn new(loc: CodeLocation, expr: Expression<'source>) -> AstNode<'source> { + AstNode { + loc, + expr, + node_type: Type::Unit, + } + } +} + +impl<'source> fmt::Display for AstNode<'source> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {} at {}", + self.expr.expr_type_str(), + self.expr.val_string(), + self.loc + ) + } +} + #[derive(Debug, PartialEq)] pub enum Expression<'source> { - EmptyLiteral(CodeLocation), - IntLiteral(CodeLocation, i64), - BoolLiteral(CodeLocation, bool), - Identifier(CodeLocation, &'source str), - UnaryOp(CodeLocation, &'source str, Box>), - BinaryOp( - CodeLocation, - Box>, - &'source str, - Box>, - ), - VarDeclaration( - CodeLocation, - &'source str, - Box>, - Option, - ), + EmptyLiteral(), + IntLiteral(i64), + BoolLiteral(bool), + Identifier(&'source str), + UnaryOp(&'source str, Box>), + BinaryOp(Box>, &'source str, Box>), + VarDeclaration(&'source str, Box>, Option), Conditional( - CodeLocation, - Box>, - Box>, - Option>>, + Box>, + Box>, + Option>>, ), - While( - CodeLocation, - Box>, - Box>, - ), - FunCall(CodeLocation, &'source str, Vec>), - Block(CodeLocation, Vec>), + While(Box>, Box>), + FunCall(&'source str, Vec>), + Block(Vec>), } impl<'source> Expression<'source> { - pub fn loc(&self) -> CodeLocation { - match self { - Expression::EmptyLiteral(loc) => *loc, - Expression::IntLiteral(loc, _) => *loc, - Expression::BoolLiteral(loc, _) => *loc, - Expression::Identifier(loc, _) => *loc, - Expression::UnaryOp(loc, _, _) => *loc, - Expression::VarDeclaration(loc, _, _, _) => *loc, - Expression::BinaryOp(loc, _, _, _) => *loc, - Expression::Conditional(loc, _, _, _) => *loc, - Expression::While(loc, _, _) => *loc, - Expression::FunCall(loc, _, _) => *loc, - Expression::Block(loc, _) => *loc, - } - } - fn expr_type_str(&self) -> &str { match self { Expression::EmptyLiteral(..) => "Empty literal", @@ -68,7 +67,7 @@ impl<'source> Expression<'source> { Expression::VarDeclaration(..) => "Variable declaration", Expression::BinaryOp(..) => "Binary operation", Expression::Conditional(..) => "Conditional", - Expression::While(_, _, _) => "While loop", + Expression::While(..) => "While loop", Expression::FunCall(..) => "Function call", Expression::Block(..) => "Block", } @@ -77,28 +76,16 @@ impl<'source> Expression<'source> { fn val_string(&self) -> String { match self { Expression::EmptyLiteral(..) => "".to_string(), - Expression::IntLiteral(_, val) => val.to_string(), - Expression::BoolLiteral(_, val) => val.to_string(), - Expression::Identifier(_, name) => name.to_string(), - Expression::UnaryOp(_, op, _) => op.to_string(), - Expression::VarDeclaration(_, name, _, _) => name.to_string(), - Expression::BinaryOp(_, _, op, _) => op.to_string(), - Expression::Conditional(_, condition, _, _) => format!("if {}", condition), - Expression::While(_, condition, _) => format!("while {}", condition), - Expression::FunCall(_, name, args) => format!("{} with {} args", name, args.len()), - Expression::Block(_, expressions) => format!("with {} expressions", expressions.len()), + Expression::IntLiteral(val) => val.to_string(), + Expression::BoolLiteral(val) => val.to_string(), + Expression::Identifier(name) => name.to_string(), + Expression::UnaryOp(op, _) => op.to_string(), + Expression::VarDeclaration(name, _, _) => name.to_string(), + Expression::BinaryOp(_, op, _) => op.to_string(), + Expression::Conditional(condition, _, _) => format!("if {:?}", condition), + Expression::While(condition, _) => format!("while {:?}", condition), + Expression::FunCall(name, args) => format!("{} with {} args", name, args.len()), + Expression::Block(expressions) => format!("with {} expressions", expressions.len()), } } } - -impl<'source> fmt::Display for Expression<'source> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} at {}", - self.expr_type_str(), - self.val_string(), - self.loc() - ) - } -} diff --git a/src/compiler/interpreter.rs b/src/compiler/interpreter.rs index ce92f4d..d545fec 100644 --- a/src/compiler/interpreter.rs +++ b/src/compiler/interpreter.rs @@ -1,19 +1,19 @@ use crate::compiler::{ - ast::Expression::{self, *}, + ast::{ + AstNode, + Expression::{self, *}, + }, symtab::SymTab, variable::Value, }; -pub fn interpret<'source>( - ast: &Expression<'source>, - symbols: &mut SymTab<'source, Value>, -) -> Value { - match ast { - EmptyLiteral(_) => Value::None(), - IntLiteral(_, val) => Value::Int(*val), - BoolLiteral(_, val) => Value::Bool(*val), - Identifier(_, name) => *symbols.get(name), - UnaryOp(_, op, expr) => match *op { +pub fn interpret<'source>(ast: &AstNode<'source>, symbols: &mut SymTab<'source, Value>) -> Value { + match &ast.expr { + EmptyLiteral() => Value::None(), + IntLiteral(val) => Value::Int(*val), + BoolLiteral(val) => Value::Bool(*val), + Identifier(name) => *symbols.get(name), + UnaryOp(op, expr) => match *op { "-" => { let Value::Func(op_fn) = symbols.get("neg") else { panic!("Operator {} does not correspond to a function!", op); @@ -27,7 +27,7 @@ pub fn interpret<'source>( op_fn(&[interpret(expr, symbols)]) } }, - BinaryOp(_, left, op, right) => match *op { + BinaryOp(left, op, right) => match *op { "and" => { let left_val = interpret(left, symbols); if let Value::Bool(left_val) = left_val { @@ -63,7 +63,7 @@ pub fn interpret<'source>( } } "=" => { - if let Expression::Identifier(_, name) = **left { + if let Expression::Identifier(name) = left.expr { let val = interpret(right, symbols); *symbols.get(name) = val; val @@ -78,12 +78,12 @@ pub fn interpret<'source>( op_fn(&[interpret(left, symbols), interpret(right, symbols)]) } }, - VarDeclaration(_, name, expr, _) => { + VarDeclaration(name, expr, _) => { let val = interpret(expr, symbols); symbols.insert(name, val); Value::None() } - Conditional(_, condition_expr, then_expr, else_expr) => { + Conditional(condition_expr, then_expr, else_expr) => { let Value::Bool(condition) = interpret(condition_expr, symbols) else { panic!("Non-bool as if-then-else condition!"); }; @@ -101,7 +101,7 @@ pub fn interpret<'source>( Value::None() } } - While(_, condition, do_expr) => { + While(condition, do_expr) => { loop { let condition = interpret(condition, symbols); if let Value::Bool(cond) = condition { @@ -116,7 +116,7 @@ pub fn interpret<'source>( } Value::None() } - FunCall(_, name, args) => { + FunCall(name, args) => { let mut arg_values = Vec::new(); for arg in args { arg_values.push(interpret(arg, symbols)); @@ -128,7 +128,7 @@ pub fn interpret<'source>( function(&arg_values) } - Block(_, expressions) => { + Block(expressions) => { symbols.push_level(); let mut val = Value::None(); diff --git a/src/compiler/parser/mod.rs b/src/compiler/parser/mod.rs index ad2a7fb..b616bb6 100644 --- a/src/compiler/parser/mod.rs +++ b/src/compiler/parser/mod.rs @@ -4,14 +4,15 @@ mod tests; use crate::compiler::{ ast::{ - Expression::{self, *}, + AstNode, + Expression::*, TypeExpression::{self}, }, parser::parser_utilities::*, token::{Token, TokenType}, }; -pub fn parse<'source>(tokens: &[Token<'source>]) -> Expression<'source> { +pub fn parse<'source>(tokens: &[Token<'source>]) -> AstNode<'source> { let mut pos = 0; let first_expression = parse_block_level_expressions(&mut pos, tokens); @@ -47,10 +48,10 @@ pub fn parse<'source>(tokens: &[Token<'source>]) -> Expression<'source> { let last_token = peek(&mut (pos - 1), tokens); if last_token.text == ";" { - expressions.push(EmptyLiteral(last_token.loc)); + expressions.push(AstNode::new(last_token.loc, EmptyLiteral())); } - Block(tokens[0].loc, expressions) + AstNode::new(tokens[0].loc, Block(expressions)) } else { first_expression } @@ -61,7 +62,7 @@ pub fn parse<'source>(tokens: &[Token<'source>]) -> Expression<'source> { fn parse_block_level_expressions<'source>( pos: &mut usize, tokens: &[Token<'source>], -) -> Expression<'source> { +) -> AstNode<'source> { // Special handling for variable declaration, since it is only allowed in very specifc places if peek(pos, tokens).text == "var" { parse_var_declaration(pos, tokens) @@ -74,7 +75,7 @@ fn parse_expression<'source>( level: usize, pos: &mut usize, tokens: &[Token<'source>], -) -> Expression<'source> { +) -> AstNode<'source> { const OPS: [&[&str]; 8] = [ &["="], // 0 &["or"], // 1 @@ -93,11 +94,9 @@ fn parse_expression<'source>( if OPS[level].contains(&peek(pos, tokens).text) { let operator_token = consume_strings(pos, tokens, OPS[level]); let right = parse_expression(level, pos, tokens); - BinaryOp( + AstNode::new( operator_token.loc, - Box::new(left), - operator_token.text, - Box::new(right), + BinaryOp(Box::new(left), operator_token.text, Box::new(right)), ) } else { left @@ -109,11 +108,9 @@ fn parse_expression<'source>( let operator_token = consume_strings(pos, tokens, OPS[level]); let right = parse_expression(level + 1, pos, tokens); - left = BinaryOp( + left = AstNode::new( operator_token.loc, - Box::new(left), - operator_token.text, - Box::new(right), + BinaryOp(Box::new(left), operator_token.text, Box::new(right)), ); } left @@ -122,7 +119,10 @@ fn parse_expression<'source>( if OPS[level].contains(&peek(pos, tokens).text) { let operator_token = consume_strings(pos, tokens, OPS[level]); let right = parse_expression(level, pos, tokens); - UnaryOp(operator_token.loc, operator_token.text, Box::new(right)) + AstNode::new( + operator_token.loc, + UnaryOp(operator_token.text, Box::new(right)), + ) } else { parse_expression(level + 1, pos, tokens) } @@ -132,7 +132,7 @@ fn parse_expression<'source>( } } -fn parse_term<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_term<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let token = peek(pos, tokens); match token.token_type { @@ -159,10 +159,7 @@ fn parse_term<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression } } -fn parse_var_declaration<'source>( - pos: &mut usize, - tokens: &[Token<'source>], -) -> Expression<'source> { +fn parse_var_declaration<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { consume_string(pos, tokens, "var"); let name_token = consume_type(pos, tokens, TokenType::Identifier); @@ -180,10 +177,13 @@ fn parse_var_declaration<'source>( consume_string(pos, tokens, "="); let value = parse_expression(0, pos, tokens); - VarDeclaration(name_token.loc, name_token.text, Box::new(value), type_expr) + AstNode::new( + name_token.loc, + VarDeclaration(name_token.text, Box::new(value), type_expr), + ) } -fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let start = consume_string(pos, tokens, "if"); let condition = Box::new(parse_expression(0, pos, tokens)); consume_string(pos, tokens, "then"); @@ -197,26 +197,26 @@ fn parse_conditional<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Exp _ => None, }; - Conditional(start.loc, condition, then_expr, else_expr) + AstNode::new(start.loc, Conditional(condition, then_expr, else_expr)) } -fn parse_while_loop<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_while_loop<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let start = consume_string(pos, tokens, "while"); let condition = Box::new(parse_expression(0, pos, tokens)); consume_string(pos, tokens, "do"); let do_expr = Box::new(parse_expression(0, pos, tokens)); - While(start.loc, condition, do_expr) + AstNode::new(start.loc, While(condition, do_expr)) } -fn parse_parenthesized<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_parenthesized<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { consume_string(pos, tokens, "("); let expression = parse_expression(0, pos, tokens); consume_string(pos, tokens, ")"); expression } -fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let start = consume_string(pos, tokens, "{"); let mut expressions = Vec::new(); @@ -240,16 +240,16 @@ fn parse_block<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expressio // If the last expression of the block ended in a semicolon, empty return let next_token = peek(pos, tokens); if next_token.text == "}" { - expressions.push(EmptyLiteral(next_token.loc)); + expressions.push(AstNode::new(next_token.loc, EmptyLiteral())); break; } } consume_string(pos, tokens, "}"); - Block(start.loc, expressions) + AstNode::new(start.loc, Block(expressions)) } -fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let identifier = consume_type(pos, tokens, TokenType::Identifier); consume_string(pos, tokens, "("); @@ -266,32 +266,35 @@ fn parse_function<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expres } } consume_string(pos, tokens, ")"); - FunCall(identifier.loc, identifier.text, arguments) + AstNode::new(identifier.loc, FunCall(identifier.text, arguments)) } -fn parse_int_literal<'source>(pos: &mut usize, tokens: &[Token]) -> Expression<'source> { +fn parse_int_literal<'source>(pos: &mut usize, tokens: &[Token]) -> AstNode<'source> { let token = consume_type(pos, tokens, TokenType::Integer); - IntLiteral( - token.loc, + let expr = IntLiteral( token .text .parse::() .unwrap_or_else(|_| panic!("Fatal parser error! Invalid value in token {token}")), - ) + ); + + AstNode::new(token.loc, expr) } -fn parse_bool_literal<'source>(pos: &mut usize, tokens: &[Token]) -> Expression<'source> { +fn parse_bool_literal<'source>(pos: &mut usize, tokens: &[Token]) -> AstNode<'source> { let token = consume_type(pos, tokens, TokenType::Identifier); - match token.text { - "true" => BoolLiteral(token.loc, true), - "false" => BoolLiteral(token.loc, false), + let expr = match token.text { + "true" => BoolLiteral(true), + "false" => BoolLiteral(false), _ => panic!("Fatal parser error! Expected bool literal but found {token}"), - } + }; + + AstNode::new(token.loc, expr) } -fn parse_identifier<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> Expression<'source> { +fn parse_identifier<'source>(pos: &mut usize, tokens: &[Token<'source>]) -> AstNode<'source> { let token = consume_type(pos, tokens, TokenType::Identifier); - Identifier(token.loc, token.text) + AstNode::new(token.loc, Identifier(token.text)) } diff --git a/src/compiler/parser/tests.rs b/src/compiler/parser/tests.rs index 5dfa1f7..3fb08b1 100644 --- a/src/compiler/parser/tests.rs +++ b/src/compiler/parser/tests.rs @@ -3,7 +3,7 @@ use crate::compiler::{token::CodeLocation, tokenizer::tokenize}; macro_rules! bool_ast { ($x:expr) => { - BoolLiteral(CodeLocation::new(usize::MAX, usize::MAX), $x) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), BoolLiteral($x)) }; } @@ -15,7 +15,7 @@ macro_rules! bool_ast_b { macro_rules! int_ast { ($x:expr) => { - IntLiteral(CodeLocation::new(usize::MAX, usize::MAX), $x) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), IntLiteral($x)) }; } @@ -27,7 +27,7 @@ macro_rules! int_ast_b { macro_rules! id_ast { ($x:expr) => { - Identifier(CodeLocation::new(usize::MAX, usize::MAX), $x) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), Identifier($x)) }; } @@ -39,7 +39,7 @@ macro_rules! id_ast_b { macro_rules! un_ast { ($x:expr, $y:expr) => { - UnaryOp(CodeLocation::new(usize::MAX, usize::MAX), $x, $y) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), UnaryOp($x, $y)) }; } @@ -51,7 +51,10 @@ macro_rules! un_ast_b { macro_rules! bin_ast { ($x:expr, $y:expr, $z:expr) => { - BinaryOp(CodeLocation::new(usize::MAX, usize::MAX), $x, $y, $z) + AstNode::new( + CodeLocation::new(usize::MAX, usize::MAX), + BinaryOp($x, $y, $z), + ) }; } @@ -63,7 +66,10 @@ macro_rules! bin_ast_b { macro_rules! con_ast { ($x:expr, $y:expr, $z:expr) => { - Conditional(CodeLocation::new(usize::MAX, usize::MAX), $x, $y, $z) + AstNode::new( + CodeLocation::new(usize::MAX, usize::MAX), + Conditional($x, $y, $z), + ) }; } @@ -75,7 +81,7 @@ macro_rules! con_ast_b { macro_rules! fun_ast { ($x:expr, $y:expr) => { - FunCall(CodeLocation::new(usize::MAX, usize::MAX), $x, $y) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), FunCall($x, $y)) }; } @@ -87,7 +93,7 @@ macro_rules! fun_ast_b { macro_rules! block_ast { ($x:expr) => { - Block(CodeLocation::new(usize::MAX, usize::MAX), $x) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), Block($x)) }; } @@ -99,19 +105,22 @@ macro_rules! block_ast_b { macro_rules! empty_ast { () => { - EmptyLiteral(CodeLocation::new(usize::MAX, usize::MAX)) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), EmptyLiteral()) }; } macro_rules! var_ast { ($x:expr, $y:expr, $z:expr) => { - VarDeclaration(CodeLocation::new(usize::MAX, usize::MAX), $x, $y, $z) + AstNode::new( + CodeLocation::new(usize::MAX, usize::MAX), + VarDeclaration($x, $y, $z), + ) }; } macro_rules! while_ast { ($x:expr, $y:expr) => { - While(CodeLocation::new(usize::MAX, usize::MAX), $x, $y) + AstNode::new(CodeLocation::new(usize::MAX, usize::MAX), While($x, $y)) }; } @@ -124,7 +133,7 @@ macro_rules! while_ast_b { #[test] #[should_panic] fn test_empty() { - parse(&vec![]); + parse(&[]); } #[test] diff --git a/src/compiler/type_checker.rs b/src/compiler/type_checker.rs index fbd082f..54b0ab1 100644 --- a/src/compiler/type_checker.rs +++ b/src/compiler/type_checker.rs @@ -1,19 +1,16 @@ use crate::compiler::{ - ast::{ - Expression::{self, *}, - TypeExpression, - }, + ast::{AstNode, Expression::*, TypeExpression}, symtab::SymTab, variable::Type, }; -pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'source, Type>) -> Type { - match ast { - EmptyLiteral(_) => Type::Unit, - IntLiteral(_, _) => Type::Int, - BoolLiteral(_, _) => Type::Bool, - Identifier(_, name) => symbols.get(name).clone(), - UnaryOp(_, op, expr) => match *op { +pub fn type_check<'source>(ast: &AstNode<'source>, symbols: &mut SymTab<'source, Type>) -> Type { + match &ast.expr { + EmptyLiteral() => Type::Unit, + IntLiteral(_) => Type::Int, + BoolLiteral(_) => Type::Bool, + Identifier(name) => symbols.get(name).clone(), + UnaryOp(op, expr) => match *op { "-" => { let expr_types = vec![type_check(expr, symbols)]; @@ -47,7 +44,7 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour (**sig_ret_type).clone() } }, - BinaryOp(_, left, op, right) => match *op { + BinaryOp(left, op, right) => match *op { "==" | "!=" => { let left_type = type_check(left, symbols); let right_type = type_check(right, symbols); @@ -57,7 +54,7 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour Type::Bool } "=" => { - if !matches!(**left, Identifier(_, _)) { + if !matches!(left.expr, Identifier(_)) { panic!("Non-variable on left side of assignment!"); } @@ -87,7 +84,7 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour (**sig_ret_type).clone() } }, - VarDeclaration(_, name, expr, type_expr) => { + VarDeclaration(name, expr, type_expr) => { let type_var = type_check(expr, symbols); if let Some(type_expr) = type_expr { @@ -107,7 +104,7 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour symbols.insert(name, type_var); Type::Unit } - Conditional(_, condition_expr, then_expr, else_expr) => { + Conditional(condition_expr, then_expr, else_expr) => { if !matches!(type_check(condition_expr, symbols), Type::Bool) { panic!("Non-bool as if-then-else condition!"); } @@ -124,14 +121,14 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour Type::Unit } } - While(_, condition_expr, do_expr) => { + While(condition_expr, do_expr) => { if !matches!(type_check(condition_expr, symbols), Type::Bool) { panic!("Non-bool as while-do condition!"); } type_check(do_expr, symbols); Type::Unit } - FunCall(_, name, args) => { + FunCall(name, args) => { let mut arg_types = Vec::new(); for arg in args { arg_types.push(type_check(arg, symbols)); @@ -150,7 +147,7 @@ pub fn type_check<'source>(ast: &Expression<'source>, symbols: &mut SymTab<'sour (**sig_ret_type).clone() } - Block(_, expressions) => { + Block(expressions) => { symbols.push_level(); let mut type_var = Type::Unit;