Parser: Relations

This commit is contained in:
2019-12-02 02:39:32 +01:00
parent 99ca81a968
commit 4f3e5a325e
11 changed files with 396 additions and 5 deletions

View File

@@ -256,5 +256,73 @@ namespace VAR.ExpressionEvaluator.Tests
#endregion Strings #endregion Strings
#region Relations
[TestMethod()]
public void Relations_1GreatherThan2_EqualsFalse()
{
string expression = "1>2";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(false, result);
}
[TestMethod()]
public void Relations_1Equals1_EqualsTrue()
{
string expression = "1=1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(true, result);
}
[TestMethod()]
public void Relations_10NotEquals1_EqualsTrue()
{
string expression = "10!=1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(true, result);
}
[TestMethod()]
public void Relations_10LessThan1_EqualsFalse()
{
string expression = "10<1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(false, result);
}
[TestMethod()]
public void Relations_1GreaterOrEqualThan1_EqualsTrue()
{
string expression = "1>=1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(true, result);
}
[TestMethod()]
public void Relations_1LessOrEqualThan1_EqualsTrue()
{
string expression = "1<=1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(true, result);
}
[TestMethod()]
public void Relations_1GreaterOrEqualThan10_EqualsFalse()
{
string expression = "1>=10";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(false, result);
}
[TestMethod()]
public void Relations_10LessOrEqualThan1_EqualsFalse()
{
string expression = "10<=1";
object result = Parser.EvaluateString(expression);
Assert.AreEqual(false, result);
}
#endregion Relations
} }
} }

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionEqualsNode : ExpressionBinaryNode
{
public ExpressionEqualsNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, EqualsOp)
{
}
private static object EqualsOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) == 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't compare non decimal values");
}
return (decimal)leftValue == (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionGreaterOrEqualThanNode : ExpressionBinaryNode
{
public ExpressionGreaterOrEqualThanNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, GreaterOrEqualThanOp)
{
}
private static object GreaterOrEqualThanOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) >= 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't compare non decimal values");
}
return (decimal)leftValue >= (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionGreaterThanNode : ExpressionBinaryNode
{
public ExpressionGreaterThanNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, GreaterThanOp)
{
}
private static object GreaterThanOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) > 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't compare non decimal values");
}
return (decimal)leftValue > (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionLessOrEqualThanNode : ExpressionBinaryNode
{
public ExpressionLessOrEqualThanNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, LessOrEqualThanOp)
{
}
private static object LessOrEqualThanOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) <= 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't substract non decimal values");
}
return (decimal)leftValue <= (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionLessThanNode : ExpressionBinaryNode
{
public ExpressionLessThanNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, LessThanOp)
{
}
private static object LessThanOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) < 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't compare non decimal values");
}
return (decimal)leftValue < (decimal)rightValue;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionNotEqualsNode : ExpressionBinaryNode
{
public ExpressionNotEqualsNode(IExpressionNode leftNode, IExpressionNode rightNode) :
base(leftNode, rightNode, NotEqualsOp)
{
}
private static object NotEqualsOp(object leftValue, object rightValue)
{
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) != 0;
}
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
}
leftValue = dec;
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)rightValue));
}
rightValue = dec;
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't compare non decimal values");
}
return (decimal)leftValue != (decimal)rightValue;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace VAR.ExpressionEvaluator
public IExpressionNode ParseExpression() public IExpressionNode ParseExpression()
{ {
var expr = ParsePlusAndMinus(); var expr = ParseRelations();
if (_tokenizer.Token != Token.EOF) if (_tokenizer.Token != Token.EOF)
{ {
@@ -25,7 +25,55 @@ namespace VAR.ExpressionEvaluator
return expr; return expr;
} }
public IExpressionNode ParsePlusAndMinus() private IExpressionNode ParseRelations()
{
IExpressionNode leftNode = ParsePlusAndMinus();
while (true)
{
if (_tokenizer.Token == Token.Equals || _tokenizer.Token == Token.ExclusiveEquals)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionEqualsNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.NotEquals)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionNotEqualsNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.LessThan)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionLessThanNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.LessOrEqualThan)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionLessOrEqualThanNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.GreaterThan)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionGreaterThanNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.GreaterOrEqualThan)
{
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionGreaterOrEqualThanNode(leftNode, rightNode);
}
else
{
return leftNode;
}
}
}
private IExpressionNode ParsePlusAndMinus()
{ {
IExpressionNode leftNode = ParseMultiplyDivision(); IExpressionNode leftNode = ParseMultiplyDivision();
while (true) while (true)
@@ -155,7 +203,7 @@ namespace VAR.ExpressionEvaluator
if (_tokenizer.Token == Token.ParenthesisStart) if (_tokenizer.Token == Token.ParenthesisStart)
{ {
_tokenizer.NextToken(); _tokenizer.NextToken();
IExpressionNode node = ParsePlusAndMinus(); IExpressionNode node = ParseRelations();
if (_tokenizer.Token != Token.ParenthesisEnd) if (_tokenizer.Token != Token.ParenthesisEnd)
{ {
throw new Exception("Missing close parenthesis"); throw new Exception("Missing close parenthesis");

View File

@@ -7,14 +7,16 @@
Minus, Minus,
Division, Division,
Multiply, Multiply,
ParenthesisStart,
ParenthesisEnd,
Not,
NotEquals,
Equals, Equals,
ExclusiveEquals, ExclusiveEquals,
GreaterThan, GreaterThan,
GreaterOrEqualThan, GreaterOrEqualThan,
LessThan, LessThan,
LessOrEqualThan, LessOrEqualThan,
ParenthesisStart,
ParenthesisEnd,
Comma, Comma,
Identifier, Identifier,
String, String,

View File

@@ -101,6 +101,15 @@ namespace VAR.ExpressionEvaluator
_currentToken = Token.ParenthesisEnd; _currentToken = Token.ParenthesisEnd;
return; return;
case '!':
NextChar();
_currentToken = Token.Not;
if (_currentChar == '=')
{
NextChar();
_currentToken = Token.NotEquals;
}
return;
case '=': case '=':
NextChar(); NextChar();
_currentToken = Token.Equals; _currentToken = Token.Equals;

View File

@@ -44,8 +44,14 @@
<Compile Include="EvaluationContext.cs" /> <Compile Include="EvaluationContext.cs" />
<Compile Include="ExpressionNodes\ExpressionBooleanNode.cs" /> <Compile Include="ExpressionNodes\ExpressionBooleanNode.cs" />
<Compile Include="ExpressionNodes\ExpressionDivisionNode.cs" /> <Compile Include="ExpressionNodes\ExpressionDivisionNode.cs" />
<Compile Include="ExpressionNodes\ExpressionEqualsNode.cs" />
<Compile Include="ExpressionNodes\ExpressionFunctionNode.cs" /> <Compile Include="ExpressionNodes\ExpressionFunctionNode.cs" />
<Compile Include="ExpressionNodes\ExpressionGreaterOrEqualThanNode.cs" />
<Compile Include="ExpressionNodes\ExpressionGreaterThanNode.cs" />
<Compile Include="ExpressionNodes\ExpressionLessOrEqualThanNode.cs" />
<Compile Include="ExpressionNodes\ExpressionLessThanNode.cs" />
<Compile Include="ExpressionNodes\ExpressionMultiplyNode.cs" /> <Compile Include="ExpressionNodes\ExpressionMultiplyNode.cs" />
<Compile Include="ExpressionNodes\ExpressionNotEqualsNode.cs" />
<Compile Include="ExpressionNodes\ExpressionUnaryNode.cs" /> <Compile Include="ExpressionNodes\ExpressionUnaryNode.cs" />
<Compile Include="ExpressionNodes\ExpressionBinaryNode.cs" /> <Compile Include="ExpressionNodes\ExpressionBinaryNode.cs" />
<Compile Include="ExpressionNodes\ExpressionMinusNode.cs" /> <Compile Include="ExpressionNodes\ExpressionMinusNode.cs" />