From 76aa122286f4dc00ab79587aa08a47693600769b Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Mon, 23 Jun 2025 16:24:28 +0200 Subject: [PATCH 1/5] refactor: inital tree-wide refactoring --- src/ir/ast/assignment_tree.rs | 149 +++ src/ir/ast/binary_operation_tree.rs | 47 + src/ir/ast/block_tree.rs | 24 + src/ir/ast/break_tree.rs | 30 + src/ir/ast/call_tree.rs | 12 + src/ir/ast/continue_tree.rs | 24 + src/ir/ast/declaration_tree.rs | 22 + src/ir/ast/expression_tree.rs | 19 + src/ir/ast/for_tree.rs | 74 ++ src/ir/ast/function_tree.rs | 46 + src/ir/ast/identifier_tree.rs | 14 + src/ir/ast/if_tree.rs | 53 + src/ir/ast/literal_tree.rs | 26 + src/ir/ast/mod.rs | 617 +++++++++++ src/ir/ast/program_tree.rs | 15 + src/ir/ast/return_tree.rs | 17 + src/ir/ast/statement_tree.rs | 39 + src/ir/ast/ternary_operation_tree.rs | 63 ++ src/ir/ast/unary_operation_tree.rs | 39 + src/ir/ast/while_tree.rs | 69 ++ src/ir/constructor.rs | 1031 ------------------- src/ir/mod.rs | 2 +- src/lexer/collection.rs | 157 +++ src/lexer/mod.rs | 66 +- src/lexer/operator.rs | 124 +++ src/lexer/token.rs | 2 +- src/main.rs | 60 +- src/parser/ast.rs | 188 ---- src/parser/ast/assignment_tree.rs | 58 ++ src/parser/ast/binary_operation_tree.rs | 59 ++ src/parser/ast/block_tree.rs | 65 ++ src/parser/ast/break_tree.rs | 31 + src/parser/ast/call_tree.rs | 38 + src/parser/ast/continue_tree.rs | 31 + src/parser/ast/declaration_tree.rs | 75 ++ src/parser/ast/expression_tree.rs | 221 ++++ src/parser/ast/for_tree.rs | 86 ++ src/parser/ast/function_parameter_tree.rs | 15 + src/parser/ast/function_tree.rs | 75 ++ src/parser/ast/identifier_tree.rs | 43 + src/parser/ast/if_tree.rs | 75 ++ src/parser/ast/literal_tree.rs | 107 ++ src/parser/ast/lvalue_tree.rs | 48 + src/parser/ast/mod.rs | 32 + src/parser/ast/name_tree.rs | 44 + src/parser/ast/program_tree.rs | 68 ++ src/parser/ast/return_tree.rs | 46 + src/parser/ast/statement_tree.rs | 180 ++++ src/parser/ast/ternary_operation_tree.rs | 68 ++ src/parser/ast/type_tree.rs | 61 ++ src/parser/ast/unary_operation_tree.rs | 96 ++ src/parser/ast/while_tree.rs | 55 + src/parser/error.rs | 32 +- src/parser/mod.rs | 472 --------- src/parser/types.rs | 2 + src/semantic/ast/assignment_tree.rs | 100 ++ src/semantic/ast/binary_operation_tree.rs | 85 ++ src/semantic/ast/block_tree.rs | 35 + src/semantic/ast/break_tree.rs | 20 + src/semantic/ast/call_tree.rs | 14 + src/semantic/ast/continue_tree.rs | 20 + src/semantic/ast/declaration_tree.rs | 50 + src/semantic/ast/expression_tree.rs | 28 + src/semantic/ast/for_tree.rs | 60 ++ src/semantic/ast/function_parameter_tree.rs | 13 + src/semantic/ast/function_tree.rs | 29 + src/semantic/ast/identifier_tree.rs | 40 + src/semantic/ast/if_tree.rs | 88 ++ src/semantic/ast/literal_tree.rs | 36 + src/semantic/ast/lvalue_tree.rs | 18 + src/semantic/ast/mod.rs | 33 + src/semantic/ast/name_tree.rs | 13 + src/semantic/ast/program_tree.rs | 19 + src/semantic/ast/return_tree.rs | 20 + src/semantic/ast/statement_tree.rs | 66 ++ src/semantic/ast/ternary_operation_tree.rs | 28 + src/semantic/ast/type_tree.rs | 13 + src/semantic/ast/unary_operation_tree.rs | 36 + src/semantic/ast/while_tree.rs | 30 + src/semantic/error.rs | 111 ++ src/semantic/mod.rs | 496 +-------- src/util/span.rs | 4 +- 82 files changed, 4479 insertions(+), 2238 deletions(-) create mode 100644 src/ir/ast/assignment_tree.rs create mode 100644 src/ir/ast/binary_operation_tree.rs create mode 100644 src/ir/ast/block_tree.rs create mode 100644 src/ir/ast/break_tree.rs create mode 100644 src/ir/ast/call_tree.rs create mode 100644 src/ir/ast/continue_tree.rs create mode 100644 src/ir/ast/declaration_tree.rs create mode 100644 src/ir/ast/expression_tree.rs create mode 100644 src/ir/ast/for_tree.rs create mode 100644 src/ir/ast/function_tree.rs create mode 100644 src/ir/ast/identifier_tree.rs create mode 100644 src/ir/ast/if_tree.rs create mode 100644 src/ir/ast/literal_tree.rs create mode 100644 src/ir/ast/mod.rs create mode 100644 src/ir/ast/program_tree.rs create mode 100644 src/ir/ast/return_tree.rs create mode 100644 src/ir/ast/statement_tree.rs create mode 100644 src/ir/ast/ternary_operation_tree.rs create mode 100644 src/ir/ast/unary_operation_tree.rs create mode 100644 src/ir/ast/while_tree.rs delete mode 100644 src/ir/constructor.rs create mode 100644 src/lexer/collection.rs create mode 100644 src/lexer/operator.rs delete mode 100644 src/parser/ast.rs create mode 100644 src/parser/ast/assignment_tree.rs create mode 100644 src/parser/ast/binary_operation_tree.rs create mode 100644 src/parser/ast/block_tree.rs create mode 100644 src/parser/ast/break_tree.rs create mode 100644 src/parser/ast/call_tree.rs create mode 100644 src/parser/ast/continue_tree.rs create mode 100644 src/parser/ast/declaration_tree.rs create mode 100644 src/parser/ast/expression_tree.rs create mode 100644 src/parser/ast/for_tree.rs create mode 100644 src/parser/ast/function_parameter_tree.rs create mode 100644 src/parser/ast/function_tree.rs create mode 100644 src/parser/ast/identifier_tree.rs create mode 100644 src/parser/ast/if_tree.rs create mode 100644 src/parser/ast/literal_tree.rs create mode 100644 src/parser/ast/lvalue_tree.rs create mode 100644 src/parser/ast/mod.rs create mode 100644 src/parser/ast/name_tree.rs create mode 100644 src/parser/ast/program_tree.rs create mode 100644 src/parser/ast/return_tree.rs create mode 100644 src/parser/ast/statement_tree.rs create mode 100644 src/parser/ast/ternary_operation_tree.rs create mode 100644 src/parser/ast/type_tree.rs create mode 100644 src/parser/ast/unary_operation_tree.rs create mode 100644 src/parser/ast/while_tree.rs create mode 100644 src/semantic/ast/assignment_tree.rs create mode 100644 src/semantic/ast/binary_operation_tree.rs create mode 100644 src/semantic/ast/block_tree.rs create mode 100644 src/semantic/ast/break_tree.rs create mode 100644 src/semantic/ast/call_tree.rs create mode 100644 src/semantic/ast/continue_tree.rs create mode 100644 src/semantic/ast/declaration_tree.rs create mode 100644 src/semantic/ast/expression_tree.rs create mode 100644 src/semantic/ast/for_tree.rs create mode 100644 src/semantic/ast/function_parameter_tree.rs create mode 100644 src/semantic/ast/function_tree.rs create mode 100644 src/semantic/ast/identifier_tree.rs create mode 100644 src/semantic/ast/if_tree.rs create mode 100644 src/semantic/ast/literal_tree.rs create mode 100644 src/semantic/ast/lvalue_tree.rs create mode 100644 src/semantic/ast/mod.rs create mode 100644 src/semantic/ast/name_tree.rs create mode 100644 src/semantic/ast/program_tree.rs create mode 100644 src/semantic/ast/return_tree.rs create mode 100644 src/semantic/ast/statement_tree.rs create mode 100644 src/semantic/ast/ternary_operation_tree.rs create mode 100644 src/semantic/ast/type_tree.rs create mode 100644 src/semantic/ast/unary_operation_tree.rs create mode 100644 src/semantic/ast/while_tree.rs create mode 100644 src/semantic/error.rs diff --git a/src/ir/ast/assignment_tree.rs b/src/ir/ast/assignment_tree.rs new file mode 100644 index 0000000..81f2f50 --- /dev/null +++ b/src/ir/ast/assignment_tree.rs @@ -0,0 +1,149 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + lexer::operator::AssignmentOperator, + parser::ast::assignment_tree::AssignmentTree, +}; + +use super::IRConstructor; + +impl ToIR for AssignmentTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let rhs = self + .expression() + .to_ir(constructor) + .expect("Invalid expression!"); + match self.operator() { + AssignmentOperator::AssignMinus => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_sub(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignPlus => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_add(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignMul => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_mul(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignDiv => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let div = constructor.create_div(lhs, rhs); + let desugar = constructor.create_div_mod_projection(div); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignMod => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let mod_node = constructor.create_mod(lhs, rhs); + let desugar = constructor.create_div_mod_projection(mod_node); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignShiftLeft => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_shift_left(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignShiftRight => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_shift_right(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignBitwiseOr => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_or(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignBitwiseAnd => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_and(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::AssignBitwiseXor => { + let lhs = constructor.read_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + ); + let desugar = constructor.create_xor(lhs, rhs); + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + desugar, + ); + } + AssignmentOperator::Assign => { + constructor.write_variable( + self.lvalue().identifier().name().clone(), + constructor.current_block(), + rhs, + ); + } + AssignmentOperator::AssignBitwiseNot => todo!(), + }; + return None; + } +} diff --git a/src/ir/ast/binary_operation_tree.rs b/src/ir/ast/binary_operation_tree.rs new file mode 100644 index 0000000..e358d9b --- /dev/null +++ b/src/ir/ast/binary_operation_tree.rs @@ -0,0 +1,47 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + lexer::operator::BinaryOperator, + parser::ast::binary_operation_tree::BinaryOperationTree, +}; + +use super::IRConstructor; + +impl ToIR for BinaryOperationTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let lhs_node = self + .lhs() + .to_ir(constructor) + .expect("Expected LHS to be expression"); + let rhs_node = self + .rhs() + .to_ir(constructor) + .expect("Expected RHS to be expression"); + let result = match self.operator() { + BinaryOperator::Minus => constructor.create_sub(lhs_node, rhs_node), + BinaryOperator::Plus => constructor.create_add(lhs_node, rhs_node), + BinaryOperator::Mul => constructor.create_mul(lhs_node, rhs_node), + BinaryOperator::Div => { + let div_node = constructor.create_div(lhs_node, rhs_node); + constructor.create_div_mod_projection(div_node) + } + BinaryOperator::Mod => { + let mod_node = constructor.create_mod(lhs_node, rhs_node); + constructor.create_div_mod_projection(mod_node) + } + BinaryOperator::ShiftLeft => constructor.create_shift_left(lhs_node, rhs_node), + BinaryOperator::ShiftRight => constructor.create_shift_right(lhs_node, rhs_node), + BinaryOperator::Lower => constructor.create_lower(lhs_node, rhs_node), + BinaryOperator::LowerEquals => constructor.create_lower_equals(lhs_node, rhs_node), + BinaryOperator::Equals => constructor.create_equals(lhs_node, rhs_node), + BinaryOperator::NotEquals => constructor.create_not_equals(lhs_node, rhs_node), + BinaryOperator::HigherEquals => constructor.create_higher_equals(lhs_node, rhs_node), + BinaryOperator::Higher => constructor.create_higher(lhs_node, rhs_node), + BinaryOperator::BitwiseOr => constructor.create_or(lhs_node, rhs_node), + BinaryOperator::BitwiseAnd => constructor.create_and(lhs_node, rhs_node), + BinaryOperator::BitwiseXor => constructor.create_xor(lhs_node, rhs_node), + BinaryOperator::LogicalAnd => constructor.create_and(lhs_node, rhs_node), + BinaryOperator::LogicalOr => constructor.create_or(lhs_node, rhs_node), + }; + Some(result) + } +} diff --git a/src/ir/ast/block_tree.rs b/src/ir/ast/block_tree.rs new file mode 100644 index 0000000..b907016 --- /dev/null +++ b/src/ir/ast/block_tree.rs @@ -0,0 +1,24 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::{ + block_tree::BlockTree, + statement_tree::{ControlStatementTree, StatementTree}, + }, +}; + +use super::IRConstructor; + +impl ToIR for BlockTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + for statement in self.statements() { + if let StatementTree::ControlStatement(control_statement) = statement { + if let ControlStatementTree::ReturnTree(return_tree) = control_statement { + return_tree.to_ir(constructor); + break; + } + } + statement.to_ir(constructor); + } + None + } +} diff --git a/src/ir/ast/break_tree.rs b/src/ir/ast/break_tree.rs new file mode 100644 index 0000000..9d1b5f2 --- /dev/null +++ b/src/ir/ast/break_tree.rs @@ -0,0 +1,30 @@ +use tracing::debug; + +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::break_tree::BreakTree, +}; + +use super::IRConstructor; + +impl ToIR for BreakTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!( + "Generating IR for break statement with active loops: {:?}", + constructor.active_loop_exits + ); + let jump = constructor.create_jump(); + constructor.register_entry_point( + *constructor.active_loop_exits.last().unwrap(), + constructor.current_block(), + jump, + ); + debug!( + "Modifying entry_points of {:?}", + constructor + .graph + .get_block_mut(*constructor.active_loop_exits.last().unwrap()) + ); + None + } +} diff --git a/src/ir/ast/call_tree.rs b/src/ir/ast/call_tree.rs new file mode 100644 index 0000000..7da0e33 --- /dev/null +++ b/src/ir/ast/call_tree.rs @@ -0,0 +1,12 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::call_tree::CallTree, +}; + +use super::IRConstructor; + +impl ToIR for CallTree { + fn to_ir(&self, _constructor: &mut IRConstructor) -> Option { + unimplemented!() + } +} diff --git a/src/ir/ast/continue_tree.rs b/src/ir/ast/continue_tree.rs new file mode 100644 index 0000000..5c05af7 --- /dev/null +++ b/src/ir/ast/continue_tree.rs @@ -0,0 +1,24 @@ +use tracing::debug; + +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::continue_tree::ContinueTree, +}; + +use super::IRConstructor; + +impl ToIR for ContinueTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!( + "Generating IR for continue statement with active loops: {:?}", + constructor.active_loop_entries + ); + let jump = constructor.create_jump(); + constructor.register_entry_point( + *constructor.active_loop_entries.last().unwrap(), + constructor.current_block(), + jump, + ); + None + } +} diff --git a/src/ir/ast/declaration_tree.rs b/src/ir/ast/declaration_tree.rs new file mode 100644 index 0000000..410fb75 --- /dev/null +++ b/src/ir/ast/declaration_tree.rs @@ -0,0 +1,22 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::declaration_tree::DeclarationTree, +}; + +use super::IRConstructor; + +impl ToIR for DeclarationTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + if let Some(initializer) = self.initializer_tree() { + let rhs = initializer + .to_ir(constructor) + .expect("Expected RHS of declaration to be expression"); + constructor.write_variable( + self.name_tree().name().clone(), + constructor.current_block(), + rhs, + ); + } + None + } +} diff --git a/src/ir/ast/expression_tree.rs b/src/ir/ast/expression_tree.rs new file mode 100644 index 0000000..1f5db08 --- /dev/null +++ b/src/ir/ast/expression_tree.rs @@ -0,0 +1,19 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::expression_tree::ExpressionTree, +}; + +use super::IRConstructor; + +impl ToIR for ExpressionTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + match self { + ExpressionTree::BooleanLiteralTree(tree) => tree.to_ir(constructor), + ExpressionTree::IntegerLiteralTree(tree) => tree.to_ir(constructor), + ExpressionTree::IdentifierExpressionTree(tree) => tree.to_ir(constructor), + ExpressionTree::UnaryOperationTree(tree) => tree.to_ir(constructor), + ExpressionTree::BinaryOperationTree(tree) => tree.to_ir(constructor), + ExpressionTree::TernaryOperationTree(tree) => tree.to_ir(constructor), + } + } +} diff --git a/src/ir/ast/for_tree.rs b/src/ir/ast/for_tree.rs new file mode 100644 index 0000000..623b0fd --- /dev/null +++ b/src/ir/ast/for_tree.rs @@ -0,0 +1,74 @@ +use tracing::debug; + +use crate::{ + ir::{ + ast::ToIR, + block::{Block, NodeIndex}, + }, + parser::ast::for_tree::ForTree, +}; + +use super::IRConstructor; + +impl ToIR for ForTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!("Generating IR for for expression"); + if let Some(initializer) = self.initializer() { + initializer.to_ir(constructor); + } + let inverted_entry_condition_node = constructor.create_inverted_condition(self.condition()); + let entry_conditional_jump = + constructor.create_conditional_jump(inverted_entry_condition_node); + + let entry_true_projection = constructor.create_true_projection(entry_conditional_jump); + let entry_false_projection = constructor.create_false_projection(entry_conditional_jump); + + let mut loop_body = Block::new("for-body".to_string()); + loop_body.register_entry_point(constructor.current_block(), entry_false_projection); + let loop_body_index = constructor.register_block(loop_body); + let mut following_block = Block::new("for-following".to_string()); + following_block.register_entry_point(constructor.current_block(), entry_true_projection); + let following_block_index = constructor.register_block(following_block); + let loop_post = Block::new("for-post".to_string()); + let loop_post_index = constructor.register_block(loop_post); + + constructor.seal_block(constructor.current_block()); + + constructor.set_current_block(loop_body_index); + constructor.active_loop_entries.push(loop_post_index); + constructor.active_loop_exits.push(following_block_index); + self.statement().to_ir(constructor); + constructor.active_loop_entries.pop(); + constructor.active_loop_exits.pop(); + let loop_body_exit = constructor.create_jump(); + constructor.register_entry_point( + loop_post_index, + constructor.current_block(), + loop_body_exit, + ); + constructor.set_current_block(loop_post_index); + constructor.seal_block(loop_post_index); + + if let Some(advancement) = self.advancement() { + advancement.to_ir(constructor); + } + + let condition_node = self + .condition() + .to_ir(constructor) + .expect("Expected condition to be statement"); + let conditional_jump = constructor.create_conditional_jump(condition_node); + + let true_projection = constructor.create_true_projection(conditional_jump); + let false_projection = constructor.create_false_projection(conditional_jump); + + constructor.register_entry_point(loop_body_index, loop_post_index, true_projection); + constructor.seal_block(loop_body_index); + constructor.register_entry_point(following_block_index, loop_post_index, false_projection); + constructor.seal_block(loop_body_index); + constructor.set_current_block(following_block_index); + constructor.seal_block(constructor.current_block()); + debug!("Following block after for: {}", constructor.current_block()); + None + } +} diff --git a/src/ir/ast/function_tree.rs b/src/ir/ast/function_tree.rs new file mode 100644 index 0000000..65b2944 --- /dev/null +++ b/src/ir/ast/function_tree.rs @@ -0,0 +1,46 @@ +use crate::{ + ir::{ + ast::ToIR, + block::{Block, NodeIndex}, + graph::{END_BLOCK, START_BLOCK}, + node::{ + projection::{ProjectionData, ProjectionInformation}, + Node, + }, + }, + parser::ast::function_tree::FunctionTree, +}; + +use super::IRConstructor; + +impl ToIR for FunctionTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let mut function_body_block = Block::new("fn-body".to_string()); + // Function body can be entered from start function block + function_body_block.register_entry_point(START_BLOCK, 0); + let side_effect_projection = function_body_block.register_node(Node::Projection( + ProjectionData::new(0, ProjectionInformation::SideEffect), + )); + let function_body_block_index = constructor.register_block(function_body_block); + constructor.set_current_block(function_body_block_index); + + constructor.write_current_side_effect(side_effect_projection); + self.body().to_ir(constructor); + constructor.seal_block(constructor.current_block()); + + // The last statement after parsing the body can exit the function + if !constructor.get_block(constructor.current_block()).empty() { + let last_statement_index = constructor + .get_block(constructor.current_block()) + .get_last_node_index(); + constructor.register_entry_point( + END_BLOCK, + constructor.current_block(), + last_statement_index, + ); + } else { + constructor.register_entry_point(END_BLOCK, constructor.current_block(), 0); + } + None + } +} diff --git a/src/ir/ast/identifier_tree.rs b/src/ir/ast/identifier_tree.rs new file mode 100644 index 0000000..07ce3b2 --- /dev/null +++ b/src/ir/ast/identifier_tree.rs @@ -0,0 +1,14 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::identifier_tree::IdentifierExpressionTree, +}; + +use super::IRConstructor; + +impl ToIR for IdentifierExpressionTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let value = + constructor.read_variable(self.name().name().clone(), constructor.current_block()); + Some(value) + } +} diff --git a/src/ir/ast/if_tree.rs b/src/ir/ast/if_tree.rs new file mode 100644 index 0000000..e8ea905 --- /dev/null +++ b/src/ir/ast/if_tree.rs @@ -0,0 +1,53 @@ +use tracing::debug; + +use crate::{ + ir::{ + ast::ToIR, + block::{Block, NodeIndex}, + }, + parser::ast::if_tree::IfTree, +}; + +use super::IRConstructor; + +impl ToIR for IfTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!("Generating IR for If"); + let condition_node = self + .condition() + .to_ir(constructor) + .expect("Condition of if statement not a condition!"); + let conditional_jump = constructor.create_conditional_jump(condition_node); + + let true_projection = constructor.create_true_projection(conditional_jump); + let false_projection = constructor.create_false_projection(conditional_jump); + + let mut false_block = Block::new("if-false".to_string()); + false_block.register_entry_point(constructor.current_block(), false_projection); + let mut true_block = Block::new("if-true".to_string()); + true_block.register_entry_point(constructor.current_block(), true_projection); + constructor.seal_block(constructor.current_block()); + let mut following_block = Block::new("if-following".to_string()); + + let false_block_index = constructor.register_block(false_block); + constructor.seal_block(false_block_index); + constructor.set_current_block(false_block_index); + if let Some(else_statement) = self.else_statement() { + else_statement.to_ir(constructor); + } + let false_jump = constructor.create_jump(); + following_block.register_entry_point(constructor.current_block(), false_jump); + + let true_block_index = constructor.register_block(true_block); + constructor.seal_block(true_block_index); + constructor.set_current_block(true_block_index); + self.if_statement().to_ir(constructor); + let true_jump = constructor.create_jump(); + following_block.register_entry_point(constructor.current_block(), true_jump); + + let following_block_index = constructor.register_block(following_block); + constructor.set_current_block(following_block_index); + constructor.seal_block(following_block_index); + None + } +} diff --git a/src/ir/ast/literal_tree.rs b/src/ir/ast/literal_tree.rs new file mode 100644 index 0000000..2ee3ef7 --- /dev/null +++ b/src/ir/ast/literal_tree.rs @@ -0,0 +1,26 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::literal_tree::{BooleanLiteralTree, IntegerLiteralTree}, + util::int_parsing::parse_int, +}; + +use super::IRConstructor; + +impl ToIR for IntegerLiteralTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let value = parse_int(self.value().to_owned(), self.base() as u64)?; + let node = constructor.create_constant_int(value); + Some(node) + } +} + +impl ToIR for BooleanLiteralTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let node = if self.value() { + constructor.create_constant_int(1) + } else { + constructor.create_constant_int(0) + }; + Some(node) + } +} diff --git a/src/ir/ast/mod.rs b/src/ir/ast/mod.rs new file mode 100644 index 0000000..6e55f7f --- /dev/null +++ b/src/ir/ast/mod.rs @@ -0,0 +1,617 @@ +use std::{collections::HashMap, usize}; + +use tracing::{debug, info, trace}; + +use crate::{ + ir::{ + block::{Block, NodeIndex}, + graph::{BlockIndex, IRGraph, START_BLOCK}, + node::{ + binary_operation::BinaryOperationData, + projection::{ProjectionData, ProjectionInformation}, + unary_operation::UnaryOperationData, + ConstantBoolData, ConstantIntData, Node, PhiData, ReturnData, + }, + }, + lexer::operator::BinaryOperator, + parser::{ast::expression_tree::ExpressionTree, symbols::Name}, +}; + +pub mod assignment_tree; +pub mod binary_operation_tree; +pub mod block_tree; +pub mod break_tree; +pub mod call_tree; +pub mod continue_tree; +pub mod declaration_tree; +pub mod expression_tree; +pub mod for_tree; +pub mod function_tree; +pub mod identifier_tree; +pub mod if_tree; +pub mod literal_tree; +pub mod program_tree; +pub mod return_tree; +pub mod statement_tree; +pub mod ternary_operation_tree; +pub mod unary_operation_tree; +pub mod while_tree; + +pub struct IRConstructor { + graph: IRGraph, + current_definitions: HashMap>, + incomplete_phis: HashMap>, + current_side_effect: HashMap, + _incomplete_side_effect_phis: HashMap, + sealed_blocks: Vec, + current_block_index: BlockIndex, + active_loop_entries: Vec, + active_loop_exits: Vec, +} + +pub trait ToIR { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option; +} + +impl IRConstructor { + pub fn new() -> IRConstructor { + IRConstructor { + graph: IRGraph::new(), + current_definitions: HashMap::new(), + incomplete_phis: HashMap::new(), + current_side_effect: HashMap::new(), + _incomplete_side_effect_phis: HashMap::new(), + sealed_blocks: vec![START_BLOCK], + current_block_index: START_BLOCK, + active_loop_entries: Vec::new(), + active_loop_exits: Vec::new(), + } + } + + pub fn current_block(&self) -> BlockIndex { + self.current_block_index + } + + pub fn set_current_block(&mut self, block_index: BlockIndex) { + self.current_block_index = block_index; + } + + pub fn get_block(&self, block_index: BlockIndex) -> &Block { + self.graph.get_block(block_index) + } + + pub fn get_block_mut(&mut self, block_index: BlockIndex) -> &mut Block { + self.graph.get_block_mut(block_index) + } + + pub fn register_entry_point( + &mut self, + block_target: BlockIndex, + block_origin: BlockIndex, + node_origin: NodeIndex, + ) { + self.graph + .get_block_mut(block_target) + .register_entry_point(block_origin, node_origin); + } + + pub fn register_block(&mut self, block: Block) -> BlockIndex { + self.graph.register_block(block) + } + + fn create_jump(&mut self) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Jump) + } + + fn create_add(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Add(BinaryOperationData::new(lhs, rhs))) + } + + fn create_inverted_condition(&mut self, condition: &ExpressionTree) -> NodeIndex { + match condition { + ExpressionTree::BinaryOperationTree(tree) => { + let left_node = tree + .lhs() + .to_ir(self) + .expect("Expected LHS to be expression"); + let right_node = tree + .rhs() + .to_ir(self) + .expect("Expected RHS to be expression"); + let current_block = self.graph.get_block_mut(self.current_block_index); + match tree.operator() { + BinaryOperator::Lower => current_block.register_node(Node::HigherEquals( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::Higher => current_block.register_node(Node::LowerEquals( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::Equals => current_block.register_node(Node::NotEquals( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::NotEquals => current_block.register_node(Node::Equals( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::LowerEquals => current_block.register_node(Node::Higher( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::HigherEquals => current_block.register_node(Node::Lower( + BinaryOperationData::new(left_node, right_node), + )), + BinaryOperator::LogicalAnd => todo!(), + BinaryOperator::Mul + | BinaryOperator::Div + | BinaryOperator::Mod + | BinaryOperator::Plus + | BinaryOperator::ShiftLeft + | BinaryOperator::BitwiseOr + | BinaryOperator::LogicalOr + | BinaryOperator::ShiftRight + | BinaryOperator::BitwiseAnd + | BinaryOperator::BitwiseXor + | BinaryOperator::Minus => { + unreachable!("Ensured by semantic analysis!") + } + } + } + ExpressionTree::BooleanLiteralTree(tree) => { + if tree.value() { + self.create_constant_int(0) + } else { + self.create_constant_int(1) + } + } + ExpressionTree::IdentifierExpressionTree(tree) => { + let variable = tree + .to_ir(self) + .expect("Expected Identfier to be expression"); + self.create_logical_not(variable) + } + ExpressionTree::IntegerLiteralTree(_) => { + unreachable!("Integer literal tree cannot occur in top level condition") + } + ExpressionTree::UnaryOperationTree(_tree) => todo!(), + ExpressionTree::TernaryOperationTree(_tree) => todo!(), + } + } + + fn create_sub(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Subtraction(BinaryOperationData::new(lhs, rhs))) + } + + fn create_mul(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Multiplication(BinaryOperationData::new(lhs, rhs))) + } + + fn create_div(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Division(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_mod(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Modulo(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_shift_left(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::ShiftLeft(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_shift_right(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::ShiftRight(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_lower(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Lower(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_lower_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::LowerEquals(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Equals(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_not_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Lower(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_higher_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::HigherEquals( + BinaryOperationData::new_with_sideeffect(lhs, rhs, sideeffect), + )) + } + + fn create_higher(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Higher(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_or(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Or(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_and(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::And(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_xor(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Xor(BinaryOperationData::new_with_sideeffect( + lhs, rhs, sideeffect, + ))) + } + + fn create_bitwise_not(&mut self, node: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::BitwiseNegate( + UnaryOperationData::new_with_sideeffect(node, sideeffect), + )) + } + + fn create_logical_not(&mut self, node: NodeIndex) -> NodeIndex { + let sideeffect = self.read_current_side_effect(); + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::LogicalNot(UnaryOperationData::new_with_sideeffect( + node, sideeffect, + ))) + } + + fn create_constant_int(&mut self, value: i32) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::ConstantInt(ConstantIntData::new(value))) + } + + fn _create_constant_bool(&mut self, value: bool) -> NodeIndex { + let start_block = self.graph.get_block_mut(START_BLOCK); + start_block.register_node(Node::ConstantBool(ConstantBoolData::new(value))) + } + + fn create_return(&mut self, input: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + let return_node_index = current_block.register_node(Node::Return(ReturnData::new(input))); + self.graph + .end_block_mut() + .register_entry_point(self.current_block_index, return_node_index); + return_node_index + } + + pub fn create_conditional_jump(&mut self, condition: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::ConditionalJump(UnaryOperationData::new(condition))) + } + + pub fn process_branch(&mut self, branch: &ExpressionTree, label: &str) -> usize { + let block = Block::new(format!("if-body-{}", label)); + self.current_block_index = self.graph.register_block(block); + self.seal_block(self.current_block_index); + branch.to_ir(self); + self.seal_block(self.current_block_index); + self.create_jump() + } + + fn _create_phi(&mut self) -> usize { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Phi(PhiData::empty())) + } + + fn create_phi_from_operands(&mut self, operands: Vec<(BlockIndex, NodeIndex)>) -> usize { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Phi(PhiData::new(operands))) + } + + fn _create_phi_operands(&mut self, block_index: BlockIndex) -> NodeIndex { + let block = self.graph.get_block(block_index); + let operands = block + .entry_points() + .iter() + .flat_map(|(v1, v2)| v2.iter().map(|v| (v1.clone(), v))) + .map(|(v1, v2)| (v1, *v2)) + .collect(); + trace!("Creating phi with operands {:?}", operands); + let current_block = self.graph.get_block_mut(block_index); + current_block.register_node(Node::Phi(PhiData::new(operands))) + } + + fn create_phi_variable_operands( + &mut self, + phi: usize, + block_index: BlockIndex, + variable: Name, + ) -> NodeIndex { + // Creating the operands for a block, by iterating over its entry points and reading the + // variable there + let mut operands = Vec::new(); + for (block_index, _) in self.graph.get_block(block_index).entry_points().clone() { + operands.push(( + block_index, + self.read_variable(variable.clone(), block_index), + )); + } + trace!( + "Created phi operands for block {} whilst reading {:?}: {:?}", + block_index, + variable, + operands + ); + + if let Node::Phi(data) = self.graph.get_block_mut(block_index).get_node_mut(phi) { + for operand in operands { + data.add_operand(operand); + } + } + phi + } + + fn create_div_mod_projection(&mut self, input: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + let projection_side_effect = current_block.register_node(Node::Projection( + ProjectionData::new(input, ProjectionInformation::SideEffect), + )); + let result_projection = current_block.register_node(Node::Projection(ProjectionData::new( + input, + ProjectionInformation::Result, + ))); + self.write_current_side_effect(projection_side_effect); + result_projection + } + + fn write_variable(&mut self, variable: Name, block: usize, node: usize) { + trace!("Trying to write into variable {:?}", variable); + match self.current_definitions.contains_key(&variable) { + true => { + self.current_definitions + .get_mut(&variable) + .unwrap() + .insert(block, node); + } + false => { + self.current_definitions + .insert(variable, HashMap::from([(block, node)])); + } + } + } + + fn read_variable(&mut self, variable: Name, block: BlockIndex) -> NodeIndex { + trace!( + "Trying to read from variable {:?} in block {}", + variable, + block + ); + if self.current_definitions.contains_key(&variable) { + if self + .current_definitions + .get(&variable) + .unwrap() + .contains_key(&block) + { + trace!("Variable defined in the same block! Returning value"); + *self + .current_definitions + .get(&variable) + .unwrap() + .get(&block) + .unwrap() + } else { + self.read_variable_recursive(variable, block) + } + } else { + self.read_variable_recursive(variable, block) + } + } + + fn read_variable_recursive(&mut self, variable: Name, block_index: BlockIndex) -> NodeIndex { + trace!( + "Reading variable {:?} recursively in block {}", + variable, + block_index + ); + trace!("Sealed blocks: {:?}", self.sealed_blocks); + let node = if !self.sealed_blocks.contains(&block_index) { + // Current block is not sealed yet, the list of operands is not final yet + let phi = self + .graph + .get_block_mut(block_index) + .register_node(Node::Phi(PhiData::empty())); + trace!("Writing incomplete phi: ({:?}, {})", variable, phi); + if self.incomplete_phis.contains_key(&block_index) { + let mut entry = self.incomplete_phis.get_mut(&block_index).unwrap().clone(); + entry.insert(variable.clone(), phi); + self.incomplete_phis.insert(block_index, entry); + } else { + self.incomplete_phis + .insert(block_index, HashMap::from([(variable.clone(), phi)])); + }; + phi + } else if self.graph.get_block(block_index).entry_points().len() == 1 { + // The block we are reading the variable in is sealed and has one previous block. + // We can read the variable from there + let previous_block = self + .graph + .get_block(block_index) + .entry_points() + .iter() + .last() + .unwrap() + .0 + .clone(); + let defining_node = self.read_variable(variable.clone(), previous_block); + let phi = self + .graph + .get_block_mut(block_index) + .register_node(Node::Phi(PhiData::new(vec![( + previous_block, + defining_node, + )]))); + phi + } else { + // The block we are reading the variable in has multiple entry points and is sealed. + // The value for the variable can come from multiple previous blocks. + // The value of the variable is dependent on the values of the variable in the previous + // blocks + let phi = self + .graph + .get_block_mut(block_index) + .register_node(Node::Phi(PhiData::empty())); + self.write_variable(variable.clone(), block_index, phi); + self.create_phi_variable_operands(phi, block_index, variable.clone()); + phi + }; + + // Denote that the newly created phi defines the variable in the current block + self.write_variable(variable.clone(), block_index, node); + node + } + + fn seal_block(&mut self, block: BlockIndex) { + debug!( + "Current graph before sealing block {}: {}", + block, self.graph + ); + info!("Incomplete Phis: {:?}", self.incomplete_phis); + if !self.incomplete_phis.contains_key(&block) { + self.sealed_blocks.push(block); + return; + } + for (block_index, definitions) in &self.incomplete_phis.clone() { + if block.ne(block_index) { + continue; + } + for (variable, phi) in definitions { + let operands = { + let mut operands = Vec::new(); + let phi_block = self.graph.get_block_mut(*block_index); + for (prev_block, _prev_nodes) in phi_block.entry_points().clone() { + operands + .push((prev_block, self.read_variable(variable.clone(), prev_block))); + } + operands + }; + let block = self.graph.get_block_mut(*block_index); + if let Node::Phi(data) = block.get_node_mut(*phi) { + for operand in operands { + data.add_operand(operand); + } + } + } + } + self.sealed_blocks.push(block); + } + + fn write_current_side_effect(&mut self, node: usize) { + self.write_side_effect(self.current_block_index, node); + } + + fn write_side_effect(&mut self, block: usize, node: usize) { + self.current_side_effect.insert(block, node); + } + + fn read_current_side_effect(&mut self) -> usize { + return 0; + //self.read_side_effect(self.current_block_index) + } + + fn _read_side_effect(&mut self, block: usize) -> usize { + if self.current_side_effect.contains_key(&block) { + *self.current_side_effect.get(&block).unwrap() + } else { + self._read_side_effect_recusive(block) + } + } + + fn _read_side_effect_recusive(&mut self, block: usize) -> usize { + let node = if !self.sealed_blocks.contains(&block) { + let phi = self._create_phi(); + let old_phi = self._incomplete_side_effect_phis.insert(block, phi); + if old_phi.is_some() { + panic!("Double read side effect recursive!"); + } + phi + } else if self.graph.get_block(block).entry_points().len() == 1 { + let (previous_block, _) = self + .graph + .get_block(block) + .entry_points() + .iter() + .last() + .unwrap(); + self._read_side_effect(*previous_block) + } else { + let phi = self._create_phi_operands(block); + self.write_side_effect(block, phi); + phi + }; + self.write_side_effect(block, node); + node + } + + pub fn graph(self) -> IRGraph { + self.graph + } + + pub fn create_true_projection(&mut self, conditional_jump: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Projection(ProjectionData::new( + conditional_jump, + ProjectionInformation::IfTrue, + ))) + } + + pub fn create_false_projection(&mut self, conditional_jump: NodeIndex) -> NodeIndex { + let current_block = self.graph.get_block_mut(self.current_block_index); + current_block.register_node(Node::Projection(ProjectionData::new( + conditional_jump, + ProjectionInformation::IfFalse, + ))) + } +} diff --git a/src/ir/ast/program_tree.rs b/src/ir/ast/program_tree.rs new file mode 100644 index 0000000..a4e230c --- /dev/null +++ b/src/ir/ast/program_tree.rs @@ -0,0 +1,15 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::program_tree::ProgramTree, +}; + +use super::IRConstructor; + +impl ToIR for ProgramTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + for function in self.functions() { + function.to_ir(constructor); + } + None + } +} diff --git a/src/ir/ast/return_tree.rs b/src/ir/ast/return_tree.rs new file mode 100644 index 0000000..3577531 --- /dev/null +++ b/src/ir/ast/return_tree.rs @@ -0,0 +1,17 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::return_tree::ReturnTree, +}; + +use super::IRConstructor; + +impl ToIR for ReturnTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + let node = self + .expression() + .to_ir(constructor) + .expect("Return must have a expression"); + constructor.create_return(node); + None + } +} diff --git a/src/ir/ast/statement_tree.rs b/src/ir/ast/statement_tree.rs new file mode 100644 index 0000000..d237e14 --- /dev/null +++ b/src/ir/ast/statement_tree.rs @@ -0,0 +1,39 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + parser::ast::statement_tree::{ControlStatementTree, SimpleStatementTree, StatementTree}, +}; + +use super::IRConstructor; + +impl ToIR for StatementTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + match self { + StatementTree::BlockStatement(tree) => tree.to_ir(constructor), + StatementTree::SimpleStatement(tree) => tree.to_ir(constructor), + StatementTree::ControlStatement(tree) => tree.to_ir(constructor), + } + } +} + +impl ToIR for SimpleStatementTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + match self { + SimpleStatementTree::CallTree(tree) => tree.to_ir(constructor), + SimpleStatementTree::AssignmentTree(tree) => tree.to_ir(constructor), + SimpleStatementTree::DeclerationTree(tree) => tree.to_ir(constructor), + } + } +} + +impl ToIR for ControlStatementTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + match self { + ControlStatementTree::IfTree(tree) => tree.to_ir(constructor), + ControlStatementTree::WhileTree(tree) => tree.to_ir(constructor), + ControlStatementTree::ForTree(tree) => tree.to_ir(constructor), + ControlStatementTree::BreakTree(tree) => tree.to_ir(constructor), + ControlStatementTree::ContinueTree(tree) => tree.to_ir(constructor), + ControlStatementTree::ReturnTree(tree) => tree.to_ir(constructor), + } + } +} diff --git a/src/ir/ast/ternary_operation_tree.rs b/src/ir/ast/ternary_operation_tree.rs new file mode 100644 index 0000000..890849b --- /dev/null +++ b/src/ir/ast/ternary_operation_tree.rs @@ -0,0 +1,63 @@ +use tracing::debug; + +use crate::{ + ir::{ + ast::ToIR, + block::{Block, NodeIndex}, + }, + parser::ast::ternary_operation_tree::TernaryOperationTree, +}; + +use super::IRConstructor; + +impl ToIR for TernaryOperationTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!("Generating IR for TernaryOperation"); + let condition_node = self + .condition() + .to_ir(constructor) + .expect("Expected condition of ternary operation to be an expression"); + let conditional_jump = constructor.create_conditional_jump(condition_node); + + let true_projection = constructor.create_true_projection(conditional_jump); + let false_projection = constructor.create_false_projection(conditional_jump); + + let mut false_block = Block::new("ternary-false".to_string()); + false_block.register_entry_point(constructor.current_block(), false_projection); + let mut true_block = Block::new("ternary-true".to_string()); + true_block.register_entry_point(constructor.current_block(), true_projection); + constructor.seal_block(constructor.current_block()); + let mut following_block = Block::new("ternary-following".to_string()); + + let false_block_index = constructor.register_block(false_block); + constructor.set_current_block(false_block_index); + let false_expression = self + .false_expression() + .to_ir(constructor) + .expect("Expected false expression in ternary operation to be expression"); + let false_jump = constructor.create_jump(); + following_block.register_entry_point(constructor.current_block(), false_jump); + constructor.seal_block(false_block_index); + + let true_block_index = constructor.register_block(true_block); + constructor.set_current_block(true_block_index); + let true_expression = self + .true_expression() + .to_ir(constructor) + .expect("Expected true expression in ternary operation to be expression"); + let true_jump = constructor.create_jump(); + following_block.register_entry_point(constructor.current_block(), true_jump); + constructor.seal_block(true_block_index); + + let following_block_index = constructor.register_block(following_block); + constructor.set_current_block(following_block_index); + constructor.seal_block(true_block_index); + constructor.seal_block(false_block_index); + let phi = constructor.create_phi_from_operands(vec![ + (false_block_index, false_expression), + (true_block_index, true_expression), + ]); + constructor.seal_block(constructor.current_block()); + Some(phi) + } +} diff --git a/src/ir/ast/unary_operation_tree.rs b/src/ir/ast/unary_operation_tree.rs new file mode 100644 index 0000000..ed9d58c --- /dev/null +++ b/src/ir/ast/unary_operation_tree.rs @@ -0,0 +1,39 @@ +use crate::{ + ir::{ast::ToIR, block::NodeIndex}, + lexer::operator::UnaryOperator, + parser::ast::unary_operation_tree::UnaryOperationTree, +}; + +use super::IRConstructor; + +impl ToIR for UnaryOperationTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + match self.operator() { + UnaryOperator::Minus => { + let node = self + .expression() + .to_ir(constructor) + .expect("Expected operand of unary operator to be expression"); + let zero = constructor.create_constant_int(0); + let result = constructor.create_sub(zero, node); + Some(result) + } + UnaryOperator::BitwiseNot => { + let node = self + .expression() + .to_ir(constructor) + .expect("Expected operand of unary operator to be expression"); + let result = constructor.create_bitwise_not(node); + Some(result) + } + UnaryOperator::LogicalNot => { + let node = self + .expression() + .to_ir(constructor) + .expect("Expected operand of unary operator to be expression"); + let result = constructor.create_logical_not(node); + Some(result) + } + } + } +} diff --git a/src/ir/ast/while_tree.rs b/src/ir/ast/while_tree.rs new file mode 100644 index 0000000..93d42d4 --- /dev/null +++ b/src/ir/ast/while_tree.rs @@ -0,0 +1,69 @@ +use tracing::debug; + +use crate::{ + ir::{ + ast::ToIR, + block::{Block, NodeIndex}, + }, + parser::ast::while_tree::WhileTree, +}; + +use super::IRConstructor; + +impl ToIR for WhileTree { + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + debug!("Generating IR for while"); + let inverted_entry_condition_node = constructor.create_inverted_condition(self.condition()); + let entry_conditional_jump = + constructor.create_conditional_jump(inverted_entry_condition_node); + + let entry_true_projection = constructor.create_true_projection(entry_conditional_jump); + let entry_false_projection = constructor.create_false_projection(entry_conditional_jump); + + let mut loop_body = Block::new("while-body".to_string()); + loop_body.register_entry_point(constructor.current_block(), entry_false_projection); + let loop_body_index = constructor.register_block(loop_body); + let loop_back_block = Block::new("while-condition".to_string()); + let loop_back_block_index = constructor.register_block(loop_back_block); + let mut following_block = Block::new("while-following".to_string()); + following_block.register_entry_point(constructor.current_block(), entry_true_projection); + let following_block_index = constructor.register_block(following_block); + constructor.seal_block(constructor.current_block()); + + constructor.set_current_block(loop_body_index); + constructor.active_loop_entries.push(loop_back_block_index); + constructor.active_loop_exits.push(following_block_index); + self.statement().to_ir(constructor); + let loop_body_jump = constructor.create_jump(); + constructor.register_entry_point( + loop_back_block_index, + constructor.current_block(), + loop_body_jump, + ); + constructor.active_loop_entries.pop(); + constructor.active_loop_exits.pop(); + + constructor.set_current_block(loop_back_block_index); + constructor.seal_block(loop_back_block_index); + let condition_node = self + .condition() + .to_ir(constructor) + .expect("Expected condition of while to be expression"); + let conditional_jump = constructor.create_conditional_jump(condition_node); + + let true_projection = constructor.create_true_projection(conditional_jump); + let false_projection = constructor.create_false_projection(conditional_jump); + + constructor.register_entry_point(loop_body_index, loop_back_block_index, true_projection); + constructor.seal_block(loop_body_index); + constructor.register_entry_point( + following_block_index, + loop_back_block_index, + false_projection, + ); + constructor.seal_block(loop_body_index); + constructor.set_current_block(following_block_index); + constructor.seal_block(constructor.current_block()); + None + } +} diff --git a/src/ir/constructor.rs b/src/ir/constructor.rs deleted file mode 100644 index 4b4b376..0000000 --- a/src/ir/constructor.rs +++ /dev/null @@ -1,1031 +0,0 @@ -use core::panic; -use std::collections::HashMap; - -use tracing::{debug, info, trace}; - -use crate::{ - ir::{ - block::Block, - graph::START_BLOCK, - node::{ - binary_operation::BinaryOperationData, - projection::{ProjectionData, ProjectionInformation}, - }, - }, - lexer::token::{OperatorType, Token}, - parser::{ast::Tree, symbols::Name}, - util::int_parsing::parse_int, -}; - -use super::{ - block::NodeIndex, - graph::{BlockIndex, IRGraph}, - node::{ - unary_operation::UnaryOperationData, ConstantBoolData, ConstantIntData, Node, PhiData, - ReturnData, - }, -}; - -pub struct IRGraphConstructor { - graph: IRGraph, - current_definitions: HashMap>, - incomplete_phis: HashMap>, - current_side_effect: HashMap, - _incomplete_side_effect_phis: HashMap, - sealed_blocks: Vec, - current_block_index: BlockIndex, - active_loop_entries: Vec, - active_loop_exits: Vec, -} - -impl IRGraphConstructor { - pub fn new() -> IRGraphConstructor { - IRGraphConstructor { - graph: IRGraph::new(), - current_definitions: HashMap::new(), - incomplete_phis: HashMap::new(), - current_side_effect: HashMap::new(), - _incomplete_side_effect_phis: HashMap::new(), - // Start Block never gets more predecessors - sealed_blocks: vec![START_BLOCK], - current_block_index: START_BLOCK, - active_loop_entries: Vec::new(), - active_loop_exits: Vec::new(), - } - } - - pub fn convert(&mut self, tree: Tree) -> Option { - debug!("Converting AST {:?} to IR!", tree); - match tree { - Tree::Program(_) => { - unimplemented!("Program Trees cannot be parsed to a single IR Representation!") - } - Tree::Function(_, _, body) => { - let mut function_body_block = Block::new("fn-body".to_string()); - // Function body can be entered from start function block - function_body_block.register_entry_point(START_BLOCK, 0); - let side_effect_projection = function_body_block.register_node(Node::Projection( - ProjectionData::new(0, ProjectionInformation::SideEffect), - )); - self.current_block_index = self.graph.register_block(function_body_block); - - self.write_current_side_effect(side_effect_projection); - self.convert_boxed(body); - self.seal_block(self.current_block_index); - - // The last statement after parsing the body can exit the function - if !self.graph.get_block(self.current_block_index).empty() { - let last_statement_index = self - .graph - .get_block(self.current_block_index) - .get_last_node_index(); - self.graph - .end_block_mut() - .register_entry_point(self.current_block_index, last_statement_index); - } else { - self.graph - .end_block_mut() - .register_entry_point(self.current_block_index, 0); - } - None - } - Tree::Assignment(lvalue, operator, expression) => match *lvalue { - Tree::LValueIdentifier(identifier) => { - if let Tree::Name(name, _) = *identifier { - let rhs = self.convert_boxed(expression).expect("Invalid expression!"); - if let Token::Operator(_, operator_type) = operator { - match operator_type { - OperatorType::AssignMinus => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_sub(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignPlus => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_add(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignMul => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_mul(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignDiv => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let div = self.create_div(lhs, rhs); - let desugar = self.create_div_mod_projection(div); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignMod => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let mod_node = self.create_mod(lhs, rhs); - let desugar = self.create_div_mod_projection(mod_node); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignShiftLeft => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_shift_left(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignShiftRight => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_shift_right(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignBitwiseOr => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_or(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignBitwiseAnd => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_and(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::AssignBitwiseXor => { - let lhs = - self.read_variable(name.clone(), self.current_block_index); - let desugar = self.create_xor(lhs, rhs); - self.write_variable(name, self.current_block_index, desugar); - } - OperatorType::Assign => { - self.write_variable(name, self.current_block_index, rhs); - } - _ => panic!("Assignment has no assignment operator"), - }; - } - return None; - } - None - } - _ => todo!(), - }, - Tree::BinaryOperation(lhs, rhs, operator_type) => { - let lhs_node = self.convert_boxed(lhs).unwrap(); - let rhs_node = self.convert_boxed(rhs).unwrap(); - let result = match operator_type { - OperatorType::Minus => self.create_sub(lhs_node, rhs_node), - OperatorType::Plus => self.create_add(lhs_node, rhs_node), - OperatorType::Mul => self.create_mul(lhs_node, rhs_node), - OperatorType::Div => { - let div_node = self.create_div(lhs_node, rhs_node); - self.create_div_mod_projection(div_node) - } - OperatorType::Mod => { - let mod_node = self.create_mod(lhs_node, rhs_node); - self.create_div_mod_projection(mod_node) - } - OperatorType::ShiftLeft => self.create_shift_left(lhs_node, rhs_node), - OperatorType::ShiftRight => self.create_shift_right(lhs_node, rhs_node), - OperatorType::Lower => self.create_lower(lhs_node, rhs_node), - OperatorType::LowerEquals => self.create_lower_equals(lhs_node, rhs_node), - OperatorType::Equals => self.create_equals(lhs_node, rhs_node), - OperatorType::NotEquals => self.create_not_equals(lhs_node, rhs_node), - OperatorType::HigherEquals => self.create_higher_equals(lhs_node, rhs_node), - OperatorType::Higher => self.create_higher(lhs_node, rhs_node), - OperatorType::BitwiseOr => self.create_or(lhs_node, rhs_node), - OperatorType::BitwiseAnd => self.create_and(lhs_node, rhs_node), - OperatorType::BitwiseXor => self.create_xor(lhs_node, rhs_node), - OperatorType::LogicalAnd => self.create_and(lhs_node, rhs_node), - OperatorType::LogicalOr => self.create_or(lhs_node, rhs_node), - OperatorType::Assign - | OperatorType::AssignMul - | OperatorType::AssignDiv - | OperatorType::AssignMod - | OperatorType::AssignPlus - | OperatorType::AssignMinus - | OperatorType::AssignShiftLeft - | OperatorType::AssignShiftRight - | OperatorType::AssignBitwiseOr - | OperatorType::AssignBitwiseNot - | OperatorType::AssignBitwiseAnd - | OperatorType::AssignBitwiseXor => { - panic!("Expected binary operator, got assignment operator!") - } - OperatorType::LogicalNot | OperatorType::BitwiseNot => { - panic!("Expected binary operator, got unary operator!") - } - OperatorType::TernaryQuestionMark | OperatorType::TernaryColon => { - panic!("Expected binary operator, got ternary operator!") - } - }; - Some(result) - } - Tree::Block(statements, _) => { - for statement in statements { - if let Tree::Return(_, _) = statement { - self.convert(statement); - break; - } - self.convert(statement); - } - None - } - Tree::Declaration(_, identifier, initializer) => { - if let Tree::Name(name, _) = *identifier { - if initializer.is_some() { - let rhs = self.convert_boxed(initializer.unwrap()).unwrap(); - self.write_variable(name, self.current_block_index, rhs); - } - None - } else { - panic!("Identifier of declaration is not name!"); - } - } - Tree::IdentifierExpression(identifier) => { - if let Tree::Name(name, _) = *identifier { - let value = self.read_variable(name, self.current_block_index); - Some(value) - } else { - panic!("Identifier expression did not have name as identifier!") - } - } - Tree::Literal(constant, base, _) => { - let value = parse_int(constant, base)?; - let node = self.create_constant_int(value); - Some(node) - } - Tree::LValueIdentifier(_) => None, - Tree::Name(_, _) => None, - Tree::UnaryOperation(expression, operator_type, _) => match operator_type { - OperatorType::Minus => { - let node = self.convert_boxed(expression)?; - let zero = self.create_constant_int(0); - let result = self.create_sub(zero, node); - Some(result) - } - OperatorType::BitwiseNot => { - let node = self.convert_boxed(expression)?; - let result = self.create_bitwise_not(node); - Some(result) - } - OperatorType::LogicalNot => { - let node = self.convert_boxed(expression)?; - let result = self.create_logical_not(node); - Some(result) - } - _ => panic!("Unregistered Unary Operation {:?}", operator_type), - }, - Tree::Return(expression, _) => { - let node = self.convert_boxed(expression).unwrap(); - self.create_return(node); - None - } - Tree::Type(_, _) => None, - Tree::BoolLiteral(boolean, _) => { - let node = if boolean { - self.create_constant_int(1) - } else { - self.create_constant_int(0) - }; - Some(node) - } - Tree::Break(_) => { - debug!( - "Generating IR for break statement with active loops: {:?}", - self.active_loop_exits - ); - let jump = self.create_jump(); - self.graph - .get_block_mut(*self.active_loop_exits.last().unwrap()) - .register_entry_point(self.current_block_index, jump); - debug!( - "Modifying entry_points of {:?}", - self.graph - .get_block_mut(*self.active_loop_exits.last().unwrap()) - ); - None - } - Tree::Continue(_) => { - debug!( - "Generating IR for continue statement with active loops: {:?}", - self.active_loop_entries - ); - let jump = self.create_jump(); - self.graph - .get_block_mut(*self.active_loop_entries.last().unwrap()) - .register_entry_point(self.current_block_index, jump); - None - } - Tree::TernaryOperation(expression, true_value, false_value) => { - debug!("Generating IR for TernaryOperation"); - let condition_node = self.convert_boxed(expression)?; - let conditional_jump = self.create_conditional_jump(condition_node); - - let true_projection = self.create_true_projection(conditional_jump); - let false_projection = self.create_false_projection(conditional_jump); - - let mut false_block = Block::new("ternary-false".to_string()); - false_block.register_entry_point(self.current_block_index, false_projection); - let mut true_block = Block::new("ternary-true".to_string()); - true_block.register_entry_point(self.current_block_index, true_projection); - self.seal_block(self.current_block_index); - let mut following_block = Block::new("ternary-following".to_string()); - - let false_block_index = self.graph.register_block(false_block); - self.current_block_index = false_block_index; - let false_expression = self.convert_boxed(false_value)?; - let false_jump = self.create_jump(); - following_block.register_entry_point(self.current_block_index, false_jump); - self.seal_block(false_block_index); - - let true_block_index = self.graph.register_block(true_block); - self.current_block_index = true_block_index; - let true_expression = self.convert_boxed(true_value)?; - let true_jump = self.create_jump(); - following_block.register_entry_point(self.current_block_index, true_jump); - self.seal_block(true_block_index); - - self.current_block_index = self.graph.register_block(following_block); - self.seal_block(true_block_index); - self.seal_block(false_block_index); - let phi = self.create_phi_from_operands(vec![ - (false_block_index, false_expression), - (true_block_index, true_expression), - ]); - self.seal_block(self.current_block_index); - Some(phi) - } - Tree::While(condition, expression, _) => { - debug!("Generating IR for while"); - let inverted_entry_condition_node = - self.create_inverted_condition(condition.clone()); - let entry_conditional_jump = - self.create_conditional_jump(inverted_entry_condition_node); - - let entry_true_projection = self.create_true_projection(entry_conditional_jump); - let entry_false_projection = self.create_false_projection(entry_conditional_jump); - - let mut loop_body = Block::new("while-body".to_string()); - loop_body.register_entry_point(self.current_block_index, entry_false_projection); - let loop_body_index = self.graph.register_block(loop_body); - let loop_back_block = Block::new("while-condition".to_string()); - let loop_back_block_index = self.graph.register_block(loop_back_block); - let mut following_block = Block::new("while-following".to_string()); - following_block - .register_entry_point(self.current_block_index, entry_true_projection); - let following_block_index = self.graph.register_block(following_block); - self.seal_block(self.current_block_index); - - self.current_block_index = loop_body_index; - self.active_loop_entries.push(loop_back_block_index); - self.active_loop_exits.push(following_block_index); - self.convert_boxed(expression); - let loop_body_jump = self.create_jump(); - self.graph - .get_block_mut(loop_back_block_index) - .register_entry_point(self.current_block_index, loop_body_jump); - self.active_loop_entries.pop(); - self.active_loop_exits.pop(); - - self.current_block_index = loop_back_block_index; - self.seal_block(loop_back_block_index); - let condition_node = self.convert_boxed(condition)?; - let conditional_jump = self.create_conditional_jump(condition_node); - - let true_projection = self.create_true_projection(conditional_jump); - let false_projection = self.create_false_projection(conditional_jump); - - self.graph - .get_block_mut(loop_body_index) - .register_entry_point(loop_back_block_index, true_projection); - self.seal_block(loop_body_index); - self.graph - .get_block_mut(following_block_index) - .register_entry_point(loop_back_block_index, false_projection); - self.seal_block(loop_body_index); - self.current_block_index = following_block_index; - self.seal_block(self.current_block_index); - None - } - Tree::If(condition, body, else_body, _) => { - debug!("Generating IR for If"); - let condition_node = self.convert_boxed(condition)?; - let conditional_jump = self.create_conditional_jump(condition_node); - - let true_projection = self.create_true_projection(conditional_jump); - let false_projection = self.create_false_projection(conditional_jump); - - let mut false_block = Block::new("if-false".to_string()); - false_block.register_entry_point(self.current_block_index, false_projection); - let mut true_block = Block::new("if-true".to_string()); - true_block.register_entry_point(self.current_block_index, true_projection); - self.seal_block(self.current_block_index); - let mut following_block = Block::new("if-following".to_string()); - - let false_block_index = self.graph.register_block(false_block); - self.seal_block(false_block_index); - self.current_block_index = false_block_index; - if let Some(else_statements) = else_body { - self.convert_boxed(else_statements); - } - let false_jump = self.create_jump(); - following_block.register_entry_point(self.current_block_index, false_jump); - - let true_block_index = self.graph.register_block(true_block); - self.seal_block(true_block_index); - self.current_block_index = true_block_index; - self.convert_boxed(body); - let true_jump = self.create_jump(); - following_block.register_entry_point(self.current_block_index, true_jump); - - self.current_block_index = self.graph.register_block(following_block); - self.seal_block(self.current_block_index); - None - } - Tree::For(option_initializer, condition, option_postincrement, expression, _) => { - debug!("Generating IR for for expression"); - if let Some(initializer) = option_initializer { - self.convert_boxed(initializer); - } - let inverted_entry_condition_node = - self.create_inverted_condition(condition.clone()); - let entry_conditional_jump = - self.create_conditional_jump(inverted_entry_condition_node); - - let entry_true_projection = self.create_true_projection(entry_conditional_jump); - let entry_false_projection = self.create_false_projection(entry_conditional_jump); - - let mut loop_body = Block::new("for-body".to_string()); - loop_body.register_entry_point(self.current_block_index, entry_false_projection); - let loop_body_index = self.graph.register_block(loop_body); - let mut following_block = Block::new("for-following".to_string()); - following_block - .register_entry_point(self.current_block_index, entry_true_projection); - let following_block_index = self.graph.register_block(following_block); - let loop_post = Block::new("for-post".to_string()); - let loop_post_index = self.graph.register_block(loop_post); - - self.seal_block(self.current_block_index); - - self.current_block_index = loop_body_index; - self.active_loop_entries.push(loop_post_index); - self.active_loop_exits.push(following_block_index); - self.convert_boxed(expression); - self.active_loop_entries.pop(); - self.active_loop_exits.pop(); - let loop_body_exit = self.create_jump(); - - self.graph - .get_block_mut(loop_post_index) - .register_entry_point(self.current_block_index, loop_body_exit); - self.current_block_index = loop_post_index; - self.seal_block(loop_post_index); - - if let Some(postincrement) = option_postincrement { - self.convert_boxed(postincrement); - } - - let condition_node = self.convert_boxed(condition)?; - let conditional_jump = self.create_conditional_jump(condition_node); - - let true_projection = self.create_true_projection(conditional_jump); - let false_projection = self.create_false_projection(conditional_jump); - - self.graph - .get_block_mut(loop_body_index) - .register_entry_point(loop_post_index, true_projection); - - self.seal_block(loop_body_index); - self.graph - .get_block_mut(following_block_index) - .register_entry_point(loop_post_index, false_projection); - self.seal_block(loop_body_index); - self.current_block_index = following_block_index; - self.seal_block(self.current_block_index); - debug!("Following block after for: {}", self.current_block_index); - None - } - #[allow(unreachable_patterns)] - node => todo!("Unimplemented {:?}", node), - } - } - - pub fn convert_boxed(&mut self, tree: Box) -> Option { - self.convert(*tree) - } - - pub fn create_conditional_jump(&mut self, condition: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::ConditionalJump(UnaryOperationData::new(condition))) - } - - // TODO: Refactor - pub fn process_branch(&mut self, a: Box, _b: usize, label: &str) -> usize { - let block = Block::new(format!("if-body-{}", label)); - self.current_block_index = self.graph.register_block(block); - //self.graph.get_node_mut(block).predecessors_mut().push(b); - self.seal_block(self.current_block_index); - self.convert_boxed(a); - self.seal_block(self.current_block_index); - self.create_jump() - } - - fn create_jump(&mut self) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Jump) - } - - fn create_add(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Add(BinaryOperationData::new(lhs, rhs))) - } - - fn create_inverted_condition(&mut self, condition: Box) -> NodeIndex { - if let Tree::BinaryOperation(lhs, rhs, operator) = *condition { - let left_node = self.convert_boxed(lhs).unwrap(); - let right_node = self.convert_boxed(rhs).unwrap(); - let current_block = self.graph.get_block_mut(self.current_block_index); - match operator { - OperatorType::TernaryColon - | OperatorType::Mul - | OperatorType::Div - | OperatorType::Mod - | OperatorType::Plus - | OperatorType::Assign - | OperatorType::AssignMul - | OperatorType::AssignDiv - | OperatorType::AssignMod - | OperatorType::ShiftLeft - | OperatorType::BitwiseOr - | OperatorType::LogicalOr - | OperatorType::AssignPlus - | OperatorType::LogicalNot - | OperatorType::BitwiseNot - | OperatorType::ShiftRight - | OperatorType::BitwiseAnd - | OperatorType::BitwiseXor - | OperatorType::Minus => panic!("Invalid operator for condition!"), - OperatorType::Lower => current_block.register_node(Node::HigherEquals( - BinaryOperationData::new(left_node, right_node), - )), - OperatorType::Higher => current_block.register_node(Node::LowerEquals( - BinaryOperationData::new(left_node, right_node), - )), - OperatorType::Equals => current_block.register_node(Node::NotEquals( - BinaryOperationData::new(left_node, right_node), - )), - OperatorType::NotEquals => current_block.register_node(Node::Equals( - BinaryOperationData::new(left_node, right_node), - )), - OperatorType::LowerEquals => current_block.register_node(Node::Higher( - BinaryOperationData::new(left_node, right_node), - )), - OperatorType::HigherEquals => current_block - .register_node(Node::Lower(BinaryOperationData::new(left_node, right_node))), - OperatorType::LogicalAnd => todo!(), - _ => unimplemented!("Unimplemented inverted operator {:?}", operator), - } - } else if let Tree::IdentifierExpression(_) = *condition { - let variable = self.convert_boxed(condition).unwrap(); - self.create_logical_not(variable) - } else if let Tree::BoolLiteral(value, _) = *condition { - if value { - self.create_constant_int(0) - } else { - self.create_constant_int(1) - } - } else { - panic!("Condition is not a binary operation, got {:?}", condition); - } - } - - fn create_sub(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Subtraction(BinaryOperationData::new(lhs, rhs))) - } - - fn create_mul(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Multiplication(BinaryOperationData::new(lhs, rhs))) - } - - fn create_div(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Division(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_mod(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Modulo(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_shift_left(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::ShiftLeft(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_shift_right(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::ShiftRight(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_lower(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Lower(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_lower_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::LowerEquals(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Equals(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_not_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Lower(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_higher_equals(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::HigherEquals( - BinaryOperationData::new_with_sideeffect(lhs, rhs, sideeffect), - )) - } - - fn create_higher(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Higher(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_or(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Or(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_and(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::And(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_xor(&mut self, lhs: NodeIndex, rhs: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Xor(BinaryOperationData::new_with_sideeffect( - lhs, rhs, sideeffect, - ))) - } - - fn create_bitwise_not(&mut self, node: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::BitwiseNegate( - UnaryOperationData::new_with_sideeffect(node, sideeffect), - )) - } - - fn create_logical_not(&mut self, node: NodeIndex) -> NodeIndex { - let sideeffect = self.read_current_side_effect(); - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::LogicalNot(UnaryOperationData::new_with_sideeffect( - node, sideeffect, - ))) - } - - fn create_constant_int(&mut self, value: i32) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::ConstantInt(ConstantIntData::new(value))) - } - - fn _create_constant_bool(&mut self, value: bool) -> NodeIndex { - let start_block = self.graph.get_block_mut(START_BLOCK); - start_block.register_node(Node::ConstantBool(ConstantBoolData::new(value))) - } - - fn create_return(&mut self, input: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - let return_node_index = current_block.register_node(Node::Return(ReturnData::new(input))); - self.graph - .end_block_mut() - .register_entry_point(self.current_block_index, return_node_index); - return_node_index - } - - fn _create_phi(&mut self) -> usize { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Phi(PhiData::empty())) - } - - fn create_phi_from_operands(&mut self, operands: Vec<(BlockIndex, NodeIndex)>) -> usize { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Phi(PhiData::new(operands))) - } - - fn _create_phi_operands(&mut self, block_index: BlockIndex) -> NodeIndex { - let block = self.graph.get_block(block_index); - let operands = block - .entry_points() - .iter() - .flat_map(|(v1, v2)| v2.iter().map(|v| (v1.clone(), v))) - .map(|(v1, v2)| (v1, *v2)) - .collect(); - trace!("Creating phi with operands {:?}", operands); - let current_block = self.graph.get_block_mut(block_index); - current_block.register_node(Node::Phi(PhiData::new(operands))) - } - - fn create_phi_variable_operands( - &mut self, - phi: usize, - block_index: BlockIndex, - variable: Name, - ) -> NodeIndex { - // Creating the operands for a block, by iterating over its entry points and reading the - // variable there - let mut operands = Vec::new(); - for (block_index, _) in self.graph.get_block(block_index).entry_points().clone() { - operands.push(( - block_index, - self.read_variable(variable.clone(), block_index), - )); - } - trace!( - "Created phi operands for block {} whilst reading {:?}: {:?}", - block_index, - variable, - operands - ); - - if let Node::Phi(data) = self.graph.get_block_mut(block_index).get_node_mut(phi) { - for operand in operands { - data.add_operand(operand); - } - } - phi - } - - fn create_div_mod_projection(&mut self, input: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - let projection_side_effect = current_block.register_node(Node::Projection( - ProjectionData::new(input, ProjectionInformation::SideEffect), - )); - let result_projection = current_block.register_node(Node::Projection(ProjectionData::new( - input, - ProjectionInformation::Result, - ))); - self.write_current_side_effect(projection_side_effect); - result_projection - } - - fn write_variable(&mut self, variable: Name, block: usize, node: usize) { - trace!("Trying to write into variable {:?}", variable); - match self.current_definitions.contains_key(&variable) { - true => { - self.current_definitions - .get_mut(&variable) - .unwrap() - .insert(block, node); - } - false => { - self.current_definitions - .insert(variable, HashMap::from([(block, node)])); - } - } - } - - fn read_variable(&mut self, variable: Name, block: BlockIndex) -> NodeIndex { - trace!( - "Trying to read from variable {:?} in block {}", - variable, - block - ); - if self.current_definitions.contains_key(&variable) { - if self - .current_definitions - .get(&variable) - .unwrap() - .contains_key(&block) - { - trace!("Variable defined in the same block! Returning value"); - *self - .current_definitions - .get(&variable) - .unwrap() - .get(&block) - .unwrap() - } else { - self.read_variable_recursive(variable, block) - } - } else { - self.read_variable_recursive(variable, block) - } - } - - fn read_variable_recursive(&mut self, variable: Name, block_index: BlockIndex) -> NodeIndex { - trace!( - "Reading variable {:?} recursively in block {}", - variable, - block_index - ); - trace!("Sealed blocks: {:?}", self.sealed_blocks); - let node = if !self.sealed_blocks.contains(&block_index) { - // Current block is not sealed yet, the list of operands is not final yet - let phi = self - .graph - .get_block_mut(block_index) - .register_node(Node::Phi(PhiData::empty())); - trace!("Writing incomplete phi: ({:?}, {})", variable, phi); - if self.incomplete_phis.contains_key(&block_index) { - let mut entry = self.incomplete_phis.get_mut(&block_index).unwrap().clone(); - entry.insert(variable.clone(), phi); - self.incomplete_phis.insert(block_index, entry); - } else { - self.incomplete_phis - .insert(block_index, HashMap::from([(variable.clone(), phi)])); - }; - phi - } else if self.graph.get_block(block_index).entry_points().len() == 1 { - // The block we are reading the variable in is sealed and has one previous block. - // We can read the variable from there - let previous_block = self - .graph - .get_block(block_index) - .entry_points() - .iter() - .last() - .unwrap() - .0 - .clone(); - let defining_node = self.read_variable(variable.clone(), previous_block); - let phi = self - .graph - .get_block_mut(block_index) - .register_node(Node::Phi(PhiData::new(vec![( - previous_block, - defining_node, - )]))); - phi - } else { - // The block we are reading the variable in has multiple entry points and is sealed. - // The value for the variable can come from multiple previous blocks. - // The value of the variable is dependent on the values of the variable in the previous - // blocks - let phi = self - .graph - .get_block_mut(block_index) - .register_node(Node::Phi(PhiData::empty())); - self.write_variable(variable.clone(), block_index, phi); - self.create_phi_variable_operands(phi, block_index, variable.clone()); - phi - }; - - // Denote that the newly created phi defines the variable in the current block - self.write_variable(variable.clone(), block_index, node); - node - } - - fn seal_block(&mut self, block: BlockIndex) { - debug!( - "Current graph before sealing block {}: {}", - block, self.graph - ); - info!("Incomplete Phis: {:?}", self.incomplete_phis); - if !self.incomplete_phis.contains_key(&block) { - self.sealed_blocks.push(block); - return; - } - for (block_index, definitions) in &self.incomplete_phis.clone() { - if block.ne(block_index) { - continue; - } - for (variable, phi) in definitions { - let operands = { - let mut operands = Vec::new(); - let phi_block = self.graph.get_block_mut(*block_index); - for (prev_block, _prev_nodes) in phi_block.entry_points().clone() { - operands - .push((prev_block, self.read_variable(variable.clone(), prev_block))); - } - operands - }; - let block = self.graph.get_block_mut(*block_index); - if let Node::Phi(data) = block.get_node_mut(*phi) { - for operand in operands { - data.add_operand(operand); - } - } - } - } - self.sealed_blocks.push(block); - } - - fn write_current_side_effect(&mut self, node: usize) { - self.write_side_effect(self.current_block_index, node); - } - - fn write_side_effect(&mut self, block: usize, node: usize) { - self.current_side_effect.insert(block, node); - } - - fn read_current_side_effect(&mut self) -> usize { - return 0; - //self.read_side_effect(self.current_block_index) - } - - fn _read_side_effect(&mut self, block: usize) -> usize { - if self.current_side_effect.contains_key(&block) { - *self.current_side_effect.get(&block).unwrap() - } else { - self._read_side_effect_recusive(block) - } - } - - fn _read_side_effect_recusive(&mut self, block: usize) -> usize { - let node = if !self.sealed_blocks.contains(&block) { - let phi = self._create_phi(); - let old_phi = self._incomplete_side_effect_phis.insert(block, phi); - if old_phi.is_some() { - panic!("Double read side effect recursive!"); - } - phi - } else if self.graph.get_block(block).entry_points().len() == 1 { - let (previous_block, _) = self - .graph - .get_block(block) - .entry_points() - .iter() - .last() - .unwrap(); - self._read_side_effect(*previous_block) - } else { - let phi = self._create_phi_operands(block); - self.write_side_effect(block, phi); - phi - }; - self.write_side_effect(block, node); - node - } - - pub fn graph(self) -> IRGraph { - self.graph - } - - pub fn create_true_projection(&mut self, conditional_jump: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Projection(ProjectionData::new( - conditional_jump, - ProjectionInformation::IfTrue, - ))) - } - - pub fn create_false_projection(&mut self, conditional_jump: NodeIndex) -> NodeIndex { - let current_block = self.graph.get_block_mut(self.current_block_index); - current_block.register_node(Node::Projection(ProjectionData::new( - conditional_jump, - ProjectionInformation::IfFalse, - ))) - } -} - -impl Default for IRGraphConstructor { - fn default() -> Self { - Self::new() - } -} diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 57f0874..4b7ac14 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -1,4 +1,4 @@ +pub mod ast; pub mod block; -pub mod constructor; pub mod graph; pub mod node; diff --git a/src/lexer/collection.rs b/src/lexer/collection.rs new file mode 100644 index 0000000..f020209 --- /dev/null +++ b/src/lexer/collection.rs @@ -0,0 +1,157 @@ +use std::collections::VecDeque; + +use crate::{ + lexer::{ + operator::AssignmentOperator, + token::{KeywordType, OperatorType, SeperatorType, Token}, + }, + parser::error::ParseError, +}; + +pub struct ParserTokens { + tokens: VecDeque, +} + +impl ParserTokens { + pub fn new(tokens: VecDeque) -> ParserTokens { + ParserTokens { tokens } + } + + #[must_use] + pub fn expect_keyword(&mut self, keyword: KeywordType) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Keyword(_, ref keyword_type) if keyword.eq(keyword_type) => { + return Ok(token); + } + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedKeyword(keyword)); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn expect_seperator(&mut self, seperator: SeperatorType) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Separator(_, ref seperator_type) if seperator.eq(seperator_type) => { + return Ok(token) + } + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedSeparator(seperator)); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn expect_operator(&mut self, operator: OperatorType) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Operator(_, ref operator_type) if operator.eq(operator_type) => { + return Ok(token); + } + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedOperator(operator)); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn expect_identifier(&mut self) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Identifier(_, _) => { + return Ok(token); + } + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedIdentifier); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn expect_type(&mut self) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Keyword(_, ref keyword_type) if keyword_type.is_type() => { + return Ok(token); + } + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedType); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn expect_assignment_operator(&mut self) -> Result { + if let Some(token) = self.tokens.pop_front() { + match token { + Token::Operator(_, operator) if operator.is_assignment_operator() => match operator + { + OperatorType::Assign => return Ok(AssignmentOperator::Assign), + OperatorType::AssignPlus => return Ok(AssignmentOperator::AssignPlus), + OperatorType::AssignMinus => return Ok(AssignmentOperator::AssignMinus), + OperatorType::AssignMul => return Ok(AssignmentOperator::AssignMul), + OperatorType::AssignDiv => return Ok(AssignmentOperator::AssignDiv), + OperatorType::AssignMod => return Ok(AssignmentOperator::AssignMod), + OperatorType::AssignShiftLeft => { + return Ok(AssignmentOperator::AssignShiftLeft) + } + OperatorType::AssignShiftRight => { + return Ok(AssignmentOperator::AssignShiftRight) + } + OperatorType::AssignBitwiseNot => { + return Ok(AssignmentOperator::AssignBitwiseNot) + } + OperatorType::AssignBitwiseAnd => { + return Ok(AssignmentOperator::AssignBitwiseAnd) + } + OperatorType::AssignBitwiseOr => { + return Ok(AssignmentOperator::AssignBitwiseOr) + } + OperatorType::AssignBitwiseXor => { + return Ok(AssignmentOperator::AssignBitwiseXor) + } + _ => return Err(ParseError::ExpectedAssignmentOperator), + }, + _ => { + self.tokens.push_front(token); + return Err(ParseError::ExpectedAssignmentOperator); + } + } + } + Err(ParseError::ReachedEnd) + } + + #[must_use] + pub fn consume(&mut self) -> Result { + self.tokens.pop_front().ok_or(ParseError::ReachedEnd) + } + + pub fn has_next(&self) -> bool { + !self.tokens.is_empty() + } + + pub fn peek(&self) -> Option<&Token> { + self.tokens.front() + } + + pub fn push(&mut self, value: Token) { + self.tokens.push_front(value); + } +} diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 4f35c13..f1ca606 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -8,6 +8,8 @@ use crate::{ util::{position::Position, span::Span}, }; +pub mod collection; +pub mod operator; pub mod token; pub struct Lexer { @@ -34,18 +36,13 @@ impl Lexer { ); let whitespace = self.skip_whitespace(); if whitespace.is_some() { - return whitespace - .clone() - .ok_or(ParseError::Error(format!("{:?}", whitespace.unwrap()))); + return whitespace.clone().ok_or(ParseError::WhitespaceError); } if self.position >= self.source.chars().count() { - return Err(ParseError::Finished); + return Err(ParseError::ReachedEnd); } - let token = match self - .peek() - .ok_or(ParseError::Error("Not a character".to_string()))? - { + let token = match self.peek().ok_or(ParseError::InvalidCharacter)? { '(' => self.seperator(SeperatorType::ParenOpen), ')' => self.seperator(SeperatorType::ParenClose), '{' => self.seperator(SeperatorType::BraceOpen), @@ -55,19 +52,19 @@ impl Lexer { ':' => Token::Operator(self.build_span(1), OperatorType::TernaryColon), '-' => self .single_assign(OperatorType::Minus, OperatorType::AssignMinus, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '+' => self .single_assign(OperatorType::Plus, OperatorType::AssignPlus, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '*' => self .single_assign(OperatorType::Mul, OperatorType::AssignMul, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '/' => self .single_assign(OperatorType::Div, OperatorType::AssignDiv, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '%' => self .single_assign(OperatorType::Mod, OperatorType::AssignMod, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '&' => self .single_assign_logical( '&', @@ -75,13 +72,13 @@ impl Lexer { OperatorType::AssignBitwiseAnd, OperatorType::LogicalAnd, ) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '~' => self .single_assign(OperatorType::BitwiseNot, OperatorType::AssignBitwiseNot, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '^' => self .single_assign(OperatorType::BitwiseXor, OperatorType::AssignBitwiseXor, 1) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '|' => self .single_assign_logical( '|', @@ -89,7 +86,7 @@ impl Lexer { OperatorType::AssignBitwiseOr, OperatorType::LogicalOr, ) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '<' => self .shift_or_comparison( '<', @@ -98,7 +95,7 @@ impl Lexer { OperatorType::Lower, OperatorType::LowerEquals, ) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '>' => self .shift_or_comparison( '>', @@ -107,21 +104,20 @@ impl Lexer { OperatorType::Higher, OperatorType::HigherEquals, ) - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '!' => self .not_or_comparison() - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, '=' => self .assign_or_comparison() - .ok_or(ParseError::Error("Not a character".to_string()))?, + .ok_or(ParseError::InvalidCharacter)?, char => { if self.is_identifier_char(char) { if self.is_numeric(char) { self.lex_number()? } else { - self.lex_identifier_keyword().map_err(|_| { - ParseError::Error("Error lexing identifier keyword".to_string()) - })? + self.lex_identifier_keyword() + .map_err(|_| ParseError::ExpectedKeywordOrIdentifier)? } } else { Token::ErrorToken(self.build_span(1), char.to_string()) @@ -249,16 +245,10 @@ impl Lexer { } fn lex_number(&mut self) -> Result { - if self - .is_hex_prefix() - .ok_or(ParseError::Error("Not a character".to_string()))? - { + if self.is_hex_prefix().ok_or(ParseError::InvalidCharacter)? { let mut offset = 2; while self.has_more(offset) - && is_hex( - self.peek_pos(offset) - .ok_or(ParseError::Error("Not a character".to_string()))?, - ) + && is_hex(self.peek_pos(offset).ok_or(ParseError::InvalidCharacter)?) { offset += 1; } @@ -273,20 +263,12 @@ impl Lexer { let mut offset = 1; while self.has_more(offset) - && self.is_numeric( - self.peek_pos(offset) - .ok_or(ParseError::Error("Not a character".to_string()))?, - ) + && self.is_numeric(self.peek_pos(offset).ok_or(ParseError::InvalidCharacter)?) { offset += 1; } - if self - .peek() - .ok_or(ParseError::Error("Not a character".to_string()))? - .eq(&'0') - && offset > 1 - { + if self.peek().ok_or(ParseError::InvalidCharacter)?.eq(&'0') && offset > 1 { return Ok(Token::ErrorToken( self.build_span(offset), self.get_substring(self.position..self.position + offset), diff --git a/src/lexer/operator.rs b/src/lexer/operator.rs new file mode 100644 index 0000000..0a7f8ca --- /dev/null +++ b/src/lexer/operator.rs @@ -0,0 +1,124 @@ +use std::fmt::Display; + +#[derive(PartialEq, Clone, Debug)] +pub enum UnaryOperator { + Minus, + LogicalNot, + BitwiseNot, +} + +impl UnaryOperator { + fn as_string(&self) -> impl ToString { + match self { + UnaryOperator::Minus => "-", + UnaryOperator::LogicalNot => "!", + UnaryOperator::BitwiseNot => "~", + } + } +} + +#[derive(PartialEq, Clone, Debug)] +pub enum BinaryOperator { + Plus, + Minus, + Mul, + Div, + Mod, + ShiftLeft, + ShiftRight, + + Lower, + LowerEquals, + Higher, + HigherEquals, + Equals, + NotEquals, + + BitwiseAnd, + BitwiseXor, + BitwiseOr, + + LogicalAnd, + LogicalOr, +} + +impl BinaryOperator { + fn as_string(&self) -> impl ToString { + match self { + BinaryOperator::Plus => "+", + BinaryOperator::Minus => "-", + BinaryOperator::Mul => "*", + BinaryOperator::Div => "/", + BinaryOperator::Mod => "%", + BinaryOperator::ShiftLeft => "<<", + BinaryOperator::ShiftRight => ">>", + + BinaryOperator::Lower => "<", + BinaryOperator::LowerEquals => "<=", + BinaryOperator::Higher => ">", + BinaryOperator::HigherEquals => ">=", + BinaryOperator::Equals => "==", + BinaryOperator::NotEquals => "!=", + + BinaryOperator::BitwiseAnd => "&", + BinaryOperator::BitwiseXor => "^", + BinaryOperator::BitwiseOr => "|", + + BinaryOperator::LogicalAnd => "&&", + BinaryOperator::LogicalOr => "||", + } + } +} + +#[derive(PartialEq, Clone, Debug)] +pub enum AssignmentOperator { + Assign, + AssignPlus, + AssignMinus, + AssignMul, + AssignDiv, + AssignMod, + AssignShiftLeft, + AssignShiftRight, + AssignBitwiseNot, + AssignBitwiseAnd, + AssignBitwiseOr, + AssignBitwiseXor, +} + +impl AssignmentOperator { + fn as_string(&self) -> impl ToString { + match self { + AssignmentOperator::Assign => "=", + AssignmentOperator::AssignPlus => "+=", + AssignmentOperator::AssignMinus => "-=", + AssignmentOperator::AssignMul => "*=", + AssignmentOperator::AssignDiv => "/=", + AssignmentOperator::AssignMod => "%=", + AssignmentOperator::AssignShiftLeft => "<<=", + AssignmentOperator::AssignShiftRight => ">>=", + AssignmentOperator::AssignBitwiseNot => "~=", + AssignmentOperator::AssignBitwiseAnd => "&=", + AssignmentOperator::AssignBitwiseOr => "|=", + AssignmentOperator::AssignBitwiseXor => "^=", + } + } +} + +impl Display for UnaryOperator { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_string().to_string()) + } +} + +impl Display for BinaryOperator { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_string().to_string()) + } +} + +impl Display for AssignmentOperator { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_string().to_string()) + } +} diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 4322a7a..4ea8a57 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -236,7 +236,7 @@ pub enum Token { ErrorToken(Span, String), Identifier(Span, String), Keyword(Span, KeywordType), - NumberLiteral(Span, String, u64), + NumberLiteral(Span, String, usize), BoolLiteral(Span, String), Operator(Span, OperatorType), Separator(Span, SeperatorType), diff --git a/src/main.rs b/src/main.rs index fdb0a25..3535b5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,12 +6,18 @@ use std::{ }; use backend::codegen::CodeGenerator; -use ir::constructor::IRGraphConstructor; use lexer::Lexer; -use parser::{ast::Tree, error::ParseError, Parser}; +use parser::{ast::Tree, error::ParseError}; use rand::{distr::Alphanumeric, Rng}; -use semantic::{analyze, AnalysisState}; -use tracing::{debug, error, info}; +use semantic::AnalysisState; +use tracing::{debug, error, info, trace}; + +use crate::{ + ir::ast::{IRConstructor, ToIR}, + lexer::collection::ParserTokens, + parser::ast::program_tree::ProgramTree, + semantic::ast::SemanticAnalysis, +}; pub mod backend; pub mod ir; @@ -40,21 +46,17 @@ fn main() { debug!("Program AST: {}", program); let mut state = AnalysisState::default(); - let semantic_analysis = analyze(Box::new(program.clone()), &mut state); - if semantic_analysis.is_err() { - error!("Semantic Error: {}", semantic_analysis.err().unwrap()); + let semantic_analysis = program.analyze(&mut state); + if let Err(error) = semantic_analysis { + error!("Semantic Error: {}", error); exit(7) } let mut ir_graphs = Vec::new(); - if let Tree::Program(functions) = program { - for function in functions { - let mut ir_graph = IRGraphConstructor::new(); - ir_graph.convert(function); - ir_graphs.push(ir_graph.graph()); - } - } else { - panic!("Result from parser is not a program tree!"); + for function in program.functions() { + let mut ir_graph = IRConstructor::new(); + function.to_ir(&mut ir_graph); + ir_graphs.push(ir_graph.graph()); } for ir_graph in ir_graphs.iter().clone() { info!("Constructed IR: {}", ir_graph); @@ -83,7 +85,7 @@ fn main() { } } -fn lex_parse(path: &Path) -> Tree { +fn lex_parse(path: &Path) -> ProgramTree { let source = fs::read_to_string(path).unwrap(); let mut lexer = Lexer::new(source); let tokens = std::iter::from_fn(|| { @@ -91,24 +93,22 @@ fn lex_parse(path: &Path) -> Tree { match next_token { Ok(t) => Some(t), Err(error) => { - if error.eq(&ParseError::Finished) { - None - } else { - error!("Lexing Error: {:?}", error); - exit(42) + if error.eq(&ParseError::ReachedEnd) { + return None; } + error!("Lexing Error: {:?}", error); + exit(42) } } }) .collect::>(); - let parser = Parser::new(tokens); - let parse_result = parser.parse_program(); - if parse_result.is_err() && matches!(parse_result.as_ref().err().unwrap(), ParseError::Error(_)) - { - if let ParseError::Error(error) = parse_result.as_ref().err().unwrap() { - error!("Parsing Error {}", error); - exit(42) - } + trace!("Tokens: {:?}", tokens); + let mut parser_tokens = ParserTokens::new(tokens); + let parse_result = ProgramTree::from_tokens(&mut parser_tokens); + if let Err(error) = parse_result { + error!("Parse Error: {}", error); + exit(42) + } else { + parse_result.ok().unwrap() } - parse_result.ok().unwrap() } diff --git a/src/parser/ast.rs b/src/parser/ast.rs deleted file mode 100644 index 171273f..0000000 --- a/src/parser/ast.rs +++ /dev/null @@ -1,188 +0,0 @@ -use std::fmt::Display; - -use crate::{ - lexer::token::{OperatorType, Token}, - parser::symbols::Name, - parser::types::Type, - util::{position::Position, span::Span}, -}; - -#[derive(Clone, Debug)] -pub enum Tree { - /// lvalue, operator, expression - Assignment(Box, Token, Box), - BinaryOperation(Box, Box, OperatorType), - Block(Vec, Span), - Declaration(Box, Box, Option>), - Function(Box, Box, Box), - IdentifierExpression(Box), - LValueIdentifier(Box), - Literal(String, u64, Span), - BoolLiteral(bool, Span), - TernaryOperation(Box, Box, Box), - Name(Name, Span), - UnaryOperation(Box, OperatorType, Span), - Return(Box, Position), - Break(Span), - Continue(Span), - For( - Option>, - Box, - Option>, - Box, - Span, - ), - While(Box, Box, Span), - If(Box, Box, Option>, Span), - Type(Type, Span), - Program(Vec), -} - -impl Tree { - pub fn span(&self) -> Span { - match self { - Tree::Assignment(lvalue, _, expression) => lvalue.span().merge(expression.span()), - Tree::BinaryOperation(lhs, rhs, _) => lhs.span().merge(rhs.span()), - Tree::Block(_, span) => span.clone(), - Tree::Declaration(type_tree, name, initializer_option) => { - if let Some(initializer) = initializer_option { - return type_tree.span().merge(initializer.span()); - } - type_tree.span().merge(name.span()) - } - Tree::Function(return_type, _name, body) => { - Span::new(return_type.span().start_owned(), body.span().end_owned()) - } - Tree::IdentifierExpression(name) => name.span(), - Tree::LValueIdentifier(name) => name.span(), - Tree::Literal(_, _, span) => span.clone(), - Tree::Name(_, span) => span.clone(), - Tree::UnaryOperation(expression, _, span) => span.clone().merge(expression.span()), - Tree::Return(expression, start) => { - Span::new(start.clone(), expression.span().end_owned()) - } - Tree::Type(_, span) => span.clone(), - Tree::Program(trees) => { - let first = trees.first().unwrap(); - let last = trees.last().unwrap(); - return Span::new(first.span().start().clone(), last.span().end().clone()); - } - Tree::BoolLiteral(_, span) => span.clone(), - Tree::TernaryOperation(start, _, end) => start.span().merge(end.span()), - Tree::Break(span) => span.clone(), - Tree::Continue(span) => span.clone(), - Tree::For(_, _, _, _, span) => span.clone(), - Tree::While(_, _, span) => span.clone(), - Tree::If(_, _, _, span) => span.clone(), - } - } - - pub fn name(&self) -> &str { - match self { - Tree::Name(name, _) => name.as_string(), - _ => todo!(), - } - } -} - -impl Display for Tree { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Tree::Program(functions) => { - write!(f, "[")?; - for function in functions { - write!(f, "\n{}\n", function)?; - } - write!(f, "]") - } - Tree::Function(return_type, name, body) => { - write!( - f, - "Function {} returning type {}:\n{}", - name, return_type, body - ) - } - Tree::Name(name, _) => { - write!(f, "{}", name.as_string()) - } - Tree::Assignment(lvalue, operator, expression) => { - writeln!(f, "{} {} {}", lvalue, operator.as_string(), expression) - } - Tree::LValueIdentifier(identifier) => write!(f, "{}", identifier), - Tree::BinaryOperation(lhs, rhs, operator) => { - write!(f, "{} {} {}", lhs, operator.as_str(), rhs) - } - Tree::Block(operations, _) => { - for operation in operations { - write!(f, "{}", operation)? - } - Ok(()) - } - Tree::Declaration(type_tree, name, initializer) => { - if initializer.is_some() { - writeln!( - f, - "{}: {} <- {}", - name, - type_tree, - initializer.clone().unwrap() - ) - } else { - writeln!(f, "{}: {}", name, type_tree) - } - } - Tree::IdentifierExpression(identifier) => { - write!(f, "{}", identifier) - } - Tree::Literal(value, _, _) => { - write!(f, "{}", value) - } - Tree::UnaryOperation(tree, operator, _) => { - write!(f, "{}{}", operator.as_str(), tree) - } - Tree::Return(expresion, _) => { - writeln!(f, "return {}", expresion) - } - Tree::Type(type_tree, _) => { - write!(f, "{}", type_tree.as_string()) - } - Tree::BoolLiteral(value, _) => { - write!(f, "{}", value.to_string()) - } - Tree::TernaryOperation(expression, true_expression, false_expression) => { - write!( - f, - "{} ? {} : {}", - expression, true_expression, false_expression - ) - } - Tree::Continue(_) => { - writeln!(f, "continue") - } - Tree::Break(_) => { - writeln!(f, "break") - } - Tree::For(init, condition, post, statement, _) => { - writeln!(f, "for {:?}; {}; {:?} {{", init, condition, post)?; - writeln!(f, "{}", statement)?; - writeln!(f, "}}") - } - Tree::While(condition, statement, _) => { - writeln!(f, "while {} {{", condition)?; - writeln!(f, "{}", statement)?; - writeln!(f, "}}") - } - Tree::If(condition, statement, else_statement, _) => { - writeln!(f, "if {} {{", condition)?; - writeln!(f, "{}", statement)?; - if let Some(other_statement) = else_statement { - writeln!(f, "}} else {{")?; - writeln!(f, "{}", other_statement)?; - writeln!(f, "}}") - } else { - writeln!(f, "}}") - } - } - } - } -} diff --git a/src/parser/ast/assignment_tree.rs b/src/parser/ast/assignment_tree.rs new file mode 100644 index 0000000..4684b09 --- /dev/null +++ b/src/parser/ast/assignment_tree.rs @@ -0,0 +1,58 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{collection::ParserTokens, operator::AssignmentOperator}, + parser::{ + ast::{expression_tree::ExpressionTree, lvalue_tree::LValueTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct AssignmentTree { + lvalue: LValueTree, + operator: AssignmentOperator, + expression: ExpressionTree, +} + +impl Tree for AssignmentTree { + fn span(&self) -> Span { + self.lvalue.span().merge(&self.expression.span()) + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing assignment from tokens"); + trace!("First token {:?}", tokens.peek()); + let lvalue = LValueTree::from_tokens(tokens)?; + let operator = tokens.expect_assignment_operator()?; + let expression = ExpressionTree::from_tokens(tokens)?; + Ok(AssignmentTree { + lvalue, + operator, + expression, + }) + } +} + +impl AssignmentTree { + pub fn lvalue(&self) -> &LValueTree { + &self.lvalue + } + + pub fn operator(&self) -> &AssignmentOperator { + &self.operator + } + + pub fn expression(&self) -> &ExpressionTree { + &self.expression + } +} + +impl Display for AssignmentTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{} {} {}", self.lvalue, self.operator, self.expression) + } +} diff --git a/src/parser/ast/binary_operation_tree.rs b/src/parser/ast/binary_operation_tree.rs new file mode 100644 index 0000000..4e52261 --- /dev/null +++ b/src/parser/ast/binary_operation_tree.rs @@ -0,0 +1,59 @@ +use std::fmt::Display; + +use crate::{ + lexer::{collection::ParserTokens, operator::BinaryOperator, token::MAX_PRECEDENCE}, + parser::{ + ast::{expression_tree::ExpressionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct BinaryOperationTree { + lhs: Box, + operator: BinaryOperator, + rhs: Box, +} + +impl Tree for BinaryOperationTree { + fn span(&self) -> Span { + self.lhs.span().merge(&self.rhs.span()) + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let result = ExpressionTree::from_tokens_precedence(tokens, MAX_PRECEDENCE)?; + match result { + ExpressionTree::BinaryOperationTree(tree) => Ok(tree), + _ => Err(ParseError::NotAOperation), + } + } +} + +impl BinaryOperationTree { + pub fn new( + lhs: Box, + operator: BinaryOperator, + rhs: Box, + ) -> BinaryOperationTree { + BinaryOperationTree { lhs, operator, rhs } + } + + pub fn operator(&self) -> &BinaryOperator { + &self.operator + } + + pub fn lhs(&self) -> &ExpressionTree { + &self.lhs + } + + pub fn rhs(&self) -> &ExpressionTree { + &self.rhs + } +} + +impl Display for BinaryOperationTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {} {}", *self.lhs, self.operator, *self.rhs) + } +} diff --git a/src/parser/ast/block_tree.rs b/src/parser/ast/block_tree.rs new file mode 100644 index 0000000..e4c027e --- /dev/null +++ b/src/parser/ast/block_tree.rs @@ -0,0 +1,65 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{SeperatorType, Token}, + }, + parser::{ + ast::{statement_tree::StatementTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct BlockTree { + statements: Vec, + block_span: Span, +} + +impl Tree for BlockTree { + fn span(&self) -> Span { + self.block_span.clone() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into body"); + let body_open = tokens.expect_seperator(SeperatorType::BraceOpen)?; + let mut statements = vec![]; + while tokens.has_next() { + trace!("Parsing body statement"); + trace!("First token {:?}", tokens.peek()); + match tokens.peek().unwrap() { + Token::Separator(_, seperator) if seperator.eq(&SeperatorType::BraceClose) => { + break; + } + _ => statements.push(StatementTree::from_tokens(tokens)?), + } + } + let body_close = tokens.expect_seperator(SeperatorType::BraceClose)?; + trace!("Successfully parsed block"); + Ok(BlockTree { + statements, + block_span: body_open.span().merge(&body_close.span()), + }) + } +} + +impl BlockTree { + pub fn statements(&self) -> &Vec { + &self.statements + } +} + +impl Display for BlockTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{{")?; + for statement in &self.statements { + write!(f, "{}", statement)?; + } + write!(f, "}}") + } +} diff --git a/src/parser/ast/break_tree.rs b/src/parser/ast/break_tree.rs new file mode 100644 index 0000000..981c1cd --- /dev/null +++ b/src/parser/ast/break_tree.rs @@ -0,0 +1,31 @@ +use std::fmt::Display; + +use crate::{ + lexer::{collection::ParserTokens, token::KeywordType}, + parser::{ast::Tree, error::ParseError}, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct BreakTree { + span: Span, +} + +impl Tree for BreakTree { + fn span(&self) -> Span { + self.span.clone() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let keyword = tokens.expect_keyword(KeywordType::Break)?; + Ok(BreakTree { + span: keyword.span(), + }) + } +} + +impl Display for BreakTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "break") + } +} diff --git a/src/parser/ast/call_tree.rs b/src/parser/ast/call_tree.rs new file mode 100644 index 0000000..5dd8e39 --- /dev/null +++ b/src/parser/ast/call_tree.rs @@ -0,0 +1,38 @@ +use std::fmt::Display; + +use crate::{ + lexer::collection::ParserTokens, + parser::{ + ast::{expression_tree::ExpressionTree, identifier_tree::IdentifierExpressionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct CallTree { + identifier: IdentifierExpressionTree, + parameter_expressions: Vec, + closing_span: Span, +} + +impl Tree for CallTree { + fn span(&self) -> Span { + self.identifier.span().merge(&self.closing_span) + } + fn from_tokens(_tokens: &mut ParserTokens) -> Result { + // TODO: Implement parsing from tokens + Err(ParseError::InvalidCharacter) + } +} + +impl Display for CallTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.identifier)?; + write!(f, "(")?; + for parameter_expression in &self.parameter_expressions { + write!(f, "{} ", parameter_expression)?; + } + write!(f, ")") + } +} diff --git a/src/parser/ast/continue_tree.rs b/src/parser/ast/continue_tree.rs new file mode 100644 index 0000000..e21a859 --- /dev/null +++ b/src/parser/ast/continue_tree.rs @@ -0,0 +1,31 @@ +use std::fmt::Display; + +use crate::{ + lexer::{collection::ParserTokens, token::KeywordType}, + parser::{ast::Tree, error::ParseError}, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct ContinueTree { + span: Span, +} + +impl Tree for ContinueTree { + fn span(&self) -> Span { + self.span.clone() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let keyword = tokens.expect_keyword(KeywordType::Continue)?; + Ok(ContinueTree { + span: keyword.span(), + }) + } +} + +impl Display for ContinueTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "continue") + } +} diff --git a/src/parser/ast/declaration_tree.rs b/src/parser/ast/declaration_tree.rs new file mode 100644 index 0000000..9e8f7b9 --- /dev/null +++ b/src/parser/ast/declaration_tree.rs @@ -0,0 +1,75 @@ +use std::fmt::{Debug, Display}; + +use tracing::trace; + +use crate::{ + lexer::{collection::ParserTokens, token::OperatorType}, + parser::{ + ast::{expression_tree::ExpressionTree, name_tree::NameTree, type_tree::TypeTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct DeclarationTree { + type_tree: TypeTree, + name_tree: NameTree, + initializer_tree: Option, +} + +impl Tree for DeclarationTree { + fn span(&self) -> Span { + if let Some(initializer_tree) = &self.initializer_tree { + self.type_tree.span().merge(&initializer_tree.span()) + } else { + self.type_tree.span().merge(&self.name_tree.span()) + } + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing declaration from tokens"); + trace!("First token {:?}", tokens.peek()); + let type_tree = TypeTree::from_tokens(tokens)?; + let name_tree = NameTree::from_tokens(tokens)?; + let mut initializer_tree = None; + if tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_operator_type(&OperatorType::Assign) + { + trace!("Declaration may initialize variable"); + trace!("First token {:?}", tokens.peek()); + tokens.expect_operator(OperatorType::Assign)?; + initializer_tree = Some(ExpressionTree::from_tokens(tokens)?); + trace!("Parsed initializer: {:?}", initializer_tree); + } + Ok(DeclarationTree { + type_tree, + name_tree, + initializer_tree, + }) + } +} + +impl DeclarationTree { + pub fn type_tree(&self) -> &TypeTree { + &self.type_tree + } + pub fn name_tree(&self) -> &NameTree { + &self.name_tree + } + pub fn initializer_tree(&self) -> &Option { + &self.initializer_tree + } +} + +impl Display for DeclarationTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self.type_tree, self.name_tree)?; + if let Some(initializer_tree) = &self.initializer_tree { + write!(f, " = {}", initializer_tree)?; + } + Ok(()) + } +} diff --git a/src/parser/ast/expression_tree.rs b/src/parser/ast/expression_tree.rs new file mode 100644 index 0000000..c3d4c22 --- /dev/null +++ b/src/parser/ast/expression_tree.rs @@ -0,0 +1,221 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + operator::{BinaryOperator, UnaryOperator}, + token::{KeywordType, OperatorType, SeperatorType, Token, MAX_PRECEDENCE}, + }, + parser::{ + ast::{ + binary_operation_tree::BinaryOperationTree, + identifier_tree::IdentifierExpressionTree, + literal_tree::{BooleanLiteralTree, IntegerLiteralTree}, + ternary_operation_tree::TernaryOperationTree, + unary_operation_tree::UnaryOperationTree, + Tree, + }, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub enum ExpressionTree { + BooleanLiteralTree(BooleanLiteralTree), + IntegerLiteralTree(IntegerLiteralTree), + IdentifierExpressionTree(IdentifierExpressionTree), + UnaryOperationTree(UnaryOperationTree), + BinaryOperationTree(BinaryOperationTree), + TernaryOperationTree(TernaryOperationTree), +} + +impl Tree for ExpressionTree { + fn span(&self) -> Span { + match self { + ExpressionTree::BooleanLiteralTree(tree) => tree.span(), + ExpressionTree::IntegerLiteralTree(tree) => tree.span(), + ExpressionTree::IdentifierExpressionTree(tree) => tree.span(), + ExpressionTree::UnaryOperationTree(tree) => tree.span(), + ExpressionTree::BinaryOperationTree(tree) => tree.span(), + ExpressionTree::TernaryOperationTree(tree) => tree.span(), + } + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into expression"); + trace!("First token {:?}", tokens.peek()); + let lhs = ExpressionTree::from_tokens_precedence(tokens, MAX_PRECEDENCE)?; + trace!( + "Parsed possible expression. First token after: {:?}", + tokens.peek() + ); + if !tokens.peek().ok_or(ParseError::ReachedEnd)?.is_operator() { + trace!("Finished parsing expression"); + return Ok(lhs); + } + if let Token::Operator(_, operator) = tokens.peek().ok_or(ParseError::ReachedEnd)? { + if !operator.eq(&OperatorType::TernaryQuestionMark) { + return Ok(lhs); + } + } + tokens.consume()?; + let true_expression = ExpressionTree::from_tokens(tokens)?; + tokens.expect_operator(OperatorType::TernaryColon)?; + let false_expression = ExpressionTree::from_tokens(tokens)?; + Ok(ExpressionTree::TernaryOperationTree( + TernaryOperationTree::new( + Box::new(lhs), + Box::new(true_expression), + Box::new(false_expression), + ), + )) + } +} + +impl ExpressionTree { + pub fn from_tokens_precedence( + tokens: &mut ParserTokens, + precedence: u8, + ) -> Result { + if precedence == 1 { + return ExpressionTree::parse_unary_expression(tokens, precedence); + } else if precedence == 0 { + return ExpressionTree::parse_basic_expression(tokens); + } + + let mut lhs = ExpressionTree::from_tokens_precedence(tokens, precedence - 1)?; + loop { + let next_operator = tokens.consume()?; + if let Token::Operator(_, ref operator) = next_operator { + if matches!( + operator, + OperatorType::TernaryColon | OperatorType::TernaryQuestionMark + ) || operator.is_assignment_operator() + { + tokens.push(next_operator); + return Ok(lhs); + } + if operator.get_precedence().contains(&precedence) { + let operator = match operator { + OperatorType::Plus => BinaryOperator::Plus, + OperatorType::Minus => BinaryOperator::Minus, + OperatorType::Mul => BinaryOperator::Mul, + OperatorType::Div => BinaryOperator::Div, + OperatorType::ShiftLeft => BinaryOperator::ShiftLeft, + OperatorType::ShiftRight => BinaryOperator::ShiftRight, + OperatorType::Mod => BinaryOperator::Mod, + OperatorType::Lower => BinaryOperator::Lower, + OperatorType::LowerEquals => BinaryOperator::LowerEquals, + OperatorType::Equals => BinaryOperator::Equals, + OperatorType::NotEquals => BinaryOperator::NotEquals, + OperatorType::Higher => BinaryOperator::Higher, + OperatorType::HigherEquals => BinaryOperator::HigherEquals, + OperatorType::BitwiseOr => BinaryOperator::BitwiseOr, + OperatorType::BitwiseAnd => BinaryOperator::BitwiseAnd, + OperatorType::BitwiseXor => BinaryOperator::BitwiseXor, + OperatorType::LogicalAnd => BinaryOperator::LogicalAnd, + OperatorType::LogicalOr => BinaryOperator::LogicalOr, + _ => return Err(ParseError::ExpectedBinaryOperator), + }; + let rhs = ExpressionTree::from_tokens_precedence(tokens, precedence - 1)?; + lhs = ExpressionTree::BinaryOperationTree(BinaryOperationTree::new( + Box::new(lhs), + operator.clone(), + Box::new(rhs), + )); + continue; + } + } + tokens.push(next_operator); + return Ok(lhs); + } + } + + pub fn parse_unary_expression( + tokens: &mut ParserTokens, + precedence: u8, + ) -> Result { + let token = tokens.consume()?; + if let Token::Operator(_, ref operator_type) = token { + if operator_type.get_precedence().contains(&precedence) { + let value = ExpressionTree::from_tokens_precedence(tokens, precedence)?; + let span = token.clone().span().merge(&value.span()); + let operator = match operator_type { + OperatorType::BitwiseNot => UnaryOperator::BitwiseNot, + OperatorType::Minus => UnaryOperator::Minus, + OperatorType::LogicalNot => UnaryOperator::LogicalNot, + _ => return Err(ParseError::ExpectedUnaryOperator), + }; + return Ok(ExpressionTree::UnaryOperationTree(UnaryOperationTree::new( + operator, + Box::new(value), + span, + ))); + } + } + tokens.push(token); + ExpressionTree::from_tokens_precedence(tokens, precedence - 1) + } + + pub fn parse_basic_expression(tokens: &mut ParserTokens) -> Result { + match tokens.peek().ok_or(ParseError::ReachedEnd)?.clone() { + Token::Separator(_, seperator) if seperator.eq(&SeperatorType::ParenOpen) => { + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let expression = ExpressionTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::ParenClose)?; + Ok(expression) + } + // FIXME: Janky negative hack, because I wanted nothing to do with int parsing + Token::Operator(span, operator) if operator.eq(&OperatorType::Minus) => { + tokens.consume()?; + match tokens.consume()? { + Token::NumberLiteral(span, value, base) => { + Ok(ExpressionTree::IntegerLiteralTree(IntegerLiteralTree::new( + "-".to_owned() + value.as_str(), + base, + span.clone(), + ))) + } + token => { + tokens.push(token); + Ok(ExpressionTree::UnaryOperationTree(UnaryOperationTree::new( + UnaryOperator::Minus, + Box::new(ExpressionTree::from_tokens(tokens)?), + span.clone(), + ))) + } + } + } + Token::Identifier(_, _) => Ok(ExpressionTree::IdentifierExpressionTree( + IdentifierExpressionTree::from_tokens(tokens)?, + )), + Token::NumberLiteral(_, _, _) => Ok(ExpressionTree::IntegerLiteralTree( + IntegerLiteralTree::from_tokens(tokens)?, + )), + Token::Keyword(_, keyword) + if keyword.eq(&KeywordType::True) || keyword.eq(&KeywordType::False) => + { + Ok(ExpressionTree::BooleanLiteralTree( + BooleanLiteralTree::from_tokens(tokens)?, + )) + } + _ => Err(ParseError::ExpectedLiteral), + } + } +} + +impl Display for ExpressionTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ExpressionTree::BooleanLiteralTree(tree) => write!(f, "{}", tree), + ExpressionTree::IntegerLiteralTree(tree) => write!(f, "{}", tree), + ExpressionTree::IdentifierExpressionTree(tree) => write!(f, "{}", tree), + ExpressionTree::UnaryOperationTree(tree) => write!(f, "{}", tree), + ExpressionTree::BinaryOperationTree(tree) => write!(f, "{}", tree), + ExpressionTree::TernaryOperationTree(tree) => write!(f, "{}", tree), + } + } +} diff --git a/src/parser/ast/for_tree.rs b/src/parser/ast/for_tree.rs new file mode 100644 index 0000000..d888484 --- /dev/null +++ b/src/parser/ast/for_tree.rs @@ -0,0 +1,86 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, SeperatorType}, + }, + parser::{ + ast::{ + expression_tree::ExpressionTree, + statement_tree::{SimpleStatementTree, StatementTree}, + Tree, + }, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Debug, Clone)] +pub struct ForTree { + initializer: Option, + condition: ExpressionTree, + advancement: Option, + statement: Box, + span: Span, +} + +impl Tree for ForTree { + fn span(&self) -> Span { + self.span.merge(&self.statement.span()) + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let keyword = tokens.expect_keyword(KeywordType::For)?; + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let initializer = SimpleStatementTree::from_tokens(tokens).ok(); + trace!("Parsed initializer {:?}", initializer); + tokens.expect_seperator(SeperatorType::Semicolon)?; + let condition = ExpressionTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::Semicolon)?; + trace!("Parsing advancement for for: {:?}", tokens.peek()); + let advancement = SimpleStatementTree::from_tokens(tokens).ok(); + trace!("Parsed advancement: {:?}", advancement); + tokens.expect_seperator(SeperatorType::ParenClose)?; + let statement = StatementTree::from_tokens(tokens)?; + let span = keyword.span().merge(&statement.span()); + Ok(ForTree { + initializer, + condition, + advancement, + statement: Box::new(statement), + span, + }) + } +} + +impl ForTree { + pub fn initializer(&self) -> &Option { + &self.initializer + } + pub fn condition(&self) -> &ExpressionTree { + &self.condition + } + pub fn advancement(&self) -> &Option { + &self.advancement + } + pub fn statement(&self) -> &StatementTree { + &self.statement + } +} + +impl Display for ForTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "for(",)?; + if let Some(initializer) = &self.initializer { + write!(f, "{}", initializer)?; + } + write!(f, "; {}; ", self.condition)?; + if let Some(advancement) = &self.advancement { + write!(f, "{}", advancement)?; + } + write!(f, ") {}", self.statement) + } +} diff --git a/src/parser/ast/function_parameter_tree.rs b/src/parser/ast/function_parameter_tree.rs new file mode 100644 index 0000000..bfe7199 --- /dev/null +++ b/src/parser/ast/function_parameter_tree.rs @@ -0,0 +1,15 @@ +use std::fmt::Display; + +use crate::parser::ast::{identifier_tree::IdentifierExpressionTree, type_tree::TypeTree}; + +#[derive(Clone, Debug)] +pub struct FunctionParameterTree { + type_tree: TypeTree, + identifier: IdentifierExpressionTree, +} + +impl Display for FunctionParameterTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", self.identifier, self.type_tree) + } +} diff --git a/src/parser/ast/function_tree.rs b/src/parser/ast/function_tree.rs new file mode 100644 index 0000000..bd81bf4 --- /dev/null +++ b/src/parser/ast/function_tree.rs @@ -0,0 +1,75 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{collection::ParserTokens, token::SeperatorType}, + parser::{ + ast::{ + block_tree::BlockTree, function_parameter_tree::FunctionParameterTree, + name_tree::NameTree, type_tree::TypeTree, Tree, + }, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct FunctionTree { + return_type: TypeTree, + name: NameTree, + body: BlockTree, + parameters: Vec, +} + +impl Tree for FunctionTree { + fn span(&self) -> Span { + self.return_type.span().merge(&self.body.span()) + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into function"); + let return_type = TypeTree::from_tokens(tokens)?; + let name = NameTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let parameters = vec![]; + // TODO: Parse function parameters + tokens.expect_seperator(SeperatorType::ParenClose)?; + let body = BlockTree::from_tokens(tokens)?; + trace!("Successfully parsed function"); + Ok(FunctionTree { + return_type, + name, + body, + parameters, + }) + } +} + +impl FunctionTree { + pub fn return_type(&self) -> &TypeTree { + &self.return_type + } + + pub fn name_tree(&self) -> &NameTree { + &self.name + } + + pub fn body(&self) -> &BlockTree { + &self.body + } + + pub fn parameters(&self) -> &Vec { + &self.parameters + } +} + +impl Display for FunctionTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{} {}(", self.return_type, self.name)?; + for parameter in &self.parameters { + write!(f, "{}", parameter)?; + } + write!(f, "{}", self.body) + } +} diff --git a/src/parser/ast/identifier_tree.rs b/src/parser/ast/identifier_tree.rs new file mode 100644 index 0000000..89f566b --- /dev/null +++ b/src/parser/ast/identifier_tree.rs @@ -0,0 +1,43 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::collection::ParserTokens, + parser::{ + ast::{name_tree::NameTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct IdentifierExpressionTree { + name: NameTree, +} + +impl Tree for IdentifierExpressionTree { + fn span(&self) -> Span { + self.name.span() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into identifier"); + trace!("First token {:?}", tokens.peek()); + let name = NameTree::from_tokens(tokens)?; + trace!("Successfully parsed tokens into name"); + Ok(IdentifierExpressionTree { name }) + } +} + +impl IdentifierExpressionTree { + pub fn name(&self) -> &NameTree { + &self.name + } +} + +impl Display for IdentifierExpressionTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} diff --git a/src/parser/ast/if_tree.rs b/src/parser/ast/if_tree.rs new file mode 100644 index 0000000..7bd7a94 --- /dev/null +++ b/src/parser/ast/if_tree.rs @@ -0,0 +1,75 @@ +use std::fmt::Display; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, SeperatorType}, + }, + parser::{ + ast::{expression_tree::ExpressionTree, statement_tree::StatementTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct IfTree { + condition: ExpressionTree, + if_statement: Box, + else_statement: Option>, +} + +impl Tree for IfTree { + fn span(&self) -> Span { + if let Some(else_statement) = &self.else_statement { + self.condition.span().merge(&else_statement.span()) + } else { + self.condition.span().merge(&self.if_statement.span()) + } + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + tokens.expect_keyword(KeywordType::If)?; + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let condition = ExpressionTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::ParenClose)?; + let if_statement = Box::new(StatementTree::from_tokens(tokens)?); + if let Some(else_token) = tokens.peek() { + if else_token.is_keyword(&KeywordType::Else) { + tokens.consume()?; + let else_statement = Box::new(StatementTree::from_tokens(tokens)?); + return Ok(IfTree { + condition, + if_statement, + else_statement: Some(else_statement), + }); + } + } + Ok(IfTree { + condition, + if_statement, + else_statement: None, + }) + } +} + +impl IfTree { + pub fn condition(&self) -> &ExpressionTree { + &self.condition + } + pub fn if_statement(&self) -> &StatementTree { + &self.if_statement + } + pub fn else_statement(&self) -> &Option> { + &self.else_statement + } +} + +impl Display for IfTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "if({}) {}", self.condition, self.if_statement)?; + if let Some(else_statement) = &self.else_statement { + write!(f, "else {}", else_statement)?; + } + Ok(()) + } +} diff --git a/src/parser/ast/literal_tree.rs b/src/parser/ast/literal_tree.rs new file mode 100644 index 0000000..c924eec --- /dev/null +++ b/src/parser/ast/literal_tree.rs @@ -0,0 +1,107 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, Token}, + }, + parser::{ast::Tree, error::ParseError}, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct IntegerLiteralTree { + value: String, + base: usize, + span: Span, +} + +impl Tree for IntegerLiteralTree { + fn span(&self) -> Span { + self.span.clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into integer literal"); + trace!("First token {:?}", tokens.peek()); + let token = tokens.consume()?; + if let Token::NumberLiteral(span, value, base) = token { + trace!("Sucessfully parsed into integer literal"); + Ok(IntegerLiteralTree { + value: value.clone(), + base: base.clone(), + span: span.clone(), + }) + } else { + tokens.push(token); + Err(ParseError::ExpectedLiteral) + } + } +} + +impl IntegerLiteralTree { + pub fn new(value: String, base: usize, span: Span) -> IntegerLiteralTree { + IntegerLiteralTree { value, base, span } + } + + pub fn value(&self) -> &String { + &self.value + } + + pub fn base(&self) -> usize { + self.base + } +} + +#[derive(Clone, Debug)] +pub struct BooleanLiteralTree { + value: bool, + span: Span, +} + +impl Tree for BooleanLiteralTree { + fn span(&self) -> Span { + self.span.clone() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + if let Token::Keyword(_, keyword_type) = tokens.peek().ok_or(ParseError::ReachedEnd)? { + if keyword_type.eq(&KeywordType::True) { + let token = tokens.consume()?; + Ok(BooleanLiteralTree { + value: true, + span: token.span(), + }) + } else if keyword_type.eq(&KeywordType::False) { + let token = tokens.consume()?; + Ok(BooleanLiteralTree { + value: false, + span: token.span(), + }) + } else { + Err(ParseError::ExpectedLiteral) + } + } else { + Err(ParseError::ExpectedLiteral) + } + } +} + +impl BooleanLiteralTree { + pub fn value(&self) -> bool { + self.value + } +} + +impl Display for IntegerLiteralTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Display for BooleanLiteralTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value) + } +} diff --git a/src/parser/ast/lvalue_tree.rs b/src/parser/ast/lvalue_tree.rs new file mode 100644 index 0000000..9a53e7c --- /dev/null +++ b/src/parser/ast/lvalue_tree.rs @@ -0,0 +1,48 @@ +use std::fmt::Display; + +use crate::{ + lexer::{collection::ParserTokens, token::SeperatorType}, + parser::{ + ast::{name_tree::NameTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct LValueTree { + identifier: NameTree, +} + +impl Tree for LValueTree { + fn span(&self) -> Span { + self.identifier.span().clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + if tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_separator(&SeperatorType::ParenOpen) + { + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let inner = LValueTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::ParenClose)?; + return Ok(inner); + } + Ok(LValueTree { + identifier: NameTree::from_tokens(tokens)?, + }) + } +} + +impl LValueTree { + pub fn identifier(&self) -> &NameTree { + &self.identifier + } +} + +impl Display for LValueTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.identifier) + } +} diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs new file mode 100644 index 0000000..8bb3ca0 --- /dev/null +++ b/src/parser/ast/mod.rs @@ -0,0 +1,32 @@ +use crate::{lexer::collection::ParserTokens, parser::error::ParseError, util::span::Span}; + +pub mod assignment_tree; +pub mod binary_operation_tree; +pub mod block_tree; +pub mod break_tree; +pub mod call_tree; +pub mod continue_tree; +pub mod declaration_tree; +pub mod expression_tree; +pub mod for_tree; +pub mod function_parameter_tree; +pub mod function_tree; +pub mod identifier_tree; +pub mod if_tree; +pub mod literal_tree; +pub mod lvalue_tree; +pub mod name_tree; +pub mod program_tree; +pub mod return_tree; +pub mod statement_tree; +pub mod ternary_operation_tree; +pub mod type_tree; +pub mod unary_operation_tree; +pub mod while_tree; + +pub trait Tree { + fn span(&self) -> Span; + fn from_tokens(tokens: &mut ParserTokens) -> Result + where + Self: Sized; +} diff --git a/src/parser/ast/name_tree.rs b/src/parser/ast/name_tree.rs new file mode 100644 index 0000000..588c4b3 --- /dev/null +++ b/src/parser/ast/name_tree.rs @@ -0,0 +1,44 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{collection::ParserTokens, token::Token}, + parser::{ast::Tree, error::ParseError, symbols::Name}, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct NameTree { + name: Name, + span: Span, +} + +impl Tree for NameTree { + fn span(&self) -> Span { + self.span.clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into name"); + if let Token::Identifier(span, value) = tokens.expect_identifier()? { + trace!("Sucessfully parsed into name"); + return Ok(NameTree { + name: Name::IdentifierName(value), + span, + }); + } + Err(ParseError::ExpectedIdentifier) + } +} + +impl NameTree { + pub fn name(&self) -> &Name { + &self.name + } +} + +impl Display for NameTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name.as_string()) + } +} diff --git a/src/parser/ast/program_tree.rs b/src/parser/ast/program_tree.rs new file mode 100644 index 0000000..d997219 --- /dev/null +++ b/src/parser/ast/program_tree.rs @@ -0,0 +1,68 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::collection::ParserTokens, + parser::{ + ast::{function_tree::FunctionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct ProgramTree { + functions: Vec, +} + +impl ProgramTree { + pub fn functions(&self) -> &Vec { + &self.functions + } +} + +impl Tree for ProgramTree { + fn span(&self) -> Span { + self.functions + .first() + .expect("Expected at least one function") + .span() + .merge( + &self + .functions + .last() + .expect("Expected at least one function") + .span(), + ) + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into program"); + let mut functions = Vec::new(); + while tokens.has_next() { + functions.push(FunctionTree::from_tokens(tokens)?); + } + trace!("Parsed functions: {:?}", functions); + if functions.is_empty() { + return Err(ParseError::NoFunctions); + } + if functions + .iter() + .any(|v| v.name_tree().name().as_string() == "main") + { + Ok(ProgramTree { functions }) + } else { + Err(ParseError::NoMainFunction) + } + } +} + +impl Display for ProgramTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for function in &self.functions { + writeln!(f, "{}", function)?; + } + Ok(()) + } +} diff --git a/src/parser/ast/return_tree.rs b/src/parser/ast/return_tree.rs new file mode 100644 index 0000000..c8a1309 --- /dev/null +++ b/src/parser/ast/return_tree.rs @@ -0,0 +1,46 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{collection::ParserTokens, token::KeywordType}, + parser::{ + ast::{expression_tree::ExpressionTree, Tree}, + error::ParseError, + }, + util::{position::Position, span::Span}, +}; + +#[derive(Clone, Debug)] +pub struct ReturnTree { + expression: ExpressionTree, + start: Position, +} + +impl Tree for ReturnTree { + fn span(&self) -> Span { + Span::new(self.start.clone(), self.expression.span().end().clone()) + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into return"); + trace!("First token {:?}", tokens.peek()); + let return_keyword = tokens.expect_keyword(KeywordType::Return)?; + let expression = ExpressionTree::from_tokens(tokens)?; + Ok(ReturnTree { + expression, + start: return_keyword.span().start().clone(), + }) + } +} + +impl ReturnTree { + pub fn expression(&self) -> &ExpressionTree { + &self.expression + } +} + +impl Display for ReturnTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "return {}", self.expression) + } +} diff --git a/src/parser/ast/statement_tree.rs b/src/parser/ast/statement_tree.rs new file mode 100644 index 0000000..901b73f --- /dev/null +++ b/src/parser/ast/statement_tree.rs @@ -0,0 +1,180 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, SeperatorType}, + }, + parser::{ + ast::{ + assignment_tree::AssignmentTree, block_tree::BlockTree, break_tree::BreakTree, + call_tree::CallTree, continue_tree::ContinueTree, declaration_tree::DeclarationTree, + for_tree::ForTree, if_tree::IfTree, return_tree::ReturnTree, while_tree::WhileTree, + Tree, + }, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub enum StatementTree { + SimpleStatement(SimpleStatementTree), + ControlStatement(ControlStatementTree), + BlockStatement(BlockTree), +} + +impl Tree for StatementTree { + fn span(&self) -> Span { + match self { + StatementTree::SimpleStatement(tree) => tree.span(), + StatementTree::ControlStatement(tree) => tree.span(), + StatementTree::BlockStatement(tree) => tree.span(), + } + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into statement"); + trace!("First token {:?}", tokens.peek()); + match tokens.peek().ok_or(ParseError::ReachedEnd)? { + token if token.is_control_keyword() => Ok(StatementTree::ControlStatement( + ControlStatementTree::from_tokens(tokens)?, + )), + token if token.is_separator(&SeperatorType::BraceOpen) => Ok( + StatementTree::BlockStatement(BlockTree::from_tokens(tokens)?), + ), + _ => { + let statement = SimpleStatementTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::Semicolon)?; + Ok(StatementTree::SimpleStatement(statement)) + } + } + } +} + +#[derive(Clone, Debug)] +pub enum SimpleStatementTree { + AssignmentTree(AssignmentTree), + DeclerationTree(DeclarationTree), + CallTree(CallTree), +} + +impl Tree for SimpleStatementTree { + fn span(&self) -> Span { + match self { + SimpleStatementTree::AssignmentTree(tree) => tree.span(), + SimpleStatementTree::DeclerationTree(tree) => tree.span(), + SimpleStatementTree::CallTree(tree) => tree.span(), + } + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into simple statement"); + trace!("First token {:?}", tokens.peek()); + match tokens.peek().ok_or(ParseError::ReachedEnd)? { + token if token.is_type_keyword() => { + let declaration_tree = DeclarationTree::from_tokens(tokens)?; + return Ok(SimpleStatementTree::DeclerationTree(declaration_tree)); + } + _ => { + if let Ok(assignment_tree) = AssignmentTree::from_tokens(tokens) { + return Ok(SimpleStatementTree::AssignmentTree(assignment_tree)); + } + if let Ok(call_tree) = CallTree::from_tokens(tokens) { + return Ok(SimpleStatementTree::CallTree(call_tree)); + } + } + } + Err(ParseError::NotAStatement) + } +} + +#[derive(Clone, Debug)] +pub enum ControlStatementTree { + IfTree(IfTree), + WhileTree(WhileTree), + ForTree(ForTree), + ContinueTree(ContinueTree), + BreakTree(BreakTree), + ReturnTree(ReturnTree), +} + +impl Tree for ControlStatementTree { + fn span(&self) -> Span { + match self { + ControlStatementTree::IfTree(tree) => tree.span(), + ControlStatementTree::WhileTree(tree) => tree.span(), + ControlStatementTree::ForTree(tree) => tree.span(), + ControlStatementTree::ContinueTree(tree) => tree.span(), + ControlStatementTree::BreakTree(tree) => tree.span(), + ControlStatementTree::ReturnTree(tree) => tree.span(), + } + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into control statement"); + trace!("First token {:?}", tokens.peek()); + match tokens.peek().ok_or(ParseError::ReachedEnd)? { + token if token.is_keyword(&KeywordType::If) => { + Ok(ControlStatementTree::IfTree(IfTree::from_tokens(tokens)?)) + } + token if token.is_keyword(&KeywordType::While) => Ok(ControlStatementTree::WhileTree( + WhileTree::from_tokens(tokens)?, + )), + token if token.is_keyword(&KeywordType::Continue) => { + let statement = ContinueTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::Semicolon)?; + Ok(ControlStatementTree::ContinueTree(statement)) + } + token if token.is_keyword(&KeywordType::For) => { + return Ok(ControlStatementTree::ForTree(ForTree::from_tokens(tokens)?)) + } + token if token.is_keyword(&KeywordType::Break) => { + let statement = BreakTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::Semicolon)?; + Ok(ControlStatementTree::BreakTree(statement)) + } + token if token.is_keyword(&KeywordType::Return) => { + let statement = ReturnTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::Semicolon)?; + Ok(ControlStatementTree::ReturnTree(statement)) + } + _ => Err(ParseError::NotAStatement), + } + } +} + +impl Display for StatementTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StatementTree::SimpleStatement(tree) => writeln!(f, "{}", tree), + StatementTree::ControlStatement(tree) => writeln!(f, "{}", tree), + StatementTree::BlockStatement(tree) => writeln!(f, "{}", tree), + } + } +} + +impl Display for SimpleStatementTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SimpleStatementTree::AssignmentTree(tree) => write!(f, "{}", tree), + SimpleStatementTree::DeclerationTree(tree) => write!(f, "{}", tree), + SimpleStatementTree::CallTree(tree) => write!(f, "{}", tree), + } + } +} + +impl Display for ControlStatementTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ControlStatementTree::IfTree(tree) => write!(f, "{}", tree), + ControlStatementTree::WhileTree(tree) => write!(f, "{}", tree), + ControlStatementTree::ForTree(tree) => write!(f, "{}", tree), + ControlStatementTree::ContinueTree(tree) => write!(f, "{}", tree), + ControlStatementTree::BreakTree(tree) => write!(f, "{}", tree), + ControlStatementTree::ReturnTree(tree) => write!(f, "{}", tree), + } + } +} diff --git a/src/parser/ast/ternary_operation_tree.rs b/src/parser/ast/ternary_operation_tree.rs new file mode 100644 index 0000000..7254be6 --- /dev/null +++ b/src/parser/ast/ternary_operation_tree.rs @@ -0,0 +1,68 @@ +use std::fmt::Display; + +use crate::{ + lexer::{collection::ParserTokens, token::MAX_PRECEDENCE}, + parser::{ + ast::{expression_tree::ExpressionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct TernaryOperationTree { + condition: Box, + true_expression: Box, + false_expression: Box, +} + +impl Tree for TernaryOperationTree { + fn span(&self) -> Span { + self.condition.span().merge(&self.false_expression.span()) + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let result = ExpressionTree::from_tokens_precedence(tokens, MAX_PRECEDENCE)?; + match result { + ExpressionTree::TernaryOperationTree(tree) => Ok(tree), + _ => Err(ParseError::NotAOperation), + } + } +} + +impl TernaryOperationTree { + pub fn new( + condition: Box, + true_expression: Box, + false_expression: Box, + ) -> TernaryOperationTree { + TernaryOperationTree { + condition, + true_expression, + false_expression, + } + } +} + +impl TernaryOperationTree { + pub fn condition(&self) -> &ExpressionTree { + &self.condition + } + + pub fn true_expression(&self) -> &ExpressionTree { + &self.true_expression + } + + pub fn false_expression(&self) -> &ExpressionTree { + &self.false_expression + } +} + +impl Display for TernaryOperationTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} ? {} : {}", + self.condition, self.true_expression, self.false_expression + ) + } +} diff --git a/src/parser/ast/type_tree.rs b/src/parser/ast/type_tree.rs new file mode 100644 index 0000000..b50f8b1 --- /dev/null +++ b/src/parser/ast/type_tree.rs @@ -0,0 +1,61 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, Token}, + }, + parser::{ast::Tree, error::ParseError, types::Type}, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct TypeTree { + type_tree: Type, + span: Span, +} + +impl Tree for TypeTree { + fn span(&self) -> Span { + self.span.clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing tokens into type"); + let token = tokens.expect_type()?; + if let Token::Keyword(span, keyword_type) = token { + match keyword_type { + KeywordType::Int => { + trace!("Successfully parsed into type"); + return Ok(TypeTree { + type_tree: Type::Int, + span, + }); + } + KeywordType::Bool => { + trace!("Successfully parsed into type"); + return Ok(TypeTree { + type_tree: Type::Bool, + span, + }); + } + _ => return Err(ParseError::ExpectedType), + } + } else { + return Err(ParseError::ExpectedType); + } + } +} + +impl TypeTree { + pub fn type_tree(&self) -> &Type { + &self.type_tree + } +} + +impl Display for TypeTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.type_tree.as_string()) + } +} diff --git a/src/parser/ast/unary_operation_tree.rs b/src/parser/ast/unary_operation_tree.rs new file mode 100644 index 0000000..4150cd0 --- /dev/null +++ b/src/parser/ast/unary_operation_tree.rs @@ -0,0 +1,96 @@ +use std::fmt::Display; + +use tracing::trace; + +use crate::{ + lexer::{ + collection::ParserTokens, + operator::UnaryOperator, + token::{OperatorType, Token, MAX_PRECEDENCE}, + }, + parser::{ + ast::{expression_tree::ExpressionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct UnaryOperationTree { + operator: UnaryOperator, + expression: Box, + span: Span, +} + +impl Tree for UnaryOperationTree { + fn span(&self) -> Span { + self.span.clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let result = UnaryOperationTree::from_tokens_precedence(tokens, MAX_PRECEDENCE)?; + match result { + ExpressionTree::UnaryOperationTree(tree) => Ok(tree), + _ => Err(ParseError::NotAOperation), + } + } +} + +impl UnaryOperationTree { + pub fn new( + operator: UnaryOperator, + expression: Box, + span: Span, + ) -> UnaryOperationTree { + UnaryOperationTree { + operator, + expression, + span, + } + } + + pub fn from_tokens_precedence( + tokens: &mut ParserTokens, + precedence: u8, + ) -> Result { + trace!("Parsing into unary operation (predecence {})", precedence); + if precedence == 0 { + return ExpressionTree::from_tokens_precedence(tokens, precedence); + } + if let Token::Operator(_, ref operator_type) = + // TODO: Is this clone nececarry + tokens.peek().ok_or(ParseError::ReachedEnd)?.clone() + { + if operator_type.get_precedence().contains(&precedence) { + let expression = + Box::new(ExpressionTree::from_tokens_precedence(tokens, precedence)?); + let span = tokens.consume()?.span().merge(&expression.span()); + let operator = match operator_type { + OperatorType::LogicalNot => UnaryOperator::LogicalNot, + OperatorType::BitwiseNot => UnaryOperator::BitwiseNot, + OperatorType::Minus => UnaryOperator::Minus, + _ => return Err(ParseError::ExpectedUnaryOperator), + }; + return Ok(ExpressionTree::UnaryOperationTree(UnaryOperationTree { + expression, + operator, + span, + })); + } + } + ExpressionTree::from_tokens_precedence(tokens, precedence - 1) + } + + pub fn operator(&self) -> &UnaryOperator { + &self.operator + } + + pub fn expression(&self) -> &ExpressionTree { + &self.expression + } +} + +impl Display for UnaryOperationTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{}", self.operator, self.expression) + } +} diff --git a/src/parser/ast/while_tree.rs b/src/parser/ast/while_tree.rs new file mode 100644 index 0000000..e93466c --- /dev/null +++ b/src/parser/ast/while_tree.rs @@ -0,0 +1,55 @@ +use std::fmt::Display; + +use crate::{ + lexer::{ + collection::ParserTokens, + token::{KeywordType, SeperatorType}, + }, + parser::{ + ast::{expression_tree::ExpressionTree, statement_tree::StatementTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct WhileTree { + span: Span, + condition: Box, + statement: Box, +} + +impl Tree for WhileTree { + fn span(&self) -> Span { + self.span.clone() + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let keyword = tokens.expect_keyword(KeywordType::While)?; + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let condition = Box::new(ExpressionTree::from_tokens(tokens)?); + tokens.expect_seperator(SeperatorType::ParenClose)?; + let statement = Box::new(StatementTree::from_tokens(tokens)?); + let span = keyword.span().merge(&statement.span()); + Ok(WhileTree { + span, + condition, + statement, + }) + } +} + +impl WhileTree { + pub fn condition(&self) -> &ExpressionTree { + &self.condition + } + pub fn statement(&self) -> &StatementTree { + &self.statement + } +} + +impl Display for WhileTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "while({}) ", self.condition)?; + write!(f, "{}", self.statement) + } +} diff --git a/src/parser/error.rs b/src/parser/error.rs index cf8c7c5..a7cb773 100644 --- a/src/parser/error.rs +++ b/src/parser/error.rs @@ -1,5 +1,33 @@ +use std::fmt::Display; + +use crate::lexer::token::{KeywordType, OperatorType, SeperatorType}; + #[derive(PartialEq, Debug)] pub enum ParseError { - Finished, - Error(String), + ExpectedKeyword(KeywordType), + ExpectedSeparator(SeperatorType), + ExpectedOperator(OperatorType), + ExpectedIdentifier, + ExpectedType, + ExpectedAssignmentOperator, + ExpectedUnaryOperator, + ExpectedBinaryOperator, + ExpectedTernaryOperator, + ExpectedLiteral, + ExpectedKeywordOrIdentifier, + NotAnExpression, + NotAStatement, + NotAOperation, + NoFunctions, + NoMainFunction, + ReachedEnd, + WhitespaceError, + InvalidCharacter, +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // TODO: Proper implementation + write!(f, "{:?}", self) + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 74cda38..6a0af2d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,476 +1,4 @@ -use std::collections::VecDeque; - -use ast::Tree; -use error::ParseError; -use symbols::Name; -use tracing::trace; -use types::Type; - -use crate::lexer::token::{KeywordType, OperatorType, SeperatorType, Token, MAX_PRECEDENCE}; - pub mod ast; pub mod error; pub mod symbols; pub mod types; - -pub struct Parser { - tokens: VecDeque, -} - -impl Parser { - pub fn new(tokens: VecDeque) -> Parser { - Parser { tokens } - } - - pub fn parse_program(mut self) -> Result { - let functions = vec![parse_function(&mut self.tokens)?]; - if !self.tokens.is_empty() { - return Err(ParseError::Error( - "Tokens leftover after parsing!".to_string(), - )); - } - Ok(Tree::Program(functions)) - } -} - -fn parse_function(tokens: &mut VecDeque) -> Result { - let return_type = expect_keyword(tokens, KeywordType::Int) - .ok_or(ParseError::Error("Expected int".to_string()))?; - let identifier = - expect_identifier(tokens).ok_or(ParseError::Error("Expected identifier".to_string()))?; - if let Token::Identifier(_, name) = identifier.clone() { - if name != "main" { - return Err(ParseError::Error(format!( - "Expected main function, but got {}", - &name - ))); - } - } else { - return Err(ParseError::Error(format!( - "Expected identifier, but got {:?}", - &identifier - ))); - } - expect_seperator(tokens, SeperatorType::ParenOpen) - .ok_or(ParseError::Error("Expected ParenOpen".to_string()))?; - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expected ParenClose".to_string()))?; - let body = parse_block(tokens)?; - Ok(Tree::Function( - Box::new(Tree::Type(Type::Int, return_type.span())), - name(identifier)?, - Box::new(body), - )) -} - -fn parse_block(tokens: &mut VecDeque) -> Result { - let body_open = expect_seperator(tokens, SeperatorType::BraceOpen) - .ok_or(ParseError::Error("Expected block for function".to_string()))?; - let mut statements = vec![]; - while !tokens.is_empty() { - match tokens.front().unwrap() { - Token::Separator(_, seperator) if seperator.eq(&SeperatorType::BraceClose) => { - break; - } - _ => statements.push(parse_statement(tokens)?), - } - } - let body_close = expect_seperator(tokens, SeperatorType::BraceClose) - .ok_or(ParseError::Error("Expected BraceClose".to_string()))?; - Ok(Tree::Block( - statements, - body_open.span().merge(body_close.span()), - )) -} - -fn parse_statement(tokens: &mut VecDeque) -> Result { - let statement = if tokens - .front() - .unwrap() - .is_separator(&SeperatorType::BraceOpen) - { - parse_block(tokens)? - } else if tokens.front().unwrap().is_control_keyword() { - parse_control(tokens)? - } else { - let simple = parse_simple(tokens)?; - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expecting Semicolon!".to_string()))?; - simple - }; - Ok(statement) -} - -fn parse_control(tokens: &mut VecDeque) -> Result { - let keyword = tokens.front().unwrap(); - let expression = if keyword.is_keyword(&KeywordType::Return) { - let result = parse_return(tokens); - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expected Semicolon".to_string()))?; - result - } else if keyword.is_keyword(&KeywordType::Break) { - let result = parse_break(tokens); - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expected Semicolon".to_string()))?; - result - } else if keyword.is_keyword(&KeywordType::Continue) { - let result = parse_continue(tokens); - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expected Semicolon".to_string()))?; - result - } else if keyword.is_keyword(&KeywordType::For) { - parse_for(tokens) - } else if keyword.is_keyword(&KeywordType::While) { - parse_while(tokens) - } else if keyword.is_keyword(&KeywordType::If) { - parse_if(tokens) - } else { - Err(ParseError::Error("Expected control keyword".to_string())) - }; - trace!("Finished parsing control structure: {:?}", tokens); - - expression -} - -fn parse_decleration(tokens: &mut VecDeque) -> Result { - let type_token = - expect_type(tokens).ok_or(ParseError::Error("Expected type keyword".to_string()))?; - let identifier = - expect_identifier(tokens).ok_or(ParseError::Error("Expected identifier".to_string()))?; - let mut expression = None; - if tokens - .front() - .unwrap() - .is_operator_type(&OperatorType::Assign) - { - expect_operator(tokens, OperatorType::Assign).ok_or(ParseError::Error( - "Expected assignment operator".to_string(), - ))?; - expression = Some(parse_expression(tokens)?); - } - Ok(Tree::Declaration( - Box::new(Tree::Type( - type_token.get_type_value().unwrap(), - type_token.span(), - )), - name(identifier)?, - expression, - )) -} - -fn parse_return(tokens: &mut VecDeque) -> Result { - trace!("Parsing return: {:?}", tokens); - let return_keyword = expect_keyword(tokens, KeywordType::Return) - .ok_or(ParseError::Error("Expected keyword RETURN".to_string()))?; - let expression = parse_expression(tokens)?; - Ok(Tree::Return( - expression, - return_keyword.span().start_owned(), - )) -} - -fn parse_break(tokens: &mut VecDeque) -> Result { - let break_keyword = expect_keyword(tokens, KeywordType::Break) - .ok_or(ParseError::Error("Expected keyword BREAK".to_string()))?; - Ok(Tree::Break(break_keyword.span())) -} - -fn parse_continue(tokens: &mut VecDeque) -> Result { - let continue_keyword = expect_keyword(tokens, KeywordType::Continue) - .ok_or(ParseError::Error("Expected keyword CONTINUE".to_string()))?; - Ok(Tree::Continue(continue_keyword.span())) -} - -fn parse_for(tokens: &mut VecDeque) -> Result { - let keyword = expect_keyword(tokens, KeywordType::For) - .ok_or(ParseError::Error("Expected keyword IF".to_string()))?; - expect_seperator(tokens, SeperatorType::ParenOpen) - .ok_or(ParseError::Error("Expected paren open".to_string()))?; - let initializer = parse_simple(tokens).ok(); - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expected Semicolon".to_string()))?; - let expression = parse_expression(tokens)?; - expect_seperator(tokens, SeperatorType::Semicolon) - .ok_or(ParseError::Error("Expected Semicolon".to_string()))?; - let updating_expression = parse_simple(tokens).ok(); - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expected paren close".to_string()))?; - let statement = parse_statement(tokens)?; - let span = keyword.span().merge(statement.span()); - Ok(Tree::For( - initializer.map(|v| Box::new(v)), - expression, - updating_expression.map(|v| Box::new(v)), - Box::new(statement), - span, - )) -} - -fn parse_while(tokens: &mut VecDeque) -> Result { - let keyword = expect_keyword(tokens, KeywordType::While) - .ok_or(ParseError::Error("Expected keyword WHILE".to_string()))?; - expect_seperator(tokens, SeperatorType::ParenOpen) - .ok_or(ParseError::Error("Expected paren open".to_string()))?; - let expression = parse_expression(tokens)?; - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expected paren close".to_string()))?; - let statement = parse_statement(tokens)?; - let span = keyword.span().merge(statement.span()); - Ok(Tree::While(expression, Box::new(statement), span)) -} - -fn parse_if(tokens: &mut VecDeque) -> Result { - let keyword = expect_keyword(tokens, KeywordType::If) - .ok_or(ParseError::Error("Expected keyword IF".to_string()))?; - expect_seperator(tokens, SeperatorType::ParenOpen) - .ok_or(ParseError::Error("Expected paren open".to_string()))?; - let expression = parse_expression(tokens)?; - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expected paren close".to_string()))?; - let statement = parse_statement(tokens)?; - if tokens.front().unwrap().is_keyword(&KeywordType::Else) { - consume(tokens); - let else_statement = parse_statement(tokens)?; - let span = keyword.span().merge(else_statement.span()); - Ok(Tree::If( - expression, - Box::new(statement), - Some(Box::new(else_statement)), - span, - )) - } else { - let span = keyword.span().merge(statement.span()); - Ok(Tree::If(expression, Box::new(statement), None, span)) - } -} - -fn parse_simple(tokens: &mut VecDeque) -> Result { - if tokens.front().unwrap().is_type_keyword() { - parse_decleration(tokens) - } else { - let lvalue = parse_lvalue(tokens)?; - let assignment_operator = parse_assignment_operator(tokens)?; - let expression = parse_expression(tokens)?; - Ok(Tree::Assignment(lvalue, assignment_operator, expression)) - } -} - -fn parse_assignment_operator(tokens: &mut VecDeque) -> Result { - if tokens.front().unwrap().is_assignment_operator() { - return tokens.pop_front().ok_or(ParseError::Finished); - } - Err(ParseError::Error( - "Expected assignment operator".to_string(), - )) -} - -fn parse_lvalue(tokens: &mut VecDeque) -> Result, ParseError> { - if tokens - .front() - .unwrap() - .is_separator(&SeperatorType::ParenOpen) - { - expect_seperator(tokens, SeperatorType::ParenOpen) - .ok_or(ParseError::Error("Expected ParenOpen".to_string()))?; - let inner = parse_lvalue(tokens)?; - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expected ParenClose".to_string()))?; - return Ok(inner); - } - let identifier = expect_identifier(tokens).ok_or(ParseError::Error(format!( - "Expected identifier, but got {:?}!", - tokens.front().unwrap() - )))?; - Ok(Box::new(Tree::LValueIdentifier(name(identifier)?))) -} - -fn parse_expression(tokens: &mut VecDeque) -> Result, ParseError> { - let lhs = parse_precedence_expression(tokens, MAX_PRECEDENCE)?; - if !tokens.front().unwrap().is_operator() { - return Ok(lhs); - } - if let Token::Operator(_, operator) = tokens.front().unwrap() { - if !operator.eq(&OperatorType::TernaryQuestionMark) { - return Ok(lhs); - } - } - consume(tokens); - let true_expression = parse_expression(tokens)?; - expect_operator(tokens, OperatorType::TernaryColon) - .ok_or(ParseError::Error("Expected ternary colon!".to_string()))?; - let false_expression = parse_expression(tokens)?; - Ok(Box::new(Tree::TernaryOperation( - lhs, - true_expression, - false_expression, - ))) -} - -fn parse_precedence_expression( - tokens: &mut VecDeque, - predecence: u8, -) -> Result, ParseError> { - if predecence == 1 { - return parse_unary_expression(tokens, predecence); - } else if predecence == 0 { - return parse_basic_expression(tokens); - } - - let mut lhs = parse_precedence_expression(tokens, predecence - 1)?; - loop { - let next_operator = tokens.pop_front().unwrap(); - if let Token::Operator(_, ref operator) = next_operator { - if matches!( - operator, - OperatorType::TernaryColon | OperatorType::TernaryQuestionMark - ) || operator.is_assignment_operator() - { - tokens.push_front(next_operator); - return Ok(lhs); - } - if operator.get_precedence().contains(&predecence) { - let rhs = parse_precedence_expression(tokens, predecence - 1)?; - lhs = Box::new(Tree::BinaryOperation(lhs, rhs, operator.clone())); - continue; - } - } - tokens.push_front(next_operator); - return Ok(lhs); - } -} - -fn parse_unary_expression( - tokens: &mut VecDeque, - predecence: u8, -) -> Result, ParseError> { - let token = tokens.pop_front().unwrap(); - if let Token::Operator(_, ref operator_type) = token { - if operator_type.get_precedence().contains(&predecence) { - let value = parse_precedence_expression(tokens, predecence)?; - let span = token.clone().span().merge(value.span()); - return Ok(Box::new(Tree::UnaryOperation( - value, - operator_type.clone(), - span, - ))); - } - } - tokens.push_front(token); - parse_precedence_expression(tokens, predecence - 1) -} - -fn parse_basic_expression(tokens: &mut VecDeque) -> Result, ParseError> { - match tokens.pop_front().unwrap() { - Token::Separator(_, seperator) if seperator.eq(&SeperatorType::ParenOpen) => { - let expression = parse_expression(tokens); - expect_seperator(tokens, SeperatorType::ParenClose) - .ok_or(ParseError::Error("Expecting ParenClose".to_string()))?; - expression - } - // FIXME: Janky negative hack, because I wanted nothing to do with int parsing - Token::Operator(span, operator) if operator.eq(&OperatorType::Minus) => { - match tokens.pop_front().unwrap() { - Token::NumberLiteral(span, value, base) => Ok(Box::new(Tree::Literal( - "-".to_owned() + value.as_str(), - base, - span.clone(), - ))), - token => { - tokens.push_front(token); - Ok(Box::new(Tree::UnaryOperation( - parse_expression(tokens)?, - OperatorType::Minus, - span, - ))) - } - } - } - identifier @ Token::Identifier(_, _) => { - Ok(Box::new(Tree::IdentifierExpression(name(identifier)?))) - } - Token::NumberLiteral(span, value, base) => Ok(Box::new(Tree::Literal(value, base, span))), - Token::Keyword(span, keyword) if keyword.eq(&KeywordType::True) => { - Ok(Box::new(Tree::BoolLiteral(true, span))) - } - Token::Keyword(span, keyword) if keyword.eq(&KeywordType::False) => { - Ok(Box::new(Tree::BoolLiteral(false, span))) - } - token => Err(ParseError::Error(format!( - "Expected ParenOpen, Minus, Identifier or Number Literal, but got {:?}", - token - ))), - } -} - -fn name(identifier: Token) -> Result, ParseError> { - if let Token::Identifier(span, value) = identifier { - return Ok(Box::new(Tree::Name(Name::IdentifierName(value), span))); - } - Err(ParseError::Error("Expected identifier as name".to_string())) -} - -#[must_use] -fn expect_keyword(tokens: &mut VecDeque, keyword: KeywordType) -> Option { - if let Some(token) = tokens.front() { - match token { - Token::Keyword(_, keyword_type) if keyword.eq(keyword_type) => { - return tokens.pop_front(); - } - _ => return None, - } - } - None -} - -#[must_use] -fn expect_seperator(tokens: &mut VecDeque, seperator: SeperatorType) -> Option { - if let Some(token) = tokens.front() { - match token { - Token::Separator(_, seperator_type) if seperator.eq(seperator_type) => { - return tokens.pop_front() - } - _ => return None, - } - } - None -} - -#[must_use] -fn expect_operator(tokens: &mut VecDeque, operator: OperatorType) -> Option { - if let Some(token) = tokens.front() { - match token { - Token::Operator(_, operator_type) if operator.eq(operator_type) => { - return tokens.pop_front() - } - _ => return None, - } - } - None -} - -#[must_use] -fn expect_identifier(tokens: &mut VecDeque) -> Option { - if let Some(token) = tokens.front() { - match token { - Token::Identifier(_, _) => { - return tokens.pop_front(); - } - _ => return None, - } - } - None -} - -fn expect_type(tokens: &mut VecDeque) -> Option { - if let Some(token) = tokens.front() { - match token { - Token::Keyword(_, keyword_type) if keyword_type.is_type() => return tokens.pop_front(), - _ => return None, - } - } - None -} - -fn consume(tokens: &mut VecDeque) -> Option { - tokens.pop_front() -} diff --git a/src/parser/types.rs b/src/parser/types.rs index 831fe63..1d07fb2 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -2,6 +2,7 @@ pub enum Type { Int, Bool, + Unit, } impl Type { @@ -9,6 +10,7 @@ impl Type { match self { Type::Int => "int", Type::Bool => "bool", + Type::Unit => "()", } } } diff --git a/src/semantic/ast/assignment_tree.rs b/src/semantic/ast/assignment_tree.rs new file mode 100644 index 0000000..5879275 --- /dev/null +++ b/src/semantic/ast/assignment_tree.rs @@ -0,0 +1,100 @@ +use tracing::trace; + +use crate::{ + lexer::operator::AssignmentOperator, + parser::{ast::assignment_tree::AssignmentTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus}, +}; + +impl SemanticAnalysis for AssignmentTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + self.lvalue().analyze(state)?; + self.expression().analyze(state)?; + + let operator = self.operator(); + let name = self.lvalue().identifier(); + if operator.eq(&AssignmentOperator::Assign) { + trace!( + "Variable {:?} is now defined with type {:?}!", + name, + self.expression().r#type(state)? + ); + state + .namespace + .get(&name.name()) + .ok_or(SemanticError::UndefinedVariable(name.clone()))?; + state + .namespace + .get_mut(&name.name()) + .unwrap() + .set_initialized(); + let expression_type = self.expression().r#type(state)?; + if state + .namespace + .get(&name.name()) + .unwrap() + .type_status() + .ne(&expression_type) + { + return Err(SemanticError::IncompatibleTypesAssign( + name.clone(), + self.expression().clone(), + )); + } + } else if !state.namespace.contains_key(&name.name()) { + return Err(SemanticError::UndefinedVariable(name.clone())); + } else if state + .namespace + .get(&name.name()) + .unwrap() + .declaration() + .eq(&DeclarationStatus::Declared) + && state.is_reachable() + { + return Err(SemanticError::UninitializedVariable(name.clone())); + } + let lhs_type = self.lvalue().r#type(state)?; + let rhs_type = self.expression().r#type(state)?; + trace!("Assignment types: {:?} {:?}", lhs_type, rhs_type); + match self.operator() { + AssignmentOperator::Assign => { + if lhs_type.ne(&rhs_type) { + return Err(SemanticError::IncompatibleTypesAssign( + name.clone(), + self.expression().clone(), + )); + } + } + AssignmentOperator::AssignPlus + | AssignmentOperator::AssignMinus + | AssignmentOperator::AssignMul + | AssignmentOperator::AssignDiv + | AssignmentOperator::AssignMod + | AssignmentOperator::AssignShiftLeft + | AssignmentOperator::AssignShiftRight => { + if lhs_type.ne(&Type::Int) || rhs_type.ne(&Type::Int) { + return Err(SemanticError::IncompatibleTypesAssign( + name.clone(), + self.expression().clone(), + )); + } + } + AssignmentOperator::AssignBitwiseNot + | AssignmentOperator::AssignBitwiseAnd + | AssignmentOperator::AssignBitwiseOr + | AssignmentOperator::AssignBitwiseXor => { + if lhs_type.ne(&Type::Int) || rhs_type.ne(&Type::Int) { + return Err(SemanticError::IncompatibleTypesAssign( + name.clone(), + self.expression().clone(), + )); + } + } + } + Ok(()) + } + + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/binary_operation_tree.rs b/src/semantic/ast/binary_operation_tree.rs new file mode 100644 index 0000000..858dee7 --- /dev/null +++ b/src/semantic/ast/binary_operation_tree.rs @@ -0,0 +1,85 @@ +use crate::{ + lexer::operator::BinaryOperator, + parser::{ast::binary_operation_tree::BinaryOperationTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for BinaryOperationTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self.operator() { + BinaryOperator::LogicalOr | BinaryOperator::LogicalAnd => { + if self.lhs().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::IncompatibleTypeOperation( + self.operator().clone(), + self.lhs().clone(), + )); + } else if self.rhs().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::IncompatibleTypeOperation( + self.operator().clone(), + self.rhs().clone(), + )); + } + } + BinaryOperator::Minus + | BinaryOperator::ShiftRight + | BinaryOperator::ShiftLeft + | BinaryOperator::BitwiseXor + | BinaryOperator::BitwiseAnd + | BinaryOperator::BitwiseOr + | BinaryOperator::Plus + | BinaryOperator::Mul + | BinaryOperator::Mod + | BinaryOperator::Div => { + if self.lhs().r#type(state)?.ne(&Type::Int) { + return Err(SemanticError::IncompatibleTypeOperation( + self.operator().clone(), + self.lhs().clone(), + )); + } else if self.rhs().r#type(state)?.ne(&Type::Int) { + return Err(SemanticError::IncompatibleTypeOperation( + self.operator().clone(), + self.rhs().clone(), + )); + } + } + BinaryOperator::Lower + | BinaryOperator::LowerEquals + | BinaryOperator::Equals + | BinaryOperator::NotEquals + | BinaryOperator::Higher + | BinaryOperator::HigherEquals => { + let lhs_type = self.lhs().r#type(state)?; + let rhs_type = self.rhs().r#type(state)?; + if lhs_type.ne(&rhs_type) { + return Err(SemanticError::IncompatibleTypeComparison( + self.lhs().clone(), + self.rhs().clone(), + )); + } + } + } + self.lhs().analyze(state)?; + self.rhs().analyze(state) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + match self.operator() { + BinaryOperator::Mul + | BinaryOperator::Div + | BinaryOperator::Plus + | BinaryOperator::Mod + | BinaryOperator::ShiftLeft + | BinaryOperator::ShiftRight + | BinaryOperator::Minus => Ok(Type::Int), + BinaryOperator::Lower + | BinaryOperator::LowerEquals + | BinaryOperator::Equals + | BinaryOperator::NotEquals + | BinaryOperator::HigherEquals + | BinaryOperator::Higher => Ok(Type::Bool), + BinaryOperator::BitwiseOr | BinaryOperator::BitwiseAnd | BinaryOperator::BitwiseXor => { + Ok(Type::Int) + } + BinaryOperator::LogicalOr | BinaryOperator::LogicalAnd => Ok(Type::Bool), + } + } +} diff --git a/src/semantic/ast/block_tree.rs b/src/semantic/ast/block_tree.rs new file mode 100644 index 0000000..554efbb --- /dev/null +++ b/src/semantic/ast/block_tree.rs @@ -0,0 +1,35 @@ +use tracing::trace; + +use crate::{ + parser::{ast::block_tree::BlockTree, symbols::Name, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus}, +}; + +impl SemanticAnalysis for BlockTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + trace!("Running semantic analyze on block"); + let mut old_namespace = state.namespace.clone(); + for statement in self.statements() { + statement.analyze(state)?; + } + trace!("Namespace in block: {:?}", state.namespace); + for initialized_variable in state + .namespace + .iter() + .filter(|v| old_namespace.contains_key(v.0)) + .filter(|v| v.1.declaration().eq(&DeclarationStatus::Initialized)) + .map(|v| v.0) + .collect::>() + { + old_namespace + .get_mut(initialized_variable) + .unwrap() + .set_initialized(); + } + state.namespace = old_namespace; + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/break_tree.rs b/src/semantic/ast/break_tree.rs new file mode 100644 index 0000000..2d9ba78 --- /dev/null +++ b/src/semantic/ast/break_tree.rs @@ -0,0 +1,20 @@ +use crate::{ + parser::{ + ast::{break_tree::BreakTree, Tree}, + types::Type, + }, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for BreakTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + if !state.loop_active() { + return Err(SemanticError::BreakOutsideLoop(self.span())); + } + state.set_unreachable(); + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/call_tree.rs b/src/semantic/ast/call_tree.rs new file mode 100644 index 0000000..6c80d42 --- /dev/null +++ b/src/semantic/ast/call_tree.rs @@ -0,0 +1,14 @@ +use crate::{ + parser::{ast::call_tree::CallTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for CallTree { + fn analyze(&self, _state: &mut AnalysisState) -> Result<(), SemanticError> { + todo!("Function must be called with all parameters, they must have the correct type"); + } + + fn r#type(&self, _state: &mut AnalysisState) -> Result { + todo!("How to get return type of calling function? Analysis State?") + } +} diff --git a/src/semantic/ast/continue_tree.rs b/src/semantic/ast/continue_tree.rs new file mode 100644 index 0000000..4641a21 --- /dev/null +++ b/src/semantic/ast/continue_tree.rs @@ -0,0 +1,20 @@ +use crate::{ + parser::{ + ast::{continue_tree::ContinueTree, Tree}, + types::Type, + }, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for ContinueTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + if !state.loop_active() { + return Err(SemanticError::ContinueOutsideLoop(self.span())); + } + state.set_unreachable(); + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/declaration_tree.rs b/src/semantic/ast/declaration_tree.rs new file mode 100644 index 0000000..6ceecaa --- /dev/null +++ b/src/semantic/ast/declaration_tree.rs @@ -0,0 +1,50 @@ +use tracing::trace; + +use crate::{ + parser::{ast::declaration_tree::DeclarationTree, types::Type}, + semantic::{ + ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus, + VariableStatus, + }, +}; + +impl SemanticAnalysis for DeclarationTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + self.type_tree().analyze(state)?; + self.name_tree().analyze(state)?; + let variable_type = self.type_tree().r#type(state)?; + let variable_state = if self.initializer_tree().is_some() { + VariableStatus::new(variable_type.clone(), DeclarationStatus::Initialized) + } else { + VariableStatus::new(variable_type.clone(), DeclarationStatus::Declared) + }; + if let Some(present_initializer) = self.initializer_tree() { + if present_initializer.r#type(state)?.ne(&variable_type) { + trace!("Initializer is {:?}", present_initializer.r#type(state)?); + trace!("Variable should be {:?}", variable_type); + return Err(SemanticError::IncompatibleTypesAssign( + self.name_tree().clone(), + present_initializer.clone(), + )); + } + present_initializer.analyze(state)?; + }; + let variable_status = state.namespace.get(&self.name_tree().name()); + if variable_status.is_some() { + return Err(SemanticError::RedeclaredVariable(self.name_tree().clone())); + } + state + .namespace + .insert(self.name_tree().name().clone(), variable_state); + trace!( + "Variable {:?} is now declared as type {:?}", + self.name_tree().name().as_string(), + variable_type + ); + Ok(()) + } + + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/expression_tree.rs b/src/semantic/ast/expression_tree.rs new file mode 100644 index 0000000..446fb1c --- /dev/null +++ b/src/semantic/ast/expression_tree.rs @@ -0,0 +1,28 @@ +use crate::{ + parser::{ast::expression_tree::ExpressionTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for ExpressionTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self { + ExpressionTree::BooleanLiteralTree(tree) => tree.analyze(state), + ExpressionTree::IntegerLiteralTree(tree) => tree.analyze(state), + ExpressionTree::UnaryOperationTree(tree) => tree.analyze(state), + ExpressionTree::BinaryOperationTree(tree) => tree.analyze(state), + ExpressionTree::TernaryOperationTree(tree) => tree.analyze(state), + ExpressionTree::IdentifierExpressionTree(tree) => tree.analyze(state), + } + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + match self { + ExpressionTree::BooleanLiteralTree(tree) => tree.r#type(state), + ExpressionTree::IntegerLiteralTree(tree) => tree.r#type(state), + ExpressionTree::UnaryOperationTree(tree) => tree.r#type(state), + ExpressionTree::BinaryOperationTree(tree) => tree.r#type(state), + ExpressionTree::TernaryOperationTree(tree) => tree.r#type(state), + ExpressionTree::IdentifierExpressionTree(tree) => tree.r#type(state), + } + } +} diff --git a/src/semantic/ast/for_tree.rs b/src/semantic/ast/for_tree.rs new file mode 100644 index 0000000..65a6c9d --- /dev/null +++ b/src/semantic/ast/for_tree.rs @@ -0,0 +1,60 @@ +use tracing::trace; + +use crate::{ + parser::{ast::for_tree::ForTree, symbols::Name, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus}, +}; + +impl SemanticAnalysis for ForTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + trace!("Running semantic analysis on {:?}", self); + let reachability = state.is_reachable(); + let mut old_namespace = state.namespace.clone(); + let returning_state = state.return_state.clone(); + if let Some(initializer_expression) = self.initializer() { + initializer_expression.analyze(state)?; + for initialized_variable in state + .namespace + .iter() + .filter(|v| old_namespace.contains_key(v.0)) + .filter(|v| v.1.declaration().eq(&DeclarationStatus::Initialized)) + .map(|v| v.0) + .collect::>() + { + old_namespace + .get_mut(initialized_variable) + .unwrap() + .set_initialized(); + } + } + self.condition().analyze(state)?; + if self.condition().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::ConditionMustBeBoolean( + self.condition().clone(), + )); + } + state.enter_loop(); + self.statement().analyze(state)?; + state.return_state = returning_state; + state.exit_loop(); + + if let Some(updater_expression) = self.advancement() { + trace!("Analysing advancement of for loop"); + let names = state.namespace.iter().map(|v| v.0).len(); + updater_expression.analyze(state)?; + let additional_names = state.namespace.iter().map(|v| v.0).len(); + if names != additional_names { + return Err(SemanticError::ForAdvancementDefinesVariable); + } + } + state.namespace = old_namespace; + if reachability { + state.set_reachable(); + } + Ok(()) + } + + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/function_parameter_tree.rs b/src/semantic/ast/function_parameter_tree.rs new file mode 100644 index 0000000..4c5dfb2 --- /dev/null +++ b/src/semantic/ast/function_parameter_tree.rs @@ -0,0 +1,13 @@ +use crate::{ + parser::{ast::function_parameter_tree::FunctionParameterTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for FunctionParameterTree { + fn analyze(&self, _state: &mut AnalysisState) -> Result<(), SemanticError> { + unimplemented!() + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/function_tree.rs b/src/semantic/ast/function_tree.rs new file mode 100644 index 0000000..b7d0f58 --- /dev/null +++ b/src/semantic/ast/function_tree.rs @@ -0,0 +1,29 @@ +use tracing::trace; + +use crate::{ + parser::{ast::function_tree::FunctionTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState, ReturnState}, +}; + +impl SemanticAnalysis for FunctionTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + trace!("Running semantic analysis on function"); + self.return_type().analyze(state)?; + state.set_return_type(self.return_type().type_tree().clone()); + self.name_tree().analyze(state)?; + self.body().analyze(state)?; + if state.return_state.eq(&ReturnState::NotReturing) { + return Err(SemanticError::FunctionNotReturning(self.body().clone())); + } + if self.name_tree().name().as_string() == "main" { + if self.return_type().type_tree().ne(&Type::Int) { + return Err(SemanticError::MainMustReturnInt); + } + } + state.return_state = ReturnState::NotReturing; + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/identifier_tree.rs b/src/semantic/ast/identifier_tree.rs new file mode 100644 index 0000000..003ab11 --- /dev/null +++ b/src/semantic/ast/identifier_tree.rs @@ -0,0 +1,40 @@ +use tracing::trace; + +use crate::{ + parser::{ast::identifier_tree::IdentifierExpressionTree, types::Type}, + semantic::{ + ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus, ReturnState, + }, +}; + +impl SemanticAnalysis for IdentifierExpressionTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + trace!("Analyzing identifier with state: {:?}", state); + self.name().analyze(state)?; + state + .namespace + .get(self.name().name()) + .ok_or(SemanticError::UndefinedVariable(self.name().clone()))?; + + if state + .namespace + .get(&self.name().name()) + .unwrap() + .declaration() + .eq(&DeclarationStatus::Declared) + && state.return_state.ne(&ReturnState::Returning) + && state.is_reachable() + { + return Err(SemanticError::UninitializedVariable(self.name().clone())); + }; + Ok(()) + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + state + .namespace + .get(self.name().name()) + .map(|v| v.type_status().clone()) + .ok_or(SemanticError::UndefinedVariable(self.name().clone())) + } +} diff --git a/src/semantic/ast/if_tree.rs b/src/semantic/ast/if_tree.rs new file mode 100644 index 0000000..d1a21b0 --- /dev/null +++ b/src/semantic/ast/if_tree.rs @@ -0,0 +1,88 @@ +use tracing::trace; + +use crate::{ + parser::{ast::if_tree::IfTree, types::Type}, + semantic::{ + ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus, ReturnState, + }, +}; + +impl SemanticAnalysis for IfTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + let returning_state = state.return_state.clone(); + let old_namespace = state.namespace.clone(); + self.condition().analyze(state)?; + if self.condition().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::ConditionMustBeBoolean( + self.condition().clone(), + )); + } + state.return_state = ReturnState::NotReturing; + let old_reachability = state.is_reachable(); + self.if_statement().analyze(state)?; + let true_namespace = state.namespace.clone(); + let true_reachability = state.is_reachable(); + state.set_reachable(); + state.namespace = old_namespace.clone(); + let if_return_state = state.return_state.clone(); + if let Some(other_expression) = self.else_statement() { + state.return_state = ReturnState::NotReturing; + other_expression.analyze(state)?; + let else_return_state = state.return_state.clone(); + if state.return_state.eq(&ReturnState::Returning) + && if_return_state.eq(&ReturnState::Returning) + { + state.return_state = ReturnState::Returning; + } else { + state.return_state = returning_state; + } + let false_namespace = state.namespace.clone(); + state.namespace = old_namespace; + trace!("True: {:?}, False:{:?}", true_namespace, false_namespace); + for (initialized_variable, _) in true_namespace + .iter() + .filter(|(_, v)| v.declaration().eq(&DeclarationStatus::Initialized)) + { + if false_namespace.contains_key(initialized_variable) + && state.namespace.contains_key(initialized_variable) + && false_namespace + .get(initialized_variable) + .unwrap() + .declaration() + .eq(&DeclarationStatus::Initialized) + { + state + .namespace + .get_mut(initialized_variable) + .unwrap() + .set_initialized(); + } + if else_return_state.eq(&ReturnState::Returning) { + if let Some(variable) = state.namespace.get_mut(initialized_variable) { + variable.set_initialized(); + } + } + } + if if_return_state.eq(&ReturnState::Returning) { + for (initialized_variable, _) in false_namespace { + state + .namespace + .get_mut(&initialized_variable) + .unwrap() + .set_initialized(); + } + } + if !old_reachability || (!true_reachability && !state.is_reachable()) { + state.set_unreachable(); + } else { + state.set_reachable(); + } + } else { + state.return_state = returning_state; + } + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/literal_tree.rs b/src/semantic/ast/literal_tree.rs new file mode 100644 index 0000000..670a217 --- /dev/null +++ b/src/semantic/ast/literal_tree.rs @@ -0,0 +1,36 @@ +use crate::{ + parser::{ + ast::literal_tree::{BooleanLiteralTree, IntegerLiteralTree}, + types::Type, + }, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, + util::int_parsing::parse_int, +}; + +impl SemanticAnalysis for IntegerLiteralTree { + fn analyze( + &self, + _: &mut crate::semantic::AnalysisState, + ) -> Result<(), crate::semantic::error::SemanticError> { + if self.base() != 16 && self.base() != 10 { + return Err(SemanticError::LiteralInvalidBase); + } + parse_int(self.value().to_owned(), self.base() as u64) + .ok_or(SemanticError::LiteralInvalid)?; + Ok(()) + } + + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Int) + } +} + +impl SemanticAnalysis for BooleanLiteralTree { + fn analyze(&self, _: &mut crate::semantic::AnalysisState) -> Result<(), SemanticError> { + Ok(()) + } + + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Bool) + } +} diff --git a/src/semantic/ast/lvalue_tree.rs b/src/semantic/ast/lvalue_tree.rs new file mode 100644 index 0000000..6ac0881 --- /dev/null +++ b/src/semantic/ast/lvalue_tree.rs @@ -0,0 +1,18 @@ +use crate::{ + parser::{ast::lvalue_tree::LValueTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for LValueTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + self.identifier().analyze(state) + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + state + .namespace + .get(self.identifier().name()) + .map(|v| v.type_status().clone()) + .ok_or(SemanticError::UndefinedVariable(self.identifier().clone())) + } +} diff --git a/src/semantic/ast/mod.rs b/src/semantic/ast/mod.rs new file mode 100644 index 0000000..922b058 --- /dev/null +++ b/src/semantic/ast/mod.rs @@ -0,0 +1,33 @@ +use crate::{ + parser::types::Type, + semantic::{error::SemanticError, AnalysisState}, +}; + +pub mod assignment_tree; +pub mod binary_operation_tree; +pub mod block_tree; +pub mod break_tree; +pub mod call_tree; +pub mod continue_tree; +pub mod declaration_tree; +pub mod expression_tree; +pub mod for_tree; +pub mod function_parameter_tree; +pub mod function_tree; +pub mod identifier_tree; +pub mod if_tree; +pub mod literal_tree; +pub mod lvalue_tree; +pub mod name_tree; +pub mod program_tree; +pub mod return_tree; +pub mod statement_tree; +pub mod ternary_operation_tree; +pub mod type_tree; +pub mod unary_operation_tree; +pub mod while_tree; + +pub trait SemanticAnalysis { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError>; + fn r#type(&self, state: &mut AnalysisState) -> Result; +} diff --git a/src/semantic/ast/name_tree.rs b/src/semantic/ast/name_tree.rs new file mode 100644 index 0000000..291291c --- /dev/null +++ b/src/semantic/ast/name_tree.rs @@ -0,0 +1,13 @@ +use crate::{ + parser::{ast::name_tree::NameTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for NameTree { + fn analyze(&self, _: &mut AnalysisState) -> Result<(), SemanticError> { + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/program_tree.rs b/src/semantic/ast/program_tree.rs new file mode 100644 index 0000000..7cf370d --- /dev/null +++ b/src/semantic/ast/program_tree.rs @@ -0,0 +1,19 @@ +use tracing::trace; + +use crate::{ + parser::{ast::program_tree::ProgramTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for ProgramTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + trace!("Running semantic analysis on program"); + for function in self.functions() { + function.analyze(state)?; + } + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/return_tree.rs b/src/semantic/ast/return_tree.rs new file mode 100644 index 0000000..5569313 --- /dev/null +++ b/src/semantic/ast/return_tree.rs @@ -0,0 +1,20 @@ +use crate::{ + parser::{ast::return_tree::ReturnTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState, ReturnState}, +}; + +impl SemanticAnalysis for ReturnTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + self.expression().analyze(state)?; + if self.expression().r#type(state)?.ne(state.return_type()) { + return Err(SemanticError::IncompatibleReturnType( + self.expression().clone(), + )); + } + state.return_state = ReturnState::Returning; + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/ast/statement_tree.rs b/src/semantic/ast/statement_tree.rs new file mode 100644 index 0000000..c4b317d --- /dev/null +++ b/src/semantic/ast/statement_tree.rs @@ -0,0 +1,66 @@ +use crate::{ + parser::{ + ast::statement_tree::{ControlStatementTree, SimpleStatementTree, StatementTree}, + types::Type, + }, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for StatementTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self { + StatementTree::SimpleStatement(tree) => tree.analyze(state), + StatementTree::ControlStatement(tree) => tree.analyze(state), + StatementTree::BlockStatement(tree) => tree.analyze(state), + } + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + match self { + StatementTree::SimpleStatement(tree) => tree.r#type(state), + StatementTree::ControlStatement(tree) => tree.r#type(state), + StatementTree::BlockStatement(tree) => tree.r#type(state), + } + } +} + +impl SemanticAnalysis for SimpleStatementTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self { + SimpleStatementTree::AssignmentTree(tree) => tree.analyze(state), + SimpleStatementTree::DeclerationTree(tree) => tree.analyze(state), + SimpleStatementTree::CallTree(tree) => tree.analyze(state), + } + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + match self { + SimpleStatementTree::AssignmentTree(tree) => tree.r#type(state), + SimpleStatementTree::DeclerationTree(tree) => tree.r#type(state), + SimpleStatementTree::CallTree(tree) => tree.r#type(state), + } + } +} + +impl SemanticAnalysis for ControlStatementTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self { + ControlStatementTree::IfTree(tree) => tree.analyze(state), + ControlStatementTree::ForTree(tree) => tree.analyze(state), + ControlStatementTree::ReturnTree(tree) => tree.analyze(state), + ControlStatementTree::WhileTree(tree) => tree.analyze(state), + ControlStatementTree::BreakTree(tree) => tree.analyze(state), + ControlStatementTree::ContinueTree(tree) => tree.analyze(state), + } + } + fn r#type(&self, state: &mut AnalysisState) -> Result { + match self { + ControlStatementTree::IfTree(tree) => tree.r#type(state), + ControlStatementTree::ForTree(tree) => tree.r#type(state), + ControlStatementTree::ReturnTree(tree) => tree.r#type(state), + ControlStatementTree::WhileTree(tree) => tree.r#type(state), + ControlStatementTree::BreakTree(tree) => tree.r#type(state), + ControlStatementTree::ContinueTree(tree) => tree.r#type(state), + } + } +} diff --git a/src/semantic/ast/ternary_operation_tree.rs b/src/semantic/ast/ternary_operation_tree.rs new file mode 100644 index 0000000..ce89e09 --- /dev/null +++ b/src/semantic/ast/ternary_operation_tree.rs @@ -0,0 +1,28 @@ +use crate::{ + parser::{ast::ternary_operation_tree::TernaryOperationTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for TernaryOperationTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + self.condition().analyze(state)?; + if self.condition().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::ConditionMustBeBoolean( + self.condition().clone(), + )); + } + let true_type = self.true_expression().r#type(state)?; + let false_type = self.false_expression().r#type(state)?; + if true_type.ne(&false_type) { + return Err(SemanticError::IncompatibleTypeTernary( + self.true_expression().clone(), + self.false_expression().clone(), + )); + } + self.true_expression().analyze(state)?; + self.false_expression().analyze(state) + } + fn r#type(&self, state: &mut AnalysisState) -> Result { + self.true_expression().r#type(state) + } +} diff --git a/src/semantic/ast/type_tree.rs b/src/semantic/ast/type_tree.rs new file mode 100644 index 0000000..cf5b5bc --- /dev/null +++ b/src/semantic/ast/type_tree.rs @@ -0,0 +1,13 @@ +use crate::{ + parser::{ast::type_tree::TypeTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for TypeTree { + fn analyze(&self, _: &mut AnalysisState) -> Result<(), SemanticError> { + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(self.type_tree().clone()) + } +} diff --git a/src/semantic/ast/unary_operation_tree.rs b/src/semantic/ast/unary_operation_tree.rs new file mode 100644 index 0000000..92ca116 --- /dev/null +++ b/src/semantic/ast/unary_operation_tree.rs @@ -0,0 +1,36 @@ +use crate::{ + lexer::operator::UnaryOperator, + parser::{ast::unary_operation_tree::UnaryOperationTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for UnaryOperationTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + match self.operator() { + UnaryOperator::LogicalNot => { + if self.expression().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::IncompatibleTypeUnary( + self.operator().clone(), + self.expression().clone(), + )); + } + } + UnaryOperator::BitwiseNot | UnaryOperator::Minus => { + if self.expression().r#type(state)?.ne(&Type::Int) { + return Err(SemanticError::IncompatibleTypeUnary( + self.operator().clone(), + self.expression().clone(), + )); + } + } + } + self.expression().analyze(state) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + match self.operator() { + UnaryOperator::Minus => Ok(Type::Int), + UnaryOperator::LogicalNot => Ok(Type::Bool), + UnaryOperator::BitwiseNot => Ok(Type::Int), + } + } +} diff --git a/src/semantic/ast/while_tree.rs b/src/semantic/ast/while_tree.rs new file mode 100644 index 0000000..b5a4e09 --- /dev/null +++ b/src/semantic/ast/while_tree.rs @@ -0,0 +1,30 @@ +use crate::{ + parser::{ast::while_tree::WhileTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for WhileTree { + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + let reachability = state.is_reachable(); + let returning_state = state.return_state.clone(); + let old_namespace = state.namespace.clone(); + self.condition().analyze(state)?; + if self.condition().r#type(state)?.ne(&Type::Bool) { + return Err(SemanticError::ConditionMustBeBoolean( + self.condition().clone(), + )); + } + state.enter_loop(); + self.statement().analyze(state)?; + state.return_state = returning_state; + state.namespace = old_namespace; + state.exit_loop(); + if reachability { + state.set_reachable(); + } + Ok(()) + } + fn r#type(&self, _: &mut AnalysisState) -> Result { + Ok(Type::Unit) + } +} diff --git a/src/semantic/error.rs b/src/semantic/error.rs new file mode 100644 index 0000000..5726658 --- /dev/null +++ b/src/semantic/error.rs @@ -0,0 +1,111 @@ +use std::fmt::Display; + +use crate::{ + lexer::operator::{BinaryOperator, UnaryOperator}, + parser::ast::{ + block_tree::BlockTree, expression_tree::ExpressionTree, name_tree::NameTree, Tree, + }, + util::span::Span, +}; + +pub enum SemanticError { + LiteralInvalidBase, + LiteralInvalid, + UninitializedVariable(NameTree), + UndefinedVariable(NameTree), + RedeclaredVariable(NameTree), + IncompatibleTypesAssign(NameTree, ExpressionTree), + IncompatibleTypeOperation(BinaryOperator, ExpressionTree), + IncompatibleTypeComparison(ExpressionTree, ExpressionTree), + IncompatibleTypeTernary(ExpressionTree, ExpressionTree), + IncompatibleTypeUnary(UnaryOperator, ExpressionTree), + ContinueOutsideLoop(Span), + BreakOutsideLoop(Span), + ConditionMustBeBoolean(ExpressionTree), + FunctionNotReturning(BlockTree), + ForAdvancementDefinesVariable, + MainMustReturnInt, + IncompatibleReturnType(ExpressionTree), +} + +impl Display for SemanticError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + SemanticError::LiteralInvalidBase => writeln!(f, "Invalid Literal Base"), + SemanticError::LiteralInvalid => writeln!(f, "Invalid Literal"), + SemanticError::UndefinedVariable(variable) => writeln!( + f, + "Undefined variable {} at {}", + variable.name().as_string(), + variable.span() + ), + SemanticError::UninitializedVariable(variable) => writeln!( + f, + "Uninitialized variable {} at {}", + variable.name().as_string(), + variable.span() + ), + SemanticError::RedeclaredVariable(variable) => writeln!( + f, + "Variable {} redeclared at {}", + variable.name().as_string(), + variable.span() + ), + SemanticError::IncompatibleTypesAssign(variable, expression) => writeln!( + f, + "Expression at {} cannot assign to variable {}", + expression.span(), + variable.name().as_string() + ), + SemanticError::IncompatibleTypeOperation(operator, tree) => writeln!( + f, + "Expression at {} cannot be used with operator {}", + tree.span(), + operator + ), + SemanticError::IncompatibleTypeComparison(left, right) => writeln!( + f, + "The arguments at {} and {} cannot be compared", + left.span(), + right.span() + ), + SemanticError::IncompatibleTypeTernary(true_expression, false_expression) => { + writeln!( + f, + "Inconsistent types between ternary arguments at {} and {}", + true_expression.span(), + false_expression.span() + ) + } + SemanticError::IncompatibleTypeUnary(operator, tree) => writeln!( + f, + "Expression at {} cannot be used with operator {}", + tree.span(), + operator + ), + SemanticError::ContinueOutsideLoop(span) => { + writeln!(f, "Continue at {} cannot exist outside a loop", span) + } + SemanticError::BreakOutsideLoop(span) => { + writeln!(f, "Break at {} cannot exist outside a loop", span) + } + SemanticError::ConditionMustBeBoolean(expression) => writeln!( + f, + "The condition at {} must be a boolean", + expression.span() + ), + SemanticError::FunctionNotReturning(block) => { + writeln!(f, "Function at {} is not returning!", block.span()) + } + SemanticError::ForAdvancementDefinesVariable => { + writeln!(f, "For advancement block cannot define a variable") + } + SemanticError::MainMustReturnInt => { + writeln!(f, "Main function must return int") + } + SemanticError::IncompatibleReturnType(tree) => { + writeln!(f, "Expression at {} returns wrong type", tree.span()) + } + } + } +} diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index a027f8c..271e3f1 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,18 +1,17 @@ use std::collections::HashMap; -use tracing::trace; +use crate::parser::{symbols::Name, types::Type}; -use crate::{ - lexer::token::{OperatorType, Token}, - parser::{ast::Tree, symbols::Name, types::Type}, - util::int_parsing::parse_int, -}; +pub mod ast; +pub mod error; #[derive(Clone, Debug)] pub struct AnalysisState { return_state: ReturnState, namespace: HashMap, active_loops: usize, + reachable: bool, + return_type: Type, } impl Default for AnalysisState { @@ -21,6 +20,8 @@ impl Default for AnalysisState { return_state: ReturnState::NotReturing, namespace: HashMap::new(), active_loops: 0, + reachable: true, + return_type: Type::Unit, } } } @@ -37,6 +38,26 @@ impl AnalysisState { pub fn loop_active(&self) -> bool { self.active_loops > 0 } + + pub fn is_reachable(&self) -> bool { + self.reachable + } + + pub fn set_reachable(&mut self) { + self.reachable = true; + } + + pub fn set_unreachable(&mut self) { + self.reachable = false; + } + + pub fn return_type(&self) -> &Type { + &self.return_type + } + + pub fn set_return_type(&mut self, return_type: Type) { + self.return_type = return_type; + } } #[derive(PartialEq, Clone, Debug)] @@ -77,466 +98,3 @@ pub enum DeclarationStatus { Declared, Initialized, } - -#[must_use] -pub fn analyze(tree: Box, state: &mut AnalysisState) -> Result<(), String> { - trace!("Analysing: {:?}", tree); - trace!("State: {:?}", state); - match *tree { - Tree::Literal(value, base, _) => { - if base != 16 && base != 10 { - return Err("Invalid base!".to_string()); - } - parse_int(value, base).ok_or("Not valid integer literal!".to_string())?; - Ok(()) - } - Tree::Return(sub, _) => { - analyze(sub.clone(), state)?; - if get_variable_type(sub, state) - .ok_or("Variable not defined!")? - .ne(&Type::Int) - { - return Err("Function must return an int".to_string()); - } - state.return_state = ReturnState::Returning; - Ok(()) - } - Tree::Function(return_type, name, body) => { - analyze(return_type, state)?; - analyze(name, state)?; - analyze(body, state)?; - if state.return_state.eq(&ReturnState::NotReturing) { - return Err("Function not returing!".to_string()); - } - state.return_state = ReturnState::NotReturing; - Ok(()) - } - Tree::Assignment(lvalue, operator, expression) => { - analyze(lvalue.clone(), state)?; - analyze(expression.clone(), state)?; - if let Tree::LValueIdentifier(identifier) = *lvalue { - if let Tree::Name(name, _) = *identifier { - if let Token::Operator(_, operator_type) = operator { - if let OperatorType::Assign = operator_type { - trace!("Variable {:?} is now defined!", name); - state - .namespace - .get(&name) - .ok_or(format!("Undeclared variable {}!", name.as_string()))?; - state.namespace.get_mut(&name).unwrap().set_initialized(); - let expression_type = get_variable_type(expression.clone(), state) - .ok_or("Variable undefined!")?; - if state - .namespace - .get(&name) - .unwrap() - .type_status() - .ne(&expression_type) - { - return Err( - "Variable must be of the same type as expression!".to_string() - ); - } - {} - } else if !state.namespace.contains_key(&name) { - return Err(format!("Undecleared variable {} used!", name.as_string())); - } else if state - .namespace - .get(&name) - .unwrap() - .declaration() - .eq(&DeclarationStatus::Declared) - { - return Err("Decleared variable without value used!".to_string()); - } - } - } - }; - Ok(()) - } - Tree::Declaration(variable_type, name, initializer) => { - analyze(variable_type.clone(), state)?; - analyze(name.clone(), state)?; - let variable_type = - get_variable_type(variable_type, state).ok_or("Variable undefined!")?; - let variable_state = if initializer.is_some() { - VariableStatus::new(variable_type.clone(), DeclarationStatus::Initialized) - } else { - VariableStatus::new(variable_type.clone(), DeclarationStatus::Declared) - }; - if let Some(present_initializer) = initializer { - if get_variable_type(present_initializer.clone(), state) - .ok_or("Variable undefined!")? - .ne(&variable_type) - { - trace!( - "Initializer is {:?}", - get_variable_type(present_initializer.clone(), state) - ); - trace!("Variable should be {:?}", variable_type); - return Err("initializer must be of same type as variable".to_string()); - } - analyze(present_initializer, state)?; - }; - if let Tree::Name(identifier, _) = *name { - let variable_status = state.namespace.get(&identifier); - if variable_status.is_some() { - return Err( - "Reinitializing or redeclaring variables are not allowed!".to_string() - ); - } - state.namespace.insert(identifier.clone(), variable_state); - } - Ok(()) - } - Tree::IdentifierExpression(identifier) => { - analyze(identifier.clone(), state)?; - if let Tree::Name(name, _) = *identifier { - state.namespace.get(&name).ok_or(format!( - "Undeclared variable {} used in expression!", - name.as_string() - ))?; - if state - .namespace - .get(&name) - .unwrap() - .declaration() - .eq(&DeclarationStatus::Declared) - && state.return_state.ne(&ReturnState::Returning) - { - return Err(format!( - "Uninitialized variable {} used in expression!", - name.as_string() - )); - } - }; - Ok(()) - } - Tree::Name(_, _) => Ok(()), - Tree::BoolLiteral(_, _) => Ok(()), - Tree::Continue(_) => { - if !state.loop_active() { - return Err("Continue can only be used in a loop".to_string()); - } - Ok(()) - } - Tree::Break(_) => { - if !state.loop_active() { - return Err("Break can only be used in a loop".to_string()); - } - Ok(()) - } - Tree::BinaryOperation(lhs, rhs, operator_type) => { - match operator_type { - OperatorType::LogicalOr | OperatorType::LogicalAnd => { - if get_variable_type(lhs.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - || get_variable_type(rhs.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Expression must be a boolean".to_string()); - } - } - OperatorType::Minus - | OperatorType::ShiftRight - | OperatorType::ShiftLeft - | OperatorType::BitwiseXor - | OperatorType::BitwiseAnd - | OperatorType::BitwiseOr - | OperatorType::Plus - | OperatorType::Mul - | OperatorType::Mod - | OperatorType::Div => { - if get_variable_type(lhs.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Int) - || get_variable_type(rhs.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Int) - { - return Err("Expression must be a integer".to_string()); - } - } - OperatorType::Lower - | OperatorType::LowerEquals - | OperatorType::Equals - | OperatorType::NotEquals - | OperatorType::Higher - | OperatorType::HigherEquals => { - let lhs_type = - get_variable_type(lhs.clone(), state).ok_or("Variable undefined!")?; - let rhs_type = - get_variable_type(rhs.clone(), state).ok_or("Variable undefined!")?; - if lhs_type.ne(&rhs_type) { - return Err("Comparison operators must have equal types".to_string()); - } - } - OperatorType::Assign - | OperatorType::AssignMul - | OperatorType::AssignDiv - | OperatorType::AssignMod - | OperatorType::AssignMinus - | OperatorType::AssignShiftLeft - | OperatorType::AssignBitwiseOr - | OperatorType::AssignBitwiseNot - | OperatorType::AssignBitwiseAnd - | OperatorType::AssignBitwiseXor - | OperatorType::AssignShiftRight - | OperatorType::AssignPlus => { - let lhs_type = - get_variable_type(lhs.clone(), state).ok_or("Variable undefined!")?; - let rhs_type = - get_variable_type(rhs.clone(), state).ok_or("Variable undefined!")?; - if lhs_type.ne(&rhs_type) { - return Err("Comparison operators must have equal types".to_string()); - } - } - OperatorType::LogicalNot - | OperatorType::BitwiseNot - | OperatorType::TernaryColon - | OperatorType::TernaryQuestionMark => return Err("Invalid operator".to_string()), - } - analyze(lhs, state)?; - analyze(rhs, state) - } - Tree::Block(statements, _) => { - let mut old_namespace = state.namespace.clone(); - for statement in statements { - analyze(Box::new(statement.clone()), state)?; - } - for initialized_variable in state - .namespace - .iter() - .filter(|v| old_namespace.contains_key(v.0)) - .filter(|v| v.1.declaration().eq(&DeclarationStatus::Initialized)) - .map(|v| v.0) - .collect::>() - { - old_namespace - .get_mut(initialized_variable) - .unwrap() - .set_initialized(); - } - state.namespace = old_namespace; - Ok(()) - } - Tree::LValueIdentifier(name) => analyze(name, state), - Tree::UnaryOperation(expression, operator_type, _) => { - match operator_type { - OperatorType::LogicalNot => { - if get_variable_type(expression.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Expression must be a boolean".to_string()); - } - } - OperatorType::BitwiseNot | OperatorType::Minus => { - if get_variable_type(expression.clone(), state) - .ok_or("Variable undefined!")? - .ne(&Type::Int) - { - return Err("Expression must be a integer".to_string()); - } - } - _ => {} - } - analyze(expression, state) - } - Tree::Type(_, _) => Ok(()), - Tree::Program(statements) => { - for statement in statements { - analyze(Box::new(statement), state)?; - } - Ok(()) - } - Tree::TernaryOperation(statement, true_statement, false_statement) => { - analyze(statement.clone(), state)?; - if get_variable_type(statement, state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Condition must be a boolean".to_string()); - } - let true_type = - get_variable_type(true_statement.clone(), state).ok_or("Variable undefined!")?; - let false_type = - get_variable_type(false_statement.clone(), state).ok_or("Variable undefined!")?; - if true_type.ne(&false_type) { - return Err("Ternary operator types not equal".to_string()); - } - analyze(true_statement, state)?; - analyze(false_statement, state) - } - Tree::If(condition, expression, else_expression, _) => { - let returning_state = state.return_state.clone(); - let old_namespace = state.namespace.clone(); - analyze(condition.clone(), state)?; - if get_variable_type(condition, state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Condition must be a boolean".to_string()); - } - state.return_state = ReturnState::NotReturing; - analyze(expression, state)?; - let true_namespace = state.namespace.clone(); - state.namespace = old_namespace.clone(); - let if_return_state = state.return_state.clone(); - if let Some(other_expression) = else_expression { - state.return_state = ReturnState::NotReturing; - analyze(other_expression, state)?; - let else_return_state = state.return_state.clone(); - if state.return_state.eq(&ReturnState::Returning) - && if_return_state.eq(&ReturnState::Returning) - { - state.return_state = ReturnState::Returning; - } else { - state.return_state = returning_state; - } - let false_namespace = state.namespace.clone(); - state.namespace = old_namespace; - trace!("True: {:?}, False:{:?}", true_namespace, false_namespace); - for (initialized_variable, _) in true_namespace - .iter() - .filter(|(_, v)| v.declaration().eq(&DeclarationStatus::Initialized)) - { - if false_namespace.contains_key(initialized_variable) - && state.namespace.contains_key(initialized_variable) - && false_namespace - .get(initialized_variable) - .unwrap() - .declaration() - .eq(&DeclarationStatus::Initialized) - { - state - .namespace - .get_mut(initialized_variable) - .unwrap() - .set_initialized(); - } - if else_return_state.eq(&ReturnState::Returning) { - state - .namespace - .get_mut(initialized_variable) - .unwrap() - .set_initialized(); - } - } - if if_return_state.eq(&ReturnState::Returning) { - for (initialized_variable, _) in false_namespace { - state - .namespace - .get_mut(&initialized_variable) - .unwrap() - .set_initialized(); - } - } - } else { - state.return_state = returning_state; - } - Ok(()) - } - Tree::While(condition, expression, _) => { - let returning_state = state.return_state.clone(); - analyze(condition.clone(), state)?; - if get_variable_type(condition, state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Condition must be a boolean".to_string()); - } - state.enter_loop(); - analyze(expression, state)?; - state.return_state = returning_state; - state.exit_loop(); - Ok(()) - } - Tree::For(initializer, condition, updater, expression, _) => { - let mut old_namespace = state.namespace.clone(); - let returning_state = state.return_state.clone(); - if let Some(initializer_expression) = initializer { - analyze(initializer_expression, state)?; - for initialized_variable in state - .namespace - .iter() - .filter(|v| old_namespace.contains_key(v.0)) - .filter(|v| v.1.declaration().eq(&DeclarationStatus::Initialized)) - .map(|v| v.0) - .collect::>() - { - old_namespace - .get_mut(initialized_variable) - .unwrap() - .set_initialized(); - } - } - analyze(condition.clone(), state)?; - if get_variable_type(condition, state) - .ok_or("Variable undefined!")? - .ne(&Type::Bool) - { - return Err("Condition must be a boolean".to_string()); - } - state.enter_loop(); - analyze(expression, state)?; - state.return_state = returning_state; - state.exit_loop(); - - if let Some(updater_expression) = updater { - let names = state.namespace.iter().map(|v| v.0).len(); - analyze(updater_expression, state)?; - let additional_names = state.namespace.iter().map(|v| v.0).len(); - if names != additional_names { - return Err("Updater Expression cannot define variables".to_string()); - } - } - state.namespace = old_namespace; - Ok(()) - } - } -} - -fn get_variable_type(type_tree: Box, state: &mut AnalysisState) -> Option { - match *type_tree { - Tree::Type(variable_type, _) => Some(variable_type), - Tree::Literal(_, _, _) => Some(Type::Int), - Tree::BoolLiteral(_, _) => Some(Type::Bool), - Tree::BinaryOperation(_, _, operator_type) | Tree::UnaryOperation(_, operator_type, _) => { - match operator_type { - OperatorType::Mul - | OperatorType::Div - | OperatorType::Plus - | OperatorType::Mod - | OperatorType::ShiftLeft - | OperatorType::ShiftRight - | OperatorType::Minus => Some(Type::Int), - OperatorType::Lower - | OperatorType::LowerEquals - | OperatorType::Equals - | OperatorType::NotEquals - | OperatorType::HigherEquals - | OperatorType::Higher => Some(Type::Bool), - OperatorType::BitwiseOr - | OperatorType::BitwiseNot - | OperatorType::BitwiseAnd - | OperatorType::BitwiseXor => Some(Type::Int), - OperatorType::LogicalOr | OperatorType::LogicalNot | OperatorType::LogicalAnd => { - Some(Type::Bool) - } - _ => None, - } - } - Tree::IdentifierExpression(name) => { - if let Tree::Name(name, _) = *name { - Some(state.namespace.get(&name)?.type_status().clone()) - } else { - None - } - } - Tree::TernaryOperation(_, true_expression, _) => get_variable_type(true_expression, state), - _ => None, - } -} diff --git a/src/util/span.rs b/src/util/span.rs index 416e167..e56cc38 100644 --- a/src/util/span.rs +++ b/src/util/span.rs @@ -29,8 +29,8 @@ impl Span { self.end } - pub fn merge(self, later: Span) -> Span { - Span::new(self.start, later.end_owned()) + pub fn merge(&self, later: &Span) -> Span { + Span::new(self.start.clone(), later.end().clone()) } } From cf51d5e5478a246507868e34a45d16f511e4aa50 Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Tue, 24 Jun 2025 15:46:14 +0200 Subject: [PATCH 2/5] feat(semantic&parser): implement call and function with params --- src/ir/ast/call_tree.rs | 6 ++- src/ir/ast/expression_tree.rs | 1 + src/ir/ast/mod.rs | 1 + src/lexer/collection.rs | 4 ++ src/lexer/mod.rs | 1 + src/lexer/token.rs | 2 + src/parser/ast/block_tree.rs | 4 +- src/parser/ast/call_parameter_tree.rs | 38 +++++++++++++++ src/parser/ast/call_tree.rs | 53 +++++++++++++++++---- src/parser/ast/expression_tree.rs | 19 ++++++-- src/parser/ast/function_parameter_tree.rs | 32 ++++++++++++- src/parser/ast/function_tree.rs | 22 +++++++-- src/parser/ast/mod.rs | 1 + src/parser/ast/statement_tree.rs | 17 ++++--- src/semantic/ast/call_parameter_tree.rs | 14 ++++++ src/semantic/ast/call_tree.rs | 25 ++++++++-- src/semantic/ast/expression_tree.rs | 2 + src/semantic/ast/function_parameter_tree.rs | 16 +++++-- src/semantic/ast/function_tree.rs | 3 ++ src/semantic/ast/mod.rs | 1 + src/semantic/ast/program_tree.rs | 19 +++++++- src/semantic/error.rs | 17 ++++++- src/semantic/mod.rs | 40 +++++++++++++++- test.l3 | 7 +++ 24 files changed, 305 insertions(+), 40 deletions(-) create mode 100644 src/parser/ast/call_parameter_tree.rs create mode 100644 src/semantic/ast/call_parameter_tree.rs create mode 100644 test.l3 diff --git a/src/ir/ast/call_tree.rs b/src/ir/ast/call_tree.rs index 7da0e33..e12206a 100644 --- a/src/ir/ast/call_tree.rs +++ b/src/ir/ast/call_tree.rs @@ -6,7 +6,9 @@ use crate::{ use super::IRConstructor; impl ToIR for CallTree { - fn to_ir(&self, _constructor: &mut IRConstructor) -> Option { - unimplemented!() + fn to_ir(&self, constructor: &mut IRConstructor) -> Option { + //TODO: Unimplemented + let temp = constructor.create_constant_int(0); + Some(temp) } } diff --git a/src/ir/ast/expression_tree.rs b/src/ir/ast/expression_tree.rs index 1f5db08..8214328 100644 --- a/src/ir/ast/expression_tree.rs +++ b/src/ir/ast/expression_tree.rs @@ -11,6 +11,7 @@ impl ToIR for ExpressionTree { ExpressionTree::BooleanLiteralTree(tree) => tree.to_ir(constructor), ExpressionTree::IntegerLiteralTree(tree) => tree.to_ir(constructor), ExpressionTree::IdentifierExpressionTree(tree) => tree.to_ir(constructor), + ExpressionTree::CallTree(tree) => tree.to_ir(constructor), ExpressionTree::UnaryOperationTree(tree) => tree.to_ir(constructor), ExpressionTree::BinaryOperationTree(tree) => tree.to_ir(constructor), ExpressionTree::TernaryOperationTree(tree) => tree.to_ir(constructor), diff --git a/src/ir/ast/mod.rs b/src/ir/ast/mod.rs index 6e55f7f..010ebd2 100644 --- a/src/ir/ast/mod.rs +++ b/src/ir/ast/mod.rs @@ -174,6 +174,7 @@ impl IRConstructor { } ExpressionTree::UnaryOperationTree(_tree) => todo!(), ExpressionTree::TernaryOperationTree(_tree) => todo!(), + ExpressionTree::CallTree(_tree) => todo!(), } } diff --git a/src/lexer/collection.rs b/src/lexer/collection.rs index f020209..011676a 100644 --- a/src/lexer/collection.rs +++ b/src/lexer/collection.rs @@ -151,6 +151,10 @@ impl ParserTokens { self.tokens.front() } + pub fn peek_index(&self, index: usize) -> Result<&Token, ParseError> { + self.tokens.get(index).ok_or(ParseError::ReachedEnd) + } + pub fn push(&mut self, value: Token) { self.tokens.push_front(value); } diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index f1ca606..f790244 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -48,6 +48,7 @@ impl Lexer { '{' => self.seperator(SeperatorType::BraceOpen), '}' => self.seperator(SeperatorType::BraceClose), ';' => self.seperator(SeperatorType::Semicolon), + ',' => self.seperator(SeperatorType::Comma), '?' => Token::Operator(self.build_span(1), OperatorType::TernaryQuestionMark), ':' => Token::Operator(self.build_span(1), OperatorType::TernaryColon), '-' => self diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 4ea8a57..f4fa002 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -217,6 +217,7 @@ pub enum SeperatorType { BraceOpen, BraceClose, Semicolon, + Comma, } impl SeperatorType { @@ -227,6 +228,7 @@ impl SeperatorType { Self::BraceOpen => "{", Self::BraceClose => "}", Self::Semicolon => ";", + Self::Comma => ",", } } } diff --git a/src/parser/ast/block_tree.rs b/src/parser/ast/block_tree.rs index e4c027e..dbe2e58 100644 --- a/src/parser/ast/block_tree.rs +++ b/src/parser/ast/block_tree.rs @@ -56,10 +56,10 @@ impl BlockTree { impl Display for BlockTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{{")?; + writeln!(f, "{{")?; for statement in &self.statements { write!(f, "{}", statement)?; } - write!(f, "}}") + writeln!(f, "}}") } } diff --git a/src/parser/ast/call_parameter_tree.rs b/src/parser/ast/call_parameter_tree.rs new file mode 100644 index 0000000..f1749cd --- /dev/null +++ b/src/parser/ast/call_parameter_tree.rs @@ -0,0 +1,38 @@ +use std::fmt::Display; + +use crate::{ + lexer::collection::ParserTokens, + parser::{ + ast::{expression_tree::ExpressionTree, Tree}, + error::ParseError, + }, + util::span::Span, +}; + +#[derive(Clone, Debug)] +pub struct CallParameterTree { + expression: ExpressionTree, +} + +impl Tree for CallParameterTree { + fn span(&self) -> Span { + self.expression.span() + } + + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let expression = ExpressionTree::from_tokens(tokens)?; + Ok(CallParameterTree { expression }) + } +} + +impl CallParameterTree { + pub fn expression(&self) -> &ExpressionTree { + &self.expression + } +} + +impl Display for CallParameterTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.expression) + } +} diff --git a/src/parser/ast/call_tree.rs b/src/parser/ast/call_tree.rs index 5dd8e39..a5a9653 100644 --- a/src/parser/ast/call_tree.rs +++ b/src/parser/ast/call_tree.rs @@ -1,9 +1,11 @@ -use std::fmt::Display; +use std::fmt::{Display, Error, Formatter}; use crate::{ - lexer::collection::ParserTokens, + lexer::{collection::ParserTokens, token::SeperatorType}, parser::{ - ast::{expression_tree::ExpressionTree, identifier_tree::IdentifierExpressionTree, Tree}, + ast::{ + call_parameter_tree::CallParameterTree, identifier_tree::IdentifierExpressionTree, Tree, + }, error::ParseError, }, util::span::Span, @@ -12,7 +14,7 @@ use crate::{ #[derive(Clone, Debug)] pub struct CallTree { identifier: IdentifierExpressionTree, - parameter_expressions: Vec, + call_parameter: Vec, closing_span: Span, } @@ -20,18 +22,49 @@ impl Tree for CallTree { fn span(&self) -> Span { self.identifier.span().merge(&self.closing_span) } - fn from_tokens(_tokens: &mut ParserTokens) -> Result { - // TODO: Implement parsing from tokens - Err(ParseError::InvalidCharacter) + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let identifier = IdentifierExpressionTree::from_tokens(tokens)?; + tokens.expect_seperator(SeperatorType::ParenOpen)?; + let mut call_parameter = Vec::new(); + if !tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_separator(&SeperatorType::ParenClose) + { + call_parameter.push(CallParameterTree::from_tokens(tokens)?); + while tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_separator(&SeperatorType::Comma) + { + tokens.consume()?; + call_parameter.push(CallParameterTree::from_tokens(tokens)?); + } + } + let closing_span = tokens.expect_seperator(SeperatorType::ParenClose)?.span(); + Ok(CallTree { + identifier, + call_parameter, + closing_span, + }) + } +} + +impl CallTree { + pub fn identifier(&self) -> &IdentifierExpressionTree { + &self.identifier + } + pub fn parameter(&self) -> &Vec { + &self.call_parameter } } impl Display for CallTree { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, "{}", self.identifier)?; write!(f, "(")?; - for parameter_expression in &self.parameter_expressions { - write!(f, "{} ", parameter_expression)?; + for call_parameter in &self.call_parameter { + write!(f, "{} ", call_parameter)?; } write!(f, ")") } diff --git a/src/parser/ast/expression_tree.rs b/src/parser/ast/expression_tree.rs index c3d4c22..4d854e5 100644 --- a/src/parser/ast/expression_tree.rs +++ b/src/parser/ast/expression_tree.rs @@ -11,6 +11,7 @@ use crate::{ parser::{ ast::{ binary_operation_tree::BinaryOperationTree, + call_tree::CallTree, identifier_tree::IdentifierExpressionTree, literal_tree::{BooleanLiteralTree, IntegerLiteralTree}, ternary_operation_tree::TernaryOperationTree, @@ -27,6 +28,7 @@ pub enum ExpressionTree { BooleanLiteralTree(BooleanLiteralTree), IntegerLiteralTree(IntegerLiteralTree), IdentifierExpressionTree(IdentifierExpressionTree), + CallTree(CallTree), UnaryOperationTree(UnaryOperationTree), BinaryOperationTree(BinaryOperationTree), TernaryOperationTree(TernaryOperationTree), @@ -38,6 +40,7 @@ impl Tree for ExpressionTree { ExpressionTree::BooleanLiteralTree(tree) => tree.span(), ExpressionTree::IntegerLiteralTree(tree) => tree.span(), ExpressionTree::IdentifierExpressionTree(tree) => tree.span(), + ExpressionTree::CallTree(tree) => tree.span(), ExpressionTree::UnaryOperationTree(tree) => tree.span(), ExpressionTree::BinaryOperationTree(tree) => tree.span(), ExpressionTree::TernaryOperationTree(tree) => tree.span(), @@ -189,9 +192,18 @@ impl ExpressionTree { } } } - Token::Identifier(_, _) => Ok(ExpressionTree::IdentifierExpressionTree( - IdentifierExpressionTree::from_tokens(tokens)?, - )), + Token::Identifier(_, _) => { + if tokens + .peek_index(1)? + .is_separator(&SeperatorType::ParenOpen) + { + Ok(ExpressionTree::CallTree(CallTree::from_tokens(tokens)?)) + } else { + Ok(ExpressionTree::IdentifierExpressionTree( + IdentifierExpressionTree::from_tokens(tokens)?, + )) + } + } Token::NumberLiteral(_, _, _) => Ok(ExpressionTree::IntegerLiteralTree( IntegerLiteralTree::from_tokens(tokens)?, )), @@ -213,6 +225,7 @@ impl Display for ExpressionTree { ExpressionTree::BooleanLiteralTree(tree) => write!(f, "{}", tree), ExpressionTree::IntegerLiteralTree(tree) => write!(f, "{}", tree), ExpressionTree::IdentifierExpressionTree(tree) => write!(f, "{}", tree), + ExpressionTree::CallTree(tree) => write!(f, "{}", tree), ExpressionTree::UnaryOperationTree(tree) => write!(f, "{}", tree), ExpressionTree::BinaryOperationTree(tree) => write!(f, "{}", tree), ExpressionTree::TernaryOperationTree(tree) => write!(f, "{}", tree), diff --git a/src/parser/ast/function_parameter_tree.rs b/src/parser/ast/function_parameter_tree.rs index bfe7199..a7c4e65 100644 --- a/src/parser/ast/function_parameter_tree.rs +++ b/src/parser/ast/function_parameter_tree.rs @@ -1,6 +1,12 @@ use std::fmt::Display; -use crate::parser::ast::{identifier_tree::IdentifierExpressionTree, type_tree::TypeTree}; +use crate::{ + lexer::collection::ParserTokens, + parser::{ + ast::{identifier_tree::IdentifierExpressionTree, type_tree::TypeTree, Tree}, + error::ParseError, + }, +}; #[derive(Clone, Debug)] pub struct FunctionParameterTree { @@ -8,6 +14,30 @@ pub struct FunctionParameterTree { identifier: IdentifierExpressionTree, } +impl Tree for FunctionParameterTree { + fn span(&self) -> crate::util::span::Span { + self.type_tree.span().merge(&self.identifier.span()) + } + fn from_tokens(tokens: &mut ParserTokens) -> Result { + let type_tree = TypeTree::from_tokens(tokens)?; + let identifier = IdentifierExpressionTree::from_tokens(tokens)?; + Ok(FunctionParameterTree { + type_tree, + identifier, + }) + } +} + +impl FunctionParameterTree { + pub fn type_tree(&self) -> &TypeTree { + &self.type_tree + } + + pub fn identifier(&self) -> &IdentifierExpressionTree { + &self.identifier + } +} + impl Display for FunctionParameterTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}: {}", self.identifier, self.type_tree) diff --git a/src/parser/ast/function_tree.rs b/src/parser/ast/function_tree.rs index bd81bf4..0967807 100644 --- a/src/parser/ast/function_tree.rs +++ b/src/parser/ast/function_tree.rs @@ -32,8 +32,22 @@ impl Tree for FunctionTree { let return_type = TypeTree::from_tokens(tokens)?; let name = NameTree::from_tokens(tokens)?; tokens.expect_seperator(SeperatorType::ParenOpen)?; - let parameters = vec![]; - // TODO: Parse function parameters + let mut parameters = vec![]; + if tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_type_keyword() + { + parameters.push(FunctionParameterTree::from_tokens(tokens)?); + while tokens + .peek() + .ok_or(ParseError::ReachedEnd)? + .is_separator(&SeperatorType::Comma) + { + tokens.consume()?; + parameters.push(FunctionParameterTree::from_tokens(tokens)?); + } + } tokens.expect_seperator(SeperatorType::ParenClose)?; let body = BlockTree::from_tokens(tokens)?; trace!("Successfully parsed function"); @@ -66,10 +80,10 @@ impl FunctionTree { impl Display for FunctionTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{} {}(", self.return_type, self.name)?; + write!(f, "{} {}(", self.return_type, self.name)?; for parameter in &self.parameters { write!(f, "{}", parameter)?; } - write!(f, "{}", self.body) + writeln!(f, "){}", self.body) } } diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs index 8bb3ca0..0895c63 100644 --- a/src/parser/ast/mod.rs +++ b/src/parser/ast/mod.rs @@ -4,6 +4,7 @@ pub mod assignment_tree; pub mod binary_operation_tree; pub mod block_tree; pub mod break_tree; +pub mod call_parameter_tree; pub mod call_tree; pub mod continue_tree; pub mod declaration_tree; diff --git a/src/parser/ast/statement_tree.rs b/src/parser/ast/statement_tree.rs index 901b73f..e1e0f57 100644 --- a/src/parser/ast/statement_tree.rs +++ b/src/parser/ast/statement_tree.rs @@ -76,18 +76,21 @@ impl Tree for SimpleStatementTree { match tokens.peek().ok_or(ParseError::ReachedEnd)? { token if token.is_type_keyword() => { let declaration_tree = DeclarationTree::from_tokens(tokens)?; - return Ok(SimpleStatementTree::DeclerationTree(declaration_tree)); + Ok(SimpleStatementTree::DeclerationTree(declaration_tree)) } _ => { - if let Ok(assignment_tree) = AssignmentTree::from_tokens(tokens) { - return Ok(SimpleStatementTree::AssignmentTree(assignment_tree)); - } - if let Ok(call_tree) = CallTree::from_tokens(tokens) { - return Ok(SimpleStatementTree::CallTree(call_tree)); + if tokens + .peek_index(1)? + .is_separator(&SeperatorType::ParenOpen) + { + let call_tree = CallTree::from_tokens(tokens)?; + Ok(SimpleStatementTree::CallTree(call_tree)) + } else { + let assignment_tree = AssignmentTree::from_tokens(tokens)?; + Ok(SimpleStatementTree::AssignmentTree(assignment_tree)) } } } - Err(ParseError::NotAStatement) } } diff --git a/src/semantic/ast/call_parameter_tree.rs b/src/semantic/ast/call_parameter_tree.rs new file mode 100644 index 0000000..c949bbc --- /dev/null +++ b/src/semantic/ast/call_parameter_tree.rs @@ -0,0 +1,14 @@ +use crate::{ + parser::{ast::call_parameter_tree::CallParameterTree, types::Type}, + semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, +}; + +impl SemanticAnalysis for CallParameterTree { + fn analyze(&self, _: &mut AnalysisState) -> Result<(), SemanticError> { + Ok(()) + } + + fn r#type(&self, state: &mut AnalysisState) -> Result { + self.expression().r#type(state) + } +} diff --git a/src/semantic/ast/call_tree.rs b/src/semantic/ast/call_tree.rs index 6c80d42..3c7f626 100644 --- a/src/semantic/ast/call_tree.rs +++ b/src/semantic/ast/call_tree.rs @@ -4,11 +4,28 @@ use crate::{ }; impl SemanticAnalysis for CallTree { - fn analyze(&self, _state: &mut AnalysisState) -> Result<(), SemanticError> { - todo!("Function must be called with all parameters, they must have the correct type"); + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + let parameter_info = state + .get_function_parameter_info(self.identifier().name().name())? + .clone(); + if parameter_info.len() != self.parameter().len() { + return Err(SemanticError::FunctionParameterMismatch); + } + for (index, defined_type) in parameter_info.iter().enumerate() { + let actual_type = self + .parameter() + .get(index) + .ok_or(SemanticError::FunctionParameterMismatch)?; + if actual_type.r#type(state)?.ne(defined_type) { + return Err(SemanticError::FunctionParameterMismatch); + } + } + Ok(()) } - fn r#type(&self, _state: &mut AnalysisState) -> Result { - todo!("How to get return type of calling function? Analysis State?") + fn r#type(&self, state: &mut AnalysisState) -> Result { + state + .get_function_return_type(self.identifier().name().name()) + .cloned() } } diff --git a/src/semantic/ast/expression_tree.rs b/src/semantic/ast/expression_tree.rs index 446fb1c..c24f553 100644 --- a/src/semantic/ast/expression_tree.rs +++ b/src/semantic/ast/expression_tree.rs @@ -12,6 +12,7 @@ impl SemanticAnalysis for ExpressionTree { ExpressionTree::BinaryOperationTree(tree) => tree.analyze(state), ExpressionTree::TernaryOperationTree(tree) => tree.analyze(state), ExpressionTree::IdentifierExpressionTree(tree) => tree.analyze(state), + ExpressionTree::CallTree(tree) => tree.analyze(state), } } @@ -23,6 +24,7 @@ impl SemanticAnalysis for ExpressionTree { ExpressionTree::BinaryOperationTree(tree) => tree.r#type(state), ExpressionTree::TernaryOperationTree(tree) => tree.r#type(state), ExpressionTree::IdentifierExpressionTree(tree) => tree.r#type(state), + ExpressionTree::CallTree(tree) => tree.r#type(state), } } } diff --git a/src/semantic/ast/function_parameter_tree.rs b/src/semantic/ast/function_parameter_tree.rs index 4c5dfb2..57867dc 100644 --- a/src/semantic/ast/function_parameter_tree.rs +++ b/src/semantic/ast/function_parameter_tree.rs @@ -1,11 +1,21 @@ use crate::{ parser::{ast::function_parameter_tree::FunctionParameterTree, types::Type}, - semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, + semantic::{ + ast::SemanticAnalysis, error::SemanticError, AnalysisState, DeclarationStatus, + VariableStatus, + }, }; impl SemanticAnalysis for FunctionParameterTree { - fn analyze(&self, _state: &mut AnalysisState) -> Result<(), SemanticError> { - unimplemented!() + fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { + state.namespace.insert( + self.identifier().name().name().clone(), + VariableStatus::new( + self.type_tree().type_tree().clone(), + DeclarationStatus::Initialized, + ), + ); + Ok(()) } fn r#type(&self, _: &mut AnalysisState) -> Result { Ok(Type::Unit) diff --git a/src/semantic/ast/function_tree.rs b/src/semantic/ast/function_tree.rs index b7d0f58..5d27a78 100644 --- a/src/semantic/ast/function_tree.rs +++ b/src/semantic/ast/function_tree.rs @@ -11,6 +11,9 @@ impl SemanticAnalysis for FunctionTree { self.return_type().analyze(state)?; state.set_return_type(self.return_type().type_tree().clone()); self.name_tree().analyze(state)?; + for function_parameter in self.parameters() { + function_parameter.analyze(state)?; + } self.body().analyze(state)?; if state.return_state.eq(&ReturnState::NotReturing) { return Err(SemanticError::FunctionNotReturning(self.body().clone())); diff --git a/src/semantic/ast/mod.rs b/src/semantic/ast/mod.rs index 922b058..17f01f4 100644 --- a/src/semantic/ast/mod.rs +++ b/src/semantic/ast/mod.rs @@ -7,6 +7,7 @@ pub mod assignment_tree; pub mod binary_operation_tree; pub mod block_tree; pub mod break_tree; +pub mod call_parameter_tree; pub mod call_tree; pub mod continue_tree; pub mod declaration_tree; diff --git a/src/semantic/ast/program_tree.rs b/src/semantic/ast/program_tree.rs index 7cf370d..11d15ef 100644 --- a/src/semantic/ast/program_tree.rs +++ b/src/semantic/ast/program_tree.rs @@ -1,13 +1,30 @@ use tracing::trace; use crate::{ - parser::{ast::program_tree::ProgramTree, types::Type}, + parser::{ast::program_tree::ProgramTree, symbols::Name, types::Type}, semantic::{ast::SemanticAnalysis, error::SemanticError, AnalysisState}, }; impl SemanticAnalysis for ProgramTree { fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { trace!("Running semantic analysis on program"); + state.register_function( + Name::IdentifierName("print".to_string()), + Type::Int, + vec![Type::Int], + )?; + state.register_function(Name::IdentifierName("read".to_string()), Type::Int, vec![])?; + state.register_function(Name::IdentifierName("flush".to_string()), Type::Int, vec![])?; + for function in self.functions() { + let name = function.name_tree().name().clone(); + let return_type = function.return_type().type_tree().clone(); + let parameter = function + .parameters() + .iter() + .map(|v| v.type_tree().type_tree().clone()) + .collect(); + state.register_function(name, return_type, parameter)?; + } for function in self.functions() { function.analyze(state)?; } diff --git a/src/semantic/error.rs b/src/semantic/error.rs index 5726658..386d2ba 100644 --- a/src/semantic/error.rs +++ b/src/semantic/error.rs @@ -2,8 +2,9 @@ use std::fmt::Display; use crate::{ lexer::operator::{BinaryOperator, UnaryOperator}, - parser::ast::{ - block_tree::BlockTree, expression_tree::ExpressionTree, name_tree::NameTree, Tree, + parser::{ + ast::{block_tree::BlockTree, expression_tree::ExpressionTree, name_tree::NameTree, Tree}, + symbols::Name, }, util::span::Span, }; @@ -26,6 +27,9 @@ pub enum SemanticError { ForAdvancementDefinesVariable, MainMustReturnInt, IncompatibleReturnType(ExpressionTree), + FunctionAlreadyDefined(Name), + UndefinedFunction(Name), + FunctionParameterMismatch, } impl Display for SemanticError { @@ -106,6 +110,15 @@ impl Display for SemanticError { SemanticError::IncompatibleReturnType(tree) => { writeln!(f, "Expression at {} returns wrong type", tree.span()) } + SemanticError::FunctionAlreadyDefined(name) => { + writeln!(f, "Function with name {} already defined", name.as_string()) + } + SemanticError::UndefinedFunction(name) => { + writeln!(f, "Undefined function {}", name.as_string()) + } + SemanticError::FunctionParameterMismatch => { + writeln!(f, "Mismatching function parameters!") + } } } } diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 271e3f1..dc02dc2 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; -use crate::parser::{symbols::Name, types::Type}; +use crate::{ + parser::{symbols::Name, types::Type}, + semantic::error::SemanticError, +}; pub mod ast; pub mod error; @@ -9,6 +12,7 @@ pub mod error; pub struct AnalysisState { return_state: ReturnState, namespace: HashMap, + functions: HashMap)>, active_loops: usize, reachable: bool, return_type: Type, @@ -19,6 +23,7 @@ impl Default for AnalysisState { AnalysisState { return_state: ReturnState::NotReturing, namespace: HashMap::new(), + functions: HashMap::new(), active_loops: 0, reachable: true, return_type: Type::Unit, @@ -58,6 +63,39 @@ impl AnalysisState { pub fn set_return_type(&mut self, return_type: Type) { self.return_type = return_type; } + + pub fn register_function( + &mut self, + name: Name, + return_type: Type, + parameter: Vec, + ) -> Result<(), SemanticError> { + if self.functions.contains_key(&name) { + Err(SemanticError::FunctionAlreadyDefined(name)) + } else { + self.functions.insert(name, (return_type, parameter)); + Ok(()) + } + } + + pub fn get_function_return_type(&mut self, name: &Name) -> Result<&Type, SemanticError> { + Ok(&self + .functions + .get(name) + .ok_or(SemanticError::UndefinedFunction(name.clone()))? + .0) + } + + pub fn get_function_parameter_info( + &mut self, + name: &Name, + ) -> Result<&Vec, SemanticError> { + Ok(&self + .functions + .get(name) + .ok_or(SemanticError::UndefinedFunction(name.clone()))? + .1) + } } #[derive(PartialEq, Clone, Debug)] diff --git a/test.l3 b/test.l3 new file mode 100644 index 0000000..0233fb9 --- /dev/null +++ b/test.l3 @@ -0,0 +1,7 @@ +int main() { +return test(1); +} + +int test(int i) { +return i; +} From 0d853ba51ac3f86d34b715efb913216baa9711fa Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Tue, 24 Jun 2025 17:50:17 +0200 Subject: [PATCH 3/5] fix(semantic/parser): some semantic and parser fixes --- src/lexer/token.rs | 6 ------ src/parser/ast/lvalue_tree.rs | 4 ++++ src/parser/ast/statement_tree.rs | 5 +++++ src/semantic/ast/function_tree.rs | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/lexer/token.rs b/src/lexer/token.rs index f4fa002..c16127b 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -14,8 +14,6 @@ pub enum KeywordType { True, False, Null, - Print, - Read, Alloc, AllocArray, Int, @@ -40,8 +38,6 @@ impl KeywordType { Self::True => "true", Self::False => "false", Self::Null => "null", - Self::Print => "print", - Self::Read => "read", Self::Alloc => "alloc", Self::AllocArray => "alloc_array", Self::Int => "int", @@ -66,8 +62,6 @@ impl KeywordType { "true" => Some(Self::True), "false" => Some(Self::False), "null" => Some(Self::Null), - "print" => Some(Self::Print), - "read" => Some(Self::Read), "alloc" => Some(Self::Alloc), "alloc_array" => Some(Self::AllocArray), "int" => Some(Self::Int), diff --git a/src/parser/ast/lvalue_tree.rs b/src/parser/ast/lvalue_tree.rs index 9a53e7c..2a8bc93 100644 --- a/src/parser/ast/lvalue_tree.rs +++ b/src/parser/ast/lvalue_tree.rs @@ -1,5 +1,7 @@ use std::fmt::Display; +use tracing::trace; + use crate::{ lexer::{collection::ParserTokens, token::SeperatorType}, parser::{ @@ -19,6 +21,8 @@ impl Tree for LValueTree { self.identifier.span().clone() } fn from_tokens(tokens: &mut ParserTokens) -> Result { + trace!("Parsing lvalue from tokens"); + trace!("First token: {:?}", tokens.peek()); if tokens .peek() .ok_or(ParseError::ReachedEnd)? diff --git a/src/parser/ast/statement_tree.rs b/src/parser/ast/statement_tree.rs index e1e0f57..9148574 100644 --- a/src/parser/ast/statement_tree.rs +++ b/src/parser/ast/statement_tree.rs @@ -78,7 +78,12 @@ impl Tree for SimpleStatementTree { let declaration_tree = DeclarationTree::from_tokens(tokens)?; Ok(SimpleStatementTree::DeclerationTree(declaration_tree)) } + token if token.is_separator(&SeperatorType::ParenOpen) => { + let assignment_tree = AssignmentTree::from_tokens(tokens)?; + Ok(SimpleStatementTree::AssignmentTree(assignment_tree)) + } _ => { + trace!("Second token {:?}", tokens.peek_index(1)); if tokens .peek_index(1)? .is_separator(&SeperatorType::ParenOpen) diff --git a/src/semantic/ast/function_tree.rs b/src/semantic/ast/function_tree.rs index 5d27a78..2c377f6 100644 --- a/src/semantic/ast/function_tree.rs +++ b/src/semantic/ast/function_tree.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use tracing::trace; use crate::{ @@ -8,6 +10,7 @@ use crate::{ impl SemanticAnalysis for FunctionTree { fn analyze(&self, state: &mut AnalysisState) -> Result<(), SemanticError> { trace!("Running semantic analysis on function"); + state.namespace = HashMap::new(); self.return_type().analyze(state)?; state.set_return_type(self.return_type().type_tree().clone()); self.name_tree().analyze(state)?; From a9a5b44df64e1a312db8fcd2abe1b20a5f6b2304 Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Tue, 24 Jun 2025 21:27:44 +0200 Subject: [PATCH 4/5] fix(semantic): additional fixes for function analysis --- src/lexer/token.rs | 17 +++++++++++++++++ src/parser/ast/call_tree.rs | 14 ++++++++++++-- src/parser/ast/expression_tree.rs | 3 +++ src/parser/ast/identifier_tree.rs | 4 ++++ src/parser/ast/name_tree.rs | 4 ++++ src/parser/ast/program_tree.rs | 9 +-------- src/parser/error.rs | 1 - src/semantic/ast/program_tree.rs | 13 ++++++++++++- src/semantic/error.rs | 8 ++++++++ 9 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/lexer/token.rs b/src/lexer/token.rs index c16127b..2460468 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -14,6 +14,9 @@ pub enum KeywordType { True, False, Null, + Print, + Read, + Flush, Alloc, AllocArray, Int, @@ -38,6 +41,9 @@ impl KeywordType { Self::True => "true", Self::False => "false", Self::Null => "null", + Self::Print => "print", + Self::Read => "read", + Self::Flush => "flush", Self::Alloc => "alloc", Self::AllocArray => "alloc_array", Self::Int => "int", @@ -62,6 +68,9 @@ impl KeywordType { "true" => Some(Self::True), "false" => Some(Self::False), "null" => Some(Self::Null), + "print" => Some(Self::Print), + "read" => Some(Self::Read), + "flush" => Some(Self::Flush), "alloc" => Some(Self::Alloc), "alloc_array" => Some(Self::AllocArray), "int" => Some(Self::Int), @@ -83,6 +92,10 @@ impl KeywordType { pub fn is_type(&self) -> bool { matches!(self, Self::Bool | Self::Int) } + + pub fn is_function(&self) -> bool { + matches!(self, Self::Flush | Self::Read | Self::Print) + } } #[derive(Eq, Hash, Clone, Debug, PartialEq)] @@ -296,6 +309,10 @@ impl Token { } } + pub fn is_function(&self) -> bool { + matches!(self, Self::Keyword(_, keyword_type) if keyword_type.is_function()) + } + pub fn is_assignment_operator(&self) -> bool { matches!(self, Self::Operator(_, operator) if operator.is_assignment_operator()) } diff --git a/src/parser/ast/call_tree.rs b/src/parser/ast/call_tree.rs index a5a9653..fa5ad7c 100644 --- a/src/parser/ast/call_tree.rs +++ b/src/parser/ast/call_tree.rs @@ -4,9 +4,11 @@ use crate::{ lexer::{collection::ParserTokens, token::SeperatorType}, parser::{ ast::{ - call_parameter_tree::CallParameterTree, identifier_tree::IdentifierExpressionTree, Tree, + call_parameter_tree::CallParameterTree, identifier_tree::IdentifierExpressionTree, + name_tree::NameTree, Tree, }, error::ParseError, + symbols::Name, }, util::span::Span, }; @@ -23,7 +25,15 @@ impl Tree for CallTree { self.identifier.span().merge(&self.closing_span) } fn from_tokens(tokens: &mut ParserTokens) -> Result { - let identifier = IdentifierExpressionTree::from_tokens(tokens)?; + let identifier = if tokens.peek().ok_or(ParseError::ReachedEnd)?.is_function() { + let token = tokens.consume()?; + IdentifierExpressionTree::new(NameTree::new( + Name::IdentifierName(token.as_string().to_string()), + token.span(), + )) + } else { + IdentifierExpressionTree::from_tokens(tokens)? + }; tokens.expect_seperator(SeperatorType::ParenOpen)?; let mut call_parameter = Vec::new(); if !tokens diff --git a/src/parser/ast/expression_tree.rs b/src/parser/ast/expression_tree.rs index 4d854e5..e994c52 100644 --- a/src/parser/ast/expression_tree.rs +++ b/src/parser/ast/expression_tree.rs @@ -204,6 +204,9 @@ impl ExpressionTree { )) } } + Token::Keyword(_, keyword_type) if keyword_type.is_function() => { + Ok(ExpressionTree::CallTree(CallTree::from_tokens(tokens)?)) + } Token::NumberLiteral(_, _, _) => Ok(ExpressionTree::IntegerLiteralTree( IntegerLiteralTree::from_tokens(tokens)?, )), diff --git a/src/parser/ast/identifier_tree.rs b/src/parser/ast/identifier_tree.rs index 89f566b..7893d43 100644 --- a/src/parser/ast/identifier_tree.rs +++ b/src/parser/ast/identifier_tree.rs @@ -31,6 +31,10 @@ impl Tree for IdentifierExpressionTree { } impl IdentifierExpressionTree { + pub fn new(name: NameTree) -> IdentifierExpressionTree { + IdentifierExpressionTree { name } + } + pub fn name(&self) -> &NameTree { &self.name } diff --git a/src/parser/ast/name_tree.rs b/src/parser/ast/name_tree.rs index 588c4b3..0eabe08 100644 --- a/src/parser/ast/name_tree.rs +++ b/src/parser/ast/name_tree.rs @@ -32,6 +32,10 @@ impl Tree for NameTree { } impl NameTree { + pub fn new(name: Name, span: Span) -> NameTree { + NameTree { name, span } + } + pub fn name(&self) -> &Name { &self.name } diff --git a/src/parser/ast/program_tree.rs b/src/parser/ast/program_tree.rs index d997219..a347711 100644 --- a/src/parser/ast/program_tree.rs +++ b/src/parser/ast/program_tree.rs @@ -47,14 +47,7 @@ impl Tree for ProgramTree { if functions.is_empty() { return Err(ParseError::NoFunctions); } - if functions - .iter() - .any(|v| v.name_tree().name().as_string() == "main") - { - Ok(ProgramTree { functions }) - } else { - Err(ParseError::NoMainFunction) - } + Ok(ProgramTree { functions }) } } diff --git a/src/parser/error.rs b/src/parser/error.rs index a7cb773..59b4415 100644 --- a/src/parser/error.rs +++ b/src/parser/error.rs @@ -19,7 +19,6 @@ pub enum ParseError { NotAStatement, NotAOperation, NoFunctions, - NoMainFunction, ReachedEnd, WhitespaceError, InvalidCharacter, diff --git a/src/semantic/ast/program_tree.rs b/src/semantic/ast/program_tree.rs index 11d15ef..46d3277 100644 --- a/src/semantic/ast/program_tree.rs +++ b/src/semantic/ast/program_tree.rs @@ -28,7 +28,18 @@ impl SemanticAnalysis for ProgramTree { for function in self.functions() { function.analyze(state)?; } - Ok(()) + if let Some(main_function) = self + .functions() + .iter() + .find(|v| v.name_tree().name().as_string() == "main") + { + if main_function.parameters().len() > 0 { + return Err(SemanticError::InvalidMainFunction); + } + Ok(()) + } else { + Err(SemanticError::NoMainFunction) + } } fn r#type(&self, _: &mut AnalysisState) -> Result { Ok(Type::Unit) diff --git a/src/semantic/error.rs b/src/semantic/error.rs index 386d2ba..590d779 100644 --- a/src/semantic/error.rs +++ b/src/semantic/error.rs @@ -25,11 +25,13 @@ pub enum SemanticError { ConditionMustBeBoolean(ExpressionTree), FunctionNotReturning(BlockTree), ForAdvancementDefinesVariable, + NoMainFunction, MainMustReturnInt, IncompatibleReturnType(ExpressionTree), FunctionAlreadyDefined(Name), UndefinedFunction(Name), FunctionParameterMismatch, + InvalidMainFunction, } impl Display for SemanticError { @@ -119,6 +121,12 @@ impl Display for SemanticError { SemanticError::FunctionParameterMismatch => { writeln!(f, "Mismatching function parameters!") } + SemanticError::NoMainFunction => { + writeln!(f, "No main function!") + } + SemanticError::InvalidMainFunction => { + writeln!(f, "Invalid main function") + } } } } From acfbb3654e25e8f12ec433b2d9dff4e7e79be1ac Mon Sep 17 00:00:00 2001 From: Felix Schwickerath Date: Tue, 24 Jun 2025 21:51:06 +0200 Subject: [PATCH 5/5] fix(codegen): fix duplicate labels --- .gitignore | 1 + src/backend/codegen.rs | 31 ++++++++++++++++++++++--------- src/ir/ast/mod.rs | 4 ++-- src/ir/graph.rs | 10 ++++++++-- src/main.rs | 2 +- test.l3 | 7 ------- 6 files changed, 34 insertions(+), 21 deletions(-) delete mode 100644 test.l3 diff --git a/.gitignore b/.gitignore index 2599f31..44d89e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ tests test.l2 output +test.l3 diff --git a/src/backend/codegen.rs b/src/backend/codegen.rs index 3a637bf..dc47154 100644 --- a/src/backend/codegen.rs +++ b/src/backend/codegen.rs @@ -31,7 +31,7 @@ _main: pub struct CodeGenerator { ir_graphs: Vec, - jump_label: HashMap, + jump_label: HashMap<(String, BlockIndex), String>, } impl CodeGenerator { @@ -140,7 +140,10 @@ impl CodeGenerator { registers: &Registers, ) -> String { let mut code = String::new(); - let block_label = self.jump_label.get(&block_index).unwrap(); + let block_label = self + .jump_label + .get(&(ir_graph.name().to_string(), block_index)) + .unwrap(); code.push_str(&format!("{}:\n", block_label)); for (node_index, node) in block.get_nodes().iter().enumerate() { @@ -324,7 +327,10 @@ impl CodeGenerator { node, ); let following_block_index = jump_information.get(&node_index).unwrap(); - let label = self.jump_label.get(following_block_index).unwrap(); + let label = self + .jump_label + .get(&(ir_graph.name().to_string(), *following_block_index)) + .unwrap(); code.push_str(&self.generate_phi_moves( block_index, *following_block_index, @@ -372,7 +378,7 @@ impl CodeGenerator { let following_block_index = jump_information.get(&node_index).unwrap(); let jump_label = self .jump_label - .get(following_block_index) + .get(&(ir_graph.name().to_string(), *following_block_index)) .expect("Expected jump label for false if"); code.push_str(&self.generate_phi_moves( block_index, @@ -620,7 +626,10 @@ impl CodeGenerator { registers: &Registers, ) -> Option { let mut code = String::new(); - let jump_label = self.jump_label.get(&jump_target).unwrap(); + let jump_label = self + .jump_label + .get(&(ir_graph.name().to_string(), jump_target)) + .unwrap(); match comparision { Node::Lower(data) | Node::LowerEquals(data) @@ -898,11 +907,11 @@ fn move_stack_variable(register: &Box) -> String { code } -fn calculate_jump_label(ir_graphs: &Vec) -> HashMap { +fn calculate_jump_label(ir_graphs: &Vec) -> HashMap<(String, BlockIndex), String> { let mut jump_label = HashMap::new(); for ir_graph in ir_graphs { for (block_index, block) in ir_graph.get_blocks().iter().enumerate() { - calculate_jump_label_block(block_index, block, &mut jump_label); + calculate_jump_label_block(block_index, ir_graph, block, &mut jump_label); } } jump_label @@ -910,8 +919,12 @@ fn calculate_jump_label(ir_graphs: &Vec) -> HashMap { fn calculate_jump_label_block<'a>( block_index: BlockIndex, + ir_graph: &IRGraph, _block: &Block, - current: &mut HashMap, + current: &mut HashMap<(String, BlockIndex), String>, ) { - current.insert(block_index, format!("LC{}", block_index)); + current.insert( + (ir_graph.name().to_string(), block_index), + format!("LC{}{}", ir_graph.name(), block_index), + ); } diff --git a/src/ir/ast/mod.rs b/src/ir/ast/mod.rs index 010ebd2..4d20fb7 100644 --- a/src/ir/ast/mod.rs +++ b/src/ir/ast/mod.rs @@ -54,9 +54,9 @@ pub trait ToIR { } impl IRConstructor { - pub fn new() -> IRConstructor { + pub fn new(name: String) -> IRConstructor { IRConstructor { - graph: IRGraph::new(), + graph: IRGraph::new(name), current_definitions: HashMap::new(), incomplete_phis: HashMap::new(), current_side_effect: HashMap::new(), diff --git a/src/ir/graph.rs b/src/ir/graph.rs index 8f1a908..a75ef41 100644 --- a/src/ir/graph.rs +++ b/src/ir/graph.rs @@ -11,12 +11,14 @@ pub const START_BLOCK: usize = 0; pub const END_BLOCK: usize = 1; pub struct IRGraph { + name: String, blocks: Vec, } impl IRGraph { - pub fn new() -> IRGraph { + pub fn new(name: String) -> IRGraph { IRGraph { + name, blocks: vec![ Block::new("start".to_string()), Block::new("end".to_string()), @@ -69,11 +71,15 @@ impl IRGraph { pub fn end_block_mut(&mut self) -> &mut Block { self.blocks.get_mut(END_BLOCK).expect("End Block missing!") } + + pub fn name(&self) -> &String { + &self.name + } } impl Default for IRGraph { fn default() -> Self { - Self::new() + Self::new("default".to_string()) } } diff --git a/src/main.rs b/src/main.rs index 3535b5b..20f013f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,7 @@ fn main() { let mut ir_graphs = Vec::new(); for function in program.functions() { - let mut ir_graph = IRConstructor::new(); + let mut ir_graph = IRConstructor::new(function.name_tree().name().as_string().to_string()); function.to_ir(&mut ir_graph); ir_graphs.push(ir_graph.graph()); } diff --git a/test.l3 b/test.l3 deleted file mode 100644 index 0233fb9..0000000 --- a/test.l3 +++ /dev/null @@ -1,7 +0,0 @@ -int main() { -return test(1); -} - -int test(int i) { -return i; -}