UNPKG

27.4 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 finishOp(_types.TokenType.incDec, 2);
411 return;
412 }
413
414 if (nextChar === _charcodes.charCodes.equalsTo) {
415 finishOp(_types.TokenType.assign, 2);
416 } else if (code === _charcodes.charCodes.plusSign) {
417 finishOp(_types.TokenType.plus, 1);
418 } else {
419 finishOp(_types.TokenType.minus, 1);
420 }
421}
422
423// '<>'
424function readToken_lt_gt(code) {
425 // Avoid right-shift for things like Array<Array<string>>.
426 if (code === _charcodes.charCodes.greaterThan && _base.state.isType) {
427 finishOp(_types.TokenType.greaterThan, 1);
428 return;
429 }
430 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
431
432 if (nextChar === code) {
433 const size =
434 code === _charcodes.charCodes.greaterThan && _base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.greaterThan
435 ? 3
436 : 2;
437 if (_base.input.charCodeAt(_base.state.pos + size) === _charcodes.charCodes.equalsTo) {
438 finishOp(_types.TokenType.assign, size + 1);
439 return;
440 }
441 finishOp(_types.TokenType.bitShift, size);
442 return;
443 }
444
445 if (nextChar === _charcodes.charCodes.equalsTo) {
446 // <= | >=
447 finishOp(_types.TokenType.relationalOrEqual, 2);
448 } else if (code === _charcodes.charCodes.lessThan) {
449 finishOp(_types.TokenType.lessThan, 1);
450 } else {
451 finishOp(_types.TokenType.greaterThan, 1);
452 }
453}
454
455function readToken_eq_excl(code) {
456 // '=!'
457 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
458 if (nextChar === _charcodes.charCodes.equalsTo) {
459 finishOp(_types.TokenType.equality, _base.input.charCodeAt(_base.state.pos + 2) === _charcodes.charCodes.equalsTo ? 3 : 2);
460 return;
461 }
462 if (code === _charcodes.charCodes.equalsTo && nextChar === _charcodes.charCodes.greaterThan) {
463 // '=>'
464 _base.state.pos += 2;
465 finishToken(_types.TokenType.arrow);
466 return;
467 }
468 finishOp(code === _charcodes.charCodes.equalsTo ? _types.TokenType.eq : _types.TokenType.bang, 1);
469}
470
471function readToken_question() {
472 // '?'
473 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
474 const nextChar2 = _base.input.charCodeAt(_base.state.pos + 2);
475 if (nextChar === _charcodes.charCodes.questionMark && !_base.state.isType) {
476 if (nextChar2 === _charcodes.charCodes.equalsTo) {
477 // '??='
478 finishOp(_types.TokenType.assign, 3);
479 } else {
480 // '??'
481 finishOp(_types.TokenType.nullishCoalescing, 2);
482 }
483 } else if (
484 nextChar === _charcodes.charCodes.dot &&
485 !(nextChar2 >= _charcodes.charCodes.digit0 && nextChar2 <= _charcodes.charCodes.digit9)
486 ) {
487 // '.' not followed by a number
488 _base.state.pos += 2;
489 finishToken(_types.TokenType.questionDot);
490 } else {
491 ++_base.state.pos;
492 finishToken(_types.TokenType.question);
493 }
494}
495
496 function getTokenFromCode(code) {
497 switch (code) {
498 case _charcodes.charCodes.numberSign:
499 ++_base.state.pos;
500 finishToken(_types.TokenType.hash);
501 return;
502
503 // The interpretation of a dot depends on whether it is followed
504 // by a digit or another two dots.
505
506 case _charcodes.charCodes.dot:
507 readToken_dot();
508 return;
509
510 // Punctuation tokens.
511 case _charcodes.charCodes.leftParenthesis:
512 ++_base.state.pos;
513 finishToken(_types.TokenType.parenL);
514 return;
515 case _charcodes.charCodes.rightParenthesis:
516 ++_base.state.pos;
517 finishToken(_types.TokenType.parenR);
518 return;
519 case _charcodes.charCodes.semicolon:
520 ++_base.state.pos;
521 finishToken(_types.TokenType.semi);
522 return;
523 case _charcodes.charCodes.comma:
524 ++_base.state.pos;
525 finishToken(_types.TokenType.comma);
526 return;
527 case _charcodes.charCodes.leftSquareBracket:
528 ++_base.state.pos;
529 finishToken(_types.TokenType.bracketL);
530 return;
531 case _charcodes.charCodes.rightSquareBracket:
532 ++_base.state.pos;
533 finishToken(_types.TokenType.bracketR);
534 return;
535
536 case _charcodes.charCodes.leftCurlyBrace:
537 if (_base.isFlowEnabled && _base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.verticalBar) {
538 finishOp(_types.TokenType.braceBarL, 2);
539 } else {
540 ++_base.state.pos;
541 finishToken(_types.TokenType.braceL);
542 }
543 return;
544
545 case _charcodes.charCodes.rightCurlyBrace:
546 ++_base.state.pos;
547 finishToken(_types.TokenType.braceR);
548 return;
549
550 case _charcodes.charCodes.colon:
551 if (_base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.colon) {
552 finishOp(_types.TokenType.doubleColon, 2);
553 } else {
554 ++_base.state.pos;
555 finishToken(_types.TokenType.colon);
556 }
557 return;
558
559 case _charcodes.charCodes.questionMark:
560 readToken_question();
561 return;
562 case _charcodes.charCodes.atSign:
563 ++_base.state.pos;
564 finishToken(_types.TokenType.at);
565 return;
566
567 case _charcodes.charCodes.graveAccent:
568 ++_base.state.pos;
569 finishToken(_types.TokenType.backQuote);
570 return;
571
572 case _charcodes.charCodes.digit0: {
573 const nextChar = _base.input.charCodeAt(_base.state.pos + 1);
574 // '0x', '0X', '0o', '0O', '0b', '0B'
575 if (
576 nextChar === _charcodes.charCodes.lowercaseX ||
577 nextChar === _charcodes.charCodes.uppercaseX ||
578 nextChar === _charcodes.charCodes.lowercaseO ||
579 nextChar === _charcodes.charCodes.uppercaseO ||
580 nextChar === _charcodes.charCodes.lowercaseB ||
581 nextChar === _charcodes.charCodes.uppercaseB
582 ) {
583 readRadixNumber();
584 return;
585 }
586 }
587 // Anything else beginning with a digit is an integer, octal
588 // number, or float.
589 case _charcodes.charCodes.digit1:
590 case _charcodes.charCodes.digit2:
591 case _charcodes.charCodes.digit3:
592 case _charcodes.charCodes.digit4:
593 case _charcodes.charCodes.digit5:
594 case _charcodes.charCodes.digit6:
595 case _charcodes.charCodes.digit7:
596 case _charcodes.charCodes.digit8:
597 case _charcodes.charCodes.digit9:
598 readNumber(false);
599 return;
600
601 // Quotes produce strings.
602 case _charcodes.charCodes.quotationMark:
603 case _charcodes.charCodes.apostrophe:
604 readString(code);
605 return;
606
607 // Operators are parsed inline in tiny state machines. '=' (charCodes.equalsTo) is
608 // often referred to. `finishOp` simply skips the amount of
609 // characters it is given as second argument, and returns a token
610 // of the type given by its first argument.
611
612 case _charcodes.charCodes.slash:
613 readToken_slash();
614 return;
615
616 case _charcodes.charCodes.percentSign:
617 case _charcodes.charCodes.asterisk:
618 readToken_mult_modulo(code);
619 return;
620
621 case _charcodes.charCodes.verticalBar:
622 case _charcodes.charCodes.ampersand:
623 readToken_pipe_amp(code);
624 return;
625
626 case _charcodes.charCodes.caret:
627 readToken_caret();
628 return;
629
630 case _charcodes.charCodes.plusSign:
631 case _charcodes.charCodes.dash:
632 readToken_plus_min(code);
633 return;
634
635 case _charcodes.charCodes.lessThan:
636 case _charcodes.charCodes.greaterThan:
637 readToken_lt_gt(code);
638 return;
639
640 case _charcodes.charCodes.equalsTo:
641 case _charcodes.charCodes.exclamationMark:
642 readToken_eq_excl(code);
643 return;
644
645 case _charcodes.charCodes.tilde:
646 finishOp(_types.TokenType.tilde, 1);
647 return;
648
649 default:
650 break;
651 }
652
653 _util.unexpected.call(void 0, `Unexpected character '${String.fromCharCode(code)}'`, _base.state.pos);
654} exports.getTokenFromCode = getTokenFromCode;
655
656function finishOp(type, size) {
657 _base.state.pos += size;
658 finishToken(type);
659}
660
661function readRegexp() {
662 const start = _base.state.pos;
663 let escaped = false;
664 let inClass = false;
665 for (;;) {
666 if (_base.state.pos >= _base.input.length) {
667 _util.unexpected.call(void 0, "Unterminated regular expression", start);
668 return;
669 }
670 const code = _base.input.charCodeAt(_base.state.pos);
671 if (escaped) {
672 escaped = false;
673 } else {
674 if (code === _charcodes.charCodes.leftSquareBracket) {
675 inClass = true;
676 } else if (code === _charcodes.charCodes.rightSquareBracket && inClass) {
677 inClass = false;
678 } else if (code === _charcodes.charCodes.slash && !inClass) {
679 break;
680 }
681 escaped = code === _charcodes.charCodes.backslash;
682 }
683 ++_base.state.pos;
684 }
685 ++_base.state.pos;
686 // Need to use `skipWord` because '\uXXXX' sequences are allowed here (don't ask).
687 skipWord();
688
689 finishToken(_types.TokenType.regexp);
690}
691
692// Read an integer. We allow any valid digit, including hex digits, plus numeric separators, and
693// stop at any other character.
694function readInt() {
695 while (true) {
696 const code = _base.input.charCodeAt(_base.state.pos);
697 if (
698 (code >= _charcodes.charCodes.digit0 && code <= _charcodes.charCodes.digit9) ||
699 (code >= _charcodes.charCodes.lowercaseA && code <= _charcodes.charCodes.lowercaseF) ||
700 (code >= _charcodes.charCodes.uppercaseA && code <= _charcodes.charCodes.uppercaseF) ||
701 code === _charcodes.charCodes.underscore
702 ) {
703 _base.state.pos++;
704 } else {
705 break;
706 }
707 }
708}
709
710function readRadixNumber() {
711 let isBigInt = false;
712
713 _base.state.pos += 2; // 0x
714 readInt();
715
716 if (_base.input.charCodeAt(_base.state.pos) === _charcodes.charCodes.lowercaseN) {
717 ++_base.state.pos;
718 isBigInt = true;
719 }
720
721 if (isBigInt) {
722 finishToken(_types.TokenType.bigint);
723 return;
724 }
725
726 finishToken(_types.TokenType.num);
727}
728
729// Read an integer, octal integer, or floating-point number.
730function readNumber(startsWithDot) {
731 let isBigInt = false;
732
733 if (!startsWithDot) {
734 readInt();
735 }
736
737 let nextChar = _base.input.charCodeAt(_base.state.pos);
738 if (nextChar === _charcodes.charCodes.dot) {
739 ++_base.state.pos;
740 readInt();
741 nextChar = _base.input.charCodeAt(_base.state.pos);
742 }
743
744 if (nextChar === _charcodes.charCodes.uppercaseE || nextChar === _charcodes.charCodes.lowercaseE) {
745 nextChar = _base.input.charCodeAt(++_base.state.pos);
746 if (nextChar === _charcodes.charCodes.plusSign || nextChar === _charcodes.charCodes.dash) {
747 ++_base.state.pos;
748 }
749 readInt();
750 nextChar = _base.input.charCodeAt(_base.state.pos);
751 }
752
753 if (nextChar === _charcodes.charCodes.lowercaseN) {
754 ++_base.state.pos;
755 isBigInt = true;
756 }
757
758 if (isBigInt) {
759 finishToken(_types.TokenType.bigint);
760 return;
761 }
762 finishToken(_types.TokenType.num);
763}
764
765function readString(quote) {
766 _base.state.pos++;
767 for (;;) {
768 if (_base.state.pos >= _base.input.length) {
769 _util.unexpected.call(void 0, "Unterminated string constant");
770 return;
771 }
772 const ch = _base.input.charCodeAt(_base.state.pos);
773 if (ch === _charcodes.charCodes.backslash) {
774 _base.state.pos++;
775 } else if (ch === quote) {
776 break;
777 }
778 _base.state.pos++;
779 }
780 _base.state.pos++;
781 finishToken(_types.TokenType.string);
782}
783
784// Reads template string tokens.
785function readTmplToken() {
786 for (;;) {
787 if (_base.state.pos >= _base.input.length) {
788 _util.unexpected.call(void 0, "Unterminated template");
789 return;
790 }
791 const ch = _base.input.charCodeAt(_base.state.pos);
792 if (
793 ch === _charcodes.charCodes.graveAccent ||
794 (ch === _charcodes.charCodes.dollarSign && _base.input.charCodeAt(_base.state.pos + 1) === _charcodes.charCodes.leftCurlyBrace)
795 ) {
796 if (_base.state.pos === _base.state.start && match(_types.TokenType.template)) {
797 if (ch === _charcodes.charCodes.dollarSign) {
798 _base.state.pos += 2;
799 finishToken(_types.TokenType.dollarBraceL);
800 return;
801 } else {
802 ++_base.state.pos;
803 finishToken(_types.TokenType.backQuote);
804 return;
805 }
806 }
807 finishToken(_types.TokenType.template);
808 return;
809 }
810 if (ch === _charcodes.charCodes.backslash) {
811 _base.state.pos++;
812 }
813 _base.state.pos++;
814 }
815}
816
817// Skip to the end of the current word. Note that this is the same as the snippet at the end of
818// readWord, but calling skipWord from readWord seems to slightly hurt performance from some rough
819// measurements.
820 function skipWord() {
821 while (_base.state.pos < _base.input.length) {
822 const ch = _base.input.charCodeAt(_base.state.pos);
823 if (_identifier.IS_IDENTIFIER_CHAR[ch]) {
824 _base.state.pos++;
825 } else if (ch === _charcodes.charCodes.backslash) {
826 // \u
827 _base.state.pos += 2;
828 if (_base.input.charCodeAt(_base.state.pos) === _charcodes.charCodes.leftCurlyBrace) {
829 while (
830 _base.state.pos < _base.input.length &&
831 _base.input.charCodeAt(_base.state.pos) !== _charcodes.charCodes.rightCurlyBrace
832 ) {
833 _base.state.pos++;
834 }
835 _base.state.pos++;
836 }
837 } else {
838 break;
839 }
840 }
841} exports.skipWord = skipWord;