diff --git a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs index 07ef88c9..62593f3d 100644 --- a/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs @@ -249,7 +249,7 @@ Expression ParseLambdaOperator() Expression ParseOrOperator() { Expression left = ParseAndOperator(); - while (_textParser.CurrentToken.Id == TokenId.DoubleBar || TokenIdentifierIs("Or") || TokenIdentifierIs("OrElse")) + while (_textParser.CurrentToken.Id == TokenId.DoubleBar) { Token op = _textParser.CurrentToken; _textParser.NextToken(); @@ -267,7 +267,7 @@ Expression ParseOrOperator() Expression ParseAndOperator() { Expression left = ParseIn(); - while (_textParser.CurrentToken.Id == TokenId.DoubleAmphersand || TokenIdentifierIs("And") || TokenIdentifierIs("AndAlso")) + while (_textParser.CurrentToken.Id == TokenId.DoubleAmphersand) { Token op = _textParser.CurrentToken; _textParser.NextToken(); diff --git a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs index 1fead975..e4c821eb 100644 --- a/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs +++ b/src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs @@ -11,20 +11,27 @@ internal class TextParser private static char[] EscapeCharacters = new[] { '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v' }; // These aliases are supposed to simply the where clause and make it more human readable - // As an addition it is compatible with the OData.Filter specification - private static readonly Dictionary _predefinedAliases = new Dictionary + private static readonly Dictionary _predefinedOperatorAliases = new Dictionary(StringComparer.OrdinalIgnoreCase) { - {"eq", TokenId.Equal}, - {"ne", TokenId.ExclamationEqual}, - {"neq", TokenId.ExclamationEqual}, - {"lt", TokenId.LessThan}, - {"le", TokenId.LessThanEqual}, - {"gt", TokenId.GreaterThan}, - {"ge", TokenId.GreaterThanEqual}, - {"and", TokenId.DoubleAmphersand}, - {"or", TokenId.DoubleBar}, - {"not", TokenId.Exclamation}, - {"mod", TokenId.Percent} + { "eq", TokenId.Equal }, + { "equal", TokenId.Equal }, + { "ne", TokenId.ExclamationEqual }, + { "notequal", TokenId.ExclamationEqual }, + { "neq", TokenId.ExclamationEqual }, + { "lt", TokenId.LessThan }, + { "LessThan", TokenId.LessThan }, + { "le", TokenId.LessThanEqual }, + { "LessThanEqual", TokenId.LessThanEqual }, + { "gt", TokenId.GreaterThan }, + { "GreaterThan", TokenId.GreaterThan }, + { "ge", TokenId.GreaterThanEqual }, + { "GreaterThanEqual", TokenId.GreaterThanEqual }, + { "and", TokenId.DoubleAmphersand }, + { "AndAlso", TokenId.DoubleAmphersand }, + { "or", TokenId.DoubleBar }, + { "OrElse", TokenId.DoubleBar }, + { "not", TokenId.Exclamation }, + { "mod", TokenId.Percent } }; private readonly string _text; @@ -451,7 +458,7 @@ private static Exception ParseError(int pos, string format, params object[] args private static TokenId GetAliasedTokenId(TokenId tokenId, string alias) { - return tokenId == TokenId.Identifier && _predefinedAliases.TryGetValue(alias, out TokenId id) ? id : tokenId; + return tokenId == TokenId.Identifier && _predefinedOperatorAliases.TryGetValue(alias, out TokenId id) ? id : tokenId; } private static bool IsHexChar(char c) diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs new file mode 100644 index 00000000..22118cf0 --- /dev/null +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/ExpressionParserTests.cs @@ -0,0 +1,73 @@ +using System.Linq.Dynamic.Core.Parser; +using System.Linq.Expressions; +using NFluent; +using Xunit; + +namespace System.Linq.Dynamic.Core.Tests.Parser +{ + public class ExpressionParserTests + { + [Theory] + [InlineData("it == 1", "(x == 1)")] + [InlineData("it eq 1", "(x == 1)")] + [InlineData("it equal 1", "(x == 1)")] + [InlineData("it != 1", "(x != 1)")] + [InlineData("it ne 1", "(x != 1)")] + [InlineData("it neq 1", "(x != 1)")] + [InlineData("it notequal 1", "(x != 1)")] + [InlineData("it lt 1", "(x < 1)")] + [InlineData("it LessThan 1", "(x < 1)")] + [InlineData("it le 1", "(x <= 1)")] + [InlineData("it LessThanEqual 1", "(x <= 1)")] + [InlineData("it gt 1", "(x > 1)")] + [InlineData("it GreaterThan 1", "(x > 1)")] + [InlineData("it ge 1", "(x >= 1)")] + [InlineData("it GreaterThanEqual 1", "(x >= 1)")] + public void Parse_ParseComparisonOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(int), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); + + // Act + var parsedExpression = sut.Parse(null).ToString(); + + // Assert + Check.That(parsedExpression).Equals(result); + } + + [Theory] + [InlineData("it || true", "(x OrElse True)")] + [InlineData("it or true", "(x OrElse True)")] + [InlineData("it OrElse true", "(x OrElse True)")] + public void Parse_ParseOrOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); + + // Act + var parsedExpression = sut.Parse(null).ToString(); + + // Assert + Check.That(parsedExpression).Equals(result); + } + + [Theory] + [InlineData("it && true", "(x AndAlso True)")] + [InlineData("it and true", "(x AndAlso True)")] + [InlineData("it AndAlso true", "(x AndAlso True)")] + public void Parse_ParseAndOperator(string expression, string result) + { + // Arrange + ParameterExpression[] parameters = { ParameterExpressionHelper.CreateParameterExpression(typeof(bool), "x") }; + var sut = new ExpressionParser(parameters, expression, null, null); + + // Act + var parsedExpression = sut.Parse(null).ToString(); + + // Assert + Check.That(parsedExpression).Equals(result); + } + } +}