source: frontend/node_modules/es-module-lexer/lexer.js

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

Fix frontend appearance

  • Property mode set to 100644
File size: 26.4 KB
Line 
1let source, pos, end,
2 openTokenDepth,
3 lastTokenPos,
4 openTokenPosStack,
5 openClassPosStack,
6 curDynamicImport,
7 templateStackDepth,
8 facade,
9 lastSlashWasDivision,
10 nextBraceIsClass,
11 templateDepth,
12 templateStack,
13 imports,
14 exports,
15 name;
16
17function addImport (ss, s, e, d) {
18 const impt = { ss, se: d === -2 ? e : d === -1 ? e + 1 : 0, s, e, d, a: -1, n: undefined, at: null };
19 imports.push(impt);
20 return impt;
21}
22
23function addExport (s, e, ls, le) {
24 exports.push({
25 s,
26 e,
27 ls,
28 le,
29 n: s[0] === '"' ? readString(s, '"') : s[0] === "'" ? readString(s, "'") : source.slice(s, e),
30 ln: ls[0] === '"' ? readString(ls, '"') : ls[0] === "'" ? readString(ls, "'") : source.slice(ls, le)
31 });
32}
33
34function readName (impt) {
35 let { d, s } = impt;
36 if (d !== -1)
37 s++;
38 impt.n = readString(s, source.charCodeAt(s - 1));
39}
40
41// Note: parsing is based on the _assumption_ that the source is already valid
42export function parse (_source, _name) {
43 openTokenDepth = 0;
44 curDynamicImport = null;
45 templateDepth = -1;
46 lastTokenPos = -1;
47 lastSlashWasDivision = false;
48 templateStack = Array(1024);
49 templateStackDepth = 0;
50 openTokenPosStack = Array(1024);
51 openClassPosStack = Array(1024);
52 nextBraceIsClass = false;
53 facade = true;
54 name = _name || '@';
55
56 imports = [];
57 exports = [];
58
59 source = _source;
60 pos = -1;
61 end = source.length - 1;
62 let ch = 0;
63
64 // start with a pure "module-only" parser
65 m: while (pos++ < end) {
66 ch = source.charCodeAt(pos);
67
68 if (ch === 32 || ch < 14 && ch > 8)
69 continue;
70
71 switch (ch) {
72 case 101/*e*/:
73 if (openTokenDepth === 0 && keywordStart(pos) && source.startsWith('xport', pos + 1)) {
74 tryParseExportStatement();
75 // export might have been a non-pure declaration
76 if (!facade) {
77 lastTokenPos = pos;
78 break m;
79 }
80 }
81 break;
82 case 105/*i*/:
83 if (keywordStart(pos) && source.startsWith('mport', pos + 1))
84 tryParseImportStatement();
85 break;
86 case 59/*;*/:
87 break;
88 case 47/*/*/: {
89 const next_ch = source.charCodeAt(pos + 1);
90 if (next_ch === 47/*/*/) {
91 lineComment();
92 // dont update lastToken
93 continue;
94 }
95 else if (next_ch === 42/***/) {
96 blockComment(true);
97 // dont update lastToken
98 continue;
99 }
100 // fallthrough
101 }
102 default:
103 // as soon as we hit a non-module token, we go to main parser
104 facade = false;
105 pos--;
106 break m;
107 }
108 lastTokenPos = pos;
109 }
110
111 while (pos++ < end) {
112 ch = source.charCodeAt(pos);
113
114 if (ch === 32 || ch < 14 && ch > 8)
115 continue;
116
117 switch (ch) {
118 case 101/*e*/:
119 if (openTokenDepth === 0 && keywordStart(pos) && source.startsWith('xport', pos + 1))
120 tryParseExportStatement();
121 break;
122 case 105/*i*/:
123 if (keywordStart(pos) && source.startsWith('mport', pos + 1))
124 tryParseImportStatement();
125 break;
126 case 99/*c*/:
127 if (keywordStart(pos) && source.startsWith('lass', pos + 1) && isBrOrWs(source.charCodeAt(pos + 5)))
128 nextBraceIsClass = true;
129 break;
130 case 40/*(*/:
131 openTokenPosStack[openTokenDepth++] = lastTokenPos;
132 break;
133 case 41/*)*/:
134 if (openTokenDepth === 0)
135 syntaxError();
136 openTokenDepth--;
137 if (curDynamicImport && curDynamicImport.d === openTokenPosStack[openTokenDepth]) {
138 if (curDynamicImport.e === 0)
139 curDynamicImport.e = pos;
140 curDynamicImport.se = pos;
141 curDynamicImport = null;
142 }
143 break;
144 case 91/*[*/:
145 openTokenPosStack[openTokenDepth++] = lastTokenPos;
146 break;
147 case 93/*]*/:
148 if (openTokenDepth === 0)
149 syntaxError();
150 openTokenDepth--;
151 break;
152 case 44/*,*/:
153 if (curDynamicImport && curDynamicImport.e === 0 && curDynamicImport.d === openTokenPosStack[openTokenDepth - 1]) {
154 curDynamicImport.e = lastTokenPos + 1;
155 pos++;
156 commentWhitespace(true);
157 curDynamicImport.a = pos;
158 pos--;
159 }
160 break;
161 case 123/*{*/:
162 // dynamic import followed by { is not a dynamic import (so remove)
163 // this is a sneaky way to get around { import () {} } v { import () }
164 // block / object ambiguity without a parser (assuming source is valid)
165 if (source.charCodeAt(lastTokenPos) === 41/*)*/ && imports.length && imports[imports.length - 1].e === lastTokenPos) {
166 imports.pop();
167 }
168 openClassPosStack[openTokenDepth] = nextBraceIsClass;
169 nextBraceIsClass = false;
170 openTokenPosStack[openTokenDepth++] = lastTokenPos;
171 break;
172 case 125/*}*/:
173 if (openTokenDepth === 0)
174 syntaxError();
175 if (openTokenDepth-- === templateDepth) {
176 templateDepth = templateStack[--templateStackDepth];
177 templateString();
178 }
179 else {
180 if (templateDepth !== -1 && openTokenDepth < templateDepth)
181 syntaxError();
182 }
183 break;
184 case 39/*'*/:
185 case 34/*"*/:
186 stringLiteral(ch);
187 break;
188 case 47/*/*/: {
189 const next_ch = source.charCodeAt(pos + 1);
190 if (next_ch === 47/*/*/) {
191 lineComment();
192 // dont update lastToken
193 continue;
194 }
195 else if (next_ch === 42/***/) {
196 blockComment(true);
197 // dont update lastToken
198 continue;
199 }
200 else {
201 // Division / regex ambiguity handling based on checking backtrack analysis of:
202 // - what token came previously (lastToken)
203 // - if a closing brace or paren, what token came before the corresponding
204 // opening brace or paren (lastOpenTokenIndex)
205 const lastToken = source.charCodeAt(lastTokenPos);
206 const lastExport = exports[exports.length - 1];
207 if (isExpressionPunctuator(lastToken) &&
208 !(lastToken === 46/*.*/ && (source.charCodeAt(lastTokenPos - 1) >= 48/*0*/ && source.charCodeAt(lastTokenPos - 1) <= 57/*9*/)) &&
209 !(lastToken === 43/*+*/ && source.charCodeAt(lastTokenPos - 1) === 43/*+*/) && !(lastToken === 45/*-*/ && source.charCodeAt(lastTokenPos - 1) === 45/*-*/) ||
210 lastToken === 41/*)*/ && isParenKeyword(openTokenPosStack[openTokenDepth]) ||
211 openTokenDepth > 0 && lastToken === 102/*f*/ && source.charCodeAt(lastTokenPos - 1) === 111/*o*/ && isForOfBinding(lastTokenPos - 2) && isForParen(openTokenPosStack[openTokenDepth - 1]) ||
212 lastToken === 125/*}*/ && (isExpressionTerminator(openTokenPosStack[openTokenDepth]) || openClassPosStack[openTokenDepth]) ||
213 lastToken === 47/*/*/ && lastSlashWasDivision ||
214 isExpressionKeyword(lastTokenPos) ||
215 !lastToken) {
216 regularExpression();
217 lastSlashWasDivision = false;
218 }
219 else if (lastExport && lastTokenPos >= lastExport.s && lastTokenPos <= lastExport.e) {
220 // export default /some-regexp/
221 regularExpression();
222 lastSlashWasDivision = false;
223 }
224 else {
225 lastSlashWasDivision = true;
226 }
227 }
228 break;
229 }
230 case 96/*`*/:
231 templateString();
232 break;
233 }
234 lastTokenPos = pos;
235 }
236
237 if (templateDepth !== -1 || openTokenDepth)
238 syntaxError();
239
240 return [imports, exports, facade];
241}
242
243function tryParseImportStatement () {
244 const startPos = pos;
245
246 pos += 6;
247
248 let ch = commentWhitespace(true);
249
250 switch (ch) {
251 // dynamic import
252 case 40/*(*/:
253 openTokenPosStack[openTokenDepth++] = startPos;
254 if (source.charCodeAt(lastTokenPos) === 46/*.*/)
255 return;
256 // dynamic import indicated by positive d
257 const impt = addImport(startPos, pos + 1, 0, startPos);
258 curDynamicImport = impt;
259 // try parse a string, to record a safe dynamic import string
260 pos++;
261 ch = commentWhitespace(true);
262 if (ch === 39/*'*/ || ch === 34/*"*/) {
263 stringLiteral(ch);
264 }
265 else {
266 pos--;
267 return;
268 }
269 pos++;
270 ch = commentWhitespace(true);
271 if (ch === 44/*,*/) {
272 impt.e = pos;
273 pos++;
274 ch = commentWhitespace(true);
275 impt.a = pos;
276 readName(impt);
277 pos--;
278 }
279 else if (ch === 41/*)*/) {
280 openTokenDepth--;
281 impt.e = pos;
282 impt.se = pos;
283 readName(impt);
284 }
285 else {
286 pos--;
287 }
288 return;
289 // import.meta
290 case 46/*.*/:
291 pos++;
292 ch = commentWhitespace(true);
293 // import.meta indicated by d === -2
294 if (ch === 109/*m*/ && source.startsWith('eta', pos + 1) && source.charCodeAt(lastTokenPos) !== 46/*.*/)
295 addImport(startPos, startPos, pos + 4, -2);
296 return;
297
298 default:
299 // no space after "import" -> not an import keyword
300 if (pos === startPos + 6)
301 break;
302 case 34/*"*/:
303 case 39/*'*/:
304 case 123/*{*/:
305 case 42/***/:
306 // import statement only permitted at base-level
307 if (openTokenDepth !== 0) {
308 pos--;
309 return;
310 }
311 while (pos < end) {
312 ch = source.charCodeAt(pos);
313 if (ch === 39/*'*/ || ch === 34/*"*/) {
314 readImportString(startPos, ch);
315 return;
316 }
317 pos++;
318 }
319 syntaxError();
320 }
321}
322
323function tryParseExportStatement () {
324 const sStartPos = pos;
325 const prevExport = exports.length;
326
327 pos += 6;
328
329 const curPos = pos;
330
331 let ch = commentWhitespace(true);
332
333 if (pos === curPos && !isPunctuator(ch))
334 return;
335
336 switch (ch) {
337 // export default ...
338 case 100/*d*/:
339 addExport(pos, pos + 7, -1, -1);
340 return;
341
342 // export async? function*? name () {
343 case 97/*a*/:
344 pos += 5;
345 commentWhitespace(true);
346 // fallthrough
347 case 102/*f*/:
348 pos += 8;
349 ch = commentWhitespace(true);
350 if (ch === 42/***/) {
351 pos++;
352 ch = commentWhitespace(true);
353 }
354 const startPos = pos;
355 ch = readToWsOrPunctuator(ch);
356 addExport(startPos, pos, startPos, pos);
357 pos--;
358 return;
359
360 // export class name ...
361 case 99/*c*/:
362 if (source.startsWith('lass', pos + 1) && isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos + 5))) {
363 pos += 5;
364 ch = commentWhitespace(true);
365 const startPos = pos;
366 ch = readToWsOrPunctuator(ch);
367 addExport(startPos, pos, startPos, pos);
368 pos--;
369 return;
370 }
371 pos += 2;
372 // fallthrough
373
374 // export var/let/const name = ...(, name = ...)+
375 case 118/*v*/:
376 case 109/*l*/:
377 // destructured initializations not currently supported (skipped for { or [)
378 // also, lexing names after variable equals is skipped (export var p = function () { ... }, q = 5 skips "q")
379 pos += 2;
380 facade = false;
381 do {
382 pos++;
383 ch = commentWhitespace(true);
384 const startPos = pos;
385 ch = readToWsOrPunctuator(ch);
386 // dont yet handle [ { destructurings
387 if (ch === 123/*{*/ || ch === 91/*[*/) {
388 pos--;
389 return;
390 }
391 if (pos === startPos)
392 return;
393 addExport(startPos, pos, startPos, pos);
394 ch = commentWhitespace(true);
395 if (ch === 61/*=*/) {
396 pos--;
397 return;
398 }
399 } while (ch === 44/*,*/);
400 pos--;
401 return;
402
403
404 // export {...}
405 case 123/*{*/:
406 pos++;
407 ch = commentWhitespace(true);
408 while (true) {
409 const startPos = pos;
410 readToWsOrPunctuator(ch);
411 const endPos = pos;
412 commentWhitespace(true);
413 ch = readExportAs(startPos, endPos);
414 // ,
415 if (ch === 44/*,*/) {
416 pos++;
417 ch = commentWhitespace(true);
418 }
419 if (ch === 125/*}*/)
420 break;
421 if (pos === startPos)
422 return syntaxError();
423 if (pos > end)
424 return syntaxError();
425 }
426 pos++;
427 ch = commentWhitespace(true);
428 break;
429
430 // export *
431 // export * as X
432 case 42/***/:
433 pos++;
434 commentWhitespace(true);
435 ch = readExportAs(pos, pos);
436 ch = commentWhitespace(true);
437 break;
438 }
439
440 // from ...
441 if (ch === 102/*f*/ && source.startsWith('rom', pos + 1)) {
442 pos += 4;
443 readImportString(sStartPos, commentWhitespace(true));
444
445 // There were no local names.
446 for (let i = prevExport; i < exports.length; ++i) {
447 exports[i].ls = exports[i].le = -1;
448 exports[i].ln = undefined;
449 }
450 }
451 else {
452 pos--;
453 }
454}
455
456/*
457 * Ported from Acorn
458 *
459 * MIT License
460
461 * Copyright (C) 2012-2020 by various contributors (see AUTHORS)
462
463 * Permission is hereby granted, free of charge, to any person obtaining a copy
464 * of this software and associated documentation files (the "Software"), to deal
465 * in the Software without restriction, including without limitation the rights
466 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
467 * copies of the Software, and to permit persons to whom the Software is
468 * furnished to do so, subject to the following conditions:
469
470 * The above copyright notice and this permission notice shall be included in
471 * all copies or substantial portions of the Software.
472
473 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
474 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
475 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
476 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
477 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
478 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
479 * THE SOFTWARE.
480 */
481let acornPos;
482function readString (start, quote) {
483 acornPos = start;
484 let out = '', chunkStart = acornPos;
485 for (;;) {
486 if (acornPos >= source.length) syntaxError();
487 const ch = source.charCodeAt(acornPos);
488 if (ch === quote) break;
489 if (ch === 92) { // '\'
490 out += source.slice(chunkStart, acornPos);
491 out += readEscapedChar();
492 chunkStart = acornPos;
493 }
494 else if (ch === 0x2028 || ch === 0x2029) {
495 ++acornPos;
496 }
497 else {
498 if (isBr(ch)) syntaxError();
499 ++acornPos;
500 }
501 }
502 out += source.slice(chunkStart, acornPos++);
503 return out;
504}
505
506// Used to read escaped characters
507
508function readEscapedChar () {
509 let ch = source.charCodeAt(++acornPos);
510 ++acornPos;
511 switch (ch) {
512 case 110: return '\n'; // 'n' -> '\n'
513 case 114: return '\r'; // 'r' -> '\r'
514 case 120: return String.fromCharCode(readHexChar(2)); // 'x'
515 case 117: return readCodePointToString(); // 'u'
516 case 116: return '\t'; // 't' -> '\t'
517 case 98: return '\b'; // 'b' -> '\b'
518 case 118: return '\u000b'; // 'v' -> '\u000b'
519 case 102: return '\f'; // 'f' -> '\f'
520 case 13: if (source.charCodeAt(acornPos) === 10) ++acornPos; // '\r\n'
521 case 10: // ' \n'
522 return '';
523 case 56:
524 case 57:
525 syntaxError();
526 default:
527 if (ch >= 48 && ch <= 55) {
528 let octalStr = source.substr(acornPos - 1, 3).match(/^[0-7]+/)[0];
529 let octal = parseInt(octalStr, 8);
530 if (octal > 255) {
531 octalStr = octalStr.slice(0, -1);
532 octal = parseInt(octalStr, 8);
533 }
534 acornPos += octalStr.length - 1;
535 ch = source.charCodeAt(acornPos);
536 if (octalStr !== '0' || ch === 56 || ch === 57)
537 syntaxError();
538 return String.fromCharCode(octal);
539 }
540 if (isBr(ch)) {
541 // Unicode new line characters after \ get removed from output in both
542 // template literals and strings
543 return '';
544 }
545 return String.fromCharCode(ch);
546 }
547}
548
549// Used to read character escape sequences ('\x', '\u', '\U').
550
551function readHexChar (len) {
552 const start = acornPos;
553 let total = 0, lastCode = 0;
554 for (let i = 0; i < len; ++i, ++acornPos) {
555 let code = source.charCodeAt(acornPos), val;
556
557 if (code === 95) {
558 if (lastCode === 95 || i === 0) syntaxError();
559 lastCode = code;
560 continue;
561 }
562
563 if (code >= 97) val = code - 97 + 10; // a
564 else if (code >= 65) val = code - 65 + 10; // A
565 else if (code >= 48 && code <= 57) val = code - 48; // 0-9
566 else break;
567 if (val >= 16) break;
568 lastCode = code;
569 total = total * 16 + val;
570 }
571
572 if (lastCode === 95 || acornPos - start !== len) syntaxError();
573
574 return total;
575}
576
577// Read a string value, interpreting backslash-escapes.
578
579function readCodePointToString () {
580 const ch = source.charCodeAt(acornPos);
581 let code;
582 if (ch === 123) { // '{'
583 ++acornPos;
584 code = readHexChar(source.indexOf('}', acornPos) - acornPos);
585 ++acornPos;
586 if (code > 0x10FFFF) syntaxError();
587 } else {
588 code = readHexChar(4);
589 }
590 // UTF-16 Decoding
591 if (code <= 0xFFFF) return String.fromCharCode(code);
592 code -= 0x10000;
593 return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00);
594}
595
596/*
597 * </ Acorn Port>
598 */
599
600function readExportAs (startPos, endPos) {
601 let ch = source.charCodeAt(pos);
602 let ls = startPos, le = endPos;
603 if (ch === 97 /*a*/) {
604 pos += 2;
605 ch = commentWhitespace(true);
606 startPos = pos;
607 readToWsOrPunctuator(ch);
608 endPos = pos;
609 ch = commentWhitespace(true);
610 }
611 if (pos !== startPos)
612 addExport(startPos, endPos, ls, le);
613 return ch;
614}
615
616function readImportString (ss, ch) {
617 const startPos = pos + 1;
618 if (ch === 39/*'*/ || ch === 34/*"*/) {
619 stringLiteral(ch);
620 }
621 else {
622 syntaxError();
623 return;
624 }
625 const impt = addImport(ss, startPos, pos, -1);
626 readName(impt);
627 pos++;
628 ch = commentWhitespace(false);
629 if (ch !== 119/*w*/ || !source.startsWith('ith', pos + 1)) {
630 pos--;
631 return;
632 }
633 const attrIndex = pos;
634
635 pos += 4;
636 ch = commentWhitespace(true);
637 if (ch !== 123/*{*/) {
638 pos = attrIndex;
639 return;
640 }
641 const attrStart = pos;
642 const attrs = [];
643 do {
644 pos++;
645 ch = commentWhitespace(true);
646 let key, keyStart, keyEnd;
647 if (ch === 39/*'*/ || ch === 34/*"*/) {
648 keyStart = pos;
649 stringLiteral(ch);
650 keyEnd = pos + 1;
651 key = readString(keyStart, ch);
652 pos++;
653 ch = commentWhitespace(true);
654 }
655 else {
656 keyStart = pos;
657 ch = readToWsOrPunctuator(ch);
658 keyEnd = pos;
659 key = source.slice(keyStart, keyEnd);
660 }
661 if (ch !== 58/*:*/) {
662 pos = attrIndex;
663 return;
664 }
665 pos++;
666 ch = commentWhitespace(true);
667 let value, valueStart;
668 if (ch === 39/*'*/ || ch === 34/*"*/) {
669 valueStart = pos;
670 stringLiteral(ch);
671 value = readString(valueStart, ch);
672 }
673 else {
674 pos = attrIndex;
675 return;
676 }
677 attrs.push([key, value]);
678 pos++;
679 ch = commentWhitespace(true);
680 if (ch === 44/*,*/) {
681 pos++;
682 continue;
683 }
684 if (ch === 125/*}*/)
685 break;
686 pos = attrIndex;
687 return;
688 } while (true);
689 impt.a = attrStart;
690 impt.at = attrs;
691 impt.se = pos + 1;
692}
693
694function commentWhitespace (br) {
695 let ch;
696 do {
697 ch = source.charCodeAt(pos);
698 if (ch === 47/*/*/) {
699 const next_ch = source.charCodeAt(pos + 1);
700 if (next_ch === 47/*/*/)
701 lineComment();
702 else if (next_ch === 42/***/)
703 blockComment(br);
704 else
705 return ch;
706 }
707 else if (br ? !isBrOrWs(ch): !isWsNotBr(ch)) {
708 return ch;
709 }
710 } while (pos++ < end);
711 return ch;
712}
713
714function templateString () {
715 while (pos++ < end) {
716 const ch = source.charCodeAt(pos);
717 if (ch === 36/*$*/ && source.charCodeAt(pos + 1) === 123/*{*/) {
718 pos++;
719 templateStack[templateStackDepth++] = templateDepth;
720 templateDepth = ++openTokenDepth;
721 return;
722 }
723 if (ch === 96/*`*/)
724 return;
725 if (ch === 92/*\*/)
726 pos++;
727 }
728 syntaxError();
729}
730
731function blockComment (br) {
732 pos++;
733 while (pos++ < end) {
734 const ch = source.charCodeAt(pos);
735 if (!br && isBr(ch))
736 return;
737 if (ch === 42/***/ && source.charCodeAt(pos + 1) === 47/*/*/) {
738 pos++;
739 return;
740 }
741 }
742}
743
744function lineComment () {
745 while (pos++ < end) {
746 const ch = source.charCodeAt(pos);
747 if (ch === 10/*\n*/ || ch === 13/*\r*/)
748 return;
749 }
750}
751
752function stringLiteral (quote) {
753 while (pos++ < end) {
754 let ch = source.charCodeAt(pos);
755 if (ch === quote)
756 return;
757 if (ch === 92/*\*/) {
758 ch = source.charCodeAt(++pos);
759 if (ch === 13/*\r*/ && source.charCodeAt(pos + 1) === 10/*\n*/)
760 pos++;
761 }
762 else if (isBr(ch))
763 break;
764 }
765 syntaxError();
766}
767
768function regexCharacterClass () {
769 while (pos++ < end) {
770 let ch = source.charCodeAt(pos);
771 if (ch === 93/*]*/)
772 return ch;
773 if (ch === 92/*\*/)
774 pos++;
775 else if (ch === 10/*\n*/ || ch === 13/*\r*/)
776 break;
777 }
778 syntaxError();
779}
780
781function regularExpression () {
782 while (pos++ < end) {
783 let ch = source.charCodeAt(pos);
784 if (ch === 47/*/*/)
785 return;
786 if (ch === 91/*[*/)
787 ch = regexCharacterClass();
788 else if (ch === 92/*\*/)
789 pos++;
790 else if (ch === 10/*\n*/ || ch === 13/*\r*/)
791 break;
792 }
793 syntaxError();
794}
795
796function readToWsOrPunctuator (ch) {
797 do {
798 if (isBrOrWs(ch) || isPunctuator(ch))
799 return ch;
800 } while (ch = source.charCodeAt(++pos));
801 return ch;
802}
803
804// Note: non-asii BR and whitespace checks omitted for perf / footprint
805// if there is a significant user need this can be reconsidered
806function isBr (c) {
807 return c === 13/*\r*/ || c === 10/*\n*/;
808}
809
810function isWsNotBr (c) {
811 return c === 9 || c === 11 || c === 12 || c === 32 || c === 160;
812}
813
814function isBrOrWs (c) {
815 return c > 8 && c < 14 || c === 32 || c === 160;
816}
817
818function isBrOrWsOrPunctuatorNotDot (c) {
819 return c > 8 && c < 14 || c === 32 || c === 160 || isPunctuator(c) && c !== 46/*.*/;
820}
821
822function keywordStart (pos) {
823 return pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - 1));
824}
825
826function readPrecedingKeyword (pos, match) {
827 if (pos < match.length - 1)
828 return false;
829 return source.startsWith(match, pos - match.length + 1) && (pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - match.length)));
830}
831
832function readPrecedingKeyword1 (pos, ch) {
833 return source.charCodeAt(pos) === ch && (pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - 1)));
834}
835
836// Detects one of case, debugger, delete, do, else, in, instanceof, new,
837// return, throw, typeof, void, yield, await
838function isExpressionKeyword (pos) {
839 switch (source.charCodeAt(pos)) {
840 case 100/*d*/:
841 switch (source.charCodeAt(pos - 1)) {
842 case 105/*i*/:
843 // void
844 return readPrecedingKeyword(pos - 2, 'vo');
845 case 108/*l*/:
846 // yield
847 return readPrecedingKeyword(pos - 2, 'yie');
848 default:
849 return false;
850 }
851 case 101/*e*/:
852 switch (source.charCodeAt(pos - 1)) {
853 case 115/*s*/:
854 switch (source.charCodeAt(pos - 2)) {
855 case 108/*l*/:
856 // else
857 return readPrecedingKeyword1(pos - 3, 101/*e*/);
858 case 97/*a*/:
859 // case
860 return readPrecedingKeyword1(pos - 3, 99/*c*/);
861 default:
862 return false;
863 }
864 case 116/*t*/:
865 // delete
866 return readPrecedingKeyword(pos - 2, 'dele');
867 default:
868 return false;
869 }
870 case 102/*f*/:
871 if (source.charCodeAt(pos - 1) !== 111/*o*/ || source.charCodeAt(pos - 2) !== 101/*e*/)
872 return false;
873 switch (source.charCodeAt(pos - 3)) {
874 case 99/*c*/:
875 // instanceof
876 return readPrecedingKeyword(pos - 4, 'instan');
877 case 112/*p*/:
878 // typeof
879 return readPrecedingKeyword(pos - 4, 'ty');
880 default:
881 return false;
882 }
883 case 110/*n*/:
884 // in, return
885 return readPrecedingKeyword1(pos - 1, 105/*i*/) || readPrecedingKeyword(pos - 1, 'retur');
886 case 111/*o*/:
887 // do
888 return readPrecedingKeyword1(pos - 1, 100/*d*/);
889 case 114/*r*/:
890 // debugger
891 return readPrecedingKeyword(pos - 1, 'debugge');
892 case 116/*t*/:
893 // await
894 return readPrecedingKeyword(pos - 1, 'awai');
895 case 119/*w*/:
896 switch (source.charCodeAt(pos - 1)) {
897 case 101/*e*/:
898 // new
899 return readPrecedingKeyword1(pos - 2, 110/*n*/);
900 case 111/*o*/:
901 // throw
902 return readPrecedingKeyword(pos - 2, 'thr');
903 default:
904 return false;
905 }
906 }
907 return false;
908}
909
910function isParenKeyword (curPos) {
911 return source.charCodeAt(curPos) === 101/*e*/ && source.startsWith('whil', curPos - 4) ||
912 source.charCodeAt(curPos) === 114/*r*/ && source.startsWith('fo', curPos - 2) ||
913 source.charCodeAt(curPos - 1) === 105/*i*/ && source.charCodeAt(curPos) === 102/*f*/;
914}
915
916function isForParen (curPos) {
917 return source.charCodeAt(curPos) === 114/*r*/ && source.startsWith('fo', curPos - 2);
918}
919
920// In valid JS, the for-of `of` keyword always follows a binding,
921// which ends with an identifier-tail char, ']', '}', or ')'.
922function isForOfBinding (pos) {
923 const ch = source.charCodeAt(pos);
924 if (!isBrOrWs(ch) && ch !== 93/*]*/ && ch !== 125/*}*/ && ch !== 41/*)*/)
925 return false;
926 while (pos > 0 && isBrOrWs(source.charCodeAt(pos)))
927 pos--;
928 const c = source.charCodeAt(pos);
929 return c === 93/*]*/ || c === 125/*}*/ || c === 41/*)*/ || !isPunctuator(c);
930}
931
932function isPunctuator (ch) {
933 // 23 possible punctuator endings: !%&()*+,-./:;<=>?[]^{}|~
934 return ch === 33/*!*/ || ch === 37/*%*/ || ch === 38/*&*/ ||
935 ch > 39 && ch < 48 || ch > 57 && ch < 64 ||
936 ch === 91/*[*/ || ch === 93/*]*/ || ch === 94/*^*/ ||
937 ch > 122 && ch < 127;
938}
939
940function isExpressionPunctuator (ch) {
941 // 20 possible expression endings: !%&(*+,-.:;<=>?[^{|~
942 return ch === 33/*!*/ || ch === 37/*%*/ || ch === 38/*&*/ ||
943 ch > 39 && ch < 47 && ch !== 41 || ch > 57 && ch < 64 ||
944 ch === 91/*[*/ || ch === 94/*^*/ || ch > 122 && ch < 127 && ch !== 125/*}*/;
945}
946
947function isExpressionTerminator (curPos) {
948 // detects:
949 // => ; ) finally catch else
950 // as all of these followed by a { will indicate a statement brace
951 switch (source.charCodeAt(curPos)) {
952 case 62/*>*/:
953 return source.charCodeAt(curPos - 1) === 61/*=*/;
954 case 59/*;*/:
955 case 41/*)*/:
956 return true;
957 case 104/*h*/:
958 return source.startsWith('catc', curPos - 4);
959 case 121/*y*/:
960 return source.startsWith('finall', curPos - 6);
961 case 101/*e*/:
962 return source.startsWith('els', curPos - 3);
963 }
964 return false;
965}
966
967function syntaxError () {
968 throw Object.assign(new Error(`Parse error ${name}:${source.slice(0, pos).split('\n').length}:${pos - source.lastIndexOf('\n', pos - 1)}`), { idx: pos });
969}
Note: See TracBrowser for help on using the repository browser.