ExpressionEqualsNode: Rewrite to be less strict

This commit is contained in:
2021-09-28 20:24:14 +02:00
parent 57c5f677f5
commit 0440b418cb
4 changed files with 136 additions and 96 deletions

View File

@@ -547,6 +547,11 @@ namespace VAR.ExpressionEvaluator.Tests
Assert.False((bool?)Parser.EvaluateString("true and false")); Assert.False((bool?)Parser.EvaluateString("true and false"));
Assert.True((bool?)Parser.EvaluateString("true and true")); Assert.True((bool?)Parser.EvaluateString("true and true"));
Assert.False((bool?)Parser.EvaluateString("False And False"));
Assert.False((bool?)Parser.EvaluateString("False And True"));
Assert.False((bool?)Parser.EvaluateString("True And False"));
Assert.True((bool?)Parser.EvaluateString("True And True"));
Assert.False((bool?)Parser.EvaluateString("false && false")); Assert.False((bool?)Parser.EvaluateString("false && false"));
Assert.False((bool?)Parser.EvaluateString("false && true")); Assert.False((bool?)Parser.EvaluateString("false && true"));
Assert.False((bool?)Parser.EvaluateString("true && false")); Assert.False((bool?)Parser.EvaluateString("true && false"));
@@ -561,6 +566,11 @@ namespace VAR.ExpressionEvaluator.Tests
Assert.True((bool?)Parser.EvaluateString("true or false")); Assert.True((bool?)Parser.EvaluateString("true or false"));
Assert.True((bool?)Parser.EvaluateString("true or true")); Assert.True((bool?)Parser.EvaluateString("true or true"));
Assert.False((bool?)Parser.EvaluateString("False Or False"));
Assert.True((bool?)Parser.EvaluateString("False Or True"));
Assert.True((bool?)Parser.EvaluateString("True Or False"));
Assert.True((bool?)Parser.EvaluateString("True Or True"));
Assert.False((bool?)Parser.EvaluateString("false || false")); Assert.False((bool?)Parser.EvaluateString("false || false"));
Assert.True((bool?)Parser.EvaluateString("false || true")); Assert.True((bool?)Parser.EvaluateString("false || true"));
Assert.True((bool?)Parser.EvaluateString("true || false")); Assert.True((bool?)Parser.EvaluateString("true || false"));
@@ -577,7 +587,6 @@ namespace VAR.ExpressionEvaluator.Tests
Assert.False((bool?)Parser.EvaluateString("not true")); Assert.False((bool?)Parser.EvaluateString("not true"));
} }
#endregion BooleanOps #endregion BooleanOps
#region Null value #region Null value
@@ -621,6 +630,40 @@ namespace VAR.ExpressionEvaluator.Tests
#endregion #endregion
#region String coercions
[Fact()]
public void StringCoercions__Var1NullEqualsStringEmpty_EqualsTrue()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", null);
string expression = "v1 = \"\"";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.True((bool?)result);
}
[Fact()]
public void StringCoercions__Var1TrueStringEqualsTrue_EqualsTrue()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", "True");
string expression = "v1 = true";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.True((bool?)result);
}
[Fact()]
public void StringCoercions__Var1FalseStringEqualsFalse_EqualsTrue()
{
EvaluationContext evaluationContex = new EvaluationContext();
evaluationContex.SetVariable("v1", "False");
string expression = "v1 = false";
object result = Parser.EvaluateString(expression, evaluationContex);
Assert.True((bool?)result);
}
#endregion String coercions
#region Excepctions #region Excepctions
[Fact] [Fact]

View File

