source: frontend/node_modules/sucrase/dist/parser/tokenizer/index.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

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