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