From 0225ae1f84fc07dacf7493904d81c6477c7ee1bb Mon Sep 17 00:00:00 2001 From: Jim <112640460+0xJ1M@users.noreply.github.com> Date: Thu, 7 Sep 2023 22:08:56 +0100 Subject: [PATCH] Updated TreeNode system to use abstract base class and inheritence --- MathEngine/EngineTests/EngineTests.csproj | 8 +- .../Parser Tests/ExpressionTreeTests.cs | 28 ++-- MathEngine/MathEngine/Evaluator/Evaluator.cs | 6 +- MathEngine/MathEngine/MathEngine.csproj | 7 +- .../Parser/Parser/ExpressionTree.cs | 35 ++-- .../MathEngine/Parser/Parser/Node/TreeNode.cs | 158 ------------------ .../MathEngine/Parser/Parser/TreeGenerator.cs | 47 +----- 7 files changed, 58 insertions(+), 231 deletions(-) delete mode 100644 MathEngine/MathEngine/Parser/Parser/Node/TreeNode.cs diff --git a/MathEngine/EngineTests/EngineTests.csproj b/MathEngine/EngineTests/EngineTests.csproj index 5217795..8f8f0fc 100644 --- a/MathEngine/EngineTests/EngineTests.csproj +++ b/MathEngine/EngineTests/EngineTests.csproj @@ -1,13 +1,19 @@ - net6.0 + net7.0 enable enable false + + True + + + + diff --git a/MathEngine/EngineTests/Parser Tests/ExpressionTreeTests.cs b/MathEngine/EngineTests/Parser Tests/ExpressionTreeTests.cs index a51bb01..e42709b 100644 --- a/MathEngine/EngineTests/Parser Tests/ExpressionTreeTests.cs +++ b/MathEngine/EngineTests/Parser Tests/ExpressionTreeTests.cs @@ -16,15 +16,8 @@ namespace EngineTests public void TestExpressionTreeSimpleExpression() { string testExp = "3+4"; - TreeNode exptectedTree = new(Token.Plus); - Token tokfour = new("4", Token.Type.Numeric, Token.NumericType.Decimal, 0); - Token tokthree = new("3", Token.Type.Numeric, Token.NumericType.Decimal, 0); - TreeNode four = new(tokfour); - TreeNode three = new(tokthree); - exptectedTree.AddChildNode(four); - exptectedTree.AddChildNode(three); ExpressionTree returnedTree = new(testExp); - Assert.IsTrue(returnedTree.Equals(exptectedTree)); + Assert.IsTrue(returnedTree.ToString() == "7"); } /// @@ -34,11 +27,8 @@ namespace EngineTests public void TestExpressionTreeSimpleExpressionEvaluation() { string testExp = "3+4*7"; - Token tok31 = new("31", Token.Type.Numeric, Token.NumericType.Decimal, 0); - TreeNode exptectedTree = new(tok31); ExpressionTree returnedTree = new(testExp); - ExpressionTree? evaluatedTree = returnedTree.Evaluate(); - Assert.IsTrue(evaluatedTree.Equals(exptectedTree)); + Assert.IsTrue(returnedTree.ToString() == "31"); } /// @@ -49,11 +39,17 @@ namespace EngineTests { string testExp = "3+4*7-8/7"; decimal testValue = decimal.Divide(209 , 7); - Token tok31 = new(testValue.ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0); - TreeNode exptectedTree = new(tok31); ExpressionTree returnedTree = new(testExp); - ExpressionTree? evaluatedTree = returnedTree.Evaluate(); - Assert.IsTrue(evaluatedTree.Equals(exptectedTree)); + Assert.IsTrue(returnedTree.ToString() == testValue.ToString()); + } + + [TestMethod] + public void TestExpressionTreeGetHashCodeReturnsHashCode() + { + string testExp = "1+1"; + ExpressionTree returnedTree1 = new(testExp); + int hash = returnedTree1.GetHashCode(); + Assert.IsInstanceOfType(hash, typeof(int)); } } } \ No newline at end of file diff --git a/MathEngine/MathEngine/Evaluator/Evaluator.cs b/MathEngine/MathEngine/Evaluator/Evaluator.cs index f3f0e8c..7496f40 100644 --- a/MathEngine/MathEngine/Evaluator/Evaluator.cs +++ b/MathEngine/MathEngine/Evaluator/Evaluator.cs @@ -4,11 +4,11 @@ using MathEngine.Parser.Tokeniser; namespace MathEngine.Parser.Evaluator { /// - /// + /// Class that evaluate TreeNodes /// internal class Evaluator { - public static TreeNode? Evaluate(TreeNode rootNode) + /*public static TreeNode? Evaluate(TreeNode rootNode) { if (rootNode == null) { @@ -69,6 +69,6 @@ namespace MathEngine.Parser.Evaluator Token.Type.Division => new TreeNode(new Token(((decimal)(lhs / rhs)).ToString(), Token.Type.Numeric, Token.NumericType.Decimal, 0)), _ => throw new Exception("Potentially invalid token?"), }; - } + }*/ } } diff --git a/MathEngine/MathEngine/MathEngine.csproj b/MathEngine/MathEngine/MathEngine.csproj index b9af703..7824531 100644 --- a/MathEngine/MathEngine/MathEngine.csproj +++ b/MathEngine/MathEngine/MathEngine.csproj @@ -1,10 +1,15 @@  - net6.0 + net7.0 enable enable + True + + + + <_Parameter1>EngineTests diff --git a/MathEngine/MathEngine/Parser/Parser/ExpressionTree.cs b/MathEngine/MathEngine/Parser/Parser/ExpressionTree.cs index 6f36a1e..8c11965 100644 --- a/MathEngine/MathEngine/Parser/Parser/ExpressionTree.cs +++ b/MathEngine/MathEngine/Parser/Parser/ExpressionTree.cs @@ -1,4 +1,5 @@ -using MathEngine.Parser.Tokeniser; +using MathEngine.Parser.Parser.Node; +using MathEngine.Parser.Tokeniser; namespace MathEngine.Parser.Parser { /// @@ -9,8 +10,8 @@ namespace MathEngine.Parser.Parser /// /// The root node of the expression tree; /// - private readonly TreeNode rootNode; - private TreeNode? evaluated_expression; + private readonly BaseNode rootNode; + private readonly BaseNode? evaluated_expression; /// /// Initialises a new instance of the MathEngine.Parser.Parser.Node class with a given Token @@ -22,9 +23,10 @@ namespace MathEngine.Parser.Parser List tokens = Tokeniser.Tokeniser.Tokenise(Expression); Stack rpnForm = Parser.Parse(tokens); rootNode = TreeGenerator.TreeFromRPN(rpnForm); + evaluated_expression = rootNode.Evaluate(); } - private ExpressionTree(TreeNode rootNode) + private ExpressionTree(BaseNode rootNode) { this.rootNode = rootNode; } @@ -35,19 +37,19 @@ namespace MathEngine.Parser.Parser /// Returns an update of the current instance which the expression Evaluated public ExpressionTree Evaluate() { - return new(Evaluator.Evaluator.Evaluate(rootNode)); + return new ExpressionTree(rootNode.Evaluate()); } - /// - /// Returns a value indicating if the given object is equal to the current instance of ExpressionTree - /// - /// The object to compare to the current instance - /// True if they are equal, False otherwise - public override bool Equals(object? other) + /// + /// Returns a value indicating if the given object is equal to the current instance of ExpressionTree + /// + /// The object to compare to the current instance + /// True if they are equal, False otherwise + public override bool Equals(object? other) { - if (other is TreeNode) + if (other is BaseNode) { - ExpressionTree otherTree = new((TreeNode)other); + ExpressionTree otherTree = new((BaseNode)other); return this.Equals(otherTree); } return false; @@ -73,7 +75,12 @@ namespace MathEngine.Parser.Parser public override int GetHashCode() { - return System.HashCode.Combine(this.rootNode); + return System.HashCode.Combine(rootNode, evaluated_expression); + } + + public override string ToString() + { + return evaluated_expression.ToString(); } } } diff --git a/MathEngine/MathEngine/Parser/Parser/Node/TreeNode.cs b/MathEngine/MathEngine/Parser/Parser/Node/TreeNode.cs deleted file mode 100644 index da26994..0000000 --- a/MathEngine/MathEngine/Parser/Parser/Node/TreeNode.cs +++ /dev/null @@ -1,158 +0,0 @@ -using MathEngine.Parser.Tokeniser; -namespace MathEngine.Parser.Parser -{ - /// - /// Represents a node in a Tree structure - /// - internal class TreeNode - { - private TreeNode? Parent; - private List? Children; - private readonly Token Value; - - /// - /// Initialises a new instance of the MathEngine.Parser.Parser.Node class with a given Token - /// - /// The token for the nodes value - public TreeNode(Token value) - { - Parent = null; - Children = null; - Value = value; - } - - /// - /// Returns the value of the node - /// - public Token NodeValue - { - get { return Value; } - } - - /// - /// Returns the parent node of the current node, or null if it does not exist - /// - public TreeNode? ParentNode - { - get - { - if (Parent == null) - { - return null; - } - else - { - return Parent; - } - } - } - - /// - /// Returns all of the child nodes of the current node, or null if it odes not exist - /// - public List? GetChildrenNodes - { - get - { - if (Children == null) - { - return null; - } - else - { - return Children; - } - } - } - - /// - /// Returns the child node specified by the index, if there are no children nodes or if the index is out of bounds than null is returned - /// - /// The index of the child node to get - /// The ChildNode at the specified index, null if it is null or the index is out-of-bounds - public TreeNode? GetChildNode(int index) - { - if (Children == null) - { - return null; - } - if (index < 0 || index >= Children.Count) - { - return null; - } - - return Children[index]; - } - - /// - /// Adds a child node to the current root node, if there are no children nodes a list is created - /// - /// The value for the child node that is to be added - public void AddChildNode(TreeNode Node) - { - if (Children == null) - { - Children = new() - { - Node - }; - } - else - { - Children.Add(Node); - } - } - - /// - /// Returns a value that indicates if the given object is equal to the current instance of TreeNode - /// - /// The object to compare to the current instance of TreeNode - /// True if the object innstace is equal to the current ExpressionTree instance, False otherwise - public override bool Equals(object? other) - { - if (other is ExpressionTree) - { - return other.Equals(this); - } - return false; - } - - /// - /// Returns a value that indicates if the given TreeNode instance is equal to another - /// - /// The TreeNode to check for equality - /// True if they are equal, False otherwise - public bool Equals(TreeNode other) - { - if (this.Value != other.Value) //If the root values are not equal we are done - { - return false; - } - // otherwise, - if (this.Children != null && other.Children != null) // If both children are NOT null then we reursively check the child nodes - { - //Covered all nullable cases, we now need to recursively check the child nodes - if (Children.Count != other.Children.Count) - { - return false; - } - for (int childNodeIndex = 0; childNodeIndex < Children.Count; childNodeIndex++) - { - if (!Children[childNodeIndex].Equals(other.Children[childNodeIndex])) - { - return false; - } - } - return true; - } - else if (this.Children == null && other.Children == null) //Special case is if both children lists are null then the TreeNodes are equal - { - return true; - } - else // otherwise at least one is null and the other is not so they can't be equal - { - return false; // if both children are not null than at least one is null so they can't be equal - } - } - } -} diff --git a/MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs b/MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs index f6ba921..11da6f6 100644 --- a/MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs +++ b/MathEngine/MathEngine/Parser/Parser/TreeGenerator.cs @@ -7,44 +7,15 @@ namespace MathEngine.Parser.Parser /// internal class TreeGenerator { - - /// - /// Creates a binary TreeNode, that is a node with a root value and two children - /// - /// The token to be the root node of the TreeNode - /// TreeNode that is the left branch of the current node - /// TreeNode that is the right branch of the current node - /// A TreeNode with CurrentToken as the root value and LeftBranch and RightBranch as Children - private static TreeNode CreateBinaryNode(Token CurrentToken, TreeNode LeftBranch, TreeNode RightBranch) - { - TreeNode root = new(CurrentToken); - root.AddChildNode(LeftBranch); - root.AddChildNode(RightBranch); - return root; - } - - /// - /// Creates a unary TreeNode, that is a node with a root value and two children - /// - /// The token to be the root node of the TreeNode - /// TreeNode that is the child of the current node - /// A TreeNode with CurrentToken as the root value and ChildNode as the sole child node - private static TreeNode CreateUnaryNode(Token CurrentToken, TreeNode ChildNode) - { - TreeNode root = new(CurrentToken); - root.AddChildNode(ChildNode); - return root; - } - /// /// Generates the full expression tree given an RPN expression stack /// /// RPN expression stack to generate an expression tree from /// An expression Tree that represents the Mathematical expression given by rpnExpression - public static TreeNode TreeFromRPN(Stack rpnExpression) + public static BaseNode TreeFromRPN(Stack rpnExpression) { - Stack OutputStack = new(rpnExpression.Count); - TreeNode Node; + Stack OutputStack = new(rpnExpression.Count); + BaseNode Node; Token CurrentToken; while (rpnExpression.Count != 0) { @@ -52,7 +23,7 @@ namespace MathEngine.Parser.Parser switch (CurrentToken.Token_Type) { case Token.Type.Numeric: - Node = new TreeNode(CurrentToken); + Node = NodeFactory.CreateNumericNode(CurrentToken); OutputStack.Push(Node); break; // We need to preserve "Left handness" of the ExpressionTree @@ -63,15 +34,15 @@ namespace MathEngine.Parser.Parser case Token.Type.Multiplication: case Token.Type.Division: case Token.Type.Exponentiation: - TreeNode Right = OutputStack.Pop(); - TreeNode Left = OutputStack.Pop(); - Node = CreateBinaryNode(CurrentToken, Left, Right); + BaseNode Right = OutputStack.Pop(); + BaseNode Left = OutputStack.Pop(); + Node = NodeFactory.CreateBinaryNode(CurrentToken, Left, Right); OutputStack.Push(Node); break; case Token.Type.UnaryPlus: case Token.Type.UnaryMinus: - Node = CreateUnaryNode(CurrentToken, OutputStack.Pop()); - OutputStack.Push(Node); + //Node = NodeFactory.CreateUnaryNode(CurrentToken, OutputStack.Pop()); + //OutputStack.Push(Node); break; } }