diff --git a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs index c8d7c5d1..0059fde6 100644 --- a/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs +++ b/src/System.Linq.Dynamic.Core/Parser/NumberParser.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Linq.Dynamic.Core.Exceptions; using System.Linq.Dynamic.Core.Validation; using System.Linq.Expressions; @@ -161,19 +161,34 @@ public Expression ParseIntegerLiteral(int tokenPosition, string text) /// public Expression ParseRealLiteral(string text, char qualifier, bool stripQualifier) { + if (stripQualifier) + { + var pos = text.Length - 1; + while (pos >= 0 && Qualifiers.Contains(text[pos])) + { + pos--; + } + + if (pos < text.Length - 1) + { + qualifier = text[pos + 1]; + text = text.Substring(0, pos + 1); + } + } + switch (qualifier) { case 'f': case 'F': - return _constantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(float))!, text); + return _constantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(float))!, text); case 'm': case 'M': - return _constantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(decimal))!, text); + return _constantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(decimal))!, text); case 'd': case 'D': - return _constantExpressionHelper.CreateLiteral(ParseNumber(stripQualifier ? text.Substring(0, text.Length - 1) : text, typeof(double))!, text); + return _constantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double))!, text); default: return _constantExpressionHelper.CreateLiteral(ParseNumber(text, typeof(double))!, text); @@ -298,4 +313,4 @@ private Expression ParseAsBinary(int tokenPosition, string text, bool isNegative throw new ParseException(string.Format(_culture, Res.InvalidBinaryIntegerLiteral, text), tokenPosition); } } -} \ No newline at end of file +} diff --git a/test/System.Linq.Dynamic.Core.Tests/Parser/NumberParserTests.cs b/test/System.Linq.Dynamic.Core.Tests/Parser/NumberParserTests.cs index 1bfa69a3..0db7404a 100644 --- a/test/System.Linq.Dynamic.Core.Tests/Parser/NumberParserTests.cs +++ b/test/System.Linq.Dynamic.Core.Tests/Parser/NumberParserTests.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using System.Collections.Generic; using System.Globalization; using System.Linq.Dynamic.Core.Parser; @@ -15,15 +15,15 @@ public static object[][] Decimals() { return new object[][] { - new object[] { "de-DE", "1", 1m }, - new object[] { "de-DE", "-42", -42m }, - new object[] { "de-DE", "3,215", 3.215m }, - new object[] { "de-DE", "3.215", 3215m }, - - new object[] { null, "1", 1m }, - new object[] { null, "-42", -42m }, - new object[] { null, "3,215", 3215m }, - new object[] { null, "3.215", 3.215m } + new object[] {"de-DE", "1", 1m}, + new object[] {"de-DE", "-42", -42m}, + new object[] {"de-DE", "3,215", 3.215m}, + new object[] {"de-DE", "3.215", 3215m}, + + new object[] {null, "1", 1m}, + new object[] {null, "-42", -42m}, + new object[] {null, "3,215", 3215m}, + new object[] {null, "3.215", 3.215m} }; } @@ -48,23 +48,23 @@ public static object[][] Floats() { return new object[][] { - new object[] { "de-DE", "1", 1f }, - new object[] { "de-DE", "-42", -42f }, - new object[] { "de-DE", "3,215", 3.215f }, - new object[] { "de-DE", "3.215", 3215f }, - new object[] { "de-DE", "1,2345E-4", 0.00012345f }, - new object[] { "de-DE", "1,2345e-4", 0.00012345f }, - new object[] { "de-DE", "1,2345E4", 12345d }, - new object[] { "de-DE", "1,2345e4", 12345d }, - - new object[] { null, "1", 1f }, - new object[] { null, "-42", -42f }, - new object[] { null, "3,215", 3215f }, - new object[] { null, "3.215", 3.215f }, - new object[] { null, "1.2345E-4", 0.00012345f }, - new object[] { null, "1.2345e-4", 0.00012345f }, - new object[] { null, "1.2345E4", 12345f }, - new object[] { null, "1.2345e4", 12345f } + new object[] {"de-DE", "1", 1f}, + new object[] {"de-DE", "-42", -42f}, + new object[] {"de-DE", "3,215", 3.215f}, + new object[] {"de-DE", "3.215", 3215f}, + new object[] {"de-DE", "1,2345E-4", 0.00012345f}, + new object[] {"de-DE", "1,2345e-4", 0.00012345f}, + new object[] {"de-DE", "1,2345E4", 12345d}, + new object[] {"de-DE", "1,2345e4", 12345d}, + + new object[] {null, "1", 1f}, + new object[] {null, "-42", -42f}, + new object[] {null, "3,215", 3215f}, + new object[] {null, "3.215", 3.215f}, + new object[] {null, "1.2345E-4", 0.00012345f}, + new object[] {null, "1.2345e-4", 0.00012345f}, + new object[] {null, "1.2345E4", 12345f}, + new object[] {null, "1.2345e4", 12345f} }; } @@ -89,23 +89,23 @@ public static IEnumerable Doubles() { return new object[][] { - new object[] { "de-DE", "1", 1d }, - new object[] { "de-DE", "-42", -42d }, - new object[] { "de-DE", "3,215", 3.215d }, - new object[] { "de-DE", "3.215", 3215d }, - new object[] { "de-DE", "1,2345E-4", 0.00012345d }, - new object[] { "de-DE", "1,2345e-4", 0.00012345d }, - new object[] { "de-DE", "1,2345E4", 12345d }, - new object[] { "de-DE", "1,2345e4", 12345d }, - - new object[] { null, "1", 1d }, - new object[] { null, "-42", -42d }, - new object[] { null, "3,215", 3215d }, - new object[] { null, "3.215", 3.215d }, - new object[] { null, "1.2345E-4", 0.00012345d }, - new object[] { null, "1.2345e-4", 0.00012345d }, - new object[] { null, "1.2345E4", 12345d }, - new object[] { null, "1.2345e4", 12345d } + new object[] {"de-DE", "1", 1d}, + new object[] {"de-DE", "-42", -42d}, + new object[] {"de-DE", "3,215", 3.215d}, + new object[] {"de-DE", "3.215", 3215d}, + new object[] {"de-DE", "1,2345E-4", 0.00012345d}, + new object[] {"de-DE", "1,2345e-4", 0.00012345d}, + new object[] {"de-DE", "1,2345E4", 12345d}, + new object[] {"de-DE", "1,2345e4", 12345d}, + + new object[] {null, "1", 1d}, + new object[] {null, "-42", -42d}, + new object[] {null, "3,215", 3215d}, + new object[] {null, "3.215", 3.215d}, + new object[] {null, "1.2345E-4", 0.00012345d}, + new object[] {null, "1.2345e-4", 0.00012345d}, + new object[] {null, "1.2345E4", 12345d}, + new object[] {null, "1.2345e4", 12345d} }; } @@ -152,5 +152,53 @@ public void NumberParser_ParseIntegerLiteral(string text, double expected) // Assert result.Value.Should().Be(expected); } + + [Theory] + [InlineData("42", 'm', 42)] + [InlineData("-42", 'm', -42)] + [InlineData("42m", 'm', 42)] + [InlineData("-42m", 'm', -42)] + public void NumberParser_ParseDecimalLiteral(string text, char qualifier, decimal expected) + { + // Arrange + + // Act + var result = new NumberParser(_parsingConfig).ParseRealLiteral(text, qualifier, true) as ConstantExpression; + + // Assert + result!.Value.Should().Be(expected); + } + + [Theory] + [InlineData("42", 'd', 42)] + [InlineData("-42", 'd', -42)] + [InlineData("42d", 'd', 42)] + [InlineData("-42d", 'd', -42)] + public void NumberParser_ParseDoubleLiteral(string text, char qualifier, double expected) + { + // Arrange + + // Act + var result = new NumberParser(_parsingConfig).ParseRealLiteral(text, qualifier, true) as ConstantExpression; + + // Assert + result!.Value.Should().Be(expected); + } + + [Theory] + [InlineData("42", 'f', 42)] + [InlineData("-42", 'f', -42)] + [InlineData("42f", 'f', 42)] + [InlineData("-42f", 'f', -42)] + public void NumberParser_ParseFloatLiteral(string text, char qualifier, float expected) + { + // Arrange + + // Act + var result = new NumberParser(_parsingConfig).ParseRealLiteral(text, qualifier, true) as ConstantExpression; + + // Assert + result!.Value.Should().Be(expected); + } } }