Parser and ExpressionNodes operate with the 3 types (decimal, string, bool)

This commit is contained in:
2019-12-02 02:10:36 +01:00
parent 071a6d8d43
commit a49655ed1d
9 changed files with 216 additions and 17 deletions

View File

@@ -1,4 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
namespace VAR.ExpressionEvaluator.Tests
@@ -152,8 +153,8 @@ namespace VAR.ExpressionEvaluator.Tests
public void Variables__Var1PlusVar2()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", 1m);
evaluationContex.SetVariable("v2", 1m);
evaluationContex.SetVariable("v1", 1);
evaluationContex.SetVariable("v2", 1);
string expression = "v1 + v2";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.AreEqual(2m, result);
@@ -163,8 +164,8 @@ namespace VAR.ExpressionEvaluator.Tests
public void Variables__Var1MultiplyVar2()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", 10m);
evaluationContex.SetVariable("v2", 5m);
evaluationContex.SetVariable("v1", 10);
evaluationContex.SetVariable("v2", 5);
string expression = "v1 * v2";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.AreEqual(50m, result);
@@ -189,5 +190,71 @@ namespace VAR.ExpressionEvaluator.Tests
#endregion Functions
#region Strings
[TestMethod()]
public void Strings__Contatenate_Hello_World()
{
string expression = "\"Hello\" + ' ' +\"World\"";
object result = Parser.EvaluateString(expression);
Assert.AreEqual("Hello World", result);
}
[TestMethod()]
public void Strings__Contatenate_Hello_World_WithVariables()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", "Hello");
evaluationContex.SetVariable("v2", " ");
evaluationContex.SetVariable("v3", "World");
string expression = "v1 + v2 + v3";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.AreEqual("Hello World", result);
}
[TestMethod()]
public void Strings__Fail_Minus()
{
string expression = "'Hello' - 'World'";
try
{
object result = Parser.EvaluateString(expression);
Assert.Fail();
}
catch (Exception)
{
}
}
[TestMethod()]
public void Strings__Fail_Multiply()
{
string expression = "'Hello' * 'World'";
try
{
object result = Parser.EvaluateString(expression);
Assert.Fail();
}
catch (Exception)
{
}
}
[TestMethod()]
public void Strings__Fail_Division()
{
string expression = "'Hello' / 'World'";
try
{
object result = Parser.EvaluateString(expression);
Assert.Fail();
}
catch (Exception)
{
}
}
#endregion Strings
}
}

View File

@@ -0,0 +1,17 @@
namespace VAR.ExpressionEvaluator
{
public class ExpressionBooleanNode : IExpressionNode
{
private bool _value;
public ExpressionBooleanNode(bool value)
{
_value = value;
}
public object Eval(IEvaluationContext evaluationContext)
{
return _value;
}
}
}

View File

@@ -1,4 +1,6 @@
namespace VAR.ExpressionEvaluator
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionDivisionNode : ExpressionBinaryNode
{
@@ -9,6 +11,27 @@
private static object DivisionOp(object leftValue, object rightValue)
{
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 divive non decimal values");
}
return (decimal)leftValue / (decimal)rightValue;
}
}

View File

@@ -1,4 +1,6 @@
namespace VAR.ExpressionEvaluator
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionMinusNode : ExpressionBinaryNode
{
@@ -9,6 +11,27 @@
private static object MinusOp(object leftValue, object rightValue)
{
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

@@ -1,4 +1,6 @@
namespace VAR.ExpressionEvaluator
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionMultiplyNode : ExpressionBinaryNode
{
@@ -9,6 +11,27 @@
private static object MultiplyOp(object leftValue, object rightValue)
{
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 multiply non decimal values");
}
return (decimal)leftValue * (decimal)rightValue;
}
}

View File

@@ -1,4 +1,6 @@
namespace VAR.ExpressionEvaluator
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionNumberNegateNode : ExpressionUnaryNode
{
@@ -9,7 +11,20 @@
private static object NumberNegateOp(object value)
{
return - (decimal)value;
if (value is string)
{
if (decimal.TryParse((string)value, out decimal dec) == false)
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)value));
}
value = dec;
}
if ((value is decimal) == false)
{
throw new Exception("Can't negate non decimal values");
}
return -(decimal)value;
}
}
}

View File

@@ -1,4 +1,6 @@
namespace VAR.ExpressionEvaluator
using System;
namespace VAR.ExpressionEvaluator
{
public class ExpressionPlusNode : ExpressionBinaryNode
{
@@ -9,6 +11,15 @@
private static object PlusOp(object leftValue, object rightValue)
{
if (leftValue is string || rightValue is string)
{
return string.Concat(Convert.ToString(leftValue), Convert.ToString(rightValue));
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{
throw new Exception("Can't sum non decimal values");
}
return (decimal)leftValue + (decimal)rightValue;
}
}

View File

@@ -99,20 +99,27 @@ namespace VAR.ExpressionEvaluator
return node;
}
if (_tokenizer.Token == Token.ParenthesisStart)
if (_tokenizer.Token == Token.String)
{
_tokenizer.NextToken();
IExpressionNode node = ParsePlusAndMinus();
if (_tokenizer.Token != Token.ParenthesisEnd)
{
throw new Exception("Missing close parenthesis");
}
IExpressionNode node = new ExpressionStringNode(_tokenizer.Text);
_tokenizer.NextToken();
return node;
}
if (_tokenizer.Token == Token.Identifier)
{
string identifierToLower = _tokenizer.Text.ToLower();
if (identifierToLower == "true")
{
_tokenizer.NextToken();
return new ExpressionBooleanNode(true);
}
if (identifierToLower == "false")
{
_tokenizer.NextToken();
return new ExpressionBooleanNode(false);
}
string identifier = _tokenizer.Text;
_tokenizer.NextToken();
if (_tokenizer.Token != Token.ParenthesisStart)
@@ -145,6 +152,18 @@ namespace VAR.ExpressionEvaluator
}
}
if (_tokenizer.Token == Token.ParenthesisStart)
{
_tokenizer.NextToken();
IExpressionNode node = ParsePlusAndMinus();
if (_tokenizer.Token != Token.ParenthesisEnd)
{
throw new Exception("Missing close parenthesis");
}
_tokenizer.NextToken();
return node;
}
throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString()));
}

View File

@@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="EvaluationContext.cs" />
<Compile Include="ExpressionBooleanNode.cs" />
<Compile Include="ExpressionDivisionNode.cs" />
<Compile Include="ExpressionFunctionNode.cs" />
<Compile Include="ExpressionMultiplyNode.cs" />