Skip to content

Commit 0935688

Browse files
committed
Support explicit integer qualifiers #10
1 parent 97b89ae commit 0935688

File tree

3 files changed

+180
-5
lines changed

3 files changed

+180
-5
lines changed

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

+64-5
Original file line numberDiff line numberDiff line change
@@ -848,16 +848,38 @@ Expression ParseStringLiteral()
848848
Expression ParseIntegerLiteral()
849849
{
850850
ValidateToken(TokenId.IntegerLiteral);
851+
851852
string text = _token.text;
853+
string qualifier = null;
854+
char last = text[text.Length - 1];
855+
856+
if (char.IsLetter(last))
857+
{
858+
int pos = text.Length - 1, count = 0;
859+
while (char.IsLetter(text[pos]))
860+
{
861+
++count;
862+
--pos;
863+
}
864+
qualifier = text.Substring(text.Length - count, count);
865+
text = text.Substring(0, text.Length - count);
866+
}
867+
852868
if (text[0] != '-')
853869
{
854870
ulong value;
855871
if (!ulong.TryParse(text, out value))
856872
throw ParseError(Res.InvalidIntegerLiteral, text);
857873
NextToken();
858-
if (value <= (ulong)int.MaxValue) return CreateLiteral((int)value, text);
859-
if (value <= (ulong)uint.MaxValue) return CreateLiteral((uint)value, text);
860-
if (value <= (ulong)long.MaxValue) return CreateLiteral((long)value, text);
874+
if (!string.IsNullOrEmpty(qualifier))
875+
{
876+
if (qualifier == "U") return CreateLiteral((uint)value, text);
877+
if (qualifier == "L") return CreateLiteral((long)value, text);
878+
else if (qualifier == "UL") return CreateLiteral(value, text);
879+
}
880+
if (value <= int.MaxValue) return CreateLiteral((int)value, text);
881+
if (value <= uint.MaxValue) return CreateLiteral((uint)value, text);
882+
if (value <= long.MaxValue) return CreateLiteral((long)value, text);
861883
return CreateLiteral(value, text);
862884
}
863885
else
@@ -866,8 +888,16 @@ Expression ParseIntegerLiteral()
866888
if (!long.TryParse(text, out value))
867889
throw ParseError(Res.InvalidIntegerLiteral, text);
868890
NextToken();
869-
if (value >= int.MinValue && value <= int.MaxValue)
870-
return CreateLiteral((int)value, text);
891+
if (!string.IsNullOrEmpty(qualifier))
892+
{
893+
if (qualifier == "L")
894+
return CreateLiteral(value, text);
895+
else
896+
throw ParseError(Res.InvalidIntegerLiteral, qualifier);
897+
}
898+
899+
if (value <= int.MaxValue) return CreateLiteral((int)value, text);
900+
871901
return CreateLiteral(value, text);
872902
}
873903
}
@@ -883,6 +913,11 @@ Expression ParseRealLiteral()
883913
float f;
884914
if (float.TryParse(text.Substring(0, text.Length - 1), out f)) value = f;
885915
}
916+
else if (last == 'D' || last == 'd')
917+
{
918+
double d;
919+
if (double.TryParse(text.Substring(0, text.Length - 1), out d)) value = d;
920+
}
886921
else
887922
{
888923
double d;
@@ -2422,13 +2457,27 @@ void NextToken()
24222457
t = TokenId.Identifier;
24232458
break;
24242459
}
2460+
24252461
if (char.IsDigit(_ch))
24262462
{
24272463
t = TokenId.IntegerLiteral;
24282464
do
24292465
{
24302466
NextChar();
24312467
} while (char.IsDigit(_ch));
2468+
2469+
if (_ch == 'U' || _ch == 'L')
2470+
{
2471+
NextChar();
2472+
if (_ch == 'L')
2473+
{
2474+
if (_text[_textPos - 1] == 'U') NextChar();
2475+
else throw ParseError(_textPos, Res.InvalidIntegerQualifier, _text.Substring(_textPos - 1, 2));
2476+
}
2477+
ValidateExpression();
2478+
break;
2479+
}
2480+
24322481
if (_ch == '.')
24332482
{
24342483
t = TokenId.RealLiteral;
@@ -2439,6 +2488,7 @@ void NextToken()
24392488
NextChar();
24402489
} while (char.IsDigit(_ch));
24412490
}
2491+
24422492
if (_ch == 'E' || _ch == 'e')
24432493
{
24442494
t = TokenId.RealLiteral;
@@ -2450,16 +2500,20 @@ void NextToken()
24502500
NextChar();
24512501
} while (char.IsDigit(_ch));
24522502
}
2503+
24532504
if (_ch == 'F' || _ch == 'f') NextChar();
2505+
if (_ch == 'D' || _ch == 'd') NextChar();
24542506
break;
24552507
}
2508+
24562509
if (_textPos == _textLen)
24572510
{
24582511
t = TokenId.End;
24592512
break;
24602513
}
24612514
throw ParseError(_textPos, Res.InvalidCharacter, _ch);
24622515
}
2516+
24632517
_token.pos = tokenPos;
24642518
_token.text = _text.Substring(tokenPos, _textPos - tokenPos);
24652519
_token.id = GetAliasedTokenId(t, _token.text);
@@ -2478,6 +2532,11 @@ string GetIdentifier()
24782532
return id;
24792533
}
24802534

