()
| 258 | } |
| 259 | |
| 260 | private scanToken(): Token | null { |
| 261 | const input = this.input; |
| 262 | const length = this.length; |
| 263 | let peek = this.peek; |
| 264 | let index = this.index; |
| 265 | |
| 266 | // Skip whitespace. |
| 267 | while (peek <= chars.$SPACE) { |
| 268 | if (++index >= length) { |
| 269 | peek = chars.$EOF; |
| 270 | break; |
| 271 | } else { |
| 272 | peek = input.charCodeAt(index); |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | this.peek = peek; |
| 277 | this.index = index; |
| 278 | |
| 279 | if (index >= length) { |
| 280 | return null; |
| 281 | } |
| 282 | |
| 283 | // Handle identifiers and numbers. |
| 284 | if (isIdentifierStart(peek)) { |
| 285 | return this.scanIdentifier(); |
| 286 | } |
| 287 | |
| 288 | if (chars.isDigit(peek)) { |
| 289 | return this.scanNumber(index); |
| 290 | } |
| 291 | |
| 292 | const start: number = index; |
| 293 | switch (peek) { |
| 294 | case chars.$PERIOD: |
| 295 | this.advance(); |
| 296 | |
| 297 | if (chars.isDigit(this.peek)) { |
| 298 | return this.scanNumber(start); |
| 299 | } |
| 300 | |
| 301 | if (this.peek !== chars.$PERIOD) { |
| 302 | return newCharacterToken(start, this.index, chars.$PERIOD); |
| 303 | } |
| 304 | |
| 305 | this.advance(); |
| 306 | if (this.peek === chars.$PERIOD) { |
| 307 | this.advance(); |
| 308 | return newOperatorToken(start, this.index, '...'); |
| 309 | } |
| 310 | return this.error(`Unexpected character [${String.fromCharCode(peek)}]`, 0); |
| 311 | case chars.$LPAREN: |
| 312 | case chars.$RPAREN: |
| 313 | case chars.$LBRACKET: |
| 314 | case chars.$RBRACKET: |
| 315 | case chars.$COMMA: |
| 316 | case chars.$COLON: |
| 317 | case chars.$SEMICOLON: |
no test coverage detected