UNPKG

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