Parser: Boolean operations
This commit is contained in:
@@ -324,5 +324,48 @@ namespace VAR.ExpressionEvaluator.Tests
|
||||
|
||||
#endregion Relations
|
||||
|
||||
#region BooleanOps
|
||||
|
||||
[TestMethod()]
|
||||
public void BooleanOps_And()
|
||||
{
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false and false"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false and true"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("true and false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true and true"));
|
||||
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false && false"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false && true"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("true && false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true && true"));
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void BooleanOps_Or()
|
||||
{
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false or false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("false or true"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true or false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true or true"));
|
||||
|
||||
Assert.AreEqual(false, Parser.EvaluateString("false || false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("false || true"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true || false"));
|
||||
Assert.AreEqual(true, Parser.EvaluateString("true || true"));
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void BooleanOps_Not()
|
||||
{
|
||||
Assert.AreEqual(true, Parser.EvaluateString("!false"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("!true"));
|
||||
|
||||
Assert.AreEqual(true, Parser.EvaluateString("not false"));
|
||||
Assert.AreEqual(false, Parser.EvaluateString("not true"));
|
||||
}
|
||||
|
||||
|
||||
#endregion BooleanOps
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace VAR.ExpressionEvaluator
|
||||
{
|
||||
public class ExpressionBooleanAndNode : ExpressionBinaryNode
|
||||
{
|
||||
public ExpressionBooleanAndNode(IExpressionNode leftNode, IExpressionNode rightNode) :
|
||||
base(leftNode, rightNode, BooleanAndOp)
|
||||
{
|
||||
}
|
||||
|
||||
private static object BooleanAndOp(object leftValue, object rightValue)
|
||||
{
|
||||
bool bLeftValue = ExpressionBooleanNode.ConvertToBoolean(leftValue);
|
||||
bool brightValue = ExpressionBooleanNode.ConvertToBoolean(rightValue);
|
||||
return bLeftValue && brightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,5 +13,30 @@
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public static bool ConvertToBoolean(object value)
|
||||
{
|
||||
if (value is bool)
|
||||
{
|
||||
return (bool)value;
|
||||
}
|
||||
if (value is decimal)
|
||||
{
|
||||
return (decimal)value == 0;
|
||||
}
|
||||
if (value is string)
|
||||
{
|
||||
string str = (string)value;
|
||||
if (string.IsNullOrEmpty(str) || str == "0" || str.ToLower() == "false")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace VAR.ExpressionEvaluator
|
||||
{
|
||||
public class ExpressionBooleanNotNode : ExpressionUnaryNode
|
||||
{
|
||||
public ExpressionBooleanNotNode(IExpressionNode node) :
|
||||
base(node, BooleanNotOp)
|
||||
{
|
||||
}
|
||||
|
||||
private static object BooleanNotOp(object value)
|
||||
{
|
||||
value = ExpressionBooleanNode.ConvertToBoolean(value);
|
||||
return !(bool)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace VAR.ExpressionEvaluator
|
||||
{
|
||||
public class ExpressionBooleanOrNode : ExpressionBinaryNode
|
||||
{
|
||||
public ExpressionBooleanOrNode(IExpressionNode leftNode, IExpressionNode rightNode) :
|
||||
base(leftNode, rightNode, BooleanOrOp)
|
||||
{
|
||||
}
|
||||
|
||||
private static object BooleanOrOp(object leftValue, object rightValue)
|
||||
{
|
||||
bool bLeftValue = ExpressionBooleanNode.ConvertToBoolean(leftValue);
|
||||
bool brightValue = ExpressionBooleanNode.ConvertToBoolean(rightValue);
|
||||
return bLeftValue || brightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace VAR.ExpressionEvaluator
|
||||
|
||||
public IExpressionNode ParseExpression()
|
||||
{
|
||||
var expr = ParseRelations();
|
||||
var expr = ParseBooleanOp();
|
||||
|
||||
if (_tokenizer.Token != Token.EOF)
|
||||
{
|
||||
@@ -25,6 +25,36 @@ namespace VAR.ExpressionEvaluator
|
||||
return expr;
|
||||
}
|
||||
|
||||
private IExpressionNode ParseBooleanOp()
|
||||
{
|
||||
if (_tokenizer.Token == Token.Not)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
var node = ParseBooleanOp();
|
||||
return new ExpressionBooleanNotNode(node);
|
||||
}
|
||||
IExpressionNode leftNode = ParseRelations();
|
||||
while (true)
|
||||
{
|
||||
if (_tokenizer.Token == Token.And)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
IExpressionNode rightNode = ParseRelations();
|
||||
leftNode = new ExpressionBooleanAndNode(leftNode, rightNode);
|
||||
}
|
||||
if (_tokenizer.Token == Token.Or)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
IExpressionNode rightNode = ParseRelations();
|
||||
leftNode = new ExpressionBooleanOrNode(leftNode, rightNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return leftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IExpressionNode ParseRelations()
|
||||
{
|
||||
IExpressionNode leftNode = ParsePlusAndMinus();
|
||||
@@ -99,20 +129,20 @@ namespace VAR.ExpressionEvaluator
|
||||
|
||||
private IExpressionNode ParseMultiplyDivision()
|
||||
{
|
||||
IExpressionNode lhs = ParseUnary();
|
||||
IExpressionNode lhs = ParseNumericSign();
|
||||
while (true)
|
||||
{
|
||||
if (_tokenizer.Token == Token.Multiply)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
IExpressionNode rhs = ParseUnary();
|
||||
IExpressionNode rhs = ParseNumericSign();
|
||||
lhs = new ExpressionMultiplyNode(lhs, rhs);
|
||||
|
||||
}
|
||||
else if (_tokenizer.Token == Token.Division)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
IExpressionNode rhs = ParseUnary();
|
||||
IExpressionNode rhs = ParseNumericSign();
|
||||
lhs = new ExpressionDivisionNode(lhs, rhs);
|
||||
}
|
||||
else
|
||||
@@ -122,17 +152,17 @@ namespace VAR.ExpressionEvaluator
|
||||
}
|
||||
}
|
||||
|
||||
private IExpressionNode ParseUnary()
|
||||
private IExpressionNode ParseNumericSign()
|
||||
{
|
||||
if (_tokenizer.Token == Token.Plus)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
return ParseUnary();
|
||||
return ParseNumericSign();
|
||||
}
|
||||
if (_tokenizer.Token == Token.Minus)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
var node = ParseUnary();
|
||||
var node = ParseNumericSign();
|
||||
return new ExpressionNumberNegateNode(node);
|
||||
}
|
||||
return ParseTerminus();
|
||||
@@ -203,7 +233,7 @@ namespace VAR.ExpressionEvaluator
|
||||
if (_tokenizer.Token == Token.ParenthesisStart)
|
||||
{
|
||||
_tokenizer.NextToken();
|
||||
IExpressionNode node = ParseRelations();
|
||||
IExpressionNode node = ParseBooleanOp();
|
||||
if (_tokenizer.Token != Token.ParenthesisEnd)
|
||||
{
|
||||
throw new Exception("Missing close parenthesis");
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
GreaterOrEqualThan,
|
||||
LessThan,
|
||||
LessOrEqualThan,
|
||||
And,
|
||||
Or,
|
||||
Comma,
|
||||
Identifier,
|
||||
String,
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace VAR.ExpressionEvaluator
|
||||
_currentToken = Token.NotEquals;
|
||||
}
|
||||
return;
|
||||
|
||||
case '=':
|
||||
NextChar();
|
||||
_currentToken = Token.Equals;
|
||||
@@ -124,6 +125,7 @@ namespace VAR.ExpressionEvaluator
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
case '>':
|
||||
NextChar();
|
||||
_currentToken = Token.GreaterThan;
|
||||
@@ -144,6 +146,24 @@ namespace VAR.ExpressionEvaluator
|
||||
}
|
||||
return;
|
||||
|
||||
case '&':
|
||||
NextChar();
|
||||
_currentToken = Token.And;
|
||||
while (_currentChar == '&')
|
||||
{
|
||||
NextChar();
|
||||
}
|
||||
return;
|
||||
|
||||
case '|':
|
||||
NextChar();
|
||||
_currentToken = Token.Or;
|
||||
while (_currentChar == '|')
|
||||
{
|
||||
NextChar();
|
||||
}
|
||||
return;
|
||||
|
||||
case ',':
|
||||
NextChar();
|
||||
_currentToken = Token.Comma;
|
||||
@@ -161,7 +181,23 @@ namespace VAR.ExpressionEvaluator
|
||||
if (_currentChar == '\0') { break; }
|
||||
}
|
||||
_text = sb.ToString();
|
||||
string textLowercase = _text.ToLower();
|
||||
if (textLowercase == "and")
|
||||
{
|
||||
_currentToken = Token.And;
|
||||
}
|
||||
else if (textLowercase == "or")
|
||||
{
|
||||
_currentToken = Token.Or;
|
||||
}
|
||||
else if (textLowercase == "not")
|
||||
{
|
||||
_currentToken = Token.Not;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentToken = Token.Identifier;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="EvaluationContext.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionBooleanAndNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionBooleanNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionBooleanNotNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionBooleanOrNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionDivisionNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionEqualsNode.cs" />
|
||||
<Compile Include="ExpressionNodes\ExpressionFunctionNode.cs" />
|
||||
|
||||
Reference in New Issue
Block a user