Skip to content

Commit ab249d4

Browse files
pferrarisStefH
authored andcommitted
Adds support for decimal qualifiers. Resolves #91 (#92)
* Adds support for decimal qualifiers * Adds tests for improve code coverage * Tests ordered alphabetically
1 parent cbb3900 commit ab249d4

File tree

5 files changed

+100
-7
lines changed

5 files changed

+100
-7
lines changed

src/System.Linq.Dynamic.Core/ExpressionParser.cs

+19-1
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ Expression ParseIntegerLiteral()
937937
bool isHexadecimal = text.StartsWith(text[0] == '-' ? "-0x" : "0x", StringComparison.CurrentCultureIgnoreCase);
938938
char[] qualifierLetters = isHexadecimal
939939
? new[] { 'U', 'u', 'L', 'l' }
940-
: new[] { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd' };
940+
: new[] { 'U', 'u', 'L', 'l', 'F', 'f', 'D', 'd', 'M', 'm' };
941941

942942
if (qualifierLetters.Contains(last))
943943
{
@@ -1007,6 +1007,9 @@ Expression ParseIntegerLiteral()
10071007
if (qualifier == "D" || qualifier == "d")
10081008
return TryParseAsDouble(text, qualifier[0]);
10091009

1010+
if (qualifier == "M" || qualifier == "m")
1011+
return TryParseAsDecimal(text, qualifier[0]);
1012+
10101013
throw ParseError(Res.MinusCannotBeAppliedToUnsignedInteger);
10111014
}
10121015

@@ -1038,6 +1041,21 @@ Expression TryParseAsFloat(string text, char qualifier)
10381041
}
10391042
}
10401043

1044+
// not possible to find float qualifier, so try to parse as double
1045+
return TryParseAsDecimal(text, qualifier);
1046+
}
1047+
1048+
Expression TryParseAsDecimal(string text, char qualifier)
1049+
{
1050+
if (qualifier == 'M' || qualifier == 'm')
1051+
{
1052+
decimal d;
1053+
if (decimal.TryParse(text.Substring(0, text.Length - 1), NumberStyles.Number, CultureInfo.InvariantCulture, out d))
1054+
{
1055+
return CreateLiteral(d, text);
1056+
}
1057+
}
1058+
10411059
// not possible to find float qualifier, so try to parse as double
10421060
return TryParseAsDouble(text, qualifier);
10431061
}

src/System.Linq.Dynamic.Core/Tokenizer/TextParser.cs

+1
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ public void NextToken()
346346

347347
if (_ch == 'F' || _ch == 'f') NextChar();
348348
if (_ch == 'D' || _ch == 'd') NextChar();
349+
if (_ch == 'M' || _ch == 'm') NextChar();
349350
break;
350351
}
351352

test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs

+23-6
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,20 @@ public void ParseLambda_ParameterExpressionMethodCall_ReturnsIntExpression()
203203
}
204204

205205
[Fact]
206-
public void ParseLambda_TupleToStringMethodCall_ReturnsStringLambdaExpression()
206+
public void ParseLambda_RealNumbers()
207207
{
208-
var expression = DynamicExpressionParser.ParseLambda(
209-
typeof(Tuple<int>),
210-
typeof(string),
211-
"it.ToString()");
212-
Assert.Equal(typeof(string), expression.ReturnType);
208+
var parameters = new ParameterExpression[0];
209+
210+
var result1 = DynamicExpressionParser.ParseLambda(parameters, typeof(double), "0.10");
211+
var result2 = DynamicExpressionParser.ParseLambda(parameters, typeof(double), "0.10d");
212+
var result3 = DynamicExpressionParser.ParseLambda(parameters, typeof(float), "0.10f");
213+
var result4 = DynamicExpressionParser.ParseLambda(parameters, typeof(decimal), "0.10m");
214+
215+
// Assert
216+
Assert.Equal(0.10d, result1.Compile().DynamicInvoke());
217+
Assert.Equal(0.10d, result2.Compile().DynamicInvoke());
218+
Assert.Equal(0.10f, result3.Compile().DynamicInvoke());
219+
Assert.Equal(0.10m, result4.Compile().DynamicInvoke());
213220
}
214221

215222
[Fact]
@@ -279,6 +286,16 @@ public void ParseLambda_StringLiteralEscapedBackslash_ReturnsBooleanLambdaExpres
279286
Assert.Equal(expectedRightValue, rightValue);
280287
}
281288

289+
[Fact]
290+
public void ParseLambda_TupleToStringMethodCall_ReturnsStringLambdaExpression()
291+
{
292+
var expression = DynamicExpressionParser.ParseLambda(
293+
typeof(Tuple<int>),
294+
typeof(string),
295+
"it.ToString()");
296+
Assert.Equal(typeof(string), expression.ReturnType);
297+
}
298+
282299
[Fact]
283300
public void ParseLambda_IllegalMethodCall_ThrowsException()
284301
{

test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs

+33
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,39 @@ public void ExpressionTests_DateTimeString()
383383
Assert.Equal(lst[0], result2.Single());
384384
}
385385

386+
[Fact]
387+
public void ExpressionTests_DecimalQualifiers()
388+
{
389+
//Arrange
390+
var values = new[] { 1m, 2M, 3M }.AsQueryable();
391+
var resultValues = new[] { 2m, 3m }.AsQueryable();
392+
393+
//Act
394+
var result1 = values.Where("it == 2M or it == 3m");
395+
var result2 = values.Where("it == 2.0M or it == 3.00m");
396+
397+
//Assert
398+
Assert.Equal(resultValues.ToArray(), result1.ToArray());
399+
Assert.Equal(resultValues.ToArray(), result2.ToArray());
400+
}
401+
402+
[Fact]
403+
public void ExpressionTests_DecimalQualifiers_Negative()
404+
{
405+
//Arrange
406+
var values = new[] { -1m, -2M, -3M }.AsQueryable();
407+
var resultValues = new[] { -2m, -3m }.AsQueryable();
408+
409+
//Act
410+
var result1 = values.Where("it == -2M or it == -3m");
411+
var result2 = values.Where("it == -2.0M or it == -3.0m");
412+
413+
//Assert
414+
Assert.Equal(resultValues.ToArray(), result1.ToArray());
415+
Assert.Equal(resultValues.ToArray(), result2.ToArray());
416+
}
417+
418+
386419
[Fact]
387420
public void ExpressionTests_DistinctBy()
388421
{

test/System.Linq.Dynamic.Core.Tests/TextParserTests.cs

+24
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,30 @@ public void TextParser_Parse_RealLiteral()
107107
Check.ThatCode(() => new TextParser("1.e25")).Throws<ParseException>();
108108
}
109109

110+
[Fact]
111+
public void TextParser_Parse_RealLiteralDecimalQualifier()
112+
{
113+
// Assign + Act
114+
var textParser = new TextParser(" 12.5m ");
115+
116+
// Assert
117+
Check.That(textParser.CurrentToken.Id).Equals(TokenId.RealLiteral);
118+
Check.That(textParser.CurrentToken.Pos).Equals(1);
119+
Check.That(textParser.CurrentToken.Text).Equals("12.5m");
120+
}
121+
122+
[Fact]
123+
public void TextParser_Parse_RealLiteralFloatQualifier()
124+
{
125+
// Assign + Act
126+
var textParser = new TextParser(" 12.5f ");
127+
128+
// Assert
129+
Check.That(textParser.CurrentToken.Id).Equals(TokenId.RealLiteral);
130+
Check.That(textParser.CurrentToken.Pos).Equals(1);
131+
Check.That(textParser.CurrentToken.Text).Equals("12.5f");
132+
}
133+
110134
[Fact]
111135
public void TextParser_Parse_RealLiteralMinus()
112136
{

0 commit comments

Comments
 (0)