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