diff --git a/examples/arithmetic.lm b/examples/arithmetic.lm index 8ab917c..0452929 100644 --- a/examples/arithmetic.lm +++ b/examples/arithmetic.lm @@ -1,6 +1,6 @@ main(){ init { - x : float + x, c, r, z, f : int } x := 27 - c diff --git a/examples/hello_world.lm b/examples/hello_world.lm index c6e6f0b..e54bc89 100644 --- a/examples/hello_world.lm +++ b/examples/hello_world.lm @@ -5,27 +5,27 @@ main(){ a, b, c, d : float var1234 : string } - a := 4+3 - b := 9 + a := 4.0+3.0 + x := 9 a := 5.25 b := -5.25 - c := "test1234" - d := 1 + var1234 := "test1234" + d := 1.0 while(a > b) { - a := 1 + a := 1.0 } if(a > b and c > d) { - a := 1 + a := 1.0 } else { - b := 1 + b := 1.0 } - b := 1 + b := 1.0 if(not b){ - a := 1 + a := 1.0 } } diff --git a/inputs/test.txt b/inputs/test.txt index 9d7569b..07c4044 100644 --- a/inputs/test.txt +++ b/inputs/test.txt @@ -55,5 +55,10 @@ read(f6f) #+ Ejemplo de error por float invalido +# #+ x := 1001247380987123904721309473201974012938740921374091237409127340983217094874.1234 +# +#+ Ejemplo de error por uso de variable no declarada +# +#+ nodeclarada1 := 1234 +# + +#+ Ejemplo de error por asignacion de con tipos incorrectos +# +#+ a1 := 33 + 1.33 +# a1 := convDate(01-02-1900) diff --git a/src/compiler/ast.rs b/src/compiler/ast.rs index 95beb94..0147412 100644 --- a/src/compiler/ast.rs +++ b/src/compiler/ast.rs @@ -1,4 +1,4 @@ -use crate::grammar::types::ComparisonOp; +use crate::grammar::types::{ComparisonOp, DataType}; use std::{ array, cell::Cell, @@ -75,6 +75,7 @@ pub struct Node { parent: Cell>>, left_child: Option>, right_child: Option>, + pub r#type: Option, } impl Debug for Node { @@ -84,12 +85,13 @@ impl Debug for Node { } impl Node { - pub fn new_leaf(value: NodeValue) -> Self { + pub fn new_leaf(value: NodeValue, node_type: Option) -> Self { Self { value, parent: Cell::new(None), left_child: None, right_child: None, + r#type: node_type, } } } @@ -109,6 +111,33 @@ impl Display for NodeValue { } } +#[derive(Clone, Debug, PartialEq)] +pub enum ExpressionType { + Float, + Int, + String, +} + +impl Display for ExpressionType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Float => write!(f, "FLOAT"), + Self::Int => write!(f, "INT"), + Self::String => write!(f, "STRING"), + } + } +} + +impl From for ExpressionType { + fn from(value: DataType) -> Self { + match value { + DataType::FloatType(_) => ExpressionType::Float, + DataType::IntType(_) => ExpressionType::Int, + DataType::StringType(_) => ExpressionType::String, + } + } +} + #[derive(Clone, Debug)] pub enum AstAction { Plus, @@ -182,7 +211,9 @@ impl From for AstAction { impl Default for Ast { fn default() -> Self { Self { - tree: array::from_fn(|_| Rc::new(Node::new_leaf(NodeValue::Value("".to_string())))), + tree: array::from_fn(|_| { + Rc::new(Node::new_leaf(NodeValue::Value("".to_string()), None)) + }), expression_stack: Vec::new(), term_stack: Vec::new(), comparision_op_stack: Vec::new(), @@ -215,6 +246,7 @@ impl Ast { left_child_ptr: AstNodeRef, right_child_ptr: AstNodeRef, dest_ptr: AstPtr, + r#type: Option, ) -> Rc { let left_child = match left_child_ptr { AstNodeRef::Ptr(ptr) => self.tree.get(ptr as usize).cloned(), @@ -230,6 +262,7 @@ impl Ast { parent: Cell::new(None), left_child: left_child.clone(), right_child: right_child.clone(), + r#type, }); if let Some(left) = left_child { @@ -243,8 +276,13 @@ impl Ast { node } - pub fn create_leaf(&mut self, value: String, dest_ptr: AstPtr) -> Rc { - let leaf = Rc::new(Node::new_leaf(NodeValue::Value(value))); + pub fn create_leaf( + &mut self, + value: String, + dest_ptr: AstPtr, + node_type: Option, + ) -> Rc { + let leaf = Rc::new(Node::new_leaf(NodeValue::Value(value), node_type)); self.tree[dest_ptr as usize] = leaf.clone(); leaf } @@ -273,7 +311,15 @@ impl Ast { ) -> Result { let node_name = format!("n{node_count:0>3}"); writeln!(file, " {node_name:0>3} ;")?; - writeln!(file, " {node_name:0>3} [label=\"{:}\"] ;", node.value)?; + writeln!( + file, + " {node_name:0>3} [label=\"{}{}\"] ;", + node.value, + node.r#type + .as_ref() + .map(|t| format!(" | {t}")) + .unwrap_or_default() + )?; if let Some(left_child) = &node.left_child { node_count += 1; writeln!(file, " {node_name} -- n{node_count:0>3} ;")?; diff --git a/src/compiler/context.rs b/src/compiler/context.rs index dae2860..716ca6c 100644 --- a/src/compiler/context.rs +++ b/src/compiler/context.rs @@ -156,6 +156,13 @@ impl CompilerContext { self.symbol_table.contains(symbol) } + pub fn get_symbol_type(&self, symbol_name: &str) -> Option> { + self.symbol_table + .iter() + .find(|x| x.name == symbol_name) + .map(|x| x.data_type.clone()) + } + pub fn create_ast_graph(&mut self, from: AstPtr) -> Result<(), CompilerError> { self.ast .graph_ast( @@ -167,66 +174,85 @@ impl CompilerContext { } } -#[derive(Clone, Debug)] -pub enum SymbolTableElement { - VarDeclaration(String, DataType, usize), - IntLiteral(TokenIntLiteral), - FloatLiteral(TokenFloatLiteral), - StringLiteral(TokenStringLiteral), +#[derive(Default)] +pub struct SymbolTableElement { + pub name: String, + pub data_type: Option, + pub value: Option, + pub length: Option, } impl Display for SymbolTableElement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::FloatLiteral(float) => write!( - f, - "{}|CONST_FLOAT|{}|{}", - float.original, - float.original, - float.original.len() - )?, - Self::IntLiteral(int) => { - write!(f, "{}|CONST_INT|{}|{}", int, int, int.to_string().len())? - } - Self::StringLiteral(string) => { - write!(f, "{}|CONST_STRING|{}|{}", string, string, string.len())? - } - Self::VarDeclaration(token, r#type, length) => { - write!(f, "{}|{}|-|{}", token, r#type, length)? - } - }; - Ok(()) + let name = &self.name; + let data_type = self + .data_type + .as_ref() + .map(|r#type| r#type.to_string()) + .unwrap_or_else(|| String::from("-")); + let value = self + .value + .as_ref() + .cloned() + .unwrap_or_else(|| String::from("-")); + let length = self + .length + .map(|length| length.to_string()) + .unwrap_or_else(|| String::from("-")); + + write!(f, "{name}|{data_type}|{value}|{length}") } } impl PartialEq for SymbolTableElement { fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::FloatLiteral(token0), Self::FloatLiteral(token1)) => token0 == token1, - (Self::IntLiteral(token0), Self::IntLiteral(token1)) => token0 == token1, - (Self::StringLiteral(token0), Self::StringLiteral(token1)) => token0 == token1, - (Self::VarDeclaration(token0, _, _), Self::VarDeclaration(token1, _, _)) => { - token0 == token1 - } - _ => false, - } + self.name == other.name } } +impl Eq for SymbolTableElement {} + impl From for SymbolTableElement { fn from(value: TokenIntLiteral) -> Self { - Self::IntLiteral(value) + let mut name = String::with_capacity(value.original.len() + 1); + name.push('_'); + name.push_str(&value.original); + + Self { + name, + data_type: None, + value: Some(value.original), + length: None, + } } } impl From for SymbolTableElement { fn from(value: TokenFloatLiteral) -> Self { - Self::FloatLiteral(value) + let mut name = String::with_capacity(value.original.len() + 1); + name.push('_'); + name.push_str(&value.original); + + Self { + name: value.original.clone(), + data_type: None, + value: Some(value.original), + length: None, + } } } impl From for SymbolTableElement { fn from(value: TokenStringLiteral) -> Self { - Self::StringLiteral(value) + let mut name = String::with_capacity(value.len() + 1); + name.push('_'); + name.push_str(&value); + + Self { + name, + data_type: None, + length: Some(value.len()), + value: Some(value), + } } } diff --git a/src/compiler/error.rs b/src/compiler/error.rs index 025723f..2f77fbc 100644 --- a/src/compiler/error.rs +++ b/src/compiler/error.rs @@ -13,6 +13,10 @@ pub enum CompilerError { Lexer(String), #[error("Context error: {0}")] Context(String), + #[error("Type mismatch error: {0}")] + TypeMismatch(String), + #[error("Use of undeclared variable: {0}")] + UndeclaredVariable(String), #[error("IO error: {0}")] IO(String), #[error("Compiler internal error: {0}. This is a bug.")] diff --git a/src/grammar/rules_actions.rs b/src/grammar/rules_actions.rs index 218ad42..25780f5 100644 --- a/src/grammar/rules_actions.rs +++ b/src/grammar/rules_actions.rs @@ -1,5 +1,5 @@ use crate::compiler::{ - ast::{AstAction, AstPtr, Node, NodeValue}, + ast::{AstAction, AstPtr, ExpressionType, Node, NodeValue}, context::CompilerContext, error::{CompilerError, log_error_and_exit}, }; @@ -40,7 +40,10 @@ pub fn token_int_literal( compiler_context: &mut CompilerContext, ) -> TokenIntLiteral { compiler_context.write_to_lexer_file(&format!("INT_LITERAL: {}", token.value)); - token.value.parse().unwrap() + TokenIntLiteral { + original: token.value.into(), + parsed: token.value.parse().unwrap(), + } } /// Parses a float literal into i64 @@ -408,7 +411,7 @@ pub fn body_body_empty(_ctx: &Ctx, compiler_context: &mut CompilerContext) -> Bo compiler_context.write_to_parser_file(" -> EMPTY"); let ast = &mut compiler_context.ast; - let leaf = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop))); + let leaf = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop), None)); ast.assign_node_to_ptr(leaf.into(), AstPtr::Body); None @@ -434,7 +437,7 @@ pub fn init_body_init_body( /// Parses the rule ` -> TokenRead TokenParOpen TokenId TokenParClose` pub fn function_read_function_read_call( - _ctx: &Ctx, + ctx: &Ctx, token_read: TokenRead, token_par_open: TokenParOpen, token_id: TokenId, @@ -445,14 +448,24 @@ pub fn function_read_function_read_call( " -> {token_read} {token_par_open} {token_id} {token_par_close}" )); + let Some(rhs_type) = compiler_context.get_symbol_type(&token_id).flatten() else { + log_undeclared_variable_error(&token_id, ctx, compiler_context) + }; + let ast = &mut compiler_context.ast; - let right_child = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop))); - let left_child = Rc::new(Node::new_leaf(NodeValue::Value(token_id.clone()))); + + let right_child = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop), None)); + let left_child = Rc::new(Node::new_leaf( + NodeValue::Value(token_id.clone()), + Some(rhs_type.into()), + )); + ast.create_node( AstAction::Read, left_child.into(), right_child.into(), AstPtr::Read, + None, ); FunctionRead { @@ -477,12 +490,13 @@ pub fn function_write_function_write_call( )); let ast = &mut compiler_context.ast; - let leaf = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop))); + let leaf = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop), None)); ast.create_node( AstAction::Write, AstPtr::SimpleExpression.into(), leaf.into(), AstPtr::Write, + None, ); FunctionWrite { @@ -505,13 +519,19 @@ pub fn function_is_zero_function_is_zero_call( compiler_context.write_to_parser_file(&format!( " -> {token_is_zero} {token_par_open} {token_par_close}" )); - let zero_leaf = Rc::new(Node::new_leaf(NodeValue::Value("0".into()))); + + let zero_leaf = Rc::new(Node::new_leaf( + NodeValue::Value("0".into()), + Some(ExpressionType::Int), + )); compiler_context.ast.create_node( AstAction::EQ, AstPtr::ArithmeticExpression.into(), zero_leaf.into(), AstPtr::IsZero, + None, ); + FunctionIsZero { token_is_zero, token_par_open, @@ -535,31 +555,52 @@ pub fn function_conv_date_function_conv_date_variable_call( let ast = &mut compiler_context.ast; - let thousand_leaf = Rc::new(Node::new_leaf(NodeValue::Value("1000".into()))); - let hundread_leaf = Rc::new(Node::new_leaf(NodeValue::Value("100".into()))); - let one_leaf = Rc::new(Node::new_leaf(NodeValue::Value("1".into()))); + let thousand_leaf = Rc::new(Node::new_leaf( + NodeValue::Value("1000".into()), + Some(ExpressionType::Int), + )); + let hundread_leaf = Rc::new(Node::new_leaf( + NodeValue::Value("100".into()), + Some(ExpressionType::Int), + )); + let one_leaf = Rc::new(Node::new_leaf( + NodeValue::Value("1".into()), + Some(ExpressionType::Int), + )); - let year_leaf = Rc::new(Node::new_leaf(NodeValue::Value(token_date.year.clone()))); - let month_leaf = Rc::new(Node::new_leaf(NodeValue::Value(token_date.month.clone()))); - let day_leaf = Rc::new(Node::new_leaf(NodeValue::Value(token_date.day.clone()))); + let year_leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_date.year.clone()), + Some(ExpressionType::Int), + )); + let month_leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_date.month.clone()), + Some(ExpressionType::Int), + )); + let day_leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_date.day.clone()), + Some(ExpressionType::Int), + )); let year_node = ast.create_node( AstAction::Mult, year_leaf.into(), thousand_leaf.into(), AstPtr::ConvDate, + Some(ExpressionType::Int), ); let month_node = ast.create_node( AstAction::Mult, month_leaf.into(), hundread_leaf.into(), AstPtr::ConvDate, + Some(ExpressionType::Int), ); let day_node = ast.create_node( AstAction::Mult, day_leaf.into(), one_leaf.into(), AstPtr::ConvDate, + Some(ExpressionType::Int), ); let sum_year_month_node = ast.create_node( @@ -567,12 +608,14 @@ pub fn function_conv_date_function_conv_date_variable_call( year_node.into(), month_node.into(), AstPtr::ConvDate, + Some(ExpressionType::Int), ); ast.create_node( AstAction::Plus, sum_year_month_node.into(), day_node.into(), AstPtr::ConvDate, + Some(ExpressionType::Int), ); FunctionConvDate { @@ -689,6 +732,7 @@ pub fn expressions_expression_recursive( statement_node.into(), AstPtr::Expressions.into(), AstPtr::Expressions, + None, ); Expressions::ExpressionRecursive(ExpressionRecursive { statement, @@ -778,7 +822,7 @@ pub fn statement_statement_read( /// Parses the rule ` -> TokenId TokenAssign ` pub fn assignment_assignment_expression( - _ctx: &Ctx, + ctx: &Ctx, token_id: TokenId, token_assign: TokenAssign, simple_expression: SimpleExpression, @@ -788,13 +832,34 @@ pub fn assignment_assignment_expression( " -> {token_id} {token_assign} " )); + let Some(lhs_type) = compiler_context.get_symbol_type(&token_id).flatten() else { + log_undeclared_variable_error(&token_id, ctx, compiler_context) + }; + let lhs_type = lhs_type.into(); + let ast = &mut compiler_context.ast; - let leaf = Node::new_leaf(NodeValue::Value(token_id.clone())); + + let rhs = ast.get_node_from_ptr(AstPtr::SimpleExpression); + + let Some(rhs_type) = rhs.r#type.clone() else { + log_ast_error( + "The rhs of an assignment is not an expression", + ctx, + compiler_context, + ) + }; + + if lhs_type != rhs_type { + log_type_error(&format!("{lhs_type} := {rhs_type}"), ctx, compiler_context) + } + + let leaf = Node::new_leaf(NodeValue::Value(token_id.clone()), Some(lhs_type)); ast.create_node( AstAction::Assign, Rc::new(leaf).into(), AstPtr::SimpleExpression.into(), AstPtr::Assignment, + None, ); Assignment::AssignmentExpression(AssignmentExpression { @@ -806,7 +871,7 @@ pub fn assignment_assignment_expression( /// Parses the rule ` -> TokenId TokenAssign ` pub fn assignment_assignment_conv_date( - _ctx: &Ctx, + ctx: &Ctx, token_id: TokenId, token_assign: TokenAssign, function_conv_date: FunctionConvDate, @@ -816,13 +881,36 @@ pub fn assignment_assignment_conv_date( " -> {token_id} {token_assign} " )); + let Some(lhs_type) = compiler_context.get_symbol_type(&token_id).flatten() else { + log_undeclared_variable_error(&token_id, ctx, compiler_context) + }; + let lhs_type = lhs_type.into(); + let ast = &mut compiler_context.ast; - let leaf = Rc::new(Node::new_leaf(NodeValue::Value(token_id.clone()))); + let rhs = ast.get_node_from_ptr(AstPtr::ConvDate); + + let Some(rhs_type) = rhs.r#type.clone() else { + log_ast_error( + "The rhs of an assignment is not an expression", + ctx, + compiler_context, + ) + }; + + if lhs_type != rhs_type { + log_type_error(&format!("{lhs_type} := {rhs_type}"), ctx, compiler_context) + } + let leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_id.clone()), + Some(lhs_type), + )); + ast.create_node( AstAction::Assign, leaf.into(), AstPtr::ConvDate.into(), AstPtr::Assignment, + None, ); Assignment::AssignmentConvDate(ConvDate { @@ -892,6 +980,7 @@ pub fn while_loop_while( conjunction_node.into(), AstPtr::Body.into(), AstPtr::While, + None, ); WhileLoop { @@ -935,6 +1024,7 @@ pub fn if_statement_if_statement( conjunction_node.into(), AstPtr::Body.into(), AstPtr::If, + None, ); IfStatement::IfStatementIfStatement(IfStatementIfStatement { @@ -979,6 +1069,7 @@ pub fn if_statement_if_statement_else_statement( if_true_body.into(), AstPtr::Body.into(), AstPtr::If, + None, ); let Some(conjunction_node) = ast.conjunction_stack.pop() else { log_ast_error( @@ -992,6 +1083,7 @@ pub fn if_statement_if_statement_else_statement( conjunction_node.into(), else_node.into(), AstPtr::If, + None, ); IfStatement::IfStatementElseStatement(IfStatementElseStatement { @@ -1069,6 +1161,7 @@ pub fn boolean_expression_boolean_expression_simple_expression( left_child.into(), AstPtr::SimpleExpression.into(), AstPtr::BooleanExpression, + None, ); ast.boolean_expression_stack.push(node); @@ -1088,7 +1181,7 @@ pub fn boolean_expression_boolean_expression_true( compiler_context.write_to_parser_file(&format!(" -> {token_true}")); let ast = &mut compiler_context.ast; - let node = ast.create_leaf(token_true.clone(), AstPtr::BooleanExpression); + let node = ast.create_leaf(token_true.clone(), AstPtr::BooleanExpression, None); ast.boolean_expression_stack.push(node); BooleanExpression::BooleanExpressionTrue(token_true) @@ -1103,7 +1196,7 @@ pub fn boolean_expression_boolean_expression_false( compiler_context.write_to_parser_file(&format!(" -> {token_false}")); let ast = &mut compiler_context.ast; - let node = ast.create_leaf(token_false.clone(), AstPtr::BooleanExpression); + let node = ast.create_leaf(token_false.clone(), AstPtr::BooleanExpression, None); ast.boolean_expression_stack.push(node); BooleanExpression::BooleanExpressionFalse(token_false) @@ -1118,7 +1211,7 @@ pub fn boolean_expression_boolean_expression_token_id( compiler_context.write_to_parser_file(&format!(" -> {token_id}")); let ast = &mut compiler_context.ast; - let node = ast.create_leaf(token_id.clone(), AstPtr::BooleanExpression); + let node = ast.create_leaf(token_id.clone(), AstPtr::BooleanExpression, None); ast.boolean_expression_stack.push(node); BooleanExpression::BooleanExpressionTokenId(token_id) @@ -1181,7 +1274,11 @@ pub fn simple_expression_simple_expression_string( compiler_context.write_to_parser_file(&format!(" -> {token_string_literal}")); let ast = &mut compiler_context.ast; - ast.create_leaf(token_string_literal.clone(), AstPtr::SimpleExpression); + ast.create_leaf( + token_string_literal.clone(), + AstPtr::SimpleExpression, + Some(ExpressionType::String), + ); SimpleExpression::SimpleExpressionString(token_string_literal) } @@ -1218,6 +1315,7 @@ pub fn conjunction_conjunction_and( boolean_expression_node.into(), conjunction_node.into(), AstPtr::Conjunction, + None, ); ast.conjunction_stack.push(conjunction_node); @@ -1260,6 +1358,7 @@ pub fn conjunction_conjunction_or( boolean_expression_node.into(), conjunction_node.into(), AstPtr::Conjunction, + None, ); ast.conjunction_stack.push(conjunction_node); @@ -1399,11 +1498,15 @@ pub fn number_number_int( token_int_literal: TokenIntLiteral, compiler_context: &mut CompilerContext, ) -> Number { - compiler_context.push_to_symbol_table(token_int_literal.into()); - compiler_context.write_to_parser_file(&format!(" -> {token_int_literal}")); + compiler_context.push_to_symbol_table(token_int_literal.clone().into()); + compiler_context.write_to_parser_file(&format!(" -> {}", token_int_literal.original)); let ast = &mut compiler_context.ast; - ast.create_leaf(token_int_literal.to_string(), AstPtr::Number); + ast.create_leaf( + token_int_literal.original.clone(), + AstPtr::Number, + Some(ExpressionType::Int), + ); Number::NumberInt(token_int_literal) } @@ -1418,7 +1521,11 @@ pub fn number_number_float( compiler_context.write_to_parser_file(&format!(" -> {}", token_float_literal.original)); let ast = &mut compiler_context.ast; - ast.create_leaf(token_float_literal.original.clone(), AstPtr::Number); + ast.create_leaf( + token_float_literal.original.clone(), + AstPtr::Number, + Some(ExpressionType::Float), + ); Number::NumberFloat(token_float_literal) } @@ -1430,34 +1537,36 @@ pub fn number_number_negative_int( token_int_literal: TokenIntLiteral, compiler_context: &mut CompilerContext, ) -> Number { - let value: i64 = format!("{token_sub}{token_int_literal}").parse().unwrap(); - compiler_context.push_to_symbol_table(value.into()); - compiler_context.write_to_parser_file(&format!(" -> {token_sub} {token_int_literal}")); + compiler_context.push_to_symbol_table(token_int_literal.clone().into()); + compiler_context.write_to_parser_file(&format!( + " -> {token_sub} {}", + token_int_literal.original + )); let ast = &mut compiler_context.ast; - let leaf = Rc::new(Node::new_leaf(NodeValue::Value( - token_int_literal.to_string(), - ))); - let noop = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop))); + let leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_int_literal.original.clone()), + Some(ExpressionType::Int), + )); + let noop = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop), None)); ast.create_node( AstAction::Negative, leaf.into(), noop.into(), AstPtr::Number, + Some(ExpressionType::Int), ); - Number::NumberInt(value) + Number::NumberInt(token_int_literal) } /// Parses the rule ` -> TokenSub TokenFloatLiteral` pub fn number_number_negative_float( _ctx: &Ctx, token_sub: TokenSub, - mut token_float_literal: TokenFloatLiteral, + token_float_literal: TokenFloatLiteral, compiler_context: &mut CompilerContext, ) -> Number { - token_float_literal.original = format!("{token_sub}{}", token_float_literal.original); - token_float_literal.parsed *= -1_f32; compiler_context.push_to_symbol_table(token_float_literal.clone().into()); compiler_context.write_to_parser_file(&format!( " -> {token_sub} {}", @@ -1465,15 +1574,17 @@ pub fn number_number_negative_float( )); let ast = &mut compiler_context.ast; - let leaf = Rc::new(Node::new_leaf(NodeValue::Value( - token_float_literal.original.clone(), - ))); - let noop = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop))); + let leaf = Rc::new(Node::new_leaf( + NodeValue::Value(token_float_literal.original.clone()), + Some(ExpressionType::Float), + )); + let noop = Rc::new(Node::new_leaf(NodeValue::Action(AstAction::Noop), None)); ast.create_node( AstAction::Negative, leaf.into(), noop.into(), AstPtr::Number, + Some(ExpressionType::Float), ); Number::NumberFloat(token_float_literal) @@ -1499,12 +1610,13 @@ pub fn not_statement_not( ); }; - let dummy = Node::new_leaf(NodeValue::Action(AstAction::Noop)); + let dummy = Node::new_leaf(NodeValue::Action(AstAction::Noop), None); ast.create_node( AstAction::Not, boolean_expression_node.into(), Rc::new(dummy).into(), AstPtr::Not, + None, ); NotStatement { @@ -1526,18 +1638,44 @@ pub fn arithmetic_expression_arithmetic_expression_sum_term( )); let ast = &mut compiler_context.ast; - let Some(node) = ast.expression_stack.pop() else { + + let right_child = ast.get_node_from_ptr(AstPtr::Term); + let Some(left_child) = ast.expression_stack.pop() else { log_ast_error( "ArithmeticExpression stack was empty when parsing ` -> TokenSum `", ctx, compiler_context, ); }; + + let Some(left_child_type) = left_child.r#type.as_ref().cloned() else { + log_ast_error( + "Left hand side of an addition has no type", + ctx, + compiler_context, + ) + }; + let Some(right_child_type) = right_child.r#type.as_ref().cloned() else { + log_ast_error( + "Right hand side of an addition has no type", + ctx, + compiler_context, + ) + }; + if left_child_type != right_child_type { + log_type_error( + &format!("{left_child_type} + {right_child_type}"), + ctx, + compiler_context, + ) + } + ast.create_node( AstAction::Plus, - node.into(), - AstPtr::Term.into(), + left_child.into(), + right_child.into(), AstPtr::ArithmeticExpression, + Some(left_child_type), ); ArithmeticExpression::ArithmeticExpressionSumTerm(ArithmeticExpressionSumTerm { @@ -1560,18 +1698,44 @@ pub fn arithmetic_expression_arithmetic_expression_sub_term( )); let ast = &mut compiler_context.ast; - let Some(node) = ast.expression_stack.pop() else { + + let right_child = ast.get_node_from_ptr(AstPtr::Term); + let Some(left_child) = ast.expression_stack.pop() else { log_ast_error( "ArithmeticExpression stack was empty when parsing ` -> TokenSub `", ctx, compiler_context, ) }; + + let Some(left_child_type) = left_child.r#type.as_ref().cloned() else { + log_ast_error( + "Left hand side of a substraction has no type", + ctx, + compiler_context, + ) + }; + let Some(right_child_type) = right_child.r#type.as_ref().cloned() else { + log_ast_error( + "Right hand side of a substraction has no type", + ctx, + compiler_context, + ) + }; + if left_child_type != right_child_type { + log_type_error( + &format!("{left_child_type} - {right_child_type}"), + ctx, + compiler_context, + ) + } + compiler_context.ast.create_node( AstAction::Sub, - node.into(), - AstPtr::Term.into(), + left_child.into(), + right_child.into(), AstPtr::ArithmeticExpression, + Some(left_child_type), ); ArithmeticExpression::ArithmeticExpressionSubTerm(ArithmeticExpressionSubTerm { @@ -1616,18 +1780,44 @@ pub fn term_term_mul_factor( .write_to_parser_file(&format!(" -> {token_mul} ")); let ast = &mut compiler_context.ast; - let Some(node) = ast.term_stack.pop() else { + + let right_child = ast.get_node_from_ptr(AstPtr::Factor); + let Some(left_child) = ast.term_stack.pop() else { log_ast_error( "Term stack was empty when parsing ` -> TokenMul `", ctx, compiler_context, ); }; + + let Some(left_child_type) = left_child.r#type.as_ref().cloned() else { + log_ast_error( + "Left hand side of a multiplication has no type", + ctx, + compiler_context, + ) + }; + let Some(right_child_type) = right_child.r#type.as_ref().cloned() else { + log_ast_error( + "Right hand side of a multiplication has no type", + ctx, + compiler_context, + ) + }; + if left_child_type != right_child_type { + log_type_error( + &format!("{left_child_type} * {right_child_type}"), + ctx, + compiler_context, + ) + } + ast.create_node( AstAction::Mult, - node.into(), - AstPtr::Factor.into(), + left_child.into(), + right_child.into(), AstPtr::Term, + Some(left_child_type), ); Term::TermMulFactor(TermMulFactor { @@ -1649,18 +1839,44 @@ pub fn term_term_div_factor( .write_to_parser_file(&format!(" -> {token_div} ")); let ast = &mut compiler_context.ast; - let Some(node) = ast.term_stack.pop() else { + + let right_child = ast.get_node_from_ptr(AstPtr::Factor); + let Some(left_child) = ast.term_stack.pop() else { log_ast_error( "Term stack was empty when parsing ` -> TokenDiv `", ctx, compiler_context, ); }; + + let Some(left_child_type) = left_child.r#type.as_ref().cloned() else { + log_ast_error( + "Left hand side of a division has no type", + ctx, + compiler_context, + ) + }; + let Some(right_child_type) = right_child.r#type.as_ref().cloned() else { + log_ast_error( + "Right hand side of a division has no type", + ctx, + compiler_context, + ) + }; + if left_child_type != right_child_type { + log_type_error( + &format!("{left_child_type} / {right_child_type}"), + ctx, + compiler_context, + ) + } + ast.create_node( AstAction::Div, - node.into(), - AstPtr::Factor.into(), + left_child.into(), + right_child.into(), AstPtr::Term, + Some(left_child_type), ); Term::TermDivFactor(TermDivFactor { @@ -1695,14 +1911,18 @@ pub fn term_term_factor( /// Parses the rule ` -> TokenId` pub fn factor_factor_id( - _ctx: &Ctx, + ctx: &Ctx, token_id: TokenId, compiler_context: &mut CompilerContext, ) -> Factor { compiler_context.write_to_parser_file(&format!(" -> {token_id}")); + let Some(id_type) = compiler_context.get_symbol_type(&token_id).flatten() else { + log_undeclared_variable_error(&token_id, ctx, compiler_context) + }; + let ast = &mut compiler_context.ast; - ast.create_leaf(token_id.clone(), AstPtr::Factor); + ast.create_leaf(token_id.clone(), AstPtr::Factor, Some(id_type.into())); Factor::FactorId(token_id) } @@ -1752,3 +1972,27 @@ fn log_ast_error(error: &str, ctx: &Ctx, compiler_context: &mut CompilerContext) compiler_context, ) } + +fn log_type_error(error: &str, ctx: &Ctx, compiler_context: &mut CompilerContext) -> ! { + log_error_and_exit( + ctx.range(), + CompilerError::TypeMismatch(error.into()), + 0, + true, + compiler_context, + ) +} + +fn log_undeclared_variable_error( + var_name: &str, + ctx: &Ctx, + compiler_context: &mut CompilerContext, +) -> ! { + log_error_and_exit( + ctx.range(), + CompilerError::UndeclaredVariable(var_name.into()), + 0, + true, + compiler_context, + ) +} diff --git a/src/grammar/types.rs b/src/grammar/types.rs index c5490b0..ff13ea6 100644 --- a/src/grammar/types.rs +++ b/src/grammar/types.rs @@ -18,7 +18,13 @@ pub type TokenFloat = String; pub type TokenString = String; /// Signed integer number -pub type TokenIntLiteral = i64; +#[derive(Debug, Clone)] +pub struct TokenIntLiteral { + /// Original string representing the int + pub original: String, + /// Parsed representation of the int + pub parsed: i64, +} /// Signed float with 32 bits precision #[derive(Debug, Clone)] @@ -308,11 +314,13 @@ impl VarDeclaration { pub fn push_to_symbol_table(&self, compiler_context: &mut CompilerContext) -> DataType { match self { Self::VarDeclarationSingle(single) => { - let symbol = SymbolTableElement::VarDeclaration( - single.token_id.clone(), - single.data_type.clone(), - single.token_id.len(), - ); + let symbol = SymbolTableElement { + name: single.token_id.clone(), + data_type: Some(single.data_type.clone()), + value: None, + length: Some(single.token_id.len()), + }; + // If the symbol already exists this is a redeclaration if compiler_context.symbol_exists(&symbol) { log_error_and_exit( @@ -334,11 +342,13 @@ impl VarDeclaration { let data_type = recursive .var_declaration .push_to_symbol_table(compiler_context); - let symbol = SymbolTableElement::VarDeclaration( - recursive.token_id.clone(), - data_type.clone(), - recursive.token_id.len(), - ); + let symbol = SymbolTableElement { + name: recursive.token_id.clone(), + data_type: Some(data_type.clone()), + value: None, + length: Some(recursive.token_id.len()), + }; + // If the symbol already exists this is a redeclaration if compiler_context.symbol_exists(&symbol) { log_error_and_exit(