Parser and ExpressionNodes operate with the 3 types (decimal, string, bool)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace VAR.ExpressionEvaluator.Tests
|
namespace VAR.ExpressionEvaluator.Tests
|
||||||
@@ -152,8 +153,8 @@ namespace VAR.ExpressionEvaluator.Tests
|
|||||||
public void Variables__Var1PlusVar2()
|
public void Variables__Var1PlusVar2()
|
||||||
{
|
{
|
||||||
EvaluationContext evaluationContex = new EvaluationContext();
|
EvaluationContext evaluationContex = new EvaluationContext();
|
||||||
evaluationContex.SetVariable("v1", 1m);
|
evaluationContex.SetVariable("v1", 1);
|
||||||
evaluationContex.SetVariable("v2", 1m);
|
evaluationContex.SetVariable("v2", 1);
|
||||||
string expression = "v1 + v2";
|
string expression = "v1 + v2";
|
||||||
object result = Parser.EvaluateString(expression, evaluationContex);
|
object result = Parser.EvaluateString(expression, evaluationContex);
|
||||||
Assert.AreEqual(2m, result);
|
Assert.AreEqual(2m, result);
|
||||||
@@ -163,8 +164,8 @@ namespace VAR.ExpressionEvaluator.Tests
|
|||||||
public void Variables__Var1MultiplyVar2()
|
public void Variables__Var1MultiplyVar2()
|
||||||
{
|
{
|
||||||
EvaluationContext evaluationContex = new EvaluationContext();
|
EvaluationContext evaluationContex = new EvaluationContext();
|
||||||
evaluationContex.SetVariable("v1", 10m);
|
evaluationContex.SetVariable("v1", 10);
|
||||||
evaluationContex.SetVariable("v2", 5m);
|
evaluationContex.SetVariable("v2", 5);
|
||||||
string expression = "v1 * v2";
|
string expression = "v1 * v2";
|
||||||
object result = Parser.EvaluateString(expression, evaluationContex);
|
object result = Parser.EvaluateString(expression, evaluationContex);
|
||||||
Assert.AreEqual(50m, result);
|
Assert.AreEqual(50m, result);
|
||||||
@@ -189,5 +190,71 @@ namespace VAR.ExpressionEvaluator.Tests
|
|||||||
|
|
||||||
#endregion Functions
|
#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
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
VAR.ExpressionEvaluator/ExpressionBooleanNode.cs
Normal file
17
VAR.ExpressionEvaluator/ExpressionBooleanNode.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace VAR.ExpressionEvaluator
|
using System;
|
||||||
|
|
||||||
|
namespace VAR.ExpressionEvaluator
|
||||||
{
|
{
|
||||||
public class ExpressionDivisionNode : ExpressionBinaryNode
|
public class ExpressionDivisionNode : ExpressionBinaryNode
|
||||||
{
|
{
|
||||||
@@ -9,6 +11,27 @@
|
|||||||
|
|
||||||
private static object DivisionOp(object leftValue, object rightValue)
|
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;
|
return (decimal)leftValue / (decimal)rightValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace VAR.ExpressionEvaluator
|
using System;
|
||||||
|
|
||||||
|
namespace VAR.ExpressionEvaluator
|
||||||
{
|
{
|
||||||
public class ExpressionMinusNode : ExpressionBinaryNode
|
public class ExpressionMinusNode : ExpressionBinaryNode
|
||||||
{
|
{
|
||||||
@@ -9,6 +11,27 @@
|
|||||||
|
|
||||||
private static object MinusOp(object leftValue, object rightValue)
|
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;
|
return (decimal)leftValue - (decimal)rightValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace VAR.ExpressionEvaluator
|
using System;
|
||||||
|
|
||||||
|
namespace VAR.ExpressionEvaluator
|
||||||
{
|
{
|
||||||
public class ExpressionMultiplyNode : ExpressionBinaryNode
|
public class ExpressionMultiplyNode : ExpressionBinaryNode
|
||||||
{
|
{
|
||||||
@@ -9,6 +11,27 @@
|
|||||||
|
|
||||||
private static object MultiplyOp(object leftValue, object rightValue)
|
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;
|
return (decimal)leftValue * (decimal)rightValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace VAR.ExpressionEvaluator
|
using System;
|
||||||
|
|
||||||
|
namespace VAR.ExpressionEvaluator
|
||||||
{
|
{
|
||||||
public class ExpressionNumberNegateNode : ExpressionUnaryNode
|
public class ExpressionNumberNegateNode : ExpressionUnaryNode
|
||||||
{
|
{
|
||||||
@@ -9,7 +11,20 @@
|
|||||||
|
|
||||||
private static object NumberNegateOp(object value)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace VAR.ExpressionEvaluator
|
using System;
|
||||||
|
|
||||||
|
namespace VAR.ExpressionEvaluator
|
||||||
{
|
{
|
||||||
public class ExpressionPlusNode : ExpressionBinaryNode
|
public class ExpressionPlusNode : ExpressionBinaryNode
|
||||||
{
|
{
|
||||||
@@ -9,6 +11,15 @@
|
|||||||
|
|
||||||
private static object PlusOp(object leftValue, object rightValue)
|
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;
|
return (decimal)leftValue + (decimal)rightValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,20 +99,27 @@ namespace VAR.ExpressionEvaluator
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tokenizer.Token == Token.ParenthesisStart)
|
if (_tokenizer.Token == Token.String)
|
||||||
{
|
{
|
||||||
_tokenizer.NextToken();
|
IExpressionNode node = new ExpressionStringNode(_tokenizer.Text);
|
||||||
IExpressionNode node = ParsePlusAndMinus();
|
|
||||||
if (_tokenizer.Token != Token.ParenthesisEnd)
|
|
||||||
{
|
|
||||||
throw new Exception("Missing close parenthesis");
|
|
||||||
}
|
|
||||||
_tokenizer.NextToken();
|
_tokenizer.NextToken();
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_tokenizer.Token == Token.Identifier)
|
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;
|
string identifier = _tokenizer.Text;
|
||||||
_tokenizer.NextToken();
|
_tokenizer.NextToken();
|
||||||
if (_tokenizer.Token != Token.ParenthesisStart)
|
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()));
|
throw new Exception(string.Format("Unexpected token: {0}", _tokenizer.Token.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="EvaluationContext.cs" />
|
<Compile Include="EvaluationContext.cs" />
|
||||||
|
<Compile Include="ExpressionBooleanNode.cs" />
|
||||||
<Compile Include="ExpressionDivisionNode.cs" />
|
<Compile Include="ExpressionDivisionNode.cs" />
|
||||||
<Compile Include="ExpressionFunctionNode.cs" />
|
<Compile Include="ExpressionFunctionNode.cs" />
|
||||||
<Compile Include="ExpressionMultiplyNode.cs" />
|
<Compile Include="ExpressionMultiplyNode.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user