@@ -1,6 +1,4 @@
using System; namespace VAR.ExpressionEvaluator
namespace VAR.ExpressionEvaluator
{ {
public class ExpressionEqualsNode : ExpressionBinaryNode public class ExpressionEqualsNode : ExpressionBinaryNode
{ {
@@ -9,49 +7,17 @@ namespace VAR.ExpressionEvaluator
{ {
} }
private static object EqualsOp(object leftValue, object rightValue) public static object EqualsOp(object leftValue, object rightValue)
{ {
if (leftValue is string && rightValue is string) // Null
{ if (leftValue is string && string.IsNullOrEmpty(leftValue as string))
return string.Compare((string)leftValue, (string)rightValue) == 0;
}
if ((leftValue is string && rightValue == null) || (leftValue == null && rightValue is string))
{
return false;
}
if (leftValue is string)
{
if (string.IsNullOrEmpty((string)leftValue))
{ {
leftValue = null; leftValue = null;
} }
else if (rightValue is string && string.IsNullOrEmpty(rightValue as string))
{ {
if (decimal.TryParse((string)leftValue, out decimal dec) == false) rightValue = null;
{
throw new Exception(string.Format("Can't convert to decimal string value \"{0}\"", (string)leftValue));
} }
leftValue = dec;
}
}
if (rightValue is string)
{
if (string.IsNullOrEmpty((string)rightValue))
{
leftValue = null;
}
else
{
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 == null && rightValue == null) if (leftValue == null && rightValue == null)
{ {
return true; return true;
@@ -61,11 +27,85 @@ namespace VAR.ExpressionEvaluator
return false; return false;
} }
// String
if (leftValue is string && rightValue is string)
{
return string.Compare((string)leftValue, (string)rightValue) == 0;
}
// Bool
if (leftValue is bool || rightValue is bool)
{
bool? leftBool = ConvertToNullableBool(leftValue);
bool? rightBool = ConvertToNullableBool(rightValue);
return leftBool == rightBool;
}
// Decimal
if (leftValue is string)
{
if (decimal.TryParse((string)leftValue, out decimal dec) == false)
{
leftValue = null;
}
else
{
leftValue = dec;
}
}
if (rightValue is string)
{
if (decimal.TryParse((string)rightValue, out decimal dec) == false)
{
rightValue = null;
}
else
{
rightValue = dec;
}
}
if ((leftValue is decimal) == false || (rightValue is decimal) == false) if ((leftValue is decimal) == false || (rightValue is decimal) == false)
{ {
throw new Exception("Can't compare non decimal values"); return false;
} }
return (decimal)leftValue == (decimal)rightValue; return (decimal)leftValue == (decimal)rightValue;
} }
private static bool? ConvertToNullableBool(object value)
{
if (value is bool)
{
return (bool)value;
}
if (value is string)
{
string text = value as string;
if (string.IsNullOrEmpty(text))
{
return null;
}
decimal decValue;
if (decimal.TryParse(text, out decValue))
{
return decValue != 0;
}
string textLower = text.ToLower();
if (textLower == "false" || textLower == "no" || textLower == "ez" || textLower == "non" || textLower == "nein")
{
return false;
}
if (textLower == "true" || textLower == "si" || textLower == "sí" || textLower == "yes" || textLower == "bai" || textLower == "oui" || textLower == "ja")
{
return true;
}
return null;
}
if (value is decimal)
{
return ((decimal)value) != 0;
}
return false;
}
} }
} }

View File

@@ -1,6 +1,4 @@
using System; namespace VAR.ExpressionEvaluator
namespace VAR.ExpressionEvaluator
{ {
public class ExpressionNotEqualsNode : ExpressionBinaryNode public class ExpressionNotEqualsNode : ExpressionBinaryNode
{ {
@@ -11,56 +9,8 @@ namespace VAR.ExpressionEvaluator
private static object NotEqualsOp(object leftValue, object rightValue) private static object NotEqualsOp(object leftValue, object rightValue)
{ {
if (leftValue is string && rightValue is string) bool result = (bool)ExpressionEqualsNode.EqualsOp(leftValue, rightValue);
{ return !result;
return string.Compare((string)leftValue, (string)rightValue) != 0;
}
if (leftValue is string)
{
if (string.IsNullOrEmpty((string)leftValue))
{
leftValue = null;
}
else
{
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 (string.IsNullOrEmpty((string)rightValue))
{
leftValue = null;
}
else
{
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 == null && rightValue == null)
{
return false;
}
if (leftValue == null || rightValue == null)
{
return true;
}
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

@@ -84,6 +84,13 @@ namespace VAR.ExpressionEvaluator
IExpressionNode rightNode = ParsePlusAndMinus(); IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionEqualsNode(leftNode, rightNode); leftNode = new ExpressionEqualsNode(leftNode, rightNode);
} }
if (_tokenizer.Token == Token.ExclusiveEquals)
{
// TODO: Implement ExpressionExclusiveEqualsNode
_tokenizer.NextToken();
IExpressionNode rightNode = ParsePlusAndMinus();
leftNode = new ExpressionEqualsNode(leftNode, rightNode);
}
else if (_tokenizer.Token == Token.NotEquals) else if (_tokenizer.Token == Token.NotEquals)
{ {
_tokenizer.NextToken(); _tokenizer.NextToken();