UNPKG

83.5 kBJavaScriptView Raw
1/***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15 Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions
19 are met:
20
21 * Redistributions of source code must retain the above
22 copyright notice, this list of conditions and the following
23 disclaimer.
24
25 * Redistributions in binary form must reproduce the above
26 copyright notice, this list of conditions and the following
27 disclaimer in the documentation and/or other materials
28 provided with the distribution.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
34 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
35 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
36 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
37 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
40 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 SUCH DAMAGE.
42
43 ***********************************************************************/
44
45"use strict";
46
47var KEYWORDS = "break case catch class const continue debugger default delete do else extends finally for function if in instanceof new return switch throw try typeof var void while with";
48var KEYWORDS_ATOM = "false null true";
49var RESERVED_WORDS = [
50 "abstract async await boolean byte char double enum export final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield",
51 KEYWORDS_ATOM,
52 KEYWORDS,
53].join(" ");
54var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
55
56KEYWORDS = makePredicate(KEYWORDS);
57RESERVED_WORDS = makePredicate(RESERVED_WORDS);
58KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
59KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
60
61var RE_BIN_NUMBER = /^0b([01]+)$/i;
62var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
63var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
64
65var OPERATORS = makePredicate([
66 "in",
67 "instanceof",
68 "typeof",
69 "new",
70 "void",
71 "delete",
72 "++",
73 "--",
74 "+",
75 "-",
76 "!",
77 "~",
78 "&",
79 "|",
80 "^",
81 "*",
82 "/",
83 "%",
84 "**",
85 ">>",
86 "<<",
87 ">>>",
88 "<",
89 ">",
90 "<=",
91 ">=",
92 "==",
93 "===",
94 "!=",
95 "!==",
96 "?",
97 "=",
98 "+=",
99 "-=",
100 "/=",
101 "*=",
102 "%=",
103 "**=",
104 ">>=",
105 "<<=",
106 ">>>=",
107 "&=",
108 "|=",
109 "^=",
110 "&&",
111 "||",
112 "??",
113 "&&=",
114 "||=",
115 "??=",
116]);
117
118var NEWLINE_CHARS = "\n\r\u2028\u2029";
119var OPERATOR_CHARS = "+-*&%=<>!?|~^";
120var PUNC_OPENERS = "[{(";
121var PUNC_SEPARATORS = ",;:";
122var PUNC_CLOSERS = ")}]";
123var PUNC_AFTER_EXPRESSION = PUNC_SEPARATORS + PUNC_CLOSERS;
124var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS;
125var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS;
126var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
127var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"#" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
128
129NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
130OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
131PUNC_AFTER_EXPRESSION = makePredicate(characters(PUNC_AFTER_EXPRESSION));
132PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
133PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
134WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
135
136/* -----[ Tokenizer ]----- */
137
138function is_surrogate_pair_head(code) {
139 return code >= 0xd800 && code <= 0xdbff;
140}
141
142function is_surrogate_pair_tail(code) {
143 return code >= 0xdc00 && code <= 0xdfff;
144}
145
146function is_digit(code) {
147 return code >= 48 && code <= 57;
148}
149
150function is_identifier_char(ch) {
151 return !NON_IDENTIFIER_CHARS[ch];
152}
153
154function is_identifier_string(str) {
155 return /^[a-z_$][a-z0-9_$]*$/i.test(str);
156}
157
158function decode_escape_sequence(seq) {
159 switch (seq[0]) {
160 case "b": return "\b";
161 case "f": return "\f";
162 case "n": return "\n";
163 case "r": return "\r";
164 case "t": return "\t";
165 case "u":
166 var code;
167 if (seq[1] == "{" && seq.slice(-1) == "}") {
168 code = seq.slice(2, -1);
169 } else if (seq.length == 5) {
170 code = seq.slice(1);
171 } else {
172 return;
173 }
174 var num = parseInt(code, 16);
175 if (num < 0 || isNaN(num)) return;
176 if (num < 0x10000) return String.fromCharCode(num);
177 if (num > 0x10ffff) return;
178 return String.fromCharCode((num >> 10) + 0xd7c0) + String.fromCharCode((num & 0x03ff) + 0xdc00);
179 case "v": return "\u000b";
180 case "x":
181 if (seq.length != 3) return;
182 var num = parseInt(seq.slice(1), 16);
183 if (num < 0 || isNaN(num)) return;
184 return String.fromCharCode(num);
185 case "\r":
186 case "\n":
187 return "";
188 default:
189 if (seq == "0") return "\0";
190 if (seq[0] >= "0" && seq[0] <= "9") return;
191 return seq;
192 }
193}
194
195function parse_js_number(num) {
196 var match;
197 if (match = RE_BIN_NUMBER.exec(num)) return parseInt(match[1], 2);
198 if (match = RE_HEX_NUMBER.exec(num)) return parseInt(match[1], 16);
199 if (match = RE_OCT_NUMBER.exec(num)) return parseInt(match[1], 8);
200 var val = parseFloat(num);
201 if (val == num) return val;
202}
203
204function JS_Parse_Error(message, filename, line, col, pos) {
205 this.message = message;
206 this.filename = filename;
207 this.line = line;
208 this.col = col;
209 this.pos = pos;
210}
211JS_Parse_Error.prototype = Object.create(Error.prototype);
212JS_Parse_Error.prototype.constructor = JS_Parse_Error;
213JS_Parse_Error.prototype.name = "SyntaxError";
214configure_error_stack(JS_Parse_Error);
215
216function js_error(message, filename, line, col, pos) {
217 throw new JS_Parse_Error(message, filename, line, col, pos);
218}
219
220function is_token(token, type, val) {
221 return token.type == type && (val == null || token.value == val);
222}
223
224var EX_EOF = {};
225
226function tokenizer($TEXT, filename, html5_comments, shebang) {
227
228 var S = {
229 text : $TEXT,
230 filename : filename,
231 pos : 0,
232 tokpos : 0,
233 line : 1,
234 tokline : 0,
235 col : 0,
236 tokcol : 0,
237 newline_before : false,
238 regex_allowed : false,
239 comments_before : [],
240 directives : {},
241 directive_stack : [],
242 read_template : with_eof_error("Unterminated template literal", function(strings) {
243 var s = "";
244 for (;;) {
245 var ch = read();
246 switch (ch) {
247 case "\\":
248 ch += read();
249 break;
250 case "`":
251 strings.push(s);
252 return;
253 case "$":
254 if (peek() == "{") {
255 next();
256 strings.push(s);
257 S.regex_allowed = true;
258 return true;
259 }
260 }
261 s += ch;
262 }
263
264 function read() {
265 var ch = next(true, true);
266 return ch == "\r" ? "\n" : ch;
267 }
268 }),
269 };
270 var prev_was_dot = false;
271
272 function peek() {
273 return S.text.charAt(S.pos);
274 }
275
276 function next(signal_eof, in_string) {
277 var ch = S.text.charAt(S.pos++);
278 if (signal_eof && !ch)
279 throw EX_EOF;
280 if (NEWLINE_CHARS[ch]) {
281 S.col = 0;
282 S.line++;
283 if (!in_string) S.newline_before = true;
284 if (ch == "\r" && peek() == "\n") {
285 // treat `\r\n` as `\n`
286 S.pos++;
287 ch = "\n";
288 }
289 } else {
290 S.col++;
291 }
292 return ch;
293 }
294
295 function forward(i) {
296 while (i-- > 0) next();
297 }
298
299 function looking_at(str) {
300 return S.text.substr(S.pos, str.length) == str;
301 }
302
303 function find_eol() {
304 var text = S.text;
305 for (var i = S.pos; i < S.text.length; ++i) {
306 if (NEWLINE_CHARS[text[i]]) return i;
307 }
308 return -1;
309 }
310
311 function find(what, signal_eof) {
312 var pos = S.text.indexOf(what, S.pos);
313 if (signal_eof && pos == -1) throw EX_EOF;
314 return pos;
315 }
316
317 function start_token() {
318 S.tokline = S.line;
319 S.tokcol = S.col;
320 S.tokpos = S.pos;
321 }
322
323 function token(type, value, is_comment) {
324 S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value]
325 || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]
326 || type == "punc" && PUNC_BEFORE_EXPRESSION[value];
327 if (type == "punc" && value == ".") prev_was_dot = true;
328 else if (!is_comment) prev_was_dot = false;
329 var ret = {
330 type : type,
331 value : value,
332 line : S.tokline,
333 col : S.tokcol,
334 pos : S.tokpos,
335 endline : S.line,
336 endcol : S.col,
337 endpos : S.pos,
338 nlb : S.newline_before,
339 file : filename
340 };
341 if (/^(?:num|string|regexp)$/i.test(type)) {
342 ret.raw = $TEXT.substring(ret.pos, ret.endpos);
343 }
344 if (!is_comment) {
345 ret.comments_before = S.comments_before;
346 ret.comments_after = S.comments_before = [];
347 }
348 S.newline_before = false;
349 return new AST_Token(ret);
350 }
351
352 function skip_whitespace() {
353 while (WHITESPACE_CHARS[peek()])
354 next();
355 }
356
357 function read_while(pred) {
358 var ret = "", ch;
359 while ((ch = peek()) && pred(ch, ret)) ret += next();
360 return ret;
361 }
362
363 function parse_error(err) {
364 js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
365 }
366
367 function is_octal(num) {
368 return /^0[0-7_]+$/.test(num);
369 }
370
371 function read_num(prefix) {
372 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
373 var num = read_while(function(ch, str) {
374 switch (ch) {
375 case "x": case "X":
376 return has_x ? false : (has_x = true);
377 case "e": case "E":
378 return has_x ? true : has_e ? false : (has_e = after_e = true);
379 case "+": case "-":
380 return after_e;
381 case (after_e = false, "."):
382 return has_dot || has_e || has_x || is_octal(str) ? false : (has_dot = true);
383 }
384 return /[_0-9a-dfo]/i.test(ch);
385 });
386 if (prefix) num = prefix + num;
387 if (is_octal(num)) {
388 if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode");
389 } else {
390 num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1");
391 }
392 var valid = parse_js_number(num);
393 if (isNaN(valid)) parse_error("Invalid syntax: " + num);
394 if (has_dot || has_e || peek() != "n") return token("num", valid);
395 return token("bigint", num.toLowerCase() + next());
396 }
397
398 function read_escaped_char(in_string) {
399 var seq = next(true, in_string);
400 if (seq >= "0" && seq <= "7") return read_octal_escape_sequence(seq);
401 if (seq == "u") {
402 var ch = next(true, in_string);
403 seq += ch;
404 if (ch != "{") {
405 seq += next(true, in_string) + next(true, in_string) + next(true, in_string);
406 } else do {
407 ch = next(true, in_string);
408 seq += ch;
409 } while (ch != "}");
410 } else if (seq == "x") {
411 seq += next(true, in_string) + next(true, in_string);
412 }
413 var str = decode_escape_sequence(seq);
414 if (typeof str != "string") parse_error("Invalid escape sequence: \\" + seq);
415 return str;
416 }
417
418 function read_octal_escape_sequence(ch) {
419 // Read
420 var p = peek();
421 if (p >= "0" && p <= "7") {
422 ch += next(true);
423 if (ch[0] <= "3" && (p = peek()) >= "0" && p <= "7")
424 ch += next(true);
425 }
426
427 // Parse
428 if (ch === "0") return "\0";
429 if (ch.length > 0 && next_token.has_directive("use strict"))
430 parse_error("Legacy octal escape sequences are not allowed in strict mode");
431 return String.fromCharCode(parseInt(ch, 8));
432 }
433
434 var read_string = with_eof_error("Unterminated string constant", function(quote_char) {
435 var quote = next(), ret = "";
436 for (;;) {
437 var ch = next(true, true);
438 if (ch == "\\") ch = read_escaped_char(true);
439 else if (NEWLINE_CHARS[ch]) parse_error("Unterminated string constant");
440 else if (ch == quote) break;
441 ret += ch;
442 }
443 var tok = token("string", ret);
444 tok.quote = quote_char;
445 return tok;
446 });
447
448 function skip_line_comment(type) {
449 var regex_allowed = S.regex_allowed;
450 var i = find_eol(), ret;
451 if (i == -1) {
452 ret = S.text.substr(S.pos);
453 S.pos = S.text.length;
454 } else {
455 ret = S.text.substring(S.pos, i);
456 S.pos = i;
457 }
458 S.col = S.tokcol + (S.pos - S.tokpos);
459 S.comments_before.push(token(type, ret, true));
460 S.regex_allowed = regex_allowed;
461 return next_token;
462 }
463
464 var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
465 var regex_allowed = S.regex_allowed;
466 var i = find("*/", true);
467 var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n");
468 // update stream position
469 forward(text.length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2);
470 S.comments_before.push(token("comment2", text, true));
471 S.regex_allowed = regex_allowed;
472 return next_token;
473 });
474
475 function read_name() {
476 var backslash = false, ch, escaped = false, name = peek() == "#" ? next() : "";
477 while (ch = peek()) {
478 if (!backslash) {
479 if (ch == "\\") escaped = backslash = true, next();
480 else if (is_identifier_char(ch)) name += next();
481 else break;
482 } else {
483 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
484 ch = read_escaped_char();
485 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
486 name += ch;
487 backslash = false;
488 }
489 }
490 if (KEYWORDS[name] && escaped) {
491 var hex = name.charCodeAt(0).toString(16).toUpperCase();
492 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
493 }
494 return name;
495 }
496
497 var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
498 var prev_backslash = false, ch, in_class = false;
499 while ((ch = next(true))) if (NEWLINE_CHARS[ch]) {
500 parse_error("Unexpected line terminator");
501 } else if (prev_backslash) {
502 source += "\\" + ch;
503 prev_backslash = false;
504 } else if (ch == "[") {
505 in_class = true;
506 source += ch;
507 } else if (ch == "]" && in_class) {
508 in_class = false;
509 source += ch;
510 } else if (ch == "/" && !in_class) {
511 break;
512 } else if (ch == "\\") {
513 prev_backslash = true;
514 } else {
515 source += ch;
516 }
517 var mods = read_name();
518 try {
519 var regexp = new RegExp(source, mods);
520 regexp.raw_source = source;
521 return token("regexp", regexp);
522 } catch (e) {
523 parse_error(e.message);
524 }
525 });
526
527 function read_operator(prefix) {
528 function grow(op) {
529 if (!peek()) return op;
530 var bigger = op + peek();
531 if (OPERATORS[bigger]) {
532 next();
533 return grow(bigger);
534 } else {
535 return op;
536 }
537 }
538 return token("operator", grow(prefix || next()));
539 }
540
541 function handle_slash() {
542 next();
543 switch (peek()) {
544 case "/":
545 next();
546 return skip_line_comment("comment1");
547 case "*":
548 next();
549 return skip_multiline_comment();
550 }
551 return S.regex_allowed ? read_regexp("") : read_operator("/");
552 }
553
554 function handle_dot() {
555 next();
556 var ch = peek();
557 if (ch == ".") {
558 var op = ".";
559 do {
560 op += ".";
561 next();
562 } while (peek() == ".");
563 return token("operator", op);
564 }
565 return is_digit(ch.charCodeAt(0)) ? read_num(".") : token("punc", ".");
566 }
567
568 function read_word() {
569 var word = read_name();
570 if (prev_was_dot) return token("name", word);
571 return KEYWORDS_ATOM[word] ? token("atom", word)
572 : !KEYWORDS[word] ? token("name", word)
573 : OPERATORS[word] ? token("operator", word)
574 : token("keyword", word);
575 }
576
577 function with_eof_error(eof_error, cont) {
578 return function(x) {
579 try {
580 return cont(x);
581 } catch (ex) {
582 if (ex === EX_EOF) parse_error(eof_error);
583 else throw ex;
584 }
585 };
586 }
587
588 function next_token(force_regexp) {
589 if (force_regexp != null)
590 return read_regexp(force_regexp);
591 if (shebang && S.pos == 0 && looking_at("#!")) {
592 start_token();
593 forward(2);
594 skip_line_comment("comment5");
595 }
596 for (;;) {
597 skip_whitespace();
598 start_token();
599 if (html5_comments) {
600 if (looking_at("<!--")) {
601 forward(4);
602 skip_line_comment("comment3");
603 continue;
604 }
605 if (looking_at("-->") && S.newline_before) {
606 forward(3);
607 skip_line_comment("comment4");
608 continue;
609 }
610 }
611 var ch = peek();
612 if (!ch) return token("eof");
613 var code = ch.charCodeAt(0);
614 switch (code) {
615 case 34: case 39: return read_string(ch);
616 case 46: return handle_dot();
617 case 47:
618 var tok = handle_slash();
619 if (tok === next_token) continue;
620 return tok;
621 }
622 if (is_digit(code)) return read_num();
623 if (PUNC_CHARS[ch]) return token("punc", next());
624 if (looking_at("=>")) return token("punc", next() + next());
625 if (OPERATOR_CHARS[ch]) return read_operator();
626 if (code == 35 || code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
627 break;
628 }
629 parse_error("Unexpected character '" + ch + "'");
630 }
631
632 next_token.context = function(nc) {
633 if (nc) S = nc;
634 return S;
635 };
636
637 next_token.add_directive = function(directive) {
638 S.directive_stack[S.directive_stack.length - 1].push(directive);
639 if (S.directives[directive]) S.directives[directive]++;
640 else S.directives[directive] = 1;
641 }
642
643 next_token.push_directives_stack = function() {
644 S.directive_stack.push([]);
645 }
646
647 next_token.pop_directives_stack = function() {
648 var directives = S.directive_stack.pop();
649 for (var i = directives.length; --i >= 0;) {
650 S.directives[directives[i]]--;
651 }
652 }
653
654 next_token.has_directive = function(directive) {
655 return S.directives[directive] > 0;
656 }
657
658 return next_token;
659}
660
661/* -----[ Parser (constants) ]----- */
662
663var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
664
665var UNARY_POSTFIX = makePredicate("-- ++");
666
667var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= &= |= ^= &&= ||= ??=");
668
669var PRECEDENCE = function(a, ret) {
670 for (var i = 0; i < a.length;) {
671 var b = a[i++];
672 for (var j = 0; j < b.length; j++) {
673 ret[b[j]] = i;
674 }
675 }
676 return ret;
677}([
678 ["??"],
679 ["||"],
680 ["&&"],
681 ["|"],
682 ["^"],
683 ["&"],
684 ["==", "===", "!=", "!=="],
685 ["<", ">", "<=", ">=", "in", "instanceof"],
686 [">>", "<<", ">>>"],
687 ["+", "-"],
688 ["*", "/", "%"],
689 ["**"],
690], {});
691
692var ATOMIC_START_TOKEN = makePredicate("atom bigint num regexp string");
693
694/* -----[ Parser ]----- */
695
696function parse($TEXT, options) {
697 options = defaults(options, {
698 bare_returns : false,
699 expression : false,
700 filename : null,
701 html5_comments : true,
702 shebang : true,
703 strict : false,
704 toplevel : null,
705 }, true);
706
707 var S = {
708 input : typeof $TEXT == "string"
709 ? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
710 : $TEXT,
711 in_async : false,
712 in_directives : true,
713 in_funarg : -1,
714 in_function : 0,
715 in_generator : false,
716 in_loop : 0,
717 labels : [],
718 peeked : null,
719 prev : null,
720 token : null,
721 };
722
723 S.token = next();
724
725 function is(type, value) {
726 return is_token(S.token, type, value);
727 }
728
729 function peek() {
730 return S.peeked || (S.peeked = S.input());
731 }
732
733 function next() {
734 S.prev = S.token;
735 if (S.peeked) {
736 S.token = S.peeked;
737 S.peeked = null;
738 } else {
739 S.token = S.input();
740 }
741 S.in_directives = S.in_directives && (
742 S.token.type == "string" || is("punc", ";")
743 );
744 return S.token;
745 }
746
747 function prev() {
748 return S.prev;
749 }
750
751 function croak(msg, line, col, pos) {
752 var ctx = S.input.context();
753 js_error(msg,
754 ctx.filename,
755 line != null ? line : ctx.tokline,
756 col != null ? col : ctx.tokcol,
757 pos != null ? pos : ctx.tokpos);
758 }
759
760 function token_error(token, msg) {
761 croak(msg, token.line, token.col);
762 }
763
764 function token_to_string(type, value) {
765 return type + (value === undefined ? "" : " «" + value + "»");
766 }
767
768 function unexpected(token) {
769 if (token == null) token = S.token;
770 token_error(token, "Unexpected token: " + token_to_string(token.type, token.value));
771 }
772
773 function expect_token(type, val) {
774 if (is(type, val)) return next();
775 token_error(S.token, "Unexpected token: " + token_to_string(S.token.type, S.token.value) + ", expected: " + token_to_string(type, val));
776 }
777
778 function expect(punc) {
779 return expect_token("punc", punc);
780 }
781
782 function has_newline_before(token) {
783 return token.nlb || !all(token.comments_before, function(comment) {
784 return !comment.nlb;
785 });
786 }
787
788 function can_insert_semicolon() {
789 return !options.strict
790 && (is("eof") || is("punc", "}") || has_newline_before(S.token));
791 }
792
793 function semicolon(optional) {
794 if (is("punc", ";")) next();
795 else if (!optional && !can_insert_semicolon()) expect(";");
796 }
797
798 function parenthesised() {
799 expect("(");
800 var exp = expression();
801 expect(")");
802 return exp;
803 }
804
805 function embed_tokens(parser) {
806 return function() {
807 var start = S.token;
808 var expr = parser.apply(null, arguments);
809 var end = prev();
810 expr.start = start;
811 expr.end = end;
812 return expr;
813 };
814 }
815
816 function handle_regexp() {
817 if (is("operator", "/") || is("operator", "/=")) {
818 S.peeked = null;
819 S.token = S.input(S.token.value.substr(1)); // force regexp
820 }
821 }
822
823 var statement = embed_tokens(function() {
824 handle_regexp();
825 switch (S.token.type) {
826 case "string":
827 var dir = S.in_directives;
828 var body = expression();
829 if (dir) {
830 if (body instanceof AST_String) {
831 var value = body.start.raw.slice(1, -1);
832 S.input.add_directive(value);
833 body.value = value;
834 } else {
835 S.in_directives = dir = false;
836 }
837 }
838 semicolon();
839 return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
840 case "num":
841 case "bigint":
842 case "regexp":
843 case "operator":
844 case "atom":
845 return simple_statement();
846
847 case "name":
848 switch (S.token.value) {
849 case "async":
850 if (is_token(peek(), "keyword", "function")) {
851 next();
852 next();
853 if (!is("operator", "*")) return function_(AST_AsyncDefun);
854 next();
855 return function_(AST_AsyncGeneratorDefun);
856 }
857 break;
858 case "await":
859 if (S.in_async) return simple_statement();
860 break;
861 case "export":
862 next();
863 return export_();
864 case "import":
865 var token = peek();
866 if (!(token.type == "punc" && /^[(.]$/.test(token.value))) {
867 next();
868 return import_();
869 }
870 break;
871 case "let":
872 if (is_vardefs()) {
873 next();
874 var node = let_();
875 semicolon();
876 return node;
877 }
878 break;
879 case "yield":
880 if (S.in_generator) return simple_statement();
881 break;
882 }
883 return is_token(peek(), "punc", ":")
884 ? labeled_statement()
885 : simple_statement();
886
887 case "punc":
888 switch (S.token.value) {
889 case "{":
890 return new AST_BlockStatement({
891 start : S.token,
892 body : block_(),
893 end : prev()
894 });
895 case "[":
896 case "(":
897 case "`":
898 return simple_statement();
899 case ";":
900 S.in_directives = false;
901 next();
902 return new AST_EmptyStatement();
903 default:
904 unexpected();
905 }
906
907 case "keyword":
908 switch (S.token.value) {
909 case "break":
910 next();
911 return break_cont(AST_Break);
912
913 case "class":
914 next();
915 return class_(AST_DefClass);
916
917 case "const":
918 next();
919 var node = const_();
920 semicolon();
921 return node;
922
923 case "continue":
924 next();
925 return break_cont(AST_Continue);
926
927 case "debugger":
928 next();
929 semicolon();
930 return new AST_Debugger();
931
932 case "do":
933 next();
934 var body = in_loop(statement);
935 expect_token("keyword", "while");
936 var condition = parenthesised();
937 semicolon(true);
938 return new AST_Do({
939 body : body,
940 condition : condition
941 });
942
943 case "while":
944 next();
945 return new AST_While({
946 condition : parenthesised(),
947 body : in_loop(statement)
948 });
949
950 case "for":
951 next();
952 return for_();
953
954 case "function":
955 next();
956 if (!is("operator", "*")) return function_(AST_Defun);
957 next();
958 return function_(AST_GeneratorDefun);
959
960 case "if":
961 next();
962 return if_();
963
964 case "return":
965 if (S.in_function == 0 && !options.bare_returns)
966 croak("'return' outside of function");
967 next();
968 var value = null;
969 if (is("punc", ";")) {
970 next();
971 } else if (!can_insert_semicolon()) {
972 value = expression();
973 semicolon();
974 }
975 return new AST_Return({
976 value: value
977 });
978
979 case "switch":
980 next();
981 return new AST_Switch({
982 expression : parenthesised(),
983 body : in_loop(switch_body_)
984 });
985
986 case "throw":
987 next();
988 if (has_newline_before(S.token))
989 croak("Illegal newline after 'throw'");
990 var value = expression();
991 semicolon();
992 return new AST_Throw({
993 value: value
994 });
995
996 case "try":
997 next();
998 return try_();
999
1000 case "var":
1001 next();
1002 var node = var_();
1003 semicolon();
1004 return node;
1005
1006 case "with":
1007 if (S.input.has_directive("use strict")) {
1008 croak("Strict mode may not include a with statement");
1009 }
1010 next();
1011 return new AST_With({
1012 expression : parenthesised(),
1013 body : statement()
1014 });
1015 }
1016 }
1017 unexpected();
1018 });
1019
1020 function labeled_statement() {
1021 var label = as_symbol(AST_Label);
1022 if (!all(S.labels, function(l) {
1023 return l.name != label.name;
1024 })) {
1025 // ECMA-262, 12.12: An ECMAScript program is considered
1026 // syntactically incorrect if it contains a
1027 // LabelledStatement that is enclosed by a
1028 // LabelledStatement with the same Identifier as label.
1029 croak("Label " + label.name + " defined twice");
1030 }
1031 expect(":");
1032 S.labels.push(label);
1033 var stat = statement();
1034 S.labels.pop();
1035 if (!(stat instanceof AST_IterationStatement)) {
1036 // check for `continue` that refers to this label.
1037 // those should be reported as syntax errors.
1038 // https://github.com/mishoo/UglifyJS/issues/287
1039 label.references.forEach(function(ref) {
1040 if (ref instanceof AST_Continue) {
1041 token_error(ref.label.start, "Continue label `" + label.name + "` must refer to IterationStatement");
1042 }
1043 });
1044 }
1045 return new AST_LabeledStatement({ body: stat, label: label });
1046 }
1047
1048 function simple_statement() {
1049 var body = expression();
1050 semicolon();
1051 return new AST_SimpleStatement({ body: body });
1052 }
1053
1054 function break_cont(type) {
1055 var label = null, ldef;
1056 if (!can_insert_semicolon()) {
1057 label = as_symbol(AST_LabelRef, true);
1058 }
1059 if (label != null) {
1060 ldef = find_if(function(l) {
1061 return l.name == label.name;
1062 }, S.labels);
1063 if (!ldef) token_error(label.start, "Undefined label " + label.name);
1064 label.thedef = ldef;
1065 } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
1066 semicolon();
1067 var stat = new type({ label: label });
1068 if (ldef) ldef.references.push(stat);
1069 return stat;
1070 }
1071
1072 function has_modifier(name) {
1073 if (!is("name", name)) return;
1074 var token = peek();
1075 if (!token) return;
1076 if (is_token(token, "operator", "=")) return;
1077 if (token.type == "punc" && /^[(;}]$/.test(token.value)) return;
1078 if (has_newline_before(token)) return;
1079 return next();
1080 }
1081
1082 function class_(ctor) {
1083 var was_async = S.in_async;
1084 var was_gen = S.in_generator;
1085 S.input.push_directives_stack();
1086 S.input.add_directive("use strict");
1087 var name;
1088 if (ctor === AST_DefClass) {
1089 name = as_symbol(AST_SymbolDefClass);
1090 } else {
1091 name = as_symbol(AST_SymbolClass, true);
1092 }
1093 var parent = null;
1094 if (is("keyword", "extends")) {
1095 next();
1096 handle_regexp();
1097 parent = expr_atom(true);
1098 }
1099 expect("{");
1100 var props = [];
1101 while (!is("punc", "}")) {
1102 if (is("punc", ";")) {
1103 next();
1104 continue;
1105 }
1106 var start = S.token;
1107 var fixed = !!has_modifier("static");
1108 var async = has_modifier("async");
1109 if (is("operator", "*")) {
1110 next();
1111 var internal = is("name") && /^#/.test(S.token.value);
1112 var key = as_property_key();
1113 var gen_start = S.token;
1114 var gen = function_(async ? AST_AsyncGeneratorFunction : AST_GeneratorFunction);
1115 gen.start = gen_start;
1116 gen.end = prev();
1117 props.push(new AST_ClassMethod({
1118 start: start,
1119 static: fixed,
1120 private: internal,
1121 key: key,
1122 value: gen,
1123 end: prev(),
1124 }));
1125 continue;
1126 }
1127 var internal = is("name") && /^#/.test(S.token.value);
1128 var key = as_property_key();
1129 if (is("punc", "(")) {
1130 var func_start = S.token;
1131 var func = function_(async ? AST_AsyncFunction : AST_Function);
1132 func.start = func_start;
1133 func.end = prev();
1134 props.push(new AST_ClassMethod({
1135 start: start,
1136 static: fixed,
1137 private: internal,
1138 key: key,
1139 value: func,
1140 end: prev(),
1141 }));
1142 continue;
1143 }
1144 if (async) unexpected(async);
1145 var value = null;
1146 if (is("operator", "=")) {
1147 next();
1148 S.in_async = false;
1149 S.in_generator = false;
1150 value = maybe_assign();
1151 S.in_generator = was_gen;
1152 S.in_async = was_async;
1153 } else if (!(is("punc", ";") || is("punc", "}"))) {
1154 var type = null;
1155 switch (key) {
1156 case "get":
1157 type = AST_ClassGetter;
1158 break;
1159 case "set":
1160 type = AST_ClassSetter;
1161 break;
1162 }
1163 if (type) {
1164 props.push(new type({
1165 start: start,
1166 static: fixed,
1167 private: is("name") && /^#/.test(S.token.value),
1168 key: as_property_key(),
1169 value: create_accessor(),
1170 end: prev(),
1171 }));
1172 continue;
1173 }
1174 }
1175 semicolon();
1176 props.push(new AST_ClassField({
1177 start: start,
1178 static: fixed,
1179 private: internal,
1180 key: key,
1181 value: value,
1182 end: prev(),
1183 }));
1184 }
1185 next();
1186 S.input.pop_directives_stack();
1187 S.in_generator = was_gen;
1188 S.in_async = was_async;
1189 return new ctor({
1190 extends: parent,
1191 name: name,
1192 properties: props,
1193 });
1194 }
1195
1196 function for_() {
1197 var await = is("name", "await") && next();
1198 expect("(");
1199 var init = null;
1200 if (await || !is("punc", ";")) {
1201 init = is("keyword", "const")
1202 ? (next(), const_(true))
1203 : is("name", "let") && is_vardefs()
1204 ? (next(), let_(true))
1205 : is("keyword", "var")
1206 ? (next(), var_(true))
1207 : expression(true);
1208 var ctor;
1209 if (await) {
1210 expect_token("name", "of");
1211 ctor = AST_ForAwaitOf;
1212 } else if (is("operator", "in")) {
1213 next();
1214 ctor = AST_ForIn;
1215 } else if (is("name", "of")) {
1216 next();
1217 ctor = AST_ForOf;
1218 }
1219 if (ctor) {
1220 if (init instanceof AST_Definitions) {
1221 if (init.definitions.length > 1) {
1222 token_error(init.start, "Only one variable declaration allowed in for..in/of loop");
1223 }
1224 if (ctor !== AST_ForIn && init.definitions[0].value) {
1225 token_error(init.definitions[0].value.start, "No initializers allowed in for..of loop");
1226 }
1227 } else if (!(is_assignable(init) || (init = to_destructured(init)) instanceof AST_Destructured)) {
1228 token_error(init.start, "Invalid left-hand side in for..in/of loop");
1229 }
1230 return for_enum(ctor, init);
1231 }
1232 }
1233 return regular_for(init);
1234 }
1235
1236 function regular_for(init) {
1237 expect(";");
1238 var test = is("punc", ";") ? null : expression();
1239 expect(";");
1240 var step = is("punc", ")") ? null : expression();
1241 expect(")");
1242 return new AST_For({
1243 init : init,
1244 condition : test,
1245 step : step,
1246 body : in_loop(statement)
1247 });
1248 }
1249
1250 function for_enum(ctor, init) {
1251 handle_regexp();
1252 var obj = expression();
1253 expect(")");
1254 return new ctor({
1255 init : init,
1256 object : obj,
1257 body : in_loop(statement)
1258 });
1259 }
1260
1261 function to_funarg(node) {
1262 if (node instanceof AST_Array) {
1263 var rest = null;
1264 if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
1265 rest = to_funarg(node.elements.pop().expression);
1266 }
1267 return new AST_DestructuredArray({
1268 start: node.start,
1269 elements: node.elements.map(to_funarg),
1270 rest: rest,
1271 end: node.end,
1272 });
1273 }
1274 if (node instanceof AST_Assign) return new AST_DefaultValue({
1275 start: node.start,
1276 name: to_funarg(node.left),
1277 value: node.right,
1278 end: node.end,
1279 });
1280 if (node instanceof AST_DefaultValue) {
1281 node.name = to_funarg(node.name);
1282 return node;
1283 }
1284 if (node instanceof AST_DestructuredArray) {
1285 node.elements = node.elements.map(to_funarg);
1286 if (node.rest) node.rest = to_funarg(node.rest);
1287 return node;
1288 }
1289 if (node instanceof AST_DestructuredObject) {
1290 node.properties.forEach(function(prop) {
1291 prop.value = to_funarg(prop.value);
1292 });
1293 if (node.rest) node.rest = to_funarg(node.rest);
1294 return node;
1295 }
1296 if (node instanceof AST_Hole) return node;
1297 if (node instanceof AST_Object) {
1298 var rest = null;
1299 if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
1300 rest = to_funarg(node.properties.pop().expression);
1301 }
1302 return new AST_DestructuredObject({
1303 start: node.start,
1304 properties: node.properties.map(function(prop) {
1305 if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
1306 return new AST_DestructuredKeyVal({
1307 start: prop.start,
1308 key: prop.key,
1309 value: to_funarg(prop.value),
1310 end: prop.end,
1311 });
1312 }),
1313 rest: rest,
1314 end: node.end,
1315 });
1316 }
1317 if (node instanceof AST_SymbolFunarg) return node;
1318 if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
1319 if (node instanceof AST_Yield) return new AST_SymbolFunarg({
1320 start: node.start,
1321 name: "yield",
1322 end: node.end,
1323 });
1324 token_error(node.start, "Invalid arrow parameter");
1325 }
1326
1327 function arrow(exprs, start, async) {
1328 var was_async = S.in_async;
1329 var was_gen = S.in_generator;
1330 S.in_async = async;
1331 S.in_generator = false;
1332 var was_funarg = S.in_funarg;
1333 S.in_funarg = S.in_function;
1334 var argnames = exprs.map(to_funarg);
1335 var rest = exprs.rest || null;
1336 if (rest) rest = to_funarg(rest);
1337 S.in_funarg = was_funarg;
1338 expect("=>");
1339 var body, value;
1340 var loop = S.in_loop;
1341 var labels = S.labels;
1342 ++S.in_function;
1343 S.in_directives = true;
1344 S.input.push_directives_stack();
1345 S.in_loop = 0;
1346 S.labels = [];
1347 if (is("punc", "{")) {
1348 body = block_();
1349 value = null;
1350 } else {
1351 body = [];
1352 handle_regexp();
1353 value = maybe_assign();
1354 }
1355 var is_strict = S.input.has_directive("use strict");
1356 S.input.pop_directives_stack();
1357 --S.in_function;
1358 S.in_loop = loop;
1359 S.labels = labels;
1360 S.in_generator = was_gen;
1361 S.in_async = was_async;
1362 var node = new (async ? AST_AsyncArrow : AST_Arrow)({
1363 start: start,
1364 argnames: argnames,
1365 rest: rest,
1366 body: body,
1367 value: value,
1368 end: prev(),
1369 });
1370 if (is_strict) node.each_argname(strict_verify_symbol);
1371 return node;
1372 }
1373
1374 var function_ = function(ctor) {
1375 var was_async = S.in_async;
1376 var was_gen = S.in_generator;
1377 var name;
1378 if (/Defun$/.test(ctor.TYPE)) {
1379 name = as_symbol(AST_SymbolDefun);
1380 S.in_async = /^Async/.test(ctor.TYPE);
1381 S.in_generator = /Generator/.test(ctor.TYPE);
1382 } else {
1383 S.in_async = /^Async/.test(ctor.TYPE);
1384 S.in_generator = /Generator/.test(ctor.TYPE);
1385 name = as_symbol(AST_SymbolLambda, true);
1386 }
1387 if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
1388 unexpected(prev());
1389 expect("(");
1390 var was_funarg = S.in_funarg;
1391 S.in_funarg = S.in_function;
1392 var argnames = expr_list(")", !options.strict, false, function() {
1393 return maybe_default(AST_SymbolFunarg);
1394 });
1395 S.in_funarg = was_funarg;
1396 var loop = S.in_loop;
1397 var labels = S.labels;
1398 ++S.in_function;
1399 S.in_directives = true;
1400 S.input.push_directives_stack();
1401 S.in_loop = 0;
1402 S.labels = [];
1403 var body = block_();
1404 var is_strict = S.input.has_directive("use strict");
1405 S.input.pop_directives_stack();
1406 --S.in_function;
1407 S.in_loop = loop;
1408 S.labels = labels;
1409 S.in_generator = was_gen;
1410 S.in_async = was_async;
1411 var node = new ctor({
1412 name: name,
1413 argnames: argnames,
1414 rest: argnames.rest || null,
1415 body: body
1416 });
1417 if (is_strict) {
1418 if (name) strict_verify_symbol(name);
1419 node.each_argname(strict_verify_symbol);
1420 }
1421 return node;
1422 };
1423
1424 function if_() {
1425 var cond = parenthesised(), body = statement(), belse = null;
1426 if (is("keyword", "else")) {
1427 next();
1428 belse = statement();
1429 }
1430 return new AST_If({
1431 condition : cond,
1432 body : body,
1433 alternative : belse
1434 });
1435 }
1436
1437 function is_alias() {
1438 return is("name") || is_identifier_string(S.token.value);
1439 }
1440
1441 function export_() {
1442 if (is("operator", "*")) {
1443 next();
1444 var alias = "*";
1445 if (is("name", "as")) {
1446 next();
1447 if (!is_alias()) expect_token("name");
1448 alias = S.token.value;
1449 next();
1450 }
1451 expect_token("name", "from");
1452 var path = S.token;
1453 expect_token("string");
1454 semicolon();
1455 return new AST_ExportForeign({
1456 aliases: [ alias ],
1457 keys: [ "*" ],
1458 path: path.value,
1459 quote: path.quote,
1460 });
1461 }
1462 if (is("punc", "{")) {
1463 next();
1464 var aliases = [];
1465 var keys = [];
1466 while (is_alias()) {
1467 var key = S.token;
1468 next();
1469 keys.push(key);
1470 if (is("name", "as")) {
1471 next();
1472 if (!is_alias()) expect_token("name");
1473 aliases.push(S.token.value);
1474 next();
1475 } else {
1476 aliases.push(key.value);
1477 }
1478 if (!is("punc", "}")) expect(",");
1479 }
1480 expect("}");
1481 if (is("name", "from")) {
1482 next();
1483 var path = S.token;
1484 expect_token("string");
1485 semicolon();
1486 return new AST_ExportForeign({
1487 aliases: aliases,
1488 keys: keys.map(function(token) {
1489 return token.value;
1490 }),
1491 path: path.value,
1492 quote: path.quote,
1493 });
1494 }
1495 semicolon();
1496 return new AST_ExportReferences({
1497 properties: keys.map(function(token, index) {
1498 if (!is_token(token, "name")) token_error(token, "Name expected");
1499 var sym = _make_symbol(AST_SymbolExport, token);
1500 sym.alias = aliases[index];
1501 return sym;
1502 }),
1503 });
1504 }
1505 if (is("keyword", "default")) {
1506 next();
1507 var start = S.token;
1508 var body = export_default_decl();
1509 if (body) {
1510 body.start = start;
1511 body.end = prev();
1512 } else {
1513 handle_regexp();
1514 body = expression();
1515 semicolon();
1516 }
1517 return new AST_ExportDefault({ body: body });
1518 }
1519 return new AST_ExportDeclaration({ body: export_decl() });
1520 }
1521
1522 function maybe_named(def, expr) {
1523 if (expr.name) {
1524 expr = new def(expr);
1525 expr.name = new (def === AST_DefClass ? AST_SymbolDefClass : AST_SymbolDefun)(expr.name);
1526 }
1527 return expr;
1528 }
1529
1530 function export_default_decl() {
1531 if (is("name", "async")) {
1532 if (!is_token(peek(), "keyword", "function")) return;
1533 next();
1534 next();
1535 if (!is("operator", "*")) return maybe_named(AST_AsyncDefun, function_(AST_AsyncFunction));
1536 next();
1537 return maybe_named(AST_AsyncGeneratorDefun, function_(AST_AsyncGeneratorFunction));
1538 } else if (is("keyword")) switch (S.token.value) {
1539 case "class":
1540 next();
1541 return maybe_named(AST_DefClass, class_(AST_ClassExpression));
1542 case "function":
1543 next();
1544 if (!is("operator", "*")) return maybe_named(AST_Defun, function_(AST_Function));
1545 next();
1546 return maybe_named(AST_GeneratorDefun, function_(AST_GeneratorFunction));
1547 }
1548 }
1549
1550 var export_decl = embed_tokens(function() {
1551 if (is("name")) switch (S.token.value) {
1552 case "async":
1553 next();
1554 expect_token("keyword", "function");
1555 if (!is("operator", "*")) return function_(AST_AsyncDefun);
1556 next();
1557 return function_(AST_AsyncGeneratorDefun);
1558 case "let":
1559 next();
1560 var node = let_();
1561 semicolon();
1562 return node;
1563 } else if (is("keyword")) switch (S.token.value) {
1564 case "class":
1565 next();
1566 return class_(AST_DefClass);
1567 case "const":
1568 next();
1569 var node = const_();
1570 semicolon();
1571 return node;
1572 case "function":
1573 next();
1574 if (!is("operator", "*")) return function_(AST_Defun);
1575 next();
1576 return function_(AST_GeneratorDefun);
1577 case "var":
1578 next();
1579 var node = var_();
1580 semicolon();
1581 return node;
1582 }
1583 unexpected();
1584 });
1585
1586 function import_() {
1587 var all = null;
1588 var def = as_symbol(AST_SymbolImport, true);
1589 var props = null;
1590 if (def ? (def.key = "", is("punc", ",") && next()) : !is("string")) {
1591 if (is("operator", "*")) {
1592 next();
1593 expect_token("name", "as");
1594 all = as_symbol(AST_SymbolImport);
1595 all.key = "*";
1596 } else {
1597 expect("{");
1598 props = [];
1599 while (is_alias()) {
1600 var alias;
1601 if (is_token(peek(), "name", "as")) {
1602 var key = S.token.value;
1603 next();
1604 next();
1605 alias = as_symbol(AST_SymbolImport);
1606 alias.key = key;
1607 } else {
1608 alias = as_symbol(AST_SymbolImport);
1609 alias.key = alias.name;
1610 }
1611 props.push(alias);
1612 if (!is("punc", "}")) expect(",");
1613 }
1614 expect("}");
1615 }
1616 }
1617 if (all || def || props) expect_token("name", "from");
1618 var path = S.token;
1619 expect_token("string");
1620 semicolon();
1621 return new AST_Import({
1622 all: all,
1623 default: def,
1624 path: path.value,
1625 properties: props,
1626 quote: path.quote,
1627 });
1628 }
1629
1630 function block_() {
1631 expect("{");
1632 var a = [];
1633 while (!is("punc", "}")) {
1634 if (is("eof")) expect("}");
1635 a.push(statement());
1636 }
1637 next();
1638 return a;
1639 }
1640
1641 function switch_body_() {
1642 expect("{");
1643 var a = [], branch, cur, default_branch, tmp;
1644 while (!is("punc", "}")) {
1645 if (is("eof")) expect("}");
1646 if (is("keyword", "case")) {
1647 if (branch) branch.end = prev();
1648 cur = [];
1649 branch = new AST_Case({
1650 start : (tmp = S.token, next(), tmp),
1651 expression : expression(),
1652 body : cur
1653 });
1654 a.push(branch);
1655 expect(":");
1656 } else if (is("keyword", "default")) {
1657 if (branch) branch.end = prev();
1658 if (default_branch) croak("More than one default clause in switch statement");
1659 cur = [];
1660 branch = new AST_Default({
1661 start : (tmp = S.token, next(), expect(":"), tmp),
1662 body : cur
1663 });
1664 a.push(branch);
1665 default_branch = branch;
1666 } else {
1667 if (!cur) unexpected();
1668 cur.push(statement());
1669 }
1670 }
1671 if (branch) branch.end = prev();
1672 next();
1673 return a;
1674 }
1675
1676 function try_() {
1677 var body = block_(), bcatch = null, bfinally = null;
1678 if (is("keyword", "catch")) {
1679 var start = S.token;
1680 next();
1681 var name = null;
1682 if (is("punc", "(")) {
1683 next();
1684 name = maybe_destructured(AST_SymbolCatch);
1685 expect(")");
1686 }
1687 bcatch = new AST_Catch({
1688 start : start,
1689 argname : name,
1690 body : block_(),
1691 end : prev()
1692 });
1693 }
1694 if (is("keyword", "finally")) {
1695 var start = S.token;
1696 next();
1697 bfinally = new AST_Finally({
1698 start : start,
1699 body : block_(),
1700 end : prev()
1701 });
1702 }
1703 if (!bcatch && !bfinally)
1704 croak("Missing catch/finally blocks");
1705 return new AST_Try({
1706 body : body,
1707 bcatch : bcatch,
1708 bfinally : bfinally
1709 });
1710 }
1711
1712 function vardefs(type, no_in) {
1713 var a = [];
1714 for (;;) {
1715 var start = S.token;
1716 var name = maybe_destructured(type);
1717 var value = null;
1718 if (is("operator", "=")) {
1719 next();
1720 value = maybe_assign(no_in);
1721 } else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
1722 croak("Missing initializer in declaration");
1723 }
1724 a.push(new AST_VarDef({
1725 start : start,
1726 name : name,
1727 value : value,
1728 end : prev()
1729 }));
1730 if (!is("punc", ","))
1731 break;
1732 next();
1733 }
1734 return a;
1735 }
1736
1737 function is_vardefs() {
1738 var token = peek();
1739 return is_token(token, "name") || is_token(token, "punc", "[") || is_token(token, "punc", "{");
1740 }
1741
1742 var const_ = function(no_in) {
1743 return new AST_Const({
1744 start : prev(),
1745 definitions : vardefs(AST_SymbolConst, no_in),
1746 end : prev()
1747 });
1748 };
1749
1750 var let_ = function(no_in) {
1751 return new AST_Let({
1752 start : prev(),
1753 definitions : vardefs(AST_SymbolLet, no_in),
1754 end : prev()
1755 });
1756 };
1757
1758 var var_ = function(no_in) {
1759 return new AST_Var({
1760 start : prev(),
1761 definitions : vardefs(AST_SymbolVar, no_in),
1762 end : prev()
1763 });
1764 };
1765
1766 var new_ = function(allow_calls) {
1767 var start = S.token;
1768 expect_token("operator", "new");
1769 var call;
1770 if (is("punc", ".") && is_token(peek(), "name", "target")) {
1771 next();
1772 next();
1773 call = new AST_NewTarget();
1774 } else {
1775 var exp = expr_atom(false), args;
1776 if (is("punc", "(")) {
1777 next();
1778 args = expr_list(")", !options.strict);
1779 } else {
1780 args = [];
1781 }
1782 call = new AST_New({ expression: exp, args: args });
1783 }
1784 call.start = start;
1785 call.end = prev();
1786 return subscripts(call, allow_calls);
1787 };
1788
1789 function as_atom_node() {
1790 var ret, tok = S.token, value = tok.value;
1791 switch (tok.type) {
1792 case "num":
1793 if (isFinite(value)) {
1794 ret = new AST_Number({ value: value });
1795 } else {
1796 ret = new AST_Infinity();
1797 if (value < 0) ret = new AST_UnaryPrefix({ operator: "-", expression: ret });
1798 }
1799 break;
1800 case "bigint":
1801 ret = new AST_BigInt({ value: value });
1802 break;
1803 case "string":
1804 ret = new AST_String({ value : value, quote : tok.quote });
1805 break;
1806 case "regexp":
1807 ret = new AST_RegExp({ value: value });
1808 break;
1809 case "atom":
1810 switch (value) {
1811 case "false":
1812 ret = new AST_False();
1813 break;
1814 case "true":
1815 ret = new AST_True();
1816 break;
1817 case "null":
1818 ret = new AST_Null();
1819 break;
1820 default:
1821 unexpected();
1822 }
1823 break;
1824 default:
1825 unexpected();
1826 }
1827 next();
1828 ret.start = ret.end = tok;
1829 return ret;
1830 }
1831
1832 var expr_atom = function(allow_calls) {
1833 if (is("operator", "new")) {
1834 return new_(allow_calls);
1835 }
1836 var start = S.token;
1837 if (is("punc")) {
1838 switch (start.value) {
1839 case "`":
1840 return subscripts(template(null), allow_calls);
1841 case "(":
1842 next();
1843 if (is("punc", ")")) {
1844 next();
1845 return arrow([], start);
1846 }
1847 var ex = expression(false, true);
1848 var len = start.comments_before.length;
1849 [].unshift.apply(ex.start.comments_before, start.comments_before);
1850 start.comments_before.length = 0;
1851 start.comments_before = ex.start.comments_before;
1852 start.comments_before_length = len;
1853 if (len == 0 && start.comments_before.length > 0) {
1854 var comment = start.comments_before[0];
1855 if (!comment.nlb) {
1856 comment.nlb = start.nlb;
1857 start.nlb = false;
1858 }
1859 }
1860 start.comments_after = ex.start.comments_after;
1861 ex.start = start;
1862 expect(")");
1863 var end = prev();
1864 end.comments_before = ex.end.comments_before;
1865 end.comments_after.forEach(function(comment) {
1866 ex.end.comments_after.push(comment);
1867 if (comment.nlb) S.token.nlb = true;
1868 });
1869 end.comments_after.length = 0;
1870 end.comments_after = ex.end.comments_after;
1871 ex.end = end;
1872 if (is("punc", "=>")) return arrow(ex instanceof AST_Sequence ? ex.expressions : [ ex ], start);
1873 return subscripts(ex, allow_calls);
1874 case "[":
1875 return subscripts(array_(), allow_calls);
1876 case "{":
1877 return subscripts(object_(), allow_calls);
1878 }
1879 unexpected();
1880 }
1881 if (is("keyword")) switch (start.value) {
1882 case "class":
1883 next();
1884 var clazz = class_(AST_ClassExpression);
1885 clazz.start = start;
1886 clazz.end = prev();
1887 return subscripts(clazz, allow_calls);
1888 case "function":
1889 next();
1890 var func;
1891 if (is("operator", "*")) {
1892 next();
1893 func = function_(AST_GeneratorFunction);
1894 } else {
1895 func = function_(AST_Function);
1896 }
1897 func.start = start;
1898 func.end = prev();
1899 return subscripts(func, allow_calls);
1900 }
1901 if (is("name")) {
1902 var sym = _make_symbol(AST_SymbolRef, start);
1903 next();
1904 if (sym.name == "async") {
1905 if (is("keyword", "function")) {
1906 next();
1907 var func;
1908 if (is("operator", "*")) {
1909 next();
1910 func = function_(AST_AsyncGeneratorFunction);
1911 } else {
1912 func = function_(AST_AsyncFunction);
1913 }
1914 func.start = start;
1915 func.end = prev();
1916 return subscripts(func, allow_calls);
1917 }
1918 if (is("name") && is_token(peek(), "punc", "=>")) {
1919 start = S.token;
1920 sym = _make_symbol(AST_SymbolRef, start);
1921 next();
1922 return arrow([ sym ], start, true);
1923 }
1924 if (is("punc", "(")) {
1925 var call = subscripts(sym, allow_calls);
1926 if (!is("punc", "=>")) return call;
1927 var args = call.args;
1928 if (args[args.length - 1] instanceof AST_Spread) {
1929 args.rest = args.pop().expression;
1930 }
1931 return arrow(args, start, true);
1932 }
1933 }
1934 return is("punc", "=>") ? arrow([ sym ], start) : subscripts(sym, allow_calls);
1935 }
1936 if (ATOMIC_START_TOKEN[S.token.type]) {
1937 return subscripts(as_atom_node(), allow_calls);
1938 }
1939 unexpected();
1940 };
1941
1942 function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
1943 if (!parser) parser = maybe_assign;
1944 var first = true, a = [];
1945 while (!is("punc", closing)) {
1946 if (first) first = false; else expect(",");
1947 if (allow_trailing_comma && is("punc", closing)) break;
1948 if (allow_empty && is("punc", ",")) {
1949 a.push(new AST_Hole({ start: S.token, end: S.token }));
1950 } else if (!is("operator", "...")) {
1951 a.push(parser());
1952 } else if (parser === maybe_assign) {
1953 a.push(new AST_Spread({
1954 start: S.token,
1955 expression: (next(), parser()),
1956 end: prev(),
1957 }));
1958 } else {
1959 next();
1960 a.rest = parser();
1961 if (a.rest instanceof AST_DefaultValue) token_error(a.rest.start, "Invalid rest parameter");
1962 break;
1963 }
1964 }
1965 expect(closing);
1966 return a;
1967 }
1968
1969 var array_ = embed_tokens(function() {
1970 expect("[");
1971 return new AST_Array({
1972 elements: expr_list("]", !options.strict, true)
1973 });
1974 });
1975
1976 var create_accessor = embed_tokens(function() {
1977 return function_(AST_Accessor);
1978 });
1979
1980 var object_ = embed_tokens(function() {
1981 expect("{");
1982 var first = true, a = [];
1983 while (!is("punc", "}")) {
1984 if (first) first = false; else expect(",");
1985 // allow trailing comma
1986 if (!options.strict && is("punc", "}")) break;
1987 var start = S.token;
1988 if (is("operator", "*")) {
1989 next();
1990 var key = as_property_key();
1991 var gen_start = S.token;
1992 var gen = function_(AST_GeneratorFunction);
1993 gen.start = gen_start;
1994 gen.end = prev();
1995 a.push(new AST_ObjectMethod({
1996 start: start,
1997 key: key,
1998 value: gen,
1999 end: prev(),
2000 }));
2001 continue;
2002 }
2003 if (is("operator", "...")) {
2004 next();
2005 a.push(new AST_Spread({
2006 start: start,
2007 expression: maybe_assign(),
2008 end: prev(),
2009 }));
2010 continue;
2011 }
2012 if (is_token(peek(), "operator", "=")) {
2013 var name = as_symbol(AST_SymbolRef);
2014 next();
2015 a.push(new AST_ObjectKeyVal({
2016 start: start,
2017 key: start.value,
2018 value: new AST_Assign({
2019 start: start,
2020 left: name,
2021 operator: "=",
2022 right: maybe_assign(),
2023 end: prev(),
2024 }),
2025 end: prev(),
2026 }));
2027 continue;
2028 }
2029 if (is_token(peek(), "punc", ",") || is_token(peek(), "punc", "}")) {
2030 a.push(new AST_ObjectKeyVal({
2031 start: start,
2032 key: start.value,
2033 value: as_symbol(AST_SymbolRef),
2034 end: prev(),
2035 }));
2036 continue;
2037 }
2038 var key = as_property_key();
2039 if (is("punc", "(")) {
2040 var func_start = S.token;
2041 var func = function_(AST_Function);
2042 func.start = func_start;
2043 func.end = prev();
2044 a.push(new AST_ObjectMethod({
2045 start: start,
2046 key: key,
2047 value: func,
2048 end: prev(),
2049 }));
2050 continue;
2051 }
2052 if (is("punc", ":")) {
2053 next();
2054 a.push(new AST_ObjectKeyVal({
2055 start: start,
2056 key: key,
2057 value: maybe_assign(),
2058 end: prev(),
2059 }));
2060 continue;
2061 }
2062 if (start.type == "name") switch (key) {
2063 case "async":
2064 var is_gen = is("operator", "*") && next();
2065 key = as_property_key();
2066 var func_start = S.token;
2067 var func = function_(is_gen ? AST_AsyncGeneratorFunction : AST_AsyncFunction);
2068 func.start = func_start;
2069 func.end = prev();
2070 a.push(new AST_ObjectMethod({
2071 start: start,
2072 key: key,
2073 value: func,
2074 end: prev(),
2075 }));
2076 continue;
2077 case "get":
2078 a.push(new AST_ObjectGetter({
2079 start: start,
2080 key: as_property_key(),
2081 value: create_accessor(),
2082 end: prev(),
2083 }));
2084 continue;
2085 case "set":
2086 a.push(new AST_ObjectSetter({
2087 start: start,
2088 key: as_property_key(),
2089 value: create_accessor(),
2090 end: prev(),
2091 }));
2092 continue;
2093 }
2094 unexpected();
2095 }
2096 next();
2097 return new AST_Object({ properties: a });
2098 });
2099
2100 function as_property_key() {
2101 var tmp = S.token;
2102 switch (tmp.type) {
2103 case "operator":
2104 if (!KEYWORDS[tmp.value]) unexpected();
2105 case "num":
2106 case "string":
2107 case "name":
2108 case "keyword":
2109 case "atom":
2110 next();
2111 return "" + tmp.value;
2112 case "punc":
2113 expect("[");
2114 var key = maybe_assign();
2115 expect("]");
2116 return key;
2117 default:
2118 unexpected();
2119 }
2120 }
2121
2122 function as_name() {
2123 var name = S.token.value;
2124 expect_token("name");
2125 return name;
2126 }
2127
2128 function _make_symbol(type, token) {
2129 var name = token.value;
2130 switch (name) {
2131 case "await":
2132 if (S.in_async) unexpected(token);
2133 break;
2134 case "super":
2135 type = AST_Super;
2136 break;
2137 case "this":
2138 type = AST_This;
2139 break;
2140 case "yield":
2141 if (S.in_generator) unexpected(token);
2142 break;
2143 }
2144 return new type({
2145 name: "" + name,
2146 start: token,
2147 end: token,
2148 });
2149 }
2150
2151 function strict_verify_symbol(sym) {
2152 if (sym.name == "arguments" || sym.name == "eval" || sym.name == "let")
2153 token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
2154 }
2155
2156 function as_symbol(type, noerror) {
2157 if (!is("name")) {
2158 if (!noerror) croak("Name expected");
2159 return null;
2160 }
2161 var sym = _make_symbol(type, S.token);
2162 if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
2163 strict_verify_symbol(sym);
2164 }
2165 next();
2166 return sym;
2167 }
2168
2169 function maybe_destructured(type) {
2170 var start = S.token;
2171 if (is("punc", "[")) {
2172 next();
2173 var elements = expr_list("]", !options.strict, true, function() {
2174 return maybe_default(type);
2175 });
2176 return new AST_DestructuredArray({
2177 start: start,
2178 elements: elements,
2179 rest: elements.rest || null,
2180 end: prev(),
2181 });
2182 }
2183 if (is("punc", "{")) {
2184 next();
2185 var first = true, a = [], rest = null;
2186 while (!is("punc", "}")) {
2187 if (first) first = false; else expect(",");
2188 // allow trailing comma
2189 if (!options.strict && is("punc", "}")) break;
2190 var key_start = S.token;
2191 if (is("punc", "[") || is_token(peek(), "punc", ":")) {
2192 var key = as_property_key();
2193 expect(":");
2194 a.push(new AST_DestructuredKeyVal({
2195 start: key_start,
2196 key: key,
2197 value: maybe_default(type),
2198 end: prev(),
2199 }));
2200 continue;
2201 }
2202 if (is("operator", "...")) {
2203 next();
2204 rest = maybe_destructured(type);
2205 break;
2206 }
2207 var name = as_symbol(type);
2208 if (is("operator", "=")) {
2209 next();
2210 name = new AST_DefaultValue({
2211 start: name.start,
2212 name: name,
2213 value: maybe_assign(),
2214 end: prev(),
2215 });
2216 }
2217 a.push(new AST_DestructuredKeyVal({
2218 start: key_start,
2219 key: key_start.value,
2220 value: name,
2221 end: prev(),
2222 }));
2223 }
2224 expect("}");
2225 return new AST_DestructuredObject({
2226 start: start,
2227 properties: a,
2228 rest: rest,
2229 end: prev(),
2230 });
2231 }
2232 return as_symbol(type);
2233 }
2234
2235 function maybe_default(type) {
2236 var start = S.token;
2237 var name = maybe_destructured(type);
2238 if (!is("operator", "=")) return name;
2239 next();
2240 return new AST_DefaultValue({
2241 start: start,
2242 name: name,
2243 value: maybe_assign(),
2244 end: prev(),
2245 });
2246 }
2247
2248 function template(tag) {
2249 var start = tag ? tag.start : S.token;
2250 var read = S.input.context().read_template;
2251 var strings = [];
2252 var expressions = [];
2253 while (read(strings)) {
2254 next();
2255 expressions.push(expression());
2256 if (!is("punc", "}")) unexpected();
2257 }
2258 next();
2259 return new AST_Template({
2260 start: start,
2261 expressions: expressions,
2262 strings: strings,
2263 tag: tag,
2264 end: prev(),
2265 });
2266 }
2267
2268 function subscripts(expr, allow_calls) {
2269 var start = expr.start;
2270 var optional = null;
2271 while (true) {
2272 if (is("operator", "?") && is_token(peek(), "punc", ".")) {
2273 next();
2274 next();
2275 optional = expr;
2276 }
2277 if (is("punc", "[")) {
2278 next();
2279 var prop = expression();
2280 expect("]");
2281 expr = new AST_Sub({
2282 start: start,
2283 optional: optional === expr,
2284 expression: expr,
2285 property: prop,
2286 end: prev(),
2287 });
2288 } else if (allow_calls && is("punc", "(")) {
2289 next();
2290 expr = new AST_Call({
2291 start: start,
2292 optional: optional === expr,
2293 expression: expr,
2294 args: expr_list(")", !options.strict),
2295 end: prev(),
2296 });
2297 } else if (optional === expr || is("punc", ".")) {
2298 if (optional !== expr) next();
2299 expr = new AST_Dot({
2300 start: start,
2301 optional: optional === expr,
2302 expression: expr,
2303 property: as_name(),
2304 end: prev(),
2305 });
2306 } else if (is("punc", "`")) {
2307 if (optional) croak("Invalid template on optional chain");
2308 expr = template(expr);
2309 } else {
2310 break;
2311 }
2312 }
2313 if (optional) expr.terminal = true;
2314 if (expr instanceof AST_Call && !expr.pure) {
2315 var start = expr.start;
2316 var comments = start.comments_before;
2317 var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
2318 while (--i >= 0) {
2319 if (/[@#]__PURE__/.test(comments[i].value)) {
2320 expr.pure = true;
2321 break;
2322 }
2323 }
2324 }
2325 return expr;
2326 }
2327
2328 function maybe_unary(no_in) {
2329 var start = S.token;
2330 if (S.in_async && is("name", "await")) {
2331 if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
2332 S.input.context().regex_allowed = true;
2333 next();
2334 return new AST_Await({
2335 start: start,
2336 expression: maybe_unary(no_in),
2337 end: prev(),
2338 });
2339 }
2340 if (S.in_generator && is("name", "yield")) {
2341 if (S.in_funarg === S.in_function) croak("Invalid use of yield in function argument");
2342 S.input.context().regex_allowed = true;
2343 next();
2344 var exp = null;
2345 var nested = false;
2346 if (is("operator", "*")) {
2347 next();
2348 exp = maybe_assign(no_in);
2349 nested = true;
2350 } else if (is("punc") ? !PUNC_AFTER_EXPRESSION[S.token.value] : !can_insert_semicolon()) {
2351 exp = maybe_assign(no_in);
2352 }
2353 return new AST_Yield({
2354 start: start,
2355 expression: exp,
2356 nested: nested,
2357 end: prev(),
2358 });
2359 }
2360 if (is("operator") && UNARY_PREFIX[start.value]) {
2361 next();
2362 handle_regexp();
2363 var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(no_in));
2364 ex.start = start;
2365 ex.end = prev();
2366 return ex;
2367 }
2368 var val = expr_atom(true);
2369 while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
2370 val = make_unary(AST_UnaryPostfix, S.token, val);
2371 val.start = start;
2372 val.end = S.token;
2373 next();
2374 }
2375 return val;
2376 }
2377
2378 function make_unary(ctor, token, expr) {
2379 var op = token.value;
2380 switch (op) {
2381 case "++":
2382 case "--":
2383 if (!is_assignable(expr))
2384 token_error(token, "Invalid use of " + op + " operator");
2385 break;
2386 case "delete":
2387 if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
2388 token_error(expr.start, "Calling delete on expression not allowed in strict mode");
2389 break;
2390 }
2391 return new ctor({ operator: op, expression: expr });
2392 }
2393
2394 var expr_op = function(left, min_prec, no_in) {
2395 var op = is("operator") ? S.token.value : null;
2396 if (op == "in" && no_in) op = null;
2397 var prec = op != null ? PRECEDENCE[op] : null;
2398 if (prec != null && prec > min_prec) {
2399 next();
2400 var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in);
2401 return expr_op(new AST_Binary({
2402 start : left.start,
2403 left : left,
2404 operator : op,
2405 right : right,
2406 end : right.end
2407 }), min_prec, no_in);
2408 }
2409 return left;
2410 };
2411
2412 function expr_ops(no_in) {
2413 return expr_op(maybe_unary(no_in), 0, no_in);
2414 }
2415
2416 var maybe_conditional = function(no_in) {
2417 var start = S.token;
2418 var expr = expr_ops(no_in);
2419 if (is("operator", "?")) {
2420 next();
2421 var yes = maybe_assign();
2422 expect(":");
2423 return new AST_Conditional({
2424 start : start,
2425 condition : expr,
2426 consequent : yes,
2427 alternative : maybe_assign(no_in),
2428 end : prev()
2429 });
2430 }
2431 return expr;
2432 };
2433
2434 function is_assignable(expr) {
2435 return expr instanceof AST_PropAccess && !expr.optional || expr instanceof AST_SymbolRef;
2436 }
2437
2438 function to_destructured(node) {
2439 if (node instanceof AST_Array) {
2440 var rest = null;
2441 if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
2442 rest = to_destructured(node.elements.pop().expression);
2443 if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
2444 }
2445 var elements = node.elements.map(to_destructured);
2446 return all(elements, function(node) {
2447 return node instanceof AST_DefaultValue
2448 || node instanceof AST_Destructured
2449 || node instanceof AST_Hole
2450 || is_assignable(node);
2451 }) ? new AST_DestructuredArray({
2452 start: node.start,
2453 elements: elements,
2454 rest: rest,
2455 end: node.end,
2456 }) : node;
2457 }
2458 if (node instanceof AST_Assign) {
2459 var name = to_destructured(node.left);
2460 return name instanceof AST_Destructured || is_assignable(name) ? new AST_DefaultValue({
2461 start: node.start,
2462 name: name,
2463 value: node.right,
2464 end: node.end,
2465 }) : node;
2466 }
2467 if (!(node instanceof AST_Object)) return node;
2468 var rest = null;
2469 if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
2470 rest = to_destructured(node.properties.pop().expression);
2471 if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
2472 }
2473 var props = [];
2474 for (var i = 0; i < node.properties.length; i++) {
2475 var prop = node.properties[i];
2476 if (!(prop instanceof AST_ObjectKeyVal)) return node;
2477 var value = to_destructured(prop.value);
2478 if (!(value instanceof AST_DefaultValue || value instanceof AST_Destructured || is_assignable(value))) {
2479 return node;
2480 }
2481 props.push(new AST_DestructuredKeyVal({
2482 start: prop.start,
2483 key: prop.key,
2484 value: value,
2485 end: prop.end,
2486 }));
2487 }
2488 return new AST_DestructuredObject({
2489 start: node.start,
2490 properties: props,
2491 rest: rest,
2492 end: node.end,
2493 });
2494 }
2495
2496 function maybe_assign(no_in) {
2497 var start = S.token;
2498 var left = maybe_conditional(no_in), val = S.token.value;
2499 if (is("operator") && ASSIGNMENT[val]) {
2500 if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
2501 next();
2502 return new AST_Assign({
2503 start : start,
2504 left : left,
2505 operator : val,
2506 right : maybe_assign(no_in),
2507 end : prev()
2508 });
2509 }
2510 croak("Invalid assignment");
2511 }
2512 return left;
2513 }
2514
2515 function expression(no_in, maybe_arrow) {
2516 var start = S.token;
2517 var exprs = [];
2518 while (true) {
2519 if (maybe_arrow && is("operator", "...")) {
2520 next();
2521 exprs.rest = maybe_destructured(AST_SymbolFunarg);
2522 break;
2523 }
2524 exprs.push(maybe_assign(no_in));
2525 if (!is("punc", ",")) break;
2526 next();
2527 if (maybe_arrow && is("punc", ")") && is_token(peek(), "punc", "=>")) break;
2528 }
2529 return exprs.length == 1 && !exprs.rest ? exprs[0] : new AST_Sequence({
2530 start: start,
2531 expressions: exprs,
2532 end: prev(),
2533 });
2534 }
2535
2536 function in_loop(cont) {
2537 ++S.in_loop;
2538 var ret = cont();
2539 --S.in_loop;
2540 return ret;
2541 }
2542
2543 if (options.expression) {
2544 handle_regexp();
2545 var exp = expression();
2546 expect_token("eof");
2547 return exp;
2548 }
2549
2550 return function() {
2551 var start = S.token;
2552 var body = [];
2553 S.input.push_directives_stack();
2554 while (!is("eof"))
2555 body.push(statement());
2556 S.input.pop_directives_stack();
2557 var end = prev() || start;
2558 var toplevel = options.toplevel;
2559 if (toplevel) {
2560 toplevel.body = toplevel.body.concat(body);
2561 toplevel.end = end;
2562 } else {
2563 toplevel = new AST_Toplevel({ start: start, body: body, end: end });
2564 }
2565 return toplevel;
2566 }();
2567}