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