UNPKG

29.3 kBJavaScriptView Raw
1"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }/* eslint max-len: 0 */
2
3var _base = require('../traverser/base');
4var _util = require('../traverser/util');
5var _charcodes = require('../util/charcodes');
6var _identifier = require('../util/identifier');
7var _whitespace = require('../util/whitespace');
8var _keywords = require('./keywords');
9var _readWord = require('./readWord'); var _readWord2 = _interopRequireDefault(_readWord);
10var _types = require('./types');
11
12var IdentifierRole; (function (IdentifierRole) {
13 const Access = 0; IdentifierRole[IdentifierRole["Access"] = Access] = "Access";
14 const ExportAccess = Access + 1; IdentifierRole[IdentifierRole["ExportAccess"] = ExportAccess] = "ExportAccess";
15 const TopLevelDeclaration = ExportAccess + 1; IdentifierRole[IdentifierRole["TopLevelDeclaration"] = TopLevelDeclaration] = "TopLevelDeclaration";
16 const FunctionScopedDeclaration = TopLevelDeclaration + 1; IdentifierRole[IdentifierRole["FunctionScopedDeclaration"] = FunctionScopedDeclaration] = "FunctionScopedDeclaration";
17 const BlockScopedDeclaration = FunctionScopedDeclaration + 1; IdentifierRole[IdentifierRole["BlockScopedDeclaration"] = BlockScopedDeclaration] = "BlockScopedDeclaration";
18 const ObjectShorthandTopLevelDeclaration = BlockScopedDeclaration + 1; IdentifierRole[IdentifierRole["ObjectShorthandTopLevelDeclaration"] = ObjectShorthandTopLevelDeclaration] = "ObjectShorthandTopLevelDeclaration";
19 const ObjectShorthandFunctionScopedDeclaration = ObjectShorthandTopLevelDeclaration + 1; IdentifierRole[IdentifierRole["ObjectShorthandFunctionScopedDeclaration"] = ObjectShorthandFunctionScopedDeclaration] = "ObjectShorthandFunctionScopedDeclaration";
20 const ObjectShorthandBlockScopedDeclaration = ObjectShorthandFunctionScopedDeclaration + 1; IdentifierRole[IdentifierRole["ObjectShorthandBlockScopedDeclaration"] = ObjectShorthandBlockScopedDeclaration] = "ObjectShorthandBlockScopedDeclaration";
21 const ObjectShorthand = ObjectShorthandBlockScopedDeclaration + 1; IdentifierRole[IdentifierRole["ObjectShorthand"] = ObjectShorthand] = "ObjectShorthand";
22 // Any identifier bound in an import statement, e.g. both A and b from
23 // `import A, * as b from 'A';`
24 const ImportDeclaration = ObjectShorthand + 1; IdentifierRole[IdentifierRole["ImportDeclaration"] = ImportDeclaration] = "ImportDeclaration";
25 const ObjectKey = ImportDeclaration + 1; IdentifierRole[IdentifierRole["ObjectKey"] = ObjectKey] = "ObjectKey";
26 // The `foo` in `import {foo as bar} from "./abc";`.
27 const ImportAccess = ObjectKey + 1; IdentifierRole[IdentifierRole["ImportAccess"] = ImportAccess] = "ImportAccess";
28})(IdentifierRole || (exports.IdentifierRole = IdentifierRole = {}));
29
30 function isDeclaration(token) {
31 const role = token.identifierRole;
32 return (
33 role === IdentifierRole.TopLevelDeclaration ||
34 role === IdentifierRole.FunctionScopedDeclaration ||
35 role === IdentifierRole.BlockScopedDeclaration ||
36 role === IdentifierRole.ObjectShorthandTopLevelDeclaration ||
37 role === IdentifierRole.ObjectShorthandFunctionScopedDeclaration ||
38 role === IdentifierRole.ObjectShorthandBlockScopedDeclaration
39 );
40} exports.isDeclaration = isDeclaration;
41
42 function isNonTopLevelDeclaration(token) {
43 const role = token.identifierRole;
44 return (
45 role === IdentifierRole.FunctionScopedDeclaration ||
46 role === IdentifierRole.BlockScopedDeclaration ||
47 role === IdentifierRole.ObjectShorthandFunctionScopedDeclaration ||
48 role === IdentifierRole.ObjectShorthandBlockScopedDeclaration
49 );
50} exports.isNonTopLevelDeclaration = isNonTopLevelDeclaration;
51
52 function isTopLevelDeclaration(token) {
53 const role = token.identifierRole;
54 return (
55 role === IdentifierRole.TopLevelDeclaration ||
56 role === IdentifierRole.ObjectShorthandTopLevelDeclaration ||
57 role === IdentifierRole.ImportDeclaration
58 );
59} exports.isTopLevelDeclaration = isTopLevelDeclaration;
60
61 function isBlockScopedDeclaration(token) {
62 const role = token.identifierRole;
63 // Treat top-level declarations as block scope since the distinction doesn't matter here.
64 return (
65 role === IdentifierRole.TopLevelDeclaration ||
66 role === IdentifierRole.BlockScopedDeclaration ||
67 role === IdentifierRole.ObjectShorthandTopLevelDeclaration ||
68 role === IdentifierRole.ObjectShorthandBlockScopedDeclaration
69 );
70} exports.isBlockScopedDeclaration = isBlockScopedDeclaration;
71
72 function isFunctionScopedDeclaration(token) {
73 const role = token.identifierRole;
74 return (
75 role === IdentifierRole.FunctionScopedDeclaration ||
76 role === IdentifierRole.ObjectShorthandFunctionScopedDeclaration
77 );
78} exports.isFunctionScopedDeclaration = isFunctionScopedDeclaration;
79
80 function isObjectShorthandDeclaration(token) {
81 return (
82 token.identifierRole === IdentifierRole.ObjectShorthandTopLevelDeclaration ||
83 token.identifierRole === IdentifierRole.ObjectShorthandBlockScopedDeclaration ||
84 token.identifierRole === IdentifierRole.ObjectShorthandFunctionScopedDeclaration
85 );
86} exports.isObjectShorthandDeclaration = isObjectShorthandDeclaration;
87
88// Object type used to represent tokens. Note that normally, tokens
89// simply exist as properties on the parser object. This is only
90// used for the onToken callback and the external tokenizer.
91 class Token {
92 constructor() {
93 this.type = _base.state.type;
94 this.contextualKeyword = _base.state.contextualKeyword;
95 this.start = _base.state.start;
96 this.end = _base.state.end;
97 this.scopeDepth = _base.state.scopeDepth;
98 this.isType = _base.state.isType;
99 this.identifierRole = null;
100 this.shadowsGlobal = false;
101 this.contextId = null;
102 this.rhsEndIndex = null;
103 this.isExpression = false;
104 this.numNullishCoalesceStarts = 0;
105 this.numNullishCoalesceEnds = 0;
106 this.isOptionalChainStart = false;
107 this.isOptionalChainEnd = false;
108 this.subscriptStartIndex = null;
109 this.nullishStartIndex = null;
110 }
111
112
113
114
115
116
117
118
119 // Initially false for all tokens, then may be computed in a follow-up step that does scope
120 // analysis.
121
122 // Initially false for all tokens, but may be set during transform to mark it as containing an
123 // await operation.
124
125
126 // For assignments, the index of the RHS. For export tokens, the end of the export.
127
128 // For class tokens, records if the class is a class expression or a class statement.
129
130 // Number of times to insert a `nullishCoalesce(` snippet before this token.
131
132 // Number of times to insert a `)` snippet after this token.
133
134 // If true, insert an `optionalChain([` snippet before this token.
135
136 // If true, insert a `])` snippet after this token.
137
138 // Tag for `.`, `?.`, `[`, `?.[`, `(`, and `?.(` to denote the "root" token for this
139 // subscript chain. This can be used to determine if this chain is an optional chain.
140
141 // Tag for `??` operators to denote the root token for this nullish coalescing call.
142
143} exports.Token = Token;
144
145// ## Tokenizer
146
147// Move to the next token
148 function next() {
149 _base.state.tokens.push(new Token());
150 nextToken();
151} exports.next = next;
152
153// Call instead of next when inside a template, since that needs to be handled differently.
154 function nextTemplateToken() {
155 _base.state.tokens.push(new Token());
156 _base.state.start = _base.state.pos;
157 readTmplToken();
158} exports.nextTemplateToken = nextTemplateToken;
159
160// The tokenizer never parses regexes by default. Instead, the parser is responsible for
161// instructing it to parse a regex when we see a slash at the start of an expression.
162 function retokenizeSlashAsRegex() {
163 if (_base.state.type === _types.TokenType.assign) {
164 --_base.state.pos;
165 }
166 readRegexp();
167} exports.retokenizeSlashAsRegex = retokenizeSlashAsRegex;
168
169 function pushTypeContext(existingTokensInType) {
170 for (let i = _base.state.tokens.length - existingTokensInType; i < _base.state.tokens.length; i++) {
171 _base.state.tokens[i].isType = true;
172 }
173 const oldIsType = _base.state.isType;
174 _base.state.isType = true;
175 return oldIsType;
176} exports.pushTypeContext = pushTypeContext;
177
178 function popTypeContext(oldIsType) {
179 _base.state.isType = oldIsType;
180} exports.popTypeContext = popTypeContext;
181
182 function eat(type) {
183 if (match(type)) {
184 next();
185 return true;
186 } else {
187 return false;
188 }
189} exports.eat = eat;
190
191 function match(type) {
192 return _base.state.type === type;
193} exports.match = match;
194
195 function lookaheadType() {
196 const snapshot = _base.state.snapshot();
197 next();
198 const type = _base.state.type;
199 _base.state.restoreFromSnapshot(snapshot);
200 return type;
201} exports.lookaheadType = lookaheadType;
202
203 class TypeAndKeyword {
204
205
206 constructor(type, contextualKeyword) {
207 this.type = type;
208 this.contextualKeyword = contextualKeyword;
209 }
210} exports.TypeAndKeyword = TypeAndKeyword;
211
212 function lookaheadTypeAndKeyword() {
213 const snapshot = _base.state.snapshot();
214 next();
215 const type = _base.state.type;
216 const contextualKeyword = _base.state.contextualKeyword;
217 _base.state.restoreFromSnapshot(snapshot);
218 return new TypeAndKeyword(type, contextualKeyword);
219} exports.lookaheadTypeAndKeyword = lookaheadTypeAndKeyword;
220
221// Read a single token, updating the parser object's token-related
222// properties.
223 function nextToken() {
224 skipSpace();
225 _base.state.start = _base.state.pos;
226 if (_base.state.pos >= _base.input.length) {
227 const tokens = _base.state.tokens;
228 // We normally run past the end a bit, but if we're way past the end, avoid an infinite loop.
229 // Also check the token positions rather than the types since sometimes we rewrite the token
230 // type to something else.
231 if (
232 tokens.length >= 2 &&
233 tokens[tokens.length - 1].start >= _base.input.length &&
234 tokens[tokens.length - 2].start >= _base.input.length
235 ) {
236 _util.unexpected.call(void 0, "Unexpectedly reached the end of input.");
237 }
238 finishToken(_types.TokenType.eof);
239 return;
240 }
241 readToken(_base.input.charCodeAt(_base.state.pos));
242} exports.nextToken = nextToken;
243
244function readToken(code) {
245 // Identifier or keyword. '\uXXXX' sequences are allowed in
246 // identifiers, so '\' also dispatches to that.
247 if (
248 _identifier.IS_IDENTIFIER_START[code] ||
249 code === _charcodes.charCodes.backslash ||
250 (code === _charcodes.charCodes.atSign && _base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.atSign)
251 ) {
252 _readWord2.default.call(void 0, );
253 } else {
254 getTokenFromCode(code);
255 }
256}
257
258function skipBlockComment() {
259 while (
260 _base.input.charCodeAt(_base.state.pos) !== _charcodes.charCodes.asterisk ||
261 _base.input.charCodeAt(_base.state.pos + 1) !== _charcodes.charCodes.slash
262 ) {
263 _base.state.pos++;
264 if (_base.state.pos > _base.input.length) {
265 _util.unexpected.call(void 0, "Unterminated comment", _base.state.pos - 2);
266 return;
267 }
268 }
269 _base.state.pos += 2;
270}
271
272 function skipLineComment(startSkip) {
273 let ch = _base.input.charCodeAt((_base.state.pos += startSkip));
274 if (_base.state.pos < _base.input.length) {
275 while (
276 ch !== _charcodes.charCodes.lineFeed &&
277 ch !== _charcodes.charCodes.carriageReturn &&
278 ch !== _charcodes.charCodes.lineSeparator &&
279 ch !== _charcodes.charCodes.paragraphSeparator &&
280 ++_base.state.pos < _base.input.length
281 ) {
282 ch = _base.input.charCodeAt(_base.state.pos);
283 }
284 }
285} exports.skipLineComment = skipLineComment;
286
287// Called at the start of the parse and after every token. Skips
288// whitespace and comments.
289 function skipSpace() {
290 while (_base.state.pos < _base.input.length) {
291 const ch = _base.input.charCodeAt(_base.state.pos);
292 switch (ch) {
293 case _charcodes.charCodes.carriageReturn:
294 if (_base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.lineFeed) {
295 ++_base.state.pos;
296 }
297
298 case _charcodes.charCodes.lineFeed:
299 case _charcodes.charCodes.lineSeparator:
300 case _charcodes.charCodes.paragraphSeparator:
301 ++_base.state.pos;
302 break;
303
304 case _charcodes.charCodes.slash:
305 switch (_base.input.charCodeAt(_base.state.pos + 1)) {
306 case _charcodes.charCodes.asterisk:
307 _base.state.pos += 2;
308 skipBlockComment();
309 break;
310
311 case _charcodes.charCodes.slash:
312 skipLineComment(2);
313 break;
314
315 default:
316 return;
317 }
318 break;
319
320 default:
321 if (_whitespace.IS_WHITESPACE[ch]) {
322 ++_base.state.pos;
323 } else {
324 return;
325 }
326 }
327 }
328} exports.skipSpace = skipSpace;
329
330// Called at the end of every token. Sets various fields, and skips the space after the token, so
331// that the next one's `start` will point at the right position.
332 function finishToken(
333 type,
334 contextualKeyword = _keywords.ContextualKeyword.NONE,
335) {
336 _base.state.end = _base.state.pos;
337 _base.state.type = type;
338 _base.state.contextualKeyword = contextualKeyword;
339} exports.finishToken = finishToken;
340
341// ### Token reading
342
343// This is the function that is called to fetch the next token. It
344// is somewhat obscure, because it works in character codes rather
345// than characters, and because operator parsing has been inlined
346// into it.
347//
348// All in the name of speed.
349function readToken_dot() {
350 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
351 if (nextChar >= _charcodes.charCodes.digit0 && nextChar <= _charcodes.charCodes.digit9) {
352 readNumber(true);
353 return;
354 }
355
356 if (nextChar === _charcodes.charCodes.dot && _base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.dot) {
357 _base.state.pos += 3;
358 finishToken(_types.TokenType.ellipsis);
359 } else {
360 ++_base.state.pos;
361 finishToken(_types.TokenType.dot);
362 }
363}
364
365function readToken_slash() {
366 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
367 if (nextChar === _charcodes.charCodes.equalsTo) {
368 finishOp(_types.TokenType.assign, 2);
369 } else {
370 finishOp(_types.TokenType.slash, 1);
371 }
372}
373
374function readToken_mult_modulo(code) {
375 // '%*'
376 let tokenType = code === _charcodes.charCodes.asterisk ? _types.TokenType.star : _types.TokenType.modulo;
377 let width = 1;
378 let nextChar = _base.input.charCodeAt(_base.state.pos + 1);
379
380 // Exponentiation operator **
381 if (code === _charcodes.charCodes.asterisk && nextChar === _charcodes.charCodes.asterisk) {
382 width++;
383 nextChar = _base.input.charCodeAt(_base.state.pos + 2);
384 tokenType = _types.TokenType.exponent;
385 }
386
387 // Match *= or %=, disallowing *=> which can be valid in flow.
388 if (
389 nextChar === _charcodes.charCodes.equalsTo &&
390 _base.input.charCodeAt(_base.state.pos + 2) !== _charcodes.charCodes.greaterThan
391 ) {
392 width++;
393 tokenType = _types.TokenType.assign;
394 }
395
396 finishOp(tokenType, width);
397}
398
399function readToken_pipe_amp(code) {
400 // '|&'
401 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
402
403 if (nextChar === code) {
404 if (_base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.equalsTo) {
405 // ||= or &&=
406 finishOp(_types.TokenType.assign, 3);
407 } else {
408 // || or &&
409 finishOp(code === _charcodes.charCodes.verticalBar ? _types.TokenType.logicalOR : _types.TokenType.logicalAND, 2);
410 }
411 return;
412 }
413
414 if (code === _charcodes.charCodes.verticalBar) {
415 // '|>'
416 if (nextChar === _charcodes.charCodes.greaterThan) {
417 finishOp(_types.TokenType.pipeline, 2);
418 return;
419 } else if (nextChar === _charcodes.charCodes.rightCurlyBrace && _base.isFlowEnabled) {
420 // '|}'
421 finishOp(_types.TokenType.braceBarR, 2);
422 return;
423 }
424 }
425
426 if (nextChar === _charcodes.charCodes.equalsTo) {
427 finishOp(_types.TokenType.assign, 2);
428 return;
429 }
430
431 finishOp(code === _charcodes.charCodes.verticalBar ? _types.TokenType.bitwiseOR : _types.TokenType.bitwiseAND, 1);
432}
433
434function readToken_caret() {
435 // '^'
436 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
437 if (nextChar === _charcodes.charCodes.equalsTo) {
438 finishOp(_types.TokenType.assign, 2);
439 } else {
440 finishOp(_types.TokenType.bitwiseXOR, 1);
441 }
442}
443
444function readToken_plus_min(code) {
445 // '+-'
446 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
447
448 if (nextChar === code) {
449 // Tentatively call this a prefix operator, but it might be changed to postfix later.
450 finishOp(_types.TokenType.preIncDec, 2);
451 return;
452 }
453
454 if (nextChar === _charcodes.charCodes.equalsTo) {
455 finishOp(_types.TokenType.assign, 2);
456 } else if (code === _charcodes.charCodes.plusSign) {
457 finishOp(_types.TokenType.plus, 1);
458 } else {
459 finishOp(_types.TokenType.minus, 1);
460 }
461}
462
463// '<>'
464function readToken_lt_gt(code) {
465 // Avoid right-shift for things like Array<Array<string>>.
466 if (code === _charcodes.charCodes.greaterThan && _base.state.isType) {
467 finishOp(_types.TokenType.greaterThan, 1);
468 return;
469 }
470 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
471
472 if (nextChar === code) {
473 const size =
474 code === _charcodes.charCodes.greaterThan && _base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.greaterThan
475 ? 3
476 : 2;
477 if (_base.input.charCodeAt(_base.state.pos + size) === _charcodes.charCodes.equalsTo) {
478 finishOp(_types.TokenType.assign, size + 1);
479 return;
480 }
481 finishOp(_types.TokenType.bitShift, size);
482 return;
483 }
484
485 if (nextChar === _charcodes.charCodes.equalsTo) {
486 // <= | >=
487 finishOp(_types.TokenType.relationalOrEqual, 2);
488 } else if (code === _charcodes.charCodes.lessThan) {
489 finishOp(_types.TokenType.lessThan, 1);
490 } else {
491 finishOp(_types.TokenType.greaterThan, 1);
492 }
493}
494
495function readToken_eq_excl(code) {
496 // '=!'
497 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
498 if (nextChar === _charcodes.charCodes.equalsTo) {
499 finishOp(_types.TokenType.equality, _base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.equalsTo ? 3 : 2);
500 return;
501 }
502 if (code === _charcodes.charCodes.equalsTo && nextChar === _charcodes.charCodes.greaterThan) {
503 // '=>'
504 _base.state.pos += 2;
505 finishToken(_types.TokenType.arrow);
506 return;
507 }
508 finishOp(code === _charcodes.charCodes.equalsTo ? _types.TokenType.eq : _types.TokenType.bang, 1);
509}
510
511function readToken_question() {
512 // '?'
513 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
514 const nextChar2 = _base.input.charCodeAt(_base.state.pos + 2);
515 if (nextChar === _charcodes.charCodes.questionMark && !_base.state.isType) {
516 if (nextChar2 === _charcodes.charCodes.equalsTo) {
517 // '??='
518 finishOp(_types.TokenType.assign, 3);
519 } else {
520 // '??'
521 finishOp(_types.TokenType.nullishCoalescing, 2);
522 }
523 } else if (
524 nextChar === _charcodes.charCodes.dot &&
525 !(nextChar2 >= _charcodes.charCodes.digit0 && nextChar2 <= _charcodes.charCodes.digit9)
526 ) {
527 // '.' not followed by a number
528 _base.state.pos += 2;
529 finishToken(_types.TokenType.questionDot);
530 } else {
531 ++_base.state.pos;
532 finishToken(_types.TokenType.question);
533 }
534}
535
536 function getTokenFromCode(code) {
537 switch (code) {
538 case _charcodes.charCodes.numberSign:
539 ++_base.state.pos;
540 finishToken(_types.TokenType.hash);
541 return;
542
543 // The interpretation of a dot depends on whether it is followed
544 // by a digit or another two dots.
545
546 case _charcodes.charCodes.dot:
547 readToken_dot();
548 return;
549
550 // Punctuation tokens.
551 case _charcodes.charCodes.leftParenthesis:
552 ++_base.state.pos;
553 finishToken(_types.TokenType.parenL);
554 return;
555 case _charcodes.charCodes.rightParenthesis:
556 ++_base.state.pos;
557 finishToken(_types.TokenType.parenR);
558 return;
559 case _charcodes.charCodes.semicolon:
560 ++_base.state.pos;
561 finishToken(_types.TokenType.semi);
562 return;
563 case _charcodes.charCodes.comma:
564 ++_base.state.pos;
565 finishToken(_types.TokenType.comma);
566 return;
567 case _charcodes.charCodes.leftSquareBracket:
568 ++_base.state.pos;
569 finishToken(_types.TokenType.bracketL);
570 return;
571 case _charcodes.charCodes.rightSquareBracket:
572 ++_base.state.pos;
573 finishToken(_types.TokenType.bracketR);
574 return;
575
576 case _charcodes.charCodes.leftCurlyBrace:
577 if (_base.isFlowEnabled && _base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.verticalBar) {
578 finishOp(_types.TokenType.braceBarL, 2);
579 } else {
580 ++_base.state.pos;
581 finishToken(_types.TokenType.braceL);
582 }
583 return;
584
585 case _charcodes.charCodes.rightCurlyBrace:
586 ++_base.state.pos;
587 finishToken(_types.TokenType.braceR);
588 return;
589
590 case _charcodes.charCodes.colon:
591 if (_base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.colon) {
592 finishOp(_types.TokenType.doubleColon, 2);
593 } else {
594 ++_base.state.pos;
595 finishToken(_types.TokenType.colon);
596 }
597 return;
598
599 case _charcodes.charCodes.questionMark:
600 readToken_question();
601 return;
602 case _charcodes.charCodes.atSign:
603 ++_base.state.pos;
604 finishToken(_types.TokenType.at);
605 return;
606
607 case _charcodes.charCodes.graveAccent:
608 ++_base.state.pos;
609 finishToken(_types.TokenType.backQuote);
610 return;
611
612 case _charcodes.charCodes.digit0: {
613 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
614 // '0x', '0X', '0o', '0O', '0b', '0B'
615 if (
616 nextChar === _charcodes.charCodes.lowercaseX ||
617 nextChar === _charcodes.charCodes.uppercaseX ||
618 nextChar === _charcodes.charCodes.lowercaseO ||
619 nextChar === _charcodes.charCodes.uppercaseO ||
620 nextChar === _charcodes.charCodes.lowercaseB ||
621 nextChar === _charcodes.charCodes.uppercaseB
622 ) {
623 readRadixNumber();
624 return;
625 }
626 }
627 // Anything else beginning with a digit is an integer, octal
628 // number, or float.
629 case _charcodes.charCodes.digit1:
630 case _charcodes.charCodes.digit2:
631 case _charcodes.charCodes.digit3:
632 case _charcodes.charCodes.digit4:
633 case _charcodes.charCodes.digit5:
634 case _charcodes.charCodes.digit6:
635 case _charcodes.charCodes.digit7:
636 case _charcodes.charCodes.digit8:
637 case _charcodes.charCodes.digit9:
638 readNumber(false);
639 return;
640
641 // Quotes produce strings.
642 case _charcodes.charCodes.quotationMark:
643 case _charcodes.charCodes.apostrophe:
644 readString(code);
645 return;
646
647 // Operators are parsed inline in tiny state machines. '=' (charCodes.equalsTo) is
648 // often referred to. `finishOp` simply skips the amount of
649 // characters it is given as second argument, and returns a token
650 // of the type given by its first argument.
651
652 case _charcodes.charCodes.slash:
653 readToken_slash();
654 return;
655
656 case _charcodes.charCodes.percentSign:
657 case _charcodes.charCodes.asterisk:
658 readToken_mult_modulo(code);
659 return;
660
661 case _charcodes.charCodes.verticalBar:
662 case _charcodes.charCodes.ampersand:
663 readToken_pipe_amp(code);
664 return;
665
666 case _charcodes.charCodes.caret:
667 readToken_caret();
668 return;
669
670 case _charcodes.charCodes.plusSign:
671 case _charcodes.charCodes.dash:
672 readToken_plus_min(code);
673 return;
674
675 case _charcodes.charCodes.lessThan:
676 case _charcodes.charCodes.greaterThan:
677 readToken_lt_gt(code);
678 return;
679
680 case _charcodes.charCodes.equalsTo:
681 case _charcodes.charCodes.exclamationMark:
682 readToken_eq_excl(code);
683 return;
684
685 case _charcodes.charCodes.tilde:
686 finishOp(_types.TokenType.tilde, 1);
687 return;
688
689 default:
690 break;
691 }
692
693 _util.unexpected.call(void 0, `Unexpected character '${String.fromCharCode(code)}'`, _base.state.pos);
694} exports.getTokenFromCode = getTokenFromCode;
695
696function finishOp(type, size) {
697 _base.state.pos += size;
698 finishToken(type);
699}
700
701function readRegexp() {
702 const start = _base.state.pos;
703 let escaped = false;
704 let inClass = false;
705 for (;;) {
706 if (_base.state.pos >= _base.input.length) {
707 _util.unexpected.call(void 0, "Unterminated regular expression", start);
708 return;
709 }
710 const code = _base.input.charCodeAt(_base.state.pos);
711 if (escaped) {
712 escaped = false;
713 } else {
714 if (code === _charcodes.charCodes.leftSquareBracket) {
715 inClass = true;
716 } else if (code === _charcodes.charCodes.rightSquareBracket && inClass) {
717 inClass = false;
718 } else if (code === _charcodes.charCodes.slash && !inClass) {
719 break;
720 }
721 escaped = code === _charcodes.charCodes.backslash;
722 }
723 ++_base.state.pos;
724 }
725 ++_base.state.pos;
726 // Need to use `skipWord` because '\uXXXX' sequences are allowed here (don't ask).
727 skipWord();
728
729 finishToken(_types.TokenType.regexp);
730}
731
732// Read an integer. We allow any valid digit, including hex digits, plus numeric separators, and
733// stop at any other character.
734function readInt() {
735 while (true) {
736 const code = _base.input.charCodeAt(_base.state.pos);
737 if (
738 (code >= _charcodes.charCodes.digit0 && code <= _charcodes.charCodes.digit9) ||
739 (code >= _charcodes.charCodes.lowercaseA && code <= _charcodes.charCodes.lowercaseF) ||
740 (code >= _charcodes.charCodes.uppercaseA && code <= _charcodes.charCodes.uppercaseF) ||
741 code === _charcodes.charCodes.underscore
742 ) {
743 _base.state.pos++;
744 } else {
745 break;
746 }
747 }
748}
749
750function readRadixNumber() {
751 let isBigInt = false;
752
753 _base.state.pos += 2; // 0x
754 readInt();
755
756 if (_base.input.charCodeAt(_base.state.pos) === _charcodes.charCodes.lowercaseN) {
757 ++_base.state.pos;
758 isBigInt = true;
759 }
760
761 if (isBigInt) {
762 finishToken(_types.TokenType.bigint);
763 return;
764 }
765
766 finishToken(_types.TokenType.num);
767}
768
769// Read an integer, octal integer, or floating-point number.
770function readNumber(startsWithDot) {
771 let isBigInt = false;
772
773 if (!startsWithDot) {
774 readInt();
775 }
776
777 let nextChar = _base.input.charCodeAt(_base.state.pos);
778 if (nextChar === _charcodes.charCodes.dot) {
779 ++_base.state.pos;
780 readInt();
781 nextChar = _base.input.charCodeAt(_base.state.pos);
782 }
783
784 if (nextChar === _charcodes.charCodes.uppercaseE || nextChar === _charcodes.charCodes.lowercaseE) {
785 nextChar = _base.input.charCodeAt(++_base.state.pos);
786 if (nextChar === _charcodes.charCodes.plusSign || nextChar === _charcodes.charCodes.dash) {
787 ++_base.state.pos;
788 }
789 readInt();
790 nextChar = _base.input.charCodeAt(_base.state.pos);
791 }
792
793 if (nextChar === _charcodes.charCodes.lowercaseN) {
794 ++_base.state.pos;
795 isBigInt = true;
796 }
797
798 if (isBigInt) {
799 finishToken(_types.TokenType.bigint);
800 return;
801 }
802 finishToken(_types.TokenType.num);
803}
804
805function readString(quote) {
806 _base.state.pos++;
807 for (;;) {
808 if (_base.state.pos >= _base.input.length) {
809 _util.unexpected.call(void 0, "Unterminated string constant");
810 return;
811 }
812 const ch = _base.input.charCodeAt(_base.state.pos);
813 if (ch === _charcodes.charCodes.backslash) {
814 _base.state.pos++;
815 } else if (ch === quote) {
816 break;
817 }
818 _base.state.pos++;
819 }
820 _base.state.pos++;
821 finishToken(_types.TokenType.string);
822}
823
824// Reads template string tokens.
825function readTmplToken() {
826 for (;;) {
827 if (_base.state.pos >= _base.input.length) {
828 _util.unexpected.call(void 0, "Unterminated template");
829 return;
830 }
831 const ch = _base.input.charCodeAt(_base.state.pos);
832 if (
833 ch === _charcodes.charCodes.graveAccent ||
834 (ch === _charcodes.charCodes.dollarSign && _base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.leftCurlyBrace)
835 ) {
836 if (_base.state.pos === _base.state.start && match(_types.TokenType.template)) {
837 if (ch === _charcodes.charCodes.dollarSign) {
838 _base.state.pos += 2;
839 finishToken(_types.TokenType.dollarBraceL);
840 return;
841 } else {
842 ++_base.state.pos;
843 finishToken(_types.TokenType.backQuote);
844 return;
845 }
846 }
847 finishToken(_types.TokenType.template);
848 return;
849 }
850 if (ch === _charcodes.charCodes.backslash) {
851 _base.state.pos++;
852 }
853 _base.state.pos++;
854 }
855}
856
857// Skip to the end of the current word. Note that this is the same as the snippet at the end of
858// readWord, but calling skipWord from readWord seems to slightly hurt performance from some rough
859// measurements.
860 function skipWord() {
861 while (_base.state.pos < _base.input.length) {
862 const ch = _base.input.charCodeAt(_base.state.pos);
863 if (_identifier.IS_IDENTIFIER_CHAR[ch]) {
864 _base.state.pos++;
865 } else if (ch === _charcodes.charCodes.backslash) {
866 // \u
867 _base.state.pos += 2;
868 if (_base.input.charCodeAt(_base.state.pos) === _charcodes.charCodes.leftCurlyBrace) {
869 while (
870 _base.state.pos < _base.input.length &&
871 _base.input.charCodeAt(_base.state.pos) !== _charcodes.charCodes.rightCurlyBrace
872 ) {
873 _base.state.pos++;
874 }
875 _base.state.pos++;
876 }
877 } else {
878 break;
879 }
880 }
881} exports.skipWord = skipWord;