UNPKG

83.4 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 token_error(node.start, "Invalid arrow parameter");
1320 }
1321
1322 function arrow(exprs, start, async) {
1323 var was_async = S.in_async;
1324 var was_gen = S.in_generator;
1325 S.in_async = async;
1326 S.in_generator = false;
1327 var was_funarg = S.in_funarg;
1328 S.in_funarg = S.in_function;
1329 var argnames = exprs.map(to_funarg);
1330 var rest = exprs.rest || null;
1331 if (rest) rest = to_funarg(rest);
1332 S.in_funarg = was_funarg;
1333 expect("=>");
1334 var body, value;
1335 var loop = S.in_loop;
1336 var labels = S.labels;
1337 ++S.in_function;
1338 S.in_directives = true;
1339 S.input.push_directives_stack();
1340 S.in_loop = 0;
1341 S.labels = [];
1342 if (is("punc", "{")) {
1343 body = block_();
1344 value = null;
1345 } else {
1346 body = [];
1347 handle_regexp();
1348 value = maybe_assign();
1349 }
1350 var is_strict = S.input.has_directive("use strict");
1351 S.input.pop_directives_stack();
1352 --S.in_function;
1353 S.in_loop = loop;
1354 S.labels = labels;
1355 S.in_generator = was_gen;
1356 S.in_async = was_async;
1357 var node = new (async ? AST_AsyncArrow : AST_Arrow)({
1358 start: start,
1359 argnames: argnames,
1360 rest: rest,
1361 body: body,
1362 value: value,
1363 end: prev(),
1364 });
1365 if (is_strict) node.each_argname(strict_verify_symbol);
1366 return node;
1367 }
1368
1369 var function_ = function(ctor) {
1370 var was_async = S.in_async;
1371 var was_gen = S.in_generator;
1372 var name;
1373 if (/Defun$/.test(ctor.TYPE)) {
1374 name = as_symbol(AST_SymbolDefun);
1375 S.in_async = /^Async/.test(ctor.TYPE);
1376 S.in_generator = /Generator/.test(ctor.TYPE);
1377 } else {
1378 S.in_async = /^Async/.test(ctor.TYPE);
1379 S.in_generator = /Generator/.test(ctor.TYPE);
1380 name = as_symbol(AST_SymbolLambda, true);
1381 }
1382 if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
1383 unexpected(prev());
1384 expect("(");
1385 var was_funarg = S.in_funarg;
1386 S.in_funarg = S.in_function;
1387 var argnames = expr_list(")", !options.strict, false, function() {
1388 return maybe_default(AST_SymbolFunarg);
1389 });
1390 S.in_funarg = was_funarg;
1391 var loop = S.in_loop;
1392 var labels = S.labels;
1393 ++S.in_function;
1394 S.in_directives = true;
1395 S.input.push_directives_stack();
1396 S.in_loop = 0;
1397 S.labels = [];
1398 var body = block_();
1399 var is_strict = S.input.has_directive("use strict");
1400 S.input.pop_directives_stack();
1401 --S.in_function;
1402 S.in_loop = loop;
1403 S.labels = labels;
1404 S.in_generator = was_gen;
1405 S.in_async = was_async;
1406 var node = new ctor({
1407 name: name,
1408 argnames: argnames,
1409 rest: argnames.rest || null,
1410 body: body
1411 });
1412 if (is_strict) {
1413 if (name) strict_verify_symbol(name);
1414 node.each_argname(strict_verify_symbol);
1415 }
1416 return node;
1417 };
1418
1419 function if_() {
1420 var cond = parenthesised(), body = statement(), belse = null;
1421 if (is("keyword", "else")) {
1422 next();
1423 belse = statement();
1424 }
1425 return new AST_If({
1426 condition : cond,
1427 body : body,
1428 alternative : belse
1429 });
1430 }
1431
1432 function is_alias() {
1433 return is("name") || is_identifier_string(S.token.value);
1434 }
1435
1436 function export_() {
1437 if (is("operator", "*")) {
1438 next();
1439 var alias = "*";
1440 if (is("name", "as")) {
1441 next();
1442 if (!is_alias()) expect_token("name");
1443 alias = S.token.value;
1444 next();
1445 }
1446 expect_token("name", "from");
1447 var path = S.token;
1448 expect_token("string");
1449 semicolon();
1450 return new AST_ExportForeign({
1451 aliases: [ alias ],
1452 keys: [ "*" ],
1453 path: path.value,
1454 quote: path.quote,
1455 });
1456 }
1457 if (is("punc", "{")) {
1458 next();
1459 var aliases = [];
1460 var keys = [];
1461 while (is_alias()) {
1462 var key = S.token;
1463 next();
1464 keys.push(key);
1465 if (is("name", "as")) {
1466 next();
1467 if (!is_alias()) expect_token("name");
1468 aliases.push(S.token.value);
1469 next();
1470 } else {
1471 aliases.push(key.value);
1472 }
1473 if (!is("punc", "}")) expect(",");
1474 }
1475 expect("}");
1476 if (is("name", "from")) {
1477 next();
1478 var path = S.token;
1479 expect_token("string");
1480 semicolon();
1481 return new AST_ExportForeign({
1482 aliases: aliases,
1483 keys: keys.map(function(token) {
1484 return token.value;
1485 }),
1486 path: path.value,
1487 quote: path.quote,
1488 });
1489 }
1490 semicolon();
1491 return new AST_ExportReferences({
1492 properties: keys.map(function(token, index) {
1493 if (!is_token(token, "name")) token_error(token, "Name expected");
1494 var sym = _make_symbol(AST_SymbolExport, token);
1495 sym.alias = aliases[index];
1496 return sym;
1497 }),
1498 });
1499 }
1500 if (is("keyword", "default")) {
1501 next();
1502 var start = S.token;
1503 var body = export_default_decl();
1504 if (body) {
1505 body.start = start;
1506 body.end = prev();
1507 } else {
1508 handle_regexp();
1509 body = expression();
1510 semicolon();
1511 }
1512 return new AST_ExportDefault({ body: body });
1513 }
1514 return new AST_ExportDeclaration({ body: export_decl() });
1515 }
1516
1517 function maybe_named(def, expr) {
1518 if (expr.name) {
1519 expr = new def(expr);
1520 expr.name = new (def === AST_DefClass ? AST_SymbolDefClass : AST_SymbolDefun)(expr.name);
1521 }
1522 return expr;
1523 }
1524
1525 function export_default_decl() {
1526 if (is("name", "async")) {
1527 if (!is_token(peek(), "keyword", "function")) return;
1528 next();
1529 next();
1530 if (!is("operator", "*")) return maybe_named(AST_AsyncDefun, function_(AST_AsyncFunction));
1531 next();
1532 return maybe_named(AST_AsyncGeneratorDefun, function_(AST_AsyncGeneratorFunction));
1533 } else if (is("keyword")) switch (S.token.value) {
1534 case "class":
1535 next();
1536 return maybe_named(AST_DefClass, class_(AST_ClassExpression));
1537 case "function":
1538 next();
1539 if (!is("operator", "*")) return maybe_named(AST_Defun, function_(AST_Function));
1540 next();
1541 return maybe_named(AST_GeneratorDefun, function_(AST_GeneratorFunction));
1542 }
1543 }
1544
1545 var export_decl = embed_tokens(function() {
1546 if (is("name")) switch (S.token.value) {
1547 case "async":
1548 next();
1549 expect_token("keyword", "function");
1550 if (!is("operator", "*")) return function_(AST_AsyncDefun);
1551 next();
1552 return function_(AST_AsyncGeneratorDefun);
1553 case "let":
1554 next();
1555 var node = let_();
1556 semicolon();
1557 return node;
1558 } else if (is("keyword")) switch (S.token.value) {
1559 case "class":
1560 next();
1561 return class_(AST_DefClass);
1562 case "const":
1563 next();
1564 var node = const_();
1565 semicolon();
1566 return node;
1567 case "function":
1568 next();
1569 if (!is("operator", "*")) return function_(AST_Defun);
1570 next();
1571 return function_(AST_GeneratorDefun);
1572 case "var":
1573 next();
1574 var node = var_();
1575 semicolon();
1576 return node;
1577 }
1578 unexpected();
1579 });
1580
1581 function import_() {
1582 var all = null;
1583 var def = as_symbol(AST_SymbolImport, true);
1584 var props = null;
1585 if (def ? (def.key = "", is("punc", ",") && next()) : !is("string")) {
1586 if (is("operator", "*")) {
1587 next();
1588 expect_token("name", "as");
1589 all = as_symbol(AST_SymbolImport);
1590 all.key = "*";
1591 } else {
1592 expect("{");
1593 props = [];
1594 while (is_alias()) {
1595 var alias;
1596 if (is_token(peek(), "name", "as")) {
1597 var key = S.token.value;
1598 next();
1599 next();
1600 alias = as_symbol(AST_SymbolImport);
1601 alias.key = key;
1602 } else {
1603 alias = as_symbol(AST_SymbolImport);
1604 alias.key = alias.name;
1605 }
1606 props.push(alias);
1607 if (!is("punc", "}")) expect(",");
1608 }
1609 expect("}");
1610 }
1611 }
1612 if (all || def || props) expect_token("name", "from");
1613 var path = S.token;
1614 expect_token("string");
1615 semicolon();
1616 return new AST_Import({
1617 all: all,
1618 default: def,
1619 path: path.value,
1620 properties: props,
1621 quote: path.quote,
1622 });
1623 }
1624
1625 function block_() {
1626 expect("{");
1627 var a = [];
1628 while (!is("punc", "}")) {
1629 if (is("eof")) expect("}");
1630 a.push(statement());
1631 }
1632 next();
1633 return a;
1634 }
1635
1636 function switch_body_() {
1637 expect("{");
1638 var a = [], branch, cur, default_branch, tmp;
1639 while (!is("punc", "}")) {
1640 if (is("eof")) expect("}");
1641 if (is("keyword", "case")) {
1642 if (branch) branch.end = prev();
1643 cur = [];
1644 branch = new AST_Case({
1645 start : (tmp = S.token, next(), tmp),
1646 expression : expression(),
1647 body : cur
1648 });
1649 a.push(branch);
1650 expect(":");
1651 } else if (is("keyword", "default")) {
1652 if (branch) branch.end = prev();
1653 if (default_branch) croak("More than one default clause in switch statement");
1654 cur = [];
1655 branch = new AST_Default({
1656 start : (tmp = S.token, next(), expect(":"), tmp),
1657 body : cur
1658 });
1659 a.push(branch);
1660 default_branch = branch;
1661 } else {
1662 if (!cur) unexpected();
1663 cur.push(statement());
1664 }
1665 }
1666 if (branch) branch.end = prev();
1667 next();
1668 return a;
1669 }
1670
1671 function try_() {
1672 var body = block_(), bcatch = null, bfinally = null;
1673 if (is("keyword", "catch")) {
1674 var start = S.token;
1675 next();
1676 var name = null;
1677 if (is("punc", "(")) {
1678 next();
1679 name = maybe_destructured(AST_SymbolCatch);
1680 expect(")");
1681 }
1682 bcatch = new AST_Catch({
1683 start : start,
1684 argname : name,
1685 body : block_(),
1686 end : prev()
1687 });
1688 }
1689 if (is("keyword", "finally")) {
1690 var start = S.token;
1691 next();
1692 bfinally = new AST_Finally({
1693 start : start,
1694 body : block_(),
1695 end : prev()
1696 });
1697 }
1698 if (!bcatch && !bfinally)
1699 croak("Missing catch/finally blocks");
1700 return new AST_Try({
1701 body : body,
1702 bcatch : bcatch,
1703 bfinally : bfinally
1704 });
1705 }
1706
1707 function vardefs(type, no_in) {
1708 var a = [];
1709 for (;;) {
1710 var start = S.token;
1711 var name = maybe_destructured(type);
1712 var value = null;
1713 if (is("operator", "=")) {
1714 next();
1715 value = maybe_assign(no_in);
1716 } else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
1717 croak("Missing initializer in declaration");
1718 }
1719 a.push(new AST_VarDef({
1720 start : start,
1721 name : name,
1722 value : value,
1723 end : prev()
1724 }));
1725 if (!is("punc", ","))
1726 break;
1727 next();
1728 }
1729 return a;
1730 }
1731
1732 function is_vardefs() {
1733 var token = peek();
1734 return is_token(token, "name") || is_token(token, "punc", "[") || is_token(token, "punc", "{");
1735 }
1736
1737 var const_ = function(no_in) {
1738 return new AST_Const({
1739 start : prev(),
1740 definitions : vardefs(AST_SymbolConst, no_in),
1741 end : prev()
1742 });
1743 };
1744
1745 var let_ = function(no_in) {
1746 return new AST_Let({
1747 start : prev(),
1748 definitions : vardefs(AST_SymbolLet, no_in),
1749 end : prev()
1750 });
1751 };
1752
1753 var var_ = function(no_in) {
1754 return new AST_Var({
1755 start : prev(),
1756 definitions : vardefs(AST_SymbolVar, no_in),
1757 end : prev()
1758 });
1759 };
1760
1761 var new_ = function(allow_calls) {
1762 var start = S.token;
1763 expect_token("operator", "new");
1764 var call;
1765 if (is("punc", ".") && is_token(peek(), "name", "target")) {
1766 next();
1767 next();
1768 call = new AST_NewTarget();
1769 } else {
1770 var exp = expr_atom(false), args;
1771 if (is("punc", "(")) {
1772 next();
1773 args = expr_list(")", !options.strict);
1774 } else {
1775 args = [];
1776 }
1777 call = new AST_New({ expression: exp, args: args });
1778 }
1779 call.start = start;
1780 call.end = prev();
1781 return subscripts(call, allow_calls);
1782 };
1783
1784 function as_atom_node() {
1785 var ret, tok = S.token, value = tok.value;
1786 switch (tok.type) {
1787 case "num":
1788 if (isFinite(value)) {
1789 ret = new AST_Number({ value: value });
1790 } else {
1791 ret = new AST_Infinity();
1792 if (value < 0) ret = new AST_UnaryPrefix({ operator: "-", expression: ret });
1793 }
1794 break;
1795 case "bigint":
1796 ret = new AST_BigInt({ value: value });
1797 break;
1798 case "string":
1799 ret = new AST_String({ value : value, quote : tok.quote });
1800 break;
1801 case "regexp":
1802 ret = new AST_RegExp({ value: value });
1803 break;
1804 case "atom":
1805 switch (value) {
1806 case "false":
1807 ret = new AST_False();
1808 break;
1809 case "true":
1810 ret = new AST_True();
1811 break;
1812 case "null":
1813 ret = new AST_Null();
1814 break;
1815 default:
1816 unexpected();
1817 }
1818 break;
1819 default:
1820 unexpected();
1821 }
1822 next();
1823 ret.start = ret.end = tok;
1824 return ret;
1825 }
1826
1827 var expr_atom = function(allow_calls) {
1828 if (is("operator", "new")) {
1829 return new_(allow_calls);
1830 }
1831 var start = S.token;
1832 if (is("punc")) {
1833 switch (start.value) {
1834 case "`":
1835 return subscripts(template(null), allow_calls);
1836 case "(":
1837 next();
1838 if (is("punc", ")")) {
1839 next();
1840 return arrow([], start);
1841 }
1842 var ex = expression(false, true);
1843 var len = start.comments_before.length;
1844 [].unshift.apply(ex.start.comments_before, start.comments_before);
1845 start.comments_before.length = 0;
1846 start.comments_before = ex.start.comments_before;
1847 start.comments_before_length = len;
1848 if (len == 0 && start.comments_before.length > 0) {
1849 var comment = start.comments_before[0];
1850 if (!comment.nlb) {
1851 comment.nlb = start.nlb;
1852 start.nlb = false;
1853 }
1854 }
1855 start.comments_after = ex.start.comments_after;
1856 ex.start = start;
1857 expect(")");
1858 var end = prev();
1859 end.comments_before = ex.end.comments_before;
1860 end.comments_after.forEach(function(comment) {
1861 ex.end.comments_after.push(comment);
1862 if (comment.nlb) S.token.nlb = true;
1863 });
1864 end.comments_after.length = 0;
1865 end.comments_after = ex.end.comments_after;
1866 ex.end = end;
1867 if (is("punc", "=>")) return arrow(ex instanceof AST_Sequence ? ex.expressions : [ ex ], start);
1868 return subscripts(ex, allow_calls);
1869 case "[":
1870 return subscripts(array_(), allow_calls);
1871 case "{":
1872 return subscripts(object_(), allow_calls);
1873 }
1874 unexpected();
1875 }
1876 if (is("keyword")) switch (start.value) {
1877 case "class":
1878 next();
1879 var clazz = class_(AST_ClassExpression);
1880 clazz.start = start;
1881 clazz.end = prev();
1882 return subscripts(clazz, allow_calls);
1883 case "function":
1884 next();
1885 var func;
1886 if (is("operator", "*")) {
1887 next();
1888 func = function_(AST_GeneratorFunction);
1889 } else {
1890 func = function_(AST_Function);
1891 }
1892 func.start = start;
1893 func.end = prev();
1894 return subscripts(func, allow_calls);
1895 }
1896 if (is("name")) {
1897 var sym = _make_symbol(AST_SymbolRef, start);
1898 next();
1899 if (sym.name == "async") {
1900 if (is("keyword", "function")) {
1901 next();
1902 var func;
1903 if (is("operator", "*")) {
1904 next();
1905 func = function_(AST_AsyncGeneratorFunction);
1906 } else {
1907 func = function_(AST_AsyncFunction);
1908 }
1909 func.start = start;
1910 func.end = prev();
1911 return subscripts(func, allow_calls);
1912 }
1913 if (is("name") && is_token(peek(), "punc", "=>")) {
1914 start = S.token;
1915 sym = _make_symbol(AST_SymbolRef, start);
1916 next();
1917 return arrow([ sym ], start, true);
1918 }
1919 if (is("punc", "(")) {
1920 var call = subscripts(sym, allow_calls);
1921 if (!is("punc", "=>")) return call;
1922 var args = call.args;
1923 if (args[args.length - 1] instanceof AST_Spread) {
1924 args.rest = args.pop().expression;
1925 }
1926 return arrow(args, start, true);
1927 }
1928 }
1929 return is("punc", "=>") ? arrow([ sym ], start) : subscripts(sym, allow_calls);
1930 }
1931 if (ATOMIC_START_TOKEN[S.token.type]) {
1932 return subscripts(as_atom_node(), allow_calls);
1933 }
1934 unexpected();
1935 };
1936
1937 function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
1938 if (!parser) parser = maybe_assign;
1939 var first = true, a = [];
1940 while (!is("punc", closing)) {
1941 if (first) first = false; else expect(",");
1942 if (allow_trailing_comma && is("punc", closing)) break;
1943 if (allow_empty && is("punc", ",")) {
1944 a.push(new AST_Hole({ start: S.token, end: S.token }));
1945 } else if (!is("operator", "...")) {
1946 a.push(parser());
1947 } else if (parser === maybe_assign) {
1948 a.push(new AST_Spread({
1949 start: S.token,
1950 expression: (next(), parser()),
1951 end: prev(),
1952 }));
1953 } else {
1954 next();
1955 a.rest = parser();
1956 if (a.rest instanceof AST_DefaultValue) token_error(a.rest.start, "Invalid rest parameter");
1957 break;
1958 }
1959 }
1960 expect(closing);
1961 return a;
1962 }
1963
1964 var array_ = embed_tokens(function() {
1965 expect("[");
1966 return new AST_Array({
1967 elements: expr_list("]", !options.strict, true)
1968 });
1969 });
1970
1971 var create_accessor = embed_tokens(function() {
1972 return function_(AST_Accessor);
1973 });
1974
1975 var object_ = embed_tokens(function() {
1976 expect("{");
1977 var first = true, a = [];
1978 while (!is("punc", "}")) {
1979 if (first) first = false; else expect(",");
1980 // allow trailing comma
1981 if (!options.strict && is("punc", "}")) break;
1982 var start = S.token;
1983 if (is("operator", "*")) {
1984 next();
1985 var key = as_property_key();
1986 var gen_start = S.token;
1987 var gen = function_(AST_GeneratorFunction);
1988 gen.start = gen_start;
1989 gen.end = prev();
1990 a.push(new AST_ObjectMethod({
1991 start: start,
1992 key: key,
1993 value: gen,
1994 end: prev(),
1995 }));
1996 continue;
1997 }
1998 if (is("operator", "...")) {
1999 next();
2000 a.push(new AST_Spread({
2001 start: start,
2002 expression: maybe_assign(),
2003 end: prev(),
2004 }));
2005 continue;
2006 }
2007 if (is_token(peek(), "operator", "=")) {
2008 var name = as_symbol(AST_SymbolRef);
2009 next();
2010 a.push(new AST_ObjectKeyVal({
2011 start: start,
2012 key: start.value,
2013 value: new AST_Assign({
2014 start: start,
2015 left: name,
2016 operator: "=",
2017 right: maybe_assign(),
2018 end: prev(),
2019 }),
2020 end: prev(),
2021 }));
2022 continue;
2023 }
2024 if (is_token(peek(), "punc", ",") || is_token(peek(), "punc", "}")) {
2025 a.push(new AST_ObjectKeyVal({
2026 start: start,
2027 key: start.value,
2028 value: as_symbol(AST_SymbolRef),
2029 end: prev(),
2030 }));
2031 continue;
2032 }
2033 var key = as_property_key();
2034 if (is("punc", "(")) {
2035 var func_start = S.token;
2036 var func = function_(AST_Function);
2037 func.start = func_start;
2038 func.end = prev();
2039 a.push(new AST_ObjectMethod({
2040 start: start,
2041 key: key,
2042 value: func,
2043 end: prev(),
2044 }));
2045 continue;
2046 }
2047 if (is("punc", ":")) {
2048 next();
2049 a.push(new AST_ObjectKeyVal({
2050 start: start,
2051 key: key,
2052 value: maybe_assign(),
2053 end: prev(),
2054 }));
2055 continue;
2056 }
2057 if (start.type == "name") switch (key) {
2058 case "async":
2059 var is_gen = is("operator", "*") && next();
2060 key = as_property_key();
2061 var func_start = S.token;
2062 var func = function_(is_gen ? AST_AsyncGeneratorFunction : AST_AsyncFunction);
2063 func.start = func_start;
2064 func.end = prev();
2065 a.push(new AST_ObjectMethod({
2066 start: start,
2067 key: key,
2068 value: func,
2069 end: prev(),
2070 }));
2071 continue;
2072 case "get":
2073 a.push(new AST_ObjectGetter({
2074 start: start,
2075 key: as_property_key(),
2076 value: create_accessor(),
2077 end: prev(),
2078 }));
2079 continue;
2080 case "set":
2081 a.push(new AST_ObjectSetter({
2082 start: start,
2083 key: as_property_key(),
2084 value: create_accessor(),
2085 end: prev(),
2086 }));
2087 continue;
2088 }
2089 unexpected();
2090 }
2091 next();
2092 return new AST_Object({ properties: a });
2093 });
2094
2095 function as_property_key() {
2096 var tmp = S.token;
2097 switch (tmp.type) {
2098 case "operator":
2099 if (!KEYWORDS[tmp.value]) unexpected();
2100 case "num":
2101 case "string":
2102 case "name":
2103 case "keyword":
2104 case "atom":
2105 next();
2106 return "" + tmp.value;
2107 case "punc":
2108 expect("[");
2109 var key = maybe_assign();
2110 expect("]");
2111 return key;
2112 default:
2113 unexpected();
2114 }
2115 }
2116
2117 function as_name() {
2118 var name = S.token.value;
2119 expect_token("name");
2120 return name;
2121 }
2122
2123 function _make_symbol(type, token) {
2124 var name = token.value;
2125 switch (name) {
2126 case "await":
2127 if (S.in_async) unexpected(token);
2128 break;
2129 case "super":
2130 type = AST_Super;
2131 break;
2132 case "this":
2133 type = AST_This;
2134 break;
2135 case "yield":
2136 if (S.in_generator) unexpected(token);
2137 break;
2138 }
2139 return new type({
2140 name: "" + name,
2141 start: token,
2142 end: token,
2143 });
2144 }
2145
2146 function strict_verify_symbol(sym) {
2147 if (sym.name == "arguments" || sym.name == "eval" || sym.name == "let")
2148 token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
2149 }
2150
2151 function as_symbol(type, noerror) {
2152 if (!is("name")) {
2153 if (!noerror) croak("Name expected");
2154 return null;
2155 }
2156 var sym = _make_symbol(type, S.token);
2157 if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
2158 strict_verify_symbol(sym);
2159 }
2160 next();
2161 return sym;
2162 }
2163
2164 function maybe_destructured(type) {
2165 var start = S.token;
2166 if (is("punc", "[")) {
2167 next();
2168 var elements = expr_list("]", !options.strict, true, function() {
2169 return maybe_default(type);
2170 });
2171 return new AST_DestructuredArray({
2172 start: start,
2173 elements: elements,
2174 rest: elements.rest || null,
2175 end: prev(),
2176 });
2177 }
2178 if (is("punc", "{")) {
2179 next();
2180 var first = true, a = [], rest = null;
2181 while (!is("punc", "}")) {
2182 if (first) first = false; else expect(",");
2183 // allow trailing comma
2184 if (!options.strict && is("punc", "}")) break;
2185 var key_start = S.token;
2186 if (is("punc", "[") || is_token(peek(), "punc", ":")) {
2187 var key = as_property_key();
2188 expect(":");
2189 a.push(new AST_DestructuredKeyVal({
2190 start: key_start,
2191 key: key,
2192 value: maybe_default(type),
2193 end: prev(),
2194 }));
2195 continue;
2196 }
2197 if (is("operator", "...")) {
2198 next();
2199 rest = maybe_destructured(type);
2200 break;
2201 }
2202 var name = as_symbol(type);
2203 if (is("operator", "=")) {
2204 next();
2205 name = new AST_DefaultValue({
2206 start: name.start,
2207 name: name,
2208 value: maybe_assign(),
2209 end: prev(),
2210 });
2211 }
2212 a.push(new AST_DestructuredKeyVal({
2213 start: key_start,
2214 key: key_start.value,
2215 value: name,
2216 end: prev(),
2217 }));
2218 }
2219 expect("}");
2220 return new AST_DestructuredObject({
2221 start: start,
2222 properties: a,
2223 rest: rest,
2224 end: prev(),
2225 });
2226 }
2227 return as_symbol(type);
2228 }
2229
2230 function maybe_default(type) {
2231 var start = S.token;
2232 var name = maybe_destructured(type);
2233 if (!is("operator", "=")) return name;
2234 next();
2235 return new AST_DefaultValue({
2236 start: start,
2237 name: name,
2238 value: maybe_assign(),
2239 end: prev(),
2240 });
2241 }
2242
2243 function template(tag) {
2244 var start = tag ? tag.start : S.token;
2245 var read = S.input.context().read_template;
2246 var strings = [];
2247 var expressions = [];
2248 while (read(strings)) {
2249 next();
2250 expressions.push(expression());
2251 if (!is("punc", "}")) unexpected();
2252 }
2253 next();
2254 return new AST_Template({
2255 start: start,
2256 expressions: expressions,
2257 strings: strings,
2258 tag: tag,
2259 end: prev(),
2260 });
2261 }
2262
2263 function subscripts(expr, allow_calls) {
2264 var start = expr.start;
2265 var optional = null;
2266 while (true) {
2267 if (is("operator", "?") && is_token(peek(), "punc", ".")) {
2268 next();
2269 next();
2270 optional = expr;
2271 }
2272 if (is("punc", "[")) {
2273 next();
2274 var prop = expression();
2275 expect("]");
2276 expr = new AST_Sub({
2277 start: start,
2278 optional: optional === expr,
2279 expression: expr,
2280 property: prop,
2281 end: prev(),
2282 });
2283 } else if (allow_calls && is("punc", "(")) {
2284 next();
2285 expr = new AST_Call({
2286 start: start,
2287 optional: optional === expr,
2288 expression: expr,
2289 args: expr_list(")", !options.strict),
2290 end: prev(),
2291 });
2292 } else if (optional === expr || is("punc", ".")) {
2293 if (optional !== expr) next();
2294 expr = new AST_Dot({
2295 start: start,
2296 optional: optional === expr,
2297 expression: expr,
2298 property: as_name(),
2299 end: prev(),
2300 });
2301 } else if (is("punc", "`")) {
2302 if (optional) croak("Invalid template on optional chain");
2303 expr = template(expr);
2304 } else {
2305 break;
2306 }
2307 }
2308 if (optional) expr.terminal = true;
2309 if (expr instanceof AST_Call && !expr.pure) {
2310 var start = expr.start;
2311 var comments = start.comments_before;
2312 var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
2313 while (--i >= 0) {
2314 var match = /[@#]__PURE__/.exec(comments[i].value);
2315 if (match) {
2316 expr.pure = match[0];
2317 break;
2318 }
2319 }
2320 }
2321 return expr;
2322 }
2323
2324 function maybe_unary(no_in) {
2325 var start = S.token;
2326 if (S.in_async && is("name", "await")) {
2327 if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
2328 S.input.context().regex_allowed = true;
2329 next();
2330 return new AST_Await({
2331 start: start,
2332 expression: maybe_unary(no_in),
2333 end: prev(),
2334 });
2335 }
2336 if (S.in_generator && is("name", "yield")) {
2337 if (S.in_funarg === S.in_function) croak("Invalid use of yield in function argument");
2338 S.input.context().regex_allowed = true;
2339 next();
2340 var exp = null;
2341 var nested = false;
2342 if (is("operator", "*")) {
2343 next();
2344 exp = maybe_assign(no_in);
2345 nested = true;
2346 } else if (is("punc") ? !PUNC_AFTER_EXPRESSION[S.token.value] : !can_insert_semicolon()) {
2347 exp = maybe_assign(no_in);
2348 }
2349 return new AST_Yield({
2350 start: start,
2351 expression: exp,
2352 nested: nested,
2353 end: prev(),
2354 });
2355 }
2356 if (is("operator") && UNARY_PREFIX[start.value]) {
2357 next();
2358 handle_regexp();
2359 var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(no_in));
2360 ex.start = start;
2361 ex.end = prev();
2362 return ex;
2363 }
2364 var val = expr_atom(true);
2365 while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
2366 val = make_unary(AST_UnaryPostfix, S.token, val);
2367 val.start = start;
2368 val.end = S.token;
2369 next();
2370 }
2371 return val;
2372 }
2373
2374 function make_unary(ctor, token, expr) {
2375 var op = token.value;
2376 switch (op) {
2377 case "++":
2378 case "--":
2379 if (!is_assignable(expr))
2380 token_error(token, "Invalid use of " + op + " operator");
2381 break;
2382 case "delete":
2383 if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
2384 token_error(expr.start, "Calling delete on expression not allowed in strict mode");
2385 break;
2386 }
2387 return new ctor({ operator: op, expression: expr });
2388 }
2389
2390 var expr_op = function(left, min_prec, no_in) {
2391 var op = is("operator") ? S.token.value : null;
2392 if (op == "in" && no_in) op = null;
2393 var prec = op != null ? PRECEDENCE[op] : null;
2394 if (prec != null && prec > min_prec) {
2395 next();
2396 var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in);
2397 return expr_op(new AST_Binary({
2398 start : left.start,
2399 left : left,
2400 operator : op,
2401 right : right,
2402 end : right.end
2403 }), min_prec, no_in);
2404 }
2405 return left;
2406 };
2407
2408 function expr_ops(no_in) {
2409 return expr_op(maybe_unary(no_in), 0, no_in);
2410 }
2411
2412 var maybe_conditional = function(no_in) {
2413 var start = S.token;
2414 var expr = expr_ops(no_in);
2415 if (is("operator", "?")) {
2416 next();
2417 var yes = maybe_assign();
2418 expect(":");
2419 return new AST_Conditional({
2420 start : start,
2421 condition : expr,
2422 consequent : yes,
2423 alternative : maybe_assign(no_in),
2424 end : prev()
2425 });
2426 }
2427 return expr;
2428 };
2429
2430 function is_assignable(expr) {
2431 return expr instanceof AST_PropAccess && !expr.optional || expr instanceof AST_SymbolRef;
2432 }
2433
2434 function to_destructured(node) {
2435 if (node instanceof AST_Array) {
2436 var rest = null;
2437 if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
2438 rest = to_destructured(node.elements.pop().expression);
2439 if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
2440 }
2441 var elements = node.elements.map(to_destructured);
2442 return all(elements, function(node) {
2443 return node instanceof AST_DefaultValue
2444 || node instanceof AST_Destructured
2445 || node instanceof AST_Hole
2446 || is_assignable(node);
2447 }) ? new AST_DestructuredArray({
2448 start: node.start,
2449 elements: elements,
2450 rest: rest,
2451 end: node.end,
2452 }) : node;
2453 }
2454 if (node instanceof AST_Assign) {
2455 var name = to_destructured(node.left);
2456 return name instanceof AST_Destructured || is_assignable(name) ? new AST_DefaultValue({
2457 start: node.start,
2458 name: name,
2459 value: node.right,
2460 end: node.end,
2461 }) : node;
2462 }
2463 if (!(node instanceof AST_Object)) return node;
2464 var rest = null;
2465 if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
2466 rest = to_destructured(node.properties.pop().expression);
2467 if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
2468 }
2469 var props = [];
2470 for (var i = 0; i < node.properties.length; i++) {
2471 var prop = node.properties[i];
2472 if (!(prop instanceof AST_ObjectKeyVal)) return node;
2473 var value = to_destructured(prop.value);
2474 if (!(value instanceof AST_DefaultValue || value instanceof AST_Destructured || is_assignable(value))) {
2475 return node;
2476 }
2477 props.push(new AST_DestructuredKeyVal({
2478 start: prop.start,
2479 key: prop.key,
2480 value: value,
2481 end: prop.end,
2482 }));
2483 }
2484 return new AST_DestructuredObject({
2485 start: node.start,
2486 properties: props,
2487 rest: rest,
2488 end: node.end,
2489 });
2490 }
2491
2492 function maybe_assign(no_in) {
2493 var start = S.token;
2494 var left = maybe_conditional(no_in), val = S.token.value;
2495 if (is("operator") && ASSIGNMENT[val]) {
2496 if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
2497 next();
2498 return new AST_Assign({
2499 start : start,
2500 left : left,
2501 operator : val,
2502 right : maybe_assign(no_in),
2503 end : prev()
2504 });
2505 }
2506 croak("Invalid assignment");
2507 }
2508 return left;
2509 }
2510
2511 function expression(no_in, maybe_arrow) {
2512 var start = S.token;
2513 var exprs = [];
2514 while (true) {
2515 if (maybe_arrow && is("operator", "...")) {
2516 next();
2517 exprs.rest = maybe_destructured(AST_SymbolFunarg);
2518 break;
2519 }
2520 exprs.push(maybe_assign(no_in));
2521 if (!is("punc", ",")) break;
2522 next();
2523 if (maybe_arrow && is("punc", ")") && is_token(peek(), "punc", "=>")) break;
2524 }
2525 return exprs.length == 1 && !exprs.rest ? exprs[0] : new AST_Sequence({
2526 start: start,
2527 expressions: exprs,
2528 end: prev(),
2529 });
2530 }
2531
2532 function in_loop(cont) {
2533 ++S.in_loop;
2534 var ret = cont();
2535 --S.in_loop;
2536 return ret;
2537 }
2538
2539 if (options.expression) {
2540 handle_regexp();
2541 var exp = expression();
2542 expect_token("eof");
2543 return exp;
2544 }
2545
2546 return function() {
2547 var start = S.token;
2548 var body = [];
2549 S.input.push_directives_stack();
2550 while (!is("eof"))
2551 body.push(statement());
2552 S.input.pop_directives_stack();
2553 var end = prev() || start;
2554 var toplevel = options.toplevel;
2555 if (toplevel) {
2556 toplevel.body = toplevel.body.concat(body);
2557 toplevel.end = end;
2558 } else {
2559 toplevel = new AST_Toplevel({ start: start, body: body, end: end });
2560 }
2561 return toplevel;
2562 }();
2563}