Skip to content

Commit b5e110e

Browse files
committed
JS: Fix value of numeric literals containing underscores
1 parent 9888f15 commit b5e110e

File tree

6 files changed

+134
-4
lines changed

6 files changed

+134
-4
lines changed

javascript/extractor/src/com/semmle/jcorn/ESNextParser.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ protected Number readInt(int radix, Integer len) {
482482

483483
if (code == '_') {
484484
if (underscoreAllowed) {
485+
seenUnderscoreNumericSeparator = true;
485486
// no adjacent underscores
486487
underscoreAllowed = false;
487488
++this.pos;

javascript/extractor/src/com/semmle/jcorn/Parser.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ public class Parser {
145145
private Stack<LabelInfo> labels;
146146
protected int yieldPos, awaitPos;
147147

148+
/**
149+
* Set to true by {@link ESNextParser#readInt} if the parsed integer contains an underscore.
150+
*/
151+
protected boolean seenUnderscoreNumericSeparator = false;
152+
148153
/**
149154
* For readability purposes, we pass this instead of false as the argument to the
150155
* hasDeclareKeyword parameter (which only exists in TypeScript).
@@ -654,7 +659,7 @@ protected Token getTokenFromCode(int code) {
654659
case 58:
655660
++this.pos;
656661
return this.finishToken(TokenType.colon);
657-
case 35:
662+
case 35:
658663
++this.pos;
659664
return this.finishToken(TokenType.pound);
660665
case 63:
@@ -847,6 +852,10 @@ else if (Identifiers.isIdentifierStart(this.fullCharCodeAtPos(), false))
847852
}
848853

849854
String str = inputSubstring(start, this.pos);
855+
if (seenUnderscoreNumericSeparator) {
856+
str = str.replace("_", "");
857+
seenUnderscoreNumericSeparator = false;
858+
}
850859
Number val = null;
851860
if (isFloat) val = parseFloat(str);
852861
else if (!octal || str.length() == 1) val = parseInt(str, 10);

javascript/ql/test/library-tests/Constants/Constants.expected

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,98 @@ getIntValue
2525
| tst.js:47:5:47:5 | 1 | 1 |
2626
| tst.js:48:7:48:7 | 1 | 1 |
2727
| tst.js:49:6:49:6 | 1 | 1 |
28-
| tst.js:52:5:52:9 | 1_000 | 1 |
29-
| tst.js:53:5:53:13 | 1_000_123 | 1 |
28+
| tst.js:52:5:52:9 | 1_000 | 1000 |
29+
| tst.js:53:5:53:13 | 1_000_123 | 1000123 |
30+
| tst.js:54:5:54:17 | 1_000_000_000 | 1000000000 |
31+
| tst.js:56:5:56:10 | 123_00 | 12300 |
32+
| tst.js:57:5:57:10 | 12_300 | 12300 |
33+
| tst.js:58:5:58:12 | 12345_00 | 1234500 |
34+
| tst.js:59:5:59:12 | 123_4500 | 1234500 |
35+
| tst.js:60:5:60:13 | 1_234_500 | 1234500 |
36+
| tst.js:62:5:62:14 | 0xaa_bb_cc | 11189196 |
37+
getFloatValue
38+
| tst2.ts:1:21:1:21 | 1 | 1.0 |
39+
| tst.js:6:1:6:1 | 1 | 1.0 |
40+
| tst.js:11:2:11:2 | 1 | 1.0 |
41+
| tst.js:12:2:12:2 | 0 | 0.0 |
42+
| tst.js:26:3:26:3 | 0 | 0.0 |
43+
| tst.js:29:6:29:6 | 0 | 0.0 |
44+
| tst.js:35:1:35:1 | 1 | 1.0 |
45+
| tst.js:35:5:35:5 | 2 | 2.0 |
46+
| tst.js:35:9:35:9 | 3 | 3.0 |
47+
| tst.js:37:2:37:2 | 1 | 1.0 |
48+
| tst.js:39:4:39:4 | 1 | 1.0 |
49+
| tst.js:40:1:40:1 | 1 | 1.0 |
50+
| tst.js:42:1:42:1 | 1 | 1.0 |
51+
| tst.js:42:4:42:4 | 2 | 2.0 |
52+
| tst.js:42:7:42:7 | 3 | 3.0 |
53+
| tst.js:43:4:43:4 | 2 | 2.0 |
54+
| tst.js:43:7:43:7 | 3 | 3.0 |
55+
| tst.js:44:1:44:1 | 1 | 1.0 |
56+
| tst.js:44:7:44:7 | 3 | 3.0 |
57+
| tst.js:45:1:45:1 | 1 | 1.0 |
58+
| tst.js:45:4:45:4 | 2 | 2.0 |
59+
| tst.js:47:5:47:5 | 1 | 1.0 |
60+
| tst.js:48:7:48:7 | 1 | 1.0 |
61+
| tst.js:49:6:49:6 | 1 | 1.0 |
62+
| tst.js:52:5:52:9 | 1_000 | 1000.0 |
63+
| tst.js:53:5:53:13 | 1_000_123 | 1000123.0 |
64+
| tst.js:54:5:54:17 | 1_000_000_000 | 1.0E9 |
65+
| tst.js:55:5:55:18 | 101_475_938.38 | 1.0147593838E8 |
66+
| tst.js:56:5:56:10 | 123_00 | 12300.0 |
67+
| tst.js:57:5:57:10 | 12_300 | 12300.0 |
68+
| tst.js:58:5:58:12 | 12345_00 | 1234500.0 |
69+
| tst.js:59:5:59:12 | 123_4500 | 1234500.0 |
70+
| tst.js:60:5:60:13 | 1_234_500 | 1234500.0 |
71+
| tst.js:61:5:61:10 | 1e1_00 | 1.0E100 |
72+
| tst.js:62:5:62:14 | 0xaa_bb_cc | 1.1189196E7 |
73+
getLiteralValue
74+
| tst2.ts:1:21:1:21 | 1 | 1 |
75+
| tst.js:1:1:1:3 | "a" | a |
76+
| tst.js:2:1:2:3 | "b" | b |
77+
| tst.js:2:7:2:9 | "c" | c |
78+
| tst.js:3:1:3:3 | "d" | d |
79+
| tst.js:3:7:3:9 | "e" | e |
80+
| tst.js:3:13:3:15 | "f" | f |
81+
| tst.js:6:1:6:1 | 1 | 1 |
82+
| tst.js:8:1:8:5 | false | false |
83+
| tst.js:9:1:9:4 | true | true |
84+
| tst.js:11:2:11:2 | 1 | 1 |
85+
| tst.js:12:2:12:2 | 0 | 0 |
86+
| tst.js:14:1:14:4 | null | null |
87+
| tst.js:20:1:20:3 | /x/ | /x/ |
88+
| tst.js:24:5:24:7 | "x" | x |
89+
| tst.js:26:3:26:3 | 0 | 0 |
90+
| tst.js:29:6:29:6 | 0 | 0 |
91+
| tst.js:35:1:35:1 | 1 | 1 |
92+
| tst.js:35:5:35:5 | 2 | 2 |
93+
| tst.js:35:9:35:9 | 3 | 3 |
94+
| tst.js:37:2:37:2 | 1 | 1 |
95+
| tst.js:39:4:39:4 | 1 | 1 |
96+
| tst.js:40:1:40:1 | 1 | 1 |
97+
| tst.js:42:1:42:1 | 1 | 1 |
98+
| tst.js:42:4:42:4 | 2 | 2 |
99+
| tst.js:42:7:42:7 | 3 | 3 |
100+
| tst.js:43:4:43:4 | 2 | 2 |
101+
| tst.js:43:7:43:7 | 3 | 3 |
102+
| tst.js:44:1:44:1 | 1 | 1 |
103+
| tst.js:44:7:44:7 | 3 | 3 |
104+
| tst.js:45:1:45:1 | 1 | 1 |
105+
| tst.js:45:4:45:4 | 2 | 2 |
106+
| tst.js:47:5:47:5 | 1 | 1 |
107+
| tst.js:48:7:48:7 | 1 | 1 |
108+
| tst.js:49:6:49:6 | 1 | 1 |
109+
| tst.js:52:5:52:9 | 1_000 | 1000 |
110+
| tst.js:53:5:53:13 | 1_000_123 | 1000123 |
111+
| tst.js:54:5:54:17 | 1_000_000_000 | 1000000000 |
112+
| tst.js:55:5:55:18 | 101_475_938.38 | 1.0147593838E8 |
113+
| tst.js:56:5:56:10 | 123_00 | 12300 |
114+
| tst.js:57:5:57:10 | 12_300 | 12300 |
115+
| tst.js:58:5:58:12 | 12345_00 | 1234500 |
116+
| tst.js:59:5:59:12 | 123_4500 | 1234500 |
117+
| tst.js:60:5:60:13 | 1_234_500 | 1234500 |
118+
| tst.js:61:5:61:10 | 1e1_00 | 1.0E100 |
119+
| tst.js:62:5:62:14 | 0xaa_bb_cc | 11189196 |
30120
#select
31121
| tst2.ts:1:13:1:21 | <number>1 |
32122
| tst2.ts:1:21:1:21 | 1 |
@@ -95,3 +185,21 @@ getIntValue
95185
| tst.js:52:5:52:9 | 1_000 |
96186
| tst.js:53:1:53:13 | x = 1_000_123 |
97187
| tst.js:53:5:53:13 | 1_000_123 |
188+
| tst.js:54:1:54:17 | x = 1_000_000_000 |
189+
| tst.js:54:5:54:17 | 1_000_000_000 |
190+
| tst.js:55:1:55:18 | x = 101_475_938.38 |
191+
| tst.js:55:5:55:18 | 101_475_938.38 |
192+
| tst.js:56:1:56:10 | x = 123_00 |
193+
| tst.js:56:5:56:10 | 123_00 |
194+
| tst.js:57:1:57:10 | x = 12_300 |
195+
| tst.js:57:5:57:10 | 12_300 |
196+
| tst.js:58:1:58:12 | x = 12345_00 |
197+
| tst.js:58:5:58:12 | 12345_00 |
198+
| tst.js:59:1:59:12 | x = 123_4500 |
199+
| tst.js:59:5:59:12 | 123_4500 |
200+
| tst.js:60:1:60:13 | x = 1_234_500 |
201+
| tst.js:60:5:60:13 | 1_234_500 |
202+
| tst.js:61:1:61:10 | x = 1e1_00 |
203+
| tst.js:61:5:61:10 | 1e1_00 |
204+
| tst.js:62:1:62:14 | x = 0xaa_bb_cc |
205+
| tst.js:62:5:62:14 | 0xaa_bb_cc |

javascript/ql/test/library-tests/Constants/Constants.ql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ from ConstantExpr c
44
select c
55

66
query int getIntValue(Expr e) { result = e.getIntValue() }
7+
8+
query float getFloatValue(NumberLiteral e) { result = e.getFloatValue() }
9+
10+
query string getLiteralValue(Literal lit) { result = lit.getValue() }

javascript/ql/test/library-tests/Constants/tst.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,12 @@ x += x;
5151

5252
x = 1_000;
5353
x = 1_000_123;
54+
x = 1_000_000_000;
55+
x = 101_475_938.38;
56+
x = 123_00;
57+
x = 12_300;
58+
x = 12345_00;
59+
x = 123_4500;
60+
x = 1_234_500;
61+
x = 1e1_00;
62+
x = 0xaa_bb_cc;
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
| constants.js:12:27:12:31 | // OK | Error: analysis claims x >= 1_000 is always false |

0 commit comments

Comments
 (0)