@@ -110,7 +110,6 @@ tokenDescription[TokenKind.FLOAT] = 'Float';
110
110
tokenDescription [ TokenKind . STRING ] = 'String' ;
111
111
112
112
var charCodeAt = String . prototype . charCodeAt ;
113
- var fromCharCode = String . fromCharCode ;
114
113
var slice = String . prototype . slice ;
115
114
116
115
/**
@@ -125,6 +124,10 @@ function makeToken(
125
124
return { kind, start, end, value } ;
126
125
}
127
126
127
+ function printCharCode ( code ) {
128
+ return isNaN ( code ) ? 'EOF' : JSON . stringify ( String . fromCharCode ( code ) ) ;
129
+ }
130
+
128
131
/**
129
132
* Gets the next token from the source starting at the given position.
130
133
*
@@ -137,12 +140,22 @@ function readToken(source: Source, fromPosition: number): Token {
137
140
var bodyLength = body . length ;
138
141
139
142
var position = positionAfterWhitespace ( body , fromPosition ) ;
140
- var code = charCodeAt . call ( body , position ) ;
141
143
142
144
if ( position >= bodyLength ) {
143
145
return makeToken ( TokenKind . EOF , position , position ) ;
144
146
}
145
147
148
+ var code = charCodeAt . call ( body , position ) ;
149
+
150
+ // SourceCharacter
151
+ if ( code < 0x0020 && code !== 0x0009 && code !== 0x000A && code !== 0x000D ) {
152
+ throw syntaxError (
153
+ source ,
154
+ position ,
155
+ `Invalid character ${ printCharCode ( code ) } .`
156
+ ) ;
157
+ }
158
+
146
159
switch ( code ) {
147
160
// !
148
161
case 33 : return makeToken ( TokenKind . BANG , position , position + 1 ) ;
@@ -201,7 +214,7 @@ function readToken(source: Source, fromPosition: number): Token {
201
214
throw syntaxError (
202
215
source ,
203
216
position ,
204
- `Unexpected character " ${ fromCharCode ( code ) } " .`
217
+ `Unexpected character ${ printCharCode ( code ) } .`
205
218
) ;
206
219
}
207
220
@@ -217,21 +230,26 @@ function positionAfterWhitespace(body: string, startPosition: number): number {
217
230
var code = charCodeAt . call ( body , position ) ;
218
231
// Skip whitespace
219
232
if (
220
- code === 32 || // space
221
- code === 44 || // comma
222
- code === 160 || // '\xa0'
223
- code === 0x2028 || // line separator
224
- code === 0x2029 || // paragraph separator
225
- code > 8 && code < 14 // whitespace
233
+ // BOM
234
+ code === 0xFEFF ||
235
+ // White Space
236
+ code === 0x0009 || // tab
237
+ code === 0x0020 || // space
238
+ // Line Terminator
239
+ code === 0x000A || // new line
240
+ code === 0x000D || // carriage return
241
+ // Comma
242
+ code === 0x002C
226
243
) {
227
244
++ position ;
228
245
// Skip comments
229
246
} else if ( code === 35 ) { // #
230
247
++ position ;
231
248
while (
232
249
position < bodyLength &&
233
- ( code = charCodeAt . call ( body , position ) ) &&
234
- code !== 10 && code !== 13 && code !== 0x2028 && code !== 0x2029
250
+ ( code = charCodeAt . call ( body , position ) ) !== null &&
251
+ // SourceCharacter but not LineTerminator
252
+ ( code > 0x001F || code === 0x0009 ) && code !== 0x000A && code !== 0x000D
235
253
) {
236
254
++ position ;
237
255
}
@@ -265,7 +283,7 @@ function readNumber(source, start, firstCode) {
265
283
throw syntaxError (
266
284
source ,
267
285
position ,
268
- `Invalid number, unexpected digit after 0: " ${ fromCharCode ( code ) } " .`
286
+ `Invalid number, unexpected digit after 0: ${ printCharCode ( code ) } .`
269
287
) ;
270
288
}
271
289
} else {
@@ -315,8 +333,7 @@ function readDigits(source, start, firstCode) {
315
333
throw syntaxError (
316
334
source ,
317
335
position ,
318
- 'Invalid number, expected digit but got: ' +
319
- ( code ? `"${ fromCharCode ( code ) } "` : 'EOF' ) + '.'
336
+ `Invalid number, expected digit but got: ${ printCharCode ( code ) } .`
320
337
) ;
321
338
}
322
339
@@ -329,15 +346,26 @@ function readString(source, start) {
329
346
var body = source . body ;
330
347
var position = start + 1 ;
331
348
var chunkStart = position ;
332
- var code ;
349
+ var code = 0 ;
333
350
var value = '' ;
334
351
335
352
while (
336
353
position < body . length &&
337
- ( code = charCodeAt . call ( body , position ) ) &&
338
- code !== 34 &&
339
- code !== 10 && code !== 13 && code !== 0x2028 && code !== 0x2029
354
+ ( code = charCodeAt . call ( body , position ) ) !== null &&
355
+ // not LineTerminator
356
+ code !== 0x000A && code !== 0x000D &&
357
+ // not Quote (")
358
+ code !== 34
340
359
) {
360
+ // SourceCharacter
361
+ if ( code < 0x0020 && code !== 0x0009 ) {
362
+ throw syntaxError (
363
+ source ,
364
+ position ,
365
+ `Invalid character within String: ${ printCharCode ( code ) } .`
366
+ ) ;
367
+ }
368
+
341
369
++ position ;
342
370
if ( code === 92 ) { // \
343
371
value += slice . call ( body , chunkStart , position - 1 ) ;
@@ -351,7 +379,7 @@ function readString(source, start) {
351
379
case 110 : value += '\n'; break ;
352
380
case 114 : value += '\r'; break ;
353
381
case 116 : value += '\t'; break ;
354
- case 117 :
382
+ case 117 : // u
355
383
var charCode = uniCharCode (
356
384
charCodeAt . call ( body , position + 1 ) ,
357
385
charCodeAt . call ( body , position + 2 ) ,
@@ -362,25 +390,26 @@ function readString(source, start) {
362
390
throw syntaxError (
363
391
source ,
364
392
position ,
365
- 'Bad character escape sequence.'
393
+ `Invalid character escape sequence: ` +
394
+ `\\u${ body . slice ( position + 1 , position + 5 ) } .`
366
395
) ;
367
396
}
368
- value += fromCharCode ( charCode ) ;
397
+ value += String . fromCharCode ( charCode ) ;
369
398
position += 4 ;
370
399
break ;
371
400
default :
372
401
throw syntaxError (
373
402
source ,
374
403
position ,
375
- 'Bad character escape sequence.'
404
+ `Invalid character escape sequence: \\ ${ String . fromCharCode ( code ) } .`
376
405
) ;
377
406
}
378
407
++ position ;
379
408
chunkStart = position ;
380
409
}
381
410
}
382
411
383
- if ( code !== 34 ) {
412
+ if ( code !== 34 ) { // quote (")
384
413
throw syntaxError ( source , position , 'Unterminated string.' ) ;
385
414
}
386
415
@@ -428,10 +457,10 @@ function readName(source, position) {
428
457
var body = source . body ;
429
458
var bodyLength = body . length ;
430
459
var end = position + 1 ;
431
- var code ;
460
+ var code = 0 ;
432
461
while (
433
462
end !== bodyLength &&
434
- ( code = charCodeAt . call ( body , end ) ) &&
463
+ ( code = charCodeAt . call ( body , end ) ) !== null &&
435
464
(
436
465
code === 95 || // _
437
466
code >= 48 && code <= 57 || // 0-9
0 commit comments