2535+
void ValidateExpression()
2536+
{
2537+
if (char.IsLetterOrDigit(_ch)) throw ParseError(_textPos, Res.ExpressionExpected);
2538+
}
2539+
24812540
void ValidateDigit()
24822541
{
24832542
if (!char.IsDigit(_ch)) throw ParseError(_textPos, Res.DigitExpected);

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

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal static class Res
77
public const string ExpressionExpected = "Expression expected";
88
public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";
99
public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'";
10+
public const string InvalidIntegerQualifier = "Invalid integer literal qualifier '{0}'";
1011
public const string InvalidRealLiteral = "Invalid real literal '{0}'";
1112
public const string UnknownIdentifier = "Unknown identifier '{0}'";
1213
public const string NoItInScope = "No 'it' is in scope";

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

+115
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,121 @@ namespace System.Linq.Dynamic.Core.Tests
88
{
99
public class ExpressionTests
1010
{
11+
//[Fact]
12+
//public void ExpressionTests_DoubleQualifiers()
13+
//{
14+
// //Arrange
15+
// var values = new[] { 1d, 2D, 3d }.AsQueryable();
16+
// var resultValues = new[] { 2d, 3d }.AsQueryable();
17+
18+
// //Act
19+
// var result = values.Where("it == 2d or it == 3D").ToDynamicArray<double>();
20+
21+
// //Assert
22+
// Assert.Equal(resultValues.ToArray(), result);
23+
//}
24+
25+
//[Fact]
26+
//public void ExpressionTests_DoubleQualifiers_Negative()
27+
//{
28+
// //Arrange
29+
// var values = new[] { -1d, -2D, -3d }.AsQueryable();
30+
// var resultValues = new[] { -2d, -3d }.AsQueryable();
31+
32+
// //Act
33+
// var result = values.Where("it == -2d or it == -3D").ToDynamicArray<double>();
34+
35+
// //Assert
36+
// Assert.Equal(resultValues.ToArray(), result);
37+
//}
38+
39+
[Fact]
40+
public void ExpressionTests_FloatQualifiers()
41+
{
42+
//Arrange
43+
var values = new[] { 1f, 2F, 3F }.AsQueryable();
44+
var resultValues = new[] { 2f, 3f }.AsQueryable();
45+
46+
//Act
47+
var result = values.Where("it == 2F or it == 3f").ToDynamicArray<float>();
48+
49+
//Assert
50+
Assert.Equal(resultValues.ToArray(), result);
51+
}
52+
53+
//[Fact]
54+
//public void ExpressionTests_FloatQualifiers_Negative()
55+
//{
56+
// //Arrange
57+
// var values = new[] { -1f, -2F, -3F }.AsQueryable();
58+
// var resultValues = new[] { -2f, -3f }.AsQueryable();
59+
60+
// //Act
61+
// var result = values.Where("it == -2F or it == -3f").ToDynamicArray<float>();
62+
63+
// //Assert
64+
// Assert.Equal(resultValues.ToArray(), result);
65+
//}
66+
67+
[Fact]
68+
public void ExpressionTests_IntegerQualifiers()
69+
{
70+
//Arrange
71+
var valuesL = new[] { 1L, 2L, 3L }.AsQueryable();
72+
var resultValuesL = new[] { 2L, 3L }.AsQueryable();
73+
74+
var valuesU = new[] { 1U, 2U, 3U }.AsQueryable();
75+
var resultValuesU = new[] { 2U, 3U }.AsQueryable();
76+
77+
var valuesUL = new[] { 1UL, 2UL, 3UL }.AsQueryable();
78+
var resultValuesUL = new[] { 2UL, 3UL }.AsQueryable();
79+
80+
//Act
81+
var resultL = valuesL.Where("it in (2L, 3L)").ToDynamicArray<long>();
82+
var resultU = valuesU.Where("it in (2U, 3U)").ToDynamicArray<uint>();
83+
var resultUL = valuesUL.Where("it in (2UL, 3UL)").ToDynamicArray<ulong>();
84+
85+
//Assert
86+
Assert.Equal(resultValuesL.ToArray(), resultL);
87+
Assert.Equal(resultValuesU.ToArray(), resultU);
88+
Assert.Equal(resultValuesUL.ToArray(), resultUL);
89+
}
90+
91+
[Fact]
92+
public void ExpressionTests_IntegerQualifiers_Negative()
93+
{
94+
//Arrange
95+
var valuesL = new[] { -1L, -2L, -3L }.AsQueryable();
96+
var resultValuesL = new[] { -2L, -3L }.AsQueryable();
97+
98+
//Act
99+
var resultL = valuesL.Where("it <= -2L").ToDynamicArray<long>();
100+
//var resultIn = valuesL.Where("it in (-2L, -3L)").ToDynamicArray<long>();
101+
102+
//Assert
103+
Assert.Equal(resultValuesL.ToArray(), resultL);
104+
// Assert.Equal(resultValuesL.ToArray(), resultIn);
105+
}
106+
107+
[Fact]
108+
public void ExpressionTests_IntegerQualifiers_Exceptions()
109+
{
110+
//Arrange
111+
var values = new[] { 1L, 2L, 3L }.AsQueryable();
112+
113+
//Assert
114+
Assert.Throws<ParseException>(() => values.Where("it in (2LL)"));
115+
Assert.Throws<ParseException>(() => values.Where("it in (2UU)"));
116+
Assert.Throws<ParseException>(() => values.Where("it in (2LU)"));
117+
Assert.Throws<ParseException>(() => values.Where("it in (2B)"));
118+
119+
Assert.Throws<ParseException>(() => values.Where("it < -2LL"));
120+
Assert.Throws<ParseException>(() => values.Where("it < -2UL"));
121+
Assert.Throws<ParseException>(() => values.Where("it < -2UU"));
122+
Assert.Throws<ParseException>(() => values.Where("it < -2LU"));
123+
Assert.Throws<ParseException>(() => values.Where("it < -2B"));
124+
}
125+
11126
[Fact]
12127
public void ExpressionTests_NullCoalescing()
13128
{

0 commit comments

Comments
 (0)