aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/es-module-lexer/lexer.js
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/es-module-lexer/lexer.js
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/es-module-lexer/lexer.js')
-rw-r--r--vanilla/node_modules/es-module-lexer/lexer.js925
1 files changed, 925 insertions, 0 deletions
diff --git a/vanilla/node_modules/es-module-lexer/lexer.js b/vanilla/node_modules/es-module-lexer/lexer.js
new file mode 100644
index 0000000..587fafe
--- /dev/null
+++ b/vanilla/node_modules/es-module-lexer/lexer.js
@@ -0,0 +1,925 @@
+let source, pos, end,
+ openTokenDepth,
+ lastTokenPos,
+ openTokenPosStack,
+ openClassPosStack,
+ curDynamicImport,
+ templateStackDepth,
+ facade,
+ lastSlashWasDivision,
+ nextBraceIsClass,
+ templateDepth,
+ templateStack,
+ imports,
+ exports,
+ name;
+
+function addImport (ss, s, e, d) {
+ const impt = { ss, se: d === -2 ? e : d === -1 ? e + 1 : 0, s, e, d, a: -1, n: undefined };
+ imports.push(impt);
+ return impt;
+}
+
+function addExport (s, e, ls, le) {
+ exports.push({
+ s,
+ e,
+ ls,
+ le,
+ n: s[0] === '"' ? readString(s, '"') : s[0] === "'" ? readString(s, "'") : source.slice(s, e),
+ ln: ls[0] === '"' ? readString(ls, '"') : ls[0] === "'" ? readString(ls, "'") : source.slice(ls, le)
+ });
+}
+
+function readName (impt) {
+ let { d, s } = impt;
+ if (d !== -1)
+ s++;
+ impt.n = readString(s, source.charCodeAt(s - 1));
+}
+
+// Note: parsing is based on the _assumption_ that the source is already valid
+export function parse (_source, _name) {
+ openTokenDepth = 0;
+ curDynamicImport = null;
+ templateDepth = -1;
+ lastTokenPos = -1;
+ lastSlashWasDivision = false;
+ templateStack = Array(1024);
+ templateStackDepth = 0;
+ openTokenPosStack = Array(1024);
+ openClassPosStack = Array(1024);
+ nextBraceIsClass = false;
+ facade = true;
+ name = _name || '@';
+
+ imports = [];
+ exports = [];
+
+ source = _source;
+ pos = -1;
+ end = source.length - 1;
+ let ch = 0;
+
+ // start with a pure "module-only" parser
+ m: while (pos++ < end) {
+ ch = source.charCodeAt(pos);
+
+ if (ch === 32 || ch < 14 && ch > 8)
+ continue;
+
+ switch (ch) {
+ case 101/*e*/:
+ if (openTokenDepth === 0 && keywordStart(pos) && source.startsWith('xport', pos + 1)) {
+ tryParseExportStatement();
+ // export might have been a non-pure declaration
+ if (!facade) {
+ lastTokenPos = pos;
+ break m;
+ }
+ }
+ break;
+ case 105/*i*/:
+ if (keywordStart(pos) && source.startsWith('mport', pos + 1))
+ tryParseImportStatement();
+ break;
+ case 59/*;*/:
+ break;
+ case 47/*/*/: {
+ const next_ch = source.charCodeAt(pos + 1);
+ if (next_ch === 47/*/*/) {
+ lineComment();
+ // dont update lastToken
+ continue;
+ }
+ else if (next_ch === 42/***/) {
+ blockComment(true);
+ // dont update lastToken
+ continue;
+ }
+ // fallthrough
+ }
+ default:
+ // as soon as we hit a non-module token, we go to main parser
+ facade = false;
+ pos--;
+ break m;
+ }
+ lastTokenPos = pos;
+ }
+
+ while (pos++ < end) {
+ ch = source.charCodeAt(pos);
+
+ if (ch === 32 || ch < 14 && ch > 8)
+ continue;
+
+ switch (ch) {
+ case 101/*e*/:
+ if (openTokenDepth === 0 && keywordStart(pos) && source.startsWith('xport', pos + 1))
+ tryParseExportStatement();
+ break;
+ case 105/*i*/:
+ if (keywordStart(pos) && source.startsWith('mport', pos + 1))
+ tryParseImportStatement();
+ break;
+ case 99/*c*/:
+ if (keywordStart(pos) && source.startsWith('lass', pos + 1) && isBrOrWs(source.charCodeAt(pos + 5)))
+ nextBraceIsClass = true;
+ break;
+ case 40/*(*/:
+ openTokenPosStack[openTokenDepth++] = lastTokenPos;
+ break;
+ case 41/*)*/:
+ if (openTokenDepth === 0)
+ syntaxError();
+ openTokenDepth--;
+ if (curDynamicImport && curDynamicImport.d === openTokenPosStack[openTokenDepth]) {
+ if (curDynamicImport.e === 0)
+ curDynamicImport.e = pos;
+ curDynamicImport.se = pos;
+ curDynamicImport = null;
+ }
+ break;
+ case 123/*{*/:
+ // dynamic import followed by { is not a dynamic import (so remove)
+ // this is a sneaky way to get around { import () {} } v { import () }
+ // block / object ambiguity without a parser (assuming source is valid)
+ if (source.charCodeAt(lastTokenPos) === 41/*)*/ && imports.length && imports[imports.length - 1].e === lastTokenPos) {
+ imports.pop();
+ }
+ openClassPosStack[openTokenDepth] = nextBraceIsClass;
+ nextBraceIsClass = false;
+ openTokenPosStack[openTokenDepth++] = lastTokenPos;
+ break;
+ case 125/*}*/:
+ if (openTokenDepth === 0)
+ syntaxError();
+ if (openTokenDepth-- === templateDepth) {
+ templateDepth = templateStack[--templateStackDepth];
+ templateString();
+ }
+ else {
+ if (templateDepth !== -1 && openTokenDepth < templateDepth)
+ syntaxError();
+ }
+ break;
+ case 39/*'*/:
+ case 34/*"*/:
+ stringLiteral(ch);
+ break;
+ case 47/*/*/: {
+ const next_ch = source.charCodeAt(pos + 1);
+ if (next_ch === 47/*/*/) {
+ lineComment();
+ // dont update lastToken
+ continue;
+ }
+ else if (next_ch === 42/***/) {
+ blockComment(true);
+ // dont update lastToken
+ continue;
+ }
+ else {
+ // Division / regex ambiguity handling based on checking backtrack analysis of:
+ // - what token came previously (lastToken)
+ // - if a closing brace or paren, what token came before the corresponding
+ // opening brace or paren (lastOpenTokenIndex)
+ const lastToken = source.charCodeAt(lastTokenPos);
+ const lastExport = exports[exports.length - 1];
+ if (isExpressionPunctuator(lastToken) &&
+ !(lastToken === 46/*.*/ && (source.charCodeAt(lastTokenPos - 1) >= 48/*0*/ && source.charCodeAt(lastTokenPos - 1) <= 57/*9*/)) &&
+ !(lastToken === 43/*+*/ && source.charCodeAt(lastTokenPos - 1) === 43/*+*/) && !(lastToken === 45/*-*/ && source.charCodeAt(lastTokenPos - 1) === 45/*-*/) ||
+ lastToken === 41/*)*/ && isParenKeyword(openTokenPosStack[openTokenDepth]) ||
+ lastToken === 125/*}*/ && (isExpressionTerminator(openTokenPosStack[openTokenDepth]) || openClassPosStack[openTokenDepth]) ||
+ lastToken === 47/*/*/ && lastSlashWasDivision ||
+ isExpressionKeyword(lastTokenPos) ||
+ !lastToken) {
+ regularExpression();
+ lastSlashWasDivision = false;
+ }
+ else if (lastExport && lastTokenPos >= lastExport.s && lastTokenPos <= lastExport.e) {
+ // export default /some-regexp/
+ regularExpression();
+ lastSlashWasDivision = false;
+ }
+ else {
+ lastSlashWasDivision = true;
+ }
+ }
+ break;
+ }
+ case 96/*`*/:
+ templateString();
+ break;
+ }
+ lastTokenPos = pos;
+ }
+
+ if (templateDepth !== -1 || openTokenDepth)
+ syntaxError();
+
+ return [imports, exports, facade];
+}
+
+function tryParseImportStatement () {
+ const startPos = pos;
+
+ pos += 6;
+
+ let ch = commentWhitespace(true);
+
+ switch (ch) {
+ // dynamic import
+ case 40/*(*/:
+ openTokenPosStack[openTokenDepth++] = startPos;
+ if (source.charCodeAt(lastTokenPos) === 46/*.*/)
+ return;
+ // dynamic import indicated by positive d
+ const impt = addImport(startPos, pos + 1, 0, startPos);
+ curDynamicImport = impt;
+ // try parse a string, to record a safe dynamic import string
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 39/*'*/ || ch === 34/*"*/) {
+ stringLiteral(ch);
+ }
+ else {
+ pos--;
+ return;
+ }
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 44/*,*/) {
+ impt.e = pos;
+ pos++;
+ ch = commentWhitespace(true);
+ impt.a = pos;
+ readName(impt);
+ pos--;
+ }
+ else if (ch === 41/*)*/) {
+ openTokenDepth--;
+ impt.e = pos;
+ impt.se = pos;
+ readName(impt);
+ }
+ else {
+ pos--;
+ }
+ return;
+ // import.meta
+ case 46/*.*/:
+ pos++;
+ ch = commentWhitespace(true);
+ // import.meta indicated by d === -2
+ if (ch === 109/*m*/ && source.startsWith('eta', pos + 1) && source.charCodeAt(lastTokenPos) !== 46/*.*/)
+ addImport(startPos, startPos, pos + 4, -2);
+ return;
+
+ default:
+ // no space after "import" -> not an import keyword
+ if (pos === startPos + 6)
+ break;
+ case 34/*"*/:
+ case 39/*'*/:
+ case 123/*{*/:
+ case 42/***/:
+ // import statement only permitted at base-level
+ if (openTokenDepth !== 0) {
+ pos--;
+ return;
+ }
+ while (pos < end) {
+ ch = source.charCodeAt(pos);
+ if (ch === 39/*'*/ || ch === 34/*"*/) {
+ readImportString(startPos, ch);
+ return;
+ }
+ pos++;
+ }
+ syntaxError();
+ }
+}
+
+function tryParseExportStatement () {
+ const sStartPos = pos;
+ const prevExport = exports.length;
+
+ pos += 6;
+
+ const curPos = pos;
+
+ let ch = commentWhitespace(true);
+
+ if (pos === curPos && !isPunctuator(ch))
+ return;
+
+ switch (ch) {
+ // export default ...
+ case 100/*d*/:
+ addExport(pos, pos + 7, -1, -1);
+ return;
+
+ // export async? function*? name () {
+ case 97/*a*/:
+ pos += 5;
+ commentWhitespace(true);
+ // fallthrough
+ case 102/*f*/:
+ pos += 8;
+ ch = commentWhitespace(true);
+ if (ch === 42/***/) {
+ pos++;
+ ch = commentWhitespace(true);
+ }
+ const startPos = pos;
+ ch = readToWsOrPunctuator(ch);
+ addExport(startPos, pos, startPos, pos);
+ pos--;
+ return;
+
+ // export class name ...
+ case 99/*c*/:
+ if (source.startsWith('lass', pos + 1) && isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos + 5))) {
+ pos += 5;
+ ch = commentWhitespace(true);
+ const startPos = pos;
+ ch = readToWsOrPunctuator(ch);
+ addExport(startPos, pos, startPos, pos);
+ pos--;
+ return;
+ }
+ pos += 2;
+ // fallthrough
+
+ // export var/let/const name = ...(, name = ...)+
+ case 118/*v*/:
+ case 109/*l*/:
+ // destructured initializations not currently supported (skipped for { or [)
+ // also, lexing names after variable equals is skipped (export var p = function () { ... }, q = 5 skips "q")
+ pos += 2;
+ facade = false;
+ do {
+ pos++;
+ ch = commentWhitespace(true);
+ const startPos = pos;
+ ch = readToWsOrPunctuator(ch);
+ // dont yet handle [ { destructurings
+ if (ch === 123/*{*/ || ch === 91/*[*/) {
+ pos--;
+ return;
+ }
+ if (pos === startPos)
+ return;
+ addExport(startPos, pos, startPos, pos);
+ ch = commentWhitespace(true);
+ if (ch === 61/*=*/) {
+ pos--;
+ return;
+ }
+ } while (ch === 44/*,*/);
+ pos--;
+ return;
+
+
+ // export {...}
+ case 123/*{*/:
+ pos++;
+ ch = commentWhitespace(true);
+ while (true) {
+ const startPos = pos;
+ readToWsOrPunctuator(ch);
+ const endPos = pos;
+ commentWhitespace(true);
+ ch = readExportAs(startPos, endPos);
+ // ,
+ if (ch === 44/*,*/) {
+ pos++;
+ ch = commentWhitespace(true);
+ }
+ if (ch === 125/*}*/)
+ break;
+ if (pos === startPos)
+ return syntaxError();
+ if (pos > end)
+ return syntaxError();
+ }
+ pos++;
+ ch = commentWhitespace(true);
+ break;
+
+ // export *
+ // export * as X
+ case 42/***/:
+ pos++;
+ commentWhitespace(true);
+ ch = readExportAs(pos, pos);
+ ch = commentWhitespace(true);
+ break;
+ }
+
+ // from ...
+ if (ch === 102/*f*/ && source.startsWith('rom', pos + 1)) {
+ pos += 4;
+ readImportString(sStartPos, commentWhitespace(true));
+
+ // There were no local names.
+ for (let i = prevExport; i < exports.length; ++i) {
+ exports[i].ls = exports[i].le = -1;
+ exports[i].ln = undefined;
+ }
+ }
+ else {
+ pos--;
+ }
+}
+
+/*
+ * Ported from Acorn
+ *
+ * MIT License
+
+ * Copyright (C) 2012-2020 by various contributors (see AUTHORS)
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+let acornPos;
+function readString (start, quote) {
+ acornPos = start;
+ let out = '', chunkStart = acornPos;
+ for (;;) {
+ if (acornPos >= source.length) syntaxError();
+ const ch = source.charCodeAt(acornPos);
+ if (ch === quote) break;
+ if (ch === 92) { // '\'
+ out += source.slice(chunkStart, acornPos);
+ out += readEscapedChar();
+ chunkStart = acornPos;
+ }
+ else if (ch === 0x2028 || ch === 0x2029) {
+ ++acornPos;
+ }
+ else {
+ if (isBr(ch)) syntaxError();
+ ++acornPos;
+ }
+ }
+ out += source.slice(chunkStart, acornPos++);
+ return out;
+}
+
+// Used to read escaped characters
+
+function readEscapedChar () {
+ let ch = source.charCodeAt(++acornPos);
+ ++acornPos;
+ switch (ch) {
+ case 110: return '\n'; // 'n' -> '\n'
+ case 114: return '\r'; // 'r' -> '\r'
+ case 120: return String.fromCharCode(readHexChar(2)); // 'x'
+ case 117: return readCodePointToString(); // 'u'
+ case 116: return '\t'; // 't' -> '\t'
+ case 98: return '\b'; // 'b' -> '\b'
+ case 118: return '\u000b'; // 'v' -> '\u000b'
+ case 102: return '\f'; // 'f' -> '\f'
+ case 13: if (source.charCodeAt(acornPos) === 10) ++acornPos; // '\r\n'
+ case 10: // ' \n'
+ return '';
+ case 56:
+ case 57:
+ syntaxError();
+ default:
+ if (ch >= 48 && ch <= 55) {
+ let octalStr = source.substr(acornPos - 1, 3).match(/^[0-7]+/)[0];
+ let octal = parseInt(octalStr, 8);
+ if (octal > 255) {
+ octalStr = octalStr.slice(0, -1);
+ octal = parseInt(octalStr, 8);
+ }
+ acornPos += octalStr.length - 1;
+ ch = source.charCodeAt(acornPos);
+ if (octalStr !== '0' || ch === 56 || ch === 57)
+ syntaxError();
+ return String.fromCharCode(octal);
+ }
+ if (isBr(ch)) {
+ // Unicode new line characters after \ get removed from output in both
+ // template literals and strings
+ return '';
+ }
+ return String.fromCharCode(ch);
+ }
+}
+
+// Used to read character escape sequences ('\x', '\u', '\U').
+
+function readHexChar (len) {
+ const start = acornPos;
+ let total = 0, lastCode = 0;
+ for (let i = 0; i < len; ++i, ++acornPos) {
+ let code = source.charCodeAt(acornPos), val;
+
+ if (code === 95) {
+ if (lastCode === 95 || i === 0) syntaxError();
+ lastCode = code;
+ continue;
+ }
+
+ if (code >= 97) val = code - 97 + 10; // a
+ else if (code >= 65) val = code - 65 + 10; // A
+ else if (code >= 48 && code <= 57) val = code - 48; // 0-9
+ else break;
+ if (val >= 16) break;
+ lastCode = code;
+ total = total * 16 + val;
+ }
+
+ if (lastCode === 95 || acornPos - start !== len) syntaxError();
+
+ return total;
+}
+
+// Read a string value, interpreting backslash-escapes.
+
+function readCodePointToString () {
+ const ch = source.charCodeAt(acornPos);
+ let code;
+ if (ch === 123) { // '{'
+ ++acornPos;
+ code = readHexChar(source.indexOf('}', acornPos) - acornPos);
+ ++acornPos;
+ if (code > 0x10FFFF) syntaxError();
+ } else {
+ code = readHexChar(4);
+ }
+ // UTF-16 Decoding
+ if (code <= 0xFFFF) return String.fromCharCode(code);
+ code -= 0x10000;
+ return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00);
+}
+
+/*
+ * </ Acorn Port>
+ */
+
+function readExportAs (startPos, endPos) {
+ let ch = source.charCodeAt(pos);
+ let ls = startPos, le = endPos;
+ if (ch === 97 /*a*/) {
+ pos += 2;
+ ch = commentWhitespace(true);
+ startPos = pos;
+ readToWsOrPunctuator(ch);
+ endPos = pos;
+ ch = commentWhitespace(true);
+ }
+ if (pos !== startPos)
+ addExport(startPos, endPos, ls, le);
+ return ch;
+}
+
+function readImportString (ss, ch) {
+ const startPos = pos + 1;
+ if (ch === 39/*'*/ || ch === 34/*"*/) {
+ stringLiteral(ch);
+ }
+ else {
+ syntaxError();
+ return;
+ }
+ const impt = addImport(ss, startPos, pos, -1);
+ readName(impt);
+ pos++;
+ ch = commentWhitespace(false);
+ if (ch !== 97/*a*/ || !source.startsWith('ssert', pos + 1)) {
+ pos--;
+ return;
+ }
+ const assertIndex = pos;
+
+ pos += 6;
+ ch = commentWhitespace(true);
+ if (ch !== 123/*{*/) {
+ pos = assertIndex;
+ return;
+ }
+ const assertStart = pos;
+ do {
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 39/*'*/ || ch === 34/*"*/) {
+ stringLiteral(ch);
+ pos++;
+ ch = commentWhitespace(true);
+ }
+ else {
+ ch = readToWsOrPunctuator(ch);
+ }
+ if (ch !== 58/*:*/) {
+ pos = assertIndex;
+ return;
+ }
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 39/*'*/ || ch === 34/*"*/) {
+ stringLiteral(ch);
+ }
+ else {
+ pos = assertIndex;
+ return;
+ }
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 44/*,*/) {
+ pos++;
+ ch = commentWhitespace(true);
+ if (ch === 125/*}*/)
+ break;
+ continue;
+ }
+ if (ch === 125/*}*/)
+ break;
+ pos = assertIndex;
+ return;
+ } while (true);
+ impt.a = assertStart;
+ impt.se = pos + 1;
+}
+
+function commentWhitespace (br) {
+ let ch;
+ do {
+ ch = source.charCodeAt(pos);
+ if (ch === 47/*/*/) {
+ const next_ch = source.charCodeAt(pos + 1);
+ if (next_ch === 47/*/*/)
+ lineComment();
+ else if (next_ch === 42/***/)
+ blockComment(br);
+ else
+ return ch;
+ }
+ else if (br ? !isBrOrWs(ch): !isWsNotBr(ch)) {
+ return ch;
+ }
+ } while (pos++ < end);
+ return ch;
+}
+
+function templateString () {
+ while (pos++ < end) {
+ const ch = source.charCodeAt(pos);
+ if (ch === 36/*$*/ && source.charCodeAt(pos + 1) === 123/*{*/) {
+ pos++;
+ templateStack[templateStackDepth++] = templateDepth;
+ templateDepth = ++openTokenDepth;
+ return;
+ }
+ if (ch === 96/*`*/)
+ return;
+ if (ch === 92/*\*/)
+ pos++;
+ }
+ syntaxError();
+}
+
+function blockComment (br) {
+ pos++;
+ while (pos++ < end) {
+ const ch = source.charCodeAt(pos);
+ if (!br && isBr(ch))
+ return;
+ if (ch === 42/***/ && source.charCodeAt(pos + 1) === 47/*/*/) {
+ pos++;
+ return;
+ }
+ }
+}
+
+function lineComment () {
+ while (pos++ < end) {
+ const ch = source.charCodeAt(pos);
+ if (ch === 10/*\n*/ || ch === 13/*\r*/)
+ return;
+ }
+}
+
+function stringLiteral (quote) {
+ while (pos++ < end) {
+ let ch = source.charCodeAt(pos);
+ if (ch === quote)
+ return;
+ if (ch === 92/*\*/) {
+ ch = source.charCodeAt(++pos);
+ if (ch === 13/*\r*/ && source.charCodeAt(pos + 1) === 10/*\n*/)
+ pos++;
+ }
+ else if (isBr(ch))
+ break;
+ }
+ syntaxError();
+}
+
+function regexCharacterClass () {
+ while (pos++ < end) {
+ let ch = source.charCodeAt(pos);
+ if (ch === 93/*]*/)
+ return ch;
+ if (ch === 92/*\*/)
+ pos++;
+ else if (ch === 10/*\n*/ || ch === 13/*\r*/)
+ break;
+ }
+ syntaxError();
+}
+
+function regularExpression () {
+ while (pos++ < end) {
+ let ch = source.charCodeAt(pos);
+ if (ch === 47/*/*/)
+ return;
+ if (ch === 91/*[*/)
+ ch = regexCharacterClass();
+ else if (ch === 92/*\*/)
+ pos++;
+ else if (ch === 10/*\n*/ || ch === 13/*\r*/)
+ break;
+ }
+ syntaxError();
+}
+
+function readToWsOrPunctuator (ch) {
+ do {
+ if (isBrOrWs(ch) || isPunctuator(ch))
+ return ch;
+ } while (ch = source.charCodeAt(++pos));
+ return ch;
+}
+
+// Note: non-asii BR and whitespace checks omitted for perf / footprint
+// if there is a significant user need this can be reconsidered
+function isBr (c) {
+ return c === 13/*\r*/ || c === 10/*\n*/;
+}
+
+function isWsNotBr (c) {
+ return c === 9 || c === 11 || c === 12 || c === 32 || c === 160;
+}
+
+function isBrOrWs (c) {
+ return c > 8 && c < 14 || c === 32 || c === 160;
+}
+
+function isBrOrWsOrPunctuatorNotDot (c) {
+ return c > 8 && c < 14 || c === 32 || c === 160 || isPunctuator(c) && c !== 46/*.*/;
+}
+
+function keywordStart (pos) {
+ return pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - 1));
+}
+
+function readPrecedingKeyword (pos, match) {
+ if (pos < match.length - 1)
+ return false;
+ return source.startsWith(match, pos - match.length + 1) && (pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - match.length)));
+}
+
+function readPrecedingKeyword1 (pos, ch) {
+ return source.charCodeAt(pos) === ch && (pos === 0 || isBrOrWsOrPunctuatorNotDot(source.charCodeAt(pos - 1)));
+}
+
+// Detects one of case, debugger, delete, do, else, in, instanceof, new,
+// return, throw, typeof, void, yield, await
+function isExpressionKeyword (pos) {
+ switch (source.charCodeAt(pos)) {
+ case 100/*d*/:
+ switch (source.charCodeAt(pos - 1)) {
+ case 105/*i*/:
+ // void
+ return readPrecedingKeyword(pos - 2, 'vo');
+ case 108/*l*/:
+ // yield
+ return readPrecedingKeyword(pos - 2, 'yie');
+ default:
+ return false;
+ }
+ case 101/*e*/:
+ switch (source.charCodeAt(pos - 1)) {
+ case 115/*s*/:
+ switch (source.charCodeAt(pos - 2)) {
+ case 108/*l*/:
+ // else
+ return readPrecedingKeyword1(pos - 3, 101/*e*/);
+ case 97/*a*/:
+ // case
+ return readPrecedingKeyword1(pos - 3, 99/*c*/);
+ default:
+ return false;
+ }
+ case 116/*t*/:
+ // delete
+ return readPrecedingKeyword(pos - 2, 'dele');
+ default:
+ return false;
+ }
+ case 102/*f*/:
+ if (source.charCodeAt(pos - 1) !== 111/*o*/ || source.charCodeAt(pos - 2) !== 101/*e*/)
+ return false;
+ switch (source.charCodeAt(pos - 3)) {
+ case 99/*c*/:
+ // instanceof
+ return readPrecedingKeyword(pos - 4, 'instan');
+ case 112/*p*/:
+ // typeof
+ return readPrecedingKeyword(pos - 4, 'ty');
+ default:
+ return false;
+ }
+ case 110/*n*/:
+ // in, return
+ return readPrecedingKeyword1(pos - 1, 105/*i*/) || readPrecedingKeyword(pos - 1, 'retur');
+ case 111/*o*/:
+ // do
+ return readPrecedingKeyword1(pos - 1, 100/*d*/);
+ case 114/*r*/:
+ // debugger
+ return readPrecedingKeyword(pos - 1, 'debugge');
+ case 116/*t*/:
+ // await
+ return readPrecedingKeyword(pos - 1, 'awai');
+ case 119/*w*/:
+ switch (source.charCodeAt(pos - 1)) {
+ case 101/*e*/:
+ // new
+ return readPrecedingKeyword1(pos - 2, 110/*n*/);
+ case 111/*o*/:
+ // throw
+ return readPrecedingKeyword(pos - 2, 'thr');
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+function isParenKeyword (curPos) {
+ return source.charCodeAt(curPos) === 101/*e*/ && source.startsWith('whil', curPos - 4) ||
+ source.charCodeAt(curPos) === 114/*r*/ && source.startsWith('fo', curPos - 2) ||
+ source.charCodeAt(curPos - 1) === 105/*i*/ && source.charCodeAt(curPos) === 102/*f*/;
+}
+
+function isPunctuator (ch) {
+ // 23 possible punctuator endings: !%&()*+,-./:;<=>?[]^{}|~
+ return ch === 33/*!*/ || ch === 37/*%*/ || ch === 38/*&*/ ||
+ ch > 39 && ch < 48 || ch > 57 && ch < 64 ||
+ ch === 91/*[*/ || ch === 93/*]*/ || ch === 94/*^*/ ||
+ ch > 122 && ch < 127;
+}
+
+function isExpressionPunctuator (ch) {
+ // 20 possible expression endings: !%&(*+,-.:;<=>?[^{|~
+ return ch === 33/*!*/ || ch === 37/*%*/ || ch === 38/*&*/ ||
+ ch > 39 && ch < 47 && ch !== 41 || ch > 57 && ch < 64 ||
+ ch === 91/*[*/ || ch === 94/*^*/ || ch > 122 && ch < 127 && ch !== 125/*}*/;
+}
+
+function isExpressionTerminator (curPos) {
+ // detects:
+ // => ; ) finally catch else
+ // as all of these followed by a { will indicate a statement brace
+ switch (source.charCodeAt(curPos)) {
+ case 62/*>*/:
+ return source.charCodeAt(curPos - 1) === 61/*=*/;
+ case 59/*;*/:
+ case 41/*)*/:
+ return true;
+ case 104/*h*/:
+ return source.startsWith('catc', curPos - 4);
+ case 121/*y*/:
+ return source.startsWith('finall', curPos - 6);
+ case 101/*e*/:
+ return source.startsWith('els', curPos - 3);
+ }
+ return false;
+}
+
+function syntaxError () {
+ throw Object.assign(new Error(`Parse error ${name}:${source.slice(0, pos).split('\n').length}:${pos - source.lastIndexOf('\n', pos - 1)}`), { idx: pos });
+} \ No newline at end of file