mirror of
https://github.com/0xJ1M/MathsEngine.git
synced 2026-06-05 02:30:06 +00:00
Feature/basic evaluator (#3)
* Refactor * Updated TreeNode system to use abstract base class and inheritence * Updated unit test coverage * Improved code coverage * Added missing files
This commit is contained in:
24
MathEngine/EngineTests/Parser Tests/Nodes/NodesTests.cs
Normal file
24
MathEngine/EngineTests/Parser Tests/Nodes/NodesTests.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace EngineTests.Parser_Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class for testing the TreeNodes
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class NodesTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Test the Parser on a basic List of tokens
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestParserBasicExpression()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
119
MathEngine/EngineTests/Parser Tests/Tokeniser/TokenIserTests.cs
Normal file
119
MathEngine/EngineTests/Parser Tests/Tokeniser/TokenIserTests.cs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
using MathEngine.Parser.Tokeniser;
|
||||||
|
|
||||||
|
namespace EngineTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class for testing the Tokeniser
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class TokeniserTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Test the tokeniser on an empty string
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokeniseEmptystringReturnsEmptyList()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
string testString = "";
|
||||||
|
Token one = new("1", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
List<Token> expectedValue = new()
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
Token.Plus,
|
||||||
|
one
|
||||||
|
};
|
||||||
|
//Act
|
||||||
|
List<Token> returnedValue = Tokeniser.Tokenise(testString);
|
||||||
|
//Assert
|
||||||
|
Assert.AreEqual(returnedValue.Count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test the tokeniser on a basic string
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokeniseBasicString()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
string testString = "1+1";
|
||||||
|
Token one = new("1", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
List<Token> expectedValue = new()
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
Token.Plus,
|
||||||
|
one
|
||||||
|
};
|
||||||
|
//Act
|
||||||
|
List<Token> returnedValue = Tokeniser.Tokenise(testString);
|
||||||
|
//Assert
|
||||||
|
Assert.IsTrue(expectedValue.SequenceEqual(returnedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test the tokeniser on a basic string, but with significant ammounts of whitespace
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokeniseBasicStringWithWhiteSpace()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
string testString = " 1 + 1 ";
|
||||||
|
Token one = new("1", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
List<Token> expectedValue = new()
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
Token.Plus,
|
||||||
|
one
|
||||||
|
};
|
||||||
|
//Act
|
||||||
|
List<Token> returnedValue = Tokeniser.Tokenise(testString);
|
||||||
|
//Assert
|
||||||
|
Assert.IsTrue(expectedValue.SequenceEqual(returnedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test the tokeniser on a string which contains a number which is not formatted correctly
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokeniseStringWithInvalidNumbr()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
string testString = "1+11.2.5";
|
||||||
|
//Act and Assert
|
||||||
|
Assert.ThrowsException<Exception>(() => Tokeniser.Tokenise(testString));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test the tokeniser with all operators
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokeniseStringWithAllOperators()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
string testString = "1+2-3*4/5";
|
||||||
|
Token one = new("1", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
Token two = new("2", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
Token three = new("3", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
Token four = new("4", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
Token five = new("5", Token.Type.Numeric, Token.NumericType.Decimal, 0);
|
||||||
|
List<Token> expectedValue = new()
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
Token.Plus,
|
||||||
|
two,
|
||||||
|
Token.Minus,
|
||||||
|
three,
|
||||||
|
Token.Multiply,
|
||||||
|
four,
|
||||||
|
Token.Divide,
|
||||||
|
five
|
||||||
|
};
|
||||||
|
//Act
|
||||||
|
List<Token> returnedValue = Tokeniser.Tokenise(testString);
|
||||||
|
//Assert
|
||||||
|
Assert.IsTrue(expectedValue.SequenceEqual(returnedValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
323
MathEngine/EngineTests/Parser Tests/Tokeniser/TokenTests.cs
Normal file
323
MathEngine/EngineTests/Parser Tests/Tokeniser/TokenTests.cs
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
using MathEngine.Parser.Tokeniser;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace EngineTests.Parser_Tests.Tokeniser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class for testing the Token
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class TokenTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Test that Token constructor returns valid token
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenConstructorReturnsToken()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
Token token = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Assert.IsNotNull(token);
|
||||||
|
Assert.AreEqual(token.TokenValue, testTokenValue);
|
||||||
|
Assert.AreEqual(token.Token_Type, testTokenType);
|
||||||
|
Assert.AreEqual(token.NumericalType, testNumericType);
|
||||||
|
Assert.AreEqual(token.FunctionArity, testArityValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
/// <summary>
|
||||||
|
/// Test ToString returns expected string format
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestToStringReturnsExpetedStringFormat()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
|
||||||
|
string token_string = token1.ToString();
|
||||||
|
Assert.AreEqual(token_string, "123,Numeric,Integer,0");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/// <summary>
|
||||||
|
/// Test for == operator comparing two equal Tokens returns true
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualOperatorReturnsTrueOnEqualTokens()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "123";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
Assert.AreEqual(token1 == token2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test for == operator comparing unequal Tokens returns false
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualOperatorReturnsFalseOnUnequalTokens()
|
||||||
|
{
|
||||||
|
string testTokenValue1 = "123";
|
||||||
|
Token.Type testTokenType1 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType1 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue1 = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "125";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
string testTokenValue3 = "123";
|
||||||
|
Token.Type testTokenType3 = Token.Type.Operator;
|
||||||
|
Token.NumericType testNumericType3 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue3 = 0;
|
||||||
|
|
||||||
|
string testTokenValue4 = "123";
|
||||||
|
Token.Type testTokenType4 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType4 = Token.NumericType.Decimal;
|
||||||
|
uint testArityValue4 = 0;
|
||||||
|
|
||||||
|
string testTokenValue5 = "123";
|
||||||
|
Token.Type testTokenType5 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType5 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue5 = 1;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue1, testTokenType1, testNumericType1, testArityValue1);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
Token token3 = new(testTokenValue3, testTokenType3, testNumericType3, testArityValue3);
|
||||||
|
Token token4 = new(testTokenValue4, testTokenType4, testNumericType4, testArityValue4);
|
||||||
|
Token token5 = new(testTokenValue5, testTokenType5, testNumericType5, testArityValue5);
|
||||||
|
|
||||||
|
Assert.AreEqual(token1 == token2, false);
|
||||||
|
Assert.AreEqual(token1 == token3, false);
|
||||||
|
Assert.AreEqual(token1 == token4, false);
|
||||||
|
Assert.AreEqual(token1 == token5, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test for != operator comparing two equal Tokens returns true
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenUnEqualOperatorReturnsFalseOnEqualTokens()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Assert.AreEqual(token1 != token2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test for != operator comparing unequal Tokens returns True
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenUnEqualOperatorReturnsTrueOnUnequalTokens()
|
||||||
|
{
|
||||||
|
string testTokenValue1 = "123";
|
||||||
|
Token.Type testTokenType1 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType1 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue1 = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "125";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
string testTokenValue3 = "123";
|
||||||
|
Token.Type testTokenType3 = Token.Type.Operator;
|
||||||
|
Token.NumericType testNumericType3 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue3 = 0;
|
||||||
|
|
||||||
|
string testTokenValue4 = "123";
|
||||||
|
Token.Type testTokenType4 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType4 = Token.NumericType.Decimal;
|
||||||
|
uint testArityValue4 = 0;
|
||||||
|
|
||||||
|
string testTokenValue5 = "123";
|
||||||
|
Token.Type testTokenType5 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType5 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue5 = 1;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue1, testTokenType1, testNumericType1, testArityValue1);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
Token token3 = new(testTokenValue3, testTokenType3, testNumericType3, testArityValue3);
|
||||||
|
Token token4 = new(testTokenValue4, testTokenType4, testNumericType4, testArityValue4);
|
||||||
|
Token token5 = new(testTokenValue5, testTokenType5, testNumericType5, testArityValue5);
|
||||||
|
|
||||||
|
Assert.AreEqual(token1 != token2, true);
|
||||||
|
Assert.AreEqual(token1 != token3, true);
|
||||||
|
Assert.AreEqual(token1 != token4, true);
|
||||||
|
Assert.AreEqual(token1 != token5, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test Equals method returns True when Tokens are equal
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualsMethodWithTokenObjectsReturnsTrueWhenEqual()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "123";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
Assert.AreEqual(token1.Equals(token2), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test Equals method returns False when Tokens are unequal
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualsMethodWithTokenObjectsReturnsFalseWhenUnequal()
|
||||||
|
{
|
||||||
|
string testTokenValue1 = "123";
|
||||||
|
Token.Type testTokenType1 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType1 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue1 = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "125";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
string testTokenValue3 = "123";
|
||||||
|
Token.Type testTokenType3 = Token.Type.Operator;
|
||||||
|
Token.NumericType testNumericType3 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue3 = 0;
|
||||||
|
|
||||||
|
string testTokenValue4 = "123";
|
||||||
|
Token.Type testTokenType4 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType4 = Token.NumericType.Decimal;
|
||||||
|
uint testArityValue4 = 0;
|
||||||
|
|
||||||
|
string testTokenValue5 = "123";
|
||||||
|
Token.Type testTokenType5 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType5 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue5 = 1;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue1, testTokenType1, testNumericType1, testArityValue1);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
Token token3 = new(testTokenValue3, testTokenType3, testNumericType3, testArityValue3);
|
||||||
|
Token token4 = new(testTokenValue4, testTokenType4, testNumericType4, testArityValue4);
|
||||||
|
Token token5 = new(testTokenValue5, testTokenType5, testNumericType5, testArityValue5);
|
||||||
|
|
||||||
|
Assert.AreEqual(token1.Equals(token2), false);
|
||||||
|
Assert.AreEqual(token1.Equals(token3), false);
|
||||||
|
Assert.AreEqual(token1.Equals(token4), false);
|
||||||
|
Assert.AreEqual(token1.Equals(token5), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test Equals method checks for Token equality when object is a token
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualsMethodWithObjectsThatIsATokenComparesForTokenEquality()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "123";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
object token_obj = token2;
|
||||||
|
Assert.AreEqual(token1.Equals(token_obj), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test Equals method checks for returns false when object is not a token
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenEqualsMethodWithObjectsThatIsNotATokenReturnsFalse()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
int non_token = 5;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Assert.AreEqual(token1.Equals(non_token), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test GetHashCode on two tokens with same values is the same
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenGetHashCodeOnTwoTokensWhichHaveSameValuesAreEqual()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "123";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
|
||||||
|
int hash1 = token1.GetHashCode();
|
||||||
|
int hash2 = token2.GetHashCode();
|
||||||
|
Assert.AreEqual(hash1, hash2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test GetHashCode on two tokens with different values are different
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestTokenGetHashCodeOnTwoTokensWhichHaveDifferentValuesAreUnequal()
|
||||||
|
{
|
||||||
|
string testTokenValue = "123";
|
||||||
|
Token.Type testTokenType = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType = Token.NumericType.Integer;
|
||||||
|
uint testArityValue = 0;
|
||||||
|
|
||||||
|
string testTokenValue2 = "125";
|
||||||
|
Token.Type testTokenType2 = Token.Type.Numeric;
|
||||||
|
Token.NumericType testNumericType2 = Token.NumericType.Integer;
|
||||||
|
uint testArityValue2 = 0;
|
||||||
|
|
||||||
|
Token token1 = new(testTokenValue, testTokenType, testNumericType, testArityValue);
|
||||||
|
Token token2 = new(testTokenValue2, testTokenType2, testNumericType2, testArityValue2);
|
||||||
|
|
||||||
|
int hash1 = token1.GetHashCode();
|
||||||
|
int hash2 = token2.GetHashCode();
|
||||||
|
Assert.AreNotEqual(hash1, hash2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
MathEngine/MathEngine/Parser/Nodes/BaseNode.cs
Normal file
114
MathEngine/MathEngine/Parser/Nodes/BaseNode.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MathEngine.Parser.Parser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract class representing a Node in a Tree structure
|
||||||
|
/// </summary>
|
||||||
|
internal abstract class BaseNode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to any child Nodes
|
||||||
|
/// </summary>
|
||||||
|
protected List<BaseNode>? Children;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base method for adding two nodes, returning another BaseNode object
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherNode">The node to be added to the current instance</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
protected virtual BaseNode Add(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Attempted to call BaseNode _add, which is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base operator for adding two Base Nodes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The left BaseNode</param>
|
||||||
|
/// <param name="rhs">The right BaseNode</param>
|
||||||
|
/// <returns>The addition of two BaseNodes, as defined by the calling type</returns>
|
||||||
|
public static BaseNode operator +(BaseNode lhs, BaseNode rhs)
|
||||||
|
{
|
||||||
|
return lhs.Add(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base method for subtracting two nodes, returning another BaseNode object
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherNode">The node to be subtract from the current instance</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
protected virtual BaseNode Subtract(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Attempted to call BaseNode Subtract, which is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base operator for subtracting two Base Nodes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The left BaseNode</param>
|
||||||
|
/// <param name="rhs">The right BaseNode</param>
|
||||||
|
/// <returns>The subtraction of two BaseNodes, as defined by the calling type</returns>
|
||||||
|
public static BaseNode operator -(BaseNode lhs, BaseNode rhs)
|
||||||
|
{
|
||||||
|
return lhs.Subtract(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base method for multiplying two nodes, returning another BaseNode object
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherNode">The node multiply the current instance by</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
protected virtual BaseNode Multiply(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Attempted to call BaseNode Multiply, which is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base operator for multiplying two Base Nodes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The left BaseNode</param>
|
||||||
|
/// <param name="rhs">The right BaseNode</param>
|
||||||
|
/// <returns>The product of two BaseNodes, as defined by the calling type</returns>
|
||||||
|
public static BaseNode operator *(BaseNode lhs, BaseNode rhs)
|
||||||
|
{
|
||||||
|
return lhs.Multiply(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base method for dividing two nodes, returning another BaseNode object
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherNode">The node which will divide the current instance</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
protected virtual BaseNode Divide(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Attempted to call BaseNode _add, which is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base operator for dividing two Base Nodes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The left BaseNode</param>
|
||||||
|
/// <param name="rhs">The right BaseNode</param>
|
||||||
|
/// <returns>The division of two BaseNodes, as defined by the calling type</returns>
|
||||||
|
public static BaseNode operator /(BaseNode lhs, BaseNode rhs)
|
||||||
|
{
|
||||||
|
return lhs.Divide(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract Base method that evaluates the current Node
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract BaseNode Evaluate();
|
||||||
|
}
|
||||||
|
}
|
||||||
36
MathEngine/MathEngine/Parser/Nodes/BinaryNode.cs
Normal file
36
MathEngine/MathEngine/Parser/Nodes/BinaryNode.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace MathEngine.Parser.Parser.Nodes
|
||||||
|
{
|
||||||
|
internal class BinaryNode:BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode left;
|
||||||
|
private BaseNode right;
|
||||||
|
private Func<BaseNode, BaseNode, BaseNode> op;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises A BinaryNode with the given left and right branches and the operation to perform
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The left branch</param>
|
||||||
|
/// <param name="right">The right branch</param>
|
||||||
|
/// <param name="op">The oepration to perform on evaluation</param>
|
||||||
|
public BinaryNode(BaseNode left, BaseNode right, Func<BaseNode, BaseNode, BaseNode> op)
|
||||||
|
{
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
this.op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evalutes the binary node based on the operator given
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override BaseNode Evaluate()
|
||||||
|
{
|
||||||
|
BaseNode lhs_val = this.left.Evaluate();
|
||||||
|
BaseNode rhs_val = this.right.Evaluate();
|
||||||
|
return op(lhs_val, rhs_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
MathEngine/MathEngine/Parser/Nodes/NodeFactory.cs
Normal file
56
MathEngine/MathEngine/Parser/Nodes/NodeFactory.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using MathEngine.Parser.Parser.Nodes;
|
||||||
|
using MathEngine.Parser.Tokeniser;
|
||||||
|
namespace MathEngine.Parser.Parser
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Factory that creates a TreeNode
|
||||||
|
/// </summary>
|
||||||
|
internal class NodeFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a binary TreeNode, that is a node with a root value and two children
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="CurrentToken">The token to be the root node of the TreeNode</param>
|
||||||
|
/// <param name="LeftToken">TreeNode that is the left branch of the current node</param>
|
||||||
|
/// <param name="RightToken">TreeNode that is the right branch of the current node</param>
|
||||||
|
/// <returns>A TreeNode with CurrentToken as the root value and LeftBranch and RightBranch as Children</returns>
|
||||||
|
public static BaseNode CreateBinaryNode(Token CurrentToken, BaseNode LeftBranch, BaseNode RightBranch)
|
||||||
|
{
|
||||||
|
switch (CurrentToken.Token_Type)
|
||||||
|
{
|
||||||
|
case Token.Type.Addition:
|
||||||
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a + b);
|
||||||
|
case Token.Type.Subtraction:
|
||||||
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a - b);
|
||||||
|
case Token.Type.Multiplication:
|
||||||
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a * b);
|
||||||
|
case Token.Type.Division:
|
||||||
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
||||||
|
case Token.Type.Exponentiation:
|
||||||
|
throw new NotImplementedException("Exponentiation is not implemented at this time");
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a Node that holds a numerical value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="CurrentToken">The token that holds the numeric value</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static BaseNode CreateNumericNode(Token CurrentToken)
|
||||||
|
{
|
||||||
|
switch (CurrentToken.NumericalType)
|
||||||
|
{
|
||||||
|
case Token.NumericType.Integer:
|
||||||
|
return new NumericNode<Int64>(Int64.Parse(CurrentToken.TokenValue));
|
||||||
|
case Token.NumericType.Decimal:
|
||||||
|
return new NumericNode<Decimal>(Decimal.Parse(CurrentToken.TokenValue));
|
||||||
|
case Token.NumericType.Complex:
|
||||||
|
throw new NotImplementedException("Complex Numbers are not implemented at this time");
|
||||||
|
default:
|
||||||
|
throw new InvalidDataException("Attempted to create a NumericNode with non numeric data!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
MathEngine/MathEngine/Parser/Nodes/NumericNode.cs
Normal file
77
MathEngine/MathEngine/Parser/Nodes/NumericNode.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace MathEngine.Parser.Parser.Nodes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Tree node that can store a numeric value
|
||||||
|
/// </summary>
|
||||||
|
internal class NumericNode<T> : BaseNode where T: INumber<T>
|
||||||
|
{
|
||||||
|
private readonly T Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises a new instance of a NumericNode with a given Token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The token for the nodes value</param>
|
||||||
|
public NumericNode(T value)
|
||||||
|
{
|
||||||
|
this.Children = null;
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BaseNode Add(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
if (otherNode is NumericNode<T>)
|
||||||
|
{
|
||||||
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
|
return new NumericNode<T>(Value + rhs.Value);
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BaseNode Subtract(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
if (otherNode is NumericNode<T>)
|
||||||
|
{
|
||||||
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
|
return new NumericNode<T>(Value - rhs.Value);
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BaseNode Multiply(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
if (otherNode is NumericNode<T>)
|
||||||
|
{
|
||||||
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
|
return new NumericNode<T>(Value * rhs.Value);
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BaseNode Divide(BaseNode otherNode)
|
||||||
|
{
|
||||||
|
if (otherNode is NumericNode<T>)
|
||||||
|
{
|
||||||
|
NumericNode<T> rhs = (NumericNode<T>)otherNode;
|
||||||
|
return new NumericNode<T>(Value / rhs.Value);
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Attempted Invalid operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates the Numeric Node by simply returning the current instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override BaseNode Evaluate()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user