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 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
} }
} }

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 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;
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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;
} }
} }
} }

View File

@@ -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;
} }
} }

View File

@@ -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()));
} }

View File

@@ -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" />