comparison node_modules/requirejs/bin/r.js @ 76:0ae87af84e2f

added oscgroups
author Rob Canning <rob@foo.net>
date Sun, 13 Jul 2014 10:07:41 +0100
parents 333afcfd3f3a
children
comparison
equal deleted inserted replaced
75:3a2845e3156e 76:0ae87af84e2f
1 #!/usr/bin/env node 1 #!/usr/bin/env node
2 /** 2 /**
3 * @license r.js 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. 3 * @license r.js 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4 * Available via the MIT or new BSD license. 4 * Available via the MIT or new BSD license.
5 * see: http://github.com/jrburke/requirejs for details 5 * see: http://github.com/jrburke/requirejs for details
6 */ 6 */
7 7
8 /* 8 /*
19 19
20 var requirejs, require, define, xpcUtil; 20 var requirejs, require, define, xpcUtil;
21 (function (console, args, readFileFunc) { 21 (function (console, args, readFileFunc) {
22 var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, 22 var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire,
23 nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, 23 nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci,
24 version = '2.1.9', 24 version = '2.1.14',
25 jsSuffixRegExp = /\.js$/, 25 jsSuffixRegExp = /\.js$/,
26 commandOption = '', 26 commandOption = '',
27 useLibLoaded = {}, 27 useLibLoaded = {},
28 //Used by jslib/rhino/args.js 28 //Used by jslib/rhino/args.js
29 rhinoArgs = args, 29 rhinoArgs = args,
50 exists = function () { 50 exists = function () {
51 console.log('x.js exists not applicable in browser env'); 51 console.log('x.js exists not applicable in browser env');
52 return false; 52 return false;
53 }; 53 };
54 54
55 } else if (typeof Packages !== 'undefined') {
56 env = 'rhino';
57
58 fileName = args[0];
59
60 if (fileName && fileName.indexOf('-') === 0) {
61 commandOption = fileName.substring(1);
62 fileName = args[1];
63 }
64
65 //Set up execution context.
66 rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext();
67
68 exec = function (string, name) {
69 return rhinoContext.evaluateString(this, string, name, 0, null);
70 };
71
72 exists = function (fileName) {
73 return (new java.io.File(fileName)).exists();
74 };
75
76 //Define a console.log for easier logging. Don't
77 //get fancy though.
78 if (typeof console === 'undefined') {
79 console = {
80 log: function () {
81 print.apply(undefined, arguments);
82 }
83 };
84 }
85 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) { 55 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
86 env = 'node'; 56 env = 'node';
87 57
88 //Get the fs module via Node's require before it 58 //Get the fs module via Node's require before it
89 //gets replaced. Used in require/node.js 59 //gets replaced. Used in require/node.js
119 fileName = process.argv[2]; 89 fileName = process.argv[2];
120 90
121 if (fileName && fileName.indexOf('-') === 0) { 91 if (fileName && fileName.indexOf('-') === 0) {
122 commandOption = fileName.substring(1); 92 commandOption = fileName.substring(1);
123 fileName = process.argv[3]; 93 fileName = process.argv[3];
94 }
95 } else if (typeof Packages !== 'undefined') {
96 env = 'rhino';
97
98 fileName = args[0];
99
100 if (fileName && fileName.indexOf('-') === 0) {
101 commandOption = fileName.substring(1);
102 fileName = args[1];
103 }
104
105 //Set up execution context.
106 rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext();
107
108 exec = function (string, name) {
109 return rhinoContext.evaluateString(this, string, name, 0, null);
110 };
111
112 exists = function (fileName) {
113 return (new java.io.File(fileName)).exists();
114 };
115
116 //Define a console.log for easier logging. Don't
117 //get fancy though.
118 if (typeof console === 'undefined') {
119 console = {
120 log: function () {
121 print.apply(undefined, arguments);
122 }
123 };
124 } 124 }
125 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) { 125 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
126 env = 'xpconnect'; 126 env = 'xpconnect';
127 127
128 Components.utils['import']('resource://gre/modules/FileUtils.jsm'); 128 Components.utils['import']('resource://gre/modules/FileUtils.jsm');
237 }; 237 };
238 } 238 }
239 } 239 }
240 240
241 /** vim: et:ts=4:sw=4:sts=4 241 /** vim: et:ts=4:sw=4:sts=4
242 * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. 242 * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
243 * Available via the MIT or new BSD license. 243 * Available via the MIT or new BSD license.
244 * see: http://github.com/jrburke/requirejs for details 244 * see: http://github.com/jrburke/requirejs for details
245 */ 245 */
246 //Not using strict: uneven strict support in browsers, #392, and causes 246 //Not using strict: uneven strict support in browsers, #392, and causes
247 //problems with requirejs.exec()/transpiler plugins that may not be strict. 247 //problems with requirejs.exec()/transpiler plugins that may not be strict.
250 250
251 251
252 (function (global) { 252 (function (global) {
253 var req, s, head, baseElement, dataMain, src, 253 var req, s, head, baseElement, dataMain, src,
254 interactiveScript, currentlyAddingScript, mainScript, subPath, 254 interactiveScript, currentlyAddingScript, mainScript, subPath,
255 version = '2.1.9', 255 version = '2.1.14',
256 commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, 256 commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
257 cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, 257 cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
258 jsSuffixRegExp = /\.js$/, 258 jsSuffixRegExp = /\.js$/,
259 currDirRegExp = /^\.\//, 259 currDirRegExp = /^\.\//,
260 op = Object.prototype, 260 op = Object.prototype,
346 */ 346 */
347 function mixin(target, source, force, deepStringMixin) { 347 function mixin(target, source, force, deepStringMixin) {
348 if (source) { 348 if (source) {
349 eachProp(source, function (value, prop) { 349 eachProp(source, function (value, prop) {
350 if (force || !hasProp(target, prop)) { 350 if (force || !hasProp(target, prop)) {
351 if (deepStringMixin && typeof value !== 'string') { 351 if (deepStringMixin && typeof value === 'object' && value &&
352 !isArray(value) && !isFunction(value) &&
353 !(value instanceof RegExp)) {
354
352 if (!target[prop]) { 355 if (!target[prop]) {
353 target[prop] = {}; 356 target[prop] = {};
354 } 357 }
355 mixin(target[prop], value, force, deepStringMixin); 358 mixin(target[prop], value, force, deepStringMixin);
356 } else { 359 } else {
376 379
377 function defaultOnError(err) { 380 function defaultOnError(err) {
378 throw err; 381 throw err;
379 } 382 }
380 383
381 //Allow getting a global that expressed in 384 //Allow getting a global that is expressed in
382 //dot notation, like 'a.b.c'. 385 //dot notation, like 'a.b.c'.
383 function getGlobal(value) { 386 function getGlobal(value) {
384 if (!value) { 387 if (!value) {
385 return value; 388 return value;
386 } 389 }
415 return; 418 return;
416 } 419 }
417 420
418 if (typeof requirejs !== 'undefined') { 421 if (typeof requirejs !== 'undefined') {
419 if (isFunction(requirejs)) { 422 if (isFunction(requirejs)) {
420 //Do not overwrite and existing requirejs instance. 423 //Do not overwrite an existing requirejs instance.
421 return; 424 return;
422 } 425 }
423 cfg = requirejs; 426 cfg = requirejs;
424 requirejs = undefined; 427 requirejs = undefined;
425 } 428 }
439 //config to speed up normalize(), which 442 //config to speed up normalize(), which
440 //will run faster if there is no default. 443 //will run faster if there is no default.
441 waitSeconds: 7, 444 waitSeconds: 7,
442 baseUrl: './', 445 baseUrl: './',
443 paths: {}, 446 paths: {},
447 bundles: {},
444 pkgs: {}, 448 pkgs: {},
445 shim: {}, 449 shim: {},
446 config: {} 450 config: {}
447 }, 451 },
448 registry = {}, 452 registry = {},
452 enabledRegistry = {}, 456 enabledRegistry = {},
453 undefEvents = {}, 457 undefEvents = {},
454 defQueue = [], 458 defQueue = [],
455 defined = {}, 459 defined = {},
456 urlFetched = {}, 460 urlFetched = {},
461 bundlesMap = {},
457 requireCounter = 1, 462 requireCounter = 1,
458 unnormalizedCounter = 1; 463 unnormalizedCounter = 1;
459 464
460 /** 465 /**
461 * Trims the . and .. from an array of path segments. 466 * Trims the . and .. from an array of path segments.
466 * NOTE: this method MODIFIES the input array. 471 * NOTE: this method MODIFIES the input array.
467 * @param {Array} ary the array of path segments. 472 * @param {Array} ary the array of path segments.
468 */ 473 */
469 function trimDots(ary) { 474 function trimDots(ary) {
470 var i, part; 475 var i, part;
471 for (i = 0; ary[i]; i += 1) { 476 for (i = 0; i < ary.length; i++) {
472 part = ary[i]; 477 part = ary[i];
473 if (part === '.') { 478 if (part === '.') {
474 ary.splice(i, 1); 479 ary.splice(i, 1);
475 i -= 1; 480 i -= 1;
476 } else if (part === '..') { 481 } else if (part === '..') {
477 if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { 482 // If at the start, or previous value is still ..,
478 //End of the line. Keep at least one non-dot 483 // keep them so that when converted to a path it may
479 //path segment at the front so it can be mapped 484 // still work when converted to a path, even though
480 //correctly to disk. Otherwise, there is likely 485 // as an ID it is less than ideal. In larger point
481 //no path mapping for a path starting with '..'. 486 // releases, may be better to just kick out an error.
482 //This can still fail, but catches the most reasonable 487 if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') {
483 //uses of .. 488 continue;
484 break;
485 } else if (i > 0) { 489 } else if (i > 0) {
486 ary.splice(i - 1, 2); 490 ary.splice(i - 1, 2);
487 i -= 2; 491 i -= 2;
488 } 492 }
489 } 493 }
499 * @param {Boolean} applyMap apply the map config to the value. Should 503 * @param {Boolean} applyMap apply the map config to the value. Should
500 * only be done if this normalization is for a dependency ID. 504 * only be done if this normalization is for a dependency ID.
501 * @returns {String} normalized name 505 * @returns {String} normalized name
502 */ 506 */
503 function normalize(name, baseName, applyMap) { 507 function normalize(name, baseName, applyMap) {
504 var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, 508 var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
505 foundMap, foundI, foundStarMap, starI, 509 foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
506 baseParts = baseName && baseName.split('/'), 510 baseParts = (baseName && baseName.split('/')),
507 normalizedBaseParts = baseParts,
508 map = config.map, 511 map = config.map,
509 starMap = map && map['*']; 512 starMap = map && map['*'];
510 513
511 //Adjust any relative paths. 514 //Adjust any relative paths.
512 if (name && name.charAt(0) === '.') { 515 if (name) {
513 //If have a base name, try to normalize against it, 516 name = name.split('/');
514 //otherwise, assume it is a top-level require that will 517 lastIndex = name.length - 1;
515 //be relative to baseUrl in the end. 518
516 if (baseName) { 519 // If wanting node ID compatibility, strip .js from end
517 if (getOwn(config.pkgs, baseName)) { 520 // of IDs. Have to do this here, and not in nameToUrl
518 //If the baseName is a package name, then just treat it as one 521 // because node allows either .js or non .js to map
519 //name to concat the name with. 522 // to same file.
520 normalizedBaseParts = baseParts = [baseName]; 523 if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
521 } else { 524 name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
522 //Convert baseName to array, and lop off the last part, 525 }
523 //so that . matches that 'directory' and not name of the baseName's 526
524 //module. For instance, baseName of 'one/two/three', maps to 527 // Starts with a '.' so need the baseName
525 //'one/two/three.js', but we want the directory, 'one/two' for 528 if (name[0].charAt(0) === '.' && baseParts) {
526 //this normalization. 529 //Convert baseName to array, and lop off the last part,
527 normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); 530 //so that . matches that 'directory' and not name of the baseName's
528 } 531 //module. For instance, baseName of 'one/two/three', maps to
529 532 //'one/two/three.js', but we want the directory, 'one/two' for
530 name = normalizedBaseParts.concat(name.split('/')); 533 //this normalization.
531 trimDots(name); 534 normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
532 535 name = normalizedBaseParts.concat(name);
533 //Some use of packages may use a . path to reference the 536 }
534 //'main' module name, so normalize for that. 537
535 pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); 538 trimDots(name);
536 name = name.join('/'); 539 name = name.join('/');
537 if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
538 name = pkgName;
539 }
540 } else if (name.indexOf('./') === 0) {
541 // No baseName, so this is ID is resolved relative
542 // to baseUrl, pull off the leading dot.
543 name = name.substring(2);
544 }
545 } 540 }
546 541
547 //Apply map config if available. 542 //Apply map config if available.
548 if (applyMap && map && (baseParts || starMap)) { 543 if (applyMap && map && (baseParts || starMap)) {
549 nameParts = name.split('/'); 544 nameParts = name.split('/');
550 545
551 for (i = nameParts.length; i > 0; i -= 1) { 546 outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
552 nameSegment = nameParts.slice(0, i).join('/'); 547 nameSegment = nameParts.slice(0, i).join('/');
553 548
554 if (baseParts) { 549 if (baseParts) {
555 //Find the longest baseName segment match in the config. 550 //Find the longest baseName segment match in the config.
556 //So, do joins on the biggest to smallest lengths of baseParts. 551 //So, do joins on the biggest to smallest lengths of baseParts.
563 mapValue = getOwn(mapValue, nameSegment); 558 mapValue = getOwn(mapValue, nameSegment);
564 if (mapValue) { 559 if (mapValue) {
565 //Match, update name to the new value. 560 //Match, update name to the new value.
566 foundMap = mapValue; 561 foundMap = mapValue;
567 foundI = i; 562 foundI = i;
568 break; 563 break outerLoop;
569 } 564 }
570 } 565 }
571 } 566 }
572 }
573
574 if (foundMap) {
575 break;
576 } 567 }
577 568
578 //Check for a star map match, but just hold on to it, 569 //Check for a star map match, but just hold on to it,
579 //if there is a shorter segment match later in a matching 570 //if there is a shorter segment match later in a matching
580 //config, then favor over this star map. 571 //config, then favor over this star map.
593 nameParts.splice(0, foundI, foundMap); 584 nameParts.splice(0, foundI, foundMap);
594 name = nameParts.join('/'); 585 name = nameParts.join('/');
595 } 586 }
596 } 587 }
597 588
598 return name; 589 // If the name points to a package's name, use
590 // the package main instead.
591 pkgMain = getOwn(config.pkgs, name);
592
593 return pkgMain ? pkgMain : name;
599 } 594 }
600 595
601 function removeScript(name) { 596 function removeScript(name) {
602 if (isBrowser) { 597 if (isBrowser) {
603 each(scripts(), function (scriptNode) { 598 each(scripts(), function (scriptNode) {
615 if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { 610 if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
616 //Pop off the first array value, since it failed, and 611 //Pop off the first array value, since it failed, and
617 //retry 612 //retry
618 pathConfig.shift(); 613 pathConfig.shift();
619 context.require.undef(id); 614 context.require.undef(id);
620 context.require([id]); 615
616 //Custom require that does not do map translation, since
617 //ID is "absolute", already mapped/resolved.
618 context.makeRequire(null, {
619 skipMap: true
620 })([id]);
621
621 return true; 622 return true;
622 } 623 }
623 } 624 }
624 625
625 //Turns a plugin!resource to [plugin, resource] 626 //Turns a plugin!resource to [plugin, resource]
681 //Plugin is loaded, use its normalize method. 682 //Plugin is loaded, use its normalize method.
682 normalizedName = pluginModule.normalize(name, function (name) { 683 normalizedName = pluginModule.normalize(name, function (name) {
683 return normalize(name, parentName, applyMap); 684 return normalize(name, parentName, applyMap);
684 }); 685 });
685 } else { 686 } else {
686 normalizedName = normalize(name, parentName, applyMap); 687 // If nested plugin references, then do not try to
688 // normalize, as it will not normalize correctly. This
689 // places a restriction on resourceIds, and the longer
690 // term solution is not to normalize until plugins are
691 // loaded and all normalizations to allow for async
692 // loading of a loader plugin. But for now, fixes the
693 // common uses. Details in #1131
694 normalizedName = name.indexOf('!') === -1 ?
695 normalize(name, parentName, applyMap) :
696 name;
687 } 697 }
688 } else { 698 } else {
689 //A regular module. 699 //A regular module.
690 normalizedName = normalize(name, parentName, applyMap); 700 normalizedName = normalize(name, parentName, applyMap);
691 701
786 if (globalDefQueue.length) { 796 if (globalDefQueue.length) {
787 //Array splice in the values since the context code has a 797 //Array splice in the values since the context code has a
788 //local var ref to defQueue, so cannot just reassign the one 798 //local var ref to defQueue, so cannot just reassign the one
789 //on context. 799 //on context.
790 apsp.apply(defQueue, 800 apsp.apply(defQueue,
791 [defQueue.length - 1, 0].concat(globalDefQueue)); 801 [defQueue.length, 0].concat(globalDefQueue));
792 globalDefQueue = []; 802 globalDefQueue = [];
793 } 803 }
794 } 804 }
795 805
796 handlers = { 806 handlers = {
803 }, 813 },
804 'exports': function (mod) { 814 'exports': function (mod) {
805 mod.usingExports = true; 815 mod.usingExports = true;
806 if (mod.map.isDefine) { 816 if (mod.map.isDefine) {
807 if (mod.exports) { 817 if (mod.exports) {
808 return mod.exports; 818 return (defined[mod.map.id] = mod.exports);
809 } else { 819 } else {
810 return (mod.exports = defined[mod.map.id] = {}); 820 return (mod.exports = defined[mod.map.id] = {});
811 } 821 }
812 } 822 }
813 }, 823 },
817 } else { 827 } else {
818 return (mod.module = { 828 return (mod.module = {
819 id: mod.map.id, 829 id: mod.map.id,
820 uri: mod.map.url, 830 uri: mod.map.url,
821 config: function () { 831 config: function () {
822 var c, 832 return getOwn(config.config, mod.map.id) || {};
823 pkg = getOwn(config.pkgs, mod.map.id);
824 // For packages, only support config targeted
825 // at the main module.
826 c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) :
827 getOwn(config.config, mod.map.id);
828 return c || {};
829 }, 833 },
830 exports: defined[mod.map.id] 834 exports: mod.exports || (mod.exports = {})
831 }); 835 });
832 } 836 }
833 } 837 }
834 }; 838 };
835 839
866 processed[id] = true; 870 processed[id] = true;
867 } 871 }
868 } 872 }
869 873
870 function checkLoaded() { 874 function checkLoaded() {
871 var map, modId, err, usingPathFallback, 875 var err, usingPathFallback,
872 waitInterval = config.waitSeconds * 1000, 876 waitInterval = config.waitSeconds * 1000,
873 //It is possible to disable the wait interval by using waitSeconds of 0. 877 //It is possible to disable the wait interval by using waitSeconds of 0.
874 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), 878 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
875 noLoads = [], 879 noLoads = [],
876 reqCalls = [], 880 reqCalls = [],
884 888
885 inCheckLoaded = true; 889 inCheckLoaded = true;
886 890
887 //Figure out the state of all the modules. 891 //Figure out the state of all the modules.
888 eachProp(enabledRegistry, function (mod) { 892 eachProp(enabledRegistry, function (mod) {
889 map = mod.map; 893 var map = mod.map,
890 modId = map.id; 894 modId = map.id;
891 895
892 //Skip things that are not enabled or in error state. 896 //Skip things that are not enabled or in error state.
893 if (!mod.enabled) { 897 if (!mod.enabled) {
894 return; 898 return;
895 } 899 }
1108 } 1112 }
1109 } else { 1113 } else {
1110 exports = context.execCb(id, factory, depExports, exports); 1114 exports = context.execCb(id, factory, depExports, exports);
1111 } 1115 }
1112 1116
1113 if (this.map.isDefine) { 1117 // Favor return value over exports. If node/cjs in play,
1114 //If setting exports via 'module' is in play, 1118 // then will not have a return value anyway. Favor
1115 //favor that over return value and exports. After that, 1119 // module.exports assignment over exports object.
1116 //favor a non-undefined return value over exports use. 1120 if (this.map.isDefine && exports === undefined) {
1117 cjsModule = this.module; 1121 cjsModule = this.module;
1118 if (cjsModule && 1122 if (cjsModule) {
1119 cjsModule.exports !== undefined &&
1120 //Make sure it is not already the exports value
1121 cjsModule.exports !== this.exports) {
1122 exports = cjsModule.exports; 1123 exports = cjsModule.exports;
1123 } else if (exports === undefined && this.usingExports) { 1124 } else if (this.usingExports) {
1124 //exports already set the defined value. 1125 //exports already set the defined value.
1125 exports = this.exports; 1126 exports = this.exports;
1126 } 1127 }
1127 } 1128 }
1128 1129
1178 //can be traced for cycles. 1179 //can be traced for cycles.
1179 this.depMaps.push(pluginMap); 1180 this.depMaps.push(pluginMap);
1180 1181
1181 on(pluginMap, 'defined', bind(this, function (plugin) { 1182 on(pluginMap, 'defined', bind(this, function (plugin) {
1182 var load, normalizedMap, normalizedMod, 1183 var load, normalizedMap, normalizedMod,
1184 bundleId = getOwn(bundlesMap, this.map.id),
1183 name = this.map.name, 1185 name = this.map.name,
1184 parentName = this.map.parentMap ? this.map.parentMap.name : null, 1186 parentName = this.map.parentMap ? this.map.parentMap.name : null,
1185 localRequire = context.makeRequire(map.parentMap, { 1187 localRequire = context.makeRequire(map.parentMap, {
1186 enableBuildCallback: true 1188 enableBuildCallback: true
1187 }); 1189 });
1223 } 1225 }
1224 1226
1225 return; 1227 return;
1226 } 1228 }
1227 1229
1230 //If a paths config, then just load that file instead to
1231 //resolve the plugin, as it is built into that paths layer.
1232 if (bundleId) {
1233 this.map.url = context.nameToUrl(bundleId);
1234 this.load();
1235 return;
1236 }
1237
1228 load = bind(this, function (value) { 1238 load = bind(this, function (value) {
1229 this.init([], function () { return value; }, null, { 1239 this.init([], function () { return value; }, null, {
1230 enabled: true 1240 enabled: true
1231 }); 1241 });
1232 }); 1242 });
1487 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { 1497 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
1488 cfg.baseUrl += '/'; 1498 cfg.baseUrl += '/';
1489 } 1499 }
1490 } 1500 }
1491 1501
1492 //Save off the paths and packages since they require special processing, 1502 //Save off the paths since they require special processing,
1493 //they are additive. 1503 //they are additive.
1494 var pkgs = config.pkgs, 1504 var shim = config.shim,
1495 shim = config.shim,
1496 objs = { 1505 objs = {
1497 paths: true, 1506 paths: true,
1507 bundles: true,
1498 config: true, 1508 config: true,
1499 map: true 1509 map: true
1500 }; 1510 };
1501 1511
1502 eachProp(cfg, function (value, prop) { 1512 eachProp(cfg, function (value, prop) {
1503 if (objs[prop]) { 1513 if (objs[prop]) {
1504 if (prop === 'map') { 1514 if (!config[prop]) {
1505 if (!config.map) { 1515 config[prop] = {};
1506 config.map = {};
1507 }
1508 mixin(config[prop], value, true, true);
1509 } else {
1510 mixin(config[prop], value, true);
1511 } 1516 }
1517 mixin(config[prop], value, true, true);
1512 } else { 1518 } else {
1513 config[prop] = value; 1519 config[prop] = value;
1514 } 1520 }
1515 }); 1521 });
1522
1523 //Reverse map the bundles
1524 if (cfg.bundles) {
1525 eachProp(cfg.bundles, function (value, prop) {
1526 each(value, function (v) {
1527 if (v !== prop) {
1528 bundlesMap[v] = prop;
1529 }
1530 });
1531 });
1532 }
1516 1533
1517 //Merge shim 1534 //Merge shim
1518 if (cfg.shim) { 1535 if (cfg.shim) {
1519 eachProp(cfg.shim, function (value, id) { 1536 eachProp(cfg.shim, function (value, id) {
1520 //Normalize the structure 1537 //Normalize the structure
1532 } 1549 }
1533 1550
1534 //Adjust packages if necessary. 1551 //Adjust packages if necessary.
1535 if (cfg.packages) { 1552 if (cfg.packages) {
1536 each(cfg.packages, function (pkgObj) { 1553 each(cfg.packages, function (pkgObj) {
1537 var location; 1554 var location, name;
1538 1555
1539 pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; 1556 pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
1557
1558 name = pkgObj.name;
1540 location = pkgObj.location; 1559 location = pkgObj.location;
1541 1560 if (location) {
1542 //Create a brand new object on pkgs, since currentPackages can 1561 config.paths[name] = pkgObj.location;
1543 //be passed in again, and config.pkgs is the internal transformed 1562 }
1544 //state for all package configs. 1563
1545 pkgs[pkgObj.name] = { 1564 //Save pointer to main module ID for pkg name.
1546 name: pkgObj.name, 1565 //Remove leading dot in main, so main paths are normalized,
1547 location: location || pkgObj.name, 1566 //and remove any trailing .js, since different package
1548 //Remove leading dot in main, so main paths are normalized, 1567 //envs have different conventions: some use a module name,
1549 //and remove any trailing .js, since different package 1568 //some use a file name.
1550 //envs have different conventions: some use a module name, 1569 config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
1551 //some use a file name. 1570 .replace(currDirRegExp, '')
1552 main: (pkgObj.main || 'main') 1571 .replace(jsSuffixRegExp, '');
1553 .replace(currDirRegExp, '')
1554 .replace(jsSuffixRegExp, '')
1555 };
1556 }); 1572 });
1557
1558 //Done with modifications, assing packages back to context config
1559 config.pkgs = pkgs;
1560 } 1573 }
1561 1574
1562 //If there are any "waiting to execute" modules in the registry, 1575 //If there are any "waiting to execute" modules in the registry,
1563 //update the maps for them, since their info, like URLs to load, 1576 //update the maps for them, since their info, like URLs to load,
1564 //may have changed. 1577 //may have changed.
1707 1720
1708 delete defined[id]; 1721 delete defined[id];
1709 delete urlFetched[map.url]; 1722 delete urlFetched[map.url];
1710 delete undefEvents[id]; 1723 delete undefEvents[id];
1711 1724
1725 //Clean queued defines too. Go backwards
1726 //in array so that the splices do not
1727 //mess up the iteration.
1728 eachReverse(defQueue, function(args, i) {
1729 if(args[0] === id) {
1730 defQueue.splice(i, 1);
1731 }
1732 });
1733
1712 if (mod) { 1734 if (mod) {
1713 //Hold on to listeners in case the 1735 //Hold on to listeners in case the
1714 //module will be attempted to be reloaded 1736 //module will be attempted to be reloaded
1715 //using a different config. 1737 //using a different config.
1716 if (mod.events.defined) { 1738 if (mod.events.defined) {
1726 }, 1748 },
1727 1749
1728 /** 1750 /**
1729 * Called to enable a module if it is still in the registry 1751 * Called to enable a module if it is still in the registry
1730 * awaiting enablement. A second arg, parent, the parent module, 1752 * awaiting enablement. A second arg, parent, the parent module,
1731 * is passed in for context, when this method is overriden by 1753 * is passed in for context, when this method is overridden by
1732 * the optimizer. Not shown here to keep code compact. 1754 * the optimizer. Not shown here to keep code compact.
1733 */ 1755 */
1734 enable: function (depMap) { 1756 enable: function (depMap) {
1735 var mod = getOwn(registry, depMap.id); 1757 var mod = getOwn(registry, depMap.id);
1736 if (mod) { 1758 if (mod) {
1800 * Note that it **does not** call normalize on the moduleName, 1822 * Note that it **does not** call normalize on the moduleName,
1801 * it is assumed to have already been normalized. This is an 1823 * it is assumed to have already been normalized. This is an
1802 * internal API, not a public one. Use toUrl for the public API. 1824 * internal API, not a public one. Use toUrl for the public API.
1803 */ 1825 */
1804 nameToUrl: function (moduleName, ext, skipExt) { 1826 nameToUrl: function (moduleName, ext, skipExt) {
1805 var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, 1827 var paths, syms, i, parentModule, url,
1806 parentPath; 1828 parentPath, bundleId,
1829 pkgMain = getOwn(config.pkgs, moduleName);
1830
1831 if (pkgMain) {
1832 moduleName = pkgMain;
1833 }
1834
1835 bundleId = getOwn(bundlesMap, moduleName);
1836
1837 if (bundleId) {
1838 return context.nameToUrl(bundleId, ext, skipExt);
1839 }
1807 1840
1808 //If a colon is in the URL, it indicates a protocol is used and it is just 1841 //If a colon is in the URL, it indicates a protocol is used and it is just
1809 //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) 1842 //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
1810 //or ends with .js, then assume the user meant to use an url and not a module id. 1843 //or ends with .js, then assume the user meant to use an url and not a module id.
1811 //The slash is important for protocol-less URLs as well as full paths. 1844 //The slash is important for protocol-less URLs as well as full paths.
1815 //an extension, this method probably needs to be reworked. 1848 //an extension, this method probably needs to be reworked.
1816 url = moduleName + (ext || ''); 1849 url = moduleName + (ext || '');
1817 } else { 1850 } else {
1818 //A module that needs to be converted to a path. 1851 //A module that needs to be converted to a path.
1819 paths = config.paths; 1852 paths = config.paths;
1820 pkgs = config.pkgs;
1821 1853
1822 syms = moduleName.split('/'); 1854 syms = moduleName.split('/');
1823 //For each module name segment, see if there is a path 1855 //For each module name segment, see if there is a path
1824 //registered for it. Start with most specific name 1856 //registered for it. Start with most specific name
1825 //and work up from it. 1857 //and work up from it.
1826 for (i = syms.length; i > 0; i -= 1) { 1858 for (i = syms.length; i > 0; i -= 1) {
1827 parentModule = syms.slice(0, i).join('/'); 1859 parentModule = syms.slice(0, i).join('/');
1828 pkg = getOwn(pkgs, parentModule); 1860
1829 parentPath = getOwn(paths, parentModule); 1861 parentPath = getOwn(paths, parentModule);
1830 if (parentPath) { 1862 if (parentPath) {
1831 //If an array, it means there are a few choices, 1863 //If an array, it means there are a few choices,
1832 //Choose the one that is desired 1864 //Choose the one that is desired
1833 if (isArray(parentPath)) { 1865 if (isArray(parentPath)) {
1834 parentPath = parentPath[0]; 1866 parentPath = parentPath[0];
1835 } 1867 }
1836 syms.splice(0, i, parentPath); 1868 syms.splice(0, i, parentPath);
1837 break;
1838 } else if (pkg) {
1839 //If module name is just the package name, then looking
1840 //for the main module.
1841 if (moduleName === pkg.name) {
1842 pkgPath = pkg.location + '/' + pkg.main;
1843 } else {
1844 pkgPath = pkg.location;
1845 }
1846 syms.splice(0, i, pkgPath);
1847 break; 1869 break;
1848 } 1870 }
1849 } 1871 }
1850 1872
1851 //Join the path parts together, then figure out if baseUrl is needed. 1873 //Join the path parts together, then figure out if baseUrl is needed.
2301 define: define 2323 define: define
2302 }; 2324 };
2303 2325
2304 if (env === 'browser') { 2326 if (env === 'browser') {
2305 /** 2327 /**
2306 * @license RequireJS rhino Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 2328 * @license RequireJS rhino Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
2307 * Available via the MIT or new BSD license. 2329 * Available via the MIT or new BSD license.
2308 * see: http://github.com/jrburke/requirejs for details 2330 * see: http://github.com/jrburke/requirejs for details
2309 */ 2331 */
2310 2332
2311 //sloppy since eval enclosed with use strict causes problems if the source 2333 //sloppy since eval enclosed with use strict causes problems if the source
2330 }; 2352 };
2331 }; 2353 };
2332 }()); 2354 }());
2333 } else if (env === 'rhino') { 2355 } else if (env === 'rhino') {
2334 /** 2356 /**
2335 * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 2357 * @license RequireJS rhino Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2336 * Available via the MIT or new BSD license. 2358 * Available via the MIT or new BSD license.
2337 * see: http://github.com/jrburke/requirejs for details 2359 * see: http://github.com/jrburke/requirejs for details
2338 */ 2360 */
2339 2361
2340 /*jslint */ 2362 /*jslint */
2354 } else if (env === 'node') { 2376 } else if (env === 'node') {
2355 this.requirejsVars.nodeRequire = nodeRequire; 2377 this.requirejsVars.nodeRequire = nodeRequire;
2356 require.nodeRequire = nodeRequire; 2378 require.nodeRequire = nodeRequire;
2357 2379
2358 /** 2380 /**
2359 * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 2381 * @license RequireJS node Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2360 * Available via the MIT or new BSD license. 2382 * Available via the MIT or new BSD license.
2361 * see: http://github.com/jrburke/requirejs for details 2383 * see: http://github.com/jrburke/requirejs for details
2362 */ 2384 */
2363 2385
2364 /*jslint regexp: false */ 2386 /*jslint regexp: false */
2436 context.enable(moduleMap, relModuleMap); 2458 context.enable(moduleMap, relModuleMap);
2437 } 2459 }
2438 2460
2439 //Break any cycles by requiring it normally, but this will 2461 //Break any cycles by requiring it normally, but this will
2440 //finish synchronously 2462 //finish synchronously
2441 require([moduleName]); 2463 context.require([moduleName]);
2442 2464
2443 //The above calls are sync, so can do the next thing safely. 2465 //The above calls are sync, so can do the next thing safely.
2444 ret = context.defined[moduleName]; 2466 ret = context.defined[moduleName];
2445 } finally { 2467 } finally {
2446 context.nextTick = oldTick; 2468 context.nextTick = oldTick;
2514 originalName + '") and it failed ' + 2536 originalName + '") and it failed ' +
2515 'with error: ' + e); 2537 'with error: ' + e);
2516 err.originalError = e; 2538 err.originalError = e;
2517 err.moduleName = originalName; 2539 err.moduleName = originalName;
2518 err.requireModules = [moduleName]; 2540 err.requireModules = [moduleName];
2519 return context.onError(err); 2541 throw err;
2520 } 2542 }
2521 }); 2543 });
2522 } 2544 }
2523 2545
2524 //Support anonymous modules. 2546 //Support anonymous modules.
2533 }; 2555 };
2534 }()); 2556 }());
2535 2557
2536 } else if (env === 'xpconnect') { 2558 } else if (env === 'xpconnect') {
2537 /** 2559 /**
2538 * @license RequireJS xpconnect Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 2560 * @license RequireJS xpconnect Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
2539 * Available via the MIT or new BSD license. 2561 * Available via the MIT or new BSD license.
2540 * see: http://github.com/jrburke/requirejs for details 2562 * see: http://github.com/jrburke/requirejs for details
2541 */ 2563 */
2542 2564
2543 /*jslint */ 2565 /*jslint */
2568 * Loads the library files that can be used for the optimizer, or for other 2590 * Loads the library files that can be used for the optimizer, or for other
2569 * tasks. 2591 * tasks.
2570 */ 2592 */
2571 function loadLib() { 2593 function loadLib() {
2572 /** 2594 /**
2573 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 2595 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2574 * Available via the MIT or new BSD license. 2596 * Available via the MIT or new BSD license.
2575 * see: http://github.com/jrburke/requirejs for details 2597 * see: http://github.com/jrburke/requirejs for details
2576 */ 2598 */
2577 2599
2578 /*jslint strict: false */ 2600 /*jslint strict: false */
2585 */ 2607 */
2586 (function () { 2608 (function () {
2587 var pathRegExp = /(\/|^)env\/|\{env\}/, 2609 var pathRegExp = /(\/|^)env\/|\{env\}/,
2588 env = 'unknown'; 2610 env = 'unknown';
2589 2611
2590 if (typeof Packages !== 'undefined') { 2612 if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
2613 env = 'node';
2614 } else if (typeof Packages !== 'undefined') {
2591 env = 'rhino'; 2615 env = 'rhino';
2592 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
2593 env = 'node';
2594 } else if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') || 2616 } else if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') ||
2595 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) { 2617 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) {
2596 env = 'browser'; 2618 env = 'browser';
2597 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) { 2619 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
2598 env = 'xpconnect'; 2620 env = 'xpconnect';
2620 req([name], function (mod) { 2642 req([name], function (mod) {
2621 load(mod); 2643 load(mod);
2622 }); 2644 });
2623 } 2645 }
2624 }); 2646 });
2625 }());/** 2647 }());
2626 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 2648 /**
2649 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2627 * Available via the MIT or new BSD license. 2650 * Available via the MIT or new BSD license.
2628 * see: http://github.com/jrburke/requirejs for details 2651 * see: http://github.com/jrburke/requirejs for details
2629 */ 2652 */
2630 2653
2631 /*jslint plusplus: true */ 2654 /*jslint plusplus: true */
2632 /*global define */ 2655 /*global define, java */
2633 2656
2634 define('lang', function () { 2657 define('lang', function () {
2635 'use strict'; 2658 'use strict';
2636 2659
2637 var lang, 2660 var lang, isJavaObj,
2638 hasOwn = Object.prototype.hasOwnProperty; 2661 hasOwn = Object.prototype.hasOwnProperty;
2639 2662
2640 function hasProp(obj, prop) { 2663 function hasProp(obj, prop) {
2641 return hasOwn.call(obj, prop); 2664 return hasOwn.call(obj, prop);
2665 }
2666
2667 isJavaObj = function () {
2668 return false;
2669 };
2670
2671 if (typeof java !== 'undefined' && java.lang && java.lang.Object) {
2672 isJavaObj = function (obj) {
2673 return obj instanceof java.lang.Object;
2674 };
2642 } 2675 }
2643 2676
2644 lang = { 2677 lang = {
2645 backSlashRegExp: /\\/g, 2678 backSlashRegExp: /\\/g,
2646 ostring: Object.prototype.toString, 2679 ostring: Object.prototype.toString,
2700 lang._mixin(dest, parameters[i], override); 2733 lang._mixin(dest, parameters[i], override);
2701 } 2734 }
2702 return dest; // Object 2735 return dest; // Object
2703 }, 2736 },
2704 2737
2738 /**
2739 * Does a deep mix of source into dest, where source values override
2740 * dest values if a winner is needed.
2741 * @param {Object} dest destination object that receives the mixed
2742 * values.
2743 * @param {Object} source source object contributing properties to mix
2744 * in.
2745 * @return {[Object]} returns dest object with the modification.
2746 */
2747 deepMix: function(dest, source) {
2748 lang.eachProp(source, function (value, prop) {
2749 if (typeof value === 'object' && value &&
2750 !lang.isArray(value) && !lang.isFunction(value) &&
2751 !(value instanceof RegExp)) {
2752
2753 if (!dest[prop]) {
2754 dest[prop] = {};
2755 }
2756 lang.deepMix(dest[prop], value);
2757 } else {
2758 dest[prop] = value;
2759 }
2760 });
2761 return dest;
2762 },
2705 2763
2706 /** 2764 /**
2707 * Does a type of deep copy. Do not give it anything fancy, best 2765 * Does a type of deep copy. Do not give it anything fancy, best
2708 * for basic object copies of objects that also work well as 2766 * for basic object copies of objects that also work well as
2709 * JSON-serialized things, or has properties pointing to functions. 2767 * JSON-serialized things, or has properties pointing to functions.
2724 } 2782 }
2725 2783
2726 type = typeof obj; 2784 type = typeof obj;
2727 if (obj === null || obj === undefined || type === 'boolean' || 2785 if (obj === null || obj === undefined || type === 'boolean' ||
2728 type === 'string' || type === 'number' || lang.isFunction(obj) || 2786 type === 'string' || type === 'number' || lang.isFunction(obj) ||
2729 lang.isRegExp(obj)) { 2787 lang.isRegExp(obj)|| isJavaObj(obj)) {
2730 return obj; 2788 return obj;
2731 } 2789 }
2732 2790
2733 //Anything else is an object, hopefully. 2791 //Anything else is an object, hopefully.
2734 result = {}; 2792 result = {};
2803 } 2861 }
2804 }; 2862 };
2805 return lang; 2863 return lang;
2806 }); 2864 });
2807 /** 2865 /**
2808 * prim 0.0.1 Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. 2866 * prim 0.0.1 Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
2809 * Available via the MIT or new BSD license. 2867 * Available via the MIT or new BSD license.
2810 * see: http://github.com/requirejs/prim for details 2868 * see: http://github.com/requirejs/prim for details
2811 */ 2869 */
2812 2870
2813 /*global setImmediate, process, setTimeout, define, module */ 2871 /*global setImmediate, process, setTimeout, define, module */
2998 module.exports = prim; 3056 module.exports = prim;
2999 } 3057 }
3000 }()); 3058 }());
3001 if(env === 'browser') { 3059 if(env === 'browser') {
3002 /** 3060 /**
3003 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 3061 * @license RequireJS Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3004 * Available via the MIT or new BSD license. 3062 * Available via the MIT or new BSD license.
3005 * see: http://github.com/jrburke/requirejs for details 3063 * see: http://github.com/jrburke/requirejs for details
3006 */ 3064 */
3007 3065
3008 /*jslint strict: false */ 3066 /*jslint strict: false */
3015 3073
3016 } 3074 }
3017 3075
3018 if(env === 'node') { 3076 if(env === 'node') {
3019 /** 3077 /**
3020 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 3078 * @license RequireJS Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3021 * Available via the MIT or new BSD license. 3079 * Available via the MIT or new BSD license.
3022 * see: http://github.com/jrburke/requirejs for details 3080 * see: http://github.com/jrburke/requirejs for details
3023 */ 3081 */
3024 3082
3025 /*jslint strict: false */ 3083 /*jslint strict: false */
3032 3090
3033 } 3091 }
3034 3092
3035 if(env === 'rhino') { 3093 if(env === 'rhino') {
3036 /** 3094 /**
3037 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 3095 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3038 * Available via the MIT or new BSD license. 3096 * Available via the MIT or new BSD license.
3039 * see: http://github.com/jrburke/requirejs for details 3097 * see: http://github.com/jrburke/requirejs for details
3040 */ 3098 */
3041 3099
3042 /*jslint strict: false */ 3100 /*jslint strict: false */
3049 3107
3050 } 3108 }
3051 3109
3052 if(env === 'xpconnect') { 3110 if(env === 'xpconnect') {
3053 /** 3111 /**
3054 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 3112 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3055 * Available via the MIT or new BSD license. 3113 * Available via the MIT or new BSD license.
3056 * see: http://github.com/jrburke/requirejs for details 3114 * see: http://github.com/jrburke/requirejs for details
3057 */ 3115 */
3058 3116
3059 /*jslint strict: false */ 3117 /*jslint strict: false */
3066 3124
3067 } 3125 }
3068 3126
3069 if(env === 'browser') { 3127 if(env === 'browser') {
3070 /** 3128 /**
3071 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3129 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3072 * Available via the MIT or new BSD license. 3130 * Available via the MIT or new BSD license.
3073 * see: http://github.com/jrburke/requirejs for details 3131 * see: http://github.com/jrburke/requirejs for details
3074 */ 3132 */
3075 3133
3076 /*jslint strict: false */ 3134 /*jslint strict: false */
3083 3141
3084 } 3142 }
3085 3143
3086 if(env === 'node') { 3144 if(env === 'node') {
3087 /** 3145 /**
3088 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3146 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3089 * Available via the MIT or new BSD license. 3147 * Available via the MIT or new BSD license.
3090 * see: http://github.com/jrburke/requirejs for details 3148 * see: http://github.com/jrburke/requirejs for details
3091 */ 3149 */
3092 3150
3093 /*jslint strict: false */ 3151 /*jslint strict: false */
3107 3165
3108 } 3166 }
3109 3167
3110 if(env === 'rhino') { 3168 if(env === 'rhino') {
3111 /** 3169 /**
3112 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3170 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3113 * Available via the MIT or new BSD license. 3171 * Available via the MIT or new BSD license.
3114 * see: http://github.com/jrburke/requirejs for details 3172 * see: http://github.com/jrburke/requirejs for details
3115 */ 3173 */
3116 3174
3117 /*jslint strict: false */ 3175 /*jslint strict: false */
3132 3190
3133 } 3191 }
3134 3192
3135 if(env === 'xpconnect') { 3193 if(env === 'xpconnect') {
3136 /** 3194 /**
3137 * @license Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 3195 * @license Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3138 * Available via the MIT or new BSD license. 3196 * Available via the MIT or new BSD license.
3139 * see: http://github.com/jrburke/requirejs for details 3197 * see: http://github.com/jrburke/requirejs for details
3140 */ 3198 */
3141 3199
3142 /*jslint strict: false */ 3200 /*jslint strict: false */
3157 3215
3158 } 3216 }
3159 3217
3160 if(env === 'browser') { 3218 if(env === 'browser') {
3161 /** 3219 /**
3162 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3220 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3163 * Available via the MIT or new BSD license. 3221 * Available via the MIT or new BSD license.
3164 * see: http://github.com/jrburke/requirejs for details 3222 * see: http://github.com/jrburke/requirejs for details
3165 */ 3223 */
3166 3224
3167 /*jslint strict: false */ 3225 /*jslint strict: false */
3177 3235
3178 } 3236 }
3179 3237
3180 if(env === 'node') { 3238 if(env === 'node') {
3181 /** 3239 /**
3182 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3240 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3183 * Available via the MIT or new BSD license. 3241 * Available via the MIT or new BSD license.
3184 * see: http://github.com/jrburke/requirejs for details 3242 * see: http://github.com/jrburke/requirejs for details
3185 */ 3243 */
3186 3244
3187 /*jslint strict: false */ 3245 /*jslint strict: false */
3198 3256
3199 } 3257 }
3200 3258
3201 if(env === 'rhino') { 3259 if(env === 'rhino') {
3202 /** 3260 /**
3203 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3261 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3204 * Available via the MIT or new BSD license. 3262 * Available via the MIT or new BSD license.
3205 * see: http://github.com/jrburke/requirejs for details 3263 * see: http://github.com/jrburke/requirejs for details
3206 */ 3264 */
3207 3265
3208 /*jslint strict: false */ 3266 /*jslint strict: false */
3214 3272
3215 } 3273 }
3216 3274
3217 if(env === 'xpconnect') { 3275 if(env === 'xpconnect') {
3218 /** 3276 /**
3219 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 3277 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3220 * Available via the MIT or new BSD license. 3278 * Available via the MIT or new BSD license.
3221 * see: http://github.com/jrburke/requirejs for details 3279 * see: http://github.com/jrburke/requirejs for details
3222 */ 3280 */
3223 3281
3224 /*jslint strict: false */ 3282 /*jslint strict: false */
3230 3288
3231 } 3289 }
3232 3290
3233 if(env === 'browser') { 3291 if(env === 'browser') {
3234 /** 3292 /**
3235 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 3293 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3236 * Available via the MIT or new BSD license. 3294 * Available via the MIT or new BSD license.
3237 * see: http://github.com/jrburke/requirejs for details 3295 * see: http://github.com/jrburke/requirejs for details
3238 */ 3296 */
3239 3297
3240 /*jslint sloppy: true, nomen: true */ 3298 /*jslint sloppy: true, nomen: true */
3408 3466
3409 } 3467 }
3410 3468
3411 if(env === 'node') { 3469 if(env === 'node') {
3412 /** 3470 /**
3413 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3471 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3414 * Available via the MIT or new BSD license. 3472 * Available via the MIT or new BSD license.
3415 * see: http://github.com/jrburke/requirejs for details 3473 * see: http://github.com/jrburke/requirejs for details
3416 */ 3474 */
3417 3475
3418 /*jslint plusplus: false, octal:false, strict: false */ 3476 /*jslint plusplus: false, octal:false, strict: false */
3671 3729
3672 deleteFile: function (/*String*/fileName) { 3730 deleteFile: function (/*String*/fileName) {
3673 //summary: deletes a file or directory if it exists. 3731 //summary: deletes a file or directory if it exists.
3674 var files, i, stat; 3732 var files, i, stat;
3675 if (file.exists(fileName)) { 3733 if (file.exists(fileName)) {
3676 stat = fs.statSync(fileName); 3734 stat = fs.lstatSync(fileName);
3677 if (stat.isDirectory()) { 3735 if (stat.isDirectory()) {
3678 files = fs.readdirSync(fileName); 3736 files = fs.readdirSync(fileName);
3679 for (i = 0; i < files.length; i++) { 3737 for (i = 0; i < files.length; i++) {
3680 this.deleteFile(path.join(fileName, files[i])); 3738 this.deleteFile(path.join(fileName, files[i]));
3681 } 3739 }
3696 if (file.exists(startDir)) { 3754 if (file.exists(startDir)) {
3697 dirFileArray = fs.readdirSync(startDir); 3755 dirFileArray = fs.readdirSync(startDir);
3698 for (i = 0; i < dirFileArray.length; i++) { 3756 for (i = 0; i < dirFileArray.length; i++) {
3699 fileName = dirFileArray[i]; 3757 fileName = dirFileArray[i];
3700 filePath = path.join(startDir, fileName); 3758 filePath = path.join(startDir, fileName);
3701 stat = fs.statSync(filePath); 3759 stat = fs.lstatSync(filePath);
3702 if (stat.isDirectory()) { 3760 if (stat.isDirectory()) {
3703 file.deleteEmptyDirs(filePath); 3761 file.deleteEmptyDirs(filePath);
3704 } 3762 }
3705 } 3763 }
3706 3764
3718 3776
3719 } 3777 }
3720 3778
3721 if(env === 'rhino') { 3779 if(env === 'rhino') {
3722 /** 3780 /**
3723 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3781 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3724 * Available via the MIT or new BSD license. 3782 * Available via the MIT or new BSD license.
3725 * see: http://github.com/jrburke/requirejs for details 3783 * see: http://github.com/jrburke/requirejs for details
3726 */ 3784 */
3727 //Helper functions to deal with file I/O. 3785 //Helper functions to deal with file I/O.
3728 3786
4012 4070
4013 } 4071 }
4014 4072
4015 if(env === 'xpconnect') { 4073 if(env === 'xpconnect') {
4016 /** 4074 /**
4017 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 4075 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
4018 * Available via the MIT or new BSD license. 4076 * Available via the MIT or new BSD license.
4019 * see: http://github.com/jrburke/requirejs for details 4077 * see: http://github.com/jrburke/requirejs for details
4020 */ 4078 */
4021 //Helper functions to deal with file I/O. 4079 //Helper functions to deal with file I/O.
4022 4080
4332 4390
4333 } 4391 }
4334 4392
4335 if(env === 'browser') { 4393 if(env === 'browser') {
4336 /** 4394 /**
4337 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 4395 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4338 * Available via the MIT or new BSD license. 4396 * Available via the MIT or new BSD license.
4339 * see: http://github.com/jrburke/requirejs for details 4397 * see: http://github.com/jrburke/requirejs for details
4340 */ 4398 */
4341 4399
4342 /*jslint strict: false */ 4400 /*jslint strict: false */
4352 4410
4353 } 4411 }
4354 4412
4355 if(env === 'node') { 4413 if(env === 'node') {
4356 /** 4414 /**
4357 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 4415 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4358 * Available via the MIT or new BSD license. 4416 * Available via the MIT or new BSD license.
4359 * see: http://github.com/jrburke/requirejs for details 4417 * see: http://github.com/jrburke/requirejs for details
4360 */ 4418 */
4361 4419
4362 /*jslint strict: false */ 4420 /*jslint strict: false */
4372 4430
4373 } 4431 }
4374 4432
4375 if(env === 'rhino') { 4433 if(env === 'rhino') {
4376 /** 4434 /**
4377 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 4435 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4378 * Available via the MIT or new BSD license. 4436 * Available via the MIT or new BSD license.
4379 * see: http://github.com/jrburke/requirejs for details 4437 * see: http://github.com/jrburke/requirejs for details
4380 */ 4438 */
4381 4439
4382 /*jslint strict: false */ 4440 /*jslint strict: false */
4388 4446
4389 } 4447 }
4390 4448
4391 if(env === 'xpconnect') { 4449 if(env === 'xpconnect') {
4392 /** 4450 /**
4393 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. 4451 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
4394 * Available via the MIT or new BSD license. 4452 * Available via the MIT or new BSD license.
4395 * see: http://github.com/jrburke/requirejs for details 4453 * see: http://github.com/jrburke/requirejs for details
4396 */ 4454 */
4397 4455
4398 /*jslint strict: false */ 4456 /*jslint strict: false */
4402 return print; 4460 return print;
4403 }); 4461 });
4404 4462
4405 } 4463 }
4406 /** 4464 /**
4407 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 4465 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4408 * Available via the MIT or new BSD license. 4466 * Available via the MIT or new BSD license.
4409 * see: http://github.com/jrburke/requirejs for details 4467 * see: http://github.com/jrburke/requirejs for details
4410 */ 4468 */
4411 4469
4412 /*jslint nomen: false, strict: false */ 4470 /*jslint nomen: false, strict: false */
4464 //Just a blank file to use when building the optimizer with the optimizer, 4522 //Just a blank file to use when building the optimizer with the optimizer,
4465 //so that the build does not attempt to inline some env modules, 4523 //so that the build does not attempt to inline some env modules,
4466 //like Node's fs and path. 4524 //like Node's fs and path.
4467 4525
4468 /* 4526 /*
4527 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
4528 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
4529 Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
4469 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> 4530 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
4470 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be> 4531 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
4471 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl> 4532 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
4472 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com> 4533 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
4473 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com> 4534 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
4495 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4556 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4496 */ 4557 */
4497 4558
4498 /*jslint bitwise:true plusplus:true */ 4559 /*jslint bitwise:true plusplus:true */
4499 /*global esprima:true, define:true, exports:true, window: true, 4560 /*global esprima:true, define:true, exports:true, window: true,
4500 throwError: true, createLiteral: true, generateStatement: true, 4561 throwErrorTolerant: true,
4562 throwError: true, generateStatement: true, peek: true,
4501 parseAssignmentExpression: true, parseBlock: true, parseExpression: true, 4563 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
4502 parseFunctionDeclaration: true, parseFunctionExpression: true, 4564 parseFunctionDeclaration: true, parseFunctionExpression: true,
4503 parseFunctionSourceElements: true, parseVariableIdentifier: true, 4565 parseFunctionSourceElements: true, parseVariableIdentifier: true,
4504 parseLeftHandSideExpression: true, 4566 parseLeftHandSideExpression: true,
4567 parseUnaryExpression: true,
4505 parseStatement: true, parseSourceElement: true */ 4568 parseStatement: true, parseSourceElement: true */
4506 4569
4507 (function (root, factory) { 4570 (function (root, factory) {
4508 'use strict'; 4571 'use strict';
4509 4572
4510 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, 4573 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
4511 // Rhino, and plain browser loading. 4574 // Rhino, and plain browser loading.
4575
4576 /* istanbul ignore next */
4512 if (typeof define === 'function' && define.amd) { 4577 if (typeof define === 'function' && define.amd) {
4513 define('esprima', ['exports'], factory); 4578 define('esprima', ['exports'], factory);
4514 } else if (typeof exports !== 'undefined') { 4579 } else if (typeof exports !== 'undefined') {
4515 factory(exports); 4580 factory(exports);
4516 } else { 4581 } else {
4519 }(this, function (exports) { 4584 }(this, function (exports) {
4520 'use strict'; 4585 'use strict';
4521 4586
4522 var Token, 4587 var Token,
4523 TokenName, 4588 TokenName,
4589 FnExprTokens,
4524 Syntax, 4590 Syntax,
4525 PropertyKind, 4591 PropertyKind,
4526 Messages, 4592 Messages,
4527 Regex, 4593 Regex,
4594 SyntaxTreeDelegate,
4528 source, 4595 source,
4529 strict, 4596 strict,
4530 index, 4597 index,
4531 lineNumber, 4598 lineNumber,
4532 lineStart, 4599 lineStart,
4533 length, 4600 length,
4534 buffer, 4601 delegate,
4602 lookahead,
4535 state, 4603 state,
4536 extra; 4604 extra;
4537 4605
4538 Token = { 4606 Token = {
4539 BooleanLiteral: 1, 4607 BooleanLiteral: 1,
4541 Identifier: 3, 4609 Identifier: 3,
4542 Keyword: 4, 4610 Keyword: 4,
4543 NullLiteral: 5, 4611 NullLiteral: 5,
4544 NumericLiteral: 6, 4612 NumericLiteral: 6,
4545 Punctuator: 7, 4613 Punctuator: 7,
4546 StringLiteral: 8 4614 StringLiteral: 8,
4615 RegularExpression: 9
4547 }; 4616 };
4548 4617
4549 TokenName = {}; 4618 TokenName = {};
4550 TokenName[Token.BooleanLiteral] = 'Boolean'; 4619 TokenName[Token.BooleanLiteral] = 'Boolean';
4551 TokenName[Token.EOF] = '<end>'; 4620 TokenName[Token.EOF] = '<end>';
4553 TokenName[Token.Keyword] = 'Keyword'; 4622 TokenName[Token.Keyword] = 'Keyword';
4554 TokenName[Token.NullLiteral] = 'Null'; 4623 TokenName[Token.NullLiteral] = 'Null';
4555 TokenName[Token.NumericLiteral] = 'Numeric'; 4624 TokenName[Token.NumericLiteral] = 'Numeric';
4556 TokenName[Token.Punctuator] = 'Punctuator'; 4625 TokenName[Token.Punctuator] = 'Punctuator';
4557 TokenName[Token.StringLiteral] = 'String'; 4626 TokenName[Token.StringLiteral] = 'String';
4627 TokenName[Token.RegularExpression] = 'RegularExpression';
4628
4629 // A function following one of those tokens is an expression.
4630 FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
4631 'return', 'case', 'delete', 'throw', 'void',
4632 // assignment operators
4633 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
4634 '&=', '|=', '^=', ',',
4635 // binary/unary operators
4636 '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
4637 '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
4638 '<=', '<', '>', '!=', '!=='];
4558 4639
4559 Syntax = { 4640 Syntax = {
4560 AssignmentExpression: 'AssignmentExpression', 4641 AssignmentExpression: 'AssignmentExpression',
4561 ArrayExpression: 'ArrayExpression', 4642 ArrayExpression: 'ArrayExpression',
4562 BlockStatement: 'BlockStatement', 4643 BlockStatement: 'BlockStatement',
4642 StrictReservedWord: 'Use of future reserved word in strict mode' 4723 StrictReservedWord: 'Use of future reserved word in strict mode'
4643 }; 4724 };
4644 4725
4645 // See also tools/generate-unicode-regex.py. 4726 // See also tools/generate-unicode-regex.py.
4646 Regex = { 4727 Regex = {
4647 NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), 4728 NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
4648 NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') 4729 NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
4649 }; 4730 };
4650 4731
4651 // Ensure the condition is true, otherwise throw an error. 4732 // Ensure the condition is true, otherwise throw an error.
4652 // This is only to have a better contract semantic, i.e. another safety net 4733 // This is only to have a better contract semantic, i.e. another safety net
4653 // to catch a logic error. The condition shall be fulfilled in normal case. 4734 // to catch a logic error. The condition shall be fulfilled in normal case.
4654 // Do NOT use this to enforce a certain condition on any user input. 4735 // Do NOT use this to enforce a certain condition on any user input.
4655 4736
4656 function assert(condition, message) { 4737 function assert(condition, message) {
4738 /* istanbul ignore if */
4657 if (!condition) { 4739 if (!condition) {
4658 throw new Error('ASSERT: ' + message); 4740 throw new Error('ASSERT: ' + message);
4659 } 4741 }
4660 } 4742 }
4661 4743
4662 function sliceSource(from, to) {
4663 return source.slice(from, to);
4664 }
4665
4666 if (typeof 'esprima'[0] === 'undefined') {
4667 sliceSource = function sliceArraySource(from, to) {
4668 return source.slice(from, to).join('');
4669 };
4670 }
4671
4672 function isDecimalDigit(ch) { 4744 function isDecimalDigit(ch) {
4673 return '0123456789'.indexOf(ch) >= 0; 4745 return (ch >= 48 && ch <= 57); // 0..9
4674 } 4746 }
4675 4747
4676 function isHexDigit(ch) { 4748 function isHexDigit(ch) {
4677 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; 4749 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
4678 } 4750 }
4683 4755
4684 4756
4685 // 7.2 White Space 4757 // 7.2 White Space
4686 4758
4687 function isWhiteSpace(ch) { 4759 function isWhiteSpace(ch) {
4688 return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || 4760 return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
4689 (ch === '\u000C') || (ch === '\u00A0') || 4761 (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
4690 (ch.charCodeAt(0) >= 0x1680 &&
4691 '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
4692 } 4762 }
4693 4763
4694 // 7.3 Line Terminators 4764 // 7.3 Line Terminators
4695 4765
4696 function isLineTerminator(ch) { 4766 function isLineTerminator(ch) {
4697 return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029'); 4767 return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
4698 } 4768 }
4699 4769
4700 // 7.6 Identifier Names and Identifiers 4770 // 7.6 Identifier Names and Identifiers
4701 4771
4702 function isIdentifierStart(ch) { 4772 function isIdentifierStart(ch) {
4703 return (ch === '$') || (ch === '_') || (ch === '\\') || 4773 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
4704 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 4774 (ch >= 0x41 && ch <= 0x5A) || // A..Z
4705 ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch)); 4775 (ch >= 0x61 && ch <= 0x7A) || // a..z
4776 (ch === 0x5C) || // \ (backslash)
4777 ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
4706 } 4778 }
4707 4779
4708 function isIdentifierPart(ch) { 4780 function isIdentifierPart(ch) {
4709 return (ch === '$') || (ch === '_') || (ch === '\\') || 4781 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
4710 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 4782 (ch >= 0x41 && ch <= 0x5A) || // A..Z
4711 ((ch >= '0') && (ch <= '9')) || 4783 (ch >= 0x61 && ch <= 0x7A) || // a..z
4712 ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch)); 4784 (ch >= 0x30 && ch <= 0x39) || // 0..9
4785 (ch === 0x5C) || // \ (backslash)
4786 ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
4713 } 4787 }
4714 4788
4715 // 7.6.1.2 Future Reserved Words 4789 // 7.6.1.2 Future Reserved Words
4716 4790
4717 function isFutureReservedWord(id) { 4791 function isFutureReservedWord(id) {
4718 switch (id) { 4792 switch (id) {
4719
4720 // Future reserved words.
4721 case 'class': 4793 case 'class':
4722 case 'enum': 4794 case 'enum':
4723 case 'export': 4795 case 'export':
4724 case 'extends': 4796 case 'extends':
4725 case 'import': 4797 case 'import':
4726 case 'super': 4798 case 'super':
4727 return true; 4799 return true;
4728 } 4800 default:
4729 4801 return false;
4730 return false; 4802 }
4731 } 4803 }
4732 4804
4733 function isStrictModeReservedWord(id) { 4805 function isStrictModeReservedWord(id) {
4734 switch (id) { 4806 switch (id) {
4735
4736 // Strict Mode reserved words.
4737 case 'implements': 4807 case 'implements':
4738 case 'interface': 4808 case 'interface':
4739 case 'package': 4809 case 'package':
4740 case 'private': 4810 case 'private':
4741 case 'protected': 4811 case 'protected':
4742 case 'public': 4812 case 'public':
4743 case 'static': 4813 case 'static':
4744 case 'yield': 4814 case 'yield':
4745 case 'let': 4815 case 'let':
4746 return true; 4816 return true;
4747 } 4817 default:
4748 4818 return false;
4749 return false; 4819 }
4750 } 4820 }
4751 4821
4752 function isRestrictedWord(id) { 4822 function isRestrictedWord(id) {
4753 return id === 'eval' || id === 'arguments'; 4823 return id === 'eval' || id === 'arguments';
4754 } 4824 }
4755 4825
4756 // 7.6.1.1 Keywords 4826 // 7.6.1.1 Keywords
4757 4827
4758 function isKeyword(id) { 4828 function isKeyword(id) {
4759 var keyword = false; 4829 if (strict && isStrictModeReservedWord(id)) {
4830 return true;
4831 }
4832
4833 // 'const' is specialized as Keyword in V8.
4834 // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
4835 // Some others are from future reserved words.
4836
4760 switch (id.length) { 4837 switch (id.length) {
4761 case 2: 4838 case 2:
4762 keyword = (id === 'if') || (id === 'in') || (id === 'do'); 4839 return (id === 'if') || (id === 'in') || (id === 'do');
4763 break;
4764 case 3: 4840 case 3:
4765 keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try'); 4841 return (id === 'var') || (id === 'for') || (id === 'new') ||
4766 break; 4842 (id === 'try') || (id === 'let');
4767 case 4: 4843 case 4:
4768 keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with'); 4844 return (id === 'this') || (id === 'else') || (id === 'case') ||
4769 break; 4845 (id === 'void') || (id === 'with') || (id === 'enum');
4770 case 5: 4846 case 5:
4771 keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw'); 4847 return (id === 'while') || (id === 'break') || (id === 'catch') ||
4772 break; 4848 (id === 'throw') || (id === 'const') || (id === 'yield') ||
4849 (id === 'class') || (id === 'super');
4773 case 6: 4850 case 6:
4774 keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch'); 4851 return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
4775 break; 4852 (id === 'switch') || (id === 'export') || (id === 'import');
4776 case 7: 4853 case 7:
4777 keyword = (id === 'default') || (id === 'finally'); 4854 return (id === 'default') || (id === 'finally') || (id === 'extends');
4778 break;
4779 case 8: 4855 case 8:
4780 keyword = (id === 'function') || (id === 'continue') || (id === 'debugger'); 4856 return (id === 'function') || (id === 'continue') || (id === 'debugger');
4781 break;
4782 case 10: 4857 case 10:
4783 keyword = (id === 'instanceof'); 4858 return (id === 'instanceof');
4784 break; 4859 default:
4785 } 4860 return false;
4786 4861 }
4787 if (keyword) {
4788 return true;
4789 }
4790
4791 switch (id) {
4792 // Future reserved words.
4793 // 'const' is specialized as Keyword in V8.
4794 case 'const':
4795 return true;
4796
4797 // For compatiblity to SpiderMonkey and ES.next
4798 case 'yield':
4799 case 'let':
4800 return true;
4801 }
4802
4803 if (strict && isStrictModeReservedWord(id)) {
4804 return true;
4805 }
4806
4807 return isFutureReservedWord(id);
4808 } 4862 }
4809 4863
4810 // 7.4 Comments 4864 // 7.4 Comments
4811 4865
4866 function addComment(type, value, start, end, loc) {
4867 var comment, attacher;
4868
4869 assert(typeof start === 'number', 'Comment must have valid position');
4870
4871 // Because the way the actual token is scanned, often the comments
4872 // (if any) are skipped twice during the lexical analysis.
4873 // Thus, we need to skip adding a comment if the comment array already
4874 // handled it.
4875 if (state.lastCommentStart >= start) {
4876 return;
4877 }
4878 state.lastCommentStart = start;
4879
4880 comment = {
4881 type: type,
4882 value: value
4883 };
4884 if (extra.range) {
4885 comment.range = [start, end];
4886 }
4887 if (extra.loc) {
4888 comment.loc = loc;
4889 }
4890 extra.comments.push(comment);
4891 if (extra.attachComment) {
4892 extra.leadingComments.push(comment);
4893 extra.trailingComments.push(comment);
4894 }
4895 }
4896
4897 function skipSingleLineComment(offset) {
4898 var start, loc, ch, comment;
4899
4900 start = index - offset;
4901 loc = {
4902 start: {
4903 line: lineNumber,
4904 column: index - lineStart - offset
4905 }
4906 };
4907
4908 while (index < length) {
4909 ch = source.charCodeAt(index);
4910 ++index;
4911 if (isLineTerminator(ch)) {
4912 if (extra.comments) {
4913 comment = source.slice(start + offset, index - 1);
4914 loc.end = {
4915 line: lineNumber,
4916 column: index - lineStart - 1
4917 };
4918 addComment('Line', comment, start, index - 1, loc);
4919 }
4920 if (ch === 13 && source.charCodeAt(index) === 10) {
4921 ++index;
4922 }
4923 ++lineNumber;
4924 lineStart = index;
4925 return;
4926 }
4927 }
4928
4929 if (extra.comments) {
4930 comment = source.slice(start + offset, index);
4931 loc.end = {
4932 line: lineNumber,
4933 column: index - lineStart
4934 };
4935 addComment('Line', comment, start, index, loc);
4936 }
4937 }
4938
4939 function skipMultiLineComment() {
4940 var start, loc, ch, comment;
4941
4942 if (extra.comments) {
4943 start = index - 2;
4944 loc = {
4945 start: {
4946 line: lineNumber,
4947 column: index - lineStart - 2
4948 }
4949 };
4950 }
4951
4952 while (index < length) {
4953 ch = source.charCodeAt(index);
4954 if (isLineTerminator(ch)) {
4955 if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
4956 ++index;
4957 }
4958 ++lineNumber;
4959 ++index;
4960 lineStart = index;
4961 if (index >= length) {
4962 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4963 }
4964 } else if (ch === 0x2A) {
4965 // Block comment ends with '*/'.
4966 if (source.charCodeAt(index + 1) === 0x2F) {
4967 ++index;
4968 ++index;
4969 if (extra.comments) {
4970 comment = source.slice(start + 2, index - 2);
4971 loc.end = {
4972 line: lineNumber,
4973 column: index - lineStart
4974 };
4975 addComment('Block', comment, start, index, loc);
4976 }
4977 return;
4978 }
4979 ++index;
4980 } else {
4981 ++index;
4982 }
4983 }
4984
4985 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4986 }
4987
4812 function skipComment() { 4988 function skipComment() {
4813 var ch, blockComment, lineComment; 4989 var ch, start;
4814 4990
4815 blockComment = false; 4991 start = (index === 0);
4816 lineComment = false;
4817
4818 while (index < length) { 4992 while (index < length) {
4819 ch = source[index]; 4993 ch = source.charCodeAt(index);
4820 4994
4821 if (lineComment) { 4995 if (isWhiteSpace(ch)) {
4822 ch = source[index++];
4823 if (isLineTerminator(ch)) {
4824 lineComment = false;
4825 if (ch === '\r' && source[index] === '\n') {
4826 ++index;
4827 }
4828 ++lineNumber;
4829 lineStart = index;
4830 }
4831 } else if (blockComment) {
4832 if (isLineTerminator(ch)) {
4833 if (ch === '\r' && source[index + 1] === '\n') {
4834 ++index;
4835 }
4836 ++lineNumber;
4837 ++index;
4838 lineStart = index;
4839 if (index >= length) {
4840 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4841 }
4842 } else {
4843 ch = source[index++];
4844 if (index >= length) {
4845 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4846 }
4847 if (ch === '*') {
4848 ch = source[index];
4849 if (ch === '/') {
4850 ++index;
4851 blockComment = false;
4852 }
4853 }
4854 }
4855 } else if (ch === '/') {
4856 ch = source[index + 1];
4857 if (ch === '/') {
4858 index += 2;
4859 lineComment = true;
4860 } else if (ch === '*') {
4861 index += 2;
4862 blockComment = true;
4863 if (index >= length) {
4864 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4865 }
4866 } else {
4867 break;
4868 }
4869 } else if (isWhiteSpace(ch)) {
4870 ++index; 4996 ++index;
4871 } else if (isLineTerminator(ch)) { 4997 } else if (isLineTerminator(ch)) {
4872 ++index; 4998 ++index;
4873 if (ch === '\r' && source[index] === '\n') { 4999 if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
4874 ++index; 5000 ++index;
4875 } 5001 }
4876 ++lineNumber; 5002 ++lineNumber;
4877 lineStart = index; 5003 lineStart = index;
5004 start = true;
5005 } else if (ch === 0x2F) { // U+002F is '/'
5006 ch = source.charCodeAt(index + 1);
5007 if (ch === 0x2F) {
5008 ++index;
5009 ++index;
5010 skipSingleLineComment(2);
5011 start = true;
5012 } else if (ch === 0x2A) { // U+002A is '*'
5013 ++index;
5014 ++index;
5015 skipMultiLineComment();
5016 } else {
5017 break;
5018 }
5019 } else if (start && ch === 0x2D) { // U+002D is '-'
5020 // U+003E is '>'
5021 if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
5022 // '-->' is a single-line comment
5023 index += 3;
5024 skipSingleLineComment(3);
5025 } else {
5026 break;
5027 }
5028 } else if (ch === 0x3C) { // U+003C is '<'
5029 if (source.slice(index + 1, index + 4) === '!--') {
5030 ++index; // `<`
5031 ++index; // `!`
5032 ++index; // `-`
5033 ++index; // `-`
5034 skipSingleLineComment(4);
5035 } else {
5036 break;
5037 }
4878 } else { 5038 } else {
4879 break; 5039 break;
4880 } 5040 }
4881 } 5041 }
4882 } 5042 }
4894 } 5054 }
4895 } 5055 }
4896 return String.fromCharCode(code); 5056 return String.fromCharCode(code);
4897 } 5057 }
4898 5058
4899 function scanIdentifier() { 5059 function getEscapedIdentifier() {
4900 var ch, start, id, restore; 5060 var ch, id;
4901 5061
4902 ch = source[index]; 5062 ch = source.charCodeAt(index++);
4903 if (!isIdentifierStart(ch)) { 5063 id = String.fromCharCode(ch);
4904 return; 5064
4905 } 5065 // '\u' (U+005C, U+0075) denotes an escaped character.
4906 5066 if (ch === 0x5C) {
4907 start = index; 5067 if (source.charCodeAt(index) !== 0x75) {
4908 if (ch === '\\') { 5068 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5069 }
4909 ++index; 5070 ++index;
4910 if (source[index] !== 'u') {
4911 return;
4912 }
4913 ++index;
4914 restore = index;
4915 ch = scanHexEscape('u'); 5071 ch = scanHexEscape('u');
4916 if (ch) { 5072 if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
4917 if (ch === '\\' || !isIdentifierStart(ch)) { 5073 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4918 return; 5074 }
4919 } 5075 id = ch;
4920 id = ch;
4921 } else {
4922 index = restore;
4923 id = 'u';
4924 }
4925 } else {
4926 id = source[index++];
4927 } 5076 }
4928 5077
4929 while (index < length) { 5078 while (index < length) {
4930 ch = source[index]; 5079 ch = source.charCodeAt(index);
4931 if (!isIdentifierPart(ch)) { 5080 if (!isIdentifierPart(ch)) {
4932 break; 5081 break;
4933 } 5082 }
4934 if (ch === '\\') { 5083 ++index;
5084 id += String.fromCharCode(ch);
5085
5086 // '\u' (U+005C, U+0075) denotes an escaped character.
5087 if (ch === 0x5C) {
5088 id = id.substr(0, id.length - 1);
5089 if (source.charCodeAt(index) !== 0x75) {
5090 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5091 }
4935 ++index; 5092 ++index;
4936 if (source[index] !== 'u') { 5093 ch = scanHexEscape('u');
4937 return; 5094 if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
4938 } 5095 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5096 }
5097 id += ch;
5098 }
5099 }
5100
5101 return id;
5102 }
5103
5104 function getIdentifier() {
5105 var start, ch;
5106
5107 start = index++;
5108 while (index < length) {
5109 ch = source.charCodeAt(index);
5110 if (ch === 0x5C) {
5111 // Blackslash (U+005C) marks Unicode escape sequence.
5112 index = start;
5113 return getEscapedIdentifier();
5114 }
5115 if (isIdentifierPart(ch)) {
4939 ++index; 5116 ++index;
4940 restore = index;
4941 ch = scanHexEscape('u');
4942 if (ch) {
4943 if (ch === '\\' || !isIdentifierPart(ch)) {
4944 return;
4945 }
4946 id += ch;
4947 } else {
4948 index = restore;
4949 id += 'u';
4950 }
4951 } else { 5117 } else {
4952 id += source[index++]; 5118 break;
4953 } 5119 }
4954 } 5120 }
5121
5122 return source.slice(start, index);
5123 }
5124
5125 function scanIdentifier() {
5126 var start, id, type;
5127
5128 start = index;
5129
5130 // Backslash (U+005C) starts an escaped character.
5131 id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
4955 5132
4956 // There is no keyword or literal with only one character. 5133 // There is no keyword or literal with only one character.
4957 // Thus, it must be an identifier. 5134 // Thus, it must be an identifier.
4958 if (id.length === 1) { 5135 if (id.length === 1) {
4959 return { 5136 type = Token.Identifier;
4960 type: Token.Identifier, 5137 } else if (isKeyword(id)) {
4961 value: id, 5138 type = Token.Keyword;
4962 lineNumber: lineNumber, 5139 } else if (id === 'null') {
4963 lineStart: lineStart, 5140 type = Token.NullLiteral;
4964 range: [start, index] 5141 } else if (id === 'true' || id === 'false') {
4965 }; 5142 type = Token.BooleanLiteral;
4966 } 5143 } else {
4967 5144 type = Token.Identifier;
4968 if (isKeyword(id)) {
4969 return {
4970 type: Token.Keyword,
4971 value: id,
4972 lineNumber: lineNumber,
4973 lineStart: lineStart,
4974 range: [start, index]
4975 };
4976 }
4977
4978 // 7.8.1 Null Literals
4979
4980 if (id === 'null') {
4981 return {
4982 type: Token.NullLiteral,
4983 value: id,
4984 lineNumber: lineNumber,
4985 lineStart: lineStart,
4986 range: [start, index]
4987 };
4988 }
4989
4990 // 7.8.2 Boolean Literals
4991
4992 if (id === 'true' || id === 'false') {
4993 return {
4994 type: Token.BooleanLiteral,
4995 value: id,
4996 lineNumber: lineNumber,
4997 lineStart: lineStart,
4998 range: [start, index]
4999 };
5000 } 5145 }
5001 5146
5002 return { 5147 return {
5003 type: Token.Identifier, 5148 type: type,
5004 value: id, 5149 value: id,
5005 lineNumber: lineNumber, 5150 lineNumber: lineNumber,
5006 lineStart: lineStart, 5151 lineStart: lineStart,
5007 range: [start, index] 5152 start: start,
5153 end: index
5008 }; 5154 };
5009 } 5155 }
5156
5010 5157
5011 // 7.7 Punctuators 5158 // 7.7 Punctuators
5012 5159
5013 function scanPunctuator() { 5160 function scanPunctuator() {
5014 var start = index, 5161 var start = index,
5162 code = source.charCodeAt(index),
5163 code2,
5015 ch1 = source[index], 5164 ch1 = source[index],
5016 ch2, 5165 ch2,
5017 ch3, 5166 ch3,
5018 ch4; 5167 ch4;
5019 5168
5169 switch (code) {
5170
5020 // Check for most common single-character punctuators. 5171 // Check for most common single-character punctuators.
5021 5172 case 0x2E: // . dot
5022 if (ch1 === ';' || ch1 === '{' || ch1 === '}') { 5173 case 0x28: // ( open bracket
5174 case 0x29: // ) close bracket
5175 case 0x3B: // ; semicolon
5176 case 0x2C: // , comma
5177 case 0x7B: // { open curly brace
5178 case 0x7D: // } close curly brace
5179 case 0x5B: // [
5180 case 0x5D: // ]
5181 case 0x3A: // :
5182 case 0x3F: // ?
5183 case 0x7E: // ~
5184 ++index;
5185 if (extra.tokenize) {
5186 if (code === 0x28) {
5187 extra.openParenToken = extra.tokens.length;
5188 } else if (code === 0x7B) {
5189 extra.openCurlyToken = extra.tokens.length;
5190 }
5191 }
5192 return {
5193 type: Token.Punctuator,
5194 value: String.fromCharCode(code),
5195 lineNumber: lineNumber,
5196 lineStart: lineStart,
5197 start: start,
5198 end: index
5199 };
5200
5201 default:
5202 code2 = source.charCodeAt(index + 1);
5203
5204 // '=' (U+003D) marks an assignment or comparison operator.
5205 if (code2 === 0x3D) {
5206 switch (code) {
5207 case 0x2B: // +
5208 case 0x2D: // -
5209 case 0x2F: // /
5210 case 0x3C: // <
5211 case 0x3E: // >
5212 case 0x5E: // ^
5213 case 0x7C: // |
5214 case 0x25: // %
5215 case 0x26: // &
5216 case 0x2A: // *
5217 index += 2;
5218 return {
5219 type: Token.Punctuator,
5220 value: String.fromCharCode(code) + String.fromCharCode(code2),
5221 lineNumber: lineNumber,
5222 lineStart: lineStart,
5223 start: start,
5224 end: index
5225 };
5226
5227 case 0x21: // !
5228 case 0x3D: // =
5229 index += 2;
5230
5231 // !== and ===
5232 if (source.charCodeAt(index) === 0x3D) {
5233 ++index;
5234 }
5235 return {
5236 type: Token.Punctuator,
5237 value: source.slice(start, index),
5238 lineNumber: lineNumber,
5239 lineStart: lineStart,
5240 start: start,
5241 end: index
5242 };
5243 }
5244 }
5245 }
5246
5247 // 4-character punctuator: >>>=
5248
5249 ch4 = source.substr(index, 4);
5250
5251 if (ch4 === '>>>=') {
5252 index += 4;
5253 return {
5254 type: Token.Punctuator,
5255 value: ch4,
5256 lineNumber: lineNumber,
5257 lineStart: lineStart,
5258 start: start,
5259 end: index
5260 };
5261 }
5262
5263 // 3-character punctuators: === !== >>> <<= >>=
5264
5265 ch3 = ch4.substr(0, 3);
5266
5267 if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') {
5268 index += 3;
5269 return {
5270 type: Token.Punctuator,
5271 value: ch3,
5272 lineNumber: lineNumber,
5273 lineStart: lineStart,
5274 start: start,
5275 end: index
5276 };
5277 }
5278
5279 // Other 2-character punctuators: ++ -- << >> && ||
5280 ch2 = ch3.substr(0, 2);
5281
5282 if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') {
5283 index += 2;
5284 return {
5285 type: Token.Punctuator,
5286 value: ch2,
5287 lineNumber: lineNumber,
5288 lineStart: lineStart,
5289 start: start,
5290 end: index
5291 };
5292 }
5293
5294 // 1-character punctuators: < > = ! + - * % & | ^ /
5295 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
5023 ++index; 5296 ++index;
5024 return { 5297 return {
5025 type: Token.Punctuator, 5298 type: Token.Punctuator,
5026 value: ch1, 5299 value: ch1,
5027 lineNumber: lineNumber, 5300 lineNumber: lineNumber,
5028 lineStart: lineStart, 5301 lineStart: lineStart,
5029 range: [start, index] 5302 start: start,
5303 end: index
5030 }; 5304 };
5031 } 5305 }
5032 5306
5033 if (ch1 === ',' || ch1 === '(' || ch1 === ')') { 5307 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5034 ++index;
5035 return {
5036 type: Token.Punctuator,
5037 value: ch1,
5038 lineNumber: lineNumber,
5039 lineStart: lineStart,
5040 range: [start, index]
5041 };
5042 }
5043
5044 // Dot (.) can also start a floating-point number, hence the need
5045 // to check the next character.
5046
5047 ch2 = source[index + 1];
5048 if (ch1 === '.' && !isDecimalDigit(ch2)) {
5049 return {
5050 type: Token.Punctuator,
5051 value: source[index++],
5052 lineNumber: lineNumber,
5053 lineStart: lineStart,
5054 range: [start, index]
5055 };
5056 }
5057
5058 // Peek more characters.
5059
5060 ch3 = source[index + 2];
5061 ch4 = source[index + 3];
5062
5063 // 4-character punctuator: >>>=
5064
5065 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
5066 if (ch4 === '=') {
5067 index += 4;
5068 return {
5069 type: Token.Punctuator,
5070 value: '>>>=',
5071 lineNumber: lineNumber,
5072 lineStart: lineStart,
5073 range: [start, index]
5074 };
5075 }
5076 }
5077
5078 // 3-character punctuators: === !== >>> <<= >>=
5079
5080 if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
5081 index += 3;
5082 return {
5083 type: Token.Punctuator,
5084 value: '===',
5085 lineNumber: lineNumber,
5086 lineStart: lineStart,
5087 range: [start, index]
5088 };
5089 }
5090
5091 if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
5092 index += 3;
5093 return {
5094 type: Token.Punctuator,
5095 value: '!==',
5096 lineNumber: lineNumber,
5097 lineStart: lineStart,
5098 range: [start, index]
5099 };
5100 }
5101
5102 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
5103 index += 3;
5104 return {
5105 type: Token.Punctuator,
5106 value: '>>>',
5107 lineNumber: lineNumber,
5108 lineStart: lineStart,
5109 range: [start, index]
5110 };
5111 }
5112
5113 if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
5114 index += 3;
5115 return {
5116 type: Token.Punctuator,
5117 value: '<<=',
5118 lineNumber: lineNumber,
5119 lineStart: lineStart,
5120 range: [start, index]
5121 };
5122 }
5123
5124 if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
5125 index += 3;
5126 return {
5127 type: Token.Punctuator,
5128 value: '>>=',
5129 lineNumber: lineNumber,
5130 lineStart: lineStart,
5131 range: [start, index]
5132 };
5133 }
5134
5135 // 2-character punctuators: <= >= == != ++ -- << >> && ||
5136 // += -= *= %= &= |= ^= /=
5137
5138 if (ch2 === '=') {
5139 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
5140 index += 2;
5141 return {
5142 type: Token.Punctuator,
5143 value: ch1 + ch2,
5144 lineNumber: lineNumber,
5145 lineStart: lineStart,
5146 range: [start, index]
5147 };
5148 }
5149 }
5150
5151 if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
5152 if ('+-<>&|'.indexOf(ch2) >= 0) {
5153 index += 2;
5154 return {
5155 type: Token.Punctuator,
5156 value: ch1 + ch2,
5157 lineNumber: lineNumber,
5158 lineStart: lineStart,
5159 range: [start, index]
5160 };
5161 }
5162 }
5163
5164 // The remaining 1-character punctuators.
5165
5166 if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
5167 return {
5168 type: Token.Punctuator,
5169 value: source[index++],
5170 lineNumber: lineNumber,
5171 lineStart: lineStart,
5172 range: [start, index]
5173 };
5174 }
5175 } 5308 }
5176 5309
5177 // 7.8.3 Numeric Literals 5310 // 7.8.3 Numeric Literals
5311
5312 function scanHexLiteral(start) {
5313 var number = '';
5314
5315 while (index < length) {
5316 if (!isHexDigit(source[index])) {
5317 break;
5318 }
5319 number += source[index++];
5320 }
5321
5322 if (number.length === 0) {
5323 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5324 }
5325
5326 if (isIdentifierStart(source.charCodeAt(index))) {
5327 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5328 }
5329
5330 return {
5331 type: Token.NumericLiteral,
5332 value: parseInt('0x' + number, 16),
5333 lineNumber: lineNumber,
5334 lineStart: lineStart,
5335 start: start,
5336 end: index
5337 };
5338 }
5339
5340 function scanOctalLiteral(start) {
5341 var number = '0' + source[index++];
5342 while (index < length) {
5343 if (!isOctalDigit(source[index])) {
5344 break;
5345 }
5346 number += source[index++];
5347 }
5348
5349 if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
5350 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5351 }
5352
5353 return {
5354 type: Token.NumericLiteral,
5355 value: parseInt(number, 8),
5356 octal: true,
5357 lineNumber: lineNumber,
5358 lineStart: lineStart,
5359 start: start,
5360 end: index
5361 };
5362 }
5178 5363
5179 function scanNumericLiteral() { 5364 function scanNumericLiteral() {
5180 var number, start, ch; 5365 var number, start, ch;
5181 5366
5182 ch = source[index]; 5367 ch = source[index];
5183 assert(isDecimalDigit(ch) || (ch === '.'), 5368 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
5184 'Numeric literal must start with a decimal digit or a decimal point'); 5369 'Numeric literal must start with a decimal digit or a decimal point');
5185 5370
5186 start = index; 5371 start = index;
5187 number = ''; 5372 number = '';
5188 if (ch !== '.') { 5373 if (ch !== '.') {
5191 5376
5192 // Hex number starts with '0x'. 5377 // Hex number starts with '0x'.
5193 // Octal number starts with '0'. 5378 // Octal number starts with '0'.
5194 if (number === '0') { 5379 if (number === '0') {
5195 if (ch === 'x' || ch === 'X') { 5380 if (ch === 'x' || ch === 'X') {
5196 number += source[index++]; 5381 ++index;
5197 while (index < length) { 5382 return scanHexLiteral(start);
5198 ch = source[index]; 5383 }
5199 if (!isHexDigit(ch)) { 5384 if (isOctalDigit(ch)) {
5200 break; 5385 return scanOctalLiteral(start);
5201 }
5202 number += source[index++];
5203 }
5204
5205 if (number.length <= 2) {
5206 // only 0x
5207 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5208 }
5209
5210 if (index < length) {
5211 ch = source[index];
5212 if (isIdentifierStart(ch)) {
5213 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5214 }
5215 }
5216 return {
5217 type: Token.NumericLiteral,
5218 value: parseInt(number, 16),
5219 lineNumber: lineNumber,
5220 lineStart: lineStart,
5221 range: [start, index]
5222 };
5223 } else if (isOctalDigit(ch)) {
5224 number += source[index++];
5225 while (index < length) {
5226 ch = source[index];
5227 if (!isOctalDigit(ch)) {
5228 break;
5229 }
5230 number += source[index++];
5231 }
5232
5233 if (index < length) {
5234 ch = source[index];
5235 if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
5236 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5237 }
5238 }
5239 return {
5240 type: Token.NumericLiteral,
5241 value: parseInt(number, 8),
5242 octal: true,
5243 lineNumber: lineNumber,
5244 lineStart: lineStart,
5245 range: [start, index]
5246 };
5247 } 5386 }
5248 5387
5249 // decimal number starts with '0' such as '09' is illegal. 5388 // decimal number starts with '0' such as '09' is illegal.
5250 if (isDecimalDigit(ch)) { 5389 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
5251 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); 5390 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5252 } 5391 }
5253 } 5392 }
5254 5393
5255 while (index < length) { 5394 while (isDecimalDigit(source.charCodeAt(index))) {
5256 ch = source[index];
5257 if (!isDecimalDigit(ch)) {
5258 break;
5259 }
5260 number += source[index++]; 5395 number += source[index++];
5261 } 5396 }
5397 ch = source[index];
5262 } 5398 }
5263 5399
5264 if (ch === '.') { 5400 if (ch === '.') {
5265 number += source[index++]; 5401 number += source[index++];
5266 while (index < length) { 5402 while (isDecimalDigit(source.charCodeAt(index))) {
5267 ch = source[index];
5268 if (!isDecimalDigit(ch)) {
5269 break;
5270 }
5271 number += source[index++]; 5403 number += source[index++];
5272 } 5404 }
5405 ch = source[index];
5273 } 5406 }
5274 5407
5275 if (ch === 'e' || ch === 'E') { 5408 if (ch === 'e' || ch === 'E') {
5276 number += source[index++]; 5409 number += source[index++];
5277 5410
5278 ch = source[index]; 5411 ch = source[index];
5279 if (ch === '+' || ch === '-') { 5412 if (ch === '+' || ch === '-') {
5280 number += source[index++]; 5413 number += source[index++];
5281 } 5414 }
5282 5415 if (isDecimalDigit(source.charCodeAt(index))) {
5283 ch = source[index]; 5416 while (isDecimalDigit(source.charCodeAt(index))) {
5284 if (isDecimalDigit(ch)) {
5285 number += source[index++];
5286 while (index < length) {
5287 ch = source[index];
5288 if (!isDecimalDigit(ch)) {
5289 break;
5290 }
5291 number += source[index++]; 5417 number += source[index++];
5292 } 5418 }
5293 } else { 5419 } else {
5294 ch = 'character ' + ch;
5295 if (index >= length) {
5296 ch = '<end>';
5297 }
5298 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); 5420 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5299 } 5421 }
5300 } 5422 }
5301 5423
5302 if (index < length) { 5424 if (isIdentifierStart(source.charCodeAt(index))) {
5303 ch = source[index]; 5425 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5304 if (isIdentifierStart(ch)) {
5305 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5306 }
5307 } 5426 }
5308 5427
5309 return { 5428 return {
5310 type: Token.NumericLiteral, 5429 type: Token.NumericLiteral,
5311 value: parseFloat(number), 5430 value: parseFloat(number),
5312 lineNumber: lineNumber, 5431 lineNumber: lineNumber,
5313 lineStart: lineStart, 5432 lineStart: lineStart,
5314 range: [start, index] 5433 start: start,
5434 end: index
5315 }; 5435 };
5316 } 5436 }
5317 5437
5318 // 7.8.4 String Literals 5438 // 7.8.4 String Literals
5319 5439
5320 function scanStringLiteral() { 5440 function scanStringLiteral() {
5321 var str = '', quote, start, ch, code, unescaped, restore, octal = false; 5441 var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
5442 startLineNumber = lineNumber;
5443 startLineStart = lineStart;
5322 5444
5323 quote = source[index]; 5445 quote = source[index];
5324 assert((quote === '\'' || quote === '"'), 5446 assert((quote === '\'' || quote === '"'),
5325 'String literal must starts with a quote'); 5447 'String literal must starts with a quote');
5326 5448
5333 if (ch === quote) { 5455 if (ch === quote) {
5334 quote = ''; 5456 quote = '';
5335 break; 5457 break;
5336 } else if (ch === '\\') { 5458 } else if (ch === '\\') {
5337 ch = source[index++]; 5459 ch = source[index++];
5338 if (!isLineTerminator(ch)) { 5460 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
5339 switch (ch) { 5461 switch (ch) {
5340 case 'n':
5341 str += '\n';
5342 break;
5343 case 'r':
5344 str += '\r';
5345 break;
5346 case 't':
5347 str += '\t';
5348 break;
5349 case 'u': 5462 case 'u':
5350 case 'x': 5463 case 'x':
5351 restore = index; 5464 restore = index;
5352 unescaped = scanHexEscape(ch); 5465 unescaped = scanHexEscape(ch);
5353 if (unescaped) { 5466 if (unescaped) {
5354 str += unescaped; 5467 str += unescaped;
5355 } else { 5468 } else {
5356 index = restore; 5469 index = restore;
5357 str += ch; 5470 str += ch;
5358 } 5471 }
5472 break;
5473 case 'n':
5474 str += '\n';
5475 break;
5476 case 'r':
5477 str += '\r';
5478 break;
5479 case 't':
5480 str += '\t';
5359 break; 5481 break;
5360 case 'b': 5482 case 'b':
5361 str += '\b'; 5483 str += '\b';
5362 break; 5484 break;
5363 case 'f': 5485 case 'f':
5397 } else { 5519 } else {
5398 ++lineNumber; 5520 ++lineNumber;
5399 if (ch === '\r' && source[index] === '\n') { 5521 if (ch === '\r' && source[index] === '\n') {
5400 ++index; 5522 ++index;
5401 } 5523 }
5402 } 5524 lineStart = index;
5403 } else if (isLineTerminator(ch)) { 5525 }
5526 } else if (isLineTerminator(ch.charCodeAt(0))) {
5404 break; 5527 break;
5405 } else { 5528 } else {
5406 str += ch; 5529 str += ch;
5407 } 5530 }
5408 } 5531 }
5413 5536
5414 return { 5537 return {
5415 type: Token.StringLiteral, 5538 type: Token.StringLiteral,
5416 value: str, 5539 value: str,
5417 octal: octal, 5540 octal: octal,
5541 startLineNumber: startLineNumber,
5542 startLineStart: startLineStart,
5418 lineNumber: lineNumber, 5543 lineNumber: lineNumber,
5419 lineStart: lineStart, 5544 lineStart: lineStart,
5420 range: [start, index] 5545 start: start,
5546 end: index
5421 }; 5547 };
5422 } 5548 }
5423 5549
5424 function scanRegExp() { 5550 function testRegExp(pattern, flags) {
5425 var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; 5551 var value;
5426 5552 try {
5427 buffer = null; 5553 value = new RegExp(pattern, flags);
5428 skipComment(); 5554 } catch (e) {
5429 5555 throwError({}, Messages.InvalidRegExp);
5430 start = index; 5556 }
5557 return value;
5558 }
5559
5560 function scanRegExpBody() {
5561 var ch, str, classMarker, terminated, body;
5562
5431 ch = source[index]; 5563 ch = source[index];
5432 assert(ch === '/', 'Regular expression literal must start with a slash'); 5564 assert(ch === '/', 'Regular expression literal must start with a slash');
5433 str = source[index++]; 5565 str = source[index++];
5434 5566
5567 classMarker = false;
5568 terminated = false;
5435 while (index < length) { 5569 while (index < length) {
5436 ch = source[index++]; 5570 ch = source[index++];
5437 str += ch; 5571 str += ch;
5438 if (ch === '\\') { 5572 if (ch === '\\') {
5439 ch = source[index++]; 5573 ch = source[index++];
5440 // ECMA-262 7.8.5 5574 // ECMA-262 7.8.5
5441 if (isLineTerminator(ch)) { 5575 if (isLineTerminator(ch.charCodeAt(0))) {
5442 throwError({}, Messages.UnterminatedRegExp); 5576 throwError({}, Messages.UnterminatedRegExp);
5443 } 5577 }
5444 str += ch; 5578 str += ch;
5579 } else if (isLineTerminator(ch.charCodeAt(0))) {
5580 throwError({}, Messages.UnterminatedRegExp);
5445 } else if (classMarker) { 5581 } else if (classMarker) {
5446 if (ch === ']') { 5582 if (ch === ']') {
5447 classMarker = false; 5583 classMarker = false;
5448 } 5584 }
5449 } else { 5585 } else {
5450 if (ch === '/') { 5586 if (ch === '/') {
5451 terminated = true; 5587 terminated = true;
5452 break; 5588 break;
5453 } else if (ch === '[') { 5589 } else if (ch === '[') {
5454 classMarker = true; 5590 classMarker = true;
5455 } else if (isLineTerminator(ch)) {
5456 throwError({}, Messages.UnterminatedRegExp);
5457 } 5591 }
5458 } 5592 }
5459 } 5593 }
5460 5594
5461 if (!terminated) { 5595 if (!terminated) {
5462 throwError({}, Messages.UnterminatedRegExp); 5596 throwError({}, Messages.UnterminatedRegExp);
5463 } 5597 }
5464 5598
5465 // Exclude leading and trailing slash. 5599 // Exclude leading and trailing slash.
5466 pattern = str.substr(1, str.length - 2); 5600 body = str.substr(1, str.length - 2);
5467 5601 return {
5602 value: body,
5603 literal: str
5604 };
5605 }
5606
5607 function scanRegExpFlags() {
5608 var ch, str, flags, restore;
5609
5610 str = '';
5468 flags = ''; 5611 flags = '';
5469 while (index < length) { 5612 while (index < length) {
5470 ch = source[index]; 5613 ch = source[index];
5471 if (!isIdentifierPart(ch)) { 5614 if (!isIdentifierPart(ch.charCodeAt(0))) {
5472 break; 5615 break;
5473 } 5616 }
5474 5617
5475 ++index; 5618 ++index;
5476 if (ch === '\\' && index < length) { 5619 if (ch === '\\' && index < length) {
5479 ++index; 5622 ++index;
5480 restore = index; 5623 restore = index;
5481 ch = scanHexEscape('u'); 5624 ch = scanHexEscape('u');
5482 if (ch) { 5625 if (ch) {
5483 flags += ch; 5626 flags += ch;
5484 str += '\\u'; 5627 for (str += '\\u'; restore < index; ++restore) {
5485 for (; restore < index; ++restore) {
5486 str += source[restore]; 5628 str += source[restore];
5487 } 5629 }
5488 } else { 5630 } else {
5489 index = restore; 5631 index = restore;
5490 flags += 'u'; 5632 flags += 'u';
5491 str += '\\u'; 5633 str += '\\u';
5492 } 5634 }
5635 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
5493 } else { 5636 } else {
5494 str += '\\'; 5637 str += '\\';
5638 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
5495 } 5639 }
5496 } else { 5640 } else {
5497 flags += ch; 5641 flags += ch;
5498 str += ch; 5642 str += ch;
5499 } 5643 }
5500 } 5644 }
5501 5645
5502 try {
5503 value = new RegExp(pattern, flags);
5504 } catch (e) {
5505 throwError({}, Messages.InvalidRegExp);
5506 }
5507
5508 return { 5646 return {
5509 literal: str, 5647 value: flags,
5648 literal: str
5649 };
5650 }
5651
5652 function scanRegExp() {
5653 var start, body, flags, pattern, value;
5654
5655 lookahead = null;
5656 skipComment();
5657 start = index;
5658
5659 body = scanRegExpBody();
5660 flags = scanRegExpFlags();
5661 value = testRegExp(body.value, flags.value);
5662
5663 if (extra.tokenize) {
5664 return {
5665 type: Token.RegularExpression,
5666 value: value,
5667 lineNumber: lineNumber,
5668 lineStart: lineStart,
5669 start: start,
5670 end: index
5671 };
5672 }
5673
5674 return {
5675 literal: body.literal + flags.literal,
5510 value: value, 5676 value: value,
5511 range: [start, index] 5677 start: start,
5678 end: index
5512 }; 5679 };
5680 }
5681
5682 function collectRegex() {
5683 var pos, loc, regex, token;
5684
5685 skipComment();
5686
5687 pos = index;
5688 loc = {
5689 start: {
5690 line: lineNumber,
5691 column: index - lineStart
5692 }
5693 };
5694
5695 regex = scanRegExp();
5696 loc.end = {
5697 line: lineNumber,
5698 column: index - lineStart
5699 };
5700
5701 /* istanbul ignore next */
5702 if (!extra.tokenize) {
5703 // Pop the previous token, which is likely '/' or '/='
5704 if (extra.tokens.length > 0) {
5705 token = extra.tokens[extra.tokens.length - 1];
5706 if (token.range[0] === pos && token.type === 'Punctuator') {
5707 if (token.value === '/' || token.value === '/=') {
5708 extra.tokens.pop();
5709 }
5710 }
5711 }
5712
5713 extra.tokens.push({
5714 type: 'RegularExpression',
5715 value: regex.literal,
5716 range: [pos, index],
5717 loc: loc
5718 });
5719 }
5720
5721 return regex;
5513 } 5722 }
5514 5723
5515 function isIdentifierName(token) { 5724 function isIdentifierName(token) {
5516 return token.type === Token.Identifier || 5725 return token.type === Token.Identifier ||
5517 token.type === Token.Keyword || 5726 token.type === Token.Keyword ||
5518 token.type === Token.BooleanLiteral || 5727 token.type === Token.BooleanLiteral ||
5519 token.type === Token.NullLiteral; 5728 token.type === Token.NullLiteral;
5520 } 5729 }
5521 5730
5731 function advanceSlash() {
5732 var prevToken,
5733 checkToken;
5734 // Using the following algorithm:
5735 // https://github.com/mozilla/sweet.js/wiki/design
5736 prevToken = extra.tokens[extra.tokens.length - 1];
5737 if (!prevToken) {
5738 // Nothing before that: it cannot be a division.
5739 return collectRegex();
5740 }
5741 if (prevToken.type === 'Punctuator') {
5742 if (prevToken.value === ']') {
5743 return scanPunctuator();
5744 }
5745 if (prevToken.value === ')') {
5746 checkToken = extra.tokens[extra.openParenToken - 1];
5747 if (checkToken &&
5748 checkToken.type === 'Keyword' &&
5749 (checkToken.value === 'if' ||
5750 checkToken.value === 'while' ||
5751 checkToken.value === 'for' ||
5752 checkToken.value === 'with')) {
5753 return collectRegex();
5754 }
5755 return scanPunctuator();
5756 }
5757 if (prevToken.value === '}') {
5758 // Dividing a function by anything makes little sense,
5759 // but we have to check for that.
5760 if (extra.tokens[extra.openCurlyToken - 3] &&
5761 extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
5762 // Anonymous function.
5763 checkToken = extra.tokens[extra.openCurlyToken - 4];
5764 if (!checkToken) {
5765 return scanPunctuator();
5766 }
5767 } else if (extra.tokens[extra.openCurlyToken - 4] &&
5768 extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
5769 // Named function.
5770 checkToken = extra.tokens[extra.openCurlyToken - 5];
5771 if (!checkToken) {
5772 return collectRegex();
5773 }
5774 } else {
5775 return scanPunctuator();
5776 }
5777 // checkToken determines whether the function is
5778 // a declaration or an expression.
5779 if (FnExprTokens.indexOf(checkToken.value) >= 0) {
5780 // It is an expression.
5781 return scanPunctuator();
5782 }
5783 // It is a declaration.
5784 return collectRegex();
5785 }
5786 return collectRegex();
5787 }
5788 if (prevToken.type === 'Keyword') {
5789 return collectRegex();
5790 }
5791 return scanPunctuator();
5792 }
5793
5522 function advance() { 5794 function advance() {
5523 var ch, token; 5795 var ch;
5524 5796
5525 skipComment(); 5797 skipComment();
5526 5798
5527 if (index >= length) { 5799 if (index >= length) {
5528 return { 5800 return {
5529 type: Token.EOF, 5801 type: Token.EOF,
5530 lineNumber: lineNumber, 5802 lineNumber: lineNumber,
5531 lineStart: lineStart, 5803 lineStart: lineStart,
5532 range: [index, index] 5804 start: index,
5805 end: index
5533 }; 5806 };
5534 } 5807 }
5535 5808
5536 token = scanPunctuator(); 5809 ch = source.charCodeAt(index);
5537 if (typeof token !== 'undefined') { 5810
5538 return token; 5811 if (isIdentifierStart(ch)) {
5539 } 5812 return scanIdentifier();
5540 5813 }
5541 ch = source[index]; 5814
5542 5815 // Very common: ( and ) and ;
5543 if (ch === '\'' || ch === '"') { 5816 if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
5817 return scanPunctuator();
5818 }
5819
5820 // String literal starts with single quote (U+0027) or double quote (U+0022).
5821 if (ch === 0x27 || ch === 0x22) {
5544 return scanStringLiteral(); 5822 return scanStringLiteral();
5545 } 5823 }
5546 5824
5547 if (ch === '.' || isDecimalDigit(ch)) { 5825
5826 // Dot (.) U+002E can also start a floating-point number, hence the need
5827 // to check the next character.
5828 if (ch === 0x2E) {
5829 if (isDecimalDigit(source.charCodeAt(index + 1))) {
5830 return scanNumericLiteral();
5831 }
5832 return scanPunctuator();
5833 }
5834
5835 if (isDecimalDigit(ch)) {
5548 return scanNumericLiteral(); 5836 return scanNumericLiteral();
5549 } 5837 }
5550 5838
5551 token = scanIdentifier(); 5839 // Slash (/) U+002F can also start a regex.
5552 if (typeof token !== 'undefined') { 5840 if (extra.tokenize && ch === 0x2F) {
5553 return token; 5841 return advanceSlash();
5554 } 5842 }
5555 5843
5556 throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); 5844 return scanPunctuator();
5845 }
5846
5847 function collectToken() {
5848 var loc, token, range, value;
5849
5850 skipComment();
5851 loc = {
5852 start: {
5853 line: lineNumber,
5854 column: index - lineStart
5855 }
5856 };
5857
5858 token = advance();
5859 loc.end = {
5860 line: lineNumber,
5861 column: index - lineStart
5862 };
5863
5864 if (token.type !== Token.EOF) {
5865 value = source.slice(token.start, token.end);
5866 extra.tokens.push({
5867 type: TokenName[token.type],
5868 value: value,
5869 range: [token.start, token.end],
5870 loc: loc
5871 });
5872 }
5873
5874 return token;
5557 } 5875 }
5558 5876
5559 function lex() { 5877 function lex() {
5560 var token; 5878 var token;
5561 5879
5562 if (buffer) { 5880 token = lookahead;
5563 index = buffer.range[1]; 5881 index = token.end;
5564 lineNumber = buffer.lineNumber; 5882 lineNumber = token.lineNumber;
5565 lineStart = buffer.lineStart; 5883 lineStart = token.lineStart;
5566 token = buffer; 5884
5567 buffer = null; 5885 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
5568 return token; 5886
5569 } 5887 index = token.end;
5570 5888 lineNumber = token.lineNumber;
5571 buffer = null; 5889 lineStart = token.lineStart;
5572 return advance(); 5890
5573 } 5891 return token;
5574 5892 }
5575 function lookahead() { 5893
5894 function peek() {
5576 var pos, line, start; 5895 var pos, line, start;
5577
5578 if (buffer !== null) {
5579 return buffer;
5580 }
5581 5896
5582 pos = index; 5897 pos = index;
5583 line = lineNumber; 5898 line = lineNumber;
5584 start = lineStart; 5899 start = lineStart;
5585 buffer = advance(); 5900 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
5586 index = pos; 5901 index = pos;
5587 lineNumber = line; 5902 lineNumber = line;
5588 lineStart = start; 5903 lineStart = start;
5589 5904 }
5590 return buffer; 5905
5591 } 5906 function Position(line, column) {
5907 this.line = line;
5908 this.column = column;
5909 }
5910
5911 function SourceLocation(startLine, startColumn, line, column) {
5912 this.start = new Position(startLine, startColumn);
5913 this.end = new Position(line, column);
5914 }
5915
5916 SyntaxTreeDelegate = {
5917
5918 name: 'SyntaxTree',
5919
5920 processComment: function (node) {
5921 var lastChild, trailingComments;
5922
5923 if (node.type === Syntax.Program) {
5924 if (node.body.length > 0) {
5925 return;
5926 }
5927 }
5928
5929 if (extra.trailingComments.length > 0) {
5930 if (extra.trailingComments[0].range[0] >= node.range[1]) {
5931 trailingComments = extra.trailingComments;
5932 extra.trailingComments = [];
5933 } else {
5934 extra.trailingComments.length = 0;
5935 }
5936 } else {
5937 if (extra.bottomRightStack.length > 0 &&
5938 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments &&
5939 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) {
5940 trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
5941 delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
5942 }
5943 }
5944
5945 // Eating the stack.
5946 while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) {
5947 lastChild = extra.bottomRightStack.pop();
5948 }
5949
5950 if (lastChild) {
5951 if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
5952 node.leadingComments = lastChild.leadingComments;
5953 delete lastChild.leadingComments;
5954 }
5955 } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
5956 node.leadingComments = extra.leadingComments;
5957 extra.leadingComments = [];
5958 }
5959
5960
5961 if (trailingComments) {
5962 node.trailingComments = trailingComments;
5963 }
5964
5965 extra.bottomRightStack.push(node);
5966 },
5967
5968 markEnd: function (node, startToken) {
5969 if (extra.range) {
5970 node.range = [startToken.start, index];
5971 }
5972 if (extra.loc) {
5973 node.loc = new SourceLocation(
5974 startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber,
5975 startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart),
5976 lineNumber,
5977 index - lineStart
5978 );
5979 this.postProcess(node);
5980 }
5981
5982 if (extra.attachComment) {
5983 this.processComment(node);
5984 }
5985 return node;
5986 },
5987
5988 postProcess: function (node) {
5989 if (extra.source) {
5990 node.loc.source = extra.source;
5991 }
5992 return node;
5993 },
5994
5995 createArrayExpression: function (elements) {
5996 return {
5997 type: Syntax.ArrayExpression,
5998 elements: elements
5999 };
6000 },
6001
6002 createAssignmentExpression: function (operator, left, right) {
6003 return {
6004 type: Syntax.AssignmentExpression,
6005 operator: operator,
6006 left: left,
6007 right: right
6008 };
6009 },
6010
6011 createBinaryExpression: function (operator, left, right) {
6012 var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
6013 Syntax.BinaryExpression;
6014 return {
6015 type: type,
6016 operator: operator,
6017 left: left,
6018 right: right
6019 };
6020 },
6021
6022 createBlockStatement: function (body) {
6023 return {
6024 type: Syntax.BlockStatement,
6025 body: body
6026 };
6027 },
6028
6029 createBreakStatement: function (label) {
6030 return {
6031 type: Syntax.BreakStatement,
6032 label: label
6033 };
6034 },
6035
6036 createCallExpression: function (callee, args) {
6037 return {
6038 type: Syntax.CallExpression,
6039 callee: callee,
6040 'arguments': args
6041 };
6042 },
6043
6044 createCatchClause: function (param, body) {
6045 return {
6046 type: Syntax.CatchClause,
6047 param: param,
6048 body: body
6049 };
6050 },
6051
6052 createConditionalExpression: function (test, consequent, alternate) {
6053 return {
6054 type: Syntax.ConditionalExpression,
6055 test: test,
6056 consequent: consequent,
6057 alternate: alternate
6058 };
6059 },
6060
6061 createContinueStatement: function (label) {
6062 return {
6063 type: Syntax.ContinueStatement,
6064 label: label
6065 };
6066 },
6067
6068 createDebuggerStatement: function () {
6069 return {
6070 type: Syntax.DebuggerStatement
6071 };
6072 },
6073
6074 createDoWhileStatement: function (body, test) {
6075 return {
6076 type: Syntax.DoWhileStatement,
6077 body: body,
6078 test: test
6079 };
6080 },
6081
6082 createEmptyStatement: function () {
6083 return {
6084 type: Syntax.EmptyStatement
6085 };
6086 },
6087
6088 createExpressionStatement: function (expression) {
6089 return {
6090 type: Syntax.ExpressionStatement,
6091 expression: expression
6092 };
6093 },
6094
6095 createForStatement: function (init, test, update, body) {
6096 return {
6097 type: Syntax.ForStatement,
6098 init: init,
6099 test: test,
6100 update: update,
6101 body: body
6102 };
6103 },
6104
6105 createForInStatement: function (left, right, body) {
6106 return {
6107 type: Syntax.ForInStatement,
6108 left: left,
6109 right: right,
6110 body: body,
6111 each: false
6112 };
6113 },
6114
6115 createFunctionDeclaration: function (id, params, defaults, body) {
6116 return {
6117 type: Syntax.FunctionDeclaration,
6118 id: id,
6119 params: params,
6120 defaults: defaults,
6121 body: body,
6122 rest: null,
6123 generator: false,
6124 expression: false
6125 };
6126 },
6127
6128 createFunctionExpression: function (id, params, defaults, body) {
6129 return {
6130 type: Syntax.FunctionExpression,
6131 id: id,
6132 params: params,
6133 defaults: defaults,
6134 body: body,
6135 rest: null,
6136 generator: false,
6137 expression: false
6138 };
6139 },
6140
6141 createIdentifier: function (name) {
6142 return {
6143 type: Syntax.Identifier,
6144 name: name
6145 };
6146 },
6147
6148 createIfStatement: function (test, consequent, alternate) {
6149 return {
6150 type: Syntax.IfStatement,
6151 test: test,
6152 consequent: consequent,
6153 alternate: alternate
6154 };
6155 },
6156
6157 createLabeledStatement: function (label, body) {
6158 return {
6159 type: Syntax.LabeledStatement,
6160 label: label,
6161 body: body
6162 };
6163 },
6164
6165 createLiteral: function (token) {
6166 return {
6167 type: Syntax.Literal,
6168 value: token.value,
6169 raw: source.slice(token.start, token.end)
6170 };
6171 },
6172
6173 createMemberExpression: function (accessor, object, property) {
6174 return {
6175 type: Syntax.MemberExpression,
6176 computed: accessor === '[',
6177 object: object,
6178 property: property
6179 };
6180 },
6181
6182 createNewExpression: function (callee, args) {
6183 return {
6184 type: Syntax.NewExpression,
6185 callee: callee,
6186 'arguments': args
6187 };
6188 },
6189
6190 createObjectExpression: function (properties) {
6191 return {
6192 type: Syntax.ObjectExpression,
6193 properties: properties
6194 };
6195 },
6196
6197 createPostfixExpression: function (operator, argument) {
6198 return {
6199 type: Syntax.UpdateExpression,
6200 operator: operator,
6201 argument: argument,
6202 prefix: false
6203 };
6204 },
6205
6206 createProgram: function (body) {
6207 return {
6208 type: Syntax.Program,
6209 body: body
6210 };
6211 },
6212
6213 createProperty: function (kind, key, value) {
6214 return {
6215 type: Syntax.Property,
6216 key: key,
6217 value: value,
6218 kind: kind
6219 };
6220 },
6221
6222 createReturnStatement: function (argument) {
6223 return {
6224 type: Syntax.ReturnStatement,
6225 argument: argument
6226 };
6227 },
6228
6229 createSequenceExpression: function (expressions) {
6230 return {
6231 type: Syntax.SequenceExpression,
6232 expressions: expressions
6233 };
6234 },
6235
6236 createSwitchCase: function (test, consequent) {
6237 return {
6238 type: Syntax.SwitchCase,
6239 test: test,
6240 consequent: consequent
6241 };
6242 },
6243
6244 createSwitchStatement: function (discriminant, cases) {
6245 return {
6246 type: Syntax.SwitchStatement,
6247 discriminant: discriminant,
6248 cases: cases
6249 };
6250 },
6251
6252 createThisExpression: function () {
6253 return {
6254 type: Syntax.ThisExpression
6255 };
6256 },
6257
6258 createThrowStatement: function (argument) {
6259 return {
6260 type: Syntax.ThrowStatement,
6261 argument: argument
6262 };
6263 },
6264
6265 createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
6266 return {
6267 type: Syntax.TryStatement,
6268 block: block,
6269 guardedHandlers: guardedHandlers,
6270 handlers: handlers,
6271 finalizer: finalizer
6272 };
6273 },
6274
6275 createUnaryExpression: function (operator, argument) {
6276 if (operator === '++' || operator === '--') {
6277 return {
6278 type: Syntax.UpdateExpression,
6279 operator: operator,
6280 argument: argument,
6281 prefix: true
6282 };
6283 }
6284 return {
6285 type: Syntax.UnaryExpression,
6286 operator: operator,
6287 argument: argument,
6288 prefix: true
6289 };
6290 },
6291
6292 createVariableDeclaration: function (declarations, kind) {
6293 return {
6294 type: Syntax.VariableDeclaration,
6295 declarations: declarations,
6296 kind: kind
6297 };
6298 },
6299
6300 createVariableDeclarator: function (id, init) {
6301 return {
6302 type: Syntax.VariableDeclarator,
6303 id: id,
6304 init: init
6305 };
6306 },
6307
6308 createWhileStatement: function (test, body) {
6309 return {
6310 type: Syntax.WhileStatement,
6311 test: test,
6312 body: body
6313 };
6314 },
6315
6316 createWithStatement: function (object, body) {
6317 return {
6318 type: Syntax.WithStatement,
6319 object: object,
6320 body: body
6321 };
6322 }
6323 };
5592 6324
5593 // Return true if there is a line terminator before the next token. 6325 // Return true if there is a line terminator before the next token.
5594 6326
5595 function peekLineTerminator() { 6327 function peekLineTerminator() {
5596 var pos, line, start, found; 6328 var pos, line, start, found;
5613 var error, 6345 var error,
5614 args = Array.prototype.slice.call(arguments, 2), 6346 args = Array.prototype.slice.call(arguments, 2),
5615 msg = messageFormat.replace( 6347 msg = messageFormat.replace(
5616 /%(\d)/g, 6348 /%(\d)/g,
5617 function (whole, index) { 6349 function (whole, index) {
5618 return args[index] || ''; 6350 assert(index < args.length, 'Message reference must be in range');
6351 return args[index];
5619 } 6352 }
5620 ); 6353 );
5621 6354
5622 if (typeof token.lineNumber === 'number') { 6355 if (typeof token.lineNumber === 'number') {
5623 error = new Error('Line ' + token.lineNumber + ': ' + msg); 6356 error = new Error('Line ' + token.lineNumber + ': ' + msg);
5624 error.index = token.range[0]; 6357 error.index = token.start;
5625 error.lineNumber = token.lineNumber; 6358 error.lineNumber = token.lineNumber;
5626 error.column = token.range[0] - lineStart + 1; 6359 error.column = token.start - lineStart + 1;
5627 } else { 6360 } else {
5628 error = new Error('Line ' + lineNumber + ': ' + msg); 6361 error = new Error('Line ' + lineNumber + ': ' + msg);
5629 error.index = index; 6362 error.index = index;
5630 error.lineNumber = lineNumber; 6363 error.lineNumber = lineNumber;
5631 error.column = index - lineStart + 1; 6364 error.column = index - lineStart + 1;
5632 } 6365 }
5633 6366
6367 error.description = msg;
5634 throw error; 6368 throw error;
5635 } 6369 }
5636 6370
5637 function throwErrorTolerant() { 6371 function throwErrorTolerant() {
5638 try { 6372 try {
5701 } 6435 }
5702 6436
5703 // Return true if the next token matches the specified punctuator. 6437 // Return true if the next token matches the specified punctuator.
5704 6438
5705 function match(value) { 6439 function match(value) {
5706 var token = lookahead(); 6440 return lookahead.type === Token.Punctuator && lookahead.value === value;
5707 return token.type === Token.Punctuator && token.value === value;
5708 } 6441 }
5709 6442
5710 // Return true if the next token matches the specified keyword 6443 // Return true if the next token matches the specified keyword
5711 6444
5712 function matchKeyword(keyword) { 6445 function matchKeyword(keyword) {
5713 var token = lookahead(); 6446 return lookahead.type === Token.Keyword && lookahead.value === keyword;
5714 return token.type === Token.Keyword && token.value === keyword;
5715 } 6447 }
5716 6448
5717 // Return true if the next token is an assignment operator 6449 // Return true if the next token is an assignment operator
5718 6450
5719 function matchAssign() { 6451 function matchAssign() {
5720 var token = lookahead(), 6452 var op;
5721 op = token.value; 6453
5722 6454 if (lookahead.type !== Token.Punctuator) {
5723 if (token.type !== Token.Punctuator) {
5724 return false; 6455 return false;
5725 } 6456 }
6457 op = lookahead.value;
5726 return op === '=' || 6458 return op === '=' ||
5727 op === '*=' || 6459 op === '*=' ||
5728 op === '/=' || 6460 op === '/=' ||
5729 op === '%=' || 6461 op === '%=' ||
5730 op === '+=' || 6462 op === '+=' ||
5736 op === '^=' || 6468 op === '^=' ||
5737 op === '|='; 6469 op === '|=';
5738 } 6470 }
5739 6471
5740 function consumeSemicolon() { 6472 function consumeSemicolon() {
5741 var token, line; 6473 var line;
5742 6474
5743 // Catch the very common case first. 6475 // Catch the very common case first: immediately a semicolon (U+003B).
5744 if (source[index] === ';') { 6476 if (source.charCodeAt(index) === 0x3B || match(';')) {
5745 lex(); 6477 lex();
5746 return; 6478 return;
5747 } 6479 }
5748 6480
5749 line = lineNumber; 6481 line = lineNumber;
5750 skipComment(); 6482 skipComment();
5751 if (lineNumber !== line) { 6483 if (lineNumber !== line) {
5752 return; 6484 return;
5753 } 6485 }
5754 6486
5755 if (match(';')) { 6487 if (lookahead.type !== Token.EOF && !match('}')) {
5756 lex(); 6488 throwUnexpected(lookahead);
5757 return;
5758 }
5759
5760 token = lookahead();
5761 if (token.type !== Token.EOF && !match('}')) {
5762 throwUnexpected(token);
5763 } 6489 }
5764 } 6490 }
5765 6491
5766 // Return true if provided expression is LeftHandSideExpression 6492 // Return true if provided expression is LeftHandSideExpression
5767 6493
5770 } 6496 }
5771 6497
5772 // 11.1.4 Array Initialiser 6498 // 11.1.4 Array Initialiser
5773 6499
5774 function parseArrayInitialiser() { 6500 function parseArrayInitialiser() {
5775 var elements = []; 6501 var elements = [], startToken;
5776 6502
6503 startToken = lookahead;
5777 expect('['); 6504 expect('[');
5778 6505
5779 while (!match(']')) { 6506 while (!match(']')) {
5780 if (match(',')) { 6507 if (match(',')) {
5781 lex(); 6508 lex();
5787 expect(','); 6514 expect(',');
5788 } 6515 }
5789 } 6516 }
5790 } 6517 }
5791 6518
5792 expect(']'); 6519 lex();
5793 6520
5794 return { 6521 return delegate.markEnd(delegate.createArrayExpression(elements), startToken);
5795 type: Syntax.ArrayExpression,
5796 elements: elements
5797 };
5798 } 6522 }
5799 6523
5800 // 11.1.5 Object Initialiser 6524 // 11.1.5 Object Initialiser
5801 6525
5802 function parsePropertyFunction(param, first) { 6526 function parsePropertyFunction(param, first) {
5803 var previousStrict, body; 6527 var previousStrict, body, startToken;
5804 6528
5805 previousStrict = strict; 6529 previousStrict = strict;
6530 startToken = lookahead;
5806 body = parseFunctionSourceElements(); 6531 body = parseFunctionSourceElements();
5807 if (first && strict && isRestrictedWord(param[0].name)) { 6532 if (first && strict && isRestrictedWord(param[0].name)) {
5808 throwErrorTolerant(first, Messages.StrictParamName); 6533 throwErrorTolerant(first, Messages.StrictParamName);
5809 } 6534 }
5810 strict = previousStrict; 6535 strict = previousStrict;
5811 6536 return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken);
5812 return {
5813 type: Syntax.FunctionExpression,
5814 id: null,
5815 params: param,
5816 defaults: [],
5817 body: body,
5818 rest: null,
5819 generator: false,
5820 expression: false
5821 };
5822 } 6537 }
5823 6538
5824 function parseObjectPropertyKey() { 6539 function parseObjectPropertyKey() {
5825 var token = lex(); 6540 var token, startToken;
6541
6542 startToken = lookahead;
6543 token = lex();
5826 6544
5827 // Note: This function is called only from parseObjectProperty(), where 6545 // Note: This function is called only from parseObjectProperty(), where
5828 // EOF and Punctuator tokens are already filtered out. 6546 // EOF and Punctuator tokens are already filtered out.
5829 6547
5830 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { 6548 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
5831 if (strict && token.octal) { 6549 if (strict && token.octal) {
5832 throwErrorTolerant(token, Messages.StrictOctalLiteral); 6550 throwErrorTolerant(token, Messages.StrictOctalLiteral);
5833 } 6551 }
5834 return createLiteral(token); 6552 return delegate.markEnd(delegate.createLiteral(token), startToken);
5835 } 6553 }
5836 6554
5837 return { 6555 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
5838 type: Syntax.Identifier,
5839 name: token.value
5840 };
5841 } 6556 }
5842 6557
5843 function parseObjectProperty() { 6558 function parseObjectProperty() {
5844 var token, key, id, param; 6559 var token, key, id, value, param, startToken;
5845 6560
5846 token = lookahead(); 6561 token = lookahead;
6562 startToken = lookahead;
5847 6563
5848 if (token.type === Token.Identifier) { 6564 if (token.type === Token.Identifier) {
5849 6565
5850 id = parseObjectPropertyKey(); 6566 id = parseObjectPropertyKey();
5851 6567
5853 6569
5854 if (token.value === 'get' && !match(':')) { 6570 if (token.value === 'get' && !match(':')) {
5855 key = parseObjectPropertyKey(); 6571 key = parseObjectPropertyKey();
5856 expect('('); 6572 expect('(');
5857 expect(')'); 6573 expect(')');
5858 return { 6574 value = parsePropertyFunction([]);
5859 type: Syntax.Property, 6575 return delegate.markEnd(delegate.createProperty('get', key, value), startToken);
5860 key: key, 6576 }
5861 value: parsePropertyFunction([]), 6577 if (token.value === 'set' && !match(':')) {
5862 kind: 'get'
5863 };
5864 } else if (token.value === 'set' && !match(':')) {
5865 key = parseObjectPropertyKey(); 6578 key = parseObjectPropertyKey();
5866 expect('('); 6579 expect('(');
5867 token = lookahead(); 6580 token = lookahead;
5868 if (token.type !== Token.Identifier) { 6581 if (token.type !== Token.Identifier) {
5869 expect(')'); 6582 expect(')');
5870 throwErrorTolerant(token, Messages.UnexpectedToken, token.value); 6583 throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
5871 return { 6584 value = parsePropertyFunction([]);
5872 type: Syntax.Property,
5873 key: key,
5874 value: parsePropertyFunction([]),
5875 kind: 'set'
5876 };
5877 } else { 6585 } else {
5878 param = [ parseVariableIdentifier() ]; 6586 param = [ parseVariableIdentifier() ];
5879 expect(')'); 6587 expect(')');
5880 return { 6588 value = parsePropertyFunction(param, token);
5881 type: Syntax.Property, 6589 }
5882 key: key, 6590 return delegate.markEnd(delegate.createProperty('set', key, value), startToken);
5883 value: parsePropertyFunction(param, token), 6591 }
5884 kind: 'set' 6592 expect(':');
5885 }; 6593 value = parseAssignmentExpression();
5886 } 6594 return delegate.markEnd(delegate.createProperty('init', id, value), startToken);
5887 } else { 6595 }
5888 expect(':'); 6596 if (token.type === Token.EOF || token.type === Token.Punctuator) {
5889 return {
5890 type: Syntax.Property,
5891 key: id,
5892 value: parseAssignmentExpression(),
5893 kind: 'init'
5894 };
5895 }
5896 } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
5897 throwUnexpected(token); 6597 throwUnexpected(token);
5898 } else { 6598 } else {
5899 key = parseObjectPropertyKey(); 6599 key = parseObjectPropertyKey();
5900 expect(':'); 6600 expect(':');
5901 return { 6601 value = parseAssignmentExpression();
5902 type: Syntax.Property, 6602 return delegate.markEnd(delegate.createProperty('init', key, value), startToken);
5903 key: key,
5904 value: parseAssignmentExpression(),
5905 kind: 'init'
5906 };
5907 } 6603 }
5908 } 6604 }
5909 6605
5910 function parseObjectInitialiser() { 6606 function parseObjectInitialiser() {
5911 var properties = [], property, name, kind, map = {}, toString = String; 6607 var properties = [], property, name, key, kind, map = {}, toString = String, startToken;
6608
6609 startToken = lookahead;
5912 6610
5913 expect('{'); 6611 expect('{');
5914 6612
5915 while (!match('}')) { 6613 while (!match('}')) {
5916 property = parseObjectProperty(); 6614 property = parseObjectProperty();
5919 name = property.key.name; 6617 name = property.key.name;
5920 } else { 6618 } else {
5921 name = toString(property.key.value); 6619 name = toString(property.key.value);
5922 } 6620 }
5923 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; 6621 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
5924 if (Object.prototype.hasOwnProperty.call(map, name)) { 6622
5925 if (map[name] === PropertyKind.Data) { 6623 key = '$' + name;
6624 if (Object.prototype.hasOwnProperty.call(map, key)) {
6625 if (map[key] === PropertyKind.Data) {
5926 if (strict && kind === PropertyKind.Data) { 6626 if (strict && kind === PropertyKind.Data) {
5927 throwErrorTolerant({}, Messages.StrictDuplicateProperty); 6627 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
5928 } else if (kind !== PropertyKind.Data) { 6628 } else if (kind !== PropertyKind.Data) {
5929 throwErrorTolerant({}, Messages.AccessorDataProperty); 6629 throwErrorTolerant({}, Messages.AccessorDataProperty);
5930 } 6630 }
5931 } else { 6631 } else {
5932 if (kind === PropertyKind.Data) { 6632 if (kind === PropertyKind.Data) {
5933 throwErrorTolerant({}, Messages.AccessorDataProperty); 6633 throwErrorTolerant({}, Messages.AccessorDataProperty);
5934 } else if (map[name] & kind) { 6634 } else if (map[key] & kind) {
5935 throwErrorTolerant({}, Messages.AccessorGetSet); 6635 throwErrorTolerant({}, Messages.AccessorGetSet);
5936 } 6636 }
5937 } 6637 }
5938 map[name] |= kind; 6638 map[key] |= kind;
5939 } else { 6639 } else {
5940 map[name] = kind; 6640 map[key] = kind;
5941 } 6641 }
5942 6642
5943 properties.push(property); 6643 properties.push(property);
5944 6644
5945 if (!match('}')) { 6645 if (!match('}')) {
5947 } 6647 }
5948 } 6648 }
5949 6649
5950 expect('}'); 6650 expect('}');
5951 6651
5952 return { 6652 return delegate.markEnd(delegate.createObjectExpression(properties), startToken);
5953 type: Syntax.ObjectExpression,
5954 properties: properties
5955 };
5956 } 6653 }
5957 6654
5958 // 11.1.6 The Grouping Operator 6655 // 11.1.6 The Grouping Operator
5959 6656
5960 function parseGroupExpression() { 6657 function parseGroupExpression() {
5971 6668
5972 6669
5973 // 11.1 Primary Expressions 6670 // 11.1 Primary Expressions
5974 6671
5975 function parsePrimaryExpression() { 6672 function parsePrimaryExpression() {
5976 var token = lookahead(), 6673 var type, token, expr, startToken;
5977 type = token.type; 6674
6675 if (match('(')) {
6676 return parseGroupExpression();
6677 }
6678
6679 if (match('[')) {
6680 return parseArrayInitialiser();
6681 }
6682
6683 if (match('{')) {
6684 return parseObjectInitialiser();
6685 }
6686
6687 type = lookahead.type;
6688 startToken = lookahead;
5978 6689
5979 if (type === Token.Identifier) { 6690 if (type === Token.Identifier) {
5980 return { 6691 expr = delegate.createIdentifier(lex().value);
5981 type: Syntax.Identifier, 6692 } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
5982 name: lex().value 6693 if (strict && lookahead.octal) {
5983 }; 6694 throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
5984 } 6695 }
5985 6696 expr = delegate.createLiteral(lex());
5986 if (type === Token.StringLiteral || type === Token.NumericLiteral) { 6697 } else if (type === Token.Keyword) {
5987 if (strict && token.octal) { 6698 if (matchKeyword('function')) {
5988 throwErrorTolerant(token, Messages.StrictOctalLiteral); 6699 return parseFunctionExpression();
5989 } 6700 }
5990 return createLiteral(lex());
5991 }
5992
5993 if (type === Token.Keyword) {
5994 if (matchKeyword('this')) { 6701 if (matchKeyword('this')) {
5995 lex(); 6702 lex();
5996 return { 6703 expr = delegate.createThisExpression();
5997 type: Syntax.ThisExpression 6704 } else {
5998 }; 6705 throwUnexpected(lex());
5999 } 6706 }
6000 6707 } else if (type === Token.BooleanLiteral) {
6001 if (matchKeyword('function')) { 6708 token = lex();
6002 return parseFunctionExpression();
6003 }
6004 }
6005
6006 if (type === Token.BooleanLiteral) {
6007 lex();
6008 token.value = (token.value === 'true'); 6709 token.value = (token.value === 'true');
6009 return createLiteral(token); 6710 expr = delegate.createLiteral(token);
6010 } 6711 } else if (type === Token.NullLiteral) {
6011 6712 token = lex();
6012 if (type === Token.NullLiteral) {
6013 lex();
6014 token.value = null; 6713 token.value = null;
6015 return createLiteral(token); 6714 expr = delegate.createLiteral(token);
6016 } 6715 } else if (match('/') || match('/=')) {
6017 6716 if (typeof extra.tokens !== 'undefined') {
6018 if (match('[')) { 6717 expr = delegate.createLiteral(collectRegex());
6019 return parseArrayInitialiser(); 6718 } else {
6020 } 6719 expr = delegate.createLiteral(scanRegExp());
6021 6720 }
6022 if (match('{')) { 6721 peek();
6023 return parseObjectInitialiser(); 6722 } else {
6024 } 6723 throwUnexpected(lex());
6025 6724 }
6026 if (match('(')) { 6725
6027 return parseGroupExpression(); 6726 return delegate.markEnd(expr, startToken);
6028 }
6029
6030 if (match('/') || match('/=')) {
6031 return createLiteral(scanRegExp());
6032 }
6033
6034 return throwUnexpected(lex());
6035 } 6727 }
6036 6728
6037 // 11.2 Left-Hand-Side Expressions 6729 // 11.2 Left-Hand-Side Expressions
6038 6730
6039 function parseArguments() { 6731 function parseArguments() {
6055 6747
6056 return args; 6748 return args;
6057 } 6749 }
6058 6750
6059 function parseNonComputedProperty() { 6751 function parseNonComputedProperty() {
6060 var token = lex(); 6752 var token, startToken;
6753
6754 startToken = lookahead;
6755 token = lex();
6061 6756
6062 if (!isIdentifierName(token)) { 6757 if (!isIdentifierName(token)) {
6063 throwUnexpected(token); 6758 throwUnexpected(token);
6064 } 6759 }
6065 6760
6066 return { 6761 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
6067 type: Syntax.Identifier,
6068 name: token.value
6069 };
6070 } 6762 }
6071 6763
6072 function parseNonComputedMember() { 6764 function parseNonComputedMember() {
6073 expect('.'); 6765 expect('.');
6074 6766
6086 6778
6087 return expr; 6779 return expr;
6088 } 6780 }
6089 6781
6090 function parseNewExpression() { 6782 function parseNewExpression() {
6091 var expr; 6783 var callee, args, startToken;
6092 6784
6785 startToken = lookahead;
6093 expectKeyword('new'); 6786 expectKeyword('new');
6094 6787 callee = parseLeftHandSideExpression();
6095 expr = { 6788 args = match('(') ? parseArguments() : [];
6096 type: Syntax.NewExpression, 6789
6097 callee: parseLeftHandSideExpression(), 6790 return delegate.markEnd(delegate.createNewExpression(callee, args), startToken);
6098 'arguments': [] 6791 }
6099 }; 6792
6100 6793 function parseLeftHandSideExpressionAllowCall() {
6101 if (match('(')) { 6794 var previousAllowIn, expr, args, property, startToken;
6102 expr['arguments'] = parseArguments(); 6795
6796 startToken = lookahead;
6797
6798 previousAllowIn = state.allowIn;
6799 state.allowIn = true;
6800 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
6801 state.allowIn = previousAllowIn;
6802
6803 for (;;) {
6804 if (match('.')) {
6805 property = parseNonComputedMember();
6806 expr = delegate.createMemberExpression('.', expr, property);
6807 } else if (match('(')) {
6808 args = parseArguments();
6809 expr = delegate.createCallExpression(expr, args);
6810 } else if (match('[')) {
6811 property = parseComputedMember();
6812 expr = delegate.createMemberExpression('[', expr, property);
6813 } else {
6814 break;
6815 }
6816 delegate.markEnd(expr, startToken);
6103 } 6817 }
6104 6818
6105 return expr; 6819 return expr;
6106 } 6820 }
6107 6821
6108 function parseLeftHandSideExpressionAllowCall() { 6822 function parseLeftHandSideExpression() {
6109 var expr; 6823 var previousAllowIn, expr, property, startToken;
6110 6824
6825 startToken = lookahead;
6826
6827 previousAllowIn = state.allowIn;
6111 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); 6828 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
6112 6829 state.allowIn = previousAllowIn;
6113 while (match('.') || match('[') || match('(')) {
6114 if (match('(')) {
6115 expr = {
6116 type: Syntax.CallExpression,
6117 callee: expr,
6118 'arguments': parseArguments()
6119 };
6120 } else if (match('[')) {
6121 expr = {
6122 type: Syntax.MemberExpression,
6123 computed: true,
6124 object: expr,
6125 property: parseComputedMember()
6126 };
6127 } else {
6128 expr = {
6129 type: Syntax.MemberExpression,
6130 computed: false,
6131 object: expr,
6132 property: parseNonComputedMember()
6133 };
6134 }
6135 }
6136
6137 return expr;
6138 }
6139
6140
6141 function parseLeftHandSideExpression() {
6142 var expr;
6143
6144 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
6145 6830
6146 while (match('.') || match('[')) { 6831 while (match('.') || match('[')) {
6147 if (match('[')) { 6832 if (match('[')) {
6148 expr = { 6833 property = parseComputedMember();
6149 type: Syntax.MemberExpression, 6834 expr = delegate.createMemberExpression('[', expr, property);
6150 computed: true,
6151 object: expr,
6152 property: parseComputedMember()
6153 };
6154 } else { 6835 } else {
6155 expr = { 6836 property = parseNonComputedMember();
6156 type: Syntax.MemberExpression, 6837 expr = delegate.createMemberExpression('.', expr, property);
6157 computed: false, 6838 }
6158 object: expr, 6839 delegate.markEnd(expr, startToken);
6159 property: parseNonComputedMember()
6160 };
6161 }
6162 } 6840 }
6163 6841
6164 return expr; 6842 return expr;
6165 } 6843 }
6166 6844
6167 // 11.3 Postfix Expressions 6845 // 11.3 Postfix Expressions
6168 6846
6169 function parsePostfixExpression() { 6847 function parsePostfixExpression() {
6170 var expr = parseLeftHandSideExpressionAllowCall(), token; 6848 var expr, token, startToken = lookahead;
6171 6849
6172 token = lookahead(); 6850 expr = parseLeftHandSideExpressionAllowCall();
6173 if (token.type !== Token.Punctuator) { 6851
6174 return expr; 6852 if (lookahead.type === Token.Punctuator) {
6175 } 6853 if ((match('++') || match('--')) && !peekLineTerminator()) {
6176 6854 // 11.3.1, 11.3.2
6177 if ((match('++') || match('--')) && !peekLineTerminator()) { 6855 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
6178 // 11.3.1, 11.3.2 6856 throwErrorTolerant({}, Messages.StrictLHSPostfix);
6179 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { 6857 }
6180 throwErrorTolerant({}, Messages.StrictLHSPostfix); 6858
6181 } 6859 if (!isLeftHandSide(expr)) {
6182 if (!isLeftHandSide(expr)) { 6860 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
6183 throwErrorTolerant({}, Messages.InvalidLHSInAssignment); 6861 }
6184 } 6862
6185 6863 token = lex();
6186 expr = { 6864 expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken);
6187 type: Syntax.UpdateExpression, 6865 }
6188 operator: lex().value,
6189 argument: expr,
6190 prefix: false
6191 };
6192 } 6866 }
6193 6867
6194 return expr; 6868 return expr;
6195 } 6869 }
6196 6870
6197 // 11.4 Unary Operators 6871 // 11.4 Unary Operators
6198 6872
6199 function parseUnaryExpression() { 6873 function parseUnaryExpression() {
6200 var token, expr; 6874 var token, expr, startToken;
6201 6875
6202 token = lookahead(); 6876 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
6203 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { 6877 expr = parsePostfixExpression();
6204 return parsePostfixExpression(); 6878 } else if (match('++') || match('--')) {
6205 } 6879 startToken = lookahead;
6206
6207 if (match('++') || match('--')) {
6208 token = lex(); 6880 token = lex();
6209 expr = parseUnaryExpression(); 6881 expr = parseUnaryExpression();
6210 // 11.4.4, 11.4.5 6882 // 11.4.4, 11.4.5
6211 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { 6883 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
6212 throwErrorTolerant({}, Messages.StrictLHSPrefix); 6884 throwErrorTolerant({}, Messages.StrictLHSPrefix);
6214 6886
6215 if (!isLeftHandSide(expr)) { 6887 if (!isLeftHandSide(expr)) {
6216 throwErrorTolerant({}, Messages.InvalidLHSInAssignment); 6888 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
6217 } 6889 }
6218 6890
6219 expr = { 6891 expr = delegate.createUnaryExpression(token.value, expr);
6220 type: Syntax.UpdateExpression, 6892 expr = delegate.markEnd(expr, startToken);
6221 operator: token.value, 6893 } else if (match('+') || match('-') || match('~') || match('!')) {
6222 argument: expr, 6894 startToken = lookahead;
6223 prefix: true 6895 token = lex();
6224 }; 6896 expr = parseUnaryExpression();
6225 return expr; 6897 expr = delegate.createUnaryExpression(token.value, expr);
6226 } 6898 expr = delegate.markEnd(expr, startToken);
6227 6899 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
6228 if (match('+') || match('-') || match('~') || match('!')) { 6900 startToken = lookahead;
6229 expr = { 6901 token = lex();
6230 type: Syntax.UnaryExpression, 6902 expr = parseUnaryExpression();
6231 operator: lex().value, 6903 expr = delegate.createUnaryExpression(token.value, expr);
6232 argument: parseUnaryExpression(), 6904 expr = delegate.markEnd(expr, startToken);
6233 prefix: true
6234 };
6235 return expr;
6236 }
6237
6238 if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
6239 expr = {
6240 type: Syntax.UnaryExpression,
6241 operator: lex().value,
6242 argument: parseUnaryExpression(),
6243 prefix: true
6244 };
6245 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { 6905 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
6246 throwErrorTolerant({}, Messages.StrictDelete); 6906 throwErrorTolerant({}, Messages.StrictDelete);
6247 } 6907 }
6248 return expr; 6908 } else {
6249 } 6909 expr = parsePostfixExpression();
6250 6910 }
6251 return parsePostfixExpression(); 6911
6912 return expr;
6913 }
6914
6915 function binaryPrecedence(token, allowIn) {
6916 var prec = 0;
6917
6918 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
6919 return 0;
6920 }
6921
6922 switch (token.value) {
6923 case '||':
6924 prec = 1;
6925 break;
6926
6927 case '&&':
6928 prec = 2;
6929 break;
6930
6931 case '|':
6932 prec = 3;
6933 break;
6934
6935 case '^':
6936 prec = 4;
6937 break;
6938
6939 case '&':
6940 prec = 5;
6941 break;
6942
6943 case '==':
6944 case '!=':
6945 case '===':
6946 case '!==':
6947 prec = 6;
6948 break;
6949
6950 case '<':
6951 case '>':
6952 case '<=':
6953 case '>=':
6954 case 'instanceof':
6955 prec = 7;
6956 break;
6957
6958 case 'in':
6959 prec = allowIn ? 7 : 0;
6960 break;
6961
6962 case '<<':
6963 case '>>':
6964 case '>>>':
6965 prec = 8;
6966 break;
6967
6968 case '+':
6969 case '-':
6970 prec = 9;
6971 break;
6972
6973 case '*':
6974 case '/':
6975 case '%':
6976 prec = 11;
6977 break;
6978
6979 default:
6980 break;
6981 }
6982
6983 return prec;
6252 } 6984 }
6253 6985
6254 // 11.5 Multiplicative Operators 6986 // 11.5 Multiplicative Operators
6255 6987 // 11.6 Additive Operators
6256 function parseMultiplicativeExpression() { 6988 // 11.7 Bitwise Shift Operators
6257 var expr = parseUnaryExpression(); 6989 // 11.8 Relational Operators
6258 6990 // 11.9 Equality Operators
6259 while (match('*') || match('/') || match('%')) { 6991 // 11.10 Binary Bitwise Operators
6260 expr = { 6992 // 11.11 Binary Logical Operators
6261 type: Syntax.BinaryExpression, 6993
6262 operator: lex().value, 6994 function parseBinaryExpression() {
6263 left: expr, 6995 var marker, markers, expr, token, prec, stack, right, operator, left, i;
6264 right: parseUnaryExpression() 6996
6265 }; 6997 marker = lookahead;
6998 left = parseUnaryExpression();
6999
7000 token = lookahead;
7001 prec = binaryPrecedence(token, state.allowIn);
7002 if (prec === 0) {
7003 return left;
7004 }
7005 token.prec = prec;
7006 lex();
7007
7008 markers = [marker, lookahead];
7009 right = parseUnaryExpression();
7010
7011 stack = [left, token, right];
7012
7013 while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
7014
7015 // Reduce: make a binary expression from the three topmost entries.
7016 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
7017 right = stack.pop();
7018 operator = stack.pop().value;
7019 left = stack.pop();
7020 expr = delegate.createBinaryExpression(operator, left, right);
7021 markers.pop();
7022 marker = markers[markers.length - 1];
7023 delegate.markEnd(expr, marker);
7024 stack.push(expr);
7025 }
7026
7027 // Shift.
7028 token = lex();
7029 token.prec = prec;
7030 stack.push(token);
7031 markers.push(lookahead);
7032 expr = parseUnaryExpression();
7033 stack.push(expr);
7034 }
7035
7036 // Final reduce to clean-up the stack.
7037 i = stack.length - 1;
7038 expr = stack[i];
7039 markers.pop();
7040 while (i > 1) {
7041 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
7042 i -= 2;
7043 marker = markers.pop();
7044 delegate.markEnd(expr, marker);
6266 } 7045 }
6267 7046
6268 return expr; 7047 return expr;
6269 } 7048 }
6270 7049
6271 // 11.6 Additive Operators
6272
6273 function parseAdditiveExpression() {
6274 var expr = parseMultiplicativeExpression();
6275
6276 while (match('+') || match('-')) {
6277 expr = {
6278 type: Syntax.BinaryExpression,
6279 operator: lex().value,
6280 left: expr,
6281 right: parseMultiplicativeExpression()
6282 };
6283 }
6284
6285 return expr;
6286 }
6287
6288 // 11.7 Bitwise Shift Operators
6289
6290 function parseShiftExpression() {
6291 var expr = parseAdditiveExpression();
6292
6293 while (match('<<') || match('>>') || match('>>>')) {
6294 expr = {
6295 type: Syntax.BinaryExpression,
6296 operator: lex().value,
6297 left: expr,
6298 right: parseAdditiveExpression()
6299 };
6300 }
6301
6302 return expr;
6303 }
6304 // 11.8 Relational Operators
6305
6306 function parseRelationalExpression() {
6307 var expr, previousAllowIn;
6308
6309 previousAllowIn = state.allowIn;
6310 state.allowIn = true;
6311
6312 expr = parseShiftExpression();
6313
6314 while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
6315 expr = {
6316 type: Syntax.BinaryExpression,
6317 operator: lex().value,
6318 left: expr,
6319 right: parseShiftExpression()
6320 };
6321 }
6322
6323 state.allowIn = previousAllowIn;
6324 return expr;
6325 }
6326
6327 // 11.9 Equality Operators
6328
6329 function parseEqualityExpression() {
6330 var expr = parseRelationalExpression();
6331
6332 while (match('==') || match('!=') || match('===') || match('!==')) {
6333 expr = {
6334 type: Syntax.BinaryExpression,
6335 operator: lex().value,
6336 left: expr,
6337 right: parseRelationalExpression()
6338 };
6339 }
6340
6341 return expr;
6342 }
6343
6344 // 11.10 Binary Bitwise Operators
6345
6346 function parseBitwiseANDExpression() {
6347 var expr = parseEqualityExpression();
6348
6349 while (match('&')) {
6350 lex();
6351 expr = {
6352 type: Syntax.BinaryExpression,
6353 operator: '&',
6354 left: expr,
6355 right: parseEqualityExpression()
6356 };
6357 }
6358
6359 return expr;
6360 }
6361
6362 function parseBitwiseXORExpression() {
6363 var expr = parseBitwiseANDExpression();
6364
6365 while (match('^')) {
6366 lex();
6367 expr = {
6368 type: Syntax.BinaryExpression,
6369 operator: '^',
6370 left: expr,
6371 right: parseBitwiseANDExpression()
6372 };
6373 }
6374
6375 return expr;
6376 }
6377
6378 function parseBitwiseORExpression() {
6379 var expr = parseBitwiseXORExpression();
6380
6381 while (match('|')) {
6382 lex();
6383 expr = {
6384 type: Syntax.BinaryExpression,
6385 operator: '|',
6386 left: expr,
6387 right: parseBitwiseXORExpression()
6388 };
6389 }
6390
6391 return expr;
6392 }
6393
6394 // 11.11 Binary Logical Operators
6395
6396 function parseLogicalANDExpression() {
6397 var expr = parseBitwiseORExpression();
6398
6399 while (match('&&')) {
6400 lex();
6401 expr = {
6402 type: Syntax.LogicalExpression,
6403 operator: '&&',
6404 left: expr,
6405 right: parseBitwiseORExpression()
6406 };
6407 }
6408
6409 return expr;
6410 }
6411
6412 function parseLogicalORExpression() {
6413 var expr = parseLogicalANDExpression();
6414
6415 while (match('||')) {
6416 lex();
6417 expr = {
6418 type: Syntax.LogicalExpression,
6419 operator: '||',
6420 left: expr,
6421 right: parseLogicalANDExpression()
6422 };
6423 }
6424
6425 return expr;
6426 }
6427 7050
6428 // 11.12 Conditional Operator 7051 // 11.12 Conditional Operator
6429 7052
6430 function parseConditionalExpression() { 7053 function parseConditionalExpression() {
6431 var expr, previousAllowIn, consequent; 7054 var expr, previousAllowIn, consequent, alternate, startToken;
6432 7055
6433 expr = parseLogicalORExpression(); 7056 startToken = lookahead;
7057
7058 expr = parseBinaryExpression();
6434 7059
6435 if (match('?')) { 7060 if (match('?')) {
6436 lex(); 7061 lex();
6437 previousAllowIn = state.allowIn; 7062 previousAllowIn = state.allowIn;
6438 state.allowIn = true; 7063 state.allowIn = true;
6439 consequent = parseAssignmentExpression(); 7064 consequent = parseAssignmentExpression();
6440 state.allowIn = previousAllowIn; 7065 state.allowIn = previousAllowIn;
6441 expect(':'); 7066 expect(':');
6442 7067 alternate = parseAssignmentExpression();
6443 expr = { 7068
6444 type: Syntax.ConditionalExpression, 7069 expr = delegate.createConditionalExpression(expr, consequent, alternate);
6445 test: expr, 7070 delegate.markEnd(expr, startToken);
6446 consequent: consequent,
6447 alternate: parseAssignmentExpression()
6448 };
6449 } 7071 }
6450 7072
6451 return expr; 7073 return expr;
6452 } 7074 }
6453 7075
6454 // 11.13 Assignment Operators 7076 // 11.13 Assignment Operators
6455 7077
6456 function parseAssignmentExpression() { 7078 function parseAssignmentExpression() {
6457 var token, expr; 7079 var token, left, right, node, startToken;
6458 7080
6459 token = lookahead(); 7081 token = lookahead;
6460 expr = parseConditionalExpression(); 7082 startToken = lookahead;
7083
7084 node = left = parseConditionalExpression();
6461 7085
6462 if (matchAssign()) { 7086 if (matchAssign()) {
6463 // LeftHandSideExpression 7087 // LeftHandSideExpression
6464 if (!isLeftHandSide(expr)) { 7088 if (!isLeftHandSide(left)) {
6465 throwErrorTolerant({}, Messages.InvalidLHSInAssignment); 7089 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
6466 } 7090 }
6467 7091
6468 // 11.13.1 7092 // 11.13.1
6469 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { 7093 if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
6470 throwErrorTolerant(token, Messages.StrictLHSAssignment); 7094 throwErrorTolerant(token, Messages.StrictLHSAssignment);
6471 } 7095 }
6472 7096
6473 expr = { 7097 token = lex();
6474 type: Syntax.AssignmentExpression, 7098 right = parseAssignmentExpression();
6475 operator: lex().value, 7099 node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken);
6476 left: expr, 7100 }
6477 right: parseAssignmentExpression() 7101
6478 }; 7102 return node;
6479 }
6480
6481 return expr;
6482 } 7103 }
6483 7104
6484 // 11.14 Comma Operator 7105 // 11.14 Comma Operator
6485 7106
6486 function parseExpression() { 7107 function parseExpression() {
6487 var expr = parseAssignmentExpression(); 7108 var expr, startToken = lookahead;
7109
7110 expr = parseAssignmentExpression();
6488 7111
6489 if (match(',')) { 7112 if (match(',')) {
6490 expr = { 7113 expr = delegate.createSequenceExpression([ expr ]);
6491 type: Syntax.SequenceExpression,
6492 expressions: [ expr ]
6493 };
6494 7114
6495 while (index < length) { 7115 while (index < length) {
6496 if (!match(',')) { 7116 if (!match(',')) {
6497 break; 7117 break;
6498 } 7118 }
6499 lex(); 7119 lex();
6500 expr.expressions.push(parseAssignmentExpression()); 7120 expr.expressions.push(parseAssignmentExpression());
6501 } 7121 }
6502 7122
6503 } 7123 delegate.markEnd(expr, startToken);
7124 }
7125
6504 return expr; 7126 return expr;
6505 } 7127 }
6506 7128
6507 // 12.1 Block 7129 // 12.1 Block
6508 7130
6523 7145
6524 return list; 7146 return list;
6525 } 7147 }
6526 7148
6527 function parseBlock() { 7149 function parseBlock() {
6528 var block; 7150 var block, startToken;
6529 7151
7152 startToken = lookahead;
6530 expect('{'); 7153 expect('{');
6531 7154
6532 block = parseStatementList(); 7155 block = parseStatementList();
6533 7156
6534 expect('}'); 7157 expect('}');
6535 7158
6536 return { 7159 return delegate.markEnd(delegate.createBlockStatement(block), startToken);
6537 type: Syntax.BlockStatement,
6538 body: block
6539 };
6540 } 7160 }
6541 7161
6542 // 12.2 Variable Statement 7162 // 12.2 Variable Statement
6543 7163
6544 function parseVariableIdentifier() { 7164 function parseVariableIdentifier() {
6545 var token = lex(); 7165 var token, startToken;
7166
7167 startToken = lookahead;
7168 token = lex();
6546 7169
6547 if (token.type !== Token.Identifier) { 7170 if (token.type !== Token.Identifier) {
6548 throwUnexpected(token); 7171 throwUnexpected(token);
6549 } 7172 }
6550 7173
6551 return { 7174 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
6552 type: Syntax.Identifier,
6553 name: token.value
6554 };
6555 } 7175 }
6556 7176
6557 function parseVariableDeclaration(kind) { 7177 function parseVariableDeclaration(kind) {
6558 var id = parseVariableIdentifier(), 7178 var init = null, id, startToken;
6559 init = null; 7179
7180 startToken = lookahead;
7181 id = parseVariableIdentifier();
6560 7182
6561 // 12.2.1 7183 // 12.2.1
6562 if (strict && isRestrictedWord(id.name)) { 7184 if (strict && isRestrictedWord(id.name)) {
6563 throwErrorTolerant({}, Messages.StrictVarName); 7185 throwErrorTolerant({}, Messages.StrictVarName);
6564 } 7186 }
6569 } else if (match('=')) { 7191 } else if (match('=')) {
6570 lex(); 7192 lex();
6571 init = parseAssignmentExpression(); 7193 init = parseAssignmentExpression();
6572 } 7194 }
6573 7195
6574 return { 7196 return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken);
6575 type: Syntax.VariableDeclarator,
6576 id: id,
6577 init: init
6578 };
6579 } 7197 }
6580 7198
6581 function parseVariableDeclarationList(kind) { 7199 function parseVariableDeclarationList(kind) {
6582 var list = []; 7200 var list = [];
6583 7201
6599 7217
6600 declarations = parseVariableDeclarationList(); 7218 declarations = parseVariableDeclarationList();
6601 7219
6602 consumeSemicolon(); 7220 consumeSemicolon();
6603 7221
6604 return { 7222 return delegate.createVariableDeclaration(declarations, 'var');
6605 type: Syntax.VariableDeclaration,
6606 declarations: declarations,
6607 kind: 'var'
6608 };
6609 } 7223 }
6610 7224
6611 // kind may be `const` or `let` 7225 // kind may be `const` or `let`
6612 // Both are experimental and not in the specification yet. 7226 // Both are experimental and not in the specification yet.
6613 // see http://wiki.ecmascript.org/doku.php?id=harmony:const 7227 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
6614 // and http://wiki.ecmascript.org/doku.php?id=harmony:let 7228 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
6615 function parseConstLetDeclaration(kind) { 7229 function parseConstLetDeclaration(kind) {
6616 var declarations; 7230 var declarations, startToken;
7231
7232 startToken = lookahead;
6617 7233
6618 expectKeyword(kind); 7234 expectKeyword(kind);
6619 7235
6620 declarations = parseVariableDeclarationList(kind); 7236 declarations = parseVariableDeclarationList(kind);
6621 7237
6622 consumeSemicolon(); 7238 consumeSemicolon();
6623 7239
6624 return { 7240 return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken);
6625 type: Syntax.VariableDeclaration,
6626 declarations: declarations,
6627 kind: kind
6628 };
6629 } 7241 }
6630 7242
6631 // 12.3 Empty Statement 7243 // 12.3 Empty Statement
6632 7244
6633 function parseEmptyStatement() { 7245 function parseEmptyStatement() {
6634 expect(';'); 7246 expect(';');
6635 7247 return delegate.createEmptyStatement();
6636 return {
6637 type: Syntax.EmptyStatement
6638 };
6639 } 7248 }
6640 7249
6641 // 12.4 Expression Statement 7250 // 12.4 Expression Statement
6642 7251
6643 function parseExpressionStatement() { 7252 function parseExpressionStatement() {
6644 var expr = parseExpression(); 7253 var expr = parseExpression();
6645
6646 consumeSemicolon(); 7254 consumeSemicolon();
6647 7255 return delegate.createExpressionStatement(expr);
6648 return {
6649 type: Syntax.ExpressionStatement,
6650 expression: expr
6651 };
6652 } 7256 }
6653 7257
6654 // 12.5 If statement 7258 // 12.5 If statement
6655 7259
6656 function parseIfStatement() { 7260 function parseIfStatement() {
6671 alternate = parseStatement(); 7275 alternate = parseStatement();
6672 } else { 7276 } else {
6673 alternate = null; 7277 alternate = null;
6674 } 7278 }
6675 7279
6676 return { 7280 return delegate.createIfStatement(test, consequent, alternate);
6677 type: Syntax.IfStatement,
6678 test: test,
6679 consequent: consequent,
6680 alternate: alternate
6681 };
6682 } 7281 }
6683 7282
6684 // 12.6 Iteration Statements 7283 // 12.6 Iteration Statements
6685 7284
6686 function parseDoWhileStatement() { 7285 function parseDoWhileStatement() {
6705 7304
6706 if (match(';')) { 7305 if (match(';')) {
6707 lex(); 7306 lex();
6708 } 7307 }
6709 7308
6710 return { 7309 return delegate.createDoWhileStatement(body, test);
6711 type: Syntax.DoWhileStatement,
6712 body: body,
6713 test: test
6714 };
6715 } 7310 }
6716 7311
6717 function parseWhileStatement() { 7312 function parseWhileStatement() {
6718 var test, body, oldInIteration; 7313 var test, body, oldInIteration;
6719 7314
6730 7325
6731 body = parseStatement(); 7326 body = parseStatement();
6732 7327
6733 state.inIteration = oldInIteration; 7328 state.inIteration = oldInIteration;
6734 7329
6735 return { 7330 return delegate.createWhileStatement(test, body);
6736 type: Syntax.WhileStatement,
6737 test: test,
6738 body: body
6739 };
6740 } 7331 }
6741 7332
6742 function parseForVariableDeclaration() { 7333 function parseForVariableDeclaration() {
6743 var token = lex(); 7334 var token, declarations, startToken;
6744 7335
6745 return { 7336 startToken = lookahead;
6746 type: Syntax.VariableDeclaration, 7337 token = lex();
6747 declarations: parseVariableDeclarationList(), 7338 declarations = parseVariableDeclarationList();
6748 kind: token.value 7339
6749 }; 7340 return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken);
6750 } 7341 }
6751 7342
6752 function parseForStatement() { 7343 function parseForStatement() {
6753 var init, test, update, left, right, body, oldInIteration; 7344 var init, test, update, left, right, body, oldInIteration;
6754 7345
6814 7405
6815 body = parseStatement(); 7406 body = parseStatement();
6816 7407
6817 state.inIteration = oldInIteration; 7408 state.inIteration = oldInIteration;
6818 7409
6819 if (typeof left === 'undefined') { 7410 return (typeof left === 'undefined') ?
6820 return { 7411 delegate.createForStatement(init, test, update, body) :
6821 type: Syntax.ForStatement, 7412 delegate.createForInStatement(left, right, body);
6822 init: init,
6823 test: test,
6824 update: update,
6825 body: body
6826 };
6827 }
6828
6829 return {
6830 type: Syntax.ForInStatement,
6831 left: left,
6832 right: right,
6833 body: body,
6834 each: false
6835 };
6836 } 7413 }
6837 7414
6838 // 12.7 The continue statement 7415 // 12.7 The continue statement
6839 7416
6840 function parseContinueStatement() { 7417 function parseContinueStatement() {
6841 var token, label = null; 7418 var label = null, key;
6842 7419
6843 expectKeyword('continue'); 7420 expectKeyword('continue');
6844 7421
6845 // Optimize the most common form: 'continue;'. 7422 // Optimize the most common form: 'continue;'.
6846 if (source[index] === ';') { 7423 if (source.charCodeAt(index) === 0x3B) {
6847 lex(); 7424 lex();
6848 7425
6849 if (!state.inIteration) { 7426 if (!state.inIteration) {
6850 throwError({}, Messages.IllegalContinue); 7427 throwError({}, Messages.IllegalContinue);
6851 } 7428 }
6852 7429
6853 return { 7430 return delegate.createContinueStatement(null);
6854 type: Syntax.ContinueStatement,
6855 label: null
6856 };
6857 } 7431 }
6858 7432
6859 if (peekLineTerminator()) { 7433 if (peekLineTerminator()) {
6860 if (!state.inIteration) { 7434 if (!state.inIteration) {
6861 throwError({}, Messages.IllegalContinue); 7435 throwError({}, Messages.IllegalContinue);
6862 } 7436 }
6863 7437
6864 return { 7438 return delegate.createContinueStatement(null);
6865 type: Syntax.ContinueStatement, 7439 }
6866 label: null 7440
6867 }; 7441 if (lookahead.type === Token.Identifier) {
6868 }
6869
6870 token = lookahead();
6871 if (token.type === Token.Identifier) {
6872 label = parseVariableIdentifier(); 7442 label = parseVariableIdentifier();
6873 7443
6874 if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { 7444 key = '$' + label.name;
7445 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
6875 throwError({}, Messages.UnknownLabel, label.name); 7446 throwError({}, Messages.UnknownLabel, label.name);
6876 } 7447 }
6877 } 7448 }
6878 7449
6879 consumeSemicolon(); 7450 consumeSemicolon();
6880 7451
6881 if (label === null && !state.inIteration) { 7452 if (label === null && !state.inIteration) {
6882 throwError({}, Messages.IllegalContinue); 7453 throwError({}, Messages.IllegalContinue);
6883 } 7454 }
6884 7455
6885 return { 7456 return delegate.createContinueStatement(label);
6886 type: Syntax.ContinueStatement,
6887 label: label
6888 };
6889 } 7457 }
6890 7458
6891 // 12.8 The break statement 7459 // 12.8 The break statement
6892 7460
6893 function parseBreakStatement() { 7461 function parseBreakStatement() {
6894 var token, label = null; 7462 var label = null, key;
6895 7463
6896 expectKeyword('break'); 7464 expectKeyword('break');
6897 7465
6898 // Optimize the most common form: 'break;'. 7466 // Catch the very common case first: immediately a semicolon (U+003B).
6899 if (source[index] === ';') { 7467 if (source.charCodeAt(index) === 0x3B) {
6900 lex(); 7468 lex();
6901 7469
6902 if (!(state.inIteration || state.inSwitch)) { 7470 if (!(state.inIteration || state.inSwitch)) {
6903 throwError({}, Messages.IllegalBreak); 7471 throwError({}, Messages.IllegalBreak);
6904 } 7472 }
6905 7473
6906 return { 7474 return delegate.createBreakStatement(null);
6907 type: Syntax.BreakStatement,
6908 label: null
6909 };
6910 } 7475 }
6911 7476
6912 if (peekLineTerminator()) { 7477 if (peekLineTerminator()) {
6913 if (!(state.inIteration || state.inSwitch)) { 7478 if (!(state.inIteration || state.inSwitch)) {
6914 throwError({}, Messages.IllegalBreak); 7479 throwError({}, Messages.IllegalBreak);
6915 } 7480 }
6916 7481
6917 return { 7482 return delegate.createBreakStatement(null);
6918 type: Syntax.BreakStatement, 7483 }
6919 label: null 7484
6920 }; 7485 if (lookahead.type === Token.Identifier) {
6921 }
6922
6923 token = lookahead();
6924 if (token.type === Token.Identifier) {
6925 label = parseVariableIdentifier(); 7486 label = parseVariableIdentifier();
6926 7487
6927 if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { 7488 key = '$' + label.name;
7489 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
6928 throwError({}, Messages.UnknownLabel, label.name); 7490 throwError({}, Messages.UnknownLabel, label.name);
6929 } 7491 }
6930 } 7492 }
6931 7493
6932 consumeSemicolon(); 7494 consumeSemicolon();
6933 7495
6934 if (label === null && !(state.inIteration || state.inSwitch)) { 7496 if (label === null && !(state.inIteration || state.inSwitch)) {
6935 throwError({}, Messages.IllegalBreak); 7497 throwError({}, Messages.IllegalBreak);
6936 } 7498 }
6937 7499
6938 return { 7500 return delegate.createBreakStatement(label);
6939 type: Syntax.BreakStatement,
6940 label: label
6941 };
6942 } 7501 }
6943 7502
6944 // 12.9 The return statement 7503 // 12.9 The return statement
6945 7504
6946 function parseReturnStatement() { 7505 function parseReturnStatement() {
6947 var token, argument = null; 7506 var argument = null;
6948 7507
6949 expectKeyword('return'); 7508 expectKeyword('return');
6950 7509
6951 if (!state.inFunctionBody) { 7510 if (!state.inFunctionBody) {
6952 throwErrorTolerant({}, Messages.IllegalReturn); 7511 throwErrorTolerant({}, Messages.IllegalReturn);
6953 } 7512 }
6954 7513
6955 // 'return' followed by a space and an identifier is very common. 7514 // 'return' followed by a space and an identifier is very common.
6956 if (source[index] === ' ') { 7515 if (source.charCodeAt(index) === 0x20) {
6957 if (isIdentifierStart(source[index + 1])) { 7516 if (isIdentifierStart(source.charCodeAt(index + 1))) {
6958 argument = parseExpression(); 7517 argument = parseExpression();
6959 consumeSemicolon(); 7518 consumeSemicolon();
6960 return { 7519 return delegate.createReturnStatement(argument);
6961 type: Syntax.ReturnStatement,
6962 argument: argument
6963 };
6964 } 7520 }
6965 } 7521 }
6966 7522
6967 if (peekLineTerminator()) { 7523 if (peekLineTerminator()) {
6968 return { 7524 return delegate.createReturnStatement(null);
6969 type: Syntax.ReturnStatement,
6970 argument: null
6971 };
6972 } 7525 }
6973 7526
6974 if (!match(';')) { 7527 if (!match(';')) {
6975 token = lookahead(); 7528 if (!match('}') && lookahead.type !== Token.EOF) {
6976 if (!match('}') && token.type !== Token.EOF) {
6977 argument = parseExpression(); 7529 argument = parseExpression();
6978 } 7530 }
6979 } 7531 }
6980 7532
6981 consumeSemicolon(); 7533 consumeSemicolon();
6982 7534
6983 return { 7535 return delegate.createReturnStatement(argument);
6984 type: Syntax.ReturnStatement,
6985 argument: argument
6986 };
6987 } 7536 }
6988 7537
6989 // 12.10 The with statement 7538 // 12.10 The with statement
6990 7539
6991 function parseWithStatement() { 7540 function parseWithStatement() {
6992 var object, body; 7541 var object, body;
6993 7542
6994 if (strict) { 7543 if (strict) {
7544 // TODO(ikarienator): Should we update the test cases instead?
7545 skipComment();
6995 throwErrorTolerant({}, Messages.StrictModeWith); 7546 throwErrorTolerant({}, Messages.StrictModeWith);
6996 } 7547 }
6997 7548
6998 expectKeyword('with'); 7549 expectKeyword('with');
6999 7550
7003 7554
7004 expect(')'); 7555 expect(')');
7005 7556
7006 body = parseStatement(); 7557 body = parseStatement();
7007 7558
7008 return { 7559 return delegate.createWithStatement(object, body);
7009 type: Syntax.WithStatement,
7010 object: object,
7011 body: body
7012 };
7013 } 7560 }
7014 7561
7015 // 12.10 The swith statement 7562 // 12.10 The swith statement
7016 7563
7017 function parseSwitchCase() { 7564 function parseSwitchCase() {
7018 var test, 7565 var test, consequent = [], statement, startToken;
7019 consequent = [], 7566
7020 statement; 7567 startToken = lookahead;
7021
7022 if (matchKeyword('default')) { 7568 if (matchKeyword('default')) {
7023 lex(); 7569 lex();
7024 test = null; 7570 test = null;
7025 } else { 7571 } else {
7026 expectKeyword('case'); 7572 expectKeyword('case');
7031 while (index < length) { 7577 while (index < length) {
7032 if (match('}') || matchKeyword('default') || matchKeyword('case')) { 7578 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
7033 break; 7579 break;
7034 } 7580 }
7035 statement = parseStatement(); 7581 statement = parseStatement();
7036 if (typeof statement === 'undefined') {
7037 break;
7038 }
7039 consequent.push(statement); 7582 consequent.push(statement);
7040 } 7583 }
7041 7584
7042 return { 7585 return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken);
7043 type: Syntax.SwitchCase,
7044 test: test,
7045 consequent: consequent
7046 };
7047 } 7586 }
7048 7587
7049 function parseSwitchStatement() { 7588 function parseSwitchStatement() {
7050 var discriminant, cases, clause, oldInSwitch, defaultFound; 7589 var discriminant, cases, clause, oldInSwitch, defaultFound;
7051 7590
7061 7600
7062 cases = []; 7601 cases = [];
7063 7602
7064 if (match('}')) { 7603 if (match('}')) {
7065 lex(); 7604 lex();
7066 return { 7605 return delegate.createSwitchStatement(discriminant, cases);
7067 type: Syntax.SwitchStatement,
7068 discriminant: discriminant,
7069 cases: cases
7070 };
7071 } 7606 }
7072 7607
7073 oldInSwitch = state.inSwitch; 7608 oldInSwitch = state.inSwitch;
7074 state.inSwitch = true; 7609 state.inSwitch = true;
7075 defaultFound = false; 7610 defaultFound = false;
7090 7625
7091 state.inSwitch = oldInSwitch; 7626 state.inSwitch = oldInSwitch;
7092 7627
7093 expect('}'); 7628 expect('}');
7094 7629
7095 return { 7630 return delegate.createSwitchStatement(discriminant, cases);
7096 type: Syntax.SwitchStatement,
7097 discriminant: discriminant,
7098 cases: cases
7099 };
7100 } 7631 }
7101 7632
7102 // 12.13 The throw statement 7633 // 12.13 The throw statement
7103 7634
7104 function parseThrowStatement() { 7635 function parseThrowStatement() {
7112 7643
7113 argument = parseExpression(); 7644 argument = parseExpression();
7114 7645
7115 consumeSemicolon(); 7646 consumeSemicolon();
7116 7647
7117 return { 7648 return delegate.createThrowStatement(argument);
7118 type: Syntax.ThrowStatement,
7119 argument: argument
7120 };
7121 } 7649 }
7122 7650
7123 // 12.14 The try statement 7651 // 12.14 The try statement
7124 7652
7125 function parseCatchClause() { 7653 function parseCatchClause() {
7126 var param; 7654 var param, body, startToken;
7127 7655
7656 startToken = lookahead;
7128 expectKeyword('catch'); 7657 expectKeyword('catch');
7129 7658
7130 expect('('); 7659 expect('(');
7131 if (match(')')) { 7660 if (match(')')) {
7132 throwUnexpected(lookahead()); 7661 throwUnexpected(lookahead);
7133 } 7662 }
7134 7663
7135 param = parseVariableIdentifier(); 7664 param = parseVariableIdentifier();
7136 // 12.14.1 7665 // 12.14.1
7137 if (strict && isRestrictedWord(param.name)) { 7666 if (strict && isRestrictedWord(param.name)) {
7138 throwErrorTolerant({}, Messages.StrictCatchVariable); 7667 throwErrorTolerant({}, Messages.StrictCatchVariable);
7139 } 7668 }
7140 7669
7141 expect(')'); 7670 expect(')');
7142 7671 body = parseBlock();
7143 return { 7672 return delegate.markEnd(delegate.createCatchClause(param, body), startToken);
7144 type: Syntax.CatchClause,
7145 param: param,
7146 body: parseBlock()
7147 };
7148 } 7673 }
7149 7674
7150 function parseTryStatement() { 7675 function parseTryStatement() {
7151 var block, handlers = [], finalizer = null; 7676 var block, handlers = [], finalizer = null;
7152 7677
7165 7690
7166 if (handlers.length === 0 && !finalizer) { 7691 if (handlers.length === 0 && !finalizer) {
7167 throwError({}, Messages.NoCatchOrFinally); 7692 throwError({}, Messages.NoCatchOrFinally);
7168 } 7693 }
7169 7694
7170 return { 7695 return delegate.createTryStatement(block, [], handlers, finalizer);
7171 type: Syntax.TryStatement,
7172 block: block,
7173 guardedHandlers: [],
7174 handlers: handlers,
7175 finalizer: finalizer
7176 };
7177 } 7696 }
7178 7697
7179 // 12.15 The debugger statement 7698 // 12.15 The debugger statement
7180 7699
7181 function parseDebuggerStatement() { 7700 function parseDebuggerStatement() {
7182 expectKeyword('debugger'); 7701 expectKeyword('debugger');
7183 7702
7184 consumeSemicolon(); 7703 consumeSemicolon();
7185 7704
7186 return { 7705 return delegate.createDebuggerStatement();
7187 type: Syntax.DebuggerStatement
7188 };
7189 } 7706 }
7190 7707
7191 // 12 Statements 7708 // 12 Statements
7192 7709
7193 function parseStatement() { 7710 function parseStatement() {
7194 var token = lookahead(), 7711 var type = lookahead.type,
7195 expr, 7712 expr,
7196 labeledBody; 7713 labeledBody,
7197 7714 key,
7198 if (token.type === Token.EOF) { 7715 startToken;
7199 throwUnexpected(token); 7716
7200 } 7717 if (type === Token.EOF) {
7201 7718 throwUnexpected(lookahead);
7202 if (token.type === Token.Punctuator) { 7719 }
7203 switch (token.value) { 7720
7721 if (type === Token.Punctuator && lookahead.value === '{') {
7722 return parseBlock();
7723 }
7724
7725 startToken = lookahead;
7726
7727 if (type === Token.Punctuator) {
7728 switch (lookahead.value) {
7204 case ';': 7729 case ';':
7205 return parseEmptyStatement(); 7730 return delegate.markEnd(parseEmptyStatement(), startToken);
7206 case '{':
7207 return parseBlock();
7208 case '(': 7731 case '(':
7209 return parseExpressionStatement(); 7732 return delegate.markEnd(parseExpressionStatement(), startToken);
7210 default: 7733 default:
7211 break; 7734 break;
7212 } 7735 }
7213 } 7736 }
7214 7737
7215 if (token.type === Token.Keyword) { 7738 if (type === Token.Keyword) {
7216 switch (token.value) { 7739 switch (lookahead.value) {
7217 case 'break': 7740 case 'break':
7218 return parseBreakStatement(); 7741 return delegate.markEnd(parseBreakStatement(), startToken);
7219 case 'continue': 7742 case 'continue':
7220 return parseContinueStatement(); 7743 return delegate.markEnd(parseContinueStatement(), startToken);
7221 case 'debugger': 7744 case 'debugger':
7222 return parseDebuggerStatement(); 7745 return delegate.markEnd(parseDebuggerStatement(), startToken);
7223 case 'do': 7746 case 'do':
7224 return parseDoWhileStatement(); 7747 return delegate.markEnd(parseDoWhileStatement(), startToken);
7225 case 'for': 7748 case 'for':
7226 return parseForStatement(); 7749 return delegate.markEnd(parseForStatement(), startToken);
7227 case 'function': 7750 case 'function':
7228 return parseFunctionDeclaration(); 7751 return delegate.markEnd(parseFunctionDeclaration(), startToken);
7229 case 'if': 7752 case 'if':
7230 return parseIfStatement(); 7753 return delegate.markEnd(parseIfStatement(), startToken);
7231 case 'return': 7754 case 'return':
7232 return parseReturnStatement(); 7755 return delegate.markEnd(parseReturnStatement(), startToken);
7233 case 'switch': 7756 case 'switch':
7234 return parseSwitchStatement(); 7757 return delegate.markEnd(parseSwitchStatement(), startToken);
7235 case 'throw': 7758 case 'throw':
7236 return parseThrowStatement(); 7759 return delegate.markEnd(parseThrowStatement(), startToken);
7237 case 'try': 7760 case 'try':
7238 return parseTryStatement(); 7761 return delegate.markEnd(parseTryStatement(), startToken);
7239 case 'var': 7762 case 'var':
7240 return parseVariableStatement(); 7763 return delegate.markEnd(parseVariableStatement(), startToken);
7241 case 'while': 7764 case 'while':
7242 return parseWhileStatement(); 7765 return delegate.markEnd(parseWhileStatement(), startToken);
7243 case 'with': 7766 case 'with':
7244 return parseWithStatement(); 7767 return delegate.markEnd(parseWithStatement(), startToken);
7245 default: 7768 default:
7246 break; 7769 break;
7247 } 7770 }
7248 } 7771 }
7249 7772
7251 7774
7252 // 12.12 Labelled Statements 7775 // 12.12 Labelled Statements
7253 if ((expr.type === Syntax.Identifier) && match(':')) { 7776 if ((expr.type === Syntax.Identifier) && match(':')) {
7254 lex(); 7777 lex();
7255 7778
7256 if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) { 7779 key = '$' + expr.name;
7780 if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
7257 throwError({}, Messages.Redeclaration, 'Label', expr.name); 7781 throwError({}, Messages.Redeclaration, 'Label', expr.name);
7258 } 7782 }
7259 7783
7260 state.labelSet[expr.name] = true; 7784 state.labelSet[key] = true;
7261 labeledBody = parseStatement(); 7785 labeledBody = parseStatement();
7262 delete state.labelSet[expr.name]; 7786 delete state.labelSet[key];
7263 7787 return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken);
7264 return {
7265 type: Syntax.LabeledStatement,
7266 label: expr,
7267 body: labeledBody
7268 };
7269 } 7788 }
7270 7789
7271 consumeSemicolon(); 7790 consumeSemicolon();
7272 7791
7273 return { 7792 return delegate.markEnd(delegate.createExpressionStatement(expr), startToken);
7274 type: Syntax.ExpressionStatement,
7275 expression: expr
7276 };
7277 } 7793 }
7278 7794
7279 // 13 Function Definition 7795 // 13 Function Definition
7280 7796
7281 function parseFunctionSourceElements() { 7797 function parseFunctionSourceElements() {
7282 var sourceElement, sourceElements = [], token, directive, firstRestricted, 7798 var sourceElement, sourceElements = [], token, directive, firstRestricted,
7283 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; 7799 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken;
7284 7800
7801 startToken = lookahead;
7285 expect('{'); 7802 expect('{');
7286 7803
7287 while (index < length) { 7804 while (index < length) {
7288 token = lookahead(); 7805 if (lookahead.type !== Token.StringLiteral) {
7289 if (token.type !== Token.StringLiteral) {
7290 break; 7806 break;
7291 } 7807 }
7808 token = lookahead;
7292 7809
7293 sourceElement = parseSourceElement(); 7810 sourceElement = parseSourceElement();
7294 sourceElements.push(sourceElement); 7811 sourceElements.push(sourceElement);
7295 if (sourceElement.expression.type !== Syntax.Literal) { 7812 if (sourceElement.expression.type !== Syntax.Literal) {
7296 // this is not directive 7813 // this is not directive
7297 break; 7814 break;
7298 } 7815 }
7299 directive = sliceSource(token.range[0] + 1, token.range[1] - 1); 7816 directive = source.slice(token.start + 1, token.end - 1);
7300 if (directive === 'use strict') { 7817 if (directive === 'use strict') {
7301 strict = true; 7818 strict = true;
7302 if (firstRestricted) { 7819 if (firstRestricted) {
7303 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); 7820 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
7304 } 7821 }
7335 state.labelSet = oldLabelSet; 7852 state.labelSet = oldLabelSet;
7336 state.inIteration = oldInIteration; 7853 state.inIteration = oldInIteration;
7337 state.inSwitch = oldInSwitch; 7854 state.inSwitch = oldInSwitch;
7338 state.inFunctionBody = oldInFunctionBody; 7855 state.inFunctionBody = oldInFunctionBody;
7339 7856
7340 return { 7857 return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken);
7341 type: Syntax.BlockStatement, 7858 }
7342 body: sourceElements 7859
7343 }; 7860 function parseParams(firstRestricted) {
7344 } 7861 var param, params = [], token, stricted, paramSet, key, message;
7345
7346 function parseFunctionDeclaration() {
7347 var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet;
7348
7349 expectKeyword('function');
7350 token = lookahead();
7351 id = parseVariableIdentifier();
7352 if (strict) {
7353 if (isRestrictedWord(token.value)) {
7354 throwErrorTolerant(token, Messages.StrictFunctionName);
7355 }
7356 } else {
7357 if (isRestrictedWord(token.value)) {
7358 firstRestricted = token;
7359 message = Messages.StrictFunctionName;
7360 } else if (isStrictModeReservedWord(token.value)) {
7361 firstRestricted = token;
7362 message = Messages.StrictReservedWord;
7363 }
7364 }
7365
7366 expect('('); 7862 expect('(');
7367 7863
7368 if (!match(')')) { 7864 if (!match(')')) {
7369 paramSet = {}; 7865 paramSet = {};
7370 while (index < length) { 7866 while (index < length) {
7371 token = lookahead(); 7867 token = lookahead;
7372 param = parseVariableIdentifier(); 7868 param = parseVariableIdentifier();
7869 key = '$' + token.value;
7373 if (strict) { 7870 if (strict) {
7374 if (isRestrictedWord(token.value)) { 7871 if (isRestrictedWord(token.value)) {
7375 stricted = token; 7872 stricted = token;
7376 message = Messages.StrictParamName; 7873 message = Messages.StrictParamName;
7377 } 7874 }
7378 if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { 7875 if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
7379 stricted = token; 7876 stricted = token;
7380 message = Messages.StrictParamDupe; 7877 message = Messages.StrictParamDupe;
7381 } 7878 }
7382 } else if (!firstRestricted) { 7879 } else if (!firstRestricted) {
7383 if (isRestrictedWord(token.value)) { 7880 if (isRestrictedWord(token.value)) {
7384 firstRestricted = token; 7881 firstRestricted = token;
7385 message = Messages.StrictParamName; 7882 message = Messages.StrictParamName;
7386 } else if (isStrictModeReservedWord(token.value)) { 7883 } else if (isStrictModeReservedWord(token.value)) {
7387 firstRestricted = token; 7884 firstRestricted = token;
7388 message = Messages.StrictReservedWord; 7885 message = Messages.StrictReservedWord;
7389 } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { 7886 } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
7390 firstRestricted = token; 7887 firstRestricted = token;
7391 message = Messages.StrictParamDupe; 7888 message = Messages.StrictParamDupe;
7392 } 7889 }
7393 } 7890 }
7394 params.push(param); 7891 params.push(param);
7395 paramSet[param.name] = true; 7892 paramSet[key] = true;
7396 if (match(')')) { 7893 if (match(')')) {
7397 break; 7894 break;
7398 } 7895 }
7399 expect(','); 7896 expect(',');
7400 } 7897 }
7401 } 7898 }
7402 7899
7403 expect(')'); 7900 expect(')');
7901
7902 return {
7903 params: params,
7904 stricted: stricted,
7905 firstRestricted: firstRestricted,
7906 message: message
7907 };
7908 }
7909
7910 function parseFunctionDeclaration() {
7911 var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken;
7912
7913 startToken = lookahead;
7914
7915 expectKeyword('function');
7916 token = lookahead;
7917 id = parseVariableIdentifier();
7918 if (strict) {
7919 if (isRestrictedWord(token.value)) {
7920 throwErrorTolerant(token, Messages.StrictFunctionName);
7921 }
7922 } else {
7923 if (isRestrictedWord(token.value)) {
7924 firstRestricted = token;
7925 message = Messages.StrictFunctionName;
7926 } else if (isStrictModeReservedWord(token.value)) {
7927 firstRestricted = token;
7928 message = Messages.StrictReservedWord;
7929 }
7930 }
7931
7932 tmp = parseParams(firstRestricted);
7933 params = tmp.params;
7934 stricted = tmp.stricted;
7935 firstRestricted = tmp.firstRestricted;
7936 if (tmp.message) {
7937 message = tmp.message;
7938 }
7404 7939
7405 previousStrict = strict; 7940 previousStrict = strict;
7406 body = parseFunctionSourceElements(); 7941 body = parseFunctionSourceElements();
7407 if (strict && firstRestricted) { 7942 if (strict && firstRestricted) {
7408 throwError(firstRestricted, message); 7943 throwError(firstRestricted, message);
7410 if (strict && stricted) { 7945 if (strict && stricted) {
7411 throwErrorTolerant(stricted, message); 7946 throwErrorTolerant(stricted, message);
7412 } 7947 }
7413 strict = previousStrict; 7948 strict = previousStrict;
7414 7949
7415 return { 7950 return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken);
7416 type: Syntax.FunctionDeclaration,
7417 id: id,
7418 params: params,
7419 defaults: [],
7420 body: body,
7421 rest: null,
7422 generator: false,
7423 expression: false
7424 };
7425 } 7951 }
7426 7952
7427 function parseFunctionExpression() { 7953 function parseFunctionExpression() {
7428 var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet; 7954 var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken;
7429 7955
7956 startToken = lookahead;
7430 expectKeyword('function'); 7957 expectKeyword('function');
7431 7958
7432 if (!match('(')) { 7959 if (!match('(')) {
7433 token = lookahead(); 7960 token = lookahead;
7434 id = parseVariableIdentifier(); 7961 id = parseVariableIdentifier();
7435 if (strict) { 7962 if (strict) {
7436 if (isRestrictedWord(token.value)) { 7963 if (isRestrictedWord(token.value)) {
7437 throwErrorTolerant(token, Messages.StrictFunctionName); 7964 throwErrorTolerant(token, Messages.StrictFunctionName);
7438 } 7965 }
7445 message = Messages.StrictReservedWord; 7972 message = Messages.StrictReservedWord;
7446 } 7973 }
7447 } 7974 }
7448 } 7975 }
7449 7976
7450 expect('('); 7977 tmp = parseParams(firstRestricted);
7451 7978 params = tmp.params;
7452 if (!match(')')) { 7979 stricted = tmp.stricted;
7453 paramSet = {}; 7980 firstRestricted = tmp.firstRestricted;
7454 while (index < length) { 7981 if (tmp.message) {
7455 token = lookahead(); 7982 message = tmp.message;
7456 param = parseVariableIdentifier(); 7983 }
7457 if (strict) {
7458 if (isRestrictedWord(token.value)) {
7459 stricted = token;
7460 message = Messages.StrictParamName;
7461 }
7462 if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7463 stricted = token;
7464 message = Messages.StrictParamDupe;
7465 }
7466 } else if (!firstRestricted) {
7467 if (isRestrictedWord(token.value)) {
7468 firstRestricted = token;
7469 message = Messages.StrictParamName;
7470 } else if (isStrictModeReservedWord(token.value)) {
7471 firstRestricted = token;
7472 message = Messages.StrictReservedWord;
7473 } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7474 firstRestricted = token;
7475 message = Messages.StrictParamDupe;
7476 }
7477 }
7478 params.push(param);
7479 paramSet[param.name] = true;
7480 if (match(')')) {
7481 break;
7482 }
7483 expect(',');
7484 }
7485 }
7486
7487 expect(')');
7488 7984
7489 previousStrict = strict; 7985 previousStrict = strict;
7490 body = parseFunctionSourceElements(); 7986 body = parseFunctionSourceElements();
7491 if (strict && firstRestricted) { 7987 if (strict && firstRestricted) {
7492 throwError(firstRestricted, message); 7988 throwError(firstRestricted, message);
7494 if (strict && stricted) { 7990 if (strict && stricted) {
7495 throwErrorTolerant(stricted, message); 7991 throwErrorTolerant(stricted, message);
7496 } 7992 }
7497 strict = previousStrict; 7993 strict = previousStrict;
7498 7994
7499 return { 7995 return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken);
7500 type: Syntax.FunctionExpression,
7501 id: id,
7502 params: params,
7503 defaults: [],
7504 body: body,
7505 rest: null,
7506 generator: false,
7507 expression: false
7508 };
7509 } 7996 }
7510 7997
7511 // 14 Program 7998 // 14 Program
7512 7999
7513 function parseSourceElement() { 8000 function parseSourceElement() {
7514 var token = lookahead(); 8001 if (lookahead.type === Token.Keyword) {
7515 8002 switch (lookahead.value) {
7516 if (token.type === Token.Keyword) {
7517 switch (token.value) {
7518 case 'const': 8003 case 'const':
7519 case 'let': 8004 case 'let':
7520 return parseConstLetDeclaration(token.value); 8005 return parseConstLetDeclaration(lookahead.value);
7521 case 'function': 8006 case 'function':
7522 return parseFunctionDeclaration(); 8007 return parseFunctionDeclaration();
7523 default: 8008 default:
7524 return parseStatement(); 8009 return parseStatement();
7525 } 8010 }
7526 } 8011 }
7527 8012
7528 if (token.type !== Token.EOF) { 8013 if (lookahead.type !== Token.EOF) {
7529 return parseStatement(); 8014 return parseStatement();
7530 } 8015 }
7531 } 8016 }
7532 8017
7533 function parseSourceElements() { 8018 function parseSourceElements() {
7534 var sourceElement, sourceElements = [], token, directive, firstRestricted; 8019 var sourceElement, sourceElements = [], token, directive, firstRestricted;
7535 8020
7536 while (index < length) { 8021 while (index < length) {
7537 token = lookahead(); 8022 token = lookahead;
7538 if (token.type !== Token.StringLiteral) { 8023 if (token.type !== Token.StringLiteral) {
7539 break; 8024 break;
7540 } 8025 }
7541 8026
7542 sourceElement = parseSourceElement(); 8027 sourceElement = parseSourceElement();
7543 sourceElements.push(sourceElement); 8028 sourceElements.push(sourceElement);
7544 if (sourceElement.expression.type !== Syntax.Literal) { 8029 if (sourceElement.expression.type !== Syntax.Literal) {
7545 // this is not directive 8030 // this is not directive
7546 break; 8031 break;
7547 } 8032 }
7548 directive = sliceSource(token.range[0] + 1, token.range[1] - 1); 8033 directive = source.slice(token.start + 1, token.end - 1);
7549 if (directive === 'use strict') { 8034 if (directive === 'use strict') {
7550 strict = true; 8035 strict = true;
7551 if (firstRestricted) { 8036 if (firstRestricted) {
7552 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); 8037 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
7553 } 8038 }
7558 } 8043 }
7559 } 8044 }
7560 8045
7561 while (index < length) { 8046 while (index < length) {
7562 sourceElement = parseSourceElement(); 8047 sourceElement = parseSourceElement();
8048 /* istanbul ignore if */
7563 if (typeof sourceElement === 'undefined') { 8049 if (typeof sourceElement === 'undefined') {
7564 break; 8050 break;
7565 } 8051 }
7566 sourceElements.push(sourceElement); 8052 sourceElements.push(sourceElement);
7567 } 8053 }
7568 return sourceElements; 8054 return sourceElements;
7569 } 8055 }
7570 8056
7571 function parseProgram() { 8057 function parseProgram() {
7572 var program; 8058 var body, startToken;
8059
8060 skipComment();
8061 peek();
8062 startToken = lookahead;
7573 strict = false; 8063 strict = false;
7574 program = { 8064
7575 type: Syntax.Program, 8065 body = parseSourceElements();
7576 body: parseSourceElements() 8066 return delegate.markEnd(delegate.createProgram(body), startToken);
7577 };
7578 return program;
7579 }
7580
7581 // The following functions are needed only when the option to preserve
7582 // the comments is active.
7583
7584 function addComment(type, value, start, end, loc) {
7585 assert(typeof start === 'number', 'Comment must have valid position');
7586
7587 // Because the way the actual token is scanned, often the comments
7588 // (if any) are skipped twice during the lexical analysis.
7589 // Thus, we need to skip adding a comment if the comment array already
7590 // handled it.
7591 if (extra.comments.length > 0) {
7592 if (extra.comments[extra.comments.length - 1].range[1] > start) {
7593 return;
7594 }
7595 }
7596
7597 extra.comments.push({
7598 type: type,
7599 value: value,
7600 range: [start, end],
7601 loc: loc
7602 });
7603 }
7604
7605 function scanComment() {
7606 var comment, ch, loc, start, blockComment, lineComment;
7607
7608 comment = '';
7609 blockComment = false;
7610 lineComment = false;
7611
7612 while (index < length) {
7613 ch = source[index];
7614
7615 if (lineComment) {
7616 ch = source[index++];
7617 if (isLineTerminator(ch)) {
7618 loc.end = {
7619 line: lineNumber,
7620 column: index - lineStart - 1
7621 };
7622 lineComment = false;
7623 addComment('Line', comment, start, index - 1, loc);
7624 if (ch === '\r' && source[index] === '\n') {
7625 ++index;
7626 }
7627 ++lineNumber;
7628 lineStart = index;
7629 comment = '';
7630 } else if (index >= length) {
7631 lineComment = false;
7632 comment += ch;
7633 loc.end = {
7634 line: lineNumber,
7635 column: length - lineStart
7636 };
7637 addComment('Line', comment, start, length, loc);
7638 } else {
7639 comment += ch;
7640 }
7641 } else if (blockComment) {
7642 if (isLineTerminator(ch)) {
7643 if (ch === '\r' && source[index + 1] === '\n') {
7644 ++index;
7645 comment += '\r\n';
7646 } else {
7647 comment += ch;
7648 }
7649 ++lineNumber;
7650 ++index;
7651 lineStart = index;
7652 if (index >= length) {
7653 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7654 }
7655 } else {
7656 ch = source[index++];
7657 if (index >= length) {
7658 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7659 }
7660 comment += ch;
7661 if (ch === '*') {
7662 ch = source[index];
7663 if (ch === '/') {
7664 comment = comment.substr(0, comment.length - 1);
7665 blockComment = false;
7666 ++index;
7667 loc.end = {
7668 line: lineNumber,
7669 column: index - lineStart
7670 };
7671 addComment('Block', comment, start, index, loc);
7672 comment = '';
7673 }
7674 }
7675 }
7676 } else if (ch === '/') {
7677 ch = source[index + 1];
7678 if (ch === '/') {
7679 loc = {
7680 start: {
7681 line: lineNumber,
7682 column: index - lineStart
7683 }
7684 };
7685 start = index;
7686 index += 2;
7687 lineComment = true;
7688 if (index >= length) {
7689 loc.end = {
7690 line: lineNumber,
7691 column: index - lineStart
7692 };
7693 lineComment = false;
7694 addComment('Line', comment, start, index, loc);
7695 }
7696 } else if (ch === '*') {
7697 start = index;
7698 index += 2;
7699 blockComment = true;
7700 loc = {
7701 start: {
7702 line: lineNumber,
7703 column: index - lineStart - 2
7704 }
7705 };
7706 if (index >= length) {
7707 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7708 }
7709 } else {
7710 break;
7711 }
7712 } else if (isWhiteSpace(ch)) {
7713 ++index;
7714 } else if (isLineTerminator(ch)) {
7715 ++index;
7716 if (ch === '\r' && source[index] === '\n') {
7717 ++index;
7718 }
7719 ++lineNumber;
7720 lineStart = index;
7721 } else {
7722 break;
7723 }
7724 }
7725 }
7726
7727 function filterCommentLocation() {
7728 var i, entry, comment, comments = [];
7729
7730 for (i = 0; i < extra.comments.length; ++i) {
7731 entry = extra.comments[i];
7732 comment = {
7733 type: entry.type,
7734 value: entry.value
7735 };
7736 if (extra.range) {
7737 comment.range = entry.range;
7738 }
7739 if (extra.loc) {
7740 comment.loc = entry.loc;
7741 }
7742 comments.push(comment);
7743 }
7744
7745 extra.comments = comments;
7746 }
7747
7748 function collectToken() {
7749 var start, loc, token, range, value;
7750
7751 skipComment();
7752 start = index;
7753 loc = {
7754 start: {
7755 line: lineNumber,
7756 column: index - lineStart
7757 }
7758 };
7759
7760 token = extra.advance();
7761 loc.end = {
7762 line: lineNumber,
7763 column: index - lineStart
7764 };
7765
7766 if (token.type !== Token.EOF) {
7767 range = [token.range[0], token.range[1]];
7768 value = sliceSource(token.range[0], token.range[1]);
7769 extra.tokens.push({
7770 type: TokenName[token.type],
7771 value: value,
7772 range: range,
7773 loc: loc
7774 });
7775 }
7776
7777 return token;
7778 }
7779
7780 function collectRegex() {
7781 var pos, loc, regex, token;
7782
7783 skipComment();
7784
7785 pos = index;
7786 loc = {
7787 start: {
7788 line: lineNumber,
7789 column: index - lineStart
7790 }
7791 };
7792
7793 regex = extra.scanRegExp();
7794 loc.end = {
7795 line: lineNumber,
7796 column: index - lineStart
7797 };
7798
7799 // Pop the previous token, which is likely '/' or '/='
7800 if (extra.tokens.length > 0) {
7801 token = extra.tokens[extra.tokens.length - 1];
7802 if (token.range[0] === pos && token.type === 'Punctuator') {
7803 if (token.value === '/' || token.value === '/=') {
7804 extra.tokens.pop();
7805 }
7806 }
7807 }
7808
7809 extra.tokens.push({
7810 type: 'RegularExpression',
7811 value: regex.literal,
7812 range: [pos, index],
7813 loc: loc
7814 });
7815
7816 return regex;
7817 } 8067 }
7818 8068
7819 function filterTokenLocation() { 8069 function filterTokenLocation() {
7820 var i, entry, token, tokens = []; 8070 var i, entry, token, tokens = [];
7821 8071
7835 } 8085 }
7836 8086
7837 extra.tokens = tokens; 8087 extra.tokens = tokens;
7838 } 8088 }
7839 8089
7840 function createLiteral(token) { 8090 function tokenize(code, options) {
7841 return { 8091 var toString,
7842 type: Syntax.Literal, 8092 token,
7843 value: token.value 8093 tokens;
7844 };
7845 }
7846
7847 function createRawLiteral(token) {
7848 return {
7849 type: Syntax.Literal,
7850 value: token.value,
7851 raw: sliceSource(token.range[0], token.range[1])
7852 };
7853 }
7854
7855 function createLocationMarker() {
7856 var marker = {};
7857
7858 marker.range = [index, index];
7859 marker.loc = {
7860 start: {
7861 line: lineNumber,
7862 column: index - lineStart
7863 },
7864 end: {
7865 line: lineNumber,
7866 column: index - lineStart
7867 }
7868 };
7869
7870 marker.end = function () {
7871 this.range[1] = index;
7872 this.loc.end.line = lineNumber;
7873 this.loc.end.column = index - lineStart;
7874 };
7875
7876 marker.applyGroup = function (node) {
7877 if (extra.range) {
7878 node.groupRange = [this.range[0], this.range[1]];
7879 }
7880 if (extra.loc) {
7881 node.groupLoc = {
7882 start: {
7883 line: this.loc.start.line,
7884 column: this.loc.start.column
7885 },
7886 end: {
7887 line: this.loc.end.line,
7888 column: this.loc.end.column
7889 }
7890 };
7891 }
7892 };
7893
7894 marker.apply = function (node) {
7895 if (extra.range) {
7896 node.range = [this.range[0], this.range[1]];
7897 }
7898 if (extra.loc) {
7899 node.loc = {
7900 start: {
7901 line: this.loc.start.line,
7902 column: this.loc.start.column
7903 },
7904 end: {
7905 line: this.loc.end.line,
7906 column: this.loc.end.column
7907 }
7908 };
7909 }
7910 };
7911
7912 return marker;
7913 }
7914
7915 function trackGroupExpression() {
7916 var marker, expr;
7917
7918 skipComment();
7919 marker = createLocationMarker();
7920 expect('(');
7921
7922 expr = parseExpression();
7923
7924 expect(')');
7925
7926 marker.end();
7927 marker.applyGroup(expr);
7928
7929 return expr;
7930 }
7931
7932 function trackLeftHandSideExpression() {
7933 var marker, expr;
7934
7935 skipComment();
7936 marker = createLocationMarker();
7937
7938 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
7939
7940 while (match('.') || match('[')) {
7941 if (match('[')) {
7942 expr = {
7943 type: Syntax.MemberExpression,
7944 computed: true,
7945 object: expr,
7946 property: parseComputedMember()
7947 };
7948 marker.end();
7949 marker.apply(expr);
7950 } else {
7951 expr = {
7952 type: Syntax.MemberExpression,
7953 computed: false,
7954 object: expr,
7955 property: parseNonComputedMember()
7956 };
7957 marker.end();
7958 marker.apply(expr);
7959 }
7960 }
7961
7962 return expr;
7963 }
7964
7965 function trackLeftHandSideExpressionAllowCall() {
7966 var marker, expr;
7967
7968 skipComment();
7969 marker = createLocationMarker();
7970
7971 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
7972
7973 while (match('.') || match('[') || match('(')) {
7974 if (match('(')) {
7975 expr = {
7976 type: Syntax.CallExpression,
7977 callee: expr,
7978 'arguments': parseArguments()
7979 };
7980 marker.end();
7981 marker.apply(expr);
7982 } else if (match('[')) {
7983 expr = {
7984 type: Syntax.MemberExpression,
7985 computed: true,
7986 object: expr,
7987 property: parseComputedMember()
7988 };
7989 marker.end();
7990 marker.apply(expr);
7991 } else {
7992 expr = {
7993 type: Syntax.MemberExpression,
7994 computed: false,
7995 object: expr,
7996 property: parseNonComputedMember()
7997 };
7998 marker.end();
7999 marker.apply(expr);
8000 }
8001 }
8002
8003 return expr;
8004 }
8005
8006 function filterGroup(node) {
8007 var n, i, entry;
8008
8009 n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
8010 for (i in node) {
8011 if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
8012 entry = node[i];
8013 if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
8014 n[i] = entry;
8015 } else {
8016 n[i] = filterGroup(entry);
8017 }
8018 }
8019 }
8020 return n;
8021 }
8022
8023 function wrapTrackingFunction(range, loc) {
8024
8025 return function (parseFunction) {
8026
8027 function isBinary(node) {
8028 return node.type === Syntax.LogicalExpression ||
8029 node.type === Syntax.BinaryExpression;
8030 }
8031
8032 function visit(node) {
8033 var start, end;
8034
8035 if (isBinary(node.left)) {
8036 visit(node.left);
8037 }
8038 if (isBinary(node.right)) {
8039 visit(node.right);
8040 }
8041
8042 if (range) {
8043 if (node.left.groupRange || node.right.groupRange) {
8044 start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
8045 end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
8046 node.range = [start, end];
8047 } else if (typeof node.range === 'undefined') {
8048 start = node.left.range[0];
8049 end = node.right.range[1];
8050 node.range = [start, end];
8051 }
8052 }
8053 if (loc) {
8054 if (node.left.groupLoc || node.right.groupLoc) {
8055 start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
8056 end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
8057 node.loc = {
8058 start: start,
8059 end: end
8060 };
8061 } else if (typeof node.loc === 'undefined') {
8062 node.loc = {
8063 start: node.left.loc.start,
8064 end: node.right.loc.end
8065 };
8066 }
8067 }
8068 }
8069
8070 return function () {
8071 var marker, node;
8072
8073 skipComment();
8074
8075 marker = createLocationMarker();
8076 node = parseFunction.apply(null, arguments);
8077 marker.end();
8078
8079 if (range && typeof node.range === 'undefined') {
8080 marker.apply(node);
8081 }
8082
8083 if (loc && typeof node.loc === 'undefined') {
8084 marker.apply(node);
8085 }
8086
8087 if (isBinary(node)) {
8088 visit(node);
8089 }
8090
8091 return node;
8092 };
8093 };
8094 }
8095
8096 function patch() {
8097
8098 var wrapTracking;
8099
8100 if (extra.comments) {
8101 extra.skipComment = skipComment;
8102 skipComment = scanComment;
8103 }
8104
8105 if (extra.raw) {
8106 extra.createLiteral = createLiteral;
8107 createLiteral = createRawLiteral;
8108 }
8109
8110 if (extra.range || extra.loc) {
8111
8112 extra.parseGroupExpression = parseGroupExpression;
8113 extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
8114 extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
8115 parseGroupExpression = trackGroupExpression;
8116 parseLeftHandSideExpression = trackLeftHandSideExpression;
8117 parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
8118
8119 wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
8120
8121 extra.parseAdditiveExpression = parseAdditiveExpression;
8122 extra.parseAssignmentExpression = parseAssignmentExpression;
8123 extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
8124 extra.parseBitwiseORExpression = parseBitwiseORExpression;
8125 extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
8126 extra.parseBlock = parseBlock;
8127 extra.parseFunctionSourceElements = parseFunctionSourceElements;
8128 extra.parseCatchClause = parseCatchClause;
8129 extra.parseComputedMember = parseComputedMember;
8130 extra.parseConditionalExpression = parseConditionalExpression;
8131 extra.parseConstLetDeclaration = parseConstLetDeclaration;
8132 extra.parseEqualityExpression = parseEqualityExpression;
8133 extra.parseExpression = parseExpression;
8134 extra.parseForVariableDeclaration = parseForVariableDeclaration;
8135 extra.parseFunctionDeclaration = parseFunctionDeclaration;
8136 extra.parseFunctionExpression = parseFunctionExpression;
8137 extra.parseLogicalANDExpression = parseLogicalANDExpression;
8138 extra.parseLogicalORExpression = parseLogicalORExpression;
8139 extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
8140 extra.parseNewExpression = parseNewExpression;
8141 extra.parseNonComputedProperty = parseNonComputedProperty;
8142 extra.parseObjectProperty = parseObjectProperty;
8143 extra.parseObjectPropertyKey = parseObjectPropertyKey;
8144 extra.parsePostfixExpression = parsePostfixExpression;
8145 extra.parsePrimaryExpression = parsePrimaryExpression;
8146 extra.parseProgram = parseProgram;
8147 extra.parsePropertyFunction = parsePropertyFunction;
8148 extra.parseRelationalExpression = parseRelationalExpression;
8149 extra.parseStatement = parseStatement;
8150 extra.parseShiftExpression = parseShiftExpression;
8151 extra.parseSwitchCase = parseSwitchCase;
8152 extra.parseUnaryExpression = parseUnaryExpression;
8153 extra.parseVariableDeclaration = parseVariableDeclaration;
8154 extra.parseVariableIdentifier = parseVariableIdentifier;
8155
8156 parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
8157 parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
8158 parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
8159 parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
8160 parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
8161 parseBlock = wrapTracking(extra.parseBlock);
8162 parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
8163 parseCatchClause = wrapTracking(extra.parseCatchClause);
8164 parseComputedMember = wrapTracking(extra.parseComputedMember);
8165 parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
8166 parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
8167 parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
8168 parseExpression = wrapTracking(extra.parseExpression);
8169 parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
8170 parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
8171 parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
8172 parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
8173 parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
8174 parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
8175 parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
8176 parseNewExpression = wrapTracking(extra.parseNewExpression);
8177 parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
8178 parseObjectProperty = wrapTracking(extra.parseObjectProperty);
8179 parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
8180 parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
8181 parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
8182 parseProgram = wrapTracking(extra.parseProgram);
8183 parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
8184 parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
8185 parseStatement = wrapTracking(extra.parseStatement);
8186 parseShiftExpression = wrapTracking(extra.parseShiftExpression);
8187 parseSwitchCase = wrapTracking(extra.parseSwitchCase);
8188 parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
8189 parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
8190 parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
8191 }
8192
8193 if (typeof extra.tokens !== 'undefined') {
8194 extra.advance = advance;
8195 extra.scanRegExp = scanRegExp;
8196
8197 advance = collectToken;
8198 scanRegExp = collectRegex;
8199 }
8200 }
8201
8202 function unpatch() {
8203 if (typeof extra.skipComment === 'function') {
8204 skipComment = extra.skipComment;
8205 }
8206
8207 if (extra.raw) {
8208 createLiteral = extra.createLiteral;
8209 }
8210
8211 if (extra.range || extra.loc) {
8212 parseAdditiveExpression = extra.parseAdditiveExpression;
8213 parseAssignmentExpression = extra.parseAssignmentExpression;
8214 parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
8215 parseBitwiseORExpression = extra.parseBitwiseORExpression;
8216 parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
8217 parseBlock = extra.parseBlock;
8218 parseFunctionSourceElements = extra.parseFunctionSourceElements;
8219 parseCatchClause = extra.parseCatchClause;
8220 parseComputedMember = extra.parseComputedMember;
8221 parseConditionalExpression = extra.parseConditionalExpression;
8222 parseConstLetDeclaration = extra.parseConstLetDeclaration;
8223 parseEqualityExpression = extra.parseEqualityExpression;
8224 parseExpression = extra.parseExpression;
8225 parseForVariableDeclaration = extra.parseForVariableDeclaration;
8226 parseFunctionDeclaration = extra.parseFunctionDeclaration;
8227 parseFunctionExpression = extra.parseFunctionExpression;
8228 parseGroupExpression = extra.parseGroupExpression;
8229 parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
8230 parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
8231 parseLogicalANDExpression = extra.parseLogicalANDExpression;
8232 parseLogicalORExpression = extra.parseLogicalORExpression;
8233 parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
8234 parseNewExpression = extra.parseNewExpression;
8235 parseNonComputedProperty = extra.parseNonComputedProperty;
8236 parseObjectProperty = extra.parseObjectProperty;
8237 parseObjectPropertyKey = extra.parseObjectPropertyKey;
8238 parsePrimaryExpression = extra.parsePrimaryExpression;
8239 parsePostfixExpression = extra.parsePostfixExpression;
8240 parseProgram = extra.parseProgram;
8241 parsePropertyFunction = extra.parsePropertyFunction;
8242 parseRelationalExpression = extra.parseRelationalExpression;
8243 parseStatement = extra.parseStatement;
8244 parseShiftExpression = extra.parseShiftExpression;
8245 parseSwitchCase = extra.parseSwitchCase;
8246 parseUnaryExpression = extra.parseUnaryExpression;
8247 parseVariableDeclaration = extra.parseVariableDeclaration;
8248 parseVariableIdentifier = extra.parseVariableIdentifier;
8249 }
8250
8251 if (typeof extra.scanRegExp === 'function') {
8252 advance = extra.advance;
8253 scanRegExp = extra.scanRegExp;
8254 }
8255 }
8256
8257 function stringToArray(str) {
8258 var length = str.length,
8259 result = [],
8260 i;
8261 for (i = 0; i < length; ++i) {
8262 result[i] = str.charAt(i);
8263 }
8264 return result;
8265 }
8266
8267 function parse(code, options) {
8268 var program, toString;
8269 8094
8270 toString = String; 8095 toString = String;
8271 if (typeof code !== 'string' && !(code instanceof String)) { 8096 if (typeof code !== 'string' && !(code instanceof String)) {
8272 code = toString(code); 8097 code = toString(code);
8273 } 8098 }
8274 8099
8100 delegate = SyntaxTreeDelegate;
8275 source = code; 8101 source = code;
8276 index = 0; 8102 index = 0;
8277 lineNumber = (source.length > 0) ? 1 : 0; 8103 lineNumber = (source.length > 0) ? 1 : 0;
8278 lineStart = 0; 8104 lineStart = 0;
8279 length = source.length; 8105 length = source.length;
8280 buffer = null; 8106 lookahead = null;
8281 state = { 8107 state = {
8282 allowIn: true, 8108 allowIn: true,
8283 labelSet: {}, 8109 labelSet: {},
8284 inFunctionBody: false, 8110 inFunctionBody: false,
8285 inIteration: false, 8111 inIteration: false,
8286 inSwitch: false 8112 inSwitch: false,
8113 lastCommentStart: -1
8114 };
8115
8116 extra = {};
8117
8118 // Options matching.
8119 options = options || {};
8120
8121 // Of course we collect tokens here.
8122 options.tokens = true;
8123 extra.tokens = [];
8124 extra.tokenize = true;
8125 // The following two fields are necessary to compute the Regex tokens.
8126 extra.openParenToken = -1;
8127 extra.openCurlyToken = -1;
8128
8129 extra.range = (typeof options.range === 'boolean') && options.range;
8130 extra.loc = (typeof options.loc === 'boolean') && options.loc;
8131
8132 if (typeof options.comment === 'boolean' && options.comment) {
8133 extra.comments = [];
8134 }
8135 if (typeof options.tolerant === 'boolean' && options.tolerant) {
8136 extra.errors = [];
8137 }
8138
8139 try {
8140 peek();
8141 if (lookahead.type === Token.EOF) {
8142 return extra.tokens;
8143 }
8144
8145 token = lex();
8146 while (lookahead.type !== Token.EOF) {
8147 try {
8148 token = lex();
8149 } catch (lexError) {
8150 token = lookahead;
8151 if (extra.errors) {
8152 extra.errors.push(lexError);
8153 // We have to break on the first error
8154 // to avoid infinite loops.
8155 break;
8156 } else {
8157 throw lexError;
8158 }
8159 }
8160 }
8161
8162 filterTokenLocation();
8163 tokens = extra.tokens;
8164 if (typeof extra.comments !== 'undefined') {
8165 tokens.comments = extra.comments;
8166 }
8167 if (typeof extra.errors !== 'undefined') {
8168 tokens.errors = extra.errors;
8169 }
8170 } catch (e) {
8171 throw e;
8172 } finally {
8173 extra = {};
8174 }
8175 return tokens;
8176 }
8177
8178 function parse(code, options) {
8179 var program, toString;
8180
8181 toString = String;
8182 if (typeof code !== 'string' && !(code instanceof String)) {
8183 code = toString(code);
8184 }
8185
8186 delegate = SyntaxTreeDelegate;
8187 source = code;
8188 index = 0;
8189 lineNumber = (source.length > 0) ? 1 : 0;
8190 lineStart = 0;
8191 length = source.length;
8192 lookahead = null;
8193 state = {
8194 allowIn: true,
8195 labelSet: {},
8196 inFunctionBody: false,
8197 inIteration: false,
8198 inSwitch: false,
8199 lastCommentStart: -1
8287 }; 8200 };
8288 8201
8289 extra = {}; 8202 extra = {};
8290 if (typeof options !== 'undefined') { 8203 if (typeof options !== 'undefined') {
8291 extra.range = (typeof options.range === 'boolean') && options.range; 8204 extra.range = (typeof options.range === 'boolean') && options.range;
8292 extra.loc = (typeof options.loc === 'boolean') && options.loc; 8205 extra.loc = (typeof options.loc === 'boolean') && options.loc;
8293 extra.raw = (typeof options.raw === 'boolean') && options.raw; 8206 extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
8207
8208 if (extra.loc && options.source !== null && options.source !== undefined) {
8209 extra.source = toString(options.source);
8210 }
8211
8294 if (typeof options.tokens === 'boolean' && options.tokens) { 8212 if (typeof options.tokens === 'boolean' && options.tokens) {
8295 extra.tokens = []; 8213 extra.tokens = [];
8296 } 8214 }
8297 if (typeof options.comment === 'boolean' && options.comment) { 8215 if (typeof options.comment === 'boolean' && options.comment) {
8298 extra.comments = []; 8216 extra.comments = [];
8299 } 8217 }
8300 if (typeof options.tolerant === 'boolean' && options.tolerant) { 8218 if (typeof options.tolerant === 'boolean' && options.tolerant) {
8301 extra.errors = []; 8219 extra.errors = [];
8302 } 8220 }
8303 } 8221 if (extra.attachComment) {
8304 8222 extra.range = true;
8305 if (length > 0) { 8223 extra.comments = [];
8306 if (typeof source[0] === 'undefined') { 8224 extra.bottomRightStack = [];
8307 // Try first to convert to a string. This is good as fast path 8225 extra.trailingComments = [];
8308 // for old IE which understands string indexing for string 8226 extra.leadingComments = [];
8309 // literals only and not for string object. 8227 }
8310 if (code instanceof String) { 8228 }
8311 source = code.valueOf(); 8229
8312 }
8313
8314 // Force accessing the characters via an array.
8315 if (typeof source[0] === 'undefined') {
8316 source = stringToArray(code);
8317 }
8318 }
8319 }
8320
8321 patch();
8322 try { 8230 try {
8323 program = parseProgram(); 8231 program = parseProgram();
8324 if (typeof extra.comments !== 'undefined') { 8232 if (typeof extra.comments !== 'undefined') {
8325 filterCommentLocation();
8326 program.comments = extra.comments; 8233 program.comments = extra.comments;
8327 } 8234 }
8328 if (typeof extra.tokens !== 'undefined') { 8235 if (typeof extra.tokens !== 'undefined') {
8329 filterTokenLocation(); 8236 filterTokenLocation();
8330 program.tokens = extra.tokens; 8237 program.tokens = extra.tokens;
8331 } 8238 }
8332 if (typeof extra.errors !== 'undefined') { 8239 if (typeof extra.errors !== 'undefined') {
8333 program.errors = extra.errors; 8240 program.errors = extra.errors;
8334 } 8241 }
8335 if (extra.range || extra.loc) {
8336 program.body = filterGroup(program.body);
8337 }
8338 } catch (e) { 8242 } catch (e) {
8339 throw e; 8243 throw e;
8340 } finally { 8244 } finally {
8341 unpatch();
8342 extra = {}; 8245 extra = {};
8343 } 8246 }
8344 8247
8345 return program; 8248 return program;
8346 } 8249 }
8347 8250
8348 // Sync with package.json. 8251 // Sync with *.json manifests.
8349 exports.version = '1.0.4'; 8252 exports.version = '1.2.2';
8253
8254 exports.tokenize = tokenize;
8350 8255
8351 exports.parse = parse; 8256 exports.parse = parse;
8352 8257
8353 // Deep copy. 8258 // Deep copy.
8259 /* istanbul ignore next */
8354 exports.Syntax = (function () { 8260 exports.Syntax = (function () {
8355 var name, types = {}; 8261 var name, types = {};
8356 8262
8357 if (typeof Object.create === 'function') { 8263 if (typeof Object.create === 'function') {
8358 types = Object.create(null); 8264 types = Object.create(null);
8372 }()); 8278 }());
8373 8279
8374 })); 8280 }));
8375 /* vim: set sw=4 ts=4 et tw=80 : */ 8281 /* vim: set sw=4 ts=4 et tw=80 : */
8376 /** 8282 /**
8377 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 8283 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
8378 * Available via the MIT or new BSD license. 8284 * Available via the MIT or new BSD license.
8379 * see: http://github.com/jrburke/requirejs for details 8285 * see: http://github.com/jrburke/requirejs for details
8380 */ 8286 */
8381 8287
8382 /*global define, Reflect */ 8288 /*global define, Reflect */
13586 * - sources: An array of URLs to the original source files. 13492 * - sources: An array of URLs to the original source files.
13587 * - names: An array of identifiers which can be referrenced by individual mappings. 13493 * - names: An array of identifiers which can be referrenced by individual mappings.
13588 * - sourceRoot: Optional. The URL root from which all sources are relative. 13494 * - sourceRoot: Optional. The URL root from which all sources are relative.
13589 * - sourcesContent: Optional. An array of contents of the original source files. 13495 * - sourcesContent: Optional. An array of contents of the original source files.
13590 * - mappings: A string of base64 VLQs which contain the actual mappings. 13496 * - mappings: A string of base64 VLQs which contain the actual mappings.
13591 * - file: The generated file this source map is associated with. 13497 * - file: Optional. The generated file this source map is associated with.
13592 * 13498 *
13593 * Here is an example source map, taken from the source map spec[0]: 13499 * Here is an example source map, taken from the source map spec[0]:
13594 * 13500 *
13595 * { 13501 * {
13596 * version : 3, 13502 * version : 3,
13609 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); 13515 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
13610 } 13516 }
13611 13517
13612 var version = util.getArg(sourceMap, 'version'); 13518 var version = util.getArg(sourceMap, 'version');
13613 var sources = util.getArg(sourceMap, 'sources'); 13519 var sources = util.getArg(sourceMap, 'sources');
13614 var names = util.getArg(sourceMap, 'names'); 13520 // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
13521 // requires the array) to play nice here.
13522 var names = util.getArg(sourceMap, 'names', []);
13615 var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); 13523 var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
13616 var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); 13524 var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
13617 var mappings = util.getArg(sourceMap, 'mappings'); 13525 var mappings = util.getArg(sourceMap, 'mappings');
13618 var file = util.getArg(sourceMap, 'file', null); 13526 var file = util.getArg(sourceMap, 'file', null);
13619 13527
13620 if (version !== this._version) { 13528 // Once again, Sass deviates from the spec and supplies the version as a
13529 // string rather than a number, so we use loose equality checking here.
13530 if (version != this._version) {
13621 throw new Error('Unsupported version: ' + version); 13531 throw new Error('Unsupported version: ' + version);
13622 } 13532 }
13623 13533
13624 // Pass `true` below to allow duplicate names and sources. While source maps 13534 // Pass `true` below to allow duplicate names and sources. While source maps
13625 // are intended to be compressed and deduplicated, the TypeScript compiler 13535 // are intended to be compressed and deduplicated, the TypeScript compiler
13626 // sometimes generates source maps with duplicates in them. See Github issue 13536 // sometimes generates source maps with duplicates in them. See Github issue
13627 // #72 and bugzil.la/889492. 13537 // #72 and bugzil.la/889492.
13628 this._names = ArraySet.fromArray(names, true); 13538 this._names = ArraySet.fromArray(names, true);
13629 this._sources = ArraySet.fromArray(sources, true); 13539 this._sources = ArraySet.fromArray(sources, true);
13540
13630 this.sourceRoot = sourceRoot; 13541 this.sourceRoot = sourceRoot;
13631 this.sourcesContent = sourcesContent; 13542 this.sourcesContent = sourcesContent;
13543 this._mappings = mappings;
13632 this.file = file; 13544 this.file = file;
13633
13634 // `this._generatedMappings` and `this._originalMappings` hold the parsed
13635 // mapping coordinates from the source map's "mappings" attribute. Each
13636 // object in the array is of the form
13637 //
13638 // {
13639 // generatedLine: The line number in the generated code,
13640 // generatedColumn: The column number in the generated code,
13641 // source: The path to the original source file that generated this
13642 // chunk of code,
13643 // originalLine: The line number in the original source that
13644 // corresponds to this chunk of generated code,
13645 // originalColumn: The column number in the original source that
13646 // corresponds to this chunk of generated code,
13647 // name: The name of the original symbol which generated this chunk of
13648 // code.
13649 // }
13650 //
13651 // All properties except for `generatedLine` and `generatedColumn` can be
13652 // `null`.
13653 //
13654 // `this._generatedMappings` is ordered by the generated positions.
13655 //
13656 // `this._originalMappings` is ordered by the original positions.
13657 this._generatedMappings = [];
13658 this._originalMappings = [];
13659 this._parseMappings(mappings, sourceRoot);
13660 } 13545 }
13661 13546
13662 /** 13547 /**
13663 * Create a SourceMapConsumer from a SourceMapGenerator. 13548 * Create a SourceMapConsumer from a SourceMapGenerator.
13664 * 13549 *
13675 smc.sourceRoot = aSourceMap._sourceRoot; 13560 smc.sourceRoot = aSourceMap._sourceRoot;
13676 smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), 13561 smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
13677 smc.sourceRoot); 13562 smc.sourceRoot);
13678 smc.file = aSourceMap._file; 13563 smc.file = aSourceMap._file;
13679 13564
13680 smc._generatedMappings = aSourceMap._mappings.slice() 13565 smc.__generatedMappings = aSourceMap._mappings.slice()
13681 .sort(util.compareByGeneratedPositions); 13566 .sort(util.compareByGeneratedPositions);
13682 smc._originalMappings = aSourceMap._mappings.slice() 13567 smc.__originalMappings = aSourceMap._mappings.slice()
13683 .sort(util.compareByOriginalPositions); 13568 .sort(util.compareByOriginalPositions);
13684 13569
13685 return smc; 13570 return smc;
13686 }; 13571 };
13687 13572
13699 return this.sourceRoot ? util.join(this.sourceRoot, s) : s; 13584 return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
13700 }, this); 13585 }, this);
13701 } 13586 }
13702 }); 13587 });
13703 13588
13589 // `__generatedMappings` and `__originalMappings` are arrays that hold the
13590 // parsed mapping coordinates from the source map's "mappings" attribute. They
13591 // are lazily instantiated, accessed via the `_generatedMappings` and
13592 // `_originalMappings` getters respectively, and we only parse the mappings
13593 // and create these arrays once queried for a source location. We jump through
13594 // these hoops because there can be many thousands of mappings, and parsing
13595 // them is expensive, so we only want to do it if we must.
13596 //
13597 // Each object in the arrays is of the form:
13598 //
13599 // {
13600 // generatedLine: The line number in the generated code,
13601 // generatedColumn: The column number in the generated code,
13602 // source: The path to the original source file that generated this
13603 // chunk of code,
13604 // originalLine: The line number in the original source that
13605 // corresponds to this chunk of generated code,
13606 // originalColumn: The column number in the original source that
13607 // corresponds to this chunk of generated code,
13608 // name: The name of the original symbol which generated this chunk of
13609 // code.
13610 // }
13611 //
13612 // All properties except for `generatedLine` and `generatedColumn` can be
13613 // `null`.
13614 //
13615 // `_generatedMappings` is ordered by the generated positions.
13616 //
13617 // `_originalMappings` is ordered by the original positions.
13618
13619 SourceMapConsumer.prototype.__generatedMappings = null;
13620 Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
13621 get: function () {
13622 if (!this.__generatedMappings) {
13623 this.__generatedMappings = [];
13624 this.__originalMappings = [];
13625 this._parseMappings(this._mappings, this.sourceRoot);
13626 }
13627
13628 return this.__generatedMappings;
13629 }
13630 });
13631
13632 SourceMapConsumer.prototype.__originalMappings = null;
13633 Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
13634 get: function () {
13635 if (!this.__originalMappings) {
13636 this.__generatedMappings = [];
13637 this.__originalMappings = [];
13638 this._parseMappings(this._mappings, this.sourceRoot);
13639 }
13640
13641 return this.__originalMappings;
13642 }
13643 });
13644
13704 /** 13645 /**
13705 * Parse the mappings in a string in to a data structure which we can easily 13646 * Parse the mappings in a string in to a data structure which we can easily
13706 * query (an ordered list in this._generatedMappings). 13647 * query (the ordered arrays in the `this.__generatedMappings` and
13648 * `this.__originalMappings` properties).
13707 */ 13649 */
13708 SourceMapConsumer.prototype._parseMappings = 13650 SourceMapConsumer.prototype._parseMappings =
13709 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { 13651 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
13710 var generatedLine = 1; 13652 var generatedLine = 1;
13711 var previousGeneratedColumn = 0; 13653 var previousGeneratedColumn = 0;
13771 previousName += temp.value; 13713 previousName += temp.value;
13772 str = temp.rest; 13714 str = temp.rest;
13773 } 13715 }
13774 } 13716 }
13775 13717
13776 this._generatedMappings.push(mapping); 13718 this.__generatedMappings.push(mapping);
13777 if (typeof mapping.originalLine === 'number') { 13719 if (typeof mapping.originalLine === 'number') {
13778 this._originalMappings.push(mapping); 13720 this.__originalMappings.push(mapping);
13779 } 13721 }
13780 } 13722 }
13781 } 13723 }
13782 13724
13783 this._originalMappings.sort(util.compareByOriginalPositions); 13725 this.__generatedMappings.sort(util.compareByGeneratedPositions);
13726 this.__originalMappings.sort(util.compareByOriginalPositions);
13784 }; 13727 };
13785 13728
13786 /** 13729 /**
13787 * Find the mapping that best matches the hypothetical "needle" mapping that 13730 * Find the mapping that best matches the hypothetical "needle" mapping that
13788 * we are searching for in the given "haystack" of mappings. 13731 * we are searching for in the given "haystack" of mappings.
13833 this._generatedMappings, 13776 this._generatedMappings,
13834 "generatedLine", 13777 "generatedLine",
13835 "generatedColumn", 13778 "generatedColumn",
13836 util.compareByGeneratedPositions); 13779 util.compareByGeneratedPositions);
13837 13780
13838 if (mapping) { 13781 if (mapping && mapping.generatedLine === needle.generatedLine) {
13839 var source = util.getArg(mapping, 'source', null); 13782 var source = util.getArg(mapping, 'source', null);
13840 if (source && this.sourceRoot) { 13783 if (source && this.sourceRoot) {
13841 source = util.join(this.sourceRoot, source); 13784 source = util.join(this.sourceRoot, source);
13842 } 13785 }
13843 return { 13786 return {
14011 var util = require('./util'); 13954 var util = require('./util');
14012 var ArraySet = require('./array-set').ArraySet; 13955 var ArraySet = require('./array-set').ArraySet;
14013 13956
14014 /** 13957 /**
14015 * An instance of the SourceMapGenerator represents a source map which is 13958 * An instance of the SourceMapGenerator represents a source map which is
14016 * being built incrementally. To create a new one, you must pass an object 13959 * being built incrementally. You may pass an object with the following
14017 * with the following properties: 13960 * properties:
14018 * 13961 *
14019 * - file: The filename of the generated source. 13962 * - file: The filename of the generated source.
14020 * - sourceRoot: An optional root for all URLs in this source map. 13963 * - sourceRoot: A root for all relative URLs in this source map.
14021 */ 13964 */
14022 function SourceMapGenerator(aArgs) { 13965 function SourceMapGenerator(aArgs) {
14023 this._file = util.getArg(aArgs, 'file'); 13966 if (!aArgs) {
13967 aArgs = {};
13968 }
13969 this._file = util.getArg(aArgs, 'file', null);
14024 this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); 13970 this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
14025 this._sources = new ArraySet(); 13971 this._sources = new ArraySet();
14026 this._names = new ArraySet(); 13972 this._names = new ArraySet();
14027 this._mappings = []; 13973 this._mappings = [];
14028 this._sourcesContents = null; 13974 this._sourcesContents = null;
14148 * resulting mappings is the minimium of this map and the supplied map. 14094 * resulting mappings is the minimium of this map and the supplied map.
14149 * 14095 *
14150 * @param aSourceMapConsumer The source map to be applied. 14096 * @param aSourceMapConsumer The source map to be applied.
14151 * @param aSourceFile Optional. The filename of the source file. 14097 * @param aSourceFile Optional. The filename of the source file.
14152 * If omitted, SourceMapConsumer's file property will be used. 14098 * If omitted, SourceMapConsumer's file property will be used.
14099 * @param aSourceMapPath Optional. The dirname of the path to the source map
14100 * to be applied. If relative, it is relative to the SourceMapConsumer.
14101 * This parameter is needed when the two source maps aren't in the same
14102 * directory, and the source map to be applied contains relative source
14103 * paths. If so, those relative source paths need to be rewritten
14104 * relative to the SourceMapGenerator.
14153 */ 14105 */
14154 SourceMapGenerator.prototype.applySourceMap = 14106 SourceMapGenerator.prototype.applySourceMap =
14155 function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { 14107 function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
14156 // If aSourceFile is omitted, we will use the file property of the SourceMap 14108 // If aSourceFile is omitted, we will use the file property of the SourceMap
14157 if (!aSourceFile) { 14109 if (!aSourceFile) {
14110 if (!aSourceMapConsumer.file) {
14111 throw new Error(
14112 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' +
14113 'or the source map\'s "file" property. Both were omitted.'
14114 );
14115 }
14158 aSourceFile = aSourceMapConsumer.file; 14116 aSourceFile = aSourceMapConsumer.file;
14159 } 14117 }
14160 var sourceRoot = this._sourceRoot; 14118 var sourceRoot = this._sourceRoot;
14161 // Make "aSourceFile" relative if an absolute Url is passed. 14119 // Make "aSourceFile" relative if an absolute Url is passed.
14162 if (sourceRoot) { 14120 if (sourceRoot) {
14175 line: mapping.originalLine, 14133 line: mapping.originalLine,
14176 column: mapping.originalColumn 14134 column: mapping.originalColumn
14177 }); 14135 });
14178 if (original.source !== null) { 14136 if (original.source !== null) {
14179 // Copy mapping 14137 // Copy mapping
14138 mapping.source = original.source;
14139 if (aSourceMapPath) {
14140 mapping.source = util.join(aSourceMapPath, mapping.source)
14141 }
14180 if (sourceRoot) { 14142 if (sourceRoot) {
14181 mapping.source = util.relative(sourceRoot, original.source); 14143 mapping.source = util.relative(sourceRoot, mapping.source);
14182 } else {
14183 mapping.source = original.source;
14184 } 14144 }
14185 mapping.originalLine = original.line; 14145 mapping.originalLine = original.line;
14186 mapping.originalColumn = original.column; 14146 mapping.originalColumn = original.column;
14187 if (original.name !== null && mapping.name !== null) { 14147 if (original.name !== null && mapping.name !== null) {
14188 // Only use the identifier name if it's an identifier 14148 // Only use the identifier name if it's an identifier
14248 } 14208 }
14249 else { 14209 else {
14250 throw new Error('Invalid mapping: ' + JSON.stringify({ 14210 throw new Error('Invalid mapping: ' + JSON.stringify({
14251 generated: aGenerated, 14211 generated: aGenerated,
14252 source: aSource, 14212 source: aSource,
14253 orginal: aOriginal, 14213 original: aOriginal,
14254 name: aName 14214 name: aName
14255 })); 14215 }));
14256 } 14216 }
14257 }; 14217 };
14258 14218
14433 // To extract it current and last mapping is used. 14393 // To extract it current and last mapping is used.
14434 // Here we store the last mapping. 14394 // Here we store the last mapping.
14435 var lastMapping = null; 14395 var lastMapping = null;
14436 14396
14437 aSourceMapConsumer.eachMapping(function (mapping) { 14397 aSourceMapConsumer.eachMapping(function (mapping) {
14438 if (lastMapping === null) { 14398 if (lastMapping !== null) {
14439 // We add the generated code until the first mapping
14440 // to the SourceNode without any mapping.
14441 // Each line is added as separate string.
14442 while (lastGeneratedLine < mapping.generatedLine) {
14443 node.add(remainingLines.shift() + "\n");
14444 lastGeneratedLine++;
14445 }
14446 if (lastGeneratedColumn < mapping.generatedColumn) {
14447 var nextLine = remainingLines[0];
14448 node.add(nextLine.substr(0, mapping.generatedColumn));
14449 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
14450 lastGeneratedColumn = mapping.generatedColumn;
14451 }
14452 } else {
14453 // We add the code from "lastMapping" to "mapping": 14399 // We add the code from "lastMapping" to "mapping":
14454 // First check if there is a new line in between. 14400 // First check if there is a new line in between.
14455 if (lastGeneratedLine < mapping.generatedLine) { 14401 if (lastGeneratedLine < mapping.generatedLine) {
14456 var code = ""; 14402 var code = "";
14457 // Associate full lines with "lastMapping" 14403 // Associate first line with "lastMapping"
14458 do { 14404 addMappingWithCode(lastMapping, remainingLines.shift() + "\n");
14459 code += remainingLines.shift() + "\n"; 14405 lastGeneratedLine++;
14460 lastGeneratedLine++; 14406 lastGeneratedColumn = 0;
14461 lastGeneratedColumn = 0; 14407 // The remaining code is added without mapping
14462 } while (lastGeneratedLine < mapping.generatedLine);
14463 // When we reached the correct line, we add code until we
14464 // reach the correct column too.
14465 if (lastGeneratedColumn < mapping.generatedColumn) {
14466 var nextLine = remainingLines[0];
14467 code += nextLine.substr(0, mapping.generatedColumn);
14468 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
14469 lastGeneratedColumn = mapping.generatedColumn;
14470 }
14471 // Create the SourceNode.
14472 addMappingWithCode(lastMapping, code);
14473 } else { 14408 } else {
14474 // There is no new line in between. 14409 // There is no new line in between.
14475 // Associate the code between "lastGeneratedColumn" and 14410 // Associate the code between "lastGeneratedColumn" and
14476 // "mapping.generatedColumn" with "lastMapping" 14411 // "mapping.generatedColumn" with "lastMapping"
14477 var nextLine = remainingLines[0]; 14412 var nextLine = remainingLines[0];
14479 lastGeneratedColumn); 14414 lastGeneratedColumn);
14480 remainingLines[0] = nextLine.substr(mapping.generatedColumn - 14415 remainingLines[0] = nextLine.substr(mapping.generatedColumn -
14481 lastGeneratedColumn); 14416 lastGeneratedColumn);
14482 lastGeneratedColumn = mapping.generatedColumn; 14417 lastGeneratedColumn = mapping.generatedColumn;
14483 addMappingWithCode(lastMapping, code); 14418 addMappingWithCode(lastMapping, code);
14419 // No more remaining code, continue
14420 lastMapping = mapping;
14421 return;
14484 } 14422 }
14423 }
14424 // We add the generated code until the first mapping
14425 // to the SourceNode without any mapping.
14426 // Each line is added as separate string.
14427 while (lastGeneratedLine < mapping.generatedLine) {
14428 node.add(remainingLines.shift() + "\n");
14429 lastGeneratedLine++;
14430 }
14431 if (lastGeneratedColumn < mapping.generatedColumn) {
14432 var nextLine = remainingLines[0];
14433 node.add(nextLine.substr(0, mapping.generatedColumn));
14434 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
14435 lastGeneratedColumn = mapping.generatedColumn;
14485 } 14436 }
14486 lastMapping = mapping; 14437 lastMapping = mapping;
14487 }, this); 14438 }, this);
14488 // We have processed all mappings. 14439 // We have processed all mappings.
14489 // Associate the remaining code in the current line with "lastMapping" 14440 if (remainingLines.length > 0) {
14490 // and add the remaining lines without any mapping 14441 if (lastMapping) {
14491 addMappingWithCode(lastMapping, remainingLines.join("\n")); 14442 // Associate the remaining code in the current line with "lastMapping"
14443 var lastLine = remainingLines.shift();
14444 if (remainingLines.length > 0) lastLine += "\n";
14445 addMappingWithCode(lastMapping, lastLine);
14446 }
14447 // and add the remaining lines without any mapping
14448 node.add(remainingLines.join("\n"));
14449 }
14492 14450
14493 // Copy sourcesContent into SourceNode 14451 // Copy sourcesContent into SourceNode
14494 aSourceMapConsumer.sources.forEach(function (sourceFile) { 14452 aSourceMapConsumer.sources.forEach(function (sourceFile) {
14495 var content = aSourceMapConsumer.sourceContentFor(sourceFile); 14453 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
14496 if (content) { 14454 if (content) {
14724 } 14682 }
14725 }); 14683 });
14726 lastOriginalSource = null; 14684 lastOriginalSource = null;
14727 sourceMappingActive = false; 14685 sourceMappingActive = false;
14728 } 14686 }
14729 chunk.split('').forEach(function (ch) { 14687 chunk.split('').forEach(function (ch, idx, array) {
14730 if (ch === '\n') { 14688 if (ch === '\n') {
14731 generated.line++; 14689 generated.line++;
14732 generated.column = 0; 14690 generated.column = 0;
14691 // Mappings end at eol
14692 if (idx + 1 === array.length) {
14693 lastOriginalSource = null;
14694 sourceMappingActive = false;
14695 } else if (sourceMappingActive) {
14696 map.addMapping({
14697 source: original.source,
14698 original: {
14699 line: original.line,
14700 column: original.column
14701 },
14702 generated: {
14703 line: generated.line,
14704 column: generated.column
14705 },
14706 name: original.name
14707 });
14708 }
14733 } else { 14709 } else {
14734 generated.column++; 14710 generated.column++;
14735 } 14711 }
14736 }); 14712 });
14737 }); 14713 });
14773 throw new Error('"' + aName + '" is a required argument.'); 14749 throw new Error('"' + aName + '" is a required argument.');
14774 } 14750 }
14775 } 14751 }
14776 exports.getArg = getArg; 14752 exports.getArg = getArg;
14777 14753
14778 var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; 14754 var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
14779 var dataUrlRegexp = /^data:.+\,.+/; 14755 var dataUrlRegexp = /^data:.+\,.+$/;
14780 14756
14781 function urlParse(aUrl) { 14757 function urlParse(aUrl) {
14782 var match = aUrl.match(urlRegexp); 14758 var match = aUrl.match(urlRegexp);
14783 if (!match) { 14759 if (!match) {
14784 return null; 14760 return null;
14785 } 14761 }
14786 return { 14762 return {
14787 scheme: match[1], 14763 scheme: match[1],
14788 auth: match[3], 14764 auth: match[2],
14789 host: match[4], 14765 host: match[3],
14790 port: match[6], 14766 port: match[4],
14791 path: match[7] 14767 path: match[5]
14792 }; 14768 };
14793 } 14769 }
14794 exports.urlParse = urlParse; 14770 exports.urlParse = urlParse;
14795 14771
14796 function urlGenerate(aParsedUrl) { 14772 function urlGenerate(aParsedUrl) {
14797 var url = aParsedUrl.scheme + "://"; 14773 var url = '';
14774 if (aParsedUrl.scheme) {
14775 url += aParsedUrl.scheme + ':';
14776 }
14777 url += '//';
14798 if (aParsedUrl.auth) { 14778 if (aParsedUrl.auth) {
14799 url += aParsedUrl.auth + "@" 14779 url += aParsedUrl.auth + '@';
14800 } 14780 }
14801 if (aParsedUrl.host) { 14781 if (aParsedUrl.host) {
14802 url += aParsedUrl.host; 14782 url += aParsedUrl.host;
14803 } 14783 }
14804 if (aParsedUrl.port) { 14784 if (aParsedUrl.port) {
14809 } 14789 }
14810 return url; 14790 return url;
14811 } 14791 }
14812 exports.urlGenerate = urlGenerate; 14792 exports.urlGenerate = urlGenerate;
14813 14793
14794 /**
14795 * Normalizes a path, or the path portion of a URL:
14796 *
14797 * - Replaces consequtive slashes with one slash.
14798 * - Removes unnecessary '.' parts.
14799 * - Removes unnecessary '<dir>/..' parts.
14800 *
14801 * Based on code in the Node.js 'path' core module.
14802 *
14803 * @param aPath The path or url to normalize.
14804 */
14805 function normalize(aPath) {
14806 var path = aPath;
14807 var url = urlParse(aPath);
14808 if (url) {
14809 if (!url.path) {
14810 return aPath;
14811 }
14812 path = url.path;
14813 }
14814 var isAbsolute = (path.charAt(0) === '/');
14815
14816 var parts = path.split(/\/+/);
14817 for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
14818 part = parts[i];
14819 if (part === '.') {
14820 parts.splice(i, 1);
14821 } else if (part === '..') {
14822 up++;
14823 } else if (up > 0) {
14824 if (part === '') {
14825 // The first part is blank if the path is absolute. Trying to go
14826 // above the root is a no-op. Therefore we can remove all '..' parts
14827 // directly after the root.
14828 parts.splice(i + 1, up);
14829 up = 0;
14830 } else {
14831 parts.splice(i, 2);
14832 up--;
14833 }
14834 }
14835 }
14836 path = parts.join('/');
14837
14838 if (path === '') {
14839 path = isAbsolute ? '/' : '.';
14840 }
14841
14842 if (url) {
14843 url.path = path;
14844 return urlGenerate(url);
14845 }
14846 return path;
14847 }
14848 exports.normalize = normalize;
14849
14850 /**
14851 * Joins two paths/URLs.
14852 *
14853 * @param aRoot The root path or URL.
14854 * @param aPath The path or URL to be joined with the root.
14855 *
14856 * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
14857 * scheme-relative URL: Then the scheme of aRoot, if any, is prepended
14858 * first.
14859 * - Otherwise aPath is a path. If aRoot is a URL, then its path portion
14860 * is updated with the result and aRoot is returned. Otherwise the result
14861 * is returned.
14862 * - If aPath is absolute, the result is aPath.
14863 * - Otherwise the two paths are joined with a slash.
14864 * - Joining for example 'http://' and 'www.example.com' is also supported.
14865 */
14814 function join(aRoot, aPath) { 14866 function join(aRoot, aPath) {
14815 var url; 14867 var aPathUrl = urlParse(aPath);
14816 14868 var aRootUrl = urlParse(aRoot);
14817 if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { 14869 if (aRootUrl) {
14870 aRoot = aRootUrl.path || '/';
14871 }
14872
14873 // `join(foo, '//www.example.org')`
14874 if (aPathUrl && !aPathUrl.scheme) {
14875 if (aRootUrl) {
14876 aPathUrl.scheme = aRootUrl.scheme;
14877 }
14878 return urlGenerate(aPathUrl);
14879 }
14880
14881 if (aPathUrl || aPath.match(dataUrlRegexp)) {
14818 return aPath; 14882 return aPath;
14819 } 14883 }
14820 14884
14821 if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { 14885 // `join('http://', 'www.example.com')`
14822 url.path = aPath; 14886 if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
14823 return urlGenerate(url); 14887 aRootUrl.host = aPath;
14824 } 14888 return urlGenerate(aRootUrl);
14825 14889 }
14826 return aRoot.replace(/\/$/, '') + '/' + aPath; 14890
14891 var joined = aPath.charAt(0) === '/'
14892 ? aPath
14893 : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
14894
14895 if (aRootUrl) {
14896 aRootUrl.path = joined;
14897 return urlGenerate(aRootUrl);
14898 }
14899 return joined;
14827 } 14900 }
14828 exports.join = join; 14901 exports.join = join;
14829 14902
14830 /** 14903 /**
14831 * Because behavior goes wacky when you set `__proto__` on objects, we 14904 * Because behavior goes wacky when you set `__proto__` on objects, we
14962 }); 15035 });
14963 15036
14964 //Distributed under the BSD license: 15037 //Distributed under the BSD license:
14965 //Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com> 15038 //Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
14966 define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) { 15039 define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) {
14967 (function(exports, global) { 15040
14968 global["UglifyJS"] = exports; 15041 /***********************************************************************
14969 "use strict"; 15042
14970 function array_to_hash(a) { 15043 A JavaScript tokenizer / parser / beautifier / compressor.
14971 var ret = Object.create(null); 15044 https://github.com/mishoo/UglifyJS2
14972 for (var i = 0; i < a.length; ++i) ret[a[i]] = true; 15045
14973 return ret; 15046 -------------------------------- (C) ---------------------------------
14974 } 15047
14975 function slice(a, start) { 15048 Author: Mihai Bazon
14976 return Array.prototype.slice.call(a, start || 0); 15049 <mihai.bazon@gmail.com>
14977 } 15050 http://mihai.bazon.net/blog
14978 function characters(str) { 15051
14979 return str.split(""); 15052 Distributed under the BSD license:
14980 } 15053
14981 function member(name, array) { 15054 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
14982 for (var i = array.length; --i >= 0; ) if (array[i] == name) return true; 15055
14983 return false; 15056 Redistribution and use in source and binary forms, with or without
14984 } 15057 modification, are permitted provided that the following conditions
14985 function find_if(func, array) { 15058 are met:
14986 for (var i = 0, n = array.length; i < n; ++i) { 15059
14987 if (func(array[i])) return array[i]; 15060 * Redistributions of source code must retain the above
14988 } 15061 copyright notice, this list of conditions and the following
14989 } 15062 disclaimer.
14990 function repeat_string(str, i) { 15063
14991 if (i <= 0) return ""; 15064 * Redistributions in binary form must reproduce the above
14992 if (i == 1) return str; 15065 copyright notice, this list of conditions and the following
14993 var d = repeat_string(str, i >> 1); 15066 disclaimer in the documentation and/or other materials
14994 d += d; 15067 provided with the distribution.
14995 if (i & 1) d += str; 15068
14996 return d; 15069 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
14997 } 15070 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14998 function DefaultsError(msg, defs) { 15071 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14999 this.msg = msg; 15072 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
15000 this.defs = defs; 15073 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
15001 } 15074 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
15002 function defaults(args, defs, croak) { 15075 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
15003 if (args === true) args = {}; 15076 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
15004 var ret = args || {}; 15077 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
15005 if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) throw new DefaultsError("`" + i + "` is not a supported option", defs); 15078 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
15006 for (var i in defs) if (defs.hasOwnProperty(i)) { 15079 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
15007 ret[i] = args && args.hasOwnProperty(i) ? args[i] : defs[i]; 15080 SUCH DAMAGE.
15008 } 15081
15009 return ret; 15082 ***********************************************************************/
15010 } 15083
15011 function merge(obj, ext) { 15084 "use strict";
15012 for (var i in ext) if (ext.hasOwnProperty(i)) { 15085
15013 obj[i] = ext[i]; 15086 function array_to_hash(a) {
15014 } 15087 var ret = Object.create(null);
15015 return obj; 15088 for (var i = 0; i < a.length; ++i)
15016 } 15089 ret[a[i]] = true;
15017 function noop() {} 15090 return ret;
15018 var MAP = function() { 15091 };
15019 function MAP(a, f, backwards) { 15092
15020 var ret = [], top = [], i; 15093 function slice(a, start) {
15021 function doit() { 15094 return Array.prototype.slice.call(a, start || 0);
15022 var val = f(a[i], i); 15095 };
15023 var is_last = val instanceof Last; 15096
15024 if (is_last) val = val.v; 15097 function characters(str) {
15025 if (val instanceof AtTop) { 15098 return str.split("");
15026 val = val.v; 15099 };
15027 if (val instanceof Splice) { 15100
15028 top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); 15101 function member(name, array) {
15029 } else { 15102 for (var i = array.length; --i >= 0;)
15030 top.push(val); 15103 if (array[i] == name)
15031 } 15104 return true;
15032 } else if (val !== skip) { 15105 return false;
15033 if (val instanceof Splice) { 15106 };
15034 ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); 15107
15035 } else { 15108 function find_if(func, array) {
15036 ret.push(val); 15109 for (var i = 0, n = array.length; i < n; ++i) {
15037 } 15110 if (func(array[i]))
15038 } 15111 return array[i];
15039 return is_last; 15112 }
15040 } 15113 };
15041 if (a instanceof Array) { 15114
15042 if (backwards) { 15115 function repeat_string(str, i) {
15043 for (i = a.length; --i >= 0; ) if (doit()) break; 15116 if (i <= 0) return "";
15044 ret.reverse(); 15117 if (i == 1) return str;
15045 top.reverse(); 15118 var d = repeat_string(str, i >> 1);
15119 d += d;
15120 if (i & 1) d += str;
15121 return d;
15122 };
15123
15124 function DefaultsError(msg, defs) {
15125 Error.call(this, msg);
15126 this.msg = msg;
15127 this.defs = defs;
15128 };
15129 DefaultsError.prototype = Object.create(Error.prototype);
15130 DefaultsError.prototype.constructor = DefaultsError;
15131
15132 DefaultsError.croak = function(msg, defs) {
15133 throw new DefaultsError(msg, defs);
15134 };
15135
15136 function defaults(args, defs, croak) {
15137 if (args === true)
15138 args = {};
15139 var ret = args || {};
15140 if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
15141 DefaultsError.croak("`" + i + "` is not a supported option", defs);
15142 for (var i in defs) if (defs.hasOwnProperty(i)) {
15143 ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
15144 }
15145 return ret;
15146 };
15147
15148 function merge(obj, ext) {
15149 for (var i in ext) if (ext.hasOwnProperty(i)) {
15150 obj[i] = ext[i];
15151 }
15152 return obj;
15153 };
15154
15155 function noop() {};
15156
15157 var MAP = (function(){
15158 function MAP(a, f, backwards) {
15159 var ret = [], top = [], i;
15160 function doit() {
15161 var val = f(a[i], i);
15162 var is_last = val instanceof Last;
15163 if (is_last) val = val.v;
15164 if (val instanceof AtTop) {
15165 val = val.v;
15166 if (val instanceof Splice) {
15167 top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
15046 } else { 15168 } else {
15047 for (i = 0; i < a.length; ++i) if (doit()) break; 15169 top.push(val);
15048 } 15170 }
15171 }
15172 else if (val !== skip) {
15173 if (val instanceof Splice) {
15174 ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
15175 } else {
15176 ret.push(val);
15177 }
15178 }
15179 return is_last;
15180 };
15181 if (a instanceof Array) {
15182 if (backwards) {
15183 for (i = a.length; --i >= 0;) if (doit()) break;
15184 ret.reverse();
15185 top.reverse();
15049 } else { 15186 } else {
15050 for (i in a) if (a.hasOwnProperty(i)) if (doit()) break; 15187 for (i = 0; i < a.length; ++i) if (doit()) break;
15051 } 15188 }
15052 return top.concat(ret); 15189 }
15053 } 15190 else {
15054 MAP.at_top = function(val) { 15191 for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
15055 return new AtTop(val); 15192 }
15056 }; 15193 return top.concat(ret);
15057 MAP.splice = function(val) { 15194 };
15058 return new Splice(val); 15195 MAP.at_top = function(val) { return new AtTop(val) };
15059 }; 15196 MAP.splice = function(val) { return new Splice(val) };
15060 MAP.last = function(val) { 15197 MAP.last = function(val) { return new Last(val) };
15061 return new Last(val); 15198 var skip = MAP.skip = {};
15062 }; 15199 function AtTop(val) { this.v = val };
15063 var skip = MAP.skip = {}; 15200 function Splice(val) { this.v = val };
15064 function AtTop(val) { 15201 function Last(val) { this.v = val };
15065 this.v = val; 15202 return MAP;
15066 } 15203 })();
15067 function Splice(val) { 15204
15068 this.v = val; 15205 function push_uniq(array, el) {
15069 } 15206 if (array.indexOf(el) < 0)
15070 function Last(val) { 15207 array.push(el);
15071 this.v = val; 15208 };
15072 } 15209
15073 return MAP; 15210 function string_template(text, props) {
15074 }(); 15211 return text.replace(/\{(.+?)\}/g, function(str, p){
15075 function push_uniq(array, el) { 15212 return props[p];
15076 if (array.indexOf(el) < 0) array.push(el); 15213 });
15077 } 15214 };
15078 function string_template(text, props) { 15215
15079 return text.replace(/\{(.+?)\}/g, function(str, p) { 15216 function remove(array, el) {
15080 return props[p]; 15217 for (var i = array.length; --i >= 0;) {
15081 }); 15218 if (array[i] === el) array.splice(i, 1);
15082 } 15219 }
15083 function remove(array, el) { 15220 };
15084 for (var i = array.length; --i >= 0; ) { 15221
15085 if (array[i] === el) array.splice(i, 1); 15222 function mergeSort(array, cmp) {
15086 } 15223 if (array.length < 2) return array.slice();
15087 } 15224 function merge(a, b) {
15088 function mergeSort(array, cmp) { 15225 var r = [], ai = 0, bi = 0, i = 0;
15089 if (array.length < 2) return array.slice(); 15226 while (ai < a.length && bi < b.length) {
15090 function merge(a, b) { 15227 cmp(a[ai], b[bi]) <= 0
15091 var r = [], ai = 0, bi = 0, i = 0; 15228 ? r[i++] = a[ai++]
15092 while (ai < a.length && bi < b.length) { 15229 : r[i++] = b[bi++];
15093 cmp(a[ai], b[bi]) <= 0 ? r[i++] = a[ai++] : r[i++] = b[bi++]; 15230 }
15094 } 15231 if (ai < a.length) r.push.apply(r, a.slice(ai));
15095 if (ai < a.length) r.push.apply(r, a.slice(ai)); 15232 if (bi < b.length) r.push.apply(r, b.slice(bi));
15096 if (bi < b.length) r.push.apply(r, b.slice(bi)); 15233 return r;
15097 return r; 15234 };
15098 } 15235 function _ms(a) {
15099 function _ms(a) { 15236 if (a.length <= 1)
15100 if (a.length <= 1) return a; 15237 return a;
15101 var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); 15238 var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
15102 left = _ms(left); 15239 left = _ms(left);
15103 right = _ms(right); 15240 right = _ms(right);
15104 return merge(left, right); 15241 return merge(left, right);
15105 } 15242 };
15106 return _ms(array); 15243 return _ms(array);
15107 } 15244 };
15108 function set_difference(a, b) { 15245
15109 return a.filter(function(el) { 15246 function set_difference(a, b) {
15110 return b.indexOf(el) < 0; 15247 return a.filter(function(el){
15111 }); 15248 return b.indexOf(el) < 0;
15112 } 15249 });
15113 function set_intersection(a, b) { 15250 };
15114 return a.filter(function(el) { 15251
15115 return b.indexOf(el) >= 0; 15252 function set_intersection(a, b) {
15116 }); 15253 return a.filter(function(el){
15117 } 15254 return b.indexOf(el) >= 0;
15118 function makePredicate(words) { 15255 });
15119 if (!(words instanceof Array)) words = words.split(" "); 15256 };
15120 var f = "", cats = []; 15257
15121 out: for (var i = 0; i < words.length; ++i) { 15258 // this function is taken from Acorn [1], written by Marijn Haverbeke
15122 for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) { 15259 // [1] https://github.com/marijnh/acorn
15260 function makePredicate(words) {
15261 if (!(words instanceof Array)) words = words.split(" ");
15262 var f = "", cats = [];
15263 out: for (var i = 0; i < words.length; ++i) {
15264 for (var j = 0; j < cats.length; ++j)
15265 if (cats[j][0].length == words[i].length) {
15123 cats[j].push(words[i]); 15266 cats[j].push(words[i]);
15124 continue out; 15267 continue out;
15125 } 15268 }
15126 cats.push([ words[i] ]); 15269 cats.push([words[i]]);
15127 } 15270 }
15128 function compareTo(arr) { 15271 function compareTo(arr) {
15129 if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; 15272 if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
15130 f += "switch(str){"; 15273 f += "switch(str){";
15131 for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; 15274 for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
15132 f += "return true}return false;"; 15275 f += "return true}return false;";
15133 } 15276 }
15134 if (cats.length > 3) { 15277 // When there are more than three length categories, an outer
15135 cats.sort(function(a, b) { 15278 // switch first dispatches on the lengths, to save on comparisons.
15136 return b.length - a.length; 15279 if (cats.length > 3) {
15280 cats.sort(function(a, b) {return b.length - a.length;});
15281 f += "switch(str.length){";
15282 for (var i = 0; i < cats.length; ++i) {
15283 var cat = cats[i];
15284 f += "case " + cat[0].length + ":";
15285 compareTo(cat);
15286 }
15287 f += "}";
15288 // Otherwise, simply generate a flat `switch` statement.
15289 } else {
15290 compareTo(words);
15291 }
15292 return new Function("str", f);
15293 };
15294
15295 function all(array, predicate) {
15296 for (var i = array.length; --i >= 0;)
15297 if (!predicate(array[i]))
15298 return false;
15299 return true;
15300 };
15301
15302 function Dictionary() {
15303 this._values = Object.create(null);
15304 this._size = 0;
15305 };
15306 Dictionary.prototype = {
15307 set: function(key, val) {
15308 if (!this.has(key)) ++this._size;
15309 this._values["$" + key] = val;
15310 return this;
15311 },
15312 add: function(key, val) {
15313 if (this.has(key)) {
15314 this.get(key).push(val);
15315 } else {
15316 this.set(key, [ val ]);
15317 }
15318 return this;
15319 },
15320 get: function(key) { return this._values["$" + key] },
15321 del: function(key) {
15322 if (this.has(key)) {
15323 --this._size;
15324 delete this._values["$" + key];
15325 }
15326 return this;
15327 },
15328 has: function(key) { return ("$" + key) in this._values },
15329 each: function(f) {
15330 for (var i in this._values)
15331 f(this._values[i], i.substr(1));
15332 },
15333 size: function() {
15334 return this._size;
15335 },
15336 map: function(f) {
15337 var ret = [];
15338 for (var i in this._values)
15339 ret.push(f(this._values[i], i.substr(1)));
15340 return ret;
15341 }
15342 };
15343
15344 /***********************************************************************
15345
15346 A JavaScript tokenizer / parser / beautifier / compressor.
15347 https://github.com/mishoo/UglifyJS2
15348
15349 -------------------------------- (C) ---------------------------------
15350
15351 Author: Mihai Bazon
15352 <mihai.bazon@gmail.com>
15353 http://mihai.bazon.net/blog
15354
15355 Distributed under the BSD license:
15356
15357 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15358
15359 Redistribution and use in source and binary forms, with or without
15360 modification, are permitted provided that the following conditions
15361 are met:
15362
15363 * Redistributions of source code must retain the above
15364 copyright notice, this list of conditions and the following
15365 disclaimer.
15366
15367 * Redistributions in binary form must reproduce the above
15368 copyright notice, this list of conditions and the following
15369 disclaimer in the documentation and/or other materials
15370 provided with the distribution.
15371
15372 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
15373 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15374 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15375 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
15376 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
15377 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
15378 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
15379 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
15380 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
15381 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
15382 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
15383 SUCH DAMAGE.
15384
15385 ***********************************************************************/
15386
15387 "use strict";
15388
15389 function DEFNODE(type, props, methods, base) {
15390 if (arguments.length < 4) base = AST_Node;
15391 if (!props) props = [];
15392 else props = props.split(/\s+/);
15393 var self_props = props;
15394 if (base && base.PROPS)
15395 props = props.concat(base.PROPS);
15396 var code = "return function AST_" + type + "(props){ if (props) { ";
15397 for (var i = props.length; --i >= 0;) {
15398 code += "this." + props[i] + " = props." + props[i] + ";";
15399 }
15400 var proto = base && new base;
15401 if (proto && proto.initialize || (methods && methods.initialize))
15402 code += "this.initialize();";
15403 code += "}}";
15404 var ctor = new Function(code)();
15405 if (proto) {
15406 ctor.prototype = proto;
15407 ctor.BASE = base;
15408 }
15409 if (base) base.SUBCLASSES.push(ctor);
15410 ctor.prototype.CTOR = ctor;
15411 ctor.PROPS = props || null;
15412 ctor.SELF_PROPS = self_props;
15413 ctor.SUBCLASSES = [];
15414 if (type) {
15415 ctor.prototype.TYPE = ctor.TYPE = type;
15416 }
15417 if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
15418 if (/^\$/.test(i)) {
15419 ctor[i.substr(1)] = methods[i];
15420 } else {
15421 ctor.prototype[i] = methods[i];
15422 }
15423 }
15424 ctor.DEFMETHOD = function(name, method) {
15425 this.prototype[name] = method;
15426 };
15427 return ctor;
15428 };
15429
15430 var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {
15431 }, null);
15432
15433 var AST_Node = DEFNODE("Node", "start end", {
15434 clone: function() {
15435 return new this.CTOR(this);
15436 },
15437 $documentation: "Base class of all AST nodes",
15438 $propdoc: {
15439 start: "[AST_Token] The first token of this node",
15440 end: "[AST_Token] The last token of this node"
15441 },
15442 _walk: function(visitor) {
15443 return visitor._visit(this);
15444 },
15445 walk: function(visitor) {
15446 return this._walk(visitor); // not sure the indirection will be any help
15447 }
15448 }, null);
15449
15450 AST_Node.warn_function = null;
15451 AST_Node.warn = function(txt, props) {
15452 if (AST_Node.warn_function)
15453 AST_Node.warn_function(string_template(txt, props));
15454 };
15455
15456 /* -----[ statements ]----- */
15457
15458 var AST_Statement = DEFNODE("Statement", null, {
15459 $documentation: "Base class of all statements",
15460 });
15461
15462 var AST_Debugger = DEFNODE("Debugger", null, {
15463 $documentation: "Represents a debugger statement",
15464 }, AST_Statement);
15465
15466 var AST_Directive = DEFNODE("Directive", "value scope", {
15467 $documentation: "Represents a directive, like \"use strict\";",
15468 $propdoc: {
15469 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
15470 scope: "[AST_Scope/S] The scope that this directive affects"
15471 },
15472 }, AST_Statement);
15473
15474 var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
15475 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
15476 $propdoc: {
15477 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
15478 },
15479 _walk: function(visitor) {
15480 return visitor._visit(this, function(){
15481 this.body._walk(visitor);
15482 });
15483 }
15484 }, AST_Statement);
15485
15486 function walk_body(node, visitor) {
15487 if (node.body instanceof AST_Statement) {
15488 node.body._walk(visitor);
15489 }
15490 else node.body.forEach(function(stat){
15491 stat._walk(visitor);
15492 });
15493 };
15494
15495 var AST_Block = DEFNODE("Block", "body", {
15496 $documentation: "A body of statements (usually bracketed)",
15497 $propdoc: {
15498 body: "[AST_Statement*] an array of statements"
15499 },
15500 _walk: function(visitor) {
15501 return visitor._visit(this, function(){
15502 walk_body(this, visitor);
15503 });
15504 }
15505 }, AST_Statement);
15506
15507 var AST_BlockStatement = DEFNODE("BlockStatement", null, {
15508 $documentation: "A block statement",
15509 }, AST_Block);
15510
15511 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
15512 $documentation: "The empty statement (empty block or simply a semicolon)",
15513 _walk: function(visitor) {
15514 return visitor._visit(this);
15515 }
15516 }, AST_Statement);
15517
15518 var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
15519 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
15520 $propdoc: {
15521 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
15522 },
15523 _walk: function(visitor) {
15524 return visitor._visit(this, function(){
15525 this.body._walk(visitor);
15526 });
15527 }
15528 }, AST_Statement);
15529
15530 var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
15531 $documentation: "Statement with a label",
15532 $propdoc: {
15533 label: "[AST_Label] a label definition"
15534 },
15535 _walk: function(visitor) {
15536 return visitor._visit(this, function(){
15537 this.label._walk(visitor);
15538 this.body._walk(visitor);
15539 });
15540 }
15541 }, AST_StatementWithBody);
15542
15543 var AST_IterationStatement = DEFNODE("IterationStatement", null, {
15544 $documentation: "Internal class. All loops inherit from it."
15545 }, AST_StatementWithBody);
15546
15547 var AST_DWLoop = DEFNODE("DWLoop", "condition", {
15548 $documentation: "Base class for do/while statements",
15549 $propdoc: {
15550 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
15551 },
15552 _walk: function(visitor) {
15553 return visitor._visit(this, function(){
15554 this.condition._walk(visitor);
15555 this.body._walk(visitor);
15556 });
15557 }
15558 }, AST_IterationStatement);
15559
15560 var AST_Do = DEFNODE("Do", null, {
15561 $documentation: "A `do` statement",
15562 }, AST_DWLoop);
15563
15564 var AST_While = DEFNODE("While", null, {
15565 $documentation: "A `while` statement",
15566 }, AST_DWLoop);
15567
15568 var AST_For = DEFNODE("For", "init condition step", {
15569 $documentation: "A `for` statement",
15570 $propdoc: {
15571 init: "[AST_Node?] the `for` initialization code, or null if empty",
15572 condition: "[AST_Node?] the `for` termination clause, or null if empty",
15573 step: "[AST_Node?] the `for` update clause, or null if empty"
15574 },
15575 _walk: function(visitor) {
15576 return visitor._visit(this, function(){
15577 if (this.init) this.init._walk(visitor);
15578 if (this.condition) this.condition._walk(visitor);
15579 if (this.step) this.step._walk(visitor);
15580 this.body._walk(visitor);
15581 });
15582 }
15583 }, AST_IterationStatement);
15584
15585 var AST_ForIn = DEFNODE("ForIn", "init name object", {
15586 $documentation: "A `for ... in` statement",
15587 $propdoc: {
15588 init: "[AST_Node] the `for/in` initialization code",
15589 name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
15590 object: "[AST_Node] the object that we're looping through"
15591 },
15592 _walk: function(visitor) {
15593 return visitor._visit(this, function(){
15594 this.init._walk(visitor);
15595 this.object._walk(visitor);
15596 this.body._walk(visitor);
15597 });
15598 }
15599 }, AST_IterationStatement);
15600
15601 var AST_With = DEFNODE("With", "expression", {
15602 $documentation: "A `with` statement",
15603 $propdoc: {
15604 expression: "[AST_Node] the `with` expression"
15605 },
15606 _walk: function(visitor) {
15607 return visitor._visit(this, function(){
15608 this.expression._walk(visitor);
15609 this.body._walk(visitor);
15610 });
15611 }
15612 }, AST_StatementWithBody);
15613
15614 /* -----[ scope and functions ]----- */
15615
15616 var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
15617 $documentation: "Base class for all statements introducing a lexical scope",
15618 $propdoc: {
15619 directives: "[string*/S] an array of directives declared in this scope",
15620 variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
15621 functions: "[Object/S] like `variables`, but only lists function declarations",
15622 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
15623 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
15624 parent_scope: "[AST_Scope?/S] link to the parent scope",
15625 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
15626 cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
15627 },
15628 }, AST_Block);
15629
15630 var AST_Toplevel = DEFNODE("Toplevel", "globals", {
15631 $documentation: "The toplevel scope",
15632 $propdoc: {
15633 globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
15634 },
15635 wrap_enclose: function(arg_parameter_pairs) {
15636 var self = this;
15637 var args = [];
15638 var parameters = [];
15639
15640 arg_parameter_pairs.forEach(function(pair) {
15641 var split = pair.split(":");
15642
15643 args.push(split[0]);
15644 parameters.push(split[1]);
15645 });
15646
15647 var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
15648 wrapped_tl = parse(wrapped_tl);
15649 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
15650 if (node instanceof AST_Directive && node.value == "$ORIG") {
15651 return MAP.splice(self.body);
15652 }
15653 }));
15654 return wrapped_tl;
15655 },
15656 wrap_commonjs: function(name, export_all) {
15657 var self = this;
15658 var to_export = [];
15659 if (export_all) {
15660 self.figure_out_scope();
15661 self.walk(new TreeWalker(function(node){
15662 if (node instanceof AST_SymbolDeclaration && node.definition().global) {
15663 if (!find_if(function(n){ return n.name == node.name }, to_export))
15664 to_export.push(node);
15665 }
15666 }));
15667 }
15668 var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
15669 wrapped_tl = parse(wrapped_tl);
15670 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
15671 if (node instanceof AST_SimpleStatement) {
15672 node = node.body;
15673 if (node instanceof AST_String) switch (node.getValue()) {
15674 case "$ORIG":
15675 return MAP.splice(self.body);
15676 case "$EXPORTS":
15677 var body = [];
15678 to_export.forEach(function(sym){
15679 body.push(new AST_SimpleStatement({
15680 body: new AST_Assign({
15681 left: new AST_Sub({
15682 expression: new AST_SymbolRef({ name: "exports" }),
15683 property: new AST_String({ value: sym.name }),
15684 }),
15685 operator: "=",
15686 right: new AST_SymbolRef(sym),
15687 }),
15688 }));
15689 });
15690 return MAP.splice(body);
15691 }
15692 }
15693 }));
15694 return wrapped_tl;
15695 }
15696 }, AST_Scope);
15697
15698 var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
15699 $documentation: "Base class for functions",
15700 $propdoc: {
15701 name: "[AST_SymbolDeclaration?] the name of this function",
15702 argnames: "[AST_SymbolFunarg*] array of function arguments",
15703 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
15704 },
15705 _walk: function(visitor) {
15706 return visitor._visit(this, function(){
15707 if (this.name) this.name._walk(visitor);
15708 this.argnames.forEach(function(arg){
15709 arg._walk(visitor);
15137 }); 15710 });
15138 f += "switch(str.length){"; 15711 walk_body(this, visitor);
15139 for (var i = 0; i < cats.length; ++i) { 15712 });
15140 var cat = cats[i]; 15713 }
15141 f += "case " + cat[0].length + ":"; 15714 }, AST_Scope);
15142 compareTo(cat); 15715
15143 } 15716 var AST_Accessor = DEFNODE("Accessor", null, {
15144 f += "}"; 15717 $documentation: "A setter/getter function. The `name` property is always null."
15718 }, AST_Lambda);
15719
15720 var AST_Function = DEFNODE("Function", null, {
15721 $documentation: "A function expression"
15722 }, AST_Lambda);
15723
15724 var AST_Defun = DEFNODE("Defun", null, {
15725 $documentation: "A function definition"
15726 }, AST_Lambda);
15727
15728 /* -----[ JUMPS ]----- */
15729
15730 var AST_Jump = DEFNODE("Jump", null, {
15731 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
15732 }, AST_Statement);
15733
15734 var AST_Exit = DEFNODE("Exit", "value", {
15735 $documentation: "Base class for “exits” (`return` and `throw`)",
15736 $propdoc: {
15737 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
15738 },
15739 _walk: function(visitor) {
15740 return visitor._visit(this, this.value && function(){
15741 this.value._walk(visitor);
15742 });
15743 }
15744 }, AST_Jump);
15745
15746 var AST_Return = DEFNODE("Return", null, {
15747 $documentation: "A `return` statement"
15748 }, AST_Exit);
15749
15750 var AST_Throw = DEFNODE("Throw", null, {
15751 $documentation: "A `throw` statement"
15752 }, AST_Exit);
15753
15754 var AST_LoopControl = DEFNODE("LoopControl", "label", {
15755 $documentation: "Base class for loop control statements (`break` and `continue`)",
15756 $propdoc: {
15757 label: "[AST_LabelRef?] the label, or null if none",
15758 },
15759 _walk: function(visitor) {
15760 return visitor._visit(this, this.label && function(){
15761 this.label._walk(visitor);
15762 });
15763 }
15764 }, AST_Jump);
15765
15766 var AST_Break = DEFNODE("Break", null, {
15767 $documentation: "A `break` statement"
15768 }, AST_LoopControl);
15769
15770 var AST_Continue = DEFNODE("Continue", null, {
15771 $documentation: "A `continue` statement"
15772 }, AST_LoopControl);
15773
15774 /* -----[ IF ]----- */
15775
15776 var AST_If = DEFNODE("If", "condition alternative", {
15777 $documentation: "A `if` statement",
15778 $propdoc: {
15779 condition: "[AST_Node] the `if` condition",
15780 alternative: "[AST_Statement?] the `else` part, or null if not present"
15781 },
15782 _walk: function(visitor) {
15783 return visitor._visit(this, function(){
15784 this.condition._walk(visitor);
15785 this.body._walk(visitor);
15786 if (this.alternative) this.alternative._walk(visitor);
15787 });
15788 }
15789 }, AST_StatementWithBody);
15790
15791 /* -----[ SWITCH ]----- */
15792
15793 var AST_Switch = DEFNODE("Switch", "expression", {
15794 $documentation: "A `switch` statement",
15795 $propdoc: {
15796 expression: "[AST_Node] the `switch` “discriminant”"
15797 },
15798 _walk: function(visitor) {
15799 return visitor._visit(this, function(){
15800 this.expression._walk(visitor);
15801 walk_body(this, visitor);
15802 });
15803 }
15804 }, AST_Block);
15805
15806 var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
15807 $documentation: "Base class for `switch` branches",
15808 }, AST_Block);
15809
15810 var AST_Default = DEFNODE("Default", null, {
15811 $documentation: "A `default` switch branch",
15812 }, AST_SwitchBranch);
15813
15814 var AST_Case = DEFNODE("Case", "expression", {
15815 $documentation: "A `case` switch branch",
15816 $propdoc: {
15817 expression: "[AST_Node] the `case` expression"
15818 },
15819 _walk: function(visitor) {
15820 return visitor._visit(this, function(){
15821 this.expression._walk(visitor);
15822 walk_body(this, visitor);
15823 });
15824 }
15825 }, AST_SwitchBranch);
15826
15827 /* -----[ EXCEPTIONS ]----- */
15828
15829 var AST_Try = DEFNODE("Try", "bcatch bfinally", {
15830 $documentation: "A `try` statement",
15831 $propdoc: {
15832 bcatch: "[AST_Catch?] the catch block, or null if not present",
15833 bfinally: "[AST_Finally?] the finally block, or null if not present"
15834 },
15835 _walk: function(visitor) {
15836 return visitor._visit(this, function(){
15837 walk_body(this, visitor);
15838 if (this.bcatch) this.bcatch._walk(visitor);
15839 if (this.bfinally) this.bfinally._walk(visitor);
15840 });
15841 }
15842 }, AST_Block);
15843
15844 var AST_Catch = DEFNODE("Catch", "argname", {
15845 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
15846 $propdoc: {
15847 argname: "[AST_SymbolCatch] symbol for the exception"
15848 },
15849 _walk: function(visitor) {
15850 return visitor._visit(this, function(){
15851 this.argname._walk(visitor);
15852 walk_body(this, visitor);
15853 });
15854 }
15855 }, AST_Block);
15856
15857 var AST_Finally = DEFNODE("Finally", null, {
15858 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
15859 }, AST_Block);
15860
15861 /* -----[ VAR/CONST ]----- */
15862
15863 var AST_Definitions = DEFNODE("Definitions", "definitions", {
15864 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
15865 $propdoc: {
15866 definitions: "[AST_VarDef*] array of variable definitions"
15867 },
15868 _walk: function(visitor) {
15869 return visitor._visit(this, function(){
15870 this.definitions.forEach(function(def){
15871 def._walk(visitor);
15872 });
15873 });
15874 }
15875 }, AST_Statement);
15876
15877 var AST_Var = DEFNODE("Var", null, {
15878 $documentation: "A `var` statement"
15879 }, AST_Definitions);
15880
15881 var AST_Const = DEFNODE("Const", null, {
15882 $documentation: "A `const` statement"
15883 }, AST_Definitions);
15884
15885 var AST_VarDef = DEFNODE("VarDef", "name value", {
15886 $documentation: "A variable declaration; only appears in a AST_Definitions node",
15887 $propdoc: {
15888 name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
15889 value: "[AST_Node?] initializer, or null of there's no initializer"
15890 },
15891 _walk: function(visitor) {
15892 return visitor._visit(this, function(){
15893 this.name._walk(visitor);
15894 if (this.value) this.value._walk(visitor);
15895 });
15896 }
15897 });
15898
15899 /* -----[ OTHER ]----- */
15900
15901 var AST_Call = DEFNODE("Call", "expression args", {
15902 $documentation: "A function call expression",
15903 $propdoc: {
15904 expression: "[AST_Node] expression to invoke as function",
15905 args: "[AST_Node*] array of arguments"
15906 },
15907 _walk: function(visitor) {
15908 return visitor._visit(this, function(){
15909 this.expression._walk(visitor);
15910 this.args.forEach(function(arg){
15911 arg._walk(visitor);
15912 });
15913 });
15914 }
15915 });
15916
15917 var AST_New = DEFNODE("New", null, {
15918 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
15919 }, AST_Call);
15920
15921 var AST_Seq = DEFNODE("Seq", "car cdr", {
15922 $documentation: "A sequence expression (two comma-separated expressions)",
15923 $propdoc: {
15924 car: "[AST_Node] first element in sequence",
15925 cdr: "[AST_Node] second element in sequence"
15926 },
15927 $cons: function(x, y) {
15928 var seq = new AST_Seq(x);
15929 seq.car = x;
15930 seq.cdr = y;
15931 return seq;
15932 },
15933 $from_array: function(array) {
15934 if (array.length == 0) return null;
15935 if (array.length == 1) return array[0].clone();
15936 var list = null;
15937 for (var i = array.length; --i >= 0;) {
15938 list = AST_Seq.cons(array[i], list);
15939 }
15940 var p = list;
15941 while (p) {
15942 if (p.cdr && !p.cdr.cdr) {
15943 p.cdr = p.cdr.car;
15944 break;
15945 }
15946 p = p.cdr;
15947 }
15948 return list;
15949 },
15950 to_array: function() {
15951 var p = this, a = [];
15952 while (p) {
15953 a.push(p.car);
15954 if (p.cdr && !(p.cdr instanceof AST_Seq)) {
15955 a.push(p.cdr);
15956 break;
15957 }
15958 p = p.cdr;
15959 }
15960 return a;
15961 },
15962 add: function(node) {
15963 var p = this;
15964 while (p) {
15965 if (!(p.cdr instanceof AST_Seq)) {
15966 var cell = AST_Seq.cons(p.cdr, node);
15967 return p.cdr = cell;
15968 }
15969 p = p.cdr;
15970 }
15971 },
15972 _walk: function(visitor) {
15973 return visitor._visit(this, function(){
15974 this.car._walk(visitor);
15975 if (this.cdr) this.cdr._walk(visitor);
15976 });
15977 }
15978 });
15979
15980 var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
15981 $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
15982 $propdoc: {
15983 expression: "[AST_Node] the “container” expression",
15984 property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
15985 }
15986 });
15987
15988 var AST_Dot = DEFNODE("Dot", null, {
15989 $documentation: "A dotted property access expression",
15990 _walk: function(visitor) {
15991 return visitor._visit(this, function(){
15992 this.expression._walk(visitor);
15993 });
15994 }
15995 }, AST_PropAccess);
15996
15997 var AST_Sub = DEFNODE("Sub", null, {
15998 $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
15999 _walk: function(visitor) {
16000 return visitor._visit(this, function(){
16001 this.expression._walk(visitor);
16002 this.property._walk(visitor);
16003 });
16004 }
16005 }, AST_PropAccess);
16006
16007 var AST_Unary = DEFNODE("Unary", "operator expression", {
16008 $documentation: "Base class for unary expressions",
16009 $propdoc: {
16010 operator: "[string] the operator",
16011 expression: "[AST_Node] expression that this unary operator applies to"
16012 },
16013 _walk: function(visitor) {
16014 return visitor._visit(this, function(){
16015 this.expression._walk(visitor);
16016 });
16017 }
16018 });
16019
16020 var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
16021 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
16022 }, AST_Unary);
16023
16024 var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
16025 $documentation: "Unary postfix expression, i.e. `i++`"
16026 }, AST_Unary);
16027
16028 var AST_Binary = DEFNODE("Binary", "left operator right", {
16029 $documentation: "Binary expression, i.e. `a + b`",
16030 $propdoc: {
16031 left: "[AST_Node] left-hand side expression",
16032 operator: "[string] the operator",
16033 right: "[AST_Node] right-hand side expression"
16034 },
16035 _walk: function(visitor) {
16036 return visitor._visit(this, function(){
16037 this.left._walk(visitor);
16038 this.right._walk(visitor);
16039 });
16040 }
16041 });
16042
16043 var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
16044 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
16045 $propdoc: {
16046 condition: "[AST_Node]",
16047 consequent: "[AST_Node]",
16048 alternative: "[AST_Node]"
16049 },
16050 _walk: function(visitor) {
16051 return visitor._visit(this, function(){
16052 this.condition._walk(visitor);
16053 this.consequent._walk(visitor);
16054 this.alternative._walk(visitor);
16055 });
16056 }
16057 });
16058
16059 var AST_Assign = DEFNODE("Assign", null, {
16060 $documentation: "An assignment expression — `a = b + 5`",
16061 }, AST_Binary);
16062
16063 /* -----[ LITERALS ]----- */
16064
16065 var AST_Array = DEFNODE("Array", "elements", {
16066 $documentation: "An array literal",
16067 $propdoc: {
16068 elements: "[AST_Node*] array of elements"
16069 },
16070 _walk: function(visitor) {
16071 return visitor._visit(this, function(){
16072 this.elements.forEach(function(el){
16073 el._walk(visitor);
16074 });
16075 });
16076 }
16077 });
16078
16079 var AST_Object = DEFNODE("Object", "properties", {
16080 $documentation: "An object literal",
16081 $propdoc: {
16082 properties: "[AST_ObjectProperty*] array of properties"
16083 },
16084 _walk: function(visitor) {
16085 return visitor._visit(this, function(){
16086 this.properties.forEach(function(prop){
16087 prop._walk(visitor);
16088 });
16089 });
16090 }
16091 });
16092
16093 var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
16094 $documentation: "Base class for literal object properties",
16095 $propdoc: {
16096 key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
16097 value: "[AST_Node] property value. For setters and getters this is an AST_Function."
16098 },
16099 _walk: function(visitor) {
16100 return visitor._visit(this, function(){
16101 this.value._walk(visitor);
16102 });
16103 }
16104 });
16105
16106 var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
16107 $documentation: "A key: value object property",
16108 }, AST_ObjectProperty);
16109
16110 var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
16111 $documentation: "An object setter property",
16112 }, AST_ObjectProperty);
16113
16114 var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
16115 $documentation: "An object getter property",
16116 }, AST_ObjectProperty);
16117
16118 var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
16119 $propdoc: {
16120 name: "[string] name of this symbol",
16121 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
16122 thedef: "[SymbolDef/S] the definition of this symbol"
16123 },
16124 $documentation: "Base class for all symbols",
16125 });
16126
16127 var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
16128 $documentation: "The name of a property accessor (setter/getter function)"
16129 }, AST_Symbol);
16130
16131 var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
16132 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
16133 $propdoc: {
16134 init: "[AST_Node*/S] array of initializers for this declaration."
16135 }
16136 }, AST_Symbol);
16137
16138 var AST_SymbolVar = DEFNODE("SymbolVar", null, {
16139 $documentation: "Symbol defining a variable",
16140 }, AST_SymbolDeclaration);
16141
16142 var AST_SymbolConst = DEFNODE("SymbolConst", null, {
16143 $documentation: "A constant declaration"
16144 }, AST_SymbolDeclaration);
16145
16146 var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
16147 $documentation: "Symbol naming a function argument",
16148 }, AST_SymbolVar);
16149
16150 var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
16151 $documentation: "Symbol defining a function",
16152 }, AST_SymbolDeclaration);
16153
16154 var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
16155 $documentation: "Symbol naming a function expression",
16156 }, AST_SymbolDeclaration);
16157
16158 var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
16159 $documentation: "Symbol naming the exception in catch",
16160 }, AST_SymbolDeclaration);
16161
16162 var AST_Label = DEFNODE("Label", "references", {
16163 $documentation: "Symbol naming a label (declaration)",
16164 $propdoc: {
16165 references: "[AST_LoopControl*] a list of nodes referring to this label"
16166 },
16167 initialize: function() {
16168 this.references = [];
16169 this.thedef = this;
16170 }
16171 }, AST_Symbol);
16172
16173 var AST_SymbolRef = DEFNODE("SymbolRef", null, {
16174 $documentation: "Reference to some symbol (not definition/declaration)",
16175 }, AST_Symbol);
16176
16177 var AST_LabelRef = DEFNODE("LabelRef", null, {
16178 $documentation: "Reference to a label symbol",
16179 }, AST_Symbol);
16180
16181 var AST_This = DEFNODE("This", null, {
16182 $documentation: "The `this` symbol",
16183 }, AST_Symbol);
16184
16185 var AST_Constant = DEFNODE("Constant", null, {
16186 $documentation: "Base class for all constants",
16187 getValue: function() {
16188 return this.value;
16189 }
16190 });
16191
16192 var AST_String = DEFNODE("String", "value", {
16193 $documentation: "A string literal",
16194 $propdoc: {
16195 value: "[string] the contents of this string"
16196 }
16197 }, AST_Constant);
16198
16199 var AST_Number = DEFNODE("Number", "value", {
16200 $documentation: "A number literal",
16201 $propdoc: {
16202 value: "[number] the numeric value"
16203 }
16204 }, AST_Constant);
16205
16206 var AST_RegExp = DEFNODE("RegExp", "value", {
16207 $documentation: "A regexp literal",
16208 $propdoc: {
16209 value: "[RegExp] the actual regexp"
16210 }
16211 }, AST_Constant);
16212
16213 var AST_Atom = DEFNODE("Atom", null, {
16214 $documentation: "Base class for atoms",
16215 }, AST_Constant);
16216
16217 var AST_Null = DEFNODE("Null", null, {
16218 $documentation: "The `null` atom",
16219 value: null
16220 }, AST_Atom);
16221
16222 var AST_NaN = DEFNODE("NaN", null, {
16223 $documentation: "The impossible value",
16224 value: 0/0
16225 }, AST_Atom);
16226
16227 var AST_Undefined = DEFNODE("Undefined", null, {
16228 $documentation: "The `undefined` value",
16229 value: (function(){}())
16230 }, AST_Atom);
16231
16232 var AST_Hole = DEFNODE("Hole", null, {
16233 $documentation: "A hole in an array",
16234 value: (function(){}())
16235 }, AST_Atom);
16236
16237 var AST_Infinity = DEFNODE("Infinity", null, {
16238 $documentation: "The `Infinity` value",
16239 value: 1/0
16240 }, AST_Atom);
16241
16242 var AST_Boolean = DEFNODE("Boolean", null, {
16243 $documentation: "Base class for booleans",
16244 }, AST_Atom);
16245
16246 var AST_False = DEFNODE("False", null, {
16247 $documentation: "The `false` atom",
16248 value: false
16249 }, AST_Boolean);
16250
16251 var AST_True = DEFNODE("True", null, {
16252 $documentation: "The `true` atom",
16253 value: true
16254 }, AST_Boolean);
16255
16256 /* -----[ TreeWalker ]----- */
16257
16258 function TreeWalker(callback) {
16259 this.visit = callback;
16260 this.stack = [];
16261 };
16262 TreeWalker.prototype = {
16263 _visit: function(node, descend) {
16264 this.stack.push(node);
16265 var ret = this.visit(node, descend ? function(){
16266 descend.call(node);
16267 } : noop);
16268 if (!ret && descend) {
16269 descend.call(node);
16270 }
16271 this.stack.pop();
16272 return ret;
16273 },
16274 parent: function(n) {
16275 return this.stack[this.stack.length - 2 - (n || 0)];
16276 },
16277 push: function (node) {
16278 this.stack.push(node);
16279 },
16280 pop: function() {
16281 return this.stack.pop();
16282 },
16283 self: function() {
16284 return this.stack[this.stack.length - 1];
16285 },
16286 find_parent: function(type) {
16287 var stack = this.stack;
16288 for (var i = stack.length; --i >= 0;) {
16289 var x = stack[i];
16290 if (x instanceof type) return x;
16291 }
16292 },
16293 has_directive: function(type) {
16294 return this.find_parent(AST_Scope).has_directive(type);
16295 },
16296 in_boolean_context: function() {
16297 var stack = this.stack;
16298 var i = stack.length, self = stack[--i];
16299 while (i > 0) {
16300 var p = stack[--i];
16301 if ((p instanceof AST_If && p.condition === self) ||
16302 (p instanceof AST_Conditional && p.condition === self) ||
16303 (p instanceof AST_DWLoop && p.condition === self) ||
16304 (p instanceof AST_For && p.condition === self) ||
16305 (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
16306 {
16307 return true;
16308 }
16309 if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
16310 return false;
16311 self = p;
16312 }
16313 },
16314 loopcontrol_target: function(label) {
16315 var stack = this.stack;
16316 if (label) for (var i = stack.length; --i >= 0;) {
16317 var x = stack[i];
16318 if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
16319 return x.body;
16320 }
16321 } else for (var i = stack.length; --i >= 0;) {
16322 var x = stack[i];
16323 if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
16324 return x;
16325 }
16326 }
16327 };
16328
16329 /***********************************************************************
16330
16331 A JavaScript tokenizer / parser / beautifier / compressor.
16332 https://github.com/mishoo/UglifyJS2
16333
16334 -------------------------------- (C) ---------------------------------
16335
16336 Author: Mihai Bazon
16337 <mihai.bazon@gmail.com>
16338 http://mihai.bazon.net/blog
16339
16340 Distributed under the BSD license:
16341
16342 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
16343 Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
16344
16345 Redistribution and use in source and binary forms, with or without
16346 modification, are permitted provided that the following conditions
16347 are met:
16348
16349 * Redistributions of source code must retain the above
16350 copyright notice, this list of conditions and the following
16351 disclaimer.
16352
16353 * Redistributions in binary form must reproduce the above
16354 copyright notice, this list of conditions and the following
16355 disclaimer in the documentation and/or other materials
16356 provided with the distribution.
16357
16358 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
16359 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16360 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16361 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
16362 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
16363 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16364 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
16365 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16366 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
16367 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
16368 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16369 SUCH DAMAGE.
16370
16371 ***********************************************************************/
16372
16373 "use strict";
16374
16375 var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
16376 var KEYWORDS_ATOM = 'false null true';
16377 var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield'
16378 + " " + KEYWORDS_ATOM + " " + KEYWORDS;
16379 var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
16380
16381 KEYWORDS = makePredicate(KEYWORDS);
16382 RESERVED_WORDS = makePredicate(RESERVED_WORDS);
16383 KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
16384 KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
16385
16386 var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
16387
16388 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
16389 var RE_OCT_NUMBER = /^0[0-7]+$/;
16390 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
16391
16392 var OPERATORS = makePredicate([
16393 "in",
16394 "instanceof",
16395 "typeof",
16396 "new",
16397 "void",
16398 "delete",
16399 "++",
16400 "--",
16401 "+",
16402 "-",
16403 "!",
16404 "~",
16405 "&",
16406 "|",
16407 "^",
16408 "*",
16409 "/",
16410 "%",
16411 ">>",
16412 "<<",
16413 ">>>",
16414 "<",
16415 ">",
16416 "<=",
16417 ">=",
16418 "==",
16419 "===",
16420 "!=",
16421 "!==",
16422 "?",
16423 "=",
16424 "+=",
16425 "-=",
16426 "/=",
16427 "*=",
16428 "%=",
16429 ">>=",
16430 "<<=",
16431 ">>>=",
16432 "|=",
16433 "^=",
16434 "&=",
16435 "&&",
16436 "||"
16437 ]);
16438
16439 var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
16440
16441 var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
16442
16443 var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
16444
16445 var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
16446
16447 /* -----[ Tokenizer ]----- */
16448
16449 // regexps adapted from http://xregexp.com/plugins/#unicode
16450 var UNICODE = {
16451 letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
16452 non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
16453 space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
16454 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
16455 };
16456
16457 function is_letter(code) {
16458 return (code >= 97 && code <= 122)
16459 || (code >= 65 && code <= 90)
16460 || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
16461 };
16462
16463 function is_digit(code) {
16464 return code >= 48 && code <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
16465 };
16466
16467 function is_alphanumeric_char(code) {
16468 return is_digit(code) || is_letter(code);
16469 };
16470
16471 function is_unicode_combining_mark(ch) {
16472 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
16473 };
16474
16475 function is_unicode_connector_punctuation(ch) {
16476 return UNICODE.connector_punctuation.test(ch);
16477 };
16478
16479 function is_identifier(name) {
16480 return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
16481 };
16482
16483 function is_identifier_start(code) {
16484 return code == 36 || code == 95 || is_letter(code);
16485 };
16486
16487 function is_identifier_char(ch) {
16488 var code = ch.charCodeAt(0);
16489 return is_identifier_start(code)
16490 || is_digit(code)
16491 || code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
16492 || code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
16493 || is_unicode_combining_mark(ch)
16494 || is_unicode_connector_punctuation(ch)
16495 ;
16496 };
16497
16498 function is_identifier_string(str){
16499 var i = str.length;
16500 if (i == 0) return false;
16501 if (!is_identifier_start(str.charCodeAt(0))) return false;
16502 while (--i >= 0) {
16503 if (!is_identifier_char(str.charAt(i)))
16504 return false;
16505 }
16506 return true;
16507 };
16508
16509 function parse_js_number(num) {
16510 if (RE_HEX_NUMBER.test(num)) {
16511 return parseInt(num.substr(2), 16);
16512 } else if (RE_OCT_NUMBER.test(num)) {
16513 return parseInt(num.substr(1), 8);
16514 } else if (RE_DEC_NUMBER.test(num)) {
16515 return parseFloat(num);
16516 }
16517 };
16518
16519 function JS_Parse_Error(message, line, col, pos) {
16520 this.message = message;
16521 this.line = line;
16522 this.col = col;
16523 this.pos = pos;
16524 this.stack = new Error().stack;
16525 };
16526
16527 JS_Parse_Error.prototype.toString = function() {
16528 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
16529 };
16530
16531 function js_error(message, filename, line, col, pos) {
16532 throw new JS_Parse_Error(message, line, col, pos);
16533 };
16534
16535 function is_token(token, type, val) {
16536 return token.type == type && (val == null || token.value == val);
16537 };
16538
16539 var EX_EOF = {};
16540
16541 function tokenizer($TEXT, filename, html5_comments) {
16542
16543 var S = {
16544 text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''),
16545 filename : filename,
16546 pos : 0,
16547 tokpos : 0,
16548 line : 1,
16549 tokline : 0,
16550 col : 0,
16551 tokcol : 0,
16552 newline_before : false,
16553 regex_allowed : false,
16554 comments_before : []
16555 };
16556
16557 function peek() { return S.text.charAt(S.pos); };
16558
16559 function next(signal_eof, in_string) {
16560 var ch = S.text.charAt(S.pos++);
16561 if (signal_eof && !ch)
16562 throw EX_EOF;
16563 if (ch == "\n") {
16564 S.newline_before = S.newline_before || !in_string;
16565 ++S.line;
16566 S.col = 0;
15145 } else { 16567 } else {
15146 compareTo(words); 16568 ++S.col;
15147 } 16569 }
15148 return new Function("str", f); 16570 return ch;
15149 } 16571 };
15150 function all(array, predicate) { 16572
15151 for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false; 16573 function forward(i) {
15152 return true; 16574 while (i-- > 0) next();
15153 } 16575 };
15154 function Dictionary() { 16576
15155 this._values = Object.create(null); 16577 function looking_at(str) {
15156 this._size = 0; 16578 return S.text.substr(S.pos, str.length) == str;
15157 } 16579 };
15158 Dictionary.prototype = { 16580
15159 set: function(key, val) { 16581 function find(what, signal_eof) {
15160 if (!this.has(key)) ++this._size; 16582 var pos = S.text.indexOf(what, S.pos);
15161 this._values["$" + key] = val; 16583 if (signal_eof && pos == -1) throw EX_EOF;
15162 return this; 16584 return pos;
15163 }, 16585 };
15164 add: function(key, val) { 16586
15165 if (this.has(key)) { 16587 function start_token() {
15166 this.get(key).push(val); 16588 S.tokline = S.line;
15167 } else { 16589 S.tokcol = S.col;
15168 this.set(key, [ val ]); 16590 S.tokpos = S.pos;
15169 } 16591 };
15170 return this; 16592
15171 }, 16593 var prev_was_dot = false;
15172 get: function(key) { 16594 function token(type, value, is_comment) {
15173 return this._values["$" + key]; 16595 S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
15174 }, 16596 (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
15175 del: function(key) { 16597 (type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
15176 if (this.has(key)) { 16598 prev_was_dot = (type == "punc" && value == ".");
15177 --this._size; 16599 var ret = {
15178 delete this._values["$" + key]; 16600 type : type,
15179 } 16601 value : value,
15180 return this; 16602 line : S.tokline,
15181 }, 16603 col : S.tokcol,
15182 has: function(key) { 16604 pos : S.tokpos,
15183 return "$" + key in this._values; 16605 endpos : S.pos,
15184 }, 16606 nlb : S.newline_before,
15185 each: function(f) { 16607 file : filename
15186 for (var i in this._values) f(this._values[i], i.substr(1));
15187 },
15188 size: function() {
15189 return this._size;
15190 },
15191 map: function(f) {
15192 var ret = [];
15193 for (var i in this._values) ret.push(f(this._values[i], i.substr(1)));
15194 return ret;
15195 }
15196 };
15197 "use strict";
15198 function DEFNODE(type, props, methods, base) {
15199 if (arguments.length < 4) base = AST_Node;
15200 if (!props) props = []; else props = props.split(/\s+/);
15201 var self_props = props;
15202 if (base && base.PROPS) props = props.concat(base.PROPS);
15203 var code = "return function AST_" + type + "(props){ if (props) { ";
15204 for (var i = props.length; --i >= 0; ) {
15205 code += "this." + props[i] + " = props." + props[i] + ";";
15206 }
15207 var proto = base && new base();
15208 if (proto && proto.initialize || methods && methods.initialize) code += "this.initialize();";
15209 code += "}}";
15210 var ctor = new Function(code)();
15211 if (proto) {
15212 ctor.prototype = proto;
15213 ctor.BASE = base;
15214 }
15215 if (base) base.SUBCLASSES.push(ctor);
15216 ctor.prototype.CTOR = ctor;
15217 ctor.PROPS = props || null;
15218 ctor.SELF_PROPS = self_props;
15219 ctor.SUBCLASSES = [];
15220 if (type) {
15221 ctor.prototype.TYPE = ctor.TYPE = type;
15222 }
15223 if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
15224 if (/^\$/.test(i)) {
15225 ctor[i.substr(1)] = methods[i];
15226 } else {
15227 ctor.prototype[i] = methods[i];
15228 }
15229 }
15230 ctor.DEFMETHOD = function(name, method) {
15231 this.prototype[name] = method;
15232 }; 16608 };
15233 return ctor; 16609 if (!is_comment) {
15234 } 16610 ret.comments_before = S.comments_before;
15235 var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {}, null); 16611 S.comments_before = [];
15236 var AST_Node = DEFNODE("Node", "start end", { 16612 // make note of any newlines in the comments that came before
15237 clone: function() { 16613 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
15238 return new this.CTOR(this); 16614 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
15239 }, 16615 }
15240 $documentation: "Base class of all AST nodes", 16616 }
15241 $propdoc: { 16617 S.newline_before = false;
15242 start: "[AST_Token] The first token of this node", 16618 return new AST_Token(ret);
15243 end: "[AST_Token] The last token of this node" 16619 };
15244 }, 16620
15245 _walk: function(visitor) { 16621 function skip_whitespace() {
15246 return visitor._visit(this); 16622 while (WHITESPACE_CHARS(peek()))
15247 },
15248 walk: function(visitor) {
15249 return this._walk(visitor);
15250 }
15251 }, null);
15252 AST_Node.warn_function = null;
15253 AST_Node.warn = function(txt, props) {
15254 if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props));
15255 };
15256 var AST_Statement = DEFNODE("Statement", null, {
15257 $documentation: "Base class of all statements"
15258 });
15259 var AST_Debugger = DEFNODE("Debugger", null, {
15260 $documentation: "Represents a debugger statement"
15261 }, AST_Statement);
15262 var AST_Directive = DEFNODE("Directive", "value scope", {
15263 $documentation: 'Represents a directive, like "use strict";',
15264 $propdoc: {
15265 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
15266 scope: "[AST_Scope/S] The scope that this directive affects"
15267 }
15268 }, AST_Statement);
15269 var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
15270 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
15271 $propdoc: {
15272 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
15273 },
15274 _walk: function(visitor) {
15275 return visitor._visit(this, function() {
15276 this.body._walk(visitor);
15277 });
15278 }
15279 }, AST_Statement);
15280 function walk_body(node, visitor) {
15281 if (node.body instanceof AST_Statement) {
15282 node.body._walk(visitor);
15283 } else node.body.forEach(function(stat) {
15284 stat._walk(visitor);
15285 });
15286 }
15287 var AST_Block = DEFNODE("Block", "body", {
15288 $documentation: "A body of statements (usually bracketed)",
15289 $propdoc: {
15290 body: "[AST_Statement*] an array of statements"
15291 },
15292 _walk: function(visitor) {
15293 return visitor._visit(this, function() {
15294 walk_body(this, visitor);
15295 });
15296 }
15297 }, AST_Statement);
15298 var AST_BlockStatement = DEFNODE("BlockStatement", null, {
15299 $documentation: "A block statement"
15300 }, AST_Block);
15301 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
15302 $documentation: "The empty statement (empty block or simply a semicolon)",
15303 _walk: function(visitor) {
15304 return visitor._visit(this);
15305 }
15306 }, AST_Statement);
15307 var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
15308 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
15309 $propdoc: {
15310 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
15311 },
15312 _walk: function(visitor) {
15313 return visitor._visit(this, function() {
15314 this.body._walk(visitor);
15315 });
15316 }
15317 }, AST_Statement);
15318 var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
15319 $documentation: "Statement with a label",
15320 $propdoc: {
15321 label: "[AST_Label] a label definition"
15322 },
15323 _walk: function(visitor) {
15324 return visitor._visit(this, function() {
15325 this.label._walk(visitor);
15326 this.body._walk(visitor);
15327 });
15328 }
15329 }, AST_StatementWithBody);
15330 var AST_DWLoop = DEFNODE("DWLoop", "condition", {
15331 $documentation: "Base class for do/while statements",
15332 $propdoc: {
15333 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
15334 },
15335 _walk: function(visitor) {
15336 return visitor._visit(this, function() {
15337 this.condition._walk(visitor);
15338 this.body._walk(visitor);
15339 });
15340 }
15341 }, AST_StatementWithBody);
15342 var AST_Do = DEFNODE("Do", null, {
15343 $documentation: "A `do` statement"
15344 }, AST_DWLoop);
15345 var AST_While = DEFNODE("While", null, {
15346 $documentation: "A `while` statement"
15347 }, AST_DWLoop);
15348 var AST_For = DEFNODE("For", "init condition step", {
15349 $documentation: "A `for` statement",
15350 $propdoc: {
15351 init: "[AST_Node?] the `for` initialization code, or null if empty",
15352 condition: "[AST_Node?] the `for` termination clause, or null if empty",
15353 step: "[AST_Node?] the `for` update clause, or null if empty"
15354 },
15355 _walk: function(visitor) {
15356 return visitor._visit(this, function() {
15357 if (this.init) this.init._walk(visitor);
15358 if (this.condition) this.condition._walk(visitor);
15359 if (this.step) this.step._walk(visitor);
15360 this.body._walk(visitor);
15361 });
15362 }
15363 }, AST_StatementWithBody);
15364 var AST_ForIn = DEFNODE("ForIn", "init name object", {
15365 $documentation: "A `for ... in` statement",
15366 $propdoc: {
15367 init: "[AST_Node] the `for/in` initialization code",
15368 name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
15369 object: "[AST_Node] the object that we're looping through"
15370 },
15371 _walk: function(visitor) {
15372 return visitor._visit(this, function() {
15373 this.init._walk(visitor);
15374 this.object._walk(visitor);
15375 this.body._walk(visitor);
15376 });
15377 }
15378 }, AST_StatementWithBody);
15379 var AST_With = DEFNODE("With", "expression", {
15380 $documentation: "A `with` statement",
15381 $propdoc: {
15382 expression: "[AST_Node] the `with` expression"
15383 },
15384 _walk: function(visitor) {
15385 return visitor._visit(this, function() {
15386 this.expression._walk(visitor);
15387 this.body._walk(visitor);
15388 });
15389 }
15390 }, AST_StatementWithBody);
15391 var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
15392 $documentation: "Base class for all statements introducing a lexical scope",
15393 $propdoc: {
15394 directives: "[string*/S] an array of directives declared in this scope",
15395 variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
15396 functions: "[Object/S] like `variables`, but only lists function declarations",
15397 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
15398 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
15399 parent_scope: "[AST_Scope?/S] link to the parent scope",
15400 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
15401 cname: "[integer/S] current index for mangling variables (used internally by the mangler)"
15402 }
15403 }, AST_Block);
15404 var AST_Toplevel = DEFNODE("Toplevel", "globals", {
15405 $documentation: "The toplevel scope",
15406 $propdoc: {
15407 globals: "[Object/S] a map of name -> SymbolDef for all undeclared names"
15408 },
15409 wrap_enclose: function(arg_parameter_pairs) {
15410 var self = this;
15411 var args = [];
15412 var parameters = [];
15413 arg_parameter_pairs.forEach(function(pair) {
15414 var split = pair.split(":");
15415 args.push(split[0]);
15416 parameters.push(split[1]);
15417 });
15418 var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
15419 wrapped_tl = parse(wrapped_tl);
15420 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
15421 if (node instanceof AST_Directive && node.value == "$ORIG") {
15422 return MAP.splice(self.body);
15423 }
15424 }));
15425 return wrapped_tl;
15426 },
15427 wrap_commonjs: function(name, export_all) {
15428 var self = this;
15429 var to_export = [];
15430 if (export_all) {
15431 self.figure_out_scope();
15432 self.walk(new TreeWalker(function(node) {
15433 if (node instanceof AST_SymbolDeclaration && node.definition().global) {
15434 if (!find_if(function(n) {
15435 return n.name == node.name;
15436 }, to_export)) to_export.push(node);
15437 }
15438 }));
15439 }
15440 var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
15441 wrapped_tl = parse(wrapped_tl);
15442 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
15443 if (node instanceof AST_SimpleStatement) {
15444 node = node.body;
15445 if (node instanceof AST_String) switch (node.getValue()) {
15446 case "$ORIG":
15447 return MAP.splice(self.body);
15448
15449 case "$EXPORTS":
15450 var body = [];
15451 to_export.forEach(function(sym) {
15452 body.push(new AST_SimpleStatement({
15453 body: new AST_Assign({
15454 left: new AST_Sub({
15455 expression: new AST_SymbolRef({
15456 name: "exports"
15457 }),
15458 property: new AST_String({
15459 value: sym.name
15460 })
15461 }),
15462 operator: "=",
15463 right: new AST_SymbolRef(sym)
15464 })
15465 }));
15466 });
15467 return MAP.splice(body);
15468 }
15469 }
15470 }));
15471 return wrapped_tl;
15472 }
15473 }, AST_Scope);
15474 var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
15475 $documentation: "Base class for functions",
15476 $propdoc: {
15477 name: "[AST_SymbolDeclaration?] the name of this function",
15478 argnames: "[AST_SymbolFunarg*] array of function arguments",
15479 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
15480 },
15481 _walk: function(visitor) {
15482 return visitor._visit(this, function() {
15483 if (this.name) this.name._walk(visitor);
15484 this.argnames.forEach(function(arg) {
15485 arg._walk(visitor);
15486 });
15487 walk_body(this, visitor);
15488 });
15489 }
15490 }, AST_Scope);
15491 var AST_Accessor = DEFNODE("Accessor", null, {
15492 $documentation: "A setter/getter function"
15493 }, AST_Lambda);
15494 var AST_Function = DEFNODE("Function", null, {
15495 $documentation: "A function expression"
15496 }, AST_Lambda);
15497 var AST_Defun = DEFNODE("Defun", null, {
15498 $documentation: "A function definition"
15499 }, AST_Lambda);
15500 var AST_Jump = DEFNODE("Jump", null, {
15501 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
15502 }, AST_Statement);
15503 var AST_Exit = DEFNODE("Exit", "value", {
15504 $documentation: "Base class for “exits” (`return` and `throw`)",
15505 $propdoc: {
15506 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
15507 },
15508 _walk: function(visitor) {
15509 return visitor._visit(this, this.value && function() {
15510 this.value._walk(visitor);
15511 });
15512 }
15513 }, AST_Jump);
15514 var AST_Return = DEFNODE("Return", null, {
15515 $documentation: "A `return` statement"
15516 }, AST_Exit);
15517 var AST_Throw = DEFNODE("Throw", null, {
15518 $documentation: "A `throw` statement"
15519 }, AST_Exit);
15520 var AST_LoopControl = DEFNODE("LoopControl", "label", {
15521 $documentation: "Base class for loop control statements (`break` and `continue`)",
15522 $propdoc: {
15523 label: "[AST_LabelRef?] the label, or null if none"
15524 },
15525 _walk: function(visitor) {
15526 return visitor._visit(this, this.label && function() {
15527 this.label._walk(visitor);
15528 });
15529 }
15530 }, AST_Jump);
15531 var AST_Break = DEFNODE("Break", null, {
15532 $documentation: "A `break` statement"
15533 }, AST_LoopControl);
15534 var AST_Continue = DEFNODE("Continue", null, {
15535 $documentation: "A `continue` statement"
15536 }, AST_LoopControl);
15537 var AST_If = DEFNODE("If", "condition alternative", {
15538 $documentation: "A `if` statement",
15539 $propdoc: {
15540 condition: "[AST_Node] the `if` condition",
15541 alternative: "[AST_Statement?] the `else` part, or null if not present"
15542 },
15543 _walk: function(visitor) {
15544 return visitor._visit(this, function() {
15545 this.condition._walk(visitor);
15546 this.body._walk(visitor);
15547 if (this.alternative) this.alternative._walk(visitor);
15548 });
15549 }
15550 }, AST_StatementWithBody);
15551 var AST_Switch = DEFNODE("Switch", "expression", {
15552 $documentation: "A `switch` statement",
15553 $propdoc: {
15554 expression: "[AST_Node] the `switch` “discriminant”"
15555 },
15556 _walk: function(visitor) {
15557 return visitor._visit(this, function() {
15558 this.expression._walk(visitor);
15559 walk_body(this, visitor);
15560 });
15561 }
15562 }, AST_Block);
15563 var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
15564 $documentation: "Base class for `switch` branches"
15565 }, AST_Block);
15566 var AST_Default = DEFNODE("Default", null, {
15567 $documentation: "A `default` switch branch"
15568 }, AST_SwitchBranch);
15569 var AST_Case = DEFNODE("Case", "expression", {
15570 $documentation: "A `case` switch branch",
15571 $propdoc: {
15572 expression: "[AST_Node] the `case` expression"
15573 },
15574 _walk: function(visitor) {
15575 return visitor._visit(this, function() {
15576 this.expression._walk(visitor);
15577 walk_body(this, visitor);
15578 });
15579 }
15580 }, AST_SwitchBranch);
15581 var AST_Try = DEFNODE("Try", "bcatch bfinally", {
15582 $documentation: "A `try` statement",
15583 $propdoc: {
15584 bcatch: "[AST_Catch?] the catch block, or null if not present",
15585 bfinally: "[AST_Finally?] the finally block, or null if not present"
15586 },
15587 _walk: function(visitor) {
15588 return visitor._visit(this, function() {
15589 walk_body(this, visitor);
15590 if (this.bcatch) this.bcatch._walk(visitor);
15591 if (this.bfinally) this.bfinally._walk(visitor);
15592 });
15593 }
15594 }, AST_Block);
15595 var AST_Catch = DEFNODE("Catch", "argname", {
15596 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
15597 $propdoc: {
15598 argname: "[AST_SymbolCatch] symbol for the exception"
15599 },
15600 _walk: function(visitor) {
15601 return visitor._visit(this, function() {
15602 this.argname._walk(visitor);
15603 walk_body(this, visitor);
15604 });
15605 }
15606 }, AST_Block);
15607 var AST_Finally = DEFNODE("Finally", null, {
15608 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
15609 }, AST_Block);
15610 var AST_Definitions = DEFNODE("Definitions", "definitions", {
15611 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
15612 $propdoc: {
15613 definitions: "[AST_VarDef*] array of variable definitions"
15614 },
15615 _walk: function(visitor) {
15616 return visitor._visit(this, function() {
15617 this.definitions.forEach(function(def) {
15618 def._walk(visitor);
15619 });
15620 });
15621 }
15622 }, AST_Statement);
15623 var AST_Var = DEFNODE("Var", null, {
15624 $documentation: "A `var` statement"
15625 }, AST_Definitions);
15626 var AST_Const = DEFNODE("Const", null, {
15627 $documentation: "A `const` statement"
15628 }, AST_Definitions);
15629 var AST_VarDef = DEFNODE("VarDef", "name value", {
15630 $documentation: "A variable declaration; only appears in a AST_Definitions node",
15631 $propdoc: {
15632 name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
15633 value: "[AST_Node?] initializer, or null of there's no initializer"
15634 },
15635 _walk: function(visitor) {
15636 return visitor._visit(this, function() {
15637 this.name._walk(visitor);
15638 if (this.value) this.value._walk(visitor);
15639 });
15640 }
15641 });
15642 var AST_Call = DEFNODE("Call", "expression args", {
15643 $documentation: "A function call expression",
15644 $propdoc: {
15645 expression: "[AST_Node] expression to invoke as function",
15646 args: "[AST_Node*] array of arguments"
15647 },
15648 _walk: function(visitor) {
15649 return visitor._visit(this, function() {
15650 this.expression._walk(visitor);
15651 this.args.forEach(function(arg) {
15652 arg._walk(visitor);
15653 });
15654 });
15655 }
15656 });
15657 var AST_New = DEFNODE("New", null, {
15658 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
15659 }, AST_Call);
15660 var AST_Seq = DEFNODE("Seq", "car cdr", {
15661 $documentation: "A sequence expression (two comma-separated expressions)",
15662 $propdoc: {
15663 car: "[AST_Node] first element in sequence",
15664 cdr: "[AST_Node] second element in sequence"
15665 },
15666 $cons: function(x, y) {
15667 var seq = new AST_Seq(x);
15668 seq.car = x;
15669 seq.cdr = y;
15670 return seq;
15671 },
15672 $from_array: function(array) {
15673 if (array.length == 0) return null;
15674 if (array.length == 1) return array[0].clone();
15675 var list = null;
15676 for (var i = array.length; --i >= 0; ) {
15677 list = AST_Seq.cons(array[i], list);
15678 }
15679 var p = list;
15680 while (p) {
15681 if (p.cdr && !p.cdr.cdr) {
15682 p.cdr = p.cdr.car;
15683 break;
15684 }
15685 p = p.cdr;
15686 }
15687 return list;
15688 },
15689 to_array: function() {
15690 var p = this, a = [];
15691 while (p) {
15692 a.push(p.car);
15693 if (p.cdr && !(p.cdr instanceof AST_Seq)) {
15694 a.push(p.cdr);
15695 break;
15696 }
15697 p = p.cdr;
15698 }
15699 return a;
15700 },
15701 add: function(node) {
15702 var p = this;
15703 while (p) {
15704 if (!(p.cdr instanceof AST_Seq)) {
15705 var cell = AST_Seq.cons(p.cdr, node);
15706 return p.cdr = cell;
15707 }
15708 p = p.cdr;
15709 }
15710 },
15711 _walk: function(visitor) {
15712 return visitor._visit(this, function() {
15713 this.car._walk(visitor);
15714 if (this.cdr) this.cdr._walk(visitor);
15715 });
15716 }
15717 });
15718 var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
15719 $documentation: 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`',
15720 $propdoc: {
15721 expression: "[AST_Node] the “container” expression",
15722 property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
15723 }
15724 });
15725 var AST_Dot = DEFNODE("Dot", null, {
15726 $documentation: "A dotted property access expression",
15727 _walk: function(visitor) {
15728 return visitor._visit(this, function() {
15729 this.expression._walk(visitor);
15730 });
15731 }
15732 }, AST_PropAccess);
15733 var AST_Sub = DEFNODE("Sub", null, {
15734 $documentation: 'Index-style property access, i.e. `a["foo"]`',
15735 _walk: function(visitor) {
15736 return visitor._visit(this, function() {
15737 this.expression._walk(visitor);
15738 this.property._walk(visitor);
15739 });
15740 }
15741 }, AST_PropAccess);
15742 var AST_Unary = DEFNODE("Unary", "operator expression", {
15743 $documentation: "Base class for unary expressions",
15744 $propdoc: {
15745 operator: "[string] the operator",
15746 expression: "[AST_Node] expression that this unary operator applies to"
15747 },
15748 _walk: function(visitor) {
15749 return visitor._visit(this, function() {
15750 this.expression._walk(visitor);
15751 });
15752 }
15753 });
15754 var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
15755 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
15756 }, AST_Unary);
15757 var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
15758 $documentation: "Unary postfix expression, i.e. `i++`"
15759 }, AST_Unary);
15760 var AST_Binary = DEFNODE("Binary", "left operator right", {
15761 $documentation: "Binary expression, i.e. `a + b`",
15762 $propdoc: {
15763 left: "[AST_Node] left-hand side expression",
15764 operator: "[string] the operator",
15765 right: "[AST_Node] right-hand side expression"
15766 },
15767 _walk: function(visitor) {
15768 return visitor._visit(this, function() {
15769 this.left._walk(visitor);
15770 this.right._walk(visitor);
15771 });
15772 }
15773 });
15774 var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
15775 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
15776 $propdoc: {
15777 condition: "[AST_Node]",
15778 consequent: "[AST_Node]",
15779 alternative: "[AST_Node]"
15780 },
15781 _walk: function(visitor) {
15782 return visitor._visit(this, function() {
15783 this.condition._walk(visitor);
15784 this.consequent._walk(visitor);
15785 this.alternative._walk(visitor);
15786 });
15787 }
15788 });
15789 var AST_Assign = DEFNODE("Assign", null, {
15790 $documentation: "An assignment expression — `a = b + 5`"
15791 }, AST_Binary);
15792 var AST_Array = DEFNODE("Array", "elements", {
15793 $documentation: "An array literal",
15794 $propdoc: {
15795 elements: "[AST_Node*] array of elements"
15796 },
15797 _walk: function(visitor) {
15798 return visitor._visit(this, function() {
15799 this.elements.forEach(function(el) {
15800 el._walk(visitor);
15801 });
15802 });
15803 }
15804 });
15805 var AST_Object = DEFNODE("Object", "properties", {
15806 $documentation: "An object literal",
15807 $propdoc: {
15808 properties: "[AST_ObjectProperty*] array of properties"
15809 },
15810 _walk: function(visitor) {
15811 return visitor._visit(this, function() {
15812 this.properties.forEach(function(prop) {
15813 prop._walk(visitor);
15814 });
15815 });
15816 }
15817 });
15818 var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
15819 $documentation: "Base class for literal object properties",
15820 $propdoc: {
15821 key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code",
15822 value: "[AST_Node] property value. For setters and getters this is an AST_Function."
15823 },
15824 _walk: function(visitor) {
15825 return visitor._visit(this, function() {
15826 this.value._walk(visitor);
15827 });
15828 }
15829 });
15830 var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
15831 $documentation: "A key: value object property"
15832 }, AST_ObjectProperty);
15833 var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
15834 $documentation: "An object setter property"
15835 }, AST_ObjectProperty);
15836 var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
15837 $documentation: "An object getter property"
15838 }, AST_ObjectProperty);
15839 var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
15840 $propdoc: {
15841 name: "[string] name of this symbol",
15842 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
15843 thedef: "[SymbolDef/S] the definition of this symbol"
15844 },
15845 $documentation: "Base class for all symbols"
15846 });
15847 var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
15848 $documentation: "The name of a property accessor (setter/getter function)"
15849 }, AST_Symbol);
15850 var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
15851 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
15852 $propdoc: {
15853 init: "[AST_Node*/S] array of initializers for this declaration."
15854 }
15855 }, AST_Symbol);
15856 var AST_SymbolVar = DEFNODE("SymbolVar", null, {
15857 $documentation: "Symbol defining a variable"
15858 }, AST_SymbolDeclaration);
15859 var AST_SymbolConst = DEFNODE("SymbolConst", null, {
15860 $documentation: "A constant declaration"
15861 }, AST_SymbolDeclaration);
15862 var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
15863 $documentation: "Symbol naming a function argument"
15864 }, AST_SymbolVar);
15865 var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
15866 $documentation: "Symbol defining a function"
15867 }, AST_SymbolDeclaration);
15868 var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
15869 $documentation: "Symbol naming a function expression"
15870 }, AST_SymbolDeclaration);
15871 var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
15872 $documentation: "Symbol naming the exception in catch"
15873 }, AST_SymbolDeclaration);
15874 var AST_Label = DEFNODE("Label", "references", {
15875 $documentation: "Symbol naming a label (declaration)",
15876 $propdoc: {
15877 references: "[AST_LabelRef*] a list of nodes referring to this label"
15878 }
15879 }, AST_Symbol);
15880 var AST_SymbolRef = DEFNODE("SymbolRef", null, {
15881 $documentation: "Reference to some symbol (not definition/declaration)"
15882 }, AST_Symbol);
15883 var AST_LabelRef = DEFNODE("LabelRef", null, {
15884 $documentation: "Reference to a label symbol"
15885 }, AST_Symbol);
15886 var AST_This = DEFNODE("This", null, {
15887 $documentation: "The `this` symbol"
15888 }, AST_Symbol);
15889 var AST_Constant = DEFNODE("Constant", null, {
15890 $documentation: "Base class for all constants",
15891 getValue: function() {
15892 return this.value;
15893 }
15894 });
15895 var AST_String = DEFNODE("String", "value", {
15896 $documentation: "A string literal",
15897 $propdoc: {
15898 value: "[string] the contents of this string"
15899 }
15900 }, AST_Constant);
15901 var AST_Number = DEFNODE("Number", "value", {
15902 $documentation: "A number literal",
15903 $propdoc: {
15904 value: "[number] the numeric value"
15905 }
15906 }, AST_Constant);
15907 var AST_RegExp = DEFNODE("RegExp", "value", {
15908 $documentation: "A regexp literal",
15909 $propdoc: {
15910 value: "[RegExp] the actual regexp"
15911 }
15912 }, AST_Constant);
15913 var AST_Atom = DEFNODE("Atom", null, {
15914 $documentation: "Base class for atoms"
15915 }, AST_Constant);
15916 var AST_Null = DEFNODE("Null", null, {
15917 $documentation: "The `null` atom",
15918 value: null
15919 }, AST_Atom);
15920 var AST_NaN = DEFNODE("NaN", null, {
15921 $documentation: "The impossible value",
15922 value: 0 / 0
15923 }, AST_Atom);
15924 var AST_Undefined = DEFNODE("Undefined", null, {
15925 $documentation: "The `undefined` value",
15926 value: function() {}()
15927 }, AST_Atom);
15928 var AST_Hole = DEFNODE("Hole", null, {
15929 $documentation: "A hole in an array",
15930 value: function() {}()
15931 }, AST_Atom);
15932 var AST_Infinity = DEFNODE("Infinity", null, {
15933 $documentation: "The `Infinity` value",
15934 value: 1 / 0
15935 }, AST_Atom);
15936 var AST_Boolean = DEFNODE("Boolean", null, {
15937 $documentation: "Base class for booleans"
15938 }, AST_Atom);
15939 var AST_False = DEFNODE("False", null, {
15940 $documentation: "The `false` atom",
15941 value: false
15942 }, AST_Boolean);
15943 var AST_True = DEFNODE("True", null, {
15944 $documentation: "The `true` atom",
15945 value: true
15946 }, AST_Boolean);
15947 function TreeWalker(callback) {
15948 this.visit = callback;
15949 this.stack = [];
15950 }
15951 TreeWalker.prototype = {
15952 _visit: function(node, descend) {
15953 this.stack.push(node);
15954 var ret = this.visit(node, descend ? function() {
15955 descend.call(node);
15956 } : noop);
15957 if (!ret && descend) {
15958 descend.call(node);
15959 }
15960 this.stack.pop();
15961 return ret;
15962 },
15963 parent: function(n) {
15964 return this.stack[this.stack.length - 2 - (n || 0)];
15965 },
15966 push: function(node) {
15967 this.stack.push(node);
15968 },
15969 pop: function() {
15970 return this.stack.pop();
15971 },
15972 self: function() {
15973 return this.stack[this.stack.length - 1];
15974 },
15975 find_parent: function(type) {
15976 var stack = this.stack;
15977 for (var i = stack.length; --i >= 0; ) {
15978 var x = stack[i];
15979 if (x instanceof type) return x;
15980 }
15981 },
15982 has_directive: function(type) {
15983 return this.find_parent(AST_Scope).has_directive(type);
15984 },
15985 in_boolean_context: function() {
15986 var stack = this.stack;
15987 var i = stack.length, self = stack[--i];
15988 while (i > 0) {
15989 var p = stack[--i];
15990 if (p instanceof AST_If && p.condition === self || p instanceof AST_Conditional && p.condition === self || p instanceof AST_DWLoop && p.condition === self || p instanceof AST_For && p.condition === self || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
15991 return true;
15992 }
15993 if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) return false;
15994 self = p;
15995 }
15996 },
15997 loopcontrol_target: function(label) {
15998 var stack = this.stack;
15999 if (label) {
16000 for (var i = stack.length; --i >= 0; ) {
16001 var x = stack[i];
16002 if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
16003 return x.body;
16004 }
16005 }
16006 } else {
16007 for (var i = stack.length; --i >= 0; ) {
16008 var x = stack[i];
16009 if (x instanceof AST_Switch || x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) return x;
16010 }
16011 }
16012 }
16013 };
16014 "use strict";
16015 var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with";
16016 var KEYWORDS_ATOM = "false null true";
16017 var RESERVED_WORDS = "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile" + " " + KEYWORDS_ATOM + " " + KEYWORDS;
16018 var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
16019 KEYWORDS = makePredicate(KEYWORDS);
16020 RESERVED_WORDS = makePredicate(RESERVED_WORDS);
16021 KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
16022 KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
16023 var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
16024 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
16025 var RE_OCT_NUMBER = /^0[0-7]+$/;
16026 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
16027 var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]);
16028 var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
16029 var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
16030 var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
16031 var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
16032 var UNICODE = {
16033 letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
16034 non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
16035 space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
16036 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
16037 };
16038 function is_letter(code) {
16039 return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 170 && UNICODE.letter.test(String.fromCharCode(code));
16040 }
16041 function is_digit(code) {
16042 return code >= 48 && code <= 57;
16043 }
16044 function is_alphanumeric_char(code) {
16045 return is_digit(code) || is_letter(code);
16046 }
16047 function is_unicode_combining_mark(ch) {
16048 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
16049 }
16050 function is_unicode_connector_punctuation(ch) {
16051 return UNICODE.connector_punctuation.test(ch);
16052 }
16053 function is_identifier(name) {
16054 return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
16055 }
16056 function is_identifier_start(code) {
16057 return code == 36 || code == 95 || is_letter(code);
16058 }
16059 function is_identifier_char(ch) {
16060 var code = ch.charCodeAt(0);
16061 return is_identifier_start(code) || is_digit(code) || code == 8204 || code == 8205 || is_unicode_combining_mark(ch) || is_unicode_connector_punctuation(ch);
16062 }
16063 function is_identifier_string(str) {
16064 var i = str.length;
16065 if (i == 0) return false;
16066 if (is_digit(str.charCodeAt(0))) return false;
16067 while (--i >= 0) {
16068 if (!is_identifier_char(str.charAt(i))) return false;
16069 }
16070 return true;
16071 }
16072 function parse_js_number(num) {
16073 if (RE_HEX_NUMBER.test(num)) {
16074 return parseInt(num.substr(2), 16);
16075 } else if (RE_OCT_NUMBER.test(num)) {
16076 return parseInt(num.substr(1), 8);
16077 } else if (RE_DEC_NUMBER.test(num)) {
16078 return parseFloat(num);
16079 }
16080 }
16081 function JS_Parse_Error(message, line, col, pos) {
16082 this.message = message;
16083 this.line = line;
16084 this.col = col;
16085 this.pos = pos;
16086 this.stack = new Error().stack;
16087 }
16088 JS_Parse_Error.prototype.toString = function() {
16089 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
16090 };
16091 function js_error(message, filename, line, col, pos) {
16092 throw new JS_Parse_Error(message, line, col, pos);
16093 }
16094 function is_token(token, type, val) {
16095 return token.type == type && (val == null || token.value == val);
16096 }
16097 var EX_EOF = {};
16098 function tokenizer($TEXT, filename) {
16099 var S = {
16100 text: $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ""),
16101 filename: filename,
16102 pos: 0,
16103 tokpos: 0,
16104 line: 1,
16105 tokline: 0,
16106 col: 0,
16107 tokcol: 0,
16108 newline_before: false,
16109 regex_allowed: false,
16110 comments_before: []
16111 };
16112 function peek() {
16113 return S.text.charAt(S.pos);
16114 }
16115 function next(signal_eof, in_string) {
16116 var ch = S.text.charAt(S.pos++);
16117 if (signal_eof && !ch) throw EX_EOF;
16118 if (ch == "\n") {
16119 S.newline_before = S.newline_before || !in_string;
16120 ++S.line;
16121 S.col = 0;
16122 } else {
16123 ++S.col;
16124 }
16125 return ch;
16126 }
16127 function find(what, signal_eof) {
16128 var pos = S.text.indexOf(what, S.pos);
16129 if (signal_eof && pos == -1) throw EX_EOF;
16130 return pos;
16131 }
16132 function start_token() {
16133 S.tokline = S.line;
16134 S.tokcol = S.col;
16135 S.tokpos = S.pos;
16136 }
16137 function token(type, value, is_comment) {
16138 S.regex_allowed = type == "operator" && !UNARY_POSTFIX(value) || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value);
16139 var ret = {
16140 type: type,
16141 value: value,
16142 line: S.tokline,
16143 col: S.tokcol,
16144 pos: S.tokpos,
16145 endpos: S.pos,
16146 nlb: S.newline_before,
16147 file: filename
16148 };
16149 if (!is_comment) {
16150 ret.comments_before = S.comments_before;
16151 S.comments_before = [];
16152 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
16153 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
16154 }
16155 }
16156 S.newline_before = false;
16157 return new AST_Token(ret);
16158 }
16159 function skip_whitespace() {
16160 while (WHITESPACE_CHARS(peek())) next();
16161 }
16162 function read_while(pred) {
16163 var ret = "", ch, i = 0;
16164 while ((ch = peek()) && pred(ch, i++)) ret += next();
16165 return ret;
16166 }
16167 function parse_error(err) {
16168 js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
16169 }
16170 function read_num(prefix) {
16171 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
16172 var num = read_while(function(ch, i) {
16173 var code = ch.charCodeAt(0);
16174 switch (code) {
16175 case 120:
16176 case 88:
16177 return has_x ? false : has_x = true;
16178
16179 case 101:
16180 case 69:
16181 return has_x ? true : has_e ? false : has_e = after_e = true;
16182
16183 case 45:
16184 return after_e || i == 0 && !prefix;
16185
16186 case 43:
16187 return after_e;
16188
16189 case after_e = false, 46:
16190 return !has_dot && !has_x && !has_e ? has_dot = true : false;
16191 }
16192 return is_alphanumeric_char(code);
16193 });
16194 if (prefix) num = prefix + num;
16195 var valid = parse_js_number(num);
16196 if (!isNaN(valid)) {
16197 return token("num", valid);
16198 } else {
16199 parse_error("Invalid syntax: " + num);
16200 }
16201 }
16202 function read_escaped_char(in_string) {
16203 var ch = next(true, in_string);
16204 switch (ch.charCodeAt(0)) {
16205 case 110:
16206 return "\n";
16207
16208 case 114:
16209 return "\r";
16210
16211 case 116:
16212 return " ";
16213
16214 case 98:
16215 return "\b";
16216
16217 case 118:
16218 return " ";
16219
16220 case 102:
16221 return "\f";
16222
16223 case 48:
16224 return "\x00";
16225
16226 case 120:
16227 return String.fromCharCode(hex_bytes(2));
16228
16229 case 117:
16230 return String.fromCharCode(hex_bytes(4));
16231
16232 case 10:
16233 return "";
16234
16235 default:
16236 return ch;
16237 }
16238 }
16239 function hex_bytes(n) {
16240 var num = 0;
16241 for (;n > 0; --n) {
16242 var digit = parseInt(next(true), 16);
16243 if (isNaN(digit)) parse_error("Invalid hex-character pattern in string");
16244 num = num << 4 | digit;
16245 }
16246 return num;
16247 }
16248 var read_string = with_eof_error("Unterminated string constant", function() {
16249 var quote = next(), ret = "";
16250 for (;;) {
16251 var ch = next(true);
16252 if (ch == "\\") {
16253 var octal_len = 0, first = null;
16254 ch = read_while(function(ch) {
16255 if (ch >= "0" && ch <= "7") {
16256 if (!first) {
16257 first = ch;
16258 return ++octal_len;
16259 } else if (first <= "3" && octal_len <= 2) return ++octal_len; else if (first >= "4" && octal_len <= 1) return ++octal_len;
16260 }
16261 return false;
16262 });
16263 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); else ch = read_escaped_char(true);
16264 } else if (ch == quote) break;
16265 ret += ch;
16266 }
16267 return token("string", ret);
16268 });
16269 function read_line_comment() {
16270 next(); 16623 next();
16271 var i = find("\n"), ret; 16624 };
16272 if (i == -1) { 16625
16273 ret = S.text.substr(S.pos); 16626 function read_while(pred) {
16274 S.pos = S.text.length; 16627 var ret = "", ch, i = 0;
16275 } else { 16628 while ((ch = peek()) && pred(ch, i++))
16276 ret = S.text.substring(S.pos, i); 16629 ret += next();
16277 S.pos = i; 16630 return ret;
16278 } 16631 };
16279 return token("comment1", ret, true); 16632
16280 } 16633 function parse_error(err) {
16281 var read_multiline_comment = with_eof_error("Unterminated multiline comment", function() { 16634 js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
16282 next(); 16635 };
16283 var i = find("*/", true); 16636
16284 var text = S.text.substring(S.pos, i); 16637 function read_num(prefix) {
16285 var a = text.split("\n"), n = a.length; 16638 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
16286 S.pos = i + 2; 16639 var num = read_while(function(ch, i){
16287 S.line += n - 1;
16288 if (n > 1) S.col = a[n - 1].length; else S.col += a[n - 1].length;
16289 S.col += 2;
16290 S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
16291 return token("comment2", text, true);
16292 });
16293 function read_name() {
16294 var backslash = false, name = "", ch, escaped = false, hex;
16295 while ((ch = peek()) != null) {
16296 if (!backslash) {
16297 if (ch == "\\") escaped = backslash = true, next(); else if (is_identifier_char(ch)) name += next(); else break;
16298 } else {
16299 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
16300 ch = read_escaped_char();
16301 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
16302 name += ch;
16303 backslash = false;
16304 }
16305 }
16306 if (KEYWORDS(name) && escaped) {
16307 hex = name.charCodeAt(0).toString(16).toUpperCase();
16308 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
16309 }
16310 return name;
16311 }
16312 var read_regexp = with_eof_error("Unterminated regular expression", function(regexp) {
16313 var prev_backslash = false, ch, in_class = false;
16314 while (ch = next(true)) if (prev_backslash) {
16315 regexp += "\\" + ch;
16316 prev_backslash = false;
16317 } else if (ch == "[") {
16318 in_class = true;
16319 regexp += ch;
16320 } else if (ch == "]" && in_class) {
16321 in_class = false;
16322 regexp += ch;
16323 } else if (ch == "/" && !in_class) {
16324 break;
16325 } else if (ch == "\\") {
16326 prev_backslash = true;
16327 } else {
16328 regexp += ch;
16329 }
16330 var mods = read_name();
16331 return token("regexp", new RegExp(regexp, mods));
16332 });
16333 function read_operator(prefix) {
16334 function grow(op) {
16335 if (!peek()) return op;
16336 var bigger = op + peek();
16337 if (OPERATORS(bigger)) {
16338 next();
16339 return grow(bigger);
16340 } else {
16341 return op;
16342 }
16343 }
16344 return token("operator", grow(prefix || next()));
16345 }
16346 function handle_slash() {
16347 next();
16348 var regex_allowed = S.regex_allowed;
16349 switch (peek()) {
16350 case "/":
16351 S.comments_before.push(read_line_comment());
16352 S.regex_allowed = regex_allowed;
16353 return next_token();
16354
16355 case "*":
16356 S.comments_before.push(read_multiline_comment());
16357 S.regex_allowed = regex_allowed;
16358 return next_token();
16359 }
16360 return S.regex_allowed ? read_regexp("") : read_operator("/");
16361 }
16362 function handle_dot() {
16363 next();
16364 return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
16365 }
16366 function read_word() {
16367 var word = read_name();
16368 return KEYWORDS_ATOM(word) ? token("atom", word) : !KEYWORDS(word) ? token("name", word) : OPERATORS(word) ? token("operator", word) : token("keyword", word);
16369 }
16370 function with_eof_error(eof_error, cont) {
16371 return function(x) {
16372 try {
16373 return cont(x);
16374 } catch (ex) {
16375 if (ex === EX_EOF) parse_error(eof_error); else throw ex;
16376 }
16377 };
16378 }
16379 function next_token(force_regexp) {
16380 if (force_regexp != null) return read_regexp(force_regexp);
16381 skip_whitespace();
16382 start_token();
16383 var ch = peek();
16384 if (!ch) return token("eof");
16385 var code = ch.charCodeAt(0); 16640 var code = ch.charCodeAt(0);
16386 switch (code) { 16641 switch (code) {
16387 case 34: 16642 case 120: case 88: // xX
16388 case 39: 16643 return has_x ? false : (has_x = true);
16389 return read_string(); 16644 case 101: case 69: // eE
16390 16645 return has_x ? true : has_e ? false : (has_e = after_e = true);
16391 case 46: 16646 case 45: // -
16392 return handle_dot(); 16647 return after_e || (i == 0 && !prefix);
16393 16648 case 43: // +
16394 case 47: 16649 return after_e;
16395 return handle_slash(); 16650 case (after_e = false, 46): // .
16396 } 16651 return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
16397 if (is_digit(code)) return read_num(); 16652 }
16398 if (PUNC_CHARS(ch)) return token("punc", next()); 16653 return is_alphanumeric_char(code);
16399 if (OPERATOR_CHARS(ch)) return read_operator(); 16654 });
16400 if (code == 92 || is_identifier_start(code)) return read_word(); 16655 if (prefix) num = prefix + num;
16401 parse_error("Unexpected character '" + ch + "'"); 16656 var valid = parse_js_number(num);
16402 } 16657 if (!isNaN(valid)) {
16403 next_token.context = function(nc) { 16658 return token("num", valid);
16404 if (nc) S = nc; 16659 } else {
16405 return S; 16660 parse_error("Invalid syntax: " + num);
16661 }
16662 };
16663
16664 function read_escaped_char(in_string) {
16665 var ch = next(true, in_string);
16666 switch (ch.charCodeAt(0)) {
16667 case 110 : return "\n";
16668 case 114 : return "\r";
16669 case 116 : return "\t";
16670 case 98 : return "\b";
16671 case 118 : return "\u000b"; // \v
16672 case 102 : return "\f";
16673 case 48 : return "\0";
16674 case 120 : return String.fromCharCode(hex_bytes(2)); // \x
16675 case 117 : return String.fromCharCode(hex_bytes(4)); // \u
16676 case 10 : return ""; // newline
16677 default : return ch;
16678 }
16679 };
16680
16681 function hex_bytes(n) {
16682 var num = 0;
16683 for (; n > 0; --n) {
16684 var digit = parseInt(next(true), 16);
16685 if (isNaN(digit))
16686 parse_error("Invalid hex-character pattern in string");
16687 num = (num << 4) | digit;
16688 }
16689 return num;
16690 };
16691
16692 var read_string = with_eof_error("Unterminated string constant", function(){
16693 var quote = next(), ret = "";
16694 for (;;) {
16695 var ch = next(true);
16696 if (ch == "\\") {
16697 // read OctalEscapeSequence (XXX: deprecated if "strict mode")
16698 // https://github.com/mishoo/UglifyJS/issues/178
16699 var octal_len = 0, first = null;
16700 ch = read_while(function(ch){
16701 if (ch >= "0" && ch <= "7") {
16702 if (!first) {
16703 first = ch;
16704 return ++octal_len;
16705 }
16706 else if (first <= "3" && octal_len <= 2) return ++octal_len;
16707 else if (first >= "4" && octal_len <= 1) return ++octal_len;
16708 }
16709 return false;
16710 });
16711 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
16712 else ch = read_escaped_char(true);
16713 }
16714 else if (ch == quote) break;
16715 ret += ch;
16716 }
16717 return token("string", ret);
16718 });
16719
16720 function skip_line_comment(type) {
16721 var regex_allowed = S.regex_allowed;
16722 var i = find("\n"), ret;
16723 if (i == -1) {
16724 ret = S.text.substr(S.pos);
16725 S.pos = S.text.length;
16726 } else {
16727 ret = S.text.substring(S.pos, i);
16728 S.pos = i;
16729 }
16730 S.comments_before.push(token(type, ret, true));
16731 S.regex_allowed = regex_allowed;
16732 return next_token();
16733 };
16734
16735 var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
16736 var regex_allowed = S.regex_allowed;
16737 var i = find("*/", true);
16738 var text = S.text.substring(S.pos, i);
16739 var a = text.split("\n"), n = a.length;
16740 // update stream position
16741 S.pos = i + 2;
16742 S.line += n - 1;
16743 if (n > 1) S.col = a[n - 1].length;
16744 else S.col += a[n - 1].length;
16745 S.col += 2;
16746 var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
16747 S.comments_before.push(token("comment2", text, true));
16748 S.regex_allowed = regex_allowed;
16749 S.newline_before = nlb;
16750 return next_token();
16751 });
16752
16753 function read_name() {
16754 var backslash = false, name = "", ch, escaped = false, hex;
16755 while ((ch = peek()) != null) {
16756 if (!backslash) {
16757 if (ch == "\\") escaped = backslash = true, next();
16758 else if (is_identifier_char(ch)) name += next();
16759 else break;
16760 }
16761 else {
16762 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
16763 ch = read_escaped_char();
16764 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
16765 name += ch;
16766 backslash = false;
16767 }
16768 }
16769 if (KEYWORDS(name) && escaped) {
16770 hex = name.charCodeAt(0).toString(16).toUpperCase();
16771 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
16772 }
16773 return name;
16774 };
16775
16776 var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
16777 var prev_backslash = false, ch, in_class = false;
16778 while ((ch = next(true))) if (prev_backslash) {
16779 regexp += "\\" + ch;
16780 prev_backslash = false;
16781 } else if (ch == "[") {
16782 in_class = true;
16783 regexp += ch;
16784 } else if (ch == "]" && in_class) {
16785 in_class = false;
16786 regexp += ch;
16787 } else if (ch == "/" && !in_class) {
16788 break;
16789 } else if (ch == "\\") {
16790 prev_backslash = true;
16791 } else {
16792 regexp += ch;
16793 }
16794 var mods = read_name();
16795 return token("regexp", new RegExp(regexp, mods));
16796 });
16797
16798 function read_operator(prefix) {
16799 function grow(op) {
16800 if (!peek()) return op;
16801 var bigger = op + peek();
16802 if (OPERATORS(bigger)) {
16803 next();
16804 return grow(bigger);
16805 } else {
16806 return op;
16807 }
16406 }; 16808 };
16407 return next_token; 16809 return token("operator", grow(prefix || next()));
16408 } 16810 };
16409 var UNARY_PREFIX = makePredicate([ "typeof", "void", "delete", "--", "++", "!", "~", "-", "+" ]); 16811
16410 var UNARY_POSTFIX = makePredicate([ "--", "++" ]); 16812 function handle_slash() {
16411 var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); 16813 next();
16412 var PRECEDENCE = function(a, ret) { 16814 switch (peek()) {
16413 for (var i = 0, n = 1; i < a.length; ++i, ++n) { 16815 case "/":
16414 var b = a[i]; 16816 next();
16415 for (var j = 0; j < b.length; ++j) { 16817 return skip_line_comment("comment1");
16416 ret[b[j]] = n; 16818 case "*":
16417 } 16819 next();
16418 } 16820 return skip_multiline_comment();
16419 return ret; 16821 }
16420 }([ [ "||" ], [ "&&" ], [ "|" ], [ "^" ], [ "&" ], [ "==", "===", "!=", "!==" ], [ "<", ">", "<=", ">=", "in", "instanceof" ], [ ">>", "<<", ">>>" ], [ "+", "-" ], [ "*", "/", "%" ] ], {}); 16822 return S.regex_allowed ? read_regexp("") : read_operator("/");
16421 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); 16823 };
16422 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); 16824
16423 function parse($TEXT, options) { 16825 function handle_dot() {
16424 options = defaults(options, { 16826 next();
16425 strict: false, 16827 return is_digit(peek().charCodeAt(0))
16426 filename: null, 16828 ? read_num(".")
16427 toplevel: null, 16829 : token("punc", ".");
16428 expression: false 16830 };
16429 }); 16831
16430 var S = { 16832 function read_word() {
16431 input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, 16833 var word = read_name();
16432 token: null, 16834 if (prev_was_dot) return token("name", word);
16433 prev: null, 16835 return KEYWORDS_ATOM(word) ? token("atom", word)
16434 peeked: null, 16836 : !KEYWORDS(word) ? token("name", word)
16435 in_function: 0, 16837 : OPERATORS(word) ? token("operator", word)
16436 in_directives: true, 16838 : token("keyword", word);
16437 in_loop: 0, 16839 };
16438 labels: [] 16840
16841 function with_eof_error(eof_error, cont) {
16842 return function(x) {
16843 try {
16844 return cont(x);
16845 } catch(ex) {
16846 if (ex === EX_EOF) parse_error(eof_error);
16847 else throw ex;
16848 }
16439 }; 16849 };
16440 S.token = next(); 16850 };
16441 function is(type, value) { 16851
16442 return is_token(S.token, type, value); 16852 function next_token(force_regexp) {
16443 } 16853 if (force_regexp != null)
16444 function peek() { 16854 return read_regexp(force_regexp);
16445 return S.peeked || (S.peeked = S.input()); 16855 skip_whitespace();
16446 } 16856 start_token();
16447 function next() { 16857 if (html5_comments) {
16448 S.prev = S.token; 16858 if (looking_at("<!--")) {
16449 if (S.peeked) { 16859 forward(4);
16450 S.token = S.peeked; 16860 return skip_line_comment("comment3");
16451 S.peeked = null; 16861 }
16452 } else { 16862 if (looking_at("-->") && S.newline_before) {
16453 S.token = S.input(); 16863 forward(3);
16454 } 16864 return skip_line_comment("comment4");
16455 S.in_directives = S.in_directives && (S.token.type == "string" || is("punc", ";")); 16865 }
16456 return S.token; 16866 }
16457 } 16867 var ch = peek();
16458 function prev() { 16868 if (!ch) return token("eof");
16459 return S.prev; 16869 var code = ch.charCodeAt(0);
16460 } 16870 switch (code) {
16461 function croak(msg, line, col, pos) { 16871 case 34: case 39: return read_string();
16462 var ctx = S.input.context(); 16872 case 46: return handle_dot();
16463 js_error(msg, ctx.filename, line != null ? line : ctx.tokline, col != null ? col : ctx.tokcol, pos != null ? pos : ctx.tokpos); 16873 case 47: return handle_slash();
16464 } 16874 }
16465 function token_error(token, msg) { 16875 if (is_digit(code)) return read_num();
16466 croak(msg, token.line, token.col); 16876 if (PUNC_CHARS(ch)) return token("punc", next());
16467 } 16877 if (OPERATOR_CHARS(ch)) return read_operator();
16468 function unexpected(token) { 16878 if (code == 92 || is_identifier_start(code)) return read_word();
16469 if (token == null) token = S.token; 16879 parse_error("Unexpected character '" + ch + "'");
16470 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); 16880 };
16471 } 16881
16472 function expect_token(type, val) { 16882 next_token.context = function(nc) {
16473 if (is(type, val)) { 16883 if (nc) S = nc;
16474 return next(); 16884 return S;
16475 } 16885 };
16476 token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); 16886
16477 } 16887 return next_token;
16478 function expect(punc) { 16888
16479 return expect_token("punc", punc); 16889 };
16480 } 16890
16481 function can_insert_semicolon() { 16891 /* -----[ Parser (constants) ]----- */
16482 return !options.strict && (S.token.nlb || is("eof") || is("punc", "}")); 16892
16483 } 16893 var UNARY_PREFIX = makePredicate([
16484 function semicolon() { 16894 "typeof",
16485 if (is("punc", ";")) next(); else if (!can_insert_semicolon()) unexpected(); 16895 "void",
16486 } 16896 "delete",
16487 function parenthesised() { 16897 "--",
16488 expect("("); 16898 "++",
16489 var exp = expression(true); 16899 "!",
16490 expect(")"); 16900 "~",
16491 return exp; 16901 "-",
16492 } 16902 "+"
16493 function embed_tokens(parser) { 16903 ]);
16494 return function() { 16904
16495 var start = S.token; 16905 var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
16496 var expr = parser(); 16906
16497 var end = prev(); 16907 var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
16498 expr.start = start; 16908
16499 expr.end = end; 16909 var PRECEDENCE = (function(a, ret){
16500 return expr; 16910 for (var i = 0; i < a.length; ++i) {
16501 }; 16911 var b = a[i];
16502 } 16912 for (var j = 0; j < b.length; ++j) {
16503 var statement = embed_tokens(function() { 16913 ret[b[j]] = i + 1;
16504 var tmp; 16914 }
16505 if (is("operator", "/") || is("operator", "/=")) { 16915 }
16506 S.peeked = null; 16916 return ret;
16507 S.token = S.input(S.token.value.substr(1)); 16917 })(
16508 } 16918 [
16509 switch (S.token.type) { 16919 ["||"],
16510 case "string": 16920 ["&&"],
16511 var dir = S.in_directives, stat = simple_statement(); 16921 ["|"],
16512 if (dir && stat.body instanceof AST_String && !is("punc", ",")) return new AST_Directive({ 16922 ["^"],
16513 value: stat.body.value 16923 ["&"],
16924 ["==", "===", "!=", "!=="],
16925 ["<", ">", "<=", ">=", "in", "instanceof"],
16926 [">>", "<<", ">>>"],
16927 ["+", "-"],
16928 ["*", "/", "%"]
16929 ],
16930 {}
16931 );
16932
16933 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
16934
16935 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
16936
16937 /* -----[ Parser ]----- */
16938
16939 function parse($TEXT, options) {
16940
16941 options = defaults(options, {
16942 strict : false,
16943 filename : null,
16944 toplevel : null,
16945 expression : false,
16946 html5_comments : true,
16947 });
16948
16949 var S = {
16950 input : (typeof $TEXT == "string"
16951 ? tokenizer($TEXT, options.filename,
16952 options.html5_comments)
16953 : $TEXT),
16954 token : null,
16955 prev : null,
16956 peeked : null,
16957 in_function : 0,
16958 in_directives : true,
16959 in_loop : 0,
16960 labels : []
16961 };
16962
16963 S.token = next();
16964
16965 function is(type, value) {
16966 return is_token(S.token, type, value);
16967 };
16968
16969 function peek() { return S.peeked || (S.peeked = S.input()); };
16970
16971 function next() {
16972 S.prev = S.token;
16973 if (S.peeked) {
16974 S.token = S.peeked;
16975 S.peeked = null;
16976 } else {
16977 S.token = S.input();
16978 }
16979 S.in_directives = S.in_directives && (
16980 S.token.type == "string" || is("punc", ";")
16981 );
16982 return S.token;
16983 };
16984
16985 function prev() {
16986 return S.prev;
16987 };
16988
16989 function croak(msg, line, col, pos) {
16990 var ctx = S.input.context();
16991 js_error(msg,
16992 ctx.filename,
16993 line != null ? line : ctx.tokline,
16994 col != null ? col : ctx.tokcol,
16995 pos != null ? pos : ctx.tokpos);
16996 };
16997
16998 function token_error(token, msg) {
16999 croak(msg, token.line, token.col);
17000 };
17001
17002 function unexpected(token) {
17003 if (token == null)
17004 token = S.token;
17005 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
17006 };
17007
17008 function expect_token(type, val) {
17009 if (is(type, val)) {
17010 return next();
17011 }
17012 token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
17013 };
17014
17015 function expect(punc) { return expect_token("punc", punc); };
17016
17017 function can_insert_semicolon() {
17018 return !options.strict && (
17019 S.token.nlb || is("eof") || is("punc", "}")
17020 );
17021 };
17022
17023 function semicolon() {
17024 if (is("punc", ";")) next();
17025 else if (!can_insert_semicolon()) unexpected();
17026 };
17027
17028 function parenthesised() {
17029 expect("(");
17030 var exp = expression(true);
17031 expect(")");
17032 return exp;
17033 };
17034
17035 function embed_tokens(parser) {
17036 return function() {
17037 var start = S.token;
17038 var expr = parser();
17039 var end = prev();
17040 expr.start = start;
17041 expr.end = end;
17042 return expr;
17043 };
17044 };
17045
17046 function handle_regexp() {
17047 if (is("operator", "/") || is("operator", "/=")) {
17048 S.peeked = null;
17049 S.token = S.input(S.token.value.substr(1)); // force regexp
17050 }
17051 };
17052
17053 var statement = embed_tokens(function() {
17054 var tmp;
17055 handle_regexp();
17056 switch (S.token.type) {
17057 case "string":
17058 var dir = S.in_directives, stat = simple_statement();
17059 // XXXv2: decide how to fix directives
17060 if (dir && stat.body instanceof AST_String && !is("punc", ","))
17061 return new AST_Directive({ value: stat.body.value });
17062 return stat;
17063 case "num":
17064 case "regexp":
17065 case "operator":
17066 case "atom":
17067 return simple_statement();
17068
17069 case "name":
17070 return is_token(peek(), "punc", ":")
17071 ? labeled_statement()
17072 : simple_statement();
17073
17074 case "punc":
17075 switch (S.token.value) {
17076 case "{":
17077 return new AST_BlockStatement({
17078 start : S.token,
17079 body : block_(),
17080 end : prev()
16514 }); 17081 });
16515 return stat; 17082 case "[":
16516 17083 case "(":
16517 case "num":
16518 case "regexp":
16519 case "operator":
16520 case "atom":
16521 return simple_statement(); 17084 return simple_statement();
16522 17085 case ";":
16523 case "name":
16524 return is_token(peek(), "punc", ":") ? labeled_statement() : simple_statement();
16525
16526 case "punc":
16527 switch (S.token.value) {
16528 case "{":
16529 return new AST_BlockStatement({
16530 start: S.token,
16531 body: block_(),
16532 end: prev()
16533 });
16534
16535 case "[":
16536 case "(":
16537 return simple_statement();
16538
16539 case ";":
16540 next();
16541 return new AST_EmptyStatement();
16542
16543 default:
16544 unexpected();
16545 }
16546
16547 case "keyword":
16548 switch (tmp = S.token.value, next(), tmp) {
16549 case "break":
16550 return break_cont(AST_Break);
16551
16552 case "continue":
16553 return break_cont(AST_Continue);
16554
16555 case "debugger":
16556 semicolon();
16557 return new AST_Debugger();
16558
16559 case "do":
16560 return new AST_Do({
16561 body: in_loop(statement),
16562 condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(),
16563 tmp)
16564 });
16565
16566 case "while":
16567 return new AST_While({
16568 condition: parenthesised(),
16569 body: in_loop(statement)
16570 });
16571
16572 case "for":
16573 return for_();
16574
16575 case "function":
16576 return function_(true);
16577
16578 case "if":
16579 return if_();
16580
16581 case "return":
16582 if (S.in_function == 0) croak("'return' outside of function");
16583 return new AST_Return({
16584 value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true),
16585 semicolon(), tmp)
16586 });
16587
16588 case "switch":
16589 return new AST_Switch({
16590 expression: parenthesised(),
16591 body: in_loop(switch_body_)
16592 });
16593
16594 case "throw":
16595 if (S.token.nlb) croak("Illegal newline after 'throw'");
16596 return new AST_Throw({
16597 value: (tmp = expression(true), semicolon(), tmp)
16598 });
16599
16600 case "try":
16601 return try_();
16602
16603 case "var":
16604 return tmp = var_(), semicolon(), tmp;
16605
16606 case "const":
16607 return tmp = const_(), semicolon(), tmp;
16608
16609 case "with":
16610 return new AST_With({
16611 expression: parenthesised(),
16612 body: statement()
16613 });
16614
16615 default:
16616 unexpected();
16617 }
16618 }
16619 });
16620 function labeled_statement() {
16621 var label = as_symbol(AST_Label);
16622 if (find_if(function(l) {
16623 return l.name == label.name;
16624 }, S.labels)) {
16625 croak("Label " + label.name + " defined twice");
16626 }
16627 expect(":");
16628 S.labels.push(label);
16629 var stat = statement();
16630 S.labels.pop();
16631 return new AST_LabeledStatement({
16632 body: stat,
16633 label: label
16634 });
16635 }
16636 function simple_statement(tmp) {
16637 return new AST_SimpleStatement({
16638 body: (tmp = expression(true), semicolon(), tmp)
16639 });
16640 }
16641 function break_cont(type) {
16642 var label = null;
16643 if (!can_insert_semicolon()) {
16644 label = as_symbol(AST_LabelRef, true);
16645 }
16646 if (label != null) {
16647 if (!find_if(function(l) {
16648 return l.name == label.name;
16649 }, S.labels)) croak("Undefined label " + label.name);
16650 } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
16651 semicolon();
16652 return new type({
16653 label: label
16654 });
16655 }
16656 function for_() {
16657 expect("(");
16658 var init = null;
16659 if (!is("punc", ";")) {
16660 init = is("keyword", "var") ? (next(), var_(true)) : expression(true, true);
16661 if (is("operator", "in")) {
16662 if (init instanceof AST_Var && init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop");
16663 next();
16664 return for_in(init);
16665 }
16666 }
16667 return regular_for(init);
16668 }
16669 function regular_for(init) {
16670 expect(";");
16671 var test = is("punc", ";") ? null : expression(true);
16672 expect(";");
16673 var step = is("punc", ")") ? null : expression(true);
16674 expect(")");
16675 return new AST_For({
16676 init: init,
16677 condition: test,
16678 step: step,
16679 body: in_loop(statement)
16680 });
16681 }
16682 function for_in(init) {
16683 var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
16684 var obj = expression(true);
16685 expect(")");
16686 return new AST_ForIn({
16687 init: init,
16688 name: lhs,
16689 object: obj,
16690 body: in_loop(statement)
16691 });
16692 }
16693 var function_ = function(in_statement, ctor) {
16694 var is_accessor = ctor === AST_Accessor;
16695 var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : is_accessor ? AST_SymbolAccessor : AST_SymbolLambda) : is_accessor && (is("string") || is("num")) ? as_atom_node() : null;
16696 if (in_statement && !name) unexpected();
16697 expect("(");
16698 if (!ctor) ctor = in_statement ? AST_Defun : AST_Function;
16699 return new ctor({
16700 name: name,
16701 argnames: function(first, a) {
16702 while (!is("punc", ")")) {
16703 if (first) first = false; else expect(",");
16704 a.push(as_symbol(AST_SymbolFunarg));
16705 }
16706 next();
16707 return a;
16708 }(true, []),
16709 body: function(loop, labels) {
16710 ++S.in_function;
16711 S.in_directives = true;
16712 S.in_loop = 0;
16713 S.labels = [];
16714 var a = block_();
16715 --S.in_function;
16716 S.in_loop = loop;
16717 S.labels = labels;
16718 return a;
16719 }(S.in_loop, S.labels)
16720 });
16721 };
16722 function if_() {
16723 var cond = parenthesised(), body = statement(), belse = null;
16724 if (is("keyword", "else")) {
16725 next(); 17086 next();
16726 belse = statement(); 17087 return new AST_EmptyStatement();
16727 }
16728 return new AST_If({
16729 condition: cond,
16730 body: body,
16731 alternative: belse
16732 });
16733 }
16734 function block_() {
16735 expect("{");
16736 var a = [];
16737 while (!is("punc", "}")) {
16738 if (is("eof")) unexpected();
16739 a.push(statement());
16740 }
16741 next();
16742 return a;
16743 }
16744 function switch_body_() {
16745 expect("{");
16746 var a = [], cur = null, branch = null, tmp;
16747 while (!is("punc", "}")) {
16748 if (is("eof")) unexpected();
16749 if (is("keyword", "case")) {
16750 if (branch) branch.end = prev();
16751 cur = [];
16752 branch = new AST_Case({
16753 start: (tmp = S.token, next(), tmp),
16754 expression: expression(true),
16755 body: cur
16756 });
16757 a.push(branch);
16758 expect(":");
16759 } else if (is("keyword", "default")) {
16760 if (branch) branch.end = prev();
16761 cur = [];
16762 branch = new AST_Default({
16763 start: (tmp = S.token, next(), expect(":"), tmp),
16764 body: cur
16765 });
16766 a.push(branch);
16767 } else {
16768 if (!cur) unexpected();
16769 cur.push(statement());
16770 }
16771 }
16772 if (branch) branch.end = prev();
16773 next();
16774 return a;
16775 }
16776 function try_() {
16777 var body = block_(), bcatch = null, bfinally = null;
16778 if (is("keyword", "catch")) {
16779 var start = S.token;
16780 next();
16781 expect("(");
16782 var name = as_symbol(AST_SymbolCatch);
16783 expect(")");
16784 bcatch = new AST_Catch({
16785 start: start,
16786 argname: name,
16787 body: block_(),
16788 end: prev()
16789 });
16790 }
16791 if (is("keyword", "finally")) {
16792 var start = S.token;
16793 next();
16794 bfinally = new AST_Finally({
16795 start: start,
16796 body: block_(),
16797 end: prev()
16798 });
16799 }
16800 if (!bcatch && !bfinally) croak("Missing catch/finally blocks");
16801 return new AST_Try({
16802 body: body,
16803 bcatch: bcatch,
16804 bfinally: bfinally
16805 });
16806 }
16807 function vardefs(no_in, in_const) {
16808 var a = [];
16809 for (;;) {
16810 a.push(new AST_VarDef({
16811 start: S.token,
16812 name: as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
16813 value: is("operator", "=") ? (next(), expression(false, no_in)) : null,
16814 end: prev()
16815 }));
16816 if (!is("punc", ",")) break;
16817 next();
16818 }
16819 return a;
16820 }
16821 var var_ = function(no_in) {
16822 return new AST_Var({
16823 start: prev(),
16824 definitions: vardefs(no_in, false),
16825 end: prev()
16826 });
16827 };
16828 var const_ = function() {
16829 return new AST_Const({
16830 start: prev(),
16831 definitions: vardefs(false, true),
16832 end: prev()
16833 });
16834 };
16835 var new_ = function() {
16836 var start = S.token;
16837 expect_token("operator", "new");
16838 var newexp = expr_atom(false), args;
16839 if (is("punc", "(")) {
16840 next();
16841 args = expr_list(")");
16842 } else {
16843 args = [];
16844 }
16845 return subscripts(new AST_New({
16846 start: start,
16847 expression: newexp,
16848 args: args,
16849 end: prev()
16850 }), true);
16851 };
16852 function as_atom_node() {
16853 var tok = S.token, ret;
16854 switch (tok.type) {
16855 case "name":
16856 return as_symbol(AST_SymbolRef);
16857
16858 case "num":
16859 ret = new AST_Number({
16860 start: tok,
16861 end: tok,
16862 value: tok.value
16863 });
16864 break;
16865
16866 case "string":
16867 ret = new AST_String({
16868 start: tok,
16869 end: tok,
16870 value: tok.value
16871 });
16872 break;
16873
16874 case "regexp":
16875 ret = new AST_RegExp({
16876 start: tok,
16877 end: tok,
16878 value: tok.value
16879 });
16880 break;
16881
16882 case "atom":
16883 switch (tok.value) {
16884 case "false":
16885 ret = new AST_False({
16886 start: tok,
16887 end: tok
16888 });
16889 break;
16890
16891 case "true":
16892 ret = new AST_True({
16893 start: tok,
16894 end: tok
16895 });
16896 break;
16897
16898 case "null":
16899 ret = new AST_Null({
16900 start: tok,
16901 end: tok
16902 });
16903 break;
16904 }
16905 break;
16906 }
16907 next();
16908 return ret;
16909 }
16910 var expr_atom = function(allow_calls) {
16911 if (is("operator", "new")) {
16912 return new_();
16913 }
16914 var start = S.token;
16915 if (is("punc")) {
16916 switch (start.value) {
16917 case "(":
16918 next();
16919 var ex = expression(true);
16920 ex.start = start;
16921 ex.end = S.token;
16922 expect(")");
16923 return subscripts(ex, allow_calls);
16924
16925 case "[":
16926 return subscripts(array_(), allow_calls);
16927
16928 case "{":
16929 return subscripts(object_(), allow_calls);
16930 }
16931 unexpected();
16932 }
16933 if (is("keyword", "function")) {
16934 next();
16935 var func = function_(false);
16936 func.start = start;
16937 func.end = prev();
16938 return subscripts(func, allow_calls);
16939 }
16940 if (ATOMIC_START_TOKEN[S.token.type]) {
16941 return subscripts(as_atom_node(), allow_calls);
16942 }
16943 unexpected();
16944 };
16945 function expr_list(closing, allow_trailing_comma, allow_empty) {
16946 var first = true, a = [];
16947 while (!is("punc", closing)) {
16948 if (first) first = false; else expect(",");
16949 if (allow_trailing_comma && is("punc", closing)) break;
16950 if (is("punc", ",") && allow_empty) {
16951 a.push(new AST_Hole({
16952 start: S.token,
16953 end: S.token
16954 }));
16955 } else {
16956 a.push(expression(false));
16957 }
16958 }
16959 next();
16960 return a;
16961 }
16962 var array_ = embed_tokens(function() {
16963 expect("[");
16964 return new AST_Array({
16965 elements: expr_list("]", !options.strict, true)
16966 });
16967 });
16968 var object_ = embed_tokens(function() {
16969 expect("{");
16970 var first = true, a = [];
16971 while (!is("punc", "}")) {
16972 if (first) first = false; else expect(",");
16973 if (!options.strict && is("punc", "}")) break;
16974 var start = S.token;
16975 var type = start.type;
16976 var name = as_property_name();
16977 if (type == "name" && !is("punc", ":")) {
16978 if (name == "get") {
16979 a.push(new AST_ObjectGetter({
16980 start: start,
16981 key: name,
16982 value: function_(false, AST_Accessor),
16983 end: prev()
16984 }));
16985 continue;
16986 }
16987 if (name == "set") {
16988 a.push(new AST_ObjectSetter({
16989 start: start,
16990 key: name,
16991 value: function_(false, AST_Accessor),
16992 end: prev()
16993 }));
16994 continue;
16995 }
16996 }
16997 expect(":");
16998 a.push(new AST_ObjectKeyVal({
16999 start: start,
17000 key: name,
17001 value: expression(false),
17002 end: prev()
17003 }));
17004 }
17005 next();
17006 return new AST_Object({
17007 properties: a
17008 });
17009 });
17010 function as_property_name() {
17011 var tmp = S.token;
17012 next();
17013 switch (tmp.type) {
17014 case "num":
17015 case "string":
17016 case "name":
17017 case "operator":
17018 case "keyword":
17019 case "atom":
17020 return tmp.value;
17021
17022 default: 17088 default:
17023 unexpected(); 17089 unexpected();
17024 } 17090 }
17025 } 17091
17026 function as_name() { 17092 case "keyword":
17027 var tmp = S.token; 17093 switch (tmp = S.token.value, next(), tmp) {
17028 next(); 17094 case "break":
17029 switch (tmp.type) { 17095 return break_cont(AST_Break);
17030 case "name": 17096
17031 case "operator": 17097 case "continue":
17032 case "keyword": 17098 return break_cont(AST_Continue);
17033 case "atom": 17099
17034 return tmp.value; 17100 case "debugger":
17101 semicolon();
17102 return new AST_Debugger();
17103
17104 case "do":
17105 return new AST_Do({
17106 body : in_loop(statement),
17107 condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp)
17108 });
17109
17110 case "while":
17111 return new AST_While({
17112 condition : parenthesised(),
17113 body : in_loop(statement)
17114 });
17115
17116 case "for":
17117 return for_();
17118
17119 case "function":
17120 return function_(AST_Defun);
17121
17122 case "if":
17123 return if_();
17124
17125 case "return":
17126 if (S.in_function == 0)
17127 croak("'return' outside of function");
17128 return new AST_Return({
17129 value: ( is("punc", ";")
17130 ? (next(), null)
17131 : can_insert_semicolon()
17132 ? null
17133 : (tmp = expression(true), semicolon(), tmp) )
17134 });
17135
17136 case "switch":
17137 return new AST_Switch({
17138 expression : parenthesised(),
17139 body : in_loop(switch_body_)
17140 });
17141
17142 case "throw":
17143 if (S.token.nlb)
17144 croak("Illegal newline after 'throw'");
17145 return new AST_Throw({
17146 value: (tmp = expression(true), semicolon(), tmp)
17147 });
17148
17149 case "try":
17150 return try_();
17151
17152 case "var":
17153 return tmp = var_(), semicolon(), tmp;
17154
17155 case "const":
17156 return tmp = const_(), semicolon(), tmp;
17157
17158 case "with":
17159 return new AST_With({
17160 expression : parenthesised(),
17161 body : statement()
17162 });
17035 17163
17036 default: 17164 default:
17037 unexpected(); 17165 unexpected();
17038 } 17166 }
17039 } 17167 }
17040 function as_symbol(type, noerror) { 17168 });
17041 if (!is("name")) { 17169
17042 if (!noerror) croak("Name expected"); 17170 function labeled_statement() {
17043 return null; 17171 var label = as_symbol(AST_Label);
17044 } 17172 if (find_if(function(l){ return l.name == label.name }, S.labels)) {
17045 var name = S.token.value; 17173 // ECMA-262, 12.12: An ECMAScript program is considered
17046 var sym = new (name == "this" ? AST_This : type)({ 17174 // syntactically incorrect if it contains a
17047 name: String(S.token.value), 17175 // LabelledStatement that is enclosed by a
17048 start: S.token, 17176 // LabelledStatement with the same Identifier as label.
17049 end: S.token 17177 croak("Label " + label.name + " defined twice");
17178 }
17179 expect(":");
17180 S.labels.push(label);
17181 var stat = statement();
17182 S.labels.pop();
17183 if (!(stat instanceof AST_IterationStatement)) {
17184 // check for `continue` that refers to this label.
17185 // those should be reported as syntax errors.
17186 // https://github.com/mishoo/UglifyJS2/issues/287
17187 label.references.forEach(function(ref){
17188 if (ref instanceof AST_Continue) {
17189 ref = ref.label.start;
17190 croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
17191 ref.line, ref.col, ref.pos);
17192 }
17050 }); 17193 });
17194 }
17195 return new AST_LabeledStatement({ body: stat, label: label });
17196 };
17197
17198 function simple_statement(tmp) {
17199 return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
17200 };
17201
17202 function break_cont(type) {
17203 var label = null, ldef;
17204 if (!can_insert_semicolon()) {
17205 label = as_symbol(AST_LabelRef, true);
17206 }
17207 if (label != null) {
17208 ldef = find_if(function(l){ return l.name == label.name }, S.labels);
17209 if (!ldef)
17210 croak("Undefined label " + label.name);
17211 label.thedef = ldef;
17212 }
17213 else if (S.in_loop == 0)
17214 croak(type.TYPE + " not inside a loop or switch");
17215 semicolon();
17216 var stat = new type({ label: label });
17217 if (ldef) ldef.references.push(stat);
17218 return stat;
17219 };
17220
17221 function for_() {
17222 expect("(");
17223 var init = null;
17224 if (!is("punc", ";")) {
17225 init = is("keyword", "var")
17226 ? (next(), var_(true))
17227 : expression(true, true);
17228 if (is("operator", "in")) {
17229 if (init instanceof AST_Var && init.definitions.length > 1)
17230 croak("Only one variable declaration allowed in for..in loop");
17231 next();
17232 return for_in(init);
17233 }
17234 }
17235 return regular_for(init);
17236 };
17237
17238 function regular_for(init) {
17239 expect(";");
17240 var test = is("punc", ";") ? null : expression(true);
17241 expect(";");
17242 var step = is("punc", ")") ? null : expression(true);
17243 expect(")");
17244 return new AST_For({
17245 init : init,
17246 condition : test,
17247 step : step,
17248 body : in_loop(statement)
17249 });
17250 };
17251
17252 function for_in(init) {
17253 var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
17254 var obj = expression(true);
17255 expect(")");
17256 return new AST_ForIn({
17257 init : init,
17258 name : lhs,
17259 object : obj,
17260 body : in_loop(statement)
17261 });
17262 };
17263
17264 var function_ = function(ctor) {
17265 var in_statement = ctor === AST_Defun;
17266 var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
17267 if (in_statement && !name)
17268 unexpected();
17269 expect("(");
17270 return new ctor({
17271 name: name,
17272 argnames: (function(first, a){
17273 while (!is("punc", ")")) {
17274 if (first) first = false; else expect(",");
17275 a.push(as_symbol(AST_SymbolFunarg));
17276 }
17277 next();
17278 return a;
17279 })(true, []),
17280 body: (function(loop, labels){
17281 ++S.in_function;
17282 S.in_directives = true;
17283 S.in_loop = 0;
17284 S.labels = [];
17285 var a = block_();
17286 --S.in_function;
17287 S.in_loop = loop;
17288 S.labels = labels;
17289 return a;
17290 })(S.in_loop, S.labels)
17291 });
17292 };
17293
17294 function if_() {
17295 var cond = parenthesised(), body = statement(), belse = null;
17296 if (is("keyword", "else")) {
17051 next(); 17297 next();
17052 return sym; 17298 belse = statement();
17053 } 17299 }
17054 var subscripts = function(expr, allow_calls) { 17300 return new AST_If({
17055 var start = expr.start; 17301 condition : cond,
17056 if (is("punc", ".")) { 17302 body : body,
17303 alternative : belse
17304 });
17305 };
17306
17307 function block_() {
17308 expect("{");
17309 var a = [];
17310 while (!is("punc", "}")) {
17311 if (is("eof")) unexpected();
17312 a.push(statement());
17313 }
17314 next();
17315 return a;
17316 };
17317
17318 function switch_body_() {
17319 expect("{");
17320 var a = [], cur = null, branch = null, tmp;
17321 while (!is("punc", "}")) {
17322 if (is("eof")) unexpected();
17323 if (is("keyword", "case")) {
17324 if (branch) branch.end = prev();
17325 cur = [];
17326 branch = new AST_Case({
17327 start : (tmp = S.token, next(), tmp),
17328 expression : expression(true),
17329 body : cur
17330 });
17331 a.push(branch);
17332 expect(":");
17333 }
17334 else if (is("keyword", "default")) {
17335 if (branch) branch.end = prev();
17336 cur = [];
17337 branch = new AST_Default({
17338 start : (tmp = S.token, next(), expect(":"), tmp),
17339 body : cur
17340 });
17341 a.push(branch);
17342 }
17343 else {
17344 if (!cur) unexpected();
17345 cur.push(statement());
17346 }
17347 }
17348 if (branch) branch.end = prev();
17349 next();
17350 return a;
17351 };
17352
17353 function try_() {
17354 var body = block_(), bcatch = null, bfinally = null;
17355 if (is("keyword", "catch")) {
17356 var start = S.token;
17357 next();
17358 expect("(");
17359 var name = as_symbol(AST_SymbolCatch);
17360 expect(")");
17361 bcatch = new AST_Catch({
17362 start : start,
17363 argname : name,
17364 body : block_(),
17365 end : prev()
17366 });
17367 }
17368 if (is("keyword", "finally")) {
17369 var start = S.token;
17370 next();
17371 bfinally = new AST_Finally({
17372 start : start,
17373 body : block_(),
17374 end : prev()
17375 });
17376 }
17377 if (!bcatch && !bfinally)
17378 croak("Missing catch/finally blocks");
17379 return new AST_Try({
17380 body : body,
17381 bcatch : bcatch,
17382 bfinally : bfinally
17383 });
17384 };
17385
17386 function vardefs(no_in, in_const) {
17387 var a = [];
17388 for (;;) {
17389 a.push(new AST_VarDef({
17390 start : S.token,
17391 name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
17392 value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
17393 end : prev()
17394 }));
17395 if (!is("punc", ","))
17396 break;
17397 next();
17398 }
17399 return a;
17400 };
17401
17402 var var_ = function(no_in) {
17403 return new AST_Var({
17404 start : prev(),
17405 definitions : vardefs(no_in, false),
17406 end : prev()
17407 });
17408 };
17409
17410 var const_ = function() {
17411 return new AST_Const({
17412 start : prev(),
17413 definitions : vardefs(false, true),
17414 end : prev()
17415 });
17416 };
17417
17418 var new_ = function() {
17419 var start = S.token;
17420 expect_token("operator", "new");
17421 var newexp = expr_atom(false), args;
17422 if (is("punc", "(")) {
17423 next();
17424 args = expr_list(")");
17425 } else {
17426 args = [];
17427 }
17428 return subscripts(new AST_New({
17429 start : start,
17430 expression : newexp,
17431 args : args,
17432 end : prev()
17433 }), true);
17434 };
17435
17436 function as_atom_node() {
17437 var tok = S.token, ret;
17438 switch (tok.type) {
17439 case "name":
17440 case "keyword":
17441 ret = _make_symbol(AST_SymbolRef);
17442 break;
17443 case "num":
17444 ret = new AST_Number({ start: tok, end: tok, value: tok.value });
17445 break;
17446 case "string":
17447 ret = new AST_String({ start: tok, end: tok, value: tok.value });
17448 break;
17449 case "regexp":
17450 ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
17451 break;
17452 case "atom":
17453 switch (tok.value) {
17454 case "false":
17455 ret = new AST_False({ start: tok, end: tok });
17456 break;
17457 case "true":
17458 ret = new AST_True({ start: tok, end: tok });
17459 break;
17460 case "null":
17461 ret = new AST_Null({ start: tok, end: tok });
17462 break;
17463 }
17464 break;
17465 }
17466 next();
17467 return ret;
17468 };
17469
17470 var expr_atom = function(allow_calls) {
17471 if (is("operator", "new")) {
17472 return new_();
17473 }
17474 var start = S.token;
17475 if (is("punc")) {
17476 switch (start.value) {
17477 case "(":
17057 next(); 17478 next();
17058 return subscripts(new AST_Dot({ 17479 var ex = expression(true);
17059 start: start,
17060 expression: expr,
17061 property: as_name(),
17062 end: prev()
17063 }), allow_calls);
17064 }
17065 if (is("punc", "[")) {
17066 next();
17067 var prop = expression(true);
17068 expect("]");
17069 return subscripts(new AST_Sub({
17070 start: start,
17071 expression: expr,
17072 property: prop,
17073 end: prev()
17074 }), allow_calls);
17075 }
17076 if (allow_calls && is("punc", "(")) {
17077 next();
17078 return subscripts(new AST_Call({
17079 start: start,
17080 expression: expr,
17081 args: expr_list(")"),
17082 end: prev()
17083 }), true);
17084 }
17085 return expr;
17086 };
17087 var maybe_unary = function(allow_calls) {
17088 var start = S.token;
17089 if (is("operator") && UNARY_PREFIX(start.value)) {
17090 next();
17091 var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
17092 ex.start = start; 17480 ex.start = start;
17093 ex.end = prev(); 17481 ex.end = S.token;
17094 return ex; 17482 expect(")");
17095 } 17483 return subscripts(ex, allow_calls);
17096 var val = expr_atom(allow_calls); 17484 case "[":
17097 while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { 17485 return subscripts(array_(), allow_calls);
17098 val = make_unary(AST_UnaryPostfix, S.token.value, val); 17486 case "{":
17099 val.start = start; 17487 return subscripts(object_(), allow_calls);
17100 val.end = S.token; 17488 }
17101 next(); 17489 unexpected();
17102 } 17490 }
17103 return val; 17491 if (is("keyword", "function")) {
17104 }; 17492 next();
17105 function make_unary(ctor, op, expr) { 17493 var func = function_(AST_Function);
17106 if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator"); 17494 func.start = start;
17107 return new ctor({ 17495 func.end = prev();
17108 operator: op, 17496 return subscripts(func, allow_calls);
17109 expression: expr 17497 }
17110 }); 17498 if (ATOMIC_START_TOKEN[S.token.type]) {
17111 } 17499 return subscripts(as_atom_node(), allow_calls);
17112 var expr_op = function(left, min_prec, no_in) { 17500 }
17113 var op = is("operator") ? S.token.value : null; 17501 unexpected();
17114 if (op == "in" && no_in) op = null; 17502 };
17115 var prec = op != null ? PRECEDENCE[op] : null; 17503
17116 if (prec != null && prec > min_prec) { 17504 function expr_list(closing, allow_trailing_comma, allow_empty) {
17117 next(); 17505 var first = true, a = [];
17118 var right = expr_op(maybe_unary(true), prec, no_in); 17506 while (!is("punc", closing)) {
17119 return expr_op(new AST_Binary({ 17507 if (first) first = false; else expect(",");
17120 start: left.start, 17508 if (allow_trailing_comma && is("punc", closing)) break;
17121 left: left, 17509 if (is("punc", ",") && allow_empty) {
17122 operator: op, 17510 a.push(new AST_Hole({ start: S.token, end: S.token }));
17123 right: right,
17124 end: right.end
17125 }), min_prec, no_in);
17126 }
17127 return left;
17128 };
17129 function expr_ops(no_in) {
17130 return expr_op(maybe_unary(true), 0, no_in);
17131 }
17132 var maybe_conditional = function(no_in) {
17133 var start = S.token;
17134 var expr = expr_ops(no_in);
17135 if (is("operator", "?")) {
17136 next();
17137 var yes = expression(false);
17138 expect(":");
17139 return new AST_Conditional({
17140 start: start,
17141 condition: expr,
17142 consequent: yes,
17143 alternative: expression(false, no_in),
17144 end: peek()
17145 });
17146 }
17147 return expr;
17148 };
17149 function is_assignable(expr) {
17150 if (!options.strict) return true;
17151 if (expr instanceof AST_This) return false;
17152 return expr instanceof AST_PropAccess || expr instanceof AST_Symbol;
17153 }
17154 var maybe_assign = function(no_in) {
17155 var start = S.token;
17156 var left = maybe_conditional(no_in), val = S.token.value;
17157 if (is("operator") && ASSIGNMENT(val)) {
17158 if (is_assignable(left)) {
17159 next();
17160 return new AST_Assign({
17161 start: start,
17162 left: left,
17163 operator: val,
17164 right: maybe_assign(no_in),
17165 end: prev()
17166 });
17167 }
17168 croak("Invalid assignment");
17169 }
17170 return left;
17171 };
17172 var expression = function(commas, no_in) {
17173 var start = S.token;
17174 var expr = maybe_assign(no_in);
17175 if (commas && is("punc", ",")) {
17176 next();
17177 return new AST_Seq({
17178 start: start,
17179 car: expr,
17180 cdr: expression(true, no_in),
17181 end: peek()
17182 });
17183 }
17184 return expr;
17185 };
17186 function in_loop(cont) {
17187 ++S.in_loop;
17188 var ret = cont();
17189 --S.in_loop;
17190 return ret;
17191 }
17192 if (options.expression) {
17193 return expression(true);
17194 }
17195 return function() {
17196 var start = S.token;
17197 var body = [];
17198 while (!is("eof")) body.push(statement());
17199 var end = prev();
17200 var toplevel = options.toplevel;
17201 if (toplevel) {
17202 toplevel.body = toplevel.body.concat(body);
17203 toplevel.end = end;
17204 } else { 17511 } else {
17205 toplevel = new AST_Toplevel({ 17512 a.push(expression(false));
17206 start: start, 17513 }
17207 body: body, 17514 }
17208 end: end 17515 next();
17209 }); 17516 return a;
17210 } 17517 };
17211 return toplevel; 17518
17212 }(); 17519 var array_ = embed_tokens(function() {
17213 } 17520 expect("[");
17214 "use strict"; 17521 return new AST_Array({
17215 function TreeTransformer(before, after) { 17522 elements: expr_list("]", !options.strict, true)
17216 TreeWalker.call(this);
17217 this.before = before;
17218 this.after = after;
17219 }
17220 TreeTransformer.prototype = new TreeWalker();
17221 (function(undefined) {
17222 function _(node, descend) {
17223 node.DEFMETHOD("transform", function(tw, in_list) {
17224 var x, y;
17225 tw.push(this);
17226 if (tw.before) x = tw.before(this, descend, in_list);
17227 if (x === undefined) {
17228 if (!tw.after) {
17229 x = this;
17230 descend(x, tw);
17231 } else {
17232 tw.stack[tw.stack.length - 1] = x = this.clone();
17233 descend(x, tw);
17234 y = tw.after(x, in_list);
17235 if (y !== undefined) x = y;
17236 }
17237 }
17238 tw.pop();
17239 return x;
17240 });
17241 }
17242 function do_list(list, tw) {
17243 return MAP(list, function(node) {
17244 return node.transform(tw, true);
17245 });
17246 }
17247 _(AST_Node, noop);
17248 _(AST_LabeledStatement, function(self, tw) {
17249 self.label = self.label.transform(tw);
17250 self.body = self.body.transform(tw);
17251 });
17252 _(AST_SimpleStatement, function(self, tw) {
17253 self.body = self.body.transform(tw);
17254 });
17255 _(AST_Block, function(self, tw) {
17256 self.body = do_list(self.body, tw);
17257 });
17258 _(AST_DWLoop, function(self, tw) {
17259 self.condition = self.condition.transform(tw);
17260 self.body = self.body.transform(tw);
17261 });
17262 _(AST_For, function(self, tw) {
17263 if (self.init) self.init = self.init.transform(tw);
17264 if (self.condition) self.condition = self.condition.transform(tw);
17265 if (self.step) self.step = self.step.transform(tw);
17266 self.body = self.body.transform(tw);
17267 });
17268 _(AST_ForIn, function(self, tw) {
17269 self.init = self.init.transform(tw);
17270 self.object = self.object.transform(tw);
17271 self.body = self.body.transform(tw);
17272 });
17273 _(AST_With, function(self, tw) {
17274 self.expression = self.expression.transform(tw);
17275 self.body = self.body.transform(tw);
17276 });
17277 _(AST_Exit, function(self, tw) {
17278 if (self.value) self.value = self.value.transform(tw);
17279 });
17280 _(AST_LoopControl, function(self, tw) {
17281 if (self.label) self.label = self.label.transform(tw);
17282 });
17283 _(AST_If, function(self, tw) {
17284 self.condition = self.condition.transform(tw);
17285 self.body = self.body.transform(tw);
17286 if (self.alternative) self.alternative = self.alternative.transform(tw);
17287 });
17288 _(AST_Switch, function(self, tw) {
17289 self.expression = self.expression.transform(tw);
17290 self.body = do_list(self.body, tw);
17291 });
17292 _(AST_Case, function(self, tw) {
17293 self.expression = self.expression.transform(tw);
17294 self.body = do_list(self.body, tw);
17295 });
17296 _(AST_Try, function(self, tw) {
17297 self.body = do_list(self.body, tw);
17298 if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
17299 if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
17300 });
17301 _(AST_Catch, function(self, tw) {
17302 self.argname = self.argname.transform(tw);
17303 self.body = do_list(self.body, tw);
17304 });
17305 _(AST_Definitions, function(self, tw) {
17306 self.definitions = do_list(self.definitions, tw);
17307 });
17308 _(AST_VarDef, function(self, tw) {
17309 self.name = self.name.transform(tw);
17310 if (self.value) self.value = self.value.transform(tw);
17311 });
17312 _(AST_Lambda, function(self, tw) {
17313 if (self.name) self.name = self.name.transform(tw);
17314 self.argnames = do_list(self.argnames, tw);
17315 self.body = do_list(self.body, tw);
17316 });
17317 _(AST_Call, function(self, tw) {
17318 self.expression = self.expression.transform(tw);
17319 self.args = do_list(self.args, tw);
17320 });
17321 _(AST_Seq, function(self, tw) {
17322 self.car = self.car.transform(tw);
17323 self.cdr = self.cdr.transform(tw);
17324 });
17325 _(AST_Dot, function(self, tw) {
17326 self.expression = self.expression.transform(tw);
17327 });
17328 _(AST_Sub, function(self, tw) {
17329 self.expression = self.expression.transform(tw);
17330 self.property = self.property.transform(tw);
17331 });
17332 _(AST_Unary, function(self, tw) {
17333 self.expression = self.expression.transform(tw);
17334 });
17335 _(AST_Binary, function(self, tw) {
17336 self.left = self.left.transform(tw);
17337 self.right = self.right.transform(tw);
17338 });
17339 _(AST_Conditional, function(self, tw) {
17340 self.condition = self.condition.transform(tw);
17341 self.consequent = self.consequent.transform(tw);
17342 self.alternative = self.alternative.transform(tw);
17343 });
17344 _(AST_Array, function(self, tw) {
17345 self.elements = do_list(self.elements, tw);
17346 });
17347 _(AST_Object, function(self, tw) {
17348 self.properties = do_list(self.properties, tw);
17349 });
17350 _(AST_ObjectProperty, function(self, tw) {
17351 self.value = self.value.transform(tw);
17352 });
17353 })();
17354 "use strict";
17355 function SymbolDef(scope, index, orig) {
17356 this.name = orig.name;
17357 this.orig = [ orig ];
17358 this.scope = scope;
17359 this.references = [];
17360 this.global = false;
17361 this.mangled_name = null;
17362 this.undeclared = false;
17363 this.constant = false;
17364 this.index = index;
17365 }
17366 SymbolDef.prototype = {
17367 unmangleable: function(options) {
17368 return this.global && !(options && options.toplevel) || this.undeclared || !(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with);
17369 },
17370 mangle: function(options) {
17371 if (!this.mangled_name && !this.unmangleable(options)) {
17372 var s = this.scope;
17373 if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8) s = s.parent_scope;
17374 this.mangled_name = s.next_mangled(options);
17375 }
17376 }
17377 };
17378 AST_Toplevel.DEFMETHOD("figure_out_scope", function() {
17379 var self = this;
17380 var scope = self.parent_scope = null;
17381 var labels = new Dictionary();
17382 var nesting = 0;
17383 var tw = new TreeWalker(function(node, descend) {
17384 if (node instanceof AST_Scope) {
17385 node.init_scope_vars(nesting);
17386 var save_scope = node.parent_scope = scope;
17387 var save_labels = labels;
17388 ++nesting;
17389 scope = node;
17390 labels = new Dictionary();
17391 descend();
17392 labels = save_labels;
17393 scope = save_scope;
17394 --nesting;
17395 return true;
17396 }
17397 if (node instanceof AST_Directive) {
17398 node.scope = scope;
17399 push_uniq(scope.directives, node.value);
17400 return true;
17401 }
17402 if (node instanceof AST_With) {
17403 for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
17404 return;
17405 }
17406 if (node instanceof AST_LabeledStatement) {
17407 var l = node.label;
17408 if (labels.has(l.name)) throw new Error(string_template("Label {name} defined twice", l));
17409 labels.set(l.name, l);
17410 descend();
17411 labels.del(l.name);
17412 return true;
17413 }
17414 if (node instanceof AST_Symbol) {
17415 node.scope = scope;
17416 }
17417 if (node instanceof AST_Label) {
17418 node.thedef = node;
17419 node.init_scope_vars();
17420 }
17421 if (node instanceof AST_SymbolLambda) {
17422 scope.def_function(node);
17423 } else if (node instanceof AST_SymbolDefun) {
17424 (node.scope = scope.parent_scope).def_function(node);
17425 } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) {
17426 var def = scope.def_variable(node);
17427 def.constant = node instanceof AST_SymbolConst;
17428 def.init = tw.parent().value;
17429 } else if (node instanceof AST_SymbolCatch) {
17430 scope.def_variable(node);
17431 }
17432 if (node instanceof AST_LabelRef) {
17433 var sym = labels.get(node.name);
17434 if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
17435 name: node.name,
17436 line: node.start.line,
17437 col: node.start.col
17438 }));
17439 node.thedef = sym;
17440 }
17441 });
17442 self.walk(tw);
17443 var func = null;
17444 var globals = self.globals = new Dictionary();
17445 var tw = new TreeWalker(function(node, descend) {
17446 if (node instanceof AST_Lambda) {
17447 var prev_func = func;
17448 func = node;
17449 descend();
17450 func = prev_func;
17451 return true;
17452 }
17453 if (node instanceof AST_LabelRef) {
17454 node.reference();
17455 return true;
17456 }
17457 if (node instanceof AST_SymbolRef) {
17458 var name = node.name;
17459 var sym = node.scope.find_variable(name);
17460 if (!sym) {
17461 var g;
17462 if (globals.has(name)) {
17463 g = globals.get(name);
17464 } else {
17465 g = new SymbolDef(self, globals.size(), node);
17466 g.undeclared = true;
17467 g.global = true;
17468 globals.set(name, g);
17469 }
17470 node.thedef = g;
17471 if (name == "eval" && tw.parent() instanceof AST_Call) {
17472 for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) s.uses_eval = true;
17473 }
17474 if (name == "arguments") {
17475 func.uses_arguments = true;
17476 }
17477 } else {
17478 node.thedef = sym;
17479 }
17480 node.reference();
17481 return true;
17482 }
17483 });
17484 self.walk(tw);
17485 });
17486 AST_Scope.DEFMETHOD("init_scope_vars", function(nesting) {
17487 this.directives = [];
17488 this.variables = new Dictionary();
17489 this.functions = new Dictionary();
17490 this.uses_with = false;
17491 this.uses_eval = false;
17492 this.parent_scope = null;
17493 this.enclosed = [];
17494 this.cname = -1;
17495 this.nesting = nesting;
17496 });
17497 AST_Scope.DEFMETHOD("strict", function() {
17498 return this.has_directive("use strict");
17499 });
17500 AST_Lambda.DEFMETHOD("init_scope_vars", function() {
17501 AST_Scope.prototype.init_scope_vars.apply(this, arguments);
17502 this.uses_arguments = false;
17503 });
17504 AST_SymbolRef.DEFMETHOD("reference", function() {
17505 var def = this.definition();
17506 def.references.push(this);
17507 var s = this.scope;
17508 while (s) {
17509 push_uniq(s.enclosed, def);
17510 if (s === def.scope) break;
17511 s = s.parent_scope;
17512 }
17513 this.frame = this.scope.nesting - def.scope.nesting;
17514 });
17515 AST_Label.DEFMETHOD("init_scope_vars", function() {
17516 this.references = [];
17517 });
17518 AST_LabelRef.DEFMETHOD("reference", function() {
17519 this.thedef.references.push(this);
17520 });
17521 AST_Scope.DEFMETHOD("find_variable", function(name) {
17522 if (name instanceof AST_Symbol) name = name.name;
17523 return this.variables.get(name) || this.parent_scope && this.parent_scope.find_variable(name);
17524 });
17525 AST_Scope.DEFMETHOD("has_directive", function(value) {
17526 return this.parent_scope && this.parent_scope.has_directive(value) || (this.directives.indexOf(value) >= 0 ? this : null);
17527 });
17528 AST_Scope.DEFMETHOD("def_function", function(symbol) {
17529 this.functions.set(symbol.name, this.def_variable(symbol));
17530 });
17531 AST_Scope.DEFMETHOD("def_variable", function(symbol) {
17532 var def;
17533 if (!this.variables.has(symbol.name)) {
17534 def = new SymbolDef(this, this.variables.size(), symbol);
17535 this.variables.set(symbol.name, def);
17536 def.global = !this.parent_scope;
17537 } else {
17538 def = this.variables.get(symbol.name);
17539 def.orig.push(symbol);
17540 }
17541 return symbol.thedef = def;
17542 });
17543 AST_Scope.DEFMETHOD("next_mangled", function(options) {
17544 var ext = this.enclosed;
17545 out: while (true) {
17546 var m = base54(++this.cname);
17547 if (!is_identifier(m)) continue;
17548 for (var i = ext.length; --i >= 0; ) {
17549 var sym = ext[i];
17550 var name = sym.mangled_name || sym.unmangleable(options) && sym.name;
17551 if (m == name) continue out;
17552 }
17553 return m;
17554 }
17555 });
17556 AST_Scope.DEFMETHOD("references", function(sym) {
17557 if (sym instanceof AST_Symbol) sym = sym.definition();
17558 return this.enclosed.indexOf(sym) < 0 ? null : sym;
17559 });
17560 AST_Symbol.DEFMETHOD("unmangleable", function(options) {
17561 return this.definition().unmangleable(options);
17562 });
17563 AST_SymbolAccessor.DEFMETHOD("unmangleable", function() {
17564 return true;
17565 });
17566 AST_Label.DEFMETHOD("unmangleable", function() {
17567 return false;
17568 });
17569 AST_Symbol.DEFMETHOD("unreferenced", function() {
17570 return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with);
17571 });
17572 AST_Symbol.DEFMETHOD("undeclared", function() {
17573 return this.definition().undeclared;
17574 });
17575 AST_LabelRef.DEFMETHOD("undeclared", function() {
17576 return false;
17577 });
17578 AST_Label.DEFMETHOD("undeclared", function() {
17579 return false;
17580 });
17581 AST_Symbol.DEFMETHOD("definition", function() {
17582 return this.thedef;
17583 });
17584 AST_Symbol.DEFMETHOD("global", function() {
17585 return this.definition().global;
17586 });
17587 AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
17588 return defaults(options, {
17589 except: [],
17590 eval: false,
17591 sort: false,
17592 toplevel: false,
17593 screw_ie8: false
17594 }); 17523 });
17595 }); 17524 });
17596 AST_Toplevel.DEFMETHOD("mangle_names", function(options) { 17525
17597 options = this._default_mangler_options(options); 17526 var object_ = embed_tokens(function() {
17598 var lname = -1; 17527 expect("{");
17599 var to_mangle = []; 17528 var first = true, a = [];
17600 var tw = new TreeWalker(function(node, descend) { 17529 while (!is("punc", "}")) {
17601 if (node instanceof AST_LabeledStatement) { 17530 if (first) first = false; else expect(",");
17602 var save_nesting = lname; 17531 if (!options.strict && is("punc", "}"))
17603 descend(); 17532 // allow trailing comma
17604 lname = save_nesting; 17533 break;
17605 return true; 17534 var start = S.token;
17606 } 17535 var type = start.type;
17607 if (node instanceof AST_Scope) { 17536 var name = as_property_name();
17608 var p = tw.parent(), a = []; 17537 if (type == "name" && !is("punc", ":")) {
17609 node.variables.each(function(symbol) { 17538 if (name == "get") {
17610 if (options.except.indexOf(symbol.name) < 0) { 17539 a.push(new AST_ObjectGetter({
17611 a.push(symbol); 17540 start : start,
17612 } 17541 key : as_atom_node(),
17542 value : function_(AST_Accessor),
17543 end : prev()
17544 }));
17545 continue;
17546 }
17547 if (name == "set") {
17548 a.push(new AST_ObjectSetter({
17549 start : start,
17550 key : as_atom_node(),
17551 value : function_(AST_Accessor),
17552 end : prev()
17553 }));
17554 continue;
17555 }
17556 }
17557 expect(":");
17558 a.push(new AST_ObjectKeyVal({
17559 start : start,
17560 key : name,
17561 value : expression(false),
17562 end : prev()
17563 }));
17564 }
17565 next();
17566 return new AST_Object({ properties: a });
17567 });
17568
17569 function as_property_name() {
17570 var tmp = S.token;
17571 next();
17572 switch (tmp.type) {
17573 case "num":
17574 case "string":
17575 case "name":
17576 case "operator":
17577 case "keyword":
17578 case "atom":
17579 return tmp.value;
17580 default:
17581 unexpected();
17582 }
17583 };
17584
17585 function as_name() {
17586 var tmp = S.token;
17587 next();
17588 switch (tmp.type) {
17589 case "name":
17590 case "operator":
17591 case "keyword":
17592 case "atom":
17593 return tmp.value;
17594 default:
17595 unexpected();
17596 }
17597 };
17598
17599 function _make_symbol(type) {
17600 var name = S.token.value;
17601 return new (name == "this" ? AST_This : type)({
17602 name : String(name),
17603 start : S.token,
17604 end : S.token
17605 });
17606 };
17607
17608 function as_symbol(type, noerror) {
17609 if (!is("name")) {
17610 if (!noerror) croak("Name expected");
17611 return null;
17612 }
17613 var sym = _make_symbol(type);
17614 next();
17615 return sym;
17616 };
17617
17618 var subscripts = function(expr, allow_calls) {
17619 var start = expr.start;
17620 if (is("punc", ".")) {
17621 next();
17622 return subscripts(new AST_Dot({
17623 start : start,
17624 expression : expr,
17625 property : as_name(),
17626 end : prev()
17627 }), allow_calls);
17628 }
17629 if (is("punc", "[")) {
17630 next();
17631 var prop = expression(true);
17632 expect("]");
17633 return subscripts(new AST_Sub({
17634 start : start,
17635 expression : expr,
17636 property : prop,
17637 end : prev()
17638 }), allow_calls);
17639 }
17640 if (allow_calls && is("punc", "(")) {
17641 next();
17642 return subscripts(new AST_Call({
17643 start : start,
17644 expression : expr,
17645 args : expr_list(")"),
17646 end : prev()
17647 }), true);
17648 }
17649 return expr;
17650 };
17651
17652 var maybe_unary = function(allow_calls) {
17653 var start = S.token;
17654 if (is("operator") && UNARY_PREFIX(start.value)) {
17655 next();
17656 handle_regexp();
17657 var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
17658 ex.start = start;
17659 ex.end = prev();
17660 return ex;
17661 }
17662 var val = expr_atom(allow_calls);
17663 while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
17664 val = make_unary(AST_UnaryPostfix, S.token.value, val);
17665 val.start = start;
17666 val.end = S.token;
17667 next();
17668 }
17669 return val;
17670 };
17671
17672 function make_unary(ctor, op, expr) {
17673 if ((op == "++" || op == "--") && !is_assignable(expr))
17674 croak("Invalid use of " + op + " operator");
17675 return new ctor({ operator: op, expression: expr });
17676 };
17677
17678 var expr_op = function(left, min_prec, no_in) {
17679 var op = is("operator") ? S.token.value : null;
17680 if (op == "in" && no_in) op = null;
17681 var prec = op != null ? PRECEDENCE[op] : null;
17682 if (prec != null && prec > min_prec) {
17683 next();
17684 var right = expr_op(maybe_unary(true), prec, no_in);
17685 return expr_op(new AST_Binary({
17686 start : left.start,
17687 left : left,
17688 operator : op,
17689 right : right,
17690 end : right.end
17691 }), min_prec, no_in);
17692 }
17693 return left;
17694 };
17695
17696 function expr_ops(no_in) {
17697 return expr_op(maybe_unary(true), 0, no_in);
17698 };
17699
17700 var maybe_conditional = function(no_in) {
17701 var start = S.token;
17702 var expr = expr_ops(no_in);
17703 if (is("operator", "?")) {
17704 next();
17705 var yes = expression(false);
17706 expect(":");
17707 return new AST_Conditional({
17708 start : start,
17709 condition : expr,
17710 consequent : yes,
17711 alternative : expression(false, no_in),
17712 end : prev()
17713 });
17714 }
17715 return expr;
17716 };
17717
17718 function is_assignable(expr) {
17719 if (!options.strict) return true;
17720 if (expr instanceof AST_This) return false;
17721 return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
17722 };
17723
17724 var maybe_assign = function(no_in) {
17725 var start = S.token;
17726 var left = maybe_conditional(no_in), val = S.token.value;
17727 if (is("operator") && ASSIGNMENT(val)) {
17728 if (is_assignable(left)) {
17729 next();
17730 return new AST_Assign({
17731 start : start,
17732 left : left,
17733 operator : val,
17734 right : maybe_assign(no_in),
17735 end : prev()
17613 }); 17736 });
17614 if (options.sort) a.sort(function(a, b) { 17737 }
17615 return b.references.length - a.references.length; 17738 croak("Invalid assignment");
17739 }
17740 return left;
17741 };
17742
17743 var expression = function(commas, no_in) {
17744 var start = S.token;
17745 var expr = maybe_assign(no_in);
17746 if (commas && is("punc", ",")) {
17747 next();
17748 return new AST_Seq({
17749 start : start,
17750 car : expr,
17751 cdr : expression(true, no_in),
17752 end : peek()
17753 });
17754 }
17755 return expr;
17756 };
17757
17758 function in_loop(cont) {
17759 ++S.in_loop;
17760 var ret = cont();
17761 --S.in_loop;
17762 return ret;
17763 };
17764
17765 if (options.expression) {
17766 return expression(true);
17767 }
17768
17769 return (function(){
17770 var start = S.token;
17771 var body = [];
17772 while (!is("eof"))
17773 body.push(statement());
17774 var end = prev();
17775 var toplevel = options.toplevel;
17776 if (toplevel) {
17777 toplevel.body = toplevel.body.concat(body);
17778 toplevel.end = end;
17779 } else {
17780 toplevel = new AST_Toplevel({ start: start, body: body, end: end });
17781 }
17782 return toplevel;
17783 })();
17784
17785 };
17786
17787 /***********************************************************************
17788
17789 A JavaScript tokenizer / parser / beautifier / compressor.
17790 https://github.com/mishoo/UglifyJS2
17791
17792 -------------------------------- (C) ---------------------------------
17793
17794 Author: Mihai Bazon
17795 <mihai.bazon@gmail.com>
17796 http://mihai.bazon.net/blog
17797
17798 Distributed under the BSD license:
17799
17800 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
17801
17802 Redistribution and use in source and binary forms, with or without
17803 modification, are permitted provided that the following conditions
17804 are met:
17805
17806 * Redistributions of source code must retain the above
17807 copyright notice, this list of conditions and the following
17808 disclaimer.
17809
17810 * Redistributions in binary form must reproduce the above
17811 copyright notice, this list of conditions and the following
17812 disclaimer in the documentation and/or other materials
17813 provided with the distribution.
17814
17815 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
17816 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17817 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17818 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
17819 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
17820 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17821 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
17822 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
17823 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
17824 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
17825 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17826 SUCH DAMAGE.
17827
17828 ***********************************************************************/
17829
17830 "use strict";
17831
17832 // Tree transformer helpers.
17833
17834 function TreeTransformer(before, after) {
17835 TreeWalker.call(this);
17836 this.before = before;
17837 this.after = after;
17838 }
17839 TreeTransformer.prototype = new TreeWalker;
17840
17841 (function(undefined){
17842
17843 function _(node, descend) {
17844 node.DEFMETHOD("transform", function(tw, in_list){
17845 var x, y;
17846 tw.push(this);
17847 if (tw.before) x = tw.before(this, descend, in_list);
17848 if (x === undefined) {
17849 if (!tw.after) {
17850 x = this;
17851 descend(x, tw);
17852 } else {
17853 tw.stack[tw.stack.length - 1] = x = this.clone();
17854 descend(x, tw);
17855 y = tw.after(x, in_list);
17856 if (y !== undefined) x = y;
17857 }
17858 }
17859 tw.pop();
17860 return x;
17861 });
17862 };
17863
17864 function do_list(list, tw) {
17865 return MAP(list, function(node){
17866 return node.transform(tw, true);
17867 });
17868 };
17869
17870 _(AST_Node, noop);
17871
17872 _(AST_LabeledStatement, function(self, tw){
17873 self.label = self.label.transform(tw);
17874 self.body = self.body.transform(tw);
17875 });
17876
17877 _(AST_SimpleStatement, function(self, tw){
17878 self.body = self.body.transform(tw);
17879 });
17880
17881 _(AST_Block, function(self, tw){
17882 self.body = do_list(self.body, tw);
17883 });
17884
17885 _(AST_DWLoop, function(self, tw){
17886 self.condition = self.condition.transform(tw);
17887 self.body = self.body.transform(tw);
17888 });
17889
17890 _(AST_For, function(self, tw){
17891 if (self.init) self.init = self.init.transform(tw);
17892 if (self.condition) self.condition = self.condition.transform(tw);
17893 if (self.step) self.step = self.step.transform(tw);
17894 self.body = self.body.transform(tw);
17895 });
17896
17897 _(AST_ForIn, function(self, tw){
17898 self.init = self.init.transform(tw);
17899 self.object = self.object.transform(tw);
17900 self.body = self.body.transform(tw);
17901 });
17902
17903 _(AST_With, function(self, tw){
17904 self.expression = self.expression.transform(tw);
17905 self.body = self.body.transform(tw);
17906 });
17907
17908 _(AST_Exit, function(self, tw){
17909 if (self.value) self.value = self.value.transform(tw);
17910 });
17911
17912 _(AST_LoopControl, function(self, tw){
17913 if (self.label) self.label = self.label.transform(tw);
17914 });
17915
17916 _(AST_If, function(self, tw){
17917 self.condition = self.condition.transform(tw);
17918 self.body = self.body.transform(tw);
17919 if (self.alternative) self.alternative = self.alternative.transform(tw);
17920 });
17921
17922 _(AST_Switch, function(self, tw){
17923 self.expression = self.expression.transform(tw);
17924 self.body = do_list(self.body, tw);
17925 });
17926
17927 _(AST_Case, function(self, tw){
17928 self.expression = self.expression.transform(tw);
17929 self.body = do_list(self.body, tw);
17930 });
17931
17932 _(AST_Try, function(self, tw){
17933 self.body = do_list(self.body, tw);
17934 if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
17935 if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
17936 });
17937
17938 _(AST_Catch, function(self, tw){
17939 self.argname = self.argname.transform(tw);
17940 self.body = do_list(self.body, tw);
17941 });
17942
17943 _(AST_Definitions, function(self, tw){
17944 self.definitions = do_list(self.definitions, tw);
17945 });
17946
17947 _(AST_VarDef, function(self, tw){
17948 self.name = self.name.transform(tw);
17949 if (self.value) self.value = self.value.transform(tw);
17950 });
17951
17952 _(AST_Lambda, function(self, tw){
17953 if (self.name) self.name = self.name.transform(tw);
17954 self.argnames = do_list(self.argnames, tw);
17955 self.body = do_list(self.body, tw);
17956 });
17957
17958 _(AST_Call, function(self, tw){
17959 self.expression = self.expression.transform(tw);
17960 self.args = do_list(self.args, tw);
17961 });
17962
17963 _(AST_Seq, function(self, tw){
17964 self.car = self.car.transform(tw);
17965 self.cdr = self.cdr.transform(tw);
17966 });
17967
17968 _(AST_Dot, function(self, tw){
17969 self.expression = self.expression.transform(tw);
17970 });
17971
17972 _(AST_Sub, function(self, tw){
17973 self.expression = self.expression.transform(tw);
17974 self.property = self.property.transform(tw);
17975 });
17976
17977 _(AST_Unary, function(self, tw){
17978 self.expression = self.expression.transform(tw);
17979 });
17980
17981 _(AST_Binary, function(self, tw){
17982 self.left = self.left.transform(tw);
17983 self.right = self.right.transform(tw);
17984 });
17985
17986 _(AST_Conditional, function(self, tw){
17987 self.condition = self.condition.transform(tw);
17988 self.consequent = self.consequent.transform(tw);
17989 self.alternative = self.alternative.transform(tw);
17990 });
17991
17992 _(AST_Array, function(self, tw){
17993 self.elements = do_list(self.elements, tw);
17994 });
17995
17996 _(AST_Object, function(self, tw){
17997 self.properties = do_list(self.properties, tw);
17998 });
17999
18000 _(AST_ObjectProperty, function(self, tw){
18001 self.value = self.value.transform(tw);
18002 });
18003
18004 })();
18005
18006 /***********************************************************************
18007
18008 A JavaScript tokenizer / parser / beautifier / compressor.
18009 https://github.com/mishoo/UglifyJS2
18010
18011 -------------------------------- (C) ---------------------------------
18012
18013 Author: Mihai Bazon
18014 <mihai.bazon@gmail.com>
18015 http://mihai.bazon.net/blog
18016
18017 Distributed under the BSD license:
18018
18019 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
18020
18021 Redistribution and use in source and binary forms, with or without
18022 modification, are permitted provided that the following conditions
18023 are met:
18024
18025 * Redistributions of source code must retain the above
18026 copyright notice, this list of conditions and the following
18027 disclaimer.
18028
18029 * Redistributions in binary form must reproduce the above
18030 copyright notice, this list of conditions and the following
18031 disclaimer in the documentation and/or other materials
18032 provided with the distribution.
18033
18034 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18035 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18036 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18037 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
18038 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
18039 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18040 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18041 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18042 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
18043 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
18044 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18045 SUCH DAMAGE.
18046
18047 ***********************************************************************/
18048
18049 "use strict";
18050
18051 function SymbolDef(scope, index, orig) {
18052 this.name = orig.name;
18053 this.orig = [ orig ];
18054 this.scope = scope;
18055 this.references = [];
18056 this.global = false;
18057 this.mangled_name = null;
18058 this.undeclared = false;
18059 this.constant = false;
18060 this.index = index;
18061 };
18062
18063 SymbolDef.prototype = {
18064 unmangleable: function(options) {
18065 return (this.global && !(options && options.toplevel))
18066 || this.undeclared
18067 || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with));
18068 },
18069 mangle: function(options) {
18070 if (!this.mangled_name && !this.unmangleable(options)) {
18071 var s = this.scope;
18072 if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
18073 s = s.parent_scope;
18074 this.mangled_name = s.next_mangled(options, this);
18075 }
18076 }
18077 };
18078
18079 AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
18080 options = defaults(options, {
18081 screw_ie8: false
18082 });
18083
18084 // pass 1: setup scope chaining and handle definitions
18085 var self = this;
18086 var scope = self.parent_scope = null;
18087 var defun = null;
18088 var nesting = 0;
18089 var tw = new TreeWalker(function(node, descend){
18090 if (options.screw_ie8 && node instanceof AST_Catch) {
18091 var save_scope = scope;
18092 scope = new AST_Scope(node);
18093 scope.init_scope_vars(nesting);
18094 scope.parent_scope = save_scope;
18095 descend();
18096 scope = save_scope;
18097 return true;
18098 }
18099 if (node instanceof AST_Scope) {
18100 node.init_scope_vars(nesting);
18101 var save_scope = node.parent_scope = scope;
18102 var save_defun = defun;
18103 defun = scope = node;
18104 ++nesting; descend(); --nesting;
18105 scope = save_scope;
18106 defun = save_defun;
18107 return true; // don't descend again in TreeWalker
18108 }
18109 if (node instanceof AST_Directive) {
18110 node.scope = scope;
18111 push_uniq(scope.directives, node.value);
18112 return true;
18113 }
18114 if (node instanceof AST_With) {
18115 for (var s = scope; s; s = s.parent_scope)
18116 s.uses_with = true;
18117 return;
18118 }
18119 if (node instanceof AST_Symbol) {
18120 node.scope = scope;
18121 }
18122 if (node instanceof AST_SymbolLambda) {
18123 defun.def_function(node);
18124 }
18125 else if (node instanceof AST_SymbolDefun) {
18126 // Careful here, the scope where this should be defined is
18127 // the parent scope. The reason is that we enter a new
18128 // scope when we encounter the AST_Defun node (which is
18129 // instanceof AST_Scope) but we get to the symbol a bit
18130 // later.
18131 (node.scope = defun.parent_scope).def_function(node);
18132 }
18133 else if (node instanceof AST_SymbolVar
18134 || node instanceof AST_SymbolConst) {
18135 var def = defun.def_variable(node);
18136 def.constant = node instanceof AST_SymbolConst;
18137 def.init = tw.parent().value;
18138 }
18139 else if (node instanceof AST_SymbolCatch) {
18140 (options.screw_ie8 ? scope : defun)
18141 .def_variable(node);
18142 }
18143 });
18144 self.walk(tw);
18145
18146 // pass 2: find back references and eval
18147 var func = null;
18148 var globals = self.globals = new Dictionary();
18149 var tw = new TreeWalker(function(node, descend){
18150 if (node instanceof AST_Lambda) {
18151 var prev_func = func;
18152 func = node;
18153 descend();
18154 func = prev_func;
18155 return true;
18156 }
18157 if (node instanceof AST_SymbolRef) {
18158 var name = node.name;
18159 var sym = node.scope.find_variable(name);
18160 if (!sym) {
18161 var g;
18162 if (globals.has(name)) {
18163 g = globals.get(name);
18164 } else {
18165 g = new SymbolDef(self, globals.size(), node);
18166 g.undeclared = true;
18167 g.global = true;
18168 globals.set(name, g);
18169 }
18170 node.thedef = g;
18171 if (name == "eval" && tw.parent() instanceof AST_Call) {
18172 for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
18173 s.uses_eval = true;
18174 }
18175 if (func && name == "arguments") {
18176 func.uses_arguments = true;
18177 }
18178 } else {
18179 node.thedef = sym;
18180 }
18181 node.reference();
18182 return true;
18183 }
18184 });
18185 self.walk(tw);
18186 });
18187
18188 AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
18189 this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
18190 this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
18191 this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
18192 this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
18193 this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
18194 this.parent_scope = null; // the parent scope
18195 this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
18196 this.cname = -1; // the current index for mangling functions/variables
18197 this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
18198 });
18199
18200 AST_Scope.DEFMETHOD("strict", function(){
18201 return this.has_directive("use strict");
18202 });
18203
18204 AST_Lambda.DEFMETHOD("init_scope_vars", function(){
18205 AST_Scope.prototype.init_scope_vars.apply(this, arguments);
18206 this.uses_arguments = false;
18207 });
18208
18209 AST_SymbolRef.DEFMETHOD("reference", function() {
18210 var def = this.definition();
18211 def.references.push(this);
18212 var s = this.scope;
18213 while (s) {
18214 push_uniq(s.enclosed, def);
18215 if (s === def.scope) break;
18216 s = s.parent_scope;
18217 }
18218 this.frame = this.scope.nesting - def.scope.nesting;
18219 });
18220
18221 AST_Scope.DEFMETHOD("find_variable", function(name){
18222 if (name instanceof AST_Symbol) name = name.name;
18223 return this.variables.get(name)
18224 || (this.parent_scope && this.parent_scope.find_variable(name));
18225 });
18226
18227 AST_Scope.DEFMETHOD("has_directive", function(value){
18228 return this.parent_scope && this.parent_scope.has_directive(value)
18229 || (this.directives.indexOf(value) >= 0 ? this : null);
18230 });
18231
18232 AST_Scope.DEFMETHOD("def_function", function(symbol){
18233 this.functions.set(symbol.name, this.def_variable(symbol));
18234 });
18235
18236 AST_Scope.DEFMETHOD("def_variable", function(symbol){
18237 var def;
18238 if (!this.variables.has(symbol.name)) {
18239 def = new SymbolDef(this, this.variables.size(), symbol);
18240 this.variables.set(symbol.name, def);
18241 def.global = !this.parent_scope;
18242 } else {
18243 def = this.variables.get(symbol.name);
18244 def.orig.push(symbol);
18245 }
18246 return symbol.thedef = def;
18247 });
18248
18249 AST_Scope.DEFMETHOD("next_mangled", function(options){
18250 var ext = this.enclosed;
18251 out: while (true) {
18252 var m = base54(++this.cname);
18253 if (!is_identifier(m)) continue; // skip over "do"
18254
18255 // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
18256 // shadow a name excepted from mangling.
18257 if (options.except.indexOf(m) >= 0) continue;
18258
18259 // we must ensure that the mangled name does not shadow a name
18260 // from some parent scope that is referenced in this or in
18261 // inner scopes.
18262 for (var i = ext.length; --i >= 0;) {
18263 var sym = ext[i];
18264 var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
18265 if (m == name) continue out;
18266 }
18267 return m;
18268 }
18269 });
18270
18271 AST_Function.DEFMETHOD("next_mangled", function(options, def){
18272 // #179, #326
18273 // in Safari strict mode, something like (function x(x){...}) is a syntax error;
18274 // a function expression's argument cannot shadow the function expression's name
18275
18276 var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
18277 while (true) {
18278 var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
18279 if (!(tricky_def && tricky_def.mangled_name == name))
18280 return name;
18281 }
18282 });
18283
18284 AST_Scope.DEFMETHOD("references", function(sym){
18285 if (sym instanceof AST_Symbol) sym = sym.definition();
18286 return this.enclosed.indexOf(sym) < 0 ? null : sym;
18287 });
18288
18289 AST_Symbol.DEFMETHOD("unmangleable", function(options){
18290 return this.definition().unmangleable(options);
18291 });
18292
18293 // property accessors are not mangleable
18294 AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
18295 return true;
18296 });
18297
18298 // labels are always mangleable
18299 AST_Label.DEFMETHOD("unmangleable", function(){
18300 return false;
18301 });
18302
18303 AST_Symbol.DEFMETHOD("unreferenced", function(){
18304 return this.definition().references.length == 0
18305 && !(this.scope.uses_eval || this.scope.uses_with);
18306 });
18307
18308 AST_Symbol.DEFMETHOD("undeclared", function(){
18309 return this.definition().undeclared;
18310 });
18311
18312 AST_LabelRef.DEFMETHOD("undeclared", function(){
18313 return false;
18314 });
18315
18316 AST_Label.DEFMETHOD("undeclared", function(){
18317 return false;
18318 });
18319
18320 AST_Symbol.DEFMETHOD("definition", function(){
18321 return this.thedef;
18322 });
18323
18324 AST_Symbol.DEFMETHOD("global", function(){
18325 return this.definition().global;
18326 });
18327
18328 AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
18329 return defaults(options, {
18330 except : [],
18331 eval : false,
18332 sort : false,
18333 toplevel : false,
18334 screw_ie8 : false
18335 });
18336 });
18337
18338 AST_Toplevel.DEFMETHOD("mangle_names", function(options){
18339 options = this._default_mangler_options(options);
18340 // We only need to mangle declaration nodes. Special logic wired
18341 // into the code generator will display the mangled name if it's
18342 // present (and for AST_SymbolRef-s it'll use the mangled name of
18343 // the AST_SymbolDeclaration that it points to).
18344 var lname = -1;
18345 var to_mangle = [];
18346 var tw = new TreeWalker(function(node, descend){
18347 if (node instanceof AST_LabeledStatement) {
18348 // lname is incremented when we get to the AST_Label
18349 var save_nesting = lname;
18350 descend();
18351 lname = save_nesting;
18352 return true; // don't descend again in TreeWalker
18353 }
18354 if (node instanceof AST_Scope) {
18355 var p = tw.parent(), a = [];
18356 node.variables.each(function(symbol){
18357 if (options.except.indexOf(symbol.name) < 0) {
18358 a.push(symbol);
18359 }
18360 });
18361 if (options.sort) a.sort(function(a, b){
18362 return b.references.length - a.references.length;
18363 });
18364 to_mangle.push.apply(to_mangle, a);
18365 return;
18366 }
18367 if (node instanceof AST_Label) {
18368 var name;
18369 do name = base54(++lname); while (!is_identifier(name));
18370 node.mangled_name = name;
18371 return true;
18372 }
18373 if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
18374 to_mangle.push(node.definition());
18375 return;
18376 }
18377 });
18378 this.walk(tw);
18379 to_mangle.forEach(function(def){ def.mangle(options) });
18380 });
18381
18382 AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
18383 options = this._default_mangler_options(options);
18384 var tw = new TreeWalker(function(node){
18385 if (node instanceof AST_Constant)
18386 base54.consider(node.print_to_string());
18387 else if (node instanceof AST_Return)
18388 base54.consider("return");
18389 else if (node instanceof AST_Throw)
18390 base54.consider("throw");
18391 else if (node instanceof AST_Continue)
18392 base54.consider("continue");
18393 else if (node instanceof AST_Break)
18394 base54.consider("break");
18395 else if (node instanceof AST_Debugger)
18396 base54.consider("debugger");
18397 else if (node instanceof AST_Directive)
18398 base54.consider(node.value);
18399 else if (node instanceof AST_While)
18400 base54.consider("while");
18401 else if (node instanceof AST_Do)
18402 base54.consider("do while");
18403 else if (node instanceof AST_If) {
18404 base54.consider("if");
18405 if (node.alternative) base54.consider("else");
18406 }
18407 else if (node instanceof AST_Var)
18408 base54.consider("var");
18409 else if (node instanceof AST_Const)
18410 base54.consider("const");
18411 else if (node instanceof AST_Lambda)
18412 base54.consider("function");
18413 else if (node instanceof AST_For)
18414 base54.consider("for");
18415 else if (node instanceof AST_ForIn)
18416 base54.consider("for in");
18417 else if (node instanceof AST_Switch)
18418 base54.consider("switch");
18419 else if (node instanceof AST_Case)
18420 base54.consider("case");
18421 else if (node instanceof AST_Default)
18422 base54.consider("default");
18423 else if (node instanceof AST_With)
18424 base54.consider("with");
18425 else if (node instanceof AST_ObjectSetter)
18426 base54.consider("set" + node.key);
18427 else if (node instanceof AST_ObjectGetter)
18428 base54.consider("get" + node.key);
18429 else if (node instanceof AST_ObjectKeyVal)
18430 base54.consider(node.key);
18431 else if (node instanceof AST_New)
18432 base54.consider("new");
18433 else if (node instanceof AST_This)
18434 base54.consider("this");
18435 else if (node instanceof AST_Try)
18436 base54.consider("try");
18437 else if (node instanceof AST_Catch)
18438 base54.consider("catch");
18439 else if (node instanceof AST_Finally)
18440 base54.consider("finally");
18441 else if (node instanceof AST_Symbol && node.unmangleable(options))
18442 base54.consider(node.name);
18443 else if (node instanceof AST_Unary || node instanceof AST_Binary)
18444 base54.consider(node.operator);
18445 else if (node instanceof AST_Dot)
18446 base54.consider(node.property);
18447 });
18448 this.walk(tw);
18449 base54.sort();
18450 });
18451
18452 var base54 = (function() {
18453 var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
18454 var chars, frequency;
18455 function reset() {
18456 frequency = Object.create(null);
18457 chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
18458 chars.forEach(function(ch){ frequency[ch] = 0 });
18459 }
18460 base54.consider = function(str){
18461 for (var i = str.length; --i >= 0;) {
18462 var code = str.charCodeAt(i);
18463 if (code in frequency) ++frequency[code];
18464 }
18465 };
18466 base54.sort = function() {
18467 chars = mergeSort(chars, function(a, b){
18468 if (is_digit(a) && !is_digit(b)) return 1;
18469 if (is_digit(b) && !is_digit(a)) return -1;
18470 return frequency[b] - frequency[a];
18471 });
18472 };
18473 base54.reset = reset;
18474 reset();
18475 base54.get = function(){ return chars };
18476 base54.freq = function(){ return frequency };
18477 function base54(num) {
18478 var ret = "", base = 54;
18479 do {
18480 ret += String.fromCharCode(chars[num % base]);
18481 num = Math.floor(num / base);
18482 base = 64;
18483 } while (num > 0);
18484 return ret;
18485 };
18486 return base54;
18487 })();
18488
18489 AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
18490 options = defaults(options, {
18491 undeclared : false, // this makes a lot of noise
18492 unreferenced : true,
18493 assign_to_global : true,
18494 func_arguments : true,
18495 nested_defuns : true,
18496 eval : true
18497 });
18498 var tw = new TreeWalker(function(node){
18499 if (options.undeclared
18500 && node instanceof AST_SymbolRef
18501 && node.undeclared())
18502 {
18503 // XXX: this also warns about JS standard names,
18504 // i.e. Object, Array, parseInt etc. Should add a list of
18505 // exceptions.
18506 AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
18507 name: node.name,
18508 file: node.start.file,
18509 line: node.start.line,
18510 col: node.start.col
18511 });
18512 }
18513 if (options.assign_to_global)
18514 {
18515 var sym = null;
18516 if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
18517 sym = node.left;
18518 else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
18519 sym = node.init;
18520 if (sym
18521 && (sym.undeclared()
18522 || (sym.global() && sym.scope !== sym.definition().scope))) {
18523 AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
18524 msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
18525 name: sym.name,
18526 file: sym.start.file,
18527 line: sym.start.line,
18528 col: sym.start.col
17616 }); 18529 });
17617 to_mangle.push.apply(to_mangle, a); 18530 }
17618 return; 18531 }
17619 } 18532 if (options.eval
17620 if (node instanceof AST_Label) { 18533 && node instanceof AST_SymbolRef
17621 var name; 18534 && node.undeclared()
17622 do name = base54(++lname); while (!is_identifier(name)); 18535 && node.name == "eval") {
17623 node.mangled_name = name; 18536 AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
17624 return true; 18537 }
18538 if (options.unreferenced
18539 && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
18540 && node.unreferenced()) {
18541 AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
18542 type: node instanceof AST_Label ? "Label" : "Symbol",
18543 name: node.name,
18544 file: node.start.file,
18545 line: node.start.line,
18546 col: node.start.col
18547 });
18548 }
18549 if (options.func_arguments
18550 && node instanceof AST_Lambda
18551 && node.uses_arguments) {
18552 AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
18553 name: node.name ? node.name.name : "anonymous",
18554 file: node.start.file,
18555 line: node.start.line,
18556 col: node.start.col
18557 });
18558 }
18559 if (options.nested_defuns
18560 && node instanceof AST_Defun
18561 && !(tw.parent() instanceof AST_Scope)) {
18562 AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
18563 name: node.name.name,
18564 type: tw.parent().TYPE,
18565 file: node.start.file,
18566 line: node.start.line,
18567 col: node.start.col
18568 });
18569 }
18570 });
18571 this.walk(tw);
18572 });
18573
18574 /***********************************************************************
18575
18576 A JavaScript tokenizer / parser / beautifier / compressor.
18577 https://github.com/mishoo/UglifyJS2
18578
18579 -------------------------------- (C) ---------------------------------
18580
18581 Author: Mihai Bazon
18582 <mihai.bazon@gmail.com>
18583 http://mihai.bazon.net/blog
18584
18585 Distributed under the BSD license:
18586
18587 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
18588
18589 Redistribution and use in source and binary forms, with or without
18590 modification, are permitted provided that the following conditions
18591 are met:
18592
18593 * Redistributions of source code must retain the above
18594 copyright notice, this list of conditions and the following
18595 disclaimer.
18596
18597 * Redistributions in binary form must reproduce the above
18598 copyright notice, this list of conditions and the following
18599 disclaimer in the documentation and/or other materials
18600 provided with the distribution.
18601
18602 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18603 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18604 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18605 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
18606 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
18607 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18608 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18609 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18610 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
18611 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
18612 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18613 SUCH DAMAGE.
18614
18615 ***********************************************************************/
18616
18617 "use strict";
18618
18619 function OutputStream(options) {
18620
18621 options = defaults(options, {
18622 indent_start : 0,
18623 indent_level : 4,
18624 quote_keys : false,
18625 space_colon : true,
18626 ascii_only : false,
18627 unescape_regexps : false,
18628 inline_script : false,
18629 width : 80,
18630 max_line_len : 32000,
18631 beautify : false,
18632 source_map : null,
18633 bracketize : false,
18634 semicolons : true,
18635 comments : false,
18636 preserve_line : false,
18637 screw_ie8 : false,
18638 preamble : null,
18639 }, true);
18640
18641 var indentation = 0;
18642 var current_col = 0;
18643 var current_line = 1;
18644 var current_pos = 0;
18645 var OUTPUT = "";
18646
18647 function to_ascii(str, identifier) {
18648 return str.replace(/[\u0080-\uffff]/g, function(ch) {
18649 var code = ch.charCodeAt(0).toString(16);
18650 if (code.length <= 2 && !identifier) {
18651 while (code.length < 2) code = "0" + code;
18652 return "\\x" + code;
18653 } else {
18654 while (code.length < 4) code = "0" + code;
18655 return "\\u" + code;
17625 } 18656 }
17626 }); 18657 });
17627 this.walk(tw); 18658 };
17628 to_mangle.forEach(function(def) { 18659
17629 def.mangle(options); 18660 function make_string(str) {
18661 var dq = 0, sq = 0;
18662 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
18663 switch (s) {
18664 case "\\": return "\\\\";
18665 case "\b": return "\\b";
18666 case "\f": return "\\f";
18667 case "\n": return "\\n";
18668 case "\r": return "\\r";
18669 case "\u2028": return "\\u2028";
18670 case "\u2029": return "\\u2029";
18671 case '"': ++dq; return '"';
18672 case "'": ++sq; return "'";
18673 case "\0": return "\\x00";
18674 }
18675 return s;
17630 }); 18676 });
17631 }); 18677 if (options.ascii_only) str = to_ascii(str);
17632 AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { 18678 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
17633 options = this._default_mangler_options(options); 18679 else return '"' + str.replace(/\x22/g, '\\"') + '"';
17634 var tw = new TreeWalker(function(node) { 18680 };
17635 if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) { 18681
17636 base54.consider("if"); 18682 function encode_string(str) {
17637 if (node.alternative) base54.consider("else"); 18683 var ret = make_string(str);
17638 } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property); 18684 if (options.inline_script)
17639 }); 18685 ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
17640 this.walk(tw); 18686 return ret;
17641 base54.sort(); 18687 };
17642 }); 18688
17643 var base54 = function() { 18689 function make_name(name) {
17644 var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; 18690 name = name.toString();
17645 var chars, frequency; 18691 if (options.ascii_only)
17646 function reset() { 18692 name = to_ascii(name, true);
17647 frequency = Object.create(null); 18693 return name;
17648 chars = string.split("").map(function(ch) { 18694 };
17649 return ch.charCodeAt(0); 18695
17650 }); 18696 function make_indent(back) {
17651 chars.forEach(function(ch) { 18697 return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
17652 frequency[ch] = 0; 18698 };
17653 }); 18699
17654 } 18700 /* -----[ beautification/minification ]----- */
17655 base54.consider = function(str) { 18701
17656 for (var i = str.length; --i >= 0; ) { 18702 var might_need_space = false;
17657 var code = str.charCodeAt(i); 18703 var might_need_semicolon = false;
17658 if (code in frequency) ++frequency[code]; 18704 var last = null;
17659 } 18705
17660 }; 18706 function last_char() {
17661 base54.sort = function() { 18707 return last.charAt(last.length - 1);
17662 chars = mergeSort(chars, function(a, b) { 18708 };
17663 if (is_digit(a) && !is_digit(b)) return 1; 18709
17664 if (is_digit(b) && !is_digit(a)) return -1; 18710 function maybe_newline() {
17665 return frequency[b] - frequency[a]; 18711 if (options.max_line_len && current_col > options.max_line_len)
17666 }); 18712 print("\n");
17667 }; 18713 };
17668 base54.reset = reset; 18714
17669 reset(); 18715 var requireSemicolonChars = makePredicate("( [ + * / - , .");
17670 base54.get = function() { 18716
17671 return chars; 18717 function print(str) {
17672 }; 18718 str = String(str);
17673 base54.freq = function() { 18719 var ch = str.charAt(0);
17674 return frequency; 18720 if (might_need_semicolon) {
17675 }; 18721 if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
17676 function base54(num) { 18722 if (options.semicolons || requireSemicolonChars(ch)) {
17677 var ret = "", base = 54; 18723 OUTPUT += ";";
17678 do { 18724 current_col++;
17679 ret += String.fromCharCode(chars[num % base]); 18725 current_pos++;
17680 num = Math.floor(num / base);
17681 base = 64;
17682 } while (num > 0);
17683 return ret;
17684 }
17685 return base54;
17686 }();
17687 AST_Toplevel.DEFMETHOD("scope_warnings", function(options) {
17688 options = defaults(options, {
17689 undeclared: false,
17690 unreferenced: true,
17691 assign_to_global: true,
17692 func_arguments: true,
17693 nested_defuns: true,
17694 eval: true
17695 });
17696 var tw = new TreeWalker(function(node) {
17697 if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) {
17698 AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
17699 name: node.name,
17700 file: node.start.file,
17701 line: node.start.line,
17702 col: node.start.col
17703 });
17704 }
17705 if (options.assign_to_global) {
17706 var sym = null;
17707 if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init;
17708 if (sym && (sym.undeclared() || sym.global() && sym.scope !== sym.definition().scope)) {
17709 AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
17710 msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
17711 name: sym.name,
17712 file: sym.start.file,
17713 line: sym.start.line,
17714 col: sym.start.col
17715 });
17716 }
17717 }
17718 if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") {
17719 AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
17720 }
17721 if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && node.unreferenced()) {
17722 AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
17723 type: node instanceof AST_Label ? "Label" : "Symbol",
17724 name: node.name,
17725 file: node.start.file,
17726 line: node.start.line,
17727 col: node.start.col
17728 });
17729 }
17730 if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) {
17731 AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
17732 name: node.name ? node.name.name : "anonymous",
17733 file: node.start.file,
17734 line: node.start.line,
17735 col: node.start.col
17736 });
17737 }
17738 if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) {
17739 AST_Node.warn('Function {name} declared in nested statement "{type}" [{file}:{line},{col}]', {
17740 name: node.name.name,
17741 type: tw.parent().TYPE,
17742 file: node.start.file,
17743 line: node.start.line,
17744 col: node.start.col
17745 });
17746 }
17747 });
17748 this.walk(tw);
17749 });
17750 "use strict";
17751 function OutputStream(options) {
17752 options = defaults(options, {
17753 indent_start: 0,
17754 indent_level: 4,
17755 quote_keys: false,
17756 space_colon: true,
17757 ascii_only: false,
17758 inline_script: false,
17759 width: 80,
17760 max_line_len: 32e3,
17761 beautify: false,
17762 source_map: null,
17763 bracketize: false,
17764 semicolons: true,
17765 comments: false,
17766 preserve_line: false,
17767 screw_ie8: false
17768 }, true);
17769 var indentation = 0;
17770 var current_col = 0;
17771 var current_line = 1;
17772 var current_pos = 0;
17773 var OUTPUT = "";
17774 function to_ascii(str, identifier) {
17775 return str.replace(/[\u0080-\uffff]/g, function(ch) {
17776 var code = ch.charCodeAt(0).toString(16);
17777 if (code.length <= 2 && !identifier) {
17778 while (code.length < 2) code = "0" + code;
17779 return "\\x" + code;
17780 } else { 18726 } else {
17781 while (code.length < 4) code = "0" + code;
17782 return "\\u" + code;
17783 }
17784 });
17785 }
17786 function make_string(str) {
17787 var dq = 0, sq = 0;
17788 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s) {
17789 switch (s) {
17790 case "\\":
17791 return "\\\\";
17792
17793 case "\b":
17794 return "\\b";
17795
17796 case "\f":
17797 return "\\f";
17798
17799 case "\n":
17800 return "\\n";
17801
17802 case "\r":
17803 return "\\r";
17804
17805 case "\u2028":
17806 return "\\u2028";
17807
17808 case "\u2029":
17809 return "\\u2029";
17810
17811 case '"':
17812 ++dq;
17813 return '"';
17814
17815 case "'":
17816 ++sq;
17817 return "'";
17818
17819 case "\x00":
17820 return "\\x00";
17821 }
17822 return s;
17823 });
17824 if (options.ascii_only) str = to_ascii(str);
17825 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; else return '"' + str.replace(/\x22/g, '\\"') + '"';
17826 }
17827 function encode_string(str) {
17828 var ret = make_string(str);
17829 if (options.inline_script) ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
17830 return ret;
17831 }
17832 function make_name(name) {
17833 name = name.toString();
17834 if (options.ascii_only) name = to_ascii(name, true);
17835 return name;
17836 }
17837 function make_indent(back) {
17838 return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
17839 }
17840 var might_need_space = false;
17841 var might_need_semicolon = false;
17842 var last = null;
17843 function last_char() {
17844 return last.charAt(last.length - 1);
17845 }
17846 function maybe_newline() {
17847 if (options.max_line_len && current_col > options.max_line_len) print("\n");
17848 }
17849 var requireSemicolonChars = makePredicate("( [ + * / - , .");
17850 function print(str) {
17851 str = String(str);
17852 var ch = str.charAt(0);
17853 if (might_need_semicolon) {
17854 if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
17855 if (options.semicolons || requireSemicolonChars(ch)) {
17856 OUTPUT += ";";
17857 current_col++;
17858 current_pos++;
17859 } else {
17860 OUTPUT += "\n";
17861 current_pos++;
17862 current_line++;
17863 current_col = 0;
17864 }
17865 if (!options.beautify) might_need_space = false;
17866 }
17867 might_need_semicolon = false;
17868 maybe_newline();
17869 }
17870 if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
17871 var target_line = stack[stack.length - 1].start.line;
17872 while (current_line < target_line) {
17873 OUTPUT += "\n"; 18727 OUTPUT += "\n";
17874 current_pos++; 18728 current_pos++;
17875 current_line++; 18729 current_line++;
17876 current_col = 0; 18730 current_col = 0;
18731 }
18732 if (!options.beautify)
17877 might_need_space = false; 18733 might_need_space = false;
17878 } 18734 }
17879 } 18735 might_need_semicolon = false;
17880 if (might_need_space) { 18736 maybe_newline();
17881 var prev = last_char(); 18737 }
17882 if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\") || /^[\+\-\/]$/.test(ch) && ch == prev) { 18738
17883 OUTPUT += " "; 18739 if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
17884 current_col++; 18740 var target_line = stack[stack.length - 1].start.line;
17885 current_pos++; 18741 while (current_line < target_line) {
17886 } 18742 OUTPUT += "\n";
18743 current_pos++;
18744 current_line++;
18745 current_col = 0;
17887 might_need_space = false; 18746 might_need_space = false;
17888 } 18747 }
17889 var a = str.split(/\r?\n/), n = a.length - 1; 18748 }
17890 current_line += n; 18749
17891 if (n == 0) { 18750 if (might_need_space) {
17892 current_col += a[n].length; 18751 var prev = last_char();
18752 if ((is_identifier_char(prev)
18753 && (is_identifier_char(ch) || ch == "\\"))
18754 || (/^[\+\-\/]$/.test(ch) && ch == prev))
18755 {
18756 OUTPUT += " ";
18757 current_col++;
18758 current_pos++;
18759 }
18760 might_need_space = false;
18761 }
18762 var a = str.split(/\r?\n/), n = a.length - 1;
18763 current_line += n;
18764 if (n == 0) {
18765 current_col += a[n].length;
18766 } else {
18767 current_col = a[n].length;
18768 }
18769 current_pos += str.length;
18770 last = str;
18771 OUTPUT += str;
18772 };
18773
18774 var space = options.beautify ? function() {
18775 print(" ");
18776 } : function() {
18777 might_need_space = true;
18778 };
18779
18780 var indent = options.beautify ? function(half) {
18781 if (options.beautify) {
18782 print(make_indent(half ? 0.5 : 0));
18783 }
18784 } : noop;
18785
18786 var with_indent = options.beautify ? function(col, cont) {
18787 if (col === true) col = next_indent();
18788 var save_indentation = indentation;
18789 indentation = col;
18790 var ret = cont();
18791 indentation = save_indentation;
18792 return ret;
18793 } : function(col, cont) { return cont() };
18794
18795 var newline = options.beautify ? function() {
18796 print("\n");
18797 } : noop;
18798
18799 var semicolon = options.beautify ? function() {
18800 print(";");
18801 } : function() {
18802 might_need_semicolon = true;
18803 };
18804
18805 function force_semicolon() {
18806 might_need_semicolon = false;
18807 print(";");
18808 };
18809
18810 function next_indent() {
18811 return indentation + options.indent_level;
18812 };
18813
18814 function with_block(cont) {
18815 var ret;
18816 print("{");
18817 newline();
18818 with_indent(next_indent(), function(){
18819 ret = cont();
18820 });
18821 indent();
18822 print("}");
18823 return ret;
18824 };
18825
18826 function with_parens(cont) {
18827 print("(");
18828 //XXX: still nice to have that for argument lists
18829 //var ret = with_indent(current_col, cont);
18830 var ret = cont();
18831 print(")");
18832 return ret;
18833 };
18834
18835 function with_square(cont) {
18836 print("[");
18837 //var ret = with_indent(current_col, cont);
18838 var ret = cont();
18839 print("]");
18840 return ret;
18841 };
18842
18843 function comma() {
18844 print(",");
18845 space();
18846 };
18847
18848 function colon() {
18849 print(":");
18850 if (options.space_colon) space();
18851 };
18852
18853 var add_mapping = options.source_map ? function(token, name) {
18854 try {
18855 if (token) options.source_map.add(
18856 token.file || "?",
18857 current_line, current_col,
18858 token.line, token.col,
18859 (!name && token.type == "name") ? token.value : name
18860 );
18861 } catch(ex) {
18862 AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
18863 file: token.file,
18864 line: token.line,
18865 col: token.col,
18866 cline: current_line,
18867 ccol: current_col,
18868 name: name || ""
18869 })
18870 }
18871 } : noop;
18872
18873 function get() {
18874 return OUTPUT;
18875 };
18876
18877 if (options.preamble) {
18878 print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
18879 }
18880
18881 var stack = [];
18882 return {
18883 get : get,
18884 toString : get,
18885 indent : indent,
18886 indentation : function() { return indentation },
18887 current_width : function() { return current_col - indentation },
18888 should_break : function() { return options.width && this.current_width() >= options.width },
18889 newline : newline,
18890 print : print,
18891 space : space,
18892 comma : comma,
18893 colon : colon,
18894 last : function() { return last },
18895 semicolon : semicolon,
18896 force_semicolon : force_semicolon,
18897 to_ascii : to_ascii,
18898 print_name : function(name) { print(make_name(name)) },
18899 print_string : function(str) { print(encode_string(str)) },
18900 next_indent : next_indent,
18901 with_indent : with_indent,
18902 with_block : with_block,
18903 with_parens : with_parens,
18904 with_square : with_square,
18905 add_mapping : add_mapping,
18906 option : function(opt) { return options[opt] },
18907 line : function() { return current_line },
18908 col : function() { return current_col },
18909 pos : function() { return current_pos },
18910 push_node : function(node) { stack.push(node) },
18911 pop_node : function() { return stack.pop() },
18912 stack : function() { return stack },
18913 parent : function(n) {
18914 return stack[stack.length - 2 - (n || 0)];
18915 }
18916 };
18917
18918 };
18919
18920 /* -----[ code generators ]----- */
18921
18922 (function(){
18923
18924 /* -----[ utils ]----- */
18925
18926 function DEFPRINT(nodetype, generator) {
18927 nodetype.DEFMETHOD("_codegen", generator);
18928 };
18929
18930 AST_Node.DEFMETHOD("print", function(stream, force_parens){
18931 var self = this, generator = self._codegen;
18932 function doit() {
18933 self.add_comments(stream);
18934 self.add_source_map(stream);
18935 generator(self, stream);
18936 }
18937 stream.push_node(self);
18938 if (force_parens || self.needs_parens(stream)) {
18939 stream.with_parens(doit);
18940 } else {
18941 doit();
18942 }
18943 stream.pop_node();
18944 });
18945
18946 AST_Node.DEFMETHOD("print_to_string", function(options){
18947 var s = OutputStream(options);
18948 this.print(s);
18949 return s.get();
18950 });
18951
18952 /* -----[ comments ]----- */
18953
18954 AST_Node.DEFMETHOD("add_comments", function(output){
18955 var c = output.option("comments"), self = this;
18956 if (c) {
18957 var start = self.start;
18958 if (start && !start._comments_dumped) {
18959 start._comments_dumped = true;
18960 var comments = start.comments_before || [];
18961
18962 // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
18963 // and https://github.com/mishoo/UglifyJS2/issues/372
18964 if (self instanceof AST_Exit && self.value) {
18965 self.value.walk(new TreeWalker(function(node){
18966 if (node.start && node.start.comments_before) {
18967 comments = comments.concat(node.start.comments_before);
18968 node.start.comments_before = [];
18969 }
18970 if (node instanceof AST_Function ||
18971 node instanceof AST_Array ||
18972 node instanceof AST_Object)
18973 {
18974 return true; // don't go inside.
18975 }
18976 }));
18977 }
18978
18979 if (c.test) {
18980 comments = comments.filter(function(comment){
18981 return c.test(comment.value);
18982 });
18983 } else if (typeof c == "function") {
18984 comments = comments.filter(function(comment){
18985 return c(self, comment);
18986 });
18987 }
18988 comments.forEach(function(c){
18989 if (/comment[134]/.test(c.type)) {
18990 output.print("//" + c.value + "\n");
18991 output.indent();
18992 }
18993 else if (c.type == "comment2") {
18994 output.print("/*" + c.value + "*/");
18995 if (start.nlb) {
18996 output.print("\n");
18997 output.indent();
18998 } else {
18999 output.space();
19000 }
19001 }
19002 });
19003 }
19004 }
19005 });
19006
19007 /* -----[ PARENTHESES ]----- */
19008
19009 function PARENS(nodetype, func) {
19010 nodetype.DEFMETHOD("needs_parens", func);
19011 };
19012
19013 PARENS(AST_Node, function(){
19014 return false;
19015 });
19016
19017 // a function expression needs parens around it when it's provably
19018 // the first token to appear in a statement.
19019 PARENS(AST_Function, function(output){
19020 return first_in_statement(output);
19021 });
19022
19023 // same goes for an object literal, because otherwise it would be
19024 // interpreted as a block of code.
19025 PARENS(AST_Object, function(output){
19026 return first_in_statement(output);
19027 });
19028
19029 PARENS(AST_Unary, function(output){
19030 var p = output.parent();
19031 return p instanceof AST_PropAccess && p.expression === this;
19032 });
19033
19034 PARENS(AST_Seq, function(output){
19035 var p = output.parent();
19036 return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
19037 || p instanceof AST_Unary // !(foo, bar, baz)
19038 || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
19039 || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
19040 || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
19041 || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
19042 || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
19043 || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
19044 * ==> 20 (side effect, set a := 10 and b := 20) */
19045 ;
19046 });
19047
19048 PARENS(AST_Binary, function(output){
19049 var p = output.parent();
19050 // (foo && bar)()
19051 if (p instanceof AST_Call && p.expression === this)
19052 return true;
19053 // typeof (foo && bar)
19054 if (p instanceof AST_Unary)
19055 return true;
19056 // (foo && bar)["prop"], (foo && bar).prop
19057 if (p instanceof AST_PropAccess && p.expression === this)
19058 return true;
19059 // this deals with precedence: 3 * (2 + 1)
19060 if (p instanceof AST_Binary) {
19061 var po = p.operator, pp = PRECEDENCE[po];
19062 var so = this.operator, sp = PRECEDENCE[so];
19063 if (pp > sp
19064 || (pp == sp
19065 && this === p.right)) {
19066 return true;
19067 }
19068 }
19069 });
19070
19071 PARENS(AST_PropAccess, function(output){
19072 var p = output.parent();
19073 if (p instanceof AST_New && p.expression === this) {
19074 // i.e. new (foo.bar().baz)
19075 //
19076 // if there's one call into this subtree, then we need
19077 // parens around it too, otherwise the call will be
19078 // interpreted as passing the arguments to the upper New
19079 // expression.
19080 try {
19081 this.walk(new TreeWalker(function(node){
19082 if (node instanceof AST_Call) throw p;
19083 }));
19084 } catch(ex) {
19085 if (ex !== p) throw ex;
19086 return true;
19087 }
19088 }
19089 });
19090
19091 PARENS(AST_Call, function(output){
19092 var p = output.parent(), p1;
19093 if (p instanceof AST_New && p.expression === this)
19094 return true;
19095
19096 // workaround for Safari bug.
19097 // https://bugs.webkit.org/show_bug.cgi?id=123506
19098 return this.expression instanceof AST_Function
19099 && p instanceof AST_PropAccess
19100 && p.expression === this
19101 && (p1 = output.parent(1)) instanceof AST_Assign
19102 && p1.left === p;
19103 });
19104
19105 PARENS(AST_New, function(output){
19106 var p = output.parent();
19107 if (no_constructor_parens(this, output)
19108 && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
19109 || p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
19110 return true;
19111 });
19112
19113 PARENS(AST_Number, function(output){
19114 var p = output.parent();
19115 if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
19116 return true;
19117 });
19118
19119 PARENS(AST_NaN, function(output){
19120 var p = output.parent();
19121 if (p instanceof AST_PropAccess && p.expression === this)
19122 return true;
19123 });
19124
19125 function assign_and_conditional_paren_rules(output) {
19126 var p = output.parent();
19127 // !(a = false) → true
19128 if (p instanceof AST_Unary)
19129 return true;
19130 // 1 + (a = 2) + 3 → 6, side effect setting a = 2
19131 if (p instanceof AST_Binary && !(p instanceof AST_Assign))
19132 return true;
19133 // (a = func)() —or— new (a = Object)()
19134 if (p instanceof AST_Call && p.expression === this)
19135 return true;
19136 // (a = foo) ? bar : baz
19137 if (p instanceof AST_Conditional && p.condition === this)
19138 return true;
19139 // (a = foo)["prop"] —or— (a = foo).prop
19140 if (p instanceof AST_PropAccess && p.expression === this)
19141 return true;
19142 };
19143
19144 PARENS(AST_Assign, assign_and_conditional_paren_rules);
19145 PARENS(AST_Conditional, assign_and_conditional_paren_rules);
19146
19147 /* -----[ PRINTERS ]----- */
19148
19149 DEFPRINT(AST_Directive, function(self, output){
19150 output.print_string(self.value);
19151 output.semicolon();
19152 });
19153 DEFPRINT(AST_Debugger, function(self, output){
19154 output.print("debugger");
19155 output.semicolon();
19156 });
19157
19158 /* -----[ statements ]----- */
19159
19160 function display_body(body, is_toplevel, output) {
19161 var last = body.length - 1;
19162 body.forEach(function(stmt, i){
19163 if (!(stmt instanceof AST_EmptyStatement)) {
19164 output.indent();
19165 stmt.print(output);
19166 if (!(i == last && is_toplevel)) {
19167 output.newline();
19168 if (is_toplevel) output.newline();
19169 }
19170 }
19171 });
19172 };
19173
19174 AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
19175 force_statement(this.body, output);
19176 });
19177
19178 DEFPRINT(AST_Statement, function(self, output){
19179 self.body.print(output);
19180 output.semicolon();
19181 });
19182 DEFPRINT(AST_Toplevel, function(self, output){
19183 display_body(self.body, true, output);
19184 output.print("");
19185 });
19186 DEFPRINT(AST_LabeledStatement, function(self, output){
19187 self.label.print(output);
19188 output.colon();
19189 self.body.print(output);
19190 });
19191 DEFPRINT(AST_SimpleStatement, function(self, output){
19192 self.body.print(output);
19193 output.semicolon();
19194 });
19195 function print_bracketed(body, output) {
19196 if (body.length > 0) output.with_block(function(){
19197 display_body(body, false, output);
19198 });
19199 else output.print("{}");
19200 };
19201 DEFPRINT(AST_BlockStatement, function(self, output){
19202 print_bracketed(self.body, output);
19203 });
19204 DEFPRINT(AST_EmptyStatement, function(self, output){
19205 output.semicolon();
19206 });
19207 DEFPRINT(AST_Do, function(self, output){
19208 output.print("do");
19209 output.space();
19210 self._do_print_body(output);
19211 output.space();
19212 output.print("while");
19213 output.space();
19214 output.with_parens(function(){
19215 self.condition.print(output);
19216 });
19217 output.semicolon();
19218 });
19219 DEFPRINT(AST_While, function(self, output){
19220 output.print("while");
19221 output.space();
19222 output.with_parens(function(){
19223 self.condition.print(output);
19224 });
19225 output.space();
19226 self._do_print_body(output);
19227 });
19228 DEFPRINT(AST_For, function(self, output){
19229 output.print("for");
19230 output.space();
19231 output.with_parens(function(){
19232 if (self.init) {
19233 if (self.init instanceof AST_Definitions) {
19234 self.init.print(output);
19235 } else {
19236 parenthesize_for_noin(self.init, output, true);
19237 }
19238 output.print(";");
19239 output.space();
17893 } else { 19240 } else {
17894 current_col = a[n].length; 19241 output.print(";");
17895 } 19242 }
17896 current_pos += str.length; 19243 if (self.condition) {
17897 last = str; 19244 self.condition.print(output);
17898 OUTPUT += str; 19245 output.print(";");
17899 } 19246 output.space();
17900 var space = options.beautify ? function() {
17901 print(" ");
17902 } : function() {
17903 might_need_space = true;
17904 };
17905 var indent = options.beautify ? function(half) {
17906 if (options.beautify) {
17907 print(make_indent(half ? .5 : 0));
17908 }
17909 } : noop;
17910 var with_indent = options.beautify ? function(col, cont) {
17911 if (col === true) col = next_indent();
17912 var save_indentation = indentation;
17913 indentation = col;
17914 var ret = cont();
17915 indentation = save_indentation;
17916 return ret;
17917 } : function(col, cont) {
17918 return cont();
17919 };
17920 var newline = options.beautify ? function() {
17921 print("\n");
17922 } : noop;
17923 var semicolon = options.beautify ? function() {
17924 print(";");
17925 } : function() {
17926 might_need_semicolon = true;
17927 };
17928 function force_semicolon() {
17929 might_need_semicolon = false;
17930 print(";");
17931 }
17932 function next_indent() {
17933 return indentation + options.indent_level;
17934 }
17935 function with_block(cont) {
17936 var ret;
17937 print("{");
17938 newline();
17939 with_indent(next_indent(), function() {
17940 ret = cont();
17941 });
17942 indent();
17943 print("}");
17944 return ret;
17945 }
17946 function with_parens(cont) {
17947 print("(");
17948 var ret = cont();
17949 print(")");
17950 return ret;
17951 }
17952 function with_square(cont) {
17953 print("[");
17954 var ret = cont();
17955 print("]");
17956 return ret;
17957 }
17958 function comma() {
17959 print(",");
17960 space();
17961 }
17962 function colon() {
17963 print(":");
17964 if (options.space_colon) space();
17965 }
17966 var add_mapping = options.source_map ? function(token, name) {
17967 try {
17968 if (token) options.source_map.add(token.file || "?", current_line, current_col, token.line, token.col, !name && token.type == "name" ? token.value : name);
17969 } catch (ex) {
17970 AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
17971 file: token.file,
17972 line: token.line,
17973 col: token.col,
17974 cline: current_line,
17975 ccol: current_col,
17976 name: name || ""
17977 });
17978 }
17979 } : noop;
17980 function get() {
17981 return OUTPUT;
17982 }
17983 var stack = [];
17984 return {
17985 get: get,
17986 toString: get,
17987 indent: indent,
17988 indentation: function() {
17989 return indentation;
17990 },
17991 current_width: function() {
17992 return current_col - indentation;
17993 },
17994 should_break: function() {
17995 return options.width && this.current_width() >= options.width;
17996 },
17997 newline: newline,
17998 print: print,
17999 space: space,
18000 comma: comma,
18001 colon: colon,
18002 last: function() {
18003 return last;
18004 },
18005 semicolon: semicolon,
18006 force_semicolon: force_semicolon,
18007 to_ascii: to_ascii,
18008 print_name: function(name) {
18009 print(make_name(name));
18010 },
18011 print_string: function(str) {
18012 print(encode_string(str));
18013 },
18014 next_indent: next_indent,
18015 with_indent: with_indent,
18016 with_block: with_block,
18017 with_parens: with_parens,
18018 with_square: with_square,
18019 add_mapping: add_mapping,
18020 option: function(opt) {
18021 return options[opt];
18022 },
18023 line: function() {
18024 return current_line;
18025 },
18026 col: function() {
18027 return current_col;
18028 },
18029 pos: function() {
18030 return current_pos;
18031 },
18032 push_node: function(node) {
18033 stack.push(node);
18034 },
18035 pop_node: function() {
18036 return stack.pop();
18037 },
18038 stack: function() {
18039 return stack;
18040 },
18041 parent: function(n) {
18042 return stack[stack.length - 2 - (n || 0)];
18043 }
18044 };
18045 }
18046 (function() {
18047 function DEFPRINT(nodetype, generator) {
18048 nodetype.DEFMETHOD("_codegen", generator);
18049 }
18050 AST_Node.DEFMETHOD("print", function(stream, force_parens) {
18051 var self = this, generator = self._codegen;
18052 function doit() {
18053 self.add_comments(stream);
18054 self.add_source_map(stream);
18055 generator(self, stream);
18056 }
18057 stream.push_node(self);
18058 if (force_parens || self.needs_parens(stream)) {
18059 stream.with_parens(doit);
18060 } else { 19247 } else {
18061 doit(); 19248 output.print(";");
18062 } 19249 }
18063 stream.pop_node(); 19250 if (self.step) {
19251 self.step.print(output);
19252 }
18064 }); 19253 });
18065 AST_Node.DEFMETHOD("print_to_string", function(options) { 19254 output.space();
18066 var s = OutputStream(options); 19255 self._do_print_body(output);
18067 this.print(s); 19256 });
18068 return s.get(); 19257 DEFPRINT(AST_ForIn, function(self, output){
19258 output.print("for");
19259 output.space();
19260 output.with_parens(function(){
19261 self.init.print(output);
19262 output.space();
19263 output.print("in");
19264 output.space();
19265 self.object.print(output);
18069 }); 19266 });
18070 AST_Node.DEFMETHOD("add_comments", function(output) { 19267 output.space();
18071 var c = output.option("comments"), self = this; 19268 self._do_print_body(output);
18072 if (c) { 19269 });
18073 var start = self.start; 19270 DEFPRINT(AST_With, function(self, output){
18074 if (start && !start._comments_dumped) { 19271 output.print("with");
18075 start._comments_dumped = true; 19272 output.space();
18076 var comments = start.comments_before; 19273 output.with_parens(function(){
18077 if (self instanceof AST_Exit && self.value && self.value.start.comments_before.length > 0) { 19274 self.expression.print(output);
18078 comments = (comments || []).concat(self.value.start.comments_before);
18079 self.value.start.comments_before = [];
18080 }
18081 if (c.test) {
18082 comments = comments.filter(function(comment) {
18083 return c.test(comment.value);
18084 });
18085 } else if (typeof c == "function") {
18086 comments = comments.filter(function(comment) {
18087 return c(self, comment);
18088 });
18089 }
18090 comments.forEach(function(c) {
18091 if (c.type == "comment1") {
18092 output.print("//" + c.value + "\n");
18093 output.indent();
18094 } else if (c.type == "comment2") {
18095 output.print("/*" + c.value + "*/");
18096 if (start.nlb) {
18097 output.print("\n");
18098 output.indent();
18099 } else {
18100 output.space();
18101 }
18102 }
18103 });
18104 }
18105 }
18106 }); 19275 });
18107 function PARENS(nodetype, func) { 19276 output.space();
18108 nodetype.DEFMETHOD("needs_parens", func); 19277 self._do_print_body(output);
18109 } 19278 });
18110 PARENS(AST_Node, function() { 19279
18111 return false; 19280 /* -----[ functions ]----- */
18112 }); 19281 AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
18113 PARENS(AST_Function, function(output) { 19282 var self = this;
18114 return first_in_statement(output); 19283 if (!nokeyword) {
18115 }); 19284 output.print("function");
18116 PARENS(AST_Object, function(output) { 19285 }
18117 return first_in_statement(output); 19286 if (self.name) {
18118 });
18119 PARENS(AST_Unary, function(output) {
18120 var p = output.parent();
18121 return p instanceof AST_PropAccess && p.expression === this;
18122 });
18123 PARENS(AST_Seq, function(output) {
18124 var p = output.parent();
18125 return p instanceof AST_Call || p instanceof AST_Unary || p instanceof AST_Binary || p instanceof AST_VarDef || p instanceof AST_Dot || p instanceof AST_Array || p instanceof AST_ObjectProperty || p instanceof AST_Conditional;
18126 });
18127 PARENS(AST_Binary, function(output) {
18128 var p = output.parent();
18129 if (p instanceof AST_Call && p.expression === this) return true;
18130 if (p instanceof AST_Unary) return true;
18131 if (p instanceof AST_PropAccess && p.expression === this) return true;
18132 if (p instanceof AST_Binary) {
18133 var po = p.operator, pp = PRECEDENCE[po];
18134 var so = this.operator, sp = PRECEDENCE[so];
18135 if (pp > sp || pp == sp && this === p.right && !(so == po && (so == "*" || so == "&&" || so == "||"))) {
18136 return true;
18137 }
18138 }
18139 });
18140 PARENS(AST_PropAccess, function(output) {
18141 var p = output.parent();
18142 if (p instanceof AST_New && p.expression === this) {
18143 try {
18144 this.walk(new TreeWalker(function(node) {
18145 if (node instanceof AST_Call) throw p;
18146 }));
18147 } catch (ex) {
18148 if (ex !== p) throw ex;
18149 return true;
18150 }
18151 }
18152 });
18153 PARENS(AST_Call, function(output) {
18154 var p = output.parent();
18155 return p instanceof AST_New && p.expression === this;
18156 });
18157 PARENS(AST_New, function(output) {
18158 var p = output.parent();
18159 if (no_constructor_parens(this, output) && (p instanceof AST_PropAccess || p instanceof AST_Call && p.expression === this)) return true;
18160 });
18161 PARENS(AST_Number, function(output) {
18162 var p = output.parent();
18163 if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) return true;
18164 });
18165 PARENS(AST_NaN, function(output) {
18166 var p = output.parent();
18167 if (p instanceof AST_PropAccess && p.expression === this) return true;
18168 });
18169 function assign_and_conditional_paren_rules(output) {
18170 var p = output.parent();
18171 if (p instanceof AST_Unary) return true;
18172 if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true;
18173 if (p instanceof AST_Call && p.expression === this) return true;
18174 if (p instanceof AST_Conditional && p.condition === this) return true;
18175 if (p instanceof AST_PropAccess && p.expression === this) return true;
18176 }
18177 PARENS(AST_Assign, assign_and_conditional_paren_rules);
18178 PARENS(AST_Conditional, assign_and_conditional_paren_rules);
18179 DEFPRINT(AST_Directive, function(self, output) {
18180 output.print_string(self.value);
18181 output.semicolon();
18182 });
18183 DEFPRINT(AST_Debugger, function(self, output) {
18184 output.print("debugger");
18185 output.semicolon();
18186 });
18187 function display_body(body, is_toplevel, output) {
18188 var last = body.length - 1;
18189 body.forEach(function(stmt, i) {
18190 if (!(stmt instanceof AST_EmptyStatement)) {
18191 output.indent();
18192 stmt.print(output);
18193 if (!(i == last && is_toplevel)) {
18194 output.newline();
18195 if (is_toplevel) output.newline();
18196 }
18197 }
18198 });
18199 }
18200 AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
18201 force_statement(this.body, output);
18202 });
18203 DEFPRINT(AST_Statement, function(self, output) {
18204 self.body.print(output);
18205 output.semicolon();
18206 });
18207 DEFPRINT(AST_Toplevel, function(self, output) {
18208 display_body(self.body, true, output);
18209 output.print("");
18210 });
18211 DEFPRINT(AST_LabeledStatement, function(self, output) {
18212 self.label.print(output);
18213 output.colon();
18214 self.body.print(output);
18215 });
18216 DEFPRINT(AST_SimpleStatement, function(self, output) {
18217 self.body.print(output);
18218 output.semicolon();
18219 });
18220 function print_bracketed(body, output) {
18221 if (body.length > 0) output.with_block(function() {
18222 display_body(body, false, output);
18223 }); else output.print("{}");
18224 }
18225 DEFPRINT(AST_BlockStatement, function(self, output) {
18226 print_bracketed(self.body, output);
18227 });
18228 DEFPRINT(AST_EmptyStatement, function(self, output) {
18229 output.semicolon();
18230 });
18231 DEFPRINT(AST_Do, function(self, output) {
18232 output.print("do");
18233 output.space(); 19287 output.space();
18234 self._do_print_body(output); 19288 self.name.print(output);
18235 output.space(); 19289 }
18236 output.print("while"); 19290 output.with_parens(function(){
18237 output.space(); 19291 self.argnames.forEach(function(arg, i){
18238 output.with_parens(function() {
18239 self.condition.print(output);
18240 });
18241 output.semicolon();
18242 });
18243 DEFPRINT(AST_While, function(self, output) {
18244 output.print("while");
18245 output.space();
18246 output.with_parens(function() {
18247 self.condition.print(output);
18248 });
18249 output.space();
18250 self._do_print_body(output);
18251 });
18252 DEFPRINT(AST_For, function(self, output) {
18253 output.print("for");
18254 output.space();
18255 output.with_parens(function() {
18256 if (self.init) {
18257 if (self.init instanceof AST_Definitions) {
18258 self.init.print(output);
18259 } else {
18260 parenthesize_for_noin(self.init, output, true);
18261 }
18262 output.print(";");
18263 output.space();
18264 } else {
18265 output.print(";");
18266 }
18267 if (self.condition) {
18268 self.condition.print(output);
18269 output.print(";");
18270 output.space();
18271 } else {
18272 output.print(";");
18273 }
18274 if (self.step) {
18275 self.step.print(output);
18276 }
18277 });
18278 output.space();
18279 self._do_print_body(output);
18280 });
18281 DEFPRINT(AST_ForIn, function(self, output) {
18282 output.print("for");
18283 output.space();
18284 output.with_parens(function() {
18285 self.init.print(output);
18286 output.space();
18287 output.print("in");
18288 output.space();
18289 self.object.print(output);
18290 });
18291 output.space();
18292 self._do_print_body(output);
18293 });
18294 DEFPRINT(AST_With, function(self, output) {
18295 output.print("with");
18296 output.space();
18297 output.with_parens(function() {
18298 self.expression.print(output);
18299 });
18300 output.space();
18301 self._do_print_body(output);
18302 });
18303 AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
18304 var self = this;
18305 if (!nokeyword) {
18306 output.print("function");
18307 }
18308 if (self.name) {
18309 output.space();
18310 self.name.print(output);
18311 }
18312 output.with_parens(function() {
18313 self.argnames.forEach(function(arg, i) {
18314 if (i) output.comma();
18315 arg.print(output);
18316 });
18317 });
18318 output.space();
18319 print_bracketed(self.body, output);
18320 });
18321 DEFPRINT(AST_Lambda, function(self, output) {
18322 self._do_print(output);
18323 });
18324 AST_Exit.DEFMETHOD("_do_print", function(output, kind) {
18325 output.print(kind);
18326 if (this.value) {
18327 output.space();
18328 this.value.print(output);
18329 }
18330 output.semicolon();
18331 });
18332 DEFPRINT(AST_Return, function(self, output) {
18333 self._do_print(output, "return");
18334 });
18335 DEFPRINT(AST_Throw, function(self, output) {
18336 self._do_print(output, "throw");
18337 });
18338 AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) {
18339 output.print(kind);
18340 if (this.label) {
18341 output.space();
18342 this.label.print(output);
18343 }
18344 output.semicolon();
18345 });
18346 DEFPRINT(AST_Break, function(self, output) {
18347 self._do_print(output, "break");
18348 });
18349 DEFPRINT(AST_Continue, function(self, output) {
18350 self._do_print(output, "continue");
18351 });
18352 function make_then(self, output) {
18353 if (output.option("bracketize")) {
18354 make_block(self.body, output);
18355 return;
18356 }
18357 if (!self.body) return output.force_semicolon();
18358 if (self.body instanceof AST_Do && !output.option("screw_ie8")) {
18359 make_block(self.body, output);
18360 return;
18361 }
18362 var b = self.body;
18363 while (true) {
18364 if (b instanceof AST_If) {
18365 if (!b.alternative) {
18366 make_block(self.body, output);
18367 return;
18368 }
18369 b = b.alternative;
18370 } else if (b instanceof AST_StatementWithBody) {
18371 b = b.body;
18372 } else break;
18373 }
18374 force_statement(self.body, output);
18375 }
18376 DEFPRINT(AST_If, function(self, output) {
18377 output.print("if");
18378 output.space();
18379 output.with_parens(function() {
18380 self.condition.print(output);
18381 });
18382 output.space();
18383 if (self.alternative) {
18384 make_then(self, output);
18385 output.space();
18386 output.print("else");
18387 output.space();
18388 force_statement(self.alternative, output);
18389 } else {
18390 self._do_print_body(output);
18391 }
18392 });
18393 DEFPRINT(AST_Switch, function(self, output) {
18394 output.print("switch");
18395 output.space();
18396 output.with_parens(function() {
18397 self.expression.print(output);
18398 });
18399 output.space();
18400 if (self.body.length > 0) output.with_block(function() {
18401 self.body.forEach(function(stmt, i) {
18402 if (i) output.newline();
18403 output.indent(true);
18404 stmt.print(output);
18405 });
18406 }); else output.print("{}");
18407 });
18408 AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
18409 if (this.body.length > 0) {
18410 output.newline();
18411 this.body.forEach(function(stmt) {
18412 output.indent();
18413 stmt.print(output);
18414 output.newline();
18415 });
18416 }
18417 });
18418 DEFPRINT(AST_Default, function(self, output) {
18419 output.print("default:");
18420 self._do_print_body(output);
18421 });
18422 DEFPRINT(AST_Case, function(self, output) {
18423 output.print("case");
18424 output.space();
18425 self.expression.print(output);
18426 output.print(":");
18427 self._do_print_body(output);
18428 });
18429 DEFPRINT(AST_Try, function(self, output) {
18430 output.print("try");
18431 output.space();
18432 print_bracketed(self.body, output);
18433 if (self.bcatch) {
18434 output.space();
18435 self.bcatch.print(output);
18436 }
18437 if (self.bfinally) {
18438 output.space();
18439 self.bfinally.print(output);
18440 }
18441 });
18442 DEFPRINT(AST_Catch, function(self, output) {
18443 output.print("catch");
18444 output.space();
18445 output.with_parens(function() {
18446 self.argname.print(output);
18447 });
18448 output.space();
18449 print_bracketed(self.body, output);
18450 });
18451 DEFPRINT(AST_Finally, function(self, output) {
18452 output.print("finally");
18453 output.space();
18454 print_bracketed(self.body, output);
18455 });
18456 AST_Definitions.DEFMETHOD("_do_print", function(output, kind) {
18457 output.print(kind);
18458 output.space();
18459 this.definitions.forEach(function(def, i) {
18460 if (i) output.comma(); 19292 if (i) output.comma();
18461 def.print(output); 19293 arg.print(output);
18462 });
18463 var p = output.parent();
18464 var in_for = p instanceof AST_For || p instanceof AST_ForIn;
18465 var avoid_semicolon = in_for && p.init === this;
18466 if (!avoid_semicolon) output.semicolon();
18467 });
18468 DEFPRINT(AST_Var, function(self, output) {
18469 self._do_print(output, "var");
18470 });
18471 DEFPRINT(AST_Const, function(self, output) {
18472 self._do_print(output, "const");
18473 });
18474 function parenthesize_for_noin(node, output, noin) {
18475 if (!noin) node.print(output); else try {
18476 node.walk(new TreeWalker(function(node) {
18477 if (node instanceof AST_Binary && node.operator == "in") throw output;
18478 }));
18479 node.print(output);
18480 } catch (ex) {
18481 if (ex !== output) throw ex;
18482 node.print(output, true);
18483 }
18484 }
18485 DEFPRINT(AST_VarDef, function(self, output) {
18486 self.name.print(output);
18487 if (self.value) {
18488 output.space();
18489 output.print("=");
18490 output.space();
18491 var p = output.parent(1);
18492 var noin = p instanceof AST_For || p instanceof AST_ForIn;
18493 parenthesize_for_noin(self.value, output, noin);
18494 }
18495 });
18496 DEFPRINT(AST_Call, function(self, output) {
18497 self.expression.print(output);
18498 if (self instanceof AST_New && no_constructor_parens(self, output)) return;
18499 output.with_parens(function() {
18500 self.args.forEach(function(expr, i) {
18501 if (i) output.comma();
18502 expr.print(output);
18503 });
18504 }); 19294 });
18505 }); 19295 });
18506 DEFPRINT(AST_New, function(self, output) { 19296 output.space();
18507 output.print("new"); 19297 print_bracketed(self.body, output);
19298 });
19299 DEFPRINT(AST_Lambda, function(self, output){
19300 self._do_print(output);
19301 });
19302
19303 /* -----[ exits ]----- */
19304 AST_Exit.DEFMETHOD("_do_print", function(output, kind){
19305 output.print(kind);
19306 if (this.value) {
18508 output.space(); 19307 output.space();
18509 AST_Call.prototype._codegen(self, output); 19308 this.value.print(output);
19309 }
19310 output.semicolon();
19311 });
19312 DEFPRINT(AST_Return, function(self, output){
19313 self._do_print(output, "return");
19314 });
19315 DEFPRINT(AST_Throw, function(self, output){
19316 self._do_print(output, "throw");
19317 });
19318
19319 /* -----[ loop control ]----- */
19320 AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
19321 output.print(kind);
19322 if (this.label) {
19323 output.space();
19324 this.label.print(output);
19325 }
19326 output.semicolon();
19327 });
19328 DEFPRINT(AST_Break, function(self, output){
19329 self._do_print(output, "break");
19330 });
19331 DEFPRINT(AST_Continue, function(self, output){
19332 self._do_print(output, "continue");
19333 });
19334
19335 /* -----[ if ]----- */
19336 function make_then(self, output) {
19337 if (output.option("bracketize")) {
19338 make_block(self.body, output);
19339 return;
19340 }
19341 // The squeezer replaces "block"-s that contain only a single
19342 // statement with the statement itself; technically, the AST
19343 // is correct, but this can create problems when we output an
19344 // IF having an ELSE clause where the THEN clause ends in an
19345 // IF *without* an ELSE block (then the outer ELSE would refer
19346 // to the inner IF). This function checks for this case and
19347 // adds the block brackets if needed.
19348 if (!self.body)
19349 return output.force_semicolon();
19350 if (self.body instanceof AST_Do
19351 && !output.option("screw_ie8")) {
19352 // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
19353 // croaks with "syntax error" on code like this: if (foo)
19354 // do ... while(cond); else ... we need block brackets
19355 // around do/while
19356 make_block(self.body, output);
19357 return;
19358 }
19359 var b = self.body;
19360 while (true) {
19361 if (b instanceof AST_If) {
19362 if (!b.alternative) {
19363 make_block(self.body, output);
19364 return;
19365 }
19366 b = b.alternative;
19367 }
19368 else if (b instanceof AST_StatementWithBody) {
19369 b = b.body;
19370 }
19371 else break;
19372 }
19373 force_statement(self.body, output);
19374 };
19375 DEFPRINT(AST_If, function(self, output){
19376 output.print("if");
19377 output.space();
19378 output.with_parens(function(){
19379 self.condition.print(output);
18510 }); 19380 });
18511 AST_Seq.DEFMETHOD("_do_print", function(output) { 19381 output.space();
18512 this.car.print(output); 19382 if (self.alternative) {
18513 if (this.cdr) { 19383 make_then(self, output);
18514 output.comma(); 19384 output.space();
18515 if (output.should_break()) { 19385 output.print("else");
18516 output.newline(); 19386 output.space();
18517 output.indent(); 19387 force_statement(self.alternative, output);
18518 } 19388 } else {
18519 this.cdr.print(output); 19389 self._do_print_body(output);
18520 } 19390 }
18521 }); 19391 });
18522 DEFPRINT(AST_Seq, function(self, output) { 19392
18523 self._do_print(output); 19393 /* -----[ switch ]----- */
18524 }); 19394 DEFPRINT(AST_Switch, function(self, output){
18525 DEFPRINT(AST_Dot, function(self, output) { 19395 output.print("switch");
18526 var expr = self.expression; 19396 output.space();
18527 expr.print(output); 19397 output.with_parens(function(){
18528 if (expr instanceof AST_Number && expr.getValue() >= 0) {
18529 if (!/[xa-f.]/i.test(output.last())) {
18530 output.print(".");
18531 }
18532 }
18533 output.print(".");
18534 output.add_mapping(self.end);
18535 output.print_name(self.property);
18536 });
18537 DEFPRINT(AST_Sub, function(self, output) {
18538 self.expression.print(output);
18539 output.print("[");
18540 self.property.print(output);
18541 output.print("]");
18542 });
18543 DEFPRINT(AST_UnaryPrefix, function(self, output) {
18544 var op = self.operator;
18545 output.print(op);
18546 if (/^[a-z]/i.test(op)) output.space();
18547 self.expression.print(output); 19398 self.expression.print(output);
18548 }); 19399 });
18549 DEFPRINT(AST_UnaryPostfix, function(self, output) { 19400 output.space();
18550 self.expression.print(output); 19401 if (self.body.length > 0) output.with_block(function(){
18551 output.print(self.operator); 19402 self.body.forEach(function(stmt, i){
18552 }); 19403 if (i) output.newline();
18553 DEFPRINT(AST_Binary, function(self, output) { 19404 output.indent(true);
18554 self.left.print(output); 19405 stmt.print(output);
18555 output.space();
18556 output.print(self.operator);
18557 output.space();
18558 self.right.print(output);
18559 });
18560 DEFPRINT(AST_Conditional, function(self, output) {
18561 self.condition.print(output);
18562 output.space();
18563 output.print("?");
18564 output.space();
18565 self.consequent.print(output);
18566 output.space();
18567 output.colon();
18568 self.alternative.print(output);
18569 });
18570 DEFPRINT(AST_Array, function(self, output) {
18571 output.with_square(function() {
18572 var a = self.elements, len = a.length;
18573 if (len > 0) output.space();
18574 a.forEach(function(exp, i) {
18575 if (i) output.comma();
18576 exp.print(output);
18577 if (i === len - 1 && exp instanceof AST_Hole) output.comma();
18578 });
18579 if (len > 0) output.space();
18580 }); 19406 });
18581 }); 19407 });
18582 DEFPRINT(AST_Object, function(self, output) { 19408 else output.print("{}");
18583 if (self.properties.length > 0) output.with_block(function() { 19409 });
18584 self.properties.forEach(function(prop, i) { 19410 AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
18585 if (i) { 19411 if (this.body.length > 0) {
18586 output.print(","); 19412 output.newline();
18587 output.newline(); 19413 this.body.forEach(function(stmt){
18588 }
18589 output.indent();
18590 prop.print(output);
18591 });
18592 output.newline();
18593 }); else output.print("{}");
18594 });
18595 DEFPRINT(AST_ObjectKeyVal, function(self, output) {
18596 var key = self.key;
18597 if (output.option("quote_keys")) {
18598 output.print_string(key + "");
18599 } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) {
18600 output.print(make_num(key));
18601 } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
18602 output.print_name(key);
18603 } else {
18604 output.print_string(key);
18605 }
18606 output.colon();
18607 self.value.print(output);
18608 });
18609 DEFPRINT(AST_ObjectSetter, function(self, output) {
18610 output.print("set");
18611 self.value._do_print(output, true);
18612 });
18613 DEFPRINT(AST_ObjectGetter, function(self, output) {
18614 output.print("get");
18615 self.value._do_print(output, true);
18616 });
18617 DEFPRINT(AST_Symbol, function(self, output) {
18618 var def = self.definition();
18619 output.print_name(def ? def.mangled_name || def.name : self.name);
18620 });
18621 DEFPRINT(AST_Undefined, function(self, output) {
18622 output.print("void 0");
18623 });
18624 DEFPRINT(AST_Hole, noop);
18625 DEFPRINT(AST_Infinity, function(self, output) {
18626 output.print("1/0");
18627 });
18628 DEFPRINT(AST_NaN, function(self, output) {
18629 output.print("0/0");
18630 });
18631 DEFPRINT(AST_This, function(self, output) {
18632 output.print("this");
18633 });
18634 DEFPRINT(AST_Constant, function(self, output) {
18635 output.print(self.getValue());
18636 });
18637 DEFPRINT(AST_String, function(self, output) {
18638 output.print_string(self.getValue());
18639 });
18640 DEFPRINT(AST_Number, function(self, output) {
18641 output.print(make_num(self.getValue()));
18642 });
18643 DEFPRINT(AST_RegExp, function(self, output) {
18644 var str = self.getValue().toString();
18645 if (output.option("ascii_only")) str = output.to_ascii(str);
18646 output.print(str);
18647 var p = output.parent();
18648 if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) output.print(" ");
18649 });
18650 function force_statement(stat, output) {
18651 if (output.option("bracketize")) {
18652 if (!stat || stat instanceof AST_EmptyStatement) output.print("{}"); else if (stat instanceof AST_BlockStatement) stat.print(output); else output.with_block(function() {
18653 output.indent();
18654 stat.print(output);
18655 output.newline();
18656 });
18657 } else {
18658 if (!stat || stat instanceof AST_EmptyStatement) output.force_semicolon(); else stat.print(output);
18659 }
18660 }
18661 function first_in_statement(output) {
18662 var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
18663 while (i > 0) {
18664 if (p instanceof AST_Statement && p.body === node) return true;
18665 if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) {
18666 node = p;
18667 p = a[--i];
18668 } else {
18669 return false;
18670 }
18671 }
18672 }
18673 function no_constructor_parens(self, output) {
18674 return self.args.length == 0 && !output.option("beautify");
18675 }
18676 function best_of(a) {
18677 var best = a[0], len = best.length;
18678 for (var i = 1; i < a.length; ++i) {
18679 if (a[i].length < len) {
18680 best = a[i];
18681 len = best.length;
18682 }
18683 }
18684 return best;
18685 }
18686 function make_num(num) {
18687 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace("e+", "e") ], m;
18688 if (Math.floor(num) === num) {
18689 if (num >= 0) {
18690 a.push("0x" + num.toString(16).toLowerCase(), "0" + num.toString(8));
18691 } else {
18692 a.push("-0x" + (-num).toString(16).toLowerCase(), "-0" + (-num).toString(8));
18693 }
18694 if (m = /^(.*?)(0+)$/.exec(num)) {
18695 a.push(m[1] + "e" + m[2].length);
18696 }
18697 } else if (m = /^0?\.(0+)(.*)$/.exec(num)) {
18698 a.push(m[2] + "e-" + (m[1].length + m[2].length), str.substr(str.indexOf(".")));
18699 }
18700 return best_of(a);
18701 }
18702 function make_block(stmt, output) {
18703 if (stmt instanceof AST_BlockStatement) {
18704 stmt.print(output);
18705 return;
18706 }
18707 output.with_block(function() {
18708 output.indent(); 19414 output.indent();
18709 stmt.print(output); 19415 stmt.print(output);
18710 output.newline(); 19416 output.newline();
18711 }); 19417 });
18712 } 19418 }
18713 function DEFMAP(nodetype, generator) { 19419 });
18714 nodetype.DEFMETHOD("add_source_map", function(stream) { 19420 DEFPRINT(AST_Default, function(self, output){
18715 generator(this, stream); 19421 output.print("default:");
19422 self._do_print_body(output);
19423 });
19424 DEFPRINT(AST_Case, function(self, output){
19425 output.print("case");
19426 output.space();
19427 self.expression.print(output);
19428 output.print(":");
19429 self._do_print_body(output);
19430 });
19431
19432 /* -----[ exceptions ]----- */
19433 DEFPRINT(AST_Try, function(self, output){
19434 output.print("try");
19435 output.space();
19436 print_bracketed(self.body, output);
19437 if (self.bcatch) {
19438 output.space();
19439 self.bcatch.print(output);
19440 }
19441 if (self.bfinally) {
19442 output.space();
19443 self.bfinally.print(output);
19444 }
19445 });
19446 DEFPRINT(AST_Catch, function(self, output){
19447 output.print("catch");
19448 output.space();
19449 output.with_parens(function(){
19450 self.argname.print(output);
19451 });
19452 output.space();
19453 print_bracketed(self.body, output);
19454 });
19455 DEFPRINT(AST_Finally, function(self, output){
19456 output.print("finally");
19457 output.space();
19458 print_bracketed(self.body, output);
19459 });
19460
19461 /* -----[ var/const ]----- */
19462 AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
19463 output.print(kind);
19464 output.space();
19465 this.definitions.forEach(function(def, i){
19466 if (i) output.comma();
19467 def.print(output);
19468 });
19469 var p = output.parent();
19470 var in_for = p instanceof AST_For || p instanceof AST_ForIn;
19471 var avoid_semicolon = in_for && p.init === this;
19472 if (!avoid_semicolon)
19473 output.semicolon();
19474 });
19475 DEFPRINT(AST_Var, function(self, output){
19476 self._do_print(output, "var");
19477 });
19478 DEFPRINT(AST_Const, function(self, output){
19479 self._do_print(output, "const");
19480 });
19481
19482 function parenthesize_for_noin(node, output, noin) {
19483 if (!noin) node.print(output);
19484 else try {
19485 // need to take some precautions here:
19486 // https://github.com/mishoo/UglifyJS2/issues/60
19487 node.walk(new TreeWalker(function(node){
19488 if (node instanceof AST_Binary && node.operator == "in")
19489 throw output;
19490 }));
19491 node.print(output);
19492 } catch(ex) {
19493 if (ex !== output) throw ex;
19494 node.print(output, true);
19495 }
19496 };
19497
19498 DEFPRINT(AST_VarDef, function(self, output){
19499 self.name.print(output);
19500 if (self.value) {
19501 output.space();
19502 output.print("=");
19503 output.space();
19504 var p = output.parent(1);
19505 var noin = p instanceof AST_For || p instanceof AST_ForIn;
19506 parenthesize_for_noin(self.value, output, noin);
19507 }
19508 });
19509
19510 /* -----[ other expressions ]----- */
19511 DEFPRINT(AST_Call, function(self, output){
19512 self.expression.print(output);
19513 if (self instanceof AST_New && no_constructor_parens(self, output))
19514 return;
19515 output.with_parens(function(){
19516 self.args.forEach(function(expr, i){
19517 if (i) output.comma();
19518 expr.print(output);
18716 }); 19519 });
18717 }
18718 DEFMAP(AST_Node, noop);
18719 function basic_sourcemap_gen(self, output) {
18720 output.add_mapping(self.start);
18721 }
18722 DEFMAP(AST_Directive, basic_sourcemap_gen);
18723 DEFMAP(AST_Debugger, basic_sourcemap_gen);
18724 DEFMAP(AST_Symbol, basic_sourcemap_gen);
18725 DEFMAP(AST_Jump, basic_sourcemap_gen);
18726 DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
18727 DEFMAP(AST_LabeledStatement, noop);
18728 DEFMAP(AST_Lambda, basic_sourcemap_gen);
18729 DEFMAP(AST_Switch, basic_sourcemap_gen);
18730 DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
18731 DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
18732 DEFMAP(AST_Toplevel, noop);
18733 DEFMAP(AST_New, basic_sourcemap_gen);
18734 DEFMAP(AST_Try, basic_sourcemap_gen);
18735 DEFMAP(AST_Catch, basic_sourcemap_gen);
18736 DEFMAP(AST_Finally, basic_sourcemap_gen);
18737 DEFMAP(AST_Definitions, basic_sourcemap_gen);
18738 DEFMAP(AST_Constant, basic_sourcemap_gen);
18739 DEFMAP(AST_ObjectProperty, function(self, output) {
18740 output.add_mapping(self.start, self.key);
18741 }); 19520 });
18742 })(); 19521 });
18743 "use strict"; 19522 DEFPRINT(AST_New, function(self, output){
18744 function Compressor(options, false_by_default) { 19523 output.print("new");
18745 if (!(this instanceof Compressor)) return new Compressor(options, false_by_default); 19524 output.space();
18746 TreeTransformer.call(this, this.before, this.after); 19525 AST_Call.prototype._codegen(self, output);
18747 this.options = defaults(options, { 19526 });
18748 sequences: !false_by_default, 19527
18749 properties: !false_by_default, 19528 AST_Seq.DEFMETHOD("_do_print", function(output){
18750 dead_code: !false_by_default, 19529 this.car.print(output);
18751 drop_debugger: !false_by_default, 19530 if (this.cdr) {
18752 unsafe: false, 19531 output.comma();
18753 unsafe_comps: false, 19532 if (output.should_break()) {
18754 conditionals: !false_by_default, 19533 output.newline();
18755 comparisons: !false_by_default, 19534 output.indent();
18756 evaluate: !false_by_default, 19535 }
18757 booleans: !false_by_default, 19536 this.cdr.print(output);
18758 loops: !false_by_default, 19537 }
18759 unused: !false_by_default, 19538 });
18760 hoist_funs: !false_by_default, 19539 DEFPRINT(AST_Seq, function(self, output){
18761 hoist_vars: false, 19540 self._do_print(output);
18762 if_return: !false_by_default, 19541 // var p = output.parent();
18763 join_vars: !false_by_default, 19542 // if (p instanceof AST_Statement) {
18764 cascade: !false_by_default, 19543 // output.with_indent(output.next_indent(), function(){
18765 side_effects: !false_by_default, 19544 // self._do_print(output);
18766 negate_iife: !false_by_default, 19545 // });
18767 screw_ie8: false, 19546 // } else {
18768 warnings: true, 19547 // self._do_print(output);
18769 global_defs: {} 19548 // }
18770 }, true); 19549 });
18771 } 19550 DEFPRINT(AST_Dot, function(self, output){
18772 Compressor.prototype = new TreeTransformer(); 19551 var expr = self.expression;
18773 merge(Compressor.prototype, { 19552 expr.print(output);
18774 option: function(key) { 19553 if (expr instanceof AST_Number && expr.getValue() >= 0) {
18775 return this.options[key]; 19554 if (!/[xa-f.]/i.test(output.last())) {
18776 }, 19555 output.print(".");
18777 warn: function() { 19556 }
18778 if (this.options.warnings) AST_Node.warn.apply(AST_Node, arguments); 19557 }
18779 }, 19558 output.print(".");
18780 before: function(node, descend, in_list) { 19559 // the name after dot would be mapped about here.
18781 if (node._squeezed) return node; 19560 output.add_mapping(self.end);
18782 if (node instanceof AST_Scope) { 19561 output.print_name(self.property);
18783 node.drop_unused(this); 19562 });
18784 node = node.hoist_declarations(this); 19563 DEFPRINT(AST_Sub, function(self, output){
18785 } 19564 self.expression.print(output);
19565 output.print("[");
19566 self.property.print(output);
19567 output.print("]");
19568 });
19569 DEFPRINT(AST_UnaryPrefix, function(self, output){
19570 var op = self.operator;
19571 output.print(op);
19572 if (/^[a-z]/i.test(op))
19573 output.space();
19574 self.expression.print(output);
19575 });
19576 DEFPRINT(AST_UnaryPostfix, function(self, output){
19577 self.expression.print(output);
19578 output.print(self.operator);
19579 });
19580 DEFPRINT(AST_Binary, function(self, output){
19581 self.left.print(output);
19582 output.space();
19583 output.print(self.operator);
19584 if (self.operator == "<"
19585 && self.right instanceof AST_UnaryPrefix
19586 && self.right.operator == "!"
19587 && self.right.expression instanceof AST_UnaryPrefix
19588 && self.right.expression.operator == "--") {
19589 // space is mandatory to avoid outputting <!--
19590 // http://javascript.spec.whatwg.org/#comment-syntax
19591 output.print(" ");
19592 } else {
19593 // the space is optional depending on "beautify"
19594 output.space();
19595 }
19596 self.right.print(output);
19597 });
19598 DEFPRINT(AST_Conditional, function(self, output){
19599 self.condition.print(output);
19600 output.space();
19601 output.print("?");
19602 output.space();
19603 self.consequent.print(output);
19604 output.space();
19605 output.colon();
19606 self.alternative.print(output);
19607 });
19608
19609 /* -----[ literals ]----- */
19610 DEFPRINT(AST_Array, function(self, output){
19611 output.with_square(function(){
19612 var a = self.elements, len = a.length;
19613 if (len > 0) output.space();
19614 a.forEach(function(exp, i){
19615 if (i) output.comma();
19616 exp.print(output);
19617 // If the final element is a hole, we need to make sure it
19618 // doesn't look like a trailing comma, by inserting an actual
19619 // trailing comma.
19620 if (i === len - 1 && exp instanceof AST_Hole)
19621 output.comma();
19622 });
19623 if (len > 0) output.space();
19624 });
19625 });
19626 DEFPRINT(AST_Object, function(self, output){
19627 if (self.properties.length > 0) output.with_block(function(){
19628 self.properties.forEach(function(prop, i){
19629 if (i) {
19630 output.print(",");
19631 output.newline();
19632 }
19633 output.indent();
19634 prop.print(output);
19635 });
19636 output.newline();
19637 });
19638 else output.print("{}");
19639 });
19640 DEFPRINT(AST_ObjectKeyVal, function(self, output){
19641 var key = self.key;
19642 if (output.option("quote_keys")) {
19643 output.print_string(key + "");
19644 } else if ((typeof key == "number"
19645 || !output.option("beautify")
19646 && +key + "" == key)
19647 && parseFloat(key) >= 0) {
19648 output.print(make_num(key));
19649 } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
19650 output.print_name(key);
19651 } else {
19652 output.print_string(key);
19653 }
19654 output.colon();
19655 self.value.print(output);
19656 });
19657 DEFPRINT(AST_ObjectSetter, function(self, output){
19658 output.print("set");
19659 output.space();
19660 self.key.print(output);
19661 self.value._do_print(output, true);
19662 });
19663 DEFPRINT(AST_ObjectGetter, function(self, output){
19664 output.print("get");
19665 output.space();
19666 self.key.print(output);
19667 self.value._do_print(output, true);
19668 });
19669 DEFPRINT(AST_Symbol, function(self, output){
19670 var def = self.definition();
19671 output.print_name(def ? def.mangled_name || def.name : self.name);
19672 });
19673 DEFPRINT(AST_Undefined, function(self, output){
19674 output.print("void 0");
19675 });
19676 DEFPRINT(AST_Hole, noop);
19677 DEFPRINT(AST_Infinity, function(self, output){
19678 output.print("1/0");
19679 });
19680 DEFPRINT(AST_NaN, function(self, output){
19681 output.print("0/0");
19682 });
19683 DEFPRINT(AST_This, function(self, output){
19684 output.print("this");
19685 });
19686 DEFPRINT(AST_Constant, function(self, output){
19687 output.print(self.getValue());
19688 });
19689 DEFPRINT(AST_String, function(self, output){
19690 output.print_string(self.getValue());
19691 });
19692 DEFPRINT(AST_Number, function(self, output){
19693 output.print(make_num(self.getValue()));
19694 });
19695
19696 function regexp_safe_literal(code) {
19697 return [
19698 0x5c , // \
19699 0x2f , // /
19700 0x2e , // .
19701 0x2b , // +
19702 0x2a , // *
19703 0x3f , // ?
19704 0x28 , // (
19705 0x29 , // )
19706 0x5b , // [
19707 0x5d , // ]
19708 0x7b , // {
19709 0x7d , // }
19710 0x24 , // $
19711 0x5e , // ^
19712 0x3a , // :
19713 0x7c , // |
19714 0x21 , // !
19715 0x0a , // \n
19716 0x0d , // \r
19717 0x00 , // \0
19718 0xfeff , // Unicode BOM
19719 0x2028 , // unicode "line separator"
19720 0x2029 , // unicode "paragraph separator"
19721 ].indexOf(code) < 0;
19722 };
19723
19724 DEFPRINT(AST_RegExp, function(self, output){
19725 var str = self.getValue().toString();
19726 if (output.option("ascii_only")) {
19727 str = output.to_ascii(str);
19728 } else if (output.option("unescape_regexps")) {
19729 str = str.split("\\\\").map(function(str){
19730 return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
19731 var code = parseInt(s.substr(2), 16);
19732 return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
19733 });
19734 }).join("\\\\");
19735 }
19736 output.print(str);
19737 var p = output.parent();
19738 if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
19739 output.print(" ");
19740 });
19741
19742 function force_statement(stat, output) {
19743 if (output.option("bracketize")) {
19744 if (!stat || stat instanceof AST_EmptyStatement)
19745 output.print("{}");
19746 else if (stat instanceof AST_BlockStatement)
19747 stat.print(output);
19748 else output.with_block(function(){
19749 output.indent();
19750 stat.print(output);
19751 output.newline();
19752 });
19753 } else {
19754 if (!stat || stat instanceof AST_EmptyStatement)
19755 output.force_semicolon();
19756 else
19757 stat.print(output);
19758 }
19759 };
19760
19761 // return true if the node at the top of the stack (that means the
19762 // innermost node in the current output) is lexically the first in
19763 // a statement.
19764 function first_in_statement(output) {
19765 var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
19766 while (i > 0) {
19767 if (p instanceof AST_Statement && p.body === node)
19768 return true;
19769 if ((p instanceof AST_Seq && p.car === node ) ||
19770 (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
19771 (p instanceof AST_Dot && p.expression === node ) ||
19772 (p instanceof AST_Sub && p.expression === node ) ||
19773 (p instanceof AST_Conditional && p.condition === node ) ||
19774 (p instanceof AST_Binary && p.left === node ) ||
19775 (p instanceof AST_UnaryPostfix && p.expression === node ))
19776 {
19777 node = p;
19778 p = a[--i];
19779 } else {
19780 return false;
19781 }
19782 }
19783 };
19784
19785 // self should be AST_New. decide if we want to show parens or not.
19786 function no_constructor_parens(self, output) {
19787 return self.args.length == 0 && !output.option("beautify");
19788 };
19789
19790 function best_of(a) {
19791 var best = a[0], len = best.length;
19792 for (var i = 1; i < a.length; ++i) {
19793 if (a[i].length < len) {
19794 best = a[i];
19795 len = best.length;
19796 }
19797 }
19798 return best;
19799 };
19800
19801 function make_num(num) {
19802 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
19803 if (Math.floor(num) === num) {
19804 if (num >= 0) {
19805 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
19806 "0" + num.toString(8)); // same.
19807 } else {
19808 a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
19809 "-0" + (-num).toString(8)); // same.
19810 }
19811 if ((m = /^(.*?)(0+)$/.exec(num))) {
19812 a.push(m[1] + "e" + m[2].length);
19813 }
19814 } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
19815 a.push(m[2] + "e-" + (m[1].length + m[2].length),
19816 str.substr(str.indexOf(".")));
19817 }
19818 return best_of(a);
19819 };
19820
19821 function make_block(stmt, output) {
19822 if (stmt instanceof AST_BlockStatement) {
19823 stmt.print(output);
19824 return;
19825 }
19826 output.with_block(function(){
19827 output.indent();
19828 stmt.print(output);
19829 output.newline();
19830 });
19831 };
19832
19833 /* -----[ source map generators ]----- */
19834
19835 function DEFMAP(nodetype, generator) {
19836 nodetype.DEFMETHOD("add_source_map", function(stream){
19837 generator(this, stream);
19838 });
19839 };
19840
19841 // We could easily add info for ALL nodes, but it seems to me that
19842 // would be quite wasteful, hence this noop in the base class.
19843 DEFMAP(AST_Node, noop);
19844
19845 function basic_sourcemap_gen(self, output) {
19846 output.add_mapping(self.start);
19847 };
19848
19849 // XXX: I'm not exactly sure if we need it for all of these nodes,
19850 // or if we should add even more.
19851
19852 DEFMAP(AST_Directive, basic_sourcemap_gen);
19853 DEFMAP(AST_Debugger, basic_sourcemap_gen);
19854 DEFMAP(AST_Symbol, basic_sourcemap_gen);
19855 DEFMAP(AST_Jump, basic_sourcemap_gen);
19856 DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
19857 DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
19858 DEFMAP(AST_Lambda, basic_sourcemap_gen);
19859 DEFMAP(AST_Switch, basic_sourcemap_gen);
19860 DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
19861 DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
19862 DEFMAP(AST_Toplevel, noop);
19863 DEFMAP(AST_New, basic_sourcemap_gen);
19864 DEFMAP(AST_Try, basic_sourcemap_gen);
19865 DEFMAP(AST_Catch, basic_sourcemap_gen);
19866 DEFMAP(AST_Finally, basic_sourcemap_gen);
19867 DEFMAP(AST_Definitions, basic_sourcemap_gen);
19868 DEFMAP(AST_Constant, basic_sourcemap_gen);
19869 DEFMAP(AST_ObjectProperty, function(self, output){
19870 output.add_mapping(self.start, self.key);
19871 });
19872
19873 })();
19874
19875 /***********************************************************************
19876
19877 A JavaScript tokenizer / parser / beautifier / compressor.
19878 https://github.com/mishoo/UglifyJS2
19879
19880 -------------------------------- (C) ---------------------------------
19881
19882 Author: Mihai Bazon
19883 <mihai.bazon@gmail.com>
19884 http://mihai.bazon.net/blog
19885
19886 Distributed under the BSD license:
19887
19888 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
19889
19890 Redistribution and use in source and binary forms, with or without
19891 modification, are permitted provided that the following conditions
19892 are met:
19893
19894 * Redistributions of source code must retain the above
19895 copyright notice, this list of conditions and the following
19896 disclaimer.
19897
19898 * Redistributions in binary form must reproduce the above
19899 copyright notice, this list of conditions and the following
19900 disclaimer in the documentation and/or other materials
19901 provided with the distribution.
19902
19903 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
19904 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19905 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19906 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
19907 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19908 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19909 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19910 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19911 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
19912 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
19913 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19914 SUCH DAMAGE.
19915
19916 ***********************************************************************/
19917
19918 "use strict";
19919
19920 function Compressor(options, false_by_default) {
19921 if (!(this instanceof Compressor))
19922 return new Compressor(options, false_by_default);
19923 TreeTransformer.call(this, this.before, this.after);
19924 this.options = defaults(options, {
19925 sequences : !false_by_default,
19926 properties : !false_by_default,
19927 dead_code : !false_by_default,
19928 drop_debugger : !false_by_default,
19929 unsafe : false,
19930 unsafe_comps : false,
19931 conditionals : !false_by_default,
19932 comparisons : !false_by_default,
19933 evaluate : !false_by_default,
19934 booleans : !false_by_default,
19935 loops : !false_by_default,
19936 unused : !false_by_default,
19937 hoist_funs : !false_by_default,
19938 keep_fargs : false,
19939 hoist_vars : false,
19940 if_return : !false_by_default,
19941 join_vars : !false_by_default,
19942 cascade : !false_by_default,
19943 side_effects : !false_by_default,
19944 pure_getters : false,
19945 pure_funcs : null,
19946 negate_iife : !false_by_default,
19947 screw_ie8 : false,
19948 drop_console : false,
19949 angular : false,
19950
19951 warnings : true,
19952 global_defs : {}
19953 }, true);
19954 };
19955
19956 Compressor.prototype = new TreeTransformer;
19957 merge(Compressor.prototype, {
19958 option: function(key) { return this.options[key] },
19959 warn: function() {
19960 if (this.options.warnings)
19961 AST_Node.warn.apply(AST_Node, arguments);
19962 },
19963 before: function(node, descend, in_list) {
19964 if (node._squeezed) return node;
19965 var was_scope = false;
19966 if (node instanceof AST_Scope) {
19967 node = node.hoist_declarations(this);
19968 was_scope = true;
19969 }
19970 descend(node, this);
19971 node = node.optimize(this);
19972 if (was_scope && node instanceof AST_Scope) {
19973 node.drop_unused(this);
18786 descend(node, this); 19974 descend(node, this);
18787 node = node.optimize(this); 19975 }
18788 if (node instanceof AST_Scope) { 19976 node._squeezed = true;
18789 var save_warnings = this.options.warnings; 19977 return node;
18790 this.options.warnings = false; 19978 }
18791 node.drop_unused(this); 19979 });
18792 this.options.warnings = save_warnings; 19980
18793 } 19981 (function(){
18794 node._squeezed = true; 19982
18795 return node; 19983 function OPT(node, optimizer) {
18796 } 19984 node.DEFMETHOD("optimize", function(compressor){
19985 var self = this;
19986 if (self._optimized) return self;
19987 var opt = optimizer(self, compressor);
19988 opt._optimized = true;
19989 if (opt === self) return opt;
19990 return opt.transform(compressor);
19991 });
19992 };
19993
19994 OPT(AST_Node, function(self, compressor){
19995 return self;
18797 }); 19996 });
18798 (function() { 19997
18799 function OPT(node, optimizer) { 19998 AST_Node.DEFMETHOD("equivalent_to", function(node){
18800 node.DEFMETHOD("optimize", function(compressor) { 19999 // XXX: this is a rather expensive way to test two node's equivalence:
18801 var self = this; 20000 return this.print_to_string() == node.print_to_string();
18802 if (self._optimized) return self; 20001 });
18803 var opt = optimizer(self, compressor); 20002
18804 opt._optimized = true; 20003 function make_node(ctor, orig, props) {
18805 if (opt === self) return opt; 20004 if (!props) props = {};
18806 return opt.transform(compressor); 20005 if (orig) {
18807 }); 20006 if (!props.start) props.start = orig.start;
18808 } 20007 if (!props.end) props.end = orig.end;
18809 OPT(AST_Node, function(self, compressor) { 20008 }
18810 return self; 20009 return new ctor(props);
18811 }); 20010 };
18812 AST_Node.DEFMETHOD("equivalent_to", function(node) { 20011
18813 return this.print_to_string() == node.print_to_string(); 20012 function make_node_from_constant(compressor, val, orig) {
18814 }); 20013 // XXX: WIP.
18815 function make_node(ctor, orig, props) { 20014 // if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){
18816 if (!props) props = {}; 20015 // if (node instanceof AST_SymbolRef) {
18817 if (orig) { 20016 // var scope = compressor.find_parent(AST_Scope);
18818 if (!props.start) props.start = orig.start; 20017 // var def = scope.find_variable(node);
18819 if (!props.end) props.end = orig.end; 20018 // node.thedef = def;
18820 } 20019 // return node;
18821 return new ctor(props); 20020 // }
18822 } 20021 // })).transform(compressor);
18823 function make_node_from_constant(compressor, val, orig) { 20022
18824 if (val instanceof AST_Node) return val.transform(compressor); 20023 if (val instanceof AST_Node) return val.transform(compressor);
18825 switch (typeof val) { 20024 switch (typeof val) {
18826 case "string": 20025 case "string":
18827 return make_node(AST_String, orig, { 20026 return make_node(AST_String, orig, {
18828 value: val 20027 value: val
18829 }).optimize(compressor); 20028 }).optimize(compressor);
18830 20029 case "number":
18831 case "number": 20030 return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
18832 return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, { 20031 value: val
18833 value: val 20032 }).optimize(compressor);
18834 }).optimize(compressor); 20033 case "boolean":
18835 20034 return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
18836 case "boolean": 20035 case "undefined":
18837 return make_node(val ? AST_True : AST_False, orig).optimize(compressor); 20036 return make_node(AST_Undefined, orig).optimize(compressor);
18838 20037 default:
18839 case "undefined": 20038 if (val === null) {
18840 return make_node(AST_Undefined, orig).optimize(compressor); 20039 return make_node(AST_Null, orig).optimize(compressor);
18841 20040 }
18842 default: 20041 if (val instanceof RegExp) {
18843 if (val === null) { 20042 return make_node(AST_RegExp, orig).optimize(compressor);
18844 return make_node(AST_Null, orig).optimize(compressor); 20043 }
18845 } 20044 throw new Error(string_template("Can't handle constant of type: {type}", {
18846 if (val instanceof RegExp) { 20045 type: typeof val
18847 return make_node(AST_RegExp, orig).optimize(compressor); 20046 }));
18848 } 20047 }
18849 throw new Error(string_template("Can't handle constant of type: {type}", { 20048 };
18850 type: typeof val 20049
18851 })); 20050 function as_statement_array(thing) {
18852 } 20051 if (thing === null) return [];
18853 } 20052 if (thing instanceof AST_BlockStatement) return thing.body;
18854 function as_statement_array(thing) { 20053 if (thing instanceof AST_EmptyStatement) return [];
18855 if (thing === null) return []; 20054 if (thing instanceof AST_Statement) return [ thing ];
18856 if (thing instanceof AST_BlockStatement) return thing.body; 20055 throw new Error("Can't convert thing to statement array");
18857 if (thing instanceof AST_EmptyStatement) return []; 20056 };
18858 if (thing instanceof AST_Statement) return [ thing ]; 20057
18859 throw new Error("Can't convert thing to statement array"); 20058 function is_empty(thing) {
18860 } 20059 if (thing === null) return true;
18861 function is_empty(thing) { 20060 if (thing instanceof AST_EmptyStatement) return true;
18862 if (thing === null) return true; 20061 if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
18863 if (thing instanceof AST_EmptyStatement) return true; 20062 return false;
18864 if (thing instanceof AST_BlockStatement) return thing.body.length == 0; 20063 };
18865 return false; 20064
18866 } 20065 function loop_body(x) {
18867 function loop_body(x) { 20066 if (x instanceof AST_Switch) return x;
18868 if (x instanceof AST_Switch) return x; 20067 if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
18869 if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) { 20068 return (x.body instanceof AST_BlockStatement ? x.body : x);
18870 return x.body instanceof AST_BlockStatement ? x.body : x; 20069 }
18871 } 20070 return x;
18872 return x; 20071 };
18873 } 20072
18874 function tighten_body(statements, compressor) { 20073 function tighten_body(statements, compressor) {
18875 var CHANGED; 20074 var CHANGED;
18876 do { 20075 do {
18877 CHANGED = false; 20076 CHANGED = false;
18878 statements = eliminate_spurious_blocks(statements); 20077 if (compressor.option("angular")) {
18879 if (compressor.option("dead_code")) { 20078 statements = process_for_angular(statements);
18880 statements = eliminate_dead_code(statements, compressor); 20079 }
18881 } 20080 statements = eliminate_spurious_blocks(statements);
18882 if (compressor.option("if_return")) { 20081 if (compressor.option("dead_code")) {
18883 statements = handle_if_return(statements, compressor); 20082 statements = eliminate_dead_code(statements, compressor);
18884 } 20083 }
18885 if (compressor.option("sequences")) { 20084 if (compressor.option("if_return")) {
18886 statements = sequencesize(statements, compressor); 20085 statements = handle_if_return(statements, compressor);
18887 } 20086 }
18888 if (compressor.option("join_vars")) { 20087 if (compressor.option("sequences")) {
18889 statements = join_consecutive_vars(statements, compressor); 20088 statements = sequencesize(statements, compressor);
18890 } 20089 }
18891 } while (CHANGED); 20090 if (compressor.option("join_vars")) {
18892 if (compressor.option("negate_iife")) { 20091 statements = join_consecutive_vars(statements, compressor);
18893 negate_iifes(statements, compressor); 20092 }
18894 } 20093 } while (CHANGED);
18895 return statements; 20094
18896 function eliminate_spurious_blocks(statements) { 20095 if (compressor.option("negate_iife")) {
18897 var seen_dirs = []; 20096 negate_iifes(statements, compressor);
18898 return statements.reduce(function(a, stat) { 20097 }
18899 if (stat instanceof AST_BlockStatement) { 20098
20099 return statements;
20100
20101 function process_for_angular(statements) {
20102 function make_injector(func, name) {
20103 return make_node(AST_SimpleStatement, func, {
20104 body: make_node(AST_Assign, func, {
20105 operator: "=",
20106 left: make_node(AST_Dot, name, {
20107 expression: make_node(AST_SymbolRef, name, name),
20108 property: "$inject"
20109 }),
20110 right: make_node(AST_Array, func, {
20111 elements: func.argnames.map(function(sym){
20112 return make_node(AST_String, sym, { value: sym.name });
20113 })
20114 })
20115 })
20116 });
20117 }
20118 return statements.reduce(function(a, stat){
20119 a.push(stat);
20120 var token = stat.start;
20121 var comments = token.comments_before;
20122 if (comments && comments.length > 0) {
20123 var last = comments.pop();
20124 if (/@ngInject/.test(last.value)) {
20125 // case 1: defun
20126 if (stat instanceof AST_Defun) {
20127 a.push(make_injector(stat, stat.name));
20128 }
20129 else if (stat instanceof AST_Definitions) {
20130 stat.definitions.forEach(function(def){
20131 if (def.value && def.value instanceof AST_Lambda) {
20132 a.push(make_injector(def.value, def.name));
20133 }
20134 });
20135 }
20136 else {
20137 compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token);
20138 }
20139 }
20140 }
20141 return a;
20142 }, []);
20143 }
20144
20145 function eliminate_spurious_blocks(statements) {
20146 var seen_dirs = [];
20147 return statements.reduce(function(a, stat){
20148 if (stat instanceof AST_BlockStatement) {
20149 CHANGED = true;
20150 a.push.apply(a, eliminate_spurious_blocks(stat.body));
20151 } else if (stat instanceof AST_EmptyStatement) {
20152 CHANGED = true;
20153 } else if (stat instanceof AST_Directive) {
20154 if (seen_dirs.indexOf(stat.value) < 0) {
20155 a.push(stat);
20156 seen_dirs.push(stat.value);
20157 } else {
18900 CHANGED = true; 20158 CHANGED = true;
18901 a.push.apply(a, eliminate_spurious_blocks(stat.body)); 20159 }
18902 } else if (stat instanceof AST_EmptyStatement) { 20160 } else {
20161 a.push(stat);
20162 }
20163 return a;
20164 }, []);
20165 };
20166
20167 function handle_if_return(statements, compressor) {
20168 var self = compressor.self();
20169 var in_lambda = self instanceof AST_Lambda;
20170 var ret = [];
20171 loop: for (var i = statements.length; --i >= 0;) {
20172 var stat = statements[i];
20173 switch (true) {
20174 case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
20175 CHANGED = true;
20176 // note, ret.length is probably always zero
20177 // because we drop unreachable code before this
20178 // step. nevertheless, it's good to check.
20179 continue loop;
20180 case stat instanceof AST_If:
20181 if (stat.body instanceof AST_Return) {
20182 //---
20183 // pretty silly case, but:
20184 // if (foo()) return; return; ==> foo(); return;
20185 if (((in_lambda && ret.length == 0)
20186 || (ret[0] instanceof AST_Return && !ret[0].value))
20187 && !stat.body.value && !stat.alternative) {
20188 CHANGED = true;
20189 var cond = make_node(AST_SimpleStatement, stat.condition, {
20190 body: stat.condition
20191 });
20192 ret.unshift(cond);
20193 continue loop;
20194 }
20195 //---
20196 // if (foo()) return x; return y; ==> return foo() ? x : y;
20197 if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
20198 CHANGED = true;
20199 stat = stat.clone();
20200 stat.alternative = ret[0];
20201 ret[0] = stat.transform(compressor);
20202 continue loop;
20203 }
20204 //---
20205 // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
20206 if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
20207 CHANGED = true;
20208 stat = stat.clone();
20209 stat.alternative = ret[0] || make_node(AST_Return, stat, {
20210 value: make_node(AST_Undefined, stat)
20211 });
20212 ret[0] = stat.transform(compressor);
20213 continue loop;
20214 }
20215 //---
20216 // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
20217 if (!stat.body.value && in_lambda) {
20218 CHANGED = true;
20219 stat = stat.clone();
20220 stat.condition = stat.condition.negate(compressor);
20221 stat.body = make_node(AST_BlockStatement, stat, {
20222 body: as_statement_array(stat.alternative).concat(ret)
20223 });
20224 stat.alternative = null;
20225 ret = [ stat.transform(compressor) ];
20226 continue loop;
20227 }
20228 //---
20229 if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
20230 && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
20231 CHANGED = true;
20232 ret.push(make_node(AST_Return, ret[0], {
20233 value: make_node(AST_Undefined, ret[0])
20234 }).transform(compressor));
20235 ret = as_statement_array(stat.alternative).concat(ret);
20236 ret.unshift(stat);
20237 continue loop;
20238 }
20239 }
20240
20241 var ab = aborts(stat.body);
20242 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
20243 if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
20244 || (ab instanceof AST_Continue && self === loop_body(lct))
20245 || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
20246 if (ab.label) {
20247 remove(ab.label.thedef.references, ab);
20248 }
18903 CHANGED = true; 20249 CHANGED = true;
18904 } else if (stat instanceof AST_Directive) { 20250 var body = as_statement_array(stat.body).slice(0, -1);
18905 if (seen_dirs.indexOf(stat.value) < 0) { 20251 stat = stat.clone();
20252 stat.condition = stat.condition.negate(compressor);
20253 stat.body = make_node(AST_BlockStatement, stat, {
20254 body: as_statement_array(stat.alternative).concat(ret)
20255 });
20256 stat.alternative = make_node(AST_BlockStatement, stat, {
20257 body: body
20258 });
20259 ret = [ stat.transform(compressor) ];
20260 continue loop;
20261 }
20262
20263 var ab = aborts(stat.alternative);
20264 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
20265 if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
20266 || (ab instanceof AST_Continue && self === loop_body(lct))
20267 || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
20268 if (ab.label) {
20269 remove(ab.label.thedef.references, ab);
20270 }
20271 CHANGED = true;
20272 stat = stat.clone();
20273 stat.body = make_node(AST_BlockStatement, stat.body, {
20274 body: as_statement_array(stat.body).concat(ret)
20275 });
20276 stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
20277 body: as_statement_array(stat.alternative).slice(0, -1)
20278 });
20279 ret = [ stat.transform(compressor) ];
20280 continue loop;
20281 }
20282
20283 ret.unshift(stat);
20284 break;
20285 default:
20286 ret.unshift(stat);
20287 break;
20288 }
20289 }
20290 return ret;
20291 };
20292
20293 function eliminate_dead_code(statements, compressor) {
20294 var has_quit = false;
20295 var orig = statements.length;
20296 var self = compressor.self();
20297 statements = statements.reduce(function(a, stat){
20298 if (has_quit) {
20299 extract_declarations_from_unreachable_code(compressor, stat, a);
20300 } else {
20301 if (stat instanceof AST_LoopControl) {
20302 var lct = compressor.loopcontrol_target(stat.label);
20303 if ((stat instanceof AST_Break
20304 && lct instanceof AST_BlockStatement
20305 && loop_body(lct) === self) || (stat instanceof AST_Continue
20306 && loop_body(lct) === self)) {
20307 if (stat.label) {
20308 remove(stat.label.thedef.references, stat);
20309 }
20310 } else {
18906 a.push(stat); 20311 a.push(stat);
18907 seen_dirs.push(stat.value);
18908 } else {
18909 CHANGED = true;
18910 } 20312 }
18911 } else { 20313 } else {
18912 a.push(stat); 20314 a.push(stat);
18913 } 20315 }
18914 return a; 20316 if (aborts(stat)) has_quit = true;
18915 }, []); 20317 }
18916 } 20318 return a;
18917 function handle_if_return(statements, compressor) { 20319 }, []);
18918 var self = compressor.self(); 20320 CHANGED = statements.length != orig;
18919 var in_lambda = self instanceof AST_Lambda; 20321 return statements;
18920 var ret = []; 20322 };
18921 loop: for (var i = statements.length; --i >= 0; ) { 20323
18922 var stat = statements[i]; 20324 function sequencesize(statements, compressor) {
18923 switch (true) { 20325 if (statements.length < 2) return statements;
18924 case in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0: 20326 var seq = [], ret = [];
18925 CHANGED = true; 20327 function push_seq() {
18926 continue loop; 20328 seq = AST_Seq.from_array(seq);
18927 20329 if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
18928 case stat instanceof AST_If: 20330 body: seq
18929 if (stat.body instanceof AST_Return) { 20331 }));
18930 if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value) && !stat.body.value && !stat.alternative) { 20332 seq = [];
18931 CHANGED = true; 20333 };
18932 var cond = make_node(AST_SimpleStatement, stat.condition, { 20334 statements.forEach(function(stat){
18933 body: stat.condition 20335 if (stat instanceof AST_SimpleStatement) seq.push(stat.body);
18934 }); 20336 else push_seq(), ret.push(stat);
18935 ret.unshift(cond); 20337 });
18936 continue loop; 20338 push_seq();
20339 ret = sequencesize_2(ret, compressor);
20340 CHANGED = ret.length != statements.length;
20341 return ret;
20342 };
20343
20344 function sequencesize_2(statements, compressor) {
20345 function cons_seq(right) {
20346 ret.pop();
20347 var left = prev.body;
20348 if (left instanceof AST_Seq) {
20349 left.add(right);
20350 } else {
20351 left = AST_Seq.cons(left, right);
20352 }
20353 return left.transform(compressor);
20354 };
20355 var ret = [], prev = null;
20356 statements.forEach(function(stat){
20357 if (prev) {
20358 if (stat instanceof AST_For) {
20359 var opera = {};
20360 try {
20361 prev.body.walk(new TreeWalker(function(node){
20362 if (node instanceof AST_Binary && node.operator == "in")
20363 throw opera;
20364 }));
20365 if (stat.init && !(stat.init instanceof AST_Definitions)) {
20366 stat.init = cons_seq(stat.init);
18937 } 20367 }
18938 if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) { 20368 else if (!stat.init) {
18939 CHANGED = true; 20369 stat.init = prev.body;
18940 stat = stat.clone(); 20370 ret.pop();
18941 stat.alternative = ret[0];
18942 ret[0] = stat.transform(compressor);
18943 continue loop;
18944 } 20371 }
18945 if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { 20372 } catch(ex) {
18946 CHANGED = true; 20373 if (ex !== opera) throw ex;
18947 stat = stat.clone();
18948 stat.alternative = ret[0] || make_node(AST_Return, stat, {
18949 value: make_node(AST_Undefined, stat)
18950 });
18951 ret[0] = stat.transform(compressor);
18952 continue loop;
18953 }
18954 if (!stat.body.value && in_lambda) {
18955 CHANGED = true;
18956 stat = stat.clone();
18957 stat.condition = stat.condition.negate(compressor);
18958 stat.body = make_node(AST_BlockStatement, stat, {
18959 body: as_statement_array(stat.alternative).concat(ret)
18960 });
18961 stat.alternative = null;
18962 ret = [ stat.transform(compressor) ];
18963 continue loop;
18964 }
18965 if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
18966 CHANGED = true;
18967 ret.push(make_node(AST_Return, ret[0], {
18968 value: make_node(AST_Undefined, ret[0])
18969 }).transform(compressor));
18970 ret = as_statement_array(stat.alternative).concat(ret);
18971 ret.unshift(stat);
18972 continue loop;
18973 }
18974 }
18975 var ab = aborts(stat.body);
18976 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
18977 if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) {
18978 if (ab.label) {
18979 remove(ab.label.thedef.references, ab.label);
18980 }
18981 CHANGED = true;
18982 var body = as_statement_array(stat.body).slice(0, -1);
18983 stat = stat.clone();
18984 stat.condition = stat.condition.negate(compressor);
18985 stat.body = make_node(AST_BlockStatement, stat, {
18986 body: ret
18987 });
18988 stat.alternative = make_node(AST_BlockStatement, stat, {
18989 body: body
18990 });
18991 ret = [ stat.transform(compressor) ];
18992 continue loop;
18993 }
18994 var ab = aborts(stat.alternative);
18995 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
18996 if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) {
18997 if (ab.label) {
18998 remove(ab.label.thedef.references, ab.label);
18999 }
19000 CHANGED = true;
19001 stat = stat.clone();
19002 stat.body = make_node(AST_BlockStatement, stat.body, {
19003 body: as_statement_array(stat.body).concat(ret)
19004 });
19005 stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
19006 body: as_statement_array(stat.alternative).slice(0, -1)
19007 });
19008 ret = [ stat.transform(compressor) ];
19009 continue loop;
19010 }
19011 ret.unshift(stat);
19012 break;
19013
19014 default:
19015 ret.unshift(stat);
19016 break;
19017 }
19018 }
19019 return ret;
19020 }
19021 function eliminate_dead_code(statements, compressor) {
19022 var has_quit = false;
19023 var orig = statements.length;
19024 var self = compressor.self();
19025 statements = statements.reduce(function(a, stat) {
19026 if (has_quit) {
19027 extract_declarations_from_unreachable_code(compressor, stat, a);
19028 } else {
19029 if (stat instanceof AST_LoopControl) {
19030 var lct = compressor.loopcontrol_target(stat.label);
19031 if (stat instanceof AST_Break && lct instanceof AST_BlockStatement && loop_body(lct) === self || stat instanceof AST_Continue && loop_body(lct) === self) {
19032 if (stat.label) {
19033 remove(stat.label.thedef.references, stat.label);
19034 }
19035 } else {
19036 a.push(stat);
19037 }
19038 } else {
19039 a.push(stat);
19040 }
19041 if (aborts(stat)) has_quit = true;
19042 }
19043 return a;
19044 }, []);
19045 CHANGED = statements.length != orig;
19046 return statements;
19047 }
19048 function sequencesize(statements, compressor) {
19049 if (statements.length < 2) return statements;
19050 var seq = [], ret = [];
19051 function push_seq() {
19052 seq = AST_Seq.from_array(seq);
19053 if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
19054 body: seq
19055 }));
19056 seq = [];
19057 }
19058 statements.forEach(function(stat) {
19059 if (stat instanceof AST_SimpleStatement) seq.push(stat.body); else push_seq(), ret.push(stat);
19060 });
19061 push_seq();
19062 ret = sequencesize_2(ret, compressor);
19063 CHANGED = ret.length != statements.length;
19064 return ret;
19065 }
19066 function sequencesize_2(statements, compressor) {
19067 function cons_seq(right) {
19068 ret.pop();
19069 var left = prev.body;
19070 if (left instanceof AST_Seq) {
19071 left.add(right);
19072 } else {
19073 left = AST_Seq.cons(left, right);
19074 }
19075 return left.transform(compressor);
19076 }
19077 var ret = [], prev = null;
19078 statements.forEach(function(stat) {
19079 if (prev) {
19080 if (stat instanceof AST_For) {
19081 var opera = {};
19082 try {
19083 prev.body.walk(new TreeWalker(function(node) {
19084 if (node instanceof AST_Binary && node.operator == "in") throw opera;
19085 }));
19086 if (stat.init && !(stat.init instanceof AST_Definitions)) {
19087 stat.init = cons_seq(stat.init);
19088 } else if (!stat.init) {
19089 stat.init = prev.body;
19090 ret.pop();
19091 }
19092 } catch (ex) {
19093 if (ex !== opera) throw ex;
19094 }
19095 } else if (stat instanceof AST_If) {
19096 stat.condition = cons_seq(stat.condition);
19097 } else if (stat instanceof AST_With) {
19098 stat.expression = cons_seq(stat.expression);
19099 } else if (stat instanceof AST_Exit && stat.value) {
19100 stat.value = cons_seq(stat.value);
19101 } else if (stat instanceof AST_Exit) {
19102 stat.value = cons_seq(make_node(AST_Undefined, stat));
19103 } else if (stat instanceof AST_Switch) {
19104 stat.expression = cons_seq(stat.expression);
19105 } 20374 }
19106 } 20375 }
19107 ret.push(stat); 20376 else if (stat instanceof AST_If) {
19108 prev = stat instanceof AST_SimpleStatement ? stat : null; 20377 stat.condition = cons_seq(stat.condition);
19109 }); 20378 }
19110 return ret; 20379 else if (stat instanceof AST_With) {
19111 } 20380 stat.expression = cons_seq(stat.expression);
19112 function join_consecutive_vars(statements, compressor) { 20381 }
19113 var prev = null; 20382 else if (stat instanceof AST_Exit && stat.value) {
19114 return statements.reduce(function(a, stat) { 20383 stat.value = cons_seq(stat.value);
19115 if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) { 20384 }
19116 prev.definitions = prev.definitions.concat(stat.definitions); 20385 else if (stat instanceof AST_Exit) {
19117 CHANGED = true; 20386 stat.value = cons_seq(make_node(AST_Undefined, stat));
19118 } else if (stat instanceof AST_For && prev instanceof AST_Definitions && (!stat.init || stat.init.TYPE == prev.TYPE)) { 20387 }
19119 CHANGED = true; 20388 else if (stat instanceof AST_Switch) {
19120 a.pop(); 20389 stat.expression = cons_seq(stat.expression);
19121 if (stat.init) { 20390 }
19122 stat.init.definitions = prev.definitions.concat(stat.init.definitions); 20391 }
19123 } else { 20392 ret.push(stat);
19124 stat.init = prev; 20393 prev = stat instanceof AST_SimpleStatement ? stat : null;
19125 } 20394 });
19126 a.push(stat); 20395 return ret;
19127 prev = stat; 20396 };
20397
20398 function join_consecutive_vars(statements, compressor) {
20399 var prev = null;
20400 return statements.reduce(function(a, stat){
20401 if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
20402 prev.definitions = prev.definitions.concat(stat.definitions);
20403 CHANGED = true;
20404 }
20405 else if (stat instanceof AST_For
20406 && prev instanceof AST_Definitions
20407 && (!stat.init || stat.init.TYPE == prev.TYPE)) {
20408 CHANGED = true;
20409 a.pop();
20410 if (stat.init) {
20411 stat.init.definitions = prev.definitions.concat(stat.init.definitions);
19128 } else { 20412 } else {
19129 prev = stat; 20413 stat.init = prev;
19130 a.push(stat);
19131 } 20414 }
19132 return a; 20415 a.push(stat);
19133 }, []); 20416 prev = stat;
19134 } 20417 }
19135 function negate_iifes(statements, compressor) { 20418 else {
19136 statements.forEach(function(stat) { 20419 prev = stat;
19137 if (stat instanceof AST_SimpleStatement) { 20420 a.push(stat);
19138 stat.body = function transform(thing) { 20421 }
19139 return thing.transform(new TreeTransformer(function(node) { 20422 return a;
19140 if (node instanceof AST_Call && node.expression instanceof AST_Function) { 20423 }, []);
19141 return make_node(AST_UnaryPrefix, node, { 20424 };
19142 operator: "!", 20425
19143 expression: node 20426 function negate_iifes(statements, compressor) {
19144 }); 20427 statements.forEach(function(stat){
19145 } else if (node instanceof AST_Call) { 20428 if (stat instanceof AST_SimpleStatement) {
19146 node.expression = transform(node.expression); 20429 stat.body = (function transform(thing) {
19147 } else if (node instanceof AST_Seq) { 20430 return thing.transform(new TreeTransformer(function(node){
19148 node.car = transform(node.car); 20431 if (node instanceof AST_Call && node.expression instanceof AST_Function) {
19149 } else if (node instanceof AST_Conditional) { 20432 return make_node(AST_UnaryPrefix, node, {
19150 var expr = transform(node.condition); 20433 operator: "!",
19151 if (expr !== node.condition) { 20434 expression: node
19152 node.condition = expr; 20435 });
19153 var tmp = node.consequent; 20436 }
19154 node.consequent = node.alternative; 20437 else if (node instanceof AST_Call) {
19155 node.alternative = tmp; 20438 node.expression = transform(node.expression);
19156 } 20439 }
20440 else if (node instanceof AST_Seq) {
20441 node.car = transform(node.car);
20442 }
20443 else if (node instanceof AST_Conditional) {
20444 var expr = transform(node.condition);
20445 if (expr !== node.condition) {
20446 // it has been negated, reverse
20447 node.condition = expr;
20448 var tmp = node.consequent;
20449 node.consequent = node.alternative;
20450 node.alternative = tmp;
19157 } 20451 }
19158 return node; 20452 }
19159 })); 20453 return node;
19160 }(stat.body); 20454 }));
19161 } 20455 })(stat.body);
19162 }); 20456 }
19163 }
19164 }
19165 function extract_declarations_from_unreachable_code(compressor, stat, target) {
19166 compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
19167 stat.walk(new TreeWalker(function(node) {
19168 if (node instanceof AST_Definitions) {
19169 compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
19170 node.remove_initializers();
19171 target.push(node);
19172 return true;
19173 }
19174 if (node instanceof AST_Defun) {
19175 target.push(node);
19176 return true;
19177 }
19178 if (node instanceof AST_Scope) {
19179 return true;
19180 }
19181 }));
19182 }
19183 (function(def) {
19184 var unary_bool = [ "!", "delete" ];
19185 var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
19186 def(AST_Node, function() {
19187 return false;
19188 }); 20457 });
19189 def(AST_UnaryPrefix, function() { 20458 };
19190 return member(this.operator, unary_bool); 20459
20460 };
20461
20462 function extract_declarations_from_unreachable_code(compressor, stat, target) {
20463 compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
20464 stat.walk(new TreeWalker(function(node){
20465 if (node instanceof AST_Definitions) {
20466 compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
20467 node.remove_initializers();
20468 target.push(node);
20469 return true;
20470 }
20471 if (node instanceof AST_Defun) {
20472 target.push(node);
20473 return true;
20474 }
20475 if (node instanceof AST_Scope) {
20476 return true;
20477 }
20478 }));
20479 };
20480
20481 /* -----[ boolean/negation helpers ]----- */
20482
20483 // methods to determine whether an expression has a boolean result type
20484 (function (def){
20485 var unary_bool = [ "!", "delete" ];
20486 var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
20487 def(AST_Node, function(){ return false });
20488 def(AST_UnaryPrefix, function(){
20489 return member(this.operator, unary_bool);
20490 });
20491 def(AST_Binary, function(){
20492 return member(this.operator, binary_bool) ||
20493 ( (this.operator == "&&" || this.operator == "||") &&
20494 this.left.is_boolean() && this.right.is_boolean() );
20495 });
20496 def(AST_Conditional, function(){
20497 return this.consequent.is_boolean() && this.alternative.is_boolean();
20498 });
20499 def(AST_Assign, function(){
20500 return this.operator == "=" && this.right.is_boolean();
20501 });
20502 def(AST_Seq, function(){
20503 return this.cdr.is_boolean();
20504 });
20505 def(AST_True, function(){ return true });
20506 def(AST_False, function(){ return true });
20507 })(function(node, func){
20508 node.DEFMETHOD("is_boolean", func);
20509 });
20510
20511 // methods to determine if an expression has a string result type
20512 (function (def){
20513 def(AST_Node, function(){ return false });
20514 def(AST_String, function(){ return true });
20515 def(AST_UnaryPrefix, function(){
20516 return this.operator == "typeof";
20517 });
20518 def(AST_Binary, function(compressor){
20519 return this.operator == "+" &&
20520 (this.left.is_string(compressor) || this.right.is_string(compressor));
20521 });
20522 def(AST_Assign, function(compressor){
20523 return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
20524 });
20525 def(AST_Seq, function(compressor){
20526 return this.cdr.is_string(compressor);
20527 });
20528 def(AST_Conditional, function(compressor){
20529 return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
20530 });
20531 def(AST_Call, function(compressor){
20532 return compressor.option("unsafe")
20533 && this.expression instanceof AST_SymbolRef
20534 && this.expression.name == "String"
20535 && this.expression.undeclared();
20536 });
20537 })(function(node, func){
20538 node.DEFMETHOD("is_string", func);
20539 });
20540
20541 function best_of(ast1, ast2) {
20542 return ast1.print_to_string().length >
20543 ast2.print_to_string().length
20544 ? ast2 : ast1;
20545 };
20546
20547 // methods to evaluate a constant expression
20548 (function (def){
20549 // The evaluate method returns an array with one or two
20550 // elements. If the node has been successfully reduced to a
20551 // constant, then the second element tells us the value;
20552 // otherwise the second element is missing. The first element
20553 // of the array is always an AST_Node descendant; if
20554 // evaluation was successful it's a node that represents the
20555 // constant; otherwise it's the original or a replacement node.
20556 AST_Node.DEFMETHOD("evaluate", function(compressor){
20557 if (!compressor.option("evaluate")) return [ this ];
20558 try {
20559 var val = this._eval(compressor);
20560 return [ best_of(make_node_from_constant(compressor, val, this), this), val ];
20561 } catch(ex) {
20562 if (ex !== def) throw ex;
20563 return [ this ];
20564 }
20565 });
20566 def(AST_Statement, function(){
20567 throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
20568 });
20569 def(AST_Function, function(){
20570 // XXX: AST_Function inherits from AST_Scope, which itself
20571 // inherits from AST_Statement; however, an AST_Function
20572 // isn't really a statement. This could byte in other
20573 // places too. :-( Wish JS had multiple inheritance.
20574 throw def;
20575 });
20576 function ev(node, compressor) {
20577 if (!compressor) throw new Error("Compressor must be passed");
20578
20579 return node._eval(compressor);
20580 };
20581 def(AST_Node, function(){
20582 throw def; // not constant
20583 });
20584 def(AST_Constant, function(){
20585 return this.getValue();
20586 });
20587 def(AST_UnaryPrefix, function(compressor){
20588 var e = this.expression;
20589 switch (this.operator) {
20590 case "!": return !ev(e, compressor);
20591 case "typeof":
20592 // Function would be evaluated to an array and so typeof would
20593 // incorrectly return 'object'. Hence making is a special case.
20594 if (e instanceof AST_Function) return typeof function(){};
20595
20596 e = ev(e, compressor);
20597
20598 // typeof <RegExp> returns "object" or "function" on different platforms
20599 // so cannot evaluate reliably
20600 if (e instanceof RegExp) throw def;
20601
20602 return typeof e;
20603 case "void": return void ev(e, compressor);
20604 case "~": return ~ev(e, compressor);
20605 case "-":
20606 e = ev(e, compressor);
20607 if (e === 0) throw def;
20608 return -e;
20609 case "+": return +ev(e, compressor);
20610 }
20611 throw def;
20612 });
20613 def(AST_Binary, function(c){
20614 var left = this.left, right = this.right;
20615 switch (this.operator) {
20616 case "&&" : return ev(left, c) && ev(right, c);
20617 case "||" : return ev(left, c) || ev(right, c);
20618 case "|" : return ev(left, c) | ev(right, c);
20619 case "&" : return ev(left, c) & ev(right, c);
20620 case "^" : return ev(left, c) ^ ev(right, c);
20621 case "+" : return ev(left, c) + ev(right, c);
20622 case "*" : return ev(left, c) * ev(right, c);
20623 case "/" : return ev(left, c) / ev(right, c);
20624 case "%" : return ev(left, c) % ev(right, c);
20625 case "-" : return ev(left, c) - ev(right, c);
20626 case "<<" : return ev(left, c) << ev(right, c);
20627 case ">>" : return ev(left, c) >> ev(right, c);
20628 case ">>>" : return ev(left, c) >>> ev(right, c);
20629 case "==" : return ev(left, c) == ev(right, c);
20630 case "===" : return ev(left, c) === ev(right, c);
20631 case "!=" : return ev(left, c) != ev(right, c);
20632 case "!==" : return ev(left, c) !== ev(right, c);
20633 case "<" : return ev(left, c) < ev(right, c);
20634 case "<=" : return ev(left, c) <= ev(right, c);
20635 case ">" : return ev(left, c) > ev(right, c);
20636 case ">=" : return ev(left, c) >= ev(right, c);
20637 case "in" : return ev(left, c) in ev(right, c);
20638 case "instanceof" : return ev(left, c) instanceof ev(right, c);
20639 }
20640 throw def;
20641 });
20642 def(AST_Conditional, function(compressor){
20643 return ev(this.condition, compressor)
20644 ? ev(this.consequent, compressor)
20645 : ev(this.alternative, compressor);
20646 });
20647 def(AST_SymbolRef, function(compressor){
20648 var d = this.definition();
20649 if (d && d.constant && d.init) return ev(d.init, compressor);
20650 throw def;
20651 });
20652 })(function(node, func){
20653 node.DEFMETHOD("_eval", func);
20654 });
20655
20656 // method to negate an expression
20657 (function(def){
20658 function basic_negation(exp) {
20659 return make_node(AST_UnaryPrefix, exp, {
20660 operator: "!",
20661 expression: exp
19191 }); 20662 });
19192 def(AST_Binary, function() { 20663 };
19193 return member(this.operator, binary_bool) || (this.operator == "&&" || this.operator == "||") && this.left.is_boolean() && this.right.is_boolean(); 20664 def(AST_Node, function(){
19194 }); 20665 return basic_negation(this);
19195 def(AST_Conditional, function() {
19196 return this.consequent.is_boolean() && this.alternative.is_boolean();
19197 });
19198 def(AST_Assign, function() {
19199 return this.operator == "=" && this.right.is_boolean();
19200 });
19201 def(AST_Seq, function() {
19202 return this.cdr.is_boolean();
19203 });
19204 def(AST_True, function() {
19205 return true;
19206 });
19207 def(AST_False, function() {
19208 return true;
19209 });
19210 })(function(node, func) {
19211 node.DEFMETHOD("is_boolean", func);
19212 }); 20666 });
19213 (function(def) { 20667 def(AST_Statement, function(){
19214 def(AST_Node, function() { 20668 throw new Error("Cannot negate a statement");
19215 return false;
19216 });
19217 def(AST_String, function() {
19218 return true;
19219 });
19220 def(AST_UnaryPrefix, function() {
19221 return this.operator == "typeof";
19222 });
19223 def(AST_Binary, function(compressor) {
19224 return this.operator == "+" && (this.left.is_string(compressor) || this.right.is_string(compressor));
19225 });
19226 def(AST_Assign, function(compressor) {
19227 return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
19228 });
19229 def(AST_Seq, function(compressor) {
19230 return this.cdr.is_string(compressor);
19231 });
19232 def(AST_Conditional, function(compressor) {
19233 return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
19234 });
19235 def(AST_Call, function(compressor) {
19236 return compressor.option("unsafe") && this.expression instanceof AST_SymbolRef && this.expression.name == "String" && this.expression.undeclared();
19237 });
19238 })(function(node, func) {
19239 node.DEFMETHOD("is_string", func);
19240 }); 20669 });
19241 function best_of(ast1, ast2) { 20670 def(AST_Function, function(){
19242 return ast1.print_to_string().length > ast2.print_to_string().length ? ast2 : ast1; 20671 return basic_negation(this);
19243 }
19244 (function(def) {
19245 AST_Node.DEFMETHOD("evaluate", function(compressor) {
19246 if (!compressor.option("evaluate")) return [ this ];
19247 try {
19248 var val = this._eval(), ast = make_node_from_constant(compressor, val, this);
19249 return [ best_of(ast, this), val ];
19250 } catch (ex) {
19251 if (ex !== def) throw ex;
19252 return [ this ];
19253 }
19254 });
19255 def(AST_Statement, function() {
19256 throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
19257 });
19258 def(AST_Function, function() {
19259 throw def;
19260 });
19261 function ev(node) {
19262 return node._eval();
19263 }
19264 def(AST_Node, function() {
19265 throw def;
19266 });
19267 def(AST_Constant, function() {
19268 return this.getValue();
19269 });
19270 def(AST_UnaryPrefix, function() {
19271 var e = this.expression;
19272 switch (this.operator) {
19273 case "!":
19274 return !ev(e);
19275
19276 case "typeof":
19277 if (e instanceof AST_Function) return typeof function() {};
19278 e = ev(e);
19279 if (e instanceof RegExp) throw def;
19280 return typeof e;
19281
19282 case "void":
19283 return void ev(e);
19284
19285 case "~":
19286 return ~ev(e);
19287
19288 case "-":
19289 e = ev(e);
19290 if (e === 0) throw def;
19291 return -e;
19292
19293 case "+":
19294 return +ev(e);
19295 }
19296 throw def;
19297 });
19298 def(AST_Binary, function() {
19299 var left = this.left, right = this.right;
19300 switch (this.operator) {
19301 case "&&":
19302 return ev(left) && ev(right);
19303
19304 case "||":
19305 return ev(left) || ev(right);
19306
19307 case "|":
19308 return ev(left) | ev(right);
19309
19310 case "&":
19311 return ev(left) & ev(right);
19312
19313 case "^":
19314 return ev(left) ^ ev(right);
19315
19316 case "+":
19317 return ev(left) + ev(right);
19318
19319 case "*":
19320 return ev(left) * ev(right);
19321
19322 case "/":
19323 return ev(left) / ev(right);
19324
19325 case "%":
19326 return ev(left) % ev(right);
19327
19328 case "-":
19329 return ev(left) - ev(right);
19330
19331 case "<<":
19332 return ev(left) << ev(right);
19333
19334 case ">>":
19335 return ev(left) >> ev(right);
19336
19337 case ">>>":
19338 return ev(left) >>> ev(right);
19339
19340 case "==":
19341 return ev(left) == ev(right);
19342
19343 case "===":
19344 return ev(left) === ev(right);
19345
19346 case "!=":
19347 return ev(left) != ev(right);
19348
19349 case "!==":
19350 return ev(left) !== ev(right);
19351
19352 case "<":
19353 return ev(left) < ev(right);
19354
19355 case "<=":
19356 return ev(left) <= ev(right);
19357
19358 case ">":
19359 return ev(left) > ev(right);
19360
19361 case ">=":
19362 return ev(left) >= ev(right);
19363
19364 case "in":
19365 return ev(left) in ev(right);
19366
19367 case "instanceof":
19368 return ev(left) instanceof ev(right);
19369 }
19370 throw def;
19371 });
19372 def(AST_Conditional, function() {
19373 return ev(this.condition) ? ev(this.consequent) : ev(this.alternative);
19374 });
19375 def(AST_SymbolRef, function() {
19376 var d = this.definition();
19377 if (d && d.constant && d.init) return ev(d.init);
19378 throw def;
19379 });
19380 })(function(node, func) {
19381 node.DEFMETHOD("_eval", func);
19382 }); 20672 });
19383 (function(def) { 20673 def(AST_UnaryPrefix, function(){
19384 function basic_negation(exp) { 20674 if (this.operator == "!")
19385 return make_node(AST_UnaryPrefix, exp, { 20675 return this.expression;
19386 operator: "!", 20676 return basic_negation(this);
19387 expression: exp
19388 });
19389 }
19390 def(AST_Node, function() {
19391 return basic_negation(this);
19392 });
19393 def(AST_Statement, function() {
19394 throw new Error("Cannot negate a statement");
19395 });
19396 def(AST_Function, function() {
19397 return basic_negation(this);
19398 });
19399 def(AST_UnaryPrefix, function() {
19400 if (this.operator == "!") return this.expression;
19401 return basic_negation(this);
19402 });
19403 def(AST_Seq, function(compressor) {
19404 var self = this.clone();
19405 self.cdr = self.cdr.negate(compressor);
19406 return self;
19407 });
19408 def(AST_Conditional, function(compressor) {
19409 var self = this.clone();
19410 self.consequent = self.consequent.negate(compressor);
19411 self.alternative = self.alternative.negate(compressor);
19412 return best_of(basic_negation(this), self);
19413 });
19414 def(AST_Binary, function(compressor) {
19415 var self = this.clone(), op = this.operator;
19416 if (compressor.option("unsafe_comps")) {
19417 switch (op) {
19418 case "<=":
19419 self.operator = ">";
19420 return self;
19421
19422 case "<":
19423 self.operator = ">=";
19424 return self;
19425
19426 case ">=":
19427 self.operator = "<";
19428 return self;
19429
19430 case ">":
19431 self.operator = "<=";
19432 return self;
19433 }
19434 }
19435 switch (op) {
19436 case "==":
19437 self.operator = "!=";
19438 return self;
19439
19440 case "!=":
19441 self.operator = "==";
19442 return self;
19443
19444 case "===":
19445 self.operator = "!==";
19446 return self;
19447
19448 case "!==":
19449 self.operator = "===";
19450 return self;
19451
19452 case "&&":
19453 self.operator = "||";
19454 self.left = self.left.negate(compressor);
19455 self.right = self.right.negate(compressor);
19456 return best_of(basic_negation(this), self);
19457
19458 case "||":
19459 self.operator = "&&";
19460 self.left = self.left.negate(compressor);
19461 self.right = self.right.negate(compressor);
19462 return best_of(basic_negation(this), self);
19463 }
19464 return basic_negation(this);
19465 });
19466 })(function(node, func) {
19467 node.DEFMETHOD("negate", function(compressor) {
19468 return func.call(this, compressor);
19469 });
19470 }); 20677 });
19471 (function(def) { 20678 def(AST_Seq, function(compressor){
19472 def(AST_Node, function() { 20679 var self = this.clone();
19473 return true; 20680 self.cdr = self.cdr.negate(compressor);
19474 });
19475 def(AST_EmptyStatement, function() {
19476 return false;
19477 });
19478 def(AST_Constant, function() {
19479 return false;
19480 });
19481 def(AST_This, function() {
19482 return false;
19483 });
19484 def(AST_Block, function() {
19485 for (var i = this.body.length; --i >= 0; ) {
19486 if (this.body[i].has_side_effects()) return true;
19487 }
19488 return false;
19489 });
19490 def(AST_SimpleStatement, function() {
19491 return this.body.has_side_effects();
19492 });
19493 def(AST_Defun, function() {
19494 return true;
19495 });
19496 def(AST_Function, function() {
19497 return false;
19498 });
19499 def(AST_Binary, function() {
19500 return this.left.has_side_effects() || this.right.has_side_effects();
19501 });
19502 def(AST_Assign, function() {
19503 return true;
19504 });
19505 def(AST_Conditional, function() {
19506 return this.condition.has_side_effects() || this.consequent.has_side_effects() || this.alternative.has_side_effects();
19507 });
19508 def(AST_Unary, function() {
19509 return this.operator == "delete" || this.operator == "++" || this.operator == "--" || this.expression.has_side_effects();
19510 });
19511 def(AST_SymbolRef, function() {
19512 return false;
19513 });
19514 def(AST_Object, function() {
19515 for (var i = this.properties.length; --i >= 0; ) if (this.properties[i].has_side_effects()) return true;
19516 return false;
19517 });
19518 def(AST_ObjectProperty, function() {
19519 return this.value.has_side_effects();
19520 });
19521 def(AST_Array, function() {
19522 for (var i = this.elements.length; --i >= 0; ) if (this.elements[i].has_side_effects()) return true;
19523 return false;
19524 });
19525 def(AST_PropAccess, function() {
19526 return true;
19527 });
19528 def(AST_Seq, function() {
19529 return this.car.has_side_effects() || this.cdr.has_side_effects();
19530 });
19531 })(function(node, func) {
19532 node.DEFMETHOD("has_side_effects", func);
19533 });
19534 function aborts(thing) {
19535 return thing && thing.aborts();
19536 }
19537 (function(def) {
19538 def(AST_Statement, function() {
19539 return null;
19540 });
19541 def(AST_Jump, function() {
19542 return this;
19543 });
19544 function block_aborts() {
19545 var n = this.body.length;
19546 return n > 0 && aborts(this.body[n - 1]);
19547 }
19548 def(AST_BlockStatement, block_aborts);
19549 def(AST_SwitchBranch, block_aborts);
19550 def(AST_If, function() {
19551 return this.alternative && aborts(this.body) && aborts(this.alternative);
19552 });
19553 })(function(node, func) {
19554 node.DEFMETHOD("aborts", func);
19555 });
19556 OPT(AST_Directive, function(self, compressor) {
19557 if (self.scope.has_directive(self.value) !== self.scope) {
19558 return make_node(AST_EmptyStatement, self);
19559 }
19560 return self; 20681 return self;
19561 }); 20682 });
19562 OPT(AST_Debugger, function(self, compressor) { 20683 def(AST_Conditional, function(compressor){
19563 if (compressor.option("drop_debugger")) return make_node(AST_EmptyStatement, self); 20684 var self = this.clone();
19564 return self; 20685 self.consequent = self.consequent.negate(compressor);
20686 self.alternative = self.alternative.negate(compressor);
20687 return best_of(basic_negation(this), self);
19565 }); 20688 });
19566 OPT(AST_LabeledStatement, function(self, compressor) { 20689 def(AST_Binary, function(compressor){
19567 if (self.body instanceof AST_Break && compressor.loopcontrol_target(self.body.label) === self.body) { 20690 var self = this.clone(), op = this.operator;
19568 return make_node(AST_EmptyStatement, self); 20691 if (compressor.option("unsafe_comps")) {
19569 } 20692 switch (op) {
19570 return self.label.references.length == 0 ? self.body : self; 20693 case "<=" : self.operator = ">" ; return self;
20694 case "<" : self.operator = ">=" ; return self;
20695 case ">=" : self.operator = "<" ; return self;
20696 case ">" : self.operator = "<=" ; return self;
20697 }
20698 }
20699 switch (op) {
20700 case "==" : self.operator = "!="; return self;
20701 case "!=" : self.operator = "=="; return self;
20702 case "===": self.operator = "!=="; return self;
20703 case "!==": self.operator = "==="; return self;
20704 case "&&":
20705 self.operator = "||";
20706 self.left = self.left.negate(compressor);
20707 self.right = self.right.negate(compressor);
20708 return best_of(basic_negation(this), self);
20709 case "||":
20710 self.operator = "&&";
20711 self.left = self.left.negate(compressor);
20712 self.right = self.right.negate(compressor);
20713 return best_of(basic_negation(this), self);
20714 }
20715 return basic_negation(this);
19571 }); 20716 });
19572 OPT(AST_Block, function(self, compressor) { 20717 })(function(node, func){
19573 self.body = tighten_body(self.body, compressor); 20718 node.DEFMETHOD("negate", function(compressor){
19574 return self; 20719 return func.call(this, compressor);
19575 }); 20720 });
19576 OPT(AST_BlockStatement, function(self, compressor) { 20721 });
19577 self.body = tighten_body(self.body, compressor); 20722
19578 switch (self.body.length) { 20723 // determine if expression has side effects
19579 case 1: 20724 (function(def){
19580 return self.body[0]; 20725 def(AST_Node, function(compressor){ return true });
19581 20726
19582 case 0: 20727 def(AST_EmptyStatement, function(compressor){ return false });
19583 return make_node(AST_EmptyStatement, self); 20728 def(AST_Constant, function(compressor){ return false });
19584 } 20729 def(AST_This, function(compressor){ return false });
19585 return self; 20730
20731 def(AST_Call, function(compressor){
20732 var pure = compressor.option("pure_funcs");
20733 if (!pure) return true;
20734 return pure.indexOf(this.expression.print_to_string()) < 0;
19586 }); 20735 });
19587 AST_Scope.DEFMETHOD("drop_unused", function(compressor) { 20736
19588 var self = this; 20737 def(AST_Block, function(compressor){
19589 if (compressor.option("unused") && !(self instanceof AST_Toplevel) && !self.uses_eval) { 20738 for (var i = this.body.length; --i >= 0;) {
19590 var in_use = []; 20739 if (this.body[i].has_side_effects(compressor))
19591 var initializations = new Dictionary(); 20740 return true;
19592 var scope = this; 20741 }
19593 var tw = new TreeWalker(function(node, descend) { 20742 return false;
19594 if (node !== self) { 20743 });
19595 if (node instanceof AST_Defun) { 20744
19596 initializations.add(node.name.name, node); 20745 def(AST_SimpleStatement, function(compressor){
19597 return true; 20746 return this.body.has_side_effects(compressor);
19598 } 20747 });
19599 if (node instanceof AST_Definitions && scope === self) { 20748 def(AST_Defun, function(compressor){ return true });
19600 node.definitions.forEach(function(def) { 20749 def(AST_Function, function(compressor){ return false });
19601 if (def.value) { 20750 def(AST_Binary, function(compressor){
19602 initializations.add(def.name.name, def.value); 20751 return this.left.has_side_effects(compressor)
19603 if (def.value.has_side_effects()) { 20752 || this.right.has_side_effects(compressor);
19604 def.value.walk(tw); 20753 });
19605 } 20754 def(AST_Assign, function(compressor){ return true });
20755 def(AST_Conditional, function(compressor){
20756 return this.condition.has_side_effects(compressor)
20757 || this.consequent.has_side_effects(compressor)
20758 || this.alternative.has_side_effects(compressor);
20759 });
20760 def(AST_Unary, function(compressor){
20761 return this.operator == "delete"
20762 || this.operator == "++"
20763 || this.operator == "--"
20764 || this.expression.has_side_effects(compressor);
20765 });
20766 def(AST_SymbolRef, function(compressor){ return false });
20767 def(AST_Object, function(compressor){
20768 for (var i = this.properties.length; --i >= 0;)
20769 if (this.properties[i].has_side_effects(compressor))
20770 return true;
20771 return false;
20772 });
20773 def(AST_ObjectProperty, function(compressor){
20774 return this.value.has_side_effects(compressor);
20775 });
20776 def(AST_Array, function(compressor){
20777 for (var i = this.elements.length; --i >= 0;)
20778 if (this.elements[i].has_side_effects(compressor))
20779 return true;
20780 return false;
20781 });
20782 def(AST_Dot, function(compressor){
20783 if (!compressor.option("pure_getters")) return true;
20784 return this.expression.has_side_effects(compressor);
20785 });
20786 def(AST_Sub, function(compressor){
20787 if (!compressor.option("pure_getters")) return true;
20788 return this.expression.has_side_effects(compressor)
20789 || this.property.has_side_effects(compressor);
20790 });
20791 def(AST_PropAccess, function(compressor){
20792 return !compressor.option("pure_getters");
20793 });
20794 def(AST_Seq, function(compressor){
20795 return this.car.has_side_effects(compressor)
20796 || this.cdr.has_side_effects(compressor);
20797 });
20798 })(function(node, func){
20799 node.DEFMETHOD("has_side_effects", func);
20800 });
20801
20802 // tell me if a statement aborts
20803 function aborts(thing) {
20804 return thing && thing.aborts();
20805 };
20806 (function(def){
20807 def(AST_Statement, function(){ return null });
20808 def(AST_Jump, function(){ return this });
20809 function block_aborts(){
20810 var n = this.body.length;
20811 return n > 0 && aborts(this.body[n - 1]);
20812 };
20813 def(AST_BlockStatement, block_aborts);
20814 def(AST_SwitchBranch, block_aborts);
20815 def(AST_If, function(){
20816 return this.alternative && aborts(this.body) && aborts(this.alternative);
20817 });
20818 })(function(node, func){
20819 node.DEFMETHOD("aborts", func);
20820 });
20821
20822 /* -----[ optimizers ]----- */
20823
20824 OPT(AST_Directive, function(self, compressor){
20825 if (self.scope.has_directive(self.value) !== self.scope) {
20826 return make_node(AST_EmptyStatement, self);
20827 }
20828 return self;
20829 });
20830
20831 OPT(AST_Debugger, function(self, compressor){
20832 if (compressor.option("drop_debugger"))
20833 return make_node(AST_EmptyStatement, self);
20834 return self;
20835 });
20836
20837 OPT(AST_LabeledStatement, function(self, compressor){
20838 if (self.body instanceof AST_Break
20839 && compressor.loopcontrol_target(self.body.label) === self.body) {
20840 return make_node(AST_EmptyStatement, self);
20841 }
20842 return self.label.references.length == 0 ? self.body : self;
20843 });
20844
20845 OPT(AST_Block, function(self, compressor){
20846 self.body = tighten_body(self.body, compressor);
20847 return self;
20848 });
20849
20850 OPT(AST_BlockStatement, function(self, compressor){
20851 self.body = tighten_body(self.body, compressor);
20852 switch (self.body.length) {
20853 case 1: return self.body[0];
20854 case 0: return make_node(AST_EmptyStatement, self);
20855 }
20856 return self;
20857 });
20858
20859 AST_Scope.DEFMETHOD("drop_unused", function(compressor){
20860 var self = this;
20861 if (compressor.option("unused")
20862 && !(self instanceof AST_Toplevel)
20863 && !self.uses_eval
20864 ) {
20865 var in_use = [];
20866 var initializations = new Dictionary();
20867 // pass 1: find out which symbols are directly used in
20868 // this scope (not in nested scopes).
20869 var scope = this;
20870 var tw = new TreeWalker(function(node, descend){
20871 if (node !== self) {
20872 if (node instanceof AST_Defun) {
20873 initializations.add(node.name.name, node);
20874 return true; // don't go in nested scopes
20875 }
20876 if (node instanceof AST_Definitions && scope === self) {
20877 node.definitions.forEach(function(def){
20878 if (def.value) {
20879 initializations.add(def.name.name, def.value);
20880 if (def.value.has_side_effects(compressor)) {
20881 def.value.walk(tw);
19606 } 20882 }
19607 }); 20883 }
19608 return true; 20884 });
19609 } 20885 return true;
19610 if (node instanceof AST_SymbolRef) {
19611 push_uniq(in_use, node.definition());
19612 return true;
19613 }
19614 if (node instanceof AST_Scope) {
19615 var save_scope = scope;
19616 scope = node;
19617 descend();
19618 scope = save_scope;
19619 return true;
19620 }
19621 } 20886 }
20887 if (node instanceof AST_SymbolRef) {
20888 push_uniq(in_use, node.definition());
20889 return true;
20890 }
20891 if (node instanceof AST_Scope) {
20892 var save_scope = scope;
20893 scope = node;
20894 descend();
20895 scope = save_scope;
20896 return true;
20897 }
20898 }
20899 });
20900 self.walk(tw);
20901 // pass 2: for every used symbol we need to walk its
20902 // initialization code to figure out if it uses other
20903 // symbols (that may not be in_use).
20904 for (var i = 0; i < in_use.length; ++i) {
20905 in_use[i].orig.forEach(function(decl){
20906 // undeclared globals will be instanceof AST_SymbolRef
20907 var init = initializations.get(decl.name);
20908 if (init) init.forEach(function(init){
20909 var tw = new TreeWalker(function(node){
20910 if (node instanceof AST_SymbolRef) {
20911 push_uniq(in_use, node.definition());
20912 }
20913 });
20914 init.walk(tw);
20915 });
19622 }); 20916 });
19623 self.walk(tw); 20917 }
19624 for (var i = 0; i < in_use.length; ++i) { 20918 // pass 3: we should drop declarations not in_use
19625 in_use[i].orig.forEach(function(decl) { 20919 var tt = new TreeTransformer(
19626 var init = initializations.get(decl.name); 20920 function before(node, descend, in_list) {
19627 if (init) init.forEach(function(init) { 20921 if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
19628 var tw = new TreeWalker(function(node) { 20922 if (!compressor.option("keep_fargs")) {
19629 if (node instanceof AST_SymbolRef) { 20923 for (var a = node.argnames, i = a.length; --i >= 0;) {
19630 push_uniq(in_use, node.definition()); 20924 var sym = a[i];
20925 if (sym.unreferenced()) {
20926 a.pop();
20927 compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
20928 name : sym.name,
20929 file : sym.start.file,
20930 line : sym.start.line,
20931 col : sym.start.col
20932 });
19631 } 20933 }
19632 }); 20934 else break;
19633 init.walk(tw); 20935 }
19634 });
19635 });
19636 }
19637 var tt = new TreeTransformer(function before(node, descend, in_list) {
19638 if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
19639 for (var a = node.argnames, i = a.length; --i >= 0; ) {
19640 var sym = a[i];
19641 if (sym.unreferenced()) {
19642 a.pop();
19643 compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
19644 name: sym.name,
19645 file: sym.start.file,
19646 line: sym.start.line,
19647 col: sym.start.col
19648 });
19649 } else break;
19650 } 20936 }
19651 } 20937 }
19652 if (node instanceof AST_Defun && node !== self) { 20938 if (node instanceof AST_Defun && node !== self) {
19653 if (!member(node.name.definition(), in_use)) { 20939 if (!member(node.name.definition(), in_use)) {
19654 compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", { 20940 compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
19655 name: node.name.name, 20941 name : node.name.name,
19656 file: node.name.start.file, 20942 file : node.name.start.file,
19657 line: node.name.start.line, 20943 line : node.name.start.line,
19658 col: node.name.start.col 20944 col : node.name.start.col
19659 }); 20945 });
19660 return make_node(AST_EmptyStatement, node); 20946 return make_node(AST_EmptyStatement, node);
19661 } 20947 }
19662 return node; 20948 return node;
19663 } 20949 }
19664 if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) { 20950 if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
19665 var def = node.definitions.filter(function(def) { 20951 var def = node.definitions.filter(function(def){
19666 if (member(def.name.definition(), in_use)) return true; 20952 if (member(def.name.definition(), in_use)) return true;
19667 var w = { 20953 var w = {
19668 name: def.name.name, 20954 name : def.name.name,
19669 file: def.name.start.file, 20955 file : def.name.start.file,
19670 line: def.name.start.line, 20956 line : def.name.start.line,
19671 col: def.name.start.col 20957 col : def.name.start.col
19672 }; 20958 };
19673 if (def.value && def.value.has_side_effects()) { 20959 if (def.value && def.value.has_side_effects(compressor)) {
19674 def._unused_side_effects = true; 20960 def._unused_side_effects = true;
19675 compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w); 20961 compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
19676 return true; 20962 return true;
19677 } 20963 }
19678 compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w); 20964 compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);
19679 return false; 20965 return false;
19680 }); 20966 });
19681 def = mergeSort(def, function(a, b) { 20967 // place uninitialized names at the start
20968 def = mergeSort(def, function(a, b){
19682 if (!a.value && b.value) return -1; 20969 if (!a.value && b.value) return -1;
19683 if (!b.value && a.value) return 1; 20970 if (!b.value && a.value) return 1;
19684 return 0; 20971 return 0;
19685 }); 20972 });
20973 // for unused names whose initialization has
20974 // side effects, we can cascade the init. code
20975 // into the next one, or next statement.
19686 var side_effects = []; 20976 var side_effects = [];
19687 for (var i = 0; i < def.length; ) { 20977 for (var i = 0; i < def.length;) {
19688 var x = def[i]; 20978 var x = def[i];
19689 if (x._unused_side_effects) { 20979 if (x._unused_side_effects) {
19690 side_effects.push(x.value); 20980 side_effects.push(x.value);
19691 def.splice(i, 1); 20981 def.splice(i, 1);
19692 } else { 20982 } else {
19718 side_effects.body.unshift(node); 21008 side_effects.body.unshift(node);
19719 node = side_effects; 21009 node = side_effects;
19720 } 21010 }
19721 return node; 21011 return node;
19722 } 21012 }
19723 if (node instanceof AST_For && node.init instanceof AST_BlockStatement) { 21013 if (node instanceof AST_For) {
19724 descend(node, this); 21014 descend(node, this);
19725 var body = node.init.body.slice(0, -1); 21015
19726 node.init = node.init.body.slice(-1)[0].body; 21016 if (node.init instanceof AST_BlockStatement) {
19727 body.push(node); 21017 // certain combination of unused name + side effect leads to:
19728 return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { 21018 // https://github.com/mishoo/UglifyJS2/issues/44
19729 body: body 21019 // that's an invalid AST.
19730 }); 21020 // We fix it at this stage by moving the `var` outside the `for`.
21021
21022 var body = node.init.body.slice(0, -1);
21023 node.init = node.init.body.slice(-1)[0].body;
21024 body.push(node);
21025
21026 return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
21027 body: body
21028 });
21029 }
19731 } 21030 }
19732 if (node instanceof AST_Scope && node !== self) return node; 21031 if (node instanceof AST_Scope && node !== self)
19733 }); 21032 return node;
19734 self.transform(tt); 21033 }
19735 } 21034 );
19736 }); 21035 self.transform(tt);
19737 AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) { 21036 }
19738 var hoist_funs = compressor.option("hoist_funs"); 21037 });
19739 var hoist_vars = compressor.option("hoist_vars"); 21038
19740 var self = this; 21039 AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
19741 if (hoist_funs || hoist_vars) { 21040 var hoist_funs = compressor.option("hoist_funs");
19742 var dirs = []; 21041 var hoist_vars = compressor.option("hoist_vars");
19743 var hoisted = []; 21042 var self = this;
19744 var vars = new Dictionary(), vars_found = 0, var_decl = 0; 21043 if (hoist_funs || hoist_vars) {
19745 self.walk(new TreeWalker(function(node) { 21044 var dirs = [];
19746 if (node instanceof AST_Scope && node !== self) return true; 21045 var hoisted = [];
19747 if (node instanceof AST_Var) { 21046 var vars = new Dictionary(), vars_found = 0, var_decl = 0;
19748 ++var_decl; 21047 // let's count var_decl first, we seem to waste a lot of
19749 return true; 21048 // space if we hoist `var` when there's only one.
19750 } 21049 self.walk(new TreeWalker(function(node){
19751 })); 21050 if (node instanceof AST_Scope && node !== self)
19752 hoist_vars = hoist_vars && var_decl > 1; 21051 return true;
19753 var tt = new TreeTransformer(function before(node) { 21052 if (node instanceof AST_Var) {
21053 ++var_decl;
21054 return true;
21055 }
21056 }));
21057 hoist_vars = hoist_vars && var_decl > 1;
21058 var tt = new TreeTransformer(
21059 function before(node) {
19754 if (node !== self) { 21060 if (node !== self) {
19755 if (node instanceof AST_Directive) { 21061 if (node instanceof AST_Directive) {
19756 dirs.push(node); 21062 dirs.push(node);
19757 return make_node(AST_EmptyStatement, node); 21063 return make_node(AST_EmptyStatement, node);
19758 } 21064 }
19759 if (node instanceof AST_Defun && hoist_funs) { 21065 if (node instanceof AST_Defun && hoist_funs) {
19760 hoisted.push(node); 21066 hoisted.push(node);
19761 return make_node(AST_EmptyStatement, node); 21067 return make_node(AST_EmptyStatement, node);
19762 } 21068 }
19763 if (node instanceof AST_Var && hoist_vars) { 21069 if (node instanceof AST_Var && hoist_vars) {
19764 node.definitions.forEach(function(def) { 21070 node.definitions.forEach(function(def){
19765 vars.set(def.name.name, def); 21071 vars.set(def.name.name, def);
19766 ++vars_found; 21072 ++vars_found;
19767 }); 21073 });
19768 var seq = node.to_assignments(); 21074 var seq = node.to_assignments();
19769 var p = tt.parent(); 21075 var p = tt.parent();
19777 if (!seq) return make_node(AST_EmptyStatement, node); 21083 if (!seq) return make_node(AST_EmptyStatement, node);
19778 return make_node(AST_SimpleStatement, node, { 21084 return make_node(AST_SimpleStatement, node, {
19779 body: seq 21085 body: seq
19780 }); 21086 });
19781 } 21087 }
19782 if (node instanceof AST_Scope) return node; 21088 if (node instanceof AST_Scope)
21089 return node; // to avoid descending in nested scopes
21090 }
21091 }
21092 );
21093 self = self.transform(tt);
21094 if (vars_found > 0) {
21095 // collect only vars which don't show up in self's arguments list
21096 var defs = [];
21097 vars.each(function(def, name){
21098 if (self instanceof AST_Lambda
21099 && find_if(function(x){ return x.name == def.name.name },
21100 self.argnames)) {
21101 vars.del(name);
21102 } else {
21103 def = def.clone();
21104 def.value = null;
21105 defs.push(def);
21106 vars.set(name, def);
19783 } 21107 }
19784 }); 21108 });
19785 self = self.transform(tt); 21109 if (defs.length > 0) {
19786 if (vars_found > 0) { 21110 // try to merge in assignments
19787 var defs = []; 21111 for (var i = 0; i < self.body.length;) {
19788 vars.each(function(def, name) { 21112 if (self.body[i] instanceof AST_SimpleStatement) {
19789 if (self instanceof AST_Lambda && find_if(function(x) { 21113 var expr = self.body[i].body, sym, assign;
19790 return x.name == def.name.name; 21114 if (expr instanceof AST_Assign
19791 }, self.argnames)) { 21115 && expr.operator == "="
19792 vars.del(name); 21116 && (sym = expr.left) instanceof AST_Symbol
19793 } else { 21117 && vars.has(sym.name))
19794 def = def.clone(); 21118 {
19795 def.value = null; 21119 var def = vars.get(sym.name);
19796 defs.push(def); 21120 if (def.value) break;
19797 vars.set(name, def); 21121 def.value = expr.right;
19798 } 21122 remove(defs, def);
19799 }); 21123 defs.push(def);
19800 if (defs.length > 0) {
19801 for (var i = 0; i < self.body.length; ) {
19802 if (self.body[i] instanceof AST_SimpleStatement) {
19803 var expr = self.body[i].body, sym, assign;
19804 if (expr instanceof AST_Assign && expr.operator == "=" && (sym = expr.left) instanceof AST_Symbol && vars.has(sym.name)) {
19805 var def = vars.get(sym.name);
19806 if (def.value) break;
19807 def.value = expr.right;
19808 remove(defs, def);
19809 defs.push(def);
19810 self.body.splice(i, 1);
19811 continue;
19812 }
19813 if (expr instanceof AST_Seq && (assign = expr.car) instanceof AST_Assign && assign.operator == "=" && (sym = assign.left) instanceof AST_Symbol && vars.has(sym.name)) {
19814 var def = vars.get(sym.name);
19815 if (def.value) break;
19816 def.value = assign.right;
19817 remove(defs, def);
19818 defs.push(def);
19819 self.body[i].body = expr.cdr;
19820 continue;
19821 }
19822 }
19823 if (self.body[i] instanceof AST_EmptyStatement) {
19824 self.body.splice(i, 1); 21124 self.body.splice(i, 1);
19825 continue; 21125 continue;
19826 } 21126 }
19827 if (self.body[i] instanceof AST_BlockStatement) { 21127 if (expr instanceof AST_Seq
19828 var tmp = [ i, 1 ].concat(self.body[i].body); 21128 && (assign = expr.car) instanceof AST_Assign
19829 self.body.splice.apply(self.body, tmp); 21129 && assign.operator == "="
21130 && (sym = assign.left) instanceof AST_Symbol
21131 && vars.has(sym.name))
21132 {
21133 var def = vars.get(sym.name);
21134 if (def.value) break;
21135 def.value = assign.right;
21136 remove(defs, def);
21137 defs.push(def);
21138 self.body[i].body = expr.cdr;
19830 continue; 21139 continue;
19831 } 21140 }
19832 break;
19833 } 21141 }
19834 defs = make_node(AST_Var, self, { 21142 if (self.body[i] instanceof AST_EmptyStatement) {
19835 definitions: defs 21143 self.body.splice(i, 1);
19836 }); 21144 continue;
19837 hoisted.push(defs);
19838 }
19839 }
19840 self.body = dirs.concat(hoisted, self.body);
19841 }
19842 return self;
19843 });
19844 OPT(AST_SimpleStatement, function(self, compressor) {
19845 if (compressor.option("side_effects")) {
19846 if (!self.body.has_side_effects()) {
19847 compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
19848 return make_node(AST_EmptyStatement, self);
19849 }
19850 }
19851 return self;
19852 });
19853 OPT(AST_DWLoop, function(self, compressor) {
19854 var cond = self.condition.evaluate(compressor);
19855 self.condition = cond[0];
19856 if (!compressor.option("loops")) return self;
19857 if (cond.length > 1) {
19858 if (cond[1]) {
19859 return make_node(AST_For, self, {
19860 body: self.body
19861 });
19862 } else if (self instanceof AST_While) {
19863 if (compressor.option("dead_code")) {
19864 var a = [];
19865 extract_declarations_from_unreachable_code(compressor, self.body, a);
19866 return make_node(AST_BlockStatement, self, {
19867 body: a
19868 });
19869 }
19870 }
19871 }
19872 return self;
19873 });
19874 function if_break_in_loop(self, compressor) {
19875 function drop_it(rest) {
19876 rest = as_statement_array(rest);
19877 if (self.body instanceof AST_BlockStatement) {
19878 self.body = self.body.clone();
19879 self.body.body = rest.concat(self.body.body.slice(1));
19880 self.body = self.body.transform(compressor);
19881 } else {
19882 self.body = make_node(AST_BlockStatement, self.body, {
19883 body: rest
19884 }).transform(compressor);
19885 }
19886 if_break_in_loop(self, compressor);
19887 }
19888 var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
19889 if (first instanceof AST_If) {
19890 if (first.body instanceof AST_Break && compressor.loopcontrol_target(first.body.label) === self) {
19891 if (self.condition) {
19892 self.condition = make_node(AST_Binary, self.condition, {
19893 left: self.condition,
19894 operator: "&&",
19895 right: first.condition.negate(compressor)
19896 });
19897 } else {
19898 self.condition = first.condition.negate(compressor);
19899 }
19900 drop_it(first.alternative);
19901 } else if (first.alternative instanceof AST_Break && compressor.loopcontrol_target(first.alternative.label) === self) {
19902 if (self.condition) {
19903 self.condition = make_node(AST_Binary, self.condition, {
19904 left: self.condition,
19905 operator: "&&",
19906 right: first.condition
19907 });
19908 } else {
19909 self.condition = first.condition;
19910 }
19911 drop_it(first.body);
19912 }
19913 }
19914 }
19915 OPT(AST_While, function(self, compressor) {
19916 if (!compressor.option("loops")) return self;
19917 self = AST_DWLoop.prototype.optimize.call(self, compressor);
19918 if (self instanceof AST_While) {
19919 if_break_in_loop(self, compressor);
19920 self = make_node(AST_For, self, self).transform(compressor);
19921 }
19922 return self;
19923 });
19924 OPT(AST_For, function(self, compressor) {
19925 var cond = self.condition;
19926 if (cond) {
19927 cond = cond.evaluate(compressor);
19928 self.condition = cond[0];
19929 }
19930 if (!compressor.option("loops")) return self;
19931 if (cond) {
19932 if (cond.length > 1 && !cond[1]) {
19933 if (compressor.option("dead_code")) {
19934 var a = [];
19935 if (self.init instanceof AST_Statement) {
19936 a.push(self.init);
19937 } else if (self.init) {
19938 a.push(make_node(AST_SimpleStatement, self.init, {
19939 body: self.init
19940 }));
19941 } 21145 }
19942 extract_declarations_from_unreachable_code(compressor, self.body, a); 21146 if (self.body[i] instanceof AST_BlockStatement) {
19943 return make_node(AST_BlockStatement, self, { 21147 var tmp = [ i, 1 ].concat(self.body[i].body);
19944 body: a 21148 self.body.splice.apply(self.body, tmp);
19945 }); 21149 continue;
19946 }
19947 }
19948 }
19949 if_break_in_loop(self, compressor);
19950 return self;
19951 });
19952 OPT(AST_If, function(self, compressor) {
19953 if (!compressor.option("conditionals")) return self;
19954 var cond = self.condition.evaluate(compressor);
19955 self.condition = cond[0];
19956 if (cond.length > 1) {
19957 if (cond[1]) {
19958 compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
19959 if (compressor.option("dead_code")) {
19960 var a = [];
19961 if (self.alternative) {
19962 extract_declarations_from_unreachable_code(compressor, self.alternative, a);
19963 }
19964 a.push(self.body);
19965 return make_node(AST_BlockStatement, self, {
19966 body: a
19967 }).transform(compressor);
19968 }
19969 } else {
19970 compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
19971 if (compressor.option("dead_code")) {
19972 var a = [];
19973 extract_declarations_from_unreachable_code(compressor, self.body, a);
19974 if (self.alternative) a.push(self.alternative);
19975 return make_node(AST_BlockStatement, self, {
19976 body: a
19977 }).transform(compressor);
19978 }
19979 }
19980 }
19981 if (is_empty(self.alternative)) self.alternative = null;
19982 var negated = self.condition.negate(compressor);
19983 var negated_is_best = best_of(self.condition, negated) === negated;
19984 if (self.alternative && negated_is_best) {
19985 negated_is_best = false;
19986 self.condition = negated;
19987 var tmp = self.body;
19988 self.body = self.alternative || make_node(AST_EmptyStatement);
19989 self.alternative = tmp;
19990 }
19991 if (is_empty(self.body) && is_empty(self.alternative)) {
19992 return make_node(AST_SimpleStatement, self.condition, {
19993 body: self.condition
19994 }).transform(compressor);
19995 }
19996 if (self.body instanceof AST_SimpleStatement && self.alternative instanceof AST_SimpleStatement) {
19997 return make_node(AST_SimpleStatement, self, {
19998 body: make_node(AST_Conditional, self, {
19999 condition: self.condition,
20000 consequent: self.body.body,
20001 alternative: self.alternative.body
20002 })
20003 }).transform(compressor);
20004 }
20005 if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
20006 if (negated_is_best) return make_node(AST_SimpleStatement, self, {
20007 body: make_node(AST_Binary, self, {
20008 operator: "||",
20009 left: negated,
20010 right: self.body.body
20011 })
20012 }).transform(compressor);
20013 return make_node(AST_SimpleStatement, self, {
20014 body: make_node(AST_Binary, self, {
20015 operator: "&&",
20016 left: self.condition,
20017 right: self.body.body
20018 })
20019 }).transform(compressor);
20020 }
20021 if (self.body instanceof AST_EmptyStatement && self.alternative && self.alternative instanceof AST_SimpleStatement) {
20022 return make_node(AST_SimpleStatement, self, {
20023 body: make_node(AST_Binary, self, {
20024 operator: "||",
20025 left: self.condition,
20026 right: self.alternative.body
20027 })
20028 }).transform(compressor);
20029 }
20030 if (self.body instanceof AST_Exit && self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) {
20031 return make_node(self.body.CTOR, self, {
20032 value: make_node(AST_Conditional, self, {
20033 condition: self.condition,
20034 consequent: self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
20035 alternative: self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
20036 })
20037 }).transform(compressor);
20038 }
20039 if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) {
20040 self.condition = make_node(AST_Binary, self.condition, {
20041 operator: "&&",
20042 left: self.condition,
20043 right: self.body.condition
20044 }).transform(compressor);
20045 self.body = self.body.body;
20046 }
20047 if (aborts(self.body)) {
20048 if (self.alternative) {
20049 var alt = self.alternative;
20050 self.alternative = null;
20051 return make_node(AST_BlockStatement, self, {
20052 body: [ self, alt ]
20053 }).transform(compressor);
20054 }
20055 }
20056 if (aborts(self.alternative)) {
20057 var body = self.body;
20058 self.body = self.alternative;
20059 self.condition = negated_is_best ? negated : self.condition.negate(compressor);
20060 self.alternative = null;
20061 return make_node(AST_BlockStatement, self, {
20062 body: [ self, body ]
20063 }).transform(compressor);
20064 }
20065 return self;
20066 });
20067 OPT(AST_Switch, function(self, compressor) {
20068 if (self.body.length == 0 && compressor.option("conditionals")) {
20069 return make_node(AST_SimpleStatement, self, {
20070 body: self.expression
20071 }).transform(compressor);
20072 }
20073 for (;;) {
20074 var last_branch = self.body[self.body.length - 1];
20075 if (last_branch) {
20076 var stat = last_branch.body[last_branch.body.length - 1];
20077 if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self) last_branch.body.pop();
20078 if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
20079 self.body.pop();
20080 continue;
20081 }
20082 }
20083 break;
20084 }
20085 var exp = self.expression.evaluate(compressor);
20086 out: if (exp.length == 2) try {
20087 self.expression = exp[0];
20088 if (!compressor.option("dead_code")) break out;
20089 var value = exp[1];
20090 var in_if = false;
20091 var in_block = false;
20092 var started = false;
20093 var stopped = false;
20094 var ruined = false;
20095 var tt = new TreeTransformer(function(node, descend, in_list) {
20096 if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
20097 return node;
20098 } else if (node instanceof AST_Switch && node === self) {
20099 node = node.clone();
20100 descend(node, this);
20101 return ruined ? node : make_node(AST_BlockStatement, node, {
20102 body: node.body.reduce(function(a, branch) {
20103 return a.concat(branch.body);
20104 }, [])
20105 }).transform(compressor);
20106 } else if (node instanceof AST_If || node instanceof AST_Try) {
20107 var save = in_if;
20108 in_if = !in_block;
20109 descend(node, this);
20110 in_if = save;
20111 return node;
20112 } else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
20113 var save = in_block;
20114 in_block = true;
20115 descend(node, this);
20116 in_block = save;
20117 return node;
20118 } else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
20119 if (in_if) {
20120 ruined = true;
20121 return node;
20122 }
20123 if (in_block) return node;
20124 stopped = true;
20125 return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
20126 } else if (node instanceof AST_SwitchBranch && this.parent() === self) {
20127 if (stopped) return MAP.skip;
20128 if (node instanceof AST_Case) {
20129 var exp = node.expression.evaluate(compressor);
20130 if (exp.length < 2) {
20131 throw self;
20132 }
20133 if (exp[1] === value || started) {
20134 started = true;
20135 if (aborts(node)) stopped = true;
20136 descend(node, this);
20137 return node;
20138 }
20139 return MAP.skip;
20140 }
20141 descend(node, this);
20142 return node;
20143 }
20144 });
20145 tt.stack = compressor.stack.slice();
20146 self = self.transform(tt);
20147 } catch (ex) {
20148 if (ex !== self) throw ex;
20149 }
20150 return self;
20151 });
20152 OPT(AST_Case, function(self, compressor) {
20153 self.body = tighten_body(self.body, compressor);
20154 return self;
20155 });
20156 OPT(AST_Try, function(self, compressor) {
20157 self.body = tighten_body(self.body, compressor);
20158 return self;
20159 });
20160 AST_Definitions.DEFMETHOD("remove_initializers", function() {
20161 this.definitions.forEach(function(def) {
20162 def.value = null;
20163 });
20164 });
20165 AST_Definitions.DEFMETHOD("to_assignments", function() {
20166 var assignments = this.definitions.reduce(function(a, def) {
20167 if (def.value) {
20168 var name = make_node(AST_SymbolRef, def.name, def.name);
20169 a.push(make_node(AST_Assign, def, {
20170 operator: "=",
20171 left: name,
20172 right: def.value
20173 }));
20174 }
20175 return a;
20176 }, []);
20177 if (assignments.length == 0) return null;
20178 return AST_Seq.from_array(assignments);
20179 });
20180 OPT(AST_Definitions, function(self, compressor) {
20181 if (self.definitions.length == 0) return make_node(AST_EmptyStatement, self);
20182 return self;
20183 });
20184 OPT(AST_Function, function(self, compressor) {
20185 self = AST_Lambda.prototype.optimize.call(self, compressor);
20186 if (compressor.option("unused")) {
20187 if (self.name && self.name.unreferenced()) {
20188 self.name = null;
20189 }
20190 }
20191 return self;
20192 });
20193 OPT(AST_Call, function(self, compressor) {
20194 if (compressor.option("unsafe")) {
20195 var exp = self.expression;
20196 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
20197 switch (exp.name) {
20198 case "Array":
20199 if (self.args.length != 1) {
20200 return make_node(AST_Array, self, {
20201 elements: self.args
20202 });
20203 }
20204 break;
20205
20206 case "Object":
20207 if (self.args.length == 0) {
20208 return make_node(AST_Object, self, {
20209 properties: []
20210 });
20211 }
20212 break;
20213
20214 case "String":
20215 if (self.args.length == 0) return make_node(AST_String, self, {
20216 value: ""
20217 });
20218 return make_node(AST_Binary, self, {
20219 left: self.args[0],
20220 operator: "+",
20221 right: make_node(AST_String, self, {
20222 value: ""
20223 })
20224 });
20225
20226 case "Function":
20227 if (all(self.args, function(x) {
20228 return x instanceof AST_String;
20229 })) {
20230 try {
20231 var code = "(function(" + self.args.slice(0, -1).map(function(arg) {
20232 return arg.value;
20233 }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
20234 var ast = parse(code);
20235 ast.figure_out_scope();
20236 var comp = new Compressor(compressor.options);
20237 ast = ast.transform(comp);
20238 ast.figure_out_scope();
20239 ast.mangle_names();
20240 var fun = ast.body[0].body.expression;
20241 var args = fun.argnames.map(function(arg, i) {
20242 return make_node(AST_String, self.args[i], {
20243 value: arg.print_to_string()
20244 });
20245 });
20246 var code = OutputStream();
20247 AST_BlockStatement.prototype._codegen.call(fun, fun, code);
20248 code = code.toString().replace(/^\{|\}$/g, "");
20249 args.push(make_node(AST_String, self.args[self.args.length - 1], {
20250 value: code
20251 }));
20252 self.args = args;
20253 return self;
20254 } catch (ex) {
20255 if (ex instanceof JS_Parse_Error) {
20256 compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
20257 compressor.warn(ex.toString());
20258 } else {
20259 console.log(ex);
20260 }
20261 }
20262 } 21150 }
20263 break; 21151 break;
20264 } 21152 }
20265 } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { 21153 defs = make_node(AST_Var, self, {
20266 return make_node(AST_Binary, self, { 21154 definitions: defs
20267 left: make_node(AST_String, self, { 21155 });
20268 value: "" 21156 hoisted.push(defs);
20269 }), 21157 };
20270 operator: "+", 21158 }
20271 right: exp.expression 21159 self.body = dirs.concat(hoisted, self.body);
21160 }
21161 return self;
21162 });
21163
21164 OPT(AST_SimpleStatement, function(self, compressor){
21165 if (compressor.option("side_effects")) {
21166 if (!self.body.has_side_effects(compressor)) {
21167 compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
21168 return make_node(AST_EmptyStatement, self);
21169 }
21170 }
21171 return self;
21172 });
21173
21174 OPT(AST_DWLoop, function(self, compressor){
21175 var cond = self.condition.evaluate(compressor);
21176 self.condition = cond[0];
21177 if (!compressor.option("loops")) return self;
21178 if (cond.length > 1) {
21179 if (cond[1]) {
21180 return make_node(AST_For, self, {
21181 body: self.body
21182 });
21183 } else if (self instanceof AST_While) {
21184 if (compressor.option("dead_code")) {
21185 var a = [];
21186 extract_declarations_from_unreachable_code(compressor, self.body, a);
21187 return make_node(AST_BlockStatement, self, { body: a });
21188 }
21189 }
21190 }
21191 return self;
21192 });
21193
21194 function if_break_in_loop(self, compressor) {
21195 function drop_it(rest) {
21196 rest = as_statement_array(rest);
21197 if (self.body instanceof AST_BlockStatement) {
21198 self.body = self.body.clone();
21199 self.body.body = rest.concat(self.body.body.slice(1));
21200 self.body = self.body.transform(compressor);
21201 } else {
21202 self.body = make_node(AST_BlockStatement, self.body, {
21203 body: rest
21204 }).transform(compressor);
21205 }
21206 if_break_in_loop(self, compressor);
21207 }
21208 var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
21209 if (first instanceof AST_If) {
21210 if (first.body instanceof AST_Break
21211 && compressor.loopcontrol_target(first.body.label) === self) {
21212 if (self.condition) {
21213 self.condition = make_node(AST_Binary, self.condition, {
21214 left: self.condition,
21215 operator: "&&",
21216 right: first.condition.negate(compressor),
21217 });
21218 } else {
21219 self.condition = first.condition.negate(compressor);
21220 }
21221 drop_it(first.alternative);
21222 }
21223 else if (first.alternative instanceof AST_Break
21224 && compressor.loopcontrol_target(first.alternative.label) === self) {
21225 if (self.condition) {
21226 self.condition = make_node(AST_Binary, self.condition, {
21227 left: self.condition,
21228 operator: "&&",
21229 right: first.condition,
21230 });
21231 } else {
21232 self.condition = first.condition;
21233 }
21234 drop_it(first.body);
21235 }
21236 }
21237 };
21238
21239 OPT(AST_While, function(self, compressor) {
21240 if (!compressor.option("loops")) return self;
21241 self = AST_DWLoop.prototype.optimize.call(self, compressor);
21242 if (self instanceof AST_While) {
21243 if_break_in_loop(self, compressor);
21244 self = make_node(AST_For, self, self).transform(compressor);
21245 }
21246 return self;
21247 });
21248
21249 OPT(AST_For, function(self, compressor){
21250 var cond = self.condition;
21251 if (cond) {
21252 cond = cond.evaluate(compressor);
21253 self.condition = cond[0];
21254 }
21255 if (!compressor.option("loops")) return self;
21256 if (cond) {
21257 if (cond.length > 1 && !cond[1]) {
21258 if (compressor.option("dead_code")) {
21259 var a = [];
21260 if (self.init instanceof AST_Statement) {
21261 a.push(self.init);
21262 }
21263 else if (self.init) {
21264 a.push(make_node(AST_SimpleStatement, self.init, {
21265 body: self.init
21266 }));
21267 }
21268 extract_declarations_from_unreachable_code(compressor, self.body, a);
21269 return make_node(AST_BlockStatement, self, { body: a });
21270 }
21271 }
21272 }
21273 if_break_in_loop(self, compressor);
21274 return self;
21275 });
21276
21277 OPT(AST_If, function(self, compressor){
21278 if (!compressor.option("conditionals")) return self;
21279 // if condition can be statically determined, warn and drop
21280 // one of the blocks. note, statically determined implies
21281 // “has no side effects”; also it doesn't work for cases like
21282 // `x && true`, though it probably should.
21283 var cond = self.condition.evaluate(compressor);
21284 self.condition = cond[0];
21285 if (cond.length > 1) {
21286 if (cond[1]) {
21287 compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
21288 if (compressor.option("dead_code")) {
21289 var a = [];
21290 if (self.alternative) {
21291 extract_declarations_from_unreachable_code(compressor, self.alternative, a);
21292 }
21293 a.push(self.body);
21294 return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
21295 }
21296 } else {
21297 compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
21298 if (compressor.option("dead_code")) {
21299 var a = [];
21300 extract_declarations_from_unreachable_code(compressor, self.body, a);
21301 if (self.alternative) a.push(self.alternative);
21302 return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
21303 }
21304 }
21305 }
21306 if (is_empty(self.alternative)) self.alternative = null;
21307 var negated = self.condition.negate(compressor);
21308 var negated_is_best = best_of(self.condition, negated) === negated;
21309 if (self.alternative && negated_is_best) {
21310 negated_is_best = false; // because we already do the switch here.
21311 self.condition = negated;
21312 var tmp = self.body;
21313 self.body = self.alternative || make_node(AST_EmptyStatement);
21314 self.alternative = tmp;
21315 }
21316 if (is_empty(self.body) && is_empty(self.alternative)) {
21317 return make_node(AST_SimpleStatement, self.condition, {
21318 body: self.condition
21319 }).transform(compressor);
21320 }
21321 if (self.body instanceof AST_SimpleStatement
21322 && self.alternative instanceof AST_SimpleStatement) {
21323 return make_node(AST_SimpleStatement, self, {
21324 body: make_node(AST_Conditional, self, {
21325 condition : self.condition,
21326 consequent : self.body.body,
21327 alternative : self.alternative.body
21328 })
21329 }).transform(compressor);
21330 }
21331 if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
21332 if (negated_is_best) return make_node(AST_SimpleStatement, self, {
21333 body: make_node(AST_Binary, self, {
21334 operator : "||",
21335 left : negated,
21336 right : self.body.body
21337 })
21338 }).transform(compressor);
21339 return make_node(AST_SimpleStatement, self, {
21340 body: make_node(AST_Binary, self, {
21341 operator : "&&",
21342 left : self.condition,
21343 right : self.body.body
21344 })
21345 }).transform(compressor);
21346 }
21347 if (self.body instanceof AST_EmptyStatement
21348 && self.alternative
21349 && self.alternative instanceof AST_SimpleStatement) {
21350 return make_node(AST_SimpleStatement, self, {
21351 body: make_node(AST_Binary, self, {
21352 operator : "||",
21353 left : self.condition,
21354 right : self.alternative.body
21355 })
21356 }).transform(compressor);
21357 }
21358 if (self.body instanceof AST_Exit
21359 && self.alternative instanceof AST_Exit
21360 && self.body.TYPE == self.alternative.TYPE) {
21361 return make_node(self.body.CTOR, self, {
21362 value: make_node(AST_Conditional, self, {
21363 condition : self.condition,
21364 consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
21365 alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
21366 })
21367 }).transform(compressor);
21368 }
21369 if (self.body instanceof AST_If
21370 && !self.body.alternative
21371 && !self.alternative) {
21372 self.condition = make_node(AST_Binary, self.condition, {
21373 operator: "&&",
21374 left: self.condition,
21375 right: self.body.condition
21376 }).transform(compressor);
21377 self.body = self.body.body;
21378 }
21379 if (aborts(self.body)) {
21380 if (self.alternative) {
21381 var alt = self.alternative;
21382 self.alternative = null;
21383 return make_node(AST_BlockStatement, self, {
21384 body: [ self, alt ]
21385 }).transform(compressor);
21386 }
21387 }
21388 if (aborts(self.alternative)) {
21389 var body = self.body;
21390 self.body = self.alternative;
21391 self.condition = negated_is_best ? negated : self.condition.negate(compressor);
21392 self.alternative = null;
21393 return make_node(AST_BlockStatement, self, {
21394 body: [ self, body ]
21395 }).transform(compressor);
21396 }
21397 return self;
21398 });
21399
21400 OPT(AST_Switch, function(self, compressor){
21401 if (self.body.length == 0 && compressor.option("conditionals")) {
21402 return make_node(AST_SimpleStatement, self, {
21403 body: self.expression
21404 }).transform(compressor);
21405 }
21406 for(;;) {
21407 var last_branch = self.body[self.body.length - 1];
21408 if (last_branch) {
21409 var stat = last_branch.body[last_branch.body.length - 1]; // last statement
21410 if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
21411 last_branch.body.pop();
21412 if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
21413 self.body.pop();
21414 continue;
21415 }
21416 }
21417 break;
21418 }
21419 var exp = self.expression.evaluate(compressor);
21420 out: if (exp.length == 2) try {
21421 // constant expression
21422 self.expression = exp[0];
21423 if (!compressor.option("dead_code")) break out;
21424 var value = exp[1];
21425 var in_if = false;
21426 var in_block = false;
21427 var started = false;
21428 var stopped = false;
21429 var ruined = false;
21430 var tt = new TreeTransformer(function(node, descend, in_list){
21431 if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
21432 // no need to descend these node types
21433 return node;
21434 }
21435 else if (node instanceof AST_Switch && node === self) {
21436 node = node.clone();
21437 descend(node, this);
21438 return ruined ? node : make_node(AST_BlockStatement, node, {
21439 body: node.body.reduce(function(a, branch){
21440 return a.concat(branch.body);
21441 }, [])
20272 }).transform(compressor); 21442 }).transform(compressor);
20273 } 21443 }
20274 } 21444 else if (node instanceof AST_If || node instanceof AST_Try) {
20275 if (compressor.option("side_effects")) { 21445 var save = in_if;
20276 if (self.expression instanceof AST_Function && self.args.length == 0 && !AST_Block.prototype.has_side_effects.call(self.expression)) { 21446 in_if = !in_block;
20277 return make_node(AST_Undefined, self).transform(compressor); 21447 descend(node, this);
20278 } 21448 in_if = save;
20279 } 21449 return node;
20280 return self; 21450 }
20281 }); 21451 else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
20282 OPT(AST_New, function(self, compressor) { 21452 var save = in_block;
20283 if (compressor.option("unsafe")) { 21453 in_block = true;
20284 var exp = self.expression; 21454 descend(node, this);
20285 if (exp instanceof AST_SymbolRef && exp.undeclared()) { 21455 in_block = save;
20286 switch (exp.name) { 21456 return node;
20287 case "Object": 21457 }
20288 case "RegExp": 21458 else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
20289 case "Function": 21459 if (in_if) {
20290 case "Error": 21460 ruined = true;
20291 case "Array": 21461 return node;
20292 return make_node(AST_Call, self, self).transform(compressor);
20293 } 21462 }
20294 } 21463 if (in_block) return node;
20295 } 21464 stopped = true;
20296 return self; 21465 return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
20297 }); 21466 }
20298 OPT(AST_Seq, function(self, compressor) { 21467 else if (node instanceof AST_SwitchBranch && this.parent() === self) {
20299 if (!compressor.option("side_effects")) return self; 21468 if (stopped) return MAP.skip;
20300 if (!self.car.has_side_effects()) { 21469 if (node instanceof AST_Case) {
20301 var p; 21470 var exp = node.expression.evaluate(compressor);
20302 if (!(self.cdr instanceof AST_SymbolRef && self.cdr.name == "eval" && self.cdr.undeclared() && (p = compressor.parent()) instanceof AST_Call && p.expression === self)) { 21471 if (exp.length < 2) {
20303 return self.cdr; 21472 // got a case with non-constant expression, baling out
20304 } 21473 throw self;
20305 } 21474 }
20306 if (compressor.option("cascade")) { 21475 if (exp[1] === value || started) {
20307 if (self.car instanceof AST_Assign && !self.car.left.has_side_effects() && self.car.left.equivalent_to(self.cdr)) { 21476 started = true;
20308 return self.car; 21477 if (aborts(node)) stopped = true;
20309 } 21478 descend(node, this);
20310 if (!self.car.has_side_effects() && !self.cdr.has_side_effects() && self.car.equivalent_to(self.cdr)) { 21479 return node;
20311 return self.car; 21480 }
20312 } 21481 return MAP.skip;
20313 } 21482 }
20314 return self; 21483 descend(node, this);
20315 }); 21484 return node;
20316 AST_Unary.DEFMETHOD("lift_sequences", function(compressor) { 21485 }
20317 if (compressor.option("sequences")) { 21486 });
20318 if (this.expression instanceof AST_Seq) { 21487 tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
20319 var seq = this.expression; 21488 self = self.transform(tt);
20320 var x = seq.to_array(); 21489 } catch(ex) {
20321 this.expression = x.pop(); 21490 if (ex !== self) throw ex;
20322 x.push(this); 21491 }
20323 seq = AST_Seq.from_array(x).transform(compressor); 21492 return self;
20324 return seq; 21493 });
20325 } 21494
20326 } 21495 OPT(AST_Case, function(self, compressor){
20327 return this; 21496 self.body = tighten_body(self.body, compressor);
20328 }); 21497 return self;
20329 OPT(AST_UnaryPostfix, function(self, compressor) { 21498 });
20330 return self.lift_sequences(compressor); 21499
20331 }); 21500 OPT(AST_Try, function(self, compressor){
20332 OPT(AST_UnaryPrefix, function(self, compressor) { 21501 self.body = tighten_body(self.body, compressor);
20333 self = self.lift_sequences(compressor); 21502 return self;
20334 var e = self.expression; 21503 });
20335 if (compressor.option("booleans") && compressor.in_boolean_context()) { 21504
20336 switch (self.operator) { 21505 AST_Definitions.DEFMETHOD("remove_initializers", function(){
20337 case "!": 21506 this.definitions.forEach(function(def){ def.value = null });
20338 if (e instanceof AST_UnaryPrefix && e.operator == "!") { 21507 });
20339 return e.expression; 21508
21509 AST_Definitions.DEFMETHOD("to_assignments", function(){
21510 var assignments = this.definitions.reduce(function(a, def){
21511 if (def.value) {
21512 var name = make_node(AST_SymbolRef, def.name, def.name);
21513 a.push(make_node(AST_Assign, def, {
21514 operator : "=",
21515 left : name,
21516 right : def.value
21517 }));
21518 }
21519 return a;
21520 }, []);
21521 if (assignments.length == 0) return null;
21522 return AST_Seq.from_array(assignments);
21523 });
21524
21525 OPT(AST_Definitions, function(self, compressor){
21526 if (self.definitions.length == 0)
21527 return make_node(AST_EmptyStatement, self);
21528 return self;
21529 });
21530
21531 OPT(AST_Function, function(self, compressor){
21532 self = AST_Lambda.prototype.optimize.call(self, compressor);
21533 if (compressor.option("unused")) {
21534 if (self.name && self.name.unreferenced()) {
21535 self.name = null;
21536 }
21537 }
21538 return self;
21539 });
21540
21541 OPT(AST_Call, function(self, compressor){
21542 if (compressor.option("unsafe")) {
21543 var exp = self.expression;
21544 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
21545 switch (exp.name) {
21546 case "Array":
21547 if (self.args.length != 1) {
21548 return make_node(AST_Array, self, {
21549 elements: self.args
21550 }).transform(compressor);
20340 } 21551 }
20341 break; 21552 break;
20342 21553 case "Object":
20343 case "typeof": 21554 if (self.args.length == 0) {
20344 compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start); 21555 return make_node(AST_Object, self, {
20345 return make_node(AST_True, self); 21556 properties: []
20346 } 21557 });
20347 if (e instanceof AST_Binary && self.operator == "!") { 21558 }
20348 self = best_of(self, e.negate(compressor)); 21559 break;
20349 } 21560 case "String":
20350 } 21561 if (self.args.length == 0) return make_node(AST_String, self, {
20351 return self.evaluate(compressor)[0]; 21562 value: ""
20352 }); 21563 });
20353 AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { 21564 if (self.args.length <= 1) return make_node(AST_Binary, self, {
20354 if (compressor.option("sequences")) { 21565 left: self.args[0],
20355 if (this.left instanceof AST_Seq) { 21566 operator: "+",
20356 var seq = this.left; 21567 right: make_node(AST_String, self, { value: "" })
20357 var x = seq.to_array(); 21568 }).transform(compressor);
20358 this.left = x.pop(); 21569 break;
20359 x.push(this); 21570 case "Number":
20360 seq = AST_Seq.from_array(x).transform(compressor); 21571 if (self.args.length == 0) return make_node(AST_Number, self, {
20361 return seq; 21572 value: 0
20362 } 21573 });
20363 if (this.right instanceof AST_Seq && !(this.operator == "||" || this.operator == "&&") && !this.left.has_side_effects()) { 21574 if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
20364 var seq = this.right; 21575 expression: self.args[0],
20365 var x = seq.to_array(); 21576 operator: "+"
20366 this.right = x.pop(); 21577 }).transform(compressor);
20367 x.push(this); 21578 case "Boolean":
20368 seq = AST_Seq.from_array(x).transform(compressor); 21579 if (self.args.length == 0) return make_node(AST_False, self);
20369 return seq; 21580 if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
20370 } 21581 expression: make_node(AST_UnaryPrefix, null, {
20371 } 21582 expression: self.args[0],
20372 return this; 21583 operator: "!"
20373 }); 21584 }),
20374 var commutativeOperators = makePredicate("== === != !== * & | ^"); 21585 operator: "!"
20375 OPT(AST_Binary, function(self, compressor) { 21586 }).transform(compressor);
20376 var reverse = compressor.has_directive("use asm") ? noop : function(op, force) { 21587 break;
20377 if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) { 21588 case "Function":
21589 if (all(self.args, function(x){ return x instanceof AST_String })) {
21590 // quite a corner-case, but we can handle it:
21591 // https://github.com/mishoo/UglifyJS2/issues/203
21592 // if the code argument is a constant, then we can minify it.
21593 try {
21594 var code = "(function(" + self.args.slice(0, -1).map(function(arg){
21595 return arg.value;
21596 }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
21597 var ast = parse(code);
21598 ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
21599 var comp = new Compressor(compressor.options);
21600 ast = ast.transform(comp);
21601 ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
21602 ast.mangle_names();
21603 var fun;
21604 try {
21605 ast.walk(new TreeWalker(function(node){
21606 if (node instanceof AST_Lambda) {
21607 fun = node;
21608 throw ast;
21609 }
21610 }));
21611 } catch(ex) {
21612 if (ex !== ast) throw ex;
21613 };
21614 var args = fun.argnames.map(function(arg, i){
21615 return make_node(AST_String, self.args[i], {
21616 value: arg.print_to_string()
21617 });
21618 });
21619 var code = OutputStream();
21620 AST_BlockStatement.prototype._codegen.call(fun, fun, code);
21621 code = code.toString().replace(/^\{|\}$/g, "");
21622 args.push(make_node(AST_String, self.args[self.args.length - 1], {
21623 value: code
21624 }));
21625 self.args = args;
21626 return self;
21627 } catch(ex) {
21628 if (ex instanceof JS_Parse_Error) {
21629 compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
21630 compressor.warn(ex.toString());
21631 } else {
21632 console.log(ex);
21633 throw ex;
21634 }
21635 }
21636 }
21637 break;
21638 }
21639 }
21640 else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
21641 return make_node(AST_Binary, self, {
21642 left: make_node(AST_String, self, { value: "" }),
21643 operator: "+",
21644 right: exp.expression
21645 }).transform(compressor);
21646 }
21647 else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
21648 var separator = self.args.length == 0 ? "," : self.args[0].evaluate(compressor)[1];
21649 if (separator == null) break EXIT; // not a constant
21650 var elements = exp.expression.elements.reduce(function(a, el){
21651 el = el.evaluate(compressor);
21652 if (a.length == 0 || el.length == 1) {
21653 a.push(el);
21654 } else {
21655 var last = a[a.length - 1];
21656 if (last.length == 2) {
21657 // it's a constant
21658 var val = "" + last[1] + separator + el[1];
21659 a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ];
21660 } else {
21661 a.push(el);
21662 }
21663 }
21664 return a;
21665 }, []);
21666 if (elements.length == 0) return make_node(AST_String, self, { value: "" });
21667 if (elements.length == 1) return elements[0][0];
21668 if (separator == "") {
21669 var first;
21670 if (elements[0][0] instanceof AST_String
21671 || elements[1][0] instanceof AST_String) {
21672 first = elements.shift()[0];
21673 } else {
21674 first = make_node(AST_String, self, { value: "" });
21675 }
21676 return elements.reduce(function(prev, el){
21677 return make_node(AST_Binary, el[0], {
21678 operator : "+",
21679 left : prev,
21680 right : el[0],
21681 });
21682 }, first).transform(compressor);
21683 }
21684 // need this awkward cloning to not affect original element
21685 // best_of will decide which one to get through.
21686 var node = self.clone();
21687 node.expression = node.expression.clone();
21688 node.expression.expression = node.expression.expression.clone();
21689 node.expression.expression.elements = elements.map(function(el){
21690 return el[0];
21691 });
21692 return best_of(self, node);
21693 }
21694 }
21695 if (compressor.option("side_effects")) {
21696 if (self.expression instanceof AST_Function
21697 && self.args.length == 0
21698 && !AST_Block.prototype.has_side_effects.call(self.expression, compressor)) {
21699 return make_node(AST_Undefined, self).transform(compressor);
21700 }
21701 }
21702 if (compressor.option("drop_console")) {
21703 if (self.expression instanceof AST_PropAccess &&
21704 self.expression.expression instanceof AST_SymbolRef &&
21705 self.expression.expression.name == "console" &&
21706 self.expression.expression.undeclared()) {
21707 return make_node(AST_Undefined, self).transform(compressor);
21708 }
21709 }
21710 return self.evaluate(compressor)[0];
21711 });
21712
21713 OPT(AST_New, function(self, compressor){
21714 if (compressor.option("unsafe")) {
21715 var exp = self.expression;
21716 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
21717 switch (exp.name) {
21718 case "Object":
21719 case "RegExp":
21720 case "Function":
21721 case "Error":
21722 case "Array":
21723 return make_node(AST_Call, self, self).transform(compressor);
21724 }
21725 }
21726 }
21727 return self;
21728 });
21729
21730 OPT(AST_Seq, function(self, compressor){
21731 if (!compressor.option("side_effects"))
21732 return self;
21733 if (!self.car.has_side_effects(compressor)) {
21734 // we shouldn't compress (1,eval)(something) to
21735 // eval(something) because that changes the meaning of
21736 // eval (becomes lexical instead of global).
21737 var p;
21738 if (!(self.cdr instanceof AST_SymbolRef
21739 && self.cdr.name == "eval"
21740 && self.cdr.undeclared()
21741 && (p = compressor.parent()) instanceof AST_Call
21742 && p.expression === self)) {
21743 return self.cdr;
21744 }
21745 }
21746 if (compressor.option("cascade")) {
21747 if (self.car instanceof AST_Assign
21748 && !self.car.left.has_side_effects(compressor)) {
21749 if (self.car.left.equivalent_to(self.cdr)) {
21750 return self.car;
21751 }
21752 if (self.cdr instanceof AST_Call
21753 && self.cdr.expression.equivalent_to(self.car.left)) {
21754 self.cdr.expression = self.car;
21755 return self.cdr;
21756 }
21757 }
21758 if (!self.car.has_side_effects(compressor)
21759 && !self.cdr.has_side_effects(compressor)
21760 && self.car.equivalent_to(self.cdr)) {
21761 return self.car;
21762 }
21763 }
21764 if (self.cdr instanceof AST_UnaryPrefix
21765 && self.cdr.operator == "void"
21766 && !self.cdr.expression.has_side_effects(compressor)) {
21767 self.cdr.operator = self.car;
21768 return self.cdr;
21769 }
21770 if (self.cdr instanceof AST_Undefined) {
21771 return make_node(AST_UnaryPrefix, self, {
21772 operator : "void",
21773 expression : self.car
21774 });
21775 }
21776 return self;
21777 });
21778
21779 AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
21780 if (compressor.option("sequences")) {
21781 if (this.expression instanceof AST_Seq) {
21782 var seq = this.expression;
21783 var x = seq.to_array();
21784 this.expression = x.pop();
21785 x.push(this);
21786 seq = AST_Seq.from_array(x).transform(compressor);
21787 return seq;
21788 }
21789 }
21790 return this;
21791 });
21792
21793 OPT(AST_UnaryPostfix, function(self, compressor){
21794 return self.lift_sequences(compressor);
21795 });
21796
21797 OPT(AST_UnaryPrefix, function(self, compressor){
21798 self = self.lift_sequences(compressor);
21799 var e = self.expression;
21800 if (compressor.option("booleans") && compressor.in_boolean_context()) {
21801 switch (self.operator) {
21802 case "!":
21803 if (e instanceof AST_UnaryPrefix && e.operator == "!") {
21804 // !!foo ==> foo, if we're in boolean context
21805 return e.expression;
21806 }
21807 break;
21808 case "typeof":
21809 // typeof always returns a non-empty string, thus it's
21810 // always true in booleans
21811 compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
21812 return make_node(AST_True, self);
21813 }
21814 if (e instanceof AST_Binary && self.operator == "!") {
21815 self = best_of(self, e.negate(compressor));
21816 }
21817 }
21818 return self.evaluate(compressor)[0];
21819 });
21820
21821 function has_side_effects_or_prop_access(node, compressor) {
21822 var save_pure_getters = compressor.option("pure_getters");
21823 compressor.options.pure_getters = false;
21824 var ret = node.has_side_effects(compressor);
21825 compressor.options.pure_getters = save_pure_getters;
21826 return ret;
21827 }
21828
21829 AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
21830 if (compressor.option("sequences")) {
21831 if (this.left instanceof AST_Seq) {
21832 var seq = this.left;
21833 var x = seq.to_array();
21834 this.left = x.pop();
21835 x.push(this);
21836 seq = AST_Seq.from_array(x).transform(compressor);
21837 return seq;
21838 }
21839 if (this.right instanceof AST_Seq
21840 && this instanceof AST_Assign
21841 && !has_side_effects_or_prop_access(this.left, compressor)) {
21842 var seq = this.right;
21843 var x = seq.to_array();
21844 this.right = x.pop();
21845 x.push(this);
21846 seq = AST_Seq.from_array(x).transform(compressor);
21847 return seq;
21848 }
21849 }
21850 return this;
21851 });
21852
21853 var commutativeOperators = makePredicate("== === != !== * & | ^");
21854
21855 OPT(AST_Binary, function(self, compressor){
21856 var reverse = compressor.has_directive("use asm") ? noop
21857 : function(op, force) {
21858 if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
20378 if (op) self.operator = op; 21859 if (op) self.operator = op;
20379 var tmp = self.left; 21860 var tmp = self.left;
20380 self.left = self.right; 21861 self.left = self.right;
20381 self.right = tmp; 21862 self.right = tmp;
20382 } 21863 }
20383 }; 21864 };
20384 if (commutativeOperators(self.operator)) { 21865 if (commutativeOperators(self.operator)) {
20385 if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { 21866 if (self.right instanceof AST_Constant
21867 && !(self.left instanceof AST_Constant)) {
21868 // if right is a constant, whatever side effects the
21869 // left side might have could not influence the
21870 // result. hence, force switch.
21871
21872 if (!(self.left instanceof AST_Binary
21873 && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
20386 reverse(null, true); 21874 reverse(null, true);
20387 } 21875 }
20388 } 21876 }
20389 self = self.lift_sequences(compressor); 21877 if (/^[!=]==?$/.test(self.operator)) {
20390 if (compressor.option("comparisons")) switch (self.operator) { 21878 if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) {
20391 case "===": 21879 if (self.right.consequent instanceof AST_SymbolRef
20392 case "!==": 21880 && self.right.consequent.definition() === self.left.definition()) {
20393 if (self.left.is_string(compressor) && self.right.is_string(compressor) || self.left.is_boolean() && self.right.is_boolean()) { 21881 if (/^==/.test(self.operator)) return self.right.condition;
20394 self.operator = self.operator.substr(0, 2); 21882 if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor);
20395 }
20396
20397 case "==":
20398 case "!=":
20399 if (self.left instanceof AST_String && self.left.value == "undefined" && self.right instanceof AST_UnaryPrefix && self.right.operator == "typeof" && compressor.option("unsafe")) {
20400 if (!(self.right.expression instanceof AST_SymbolRef) || !self.right.expression.undeclared()) {
20401 self.right = self.right.expression;
20402 self.left = make_node(AST_Undefined, self.left).optimize(compressor);
20403 if (self.operator.length == 2) self.operator += "=";
20404 } 21883 }
20405 } 21884 if (self.right.alternative instanceof AST_SymbolRef
20406 break; 21885 && self.right.alternative.definition() === self.left.definition()) {
20407 } 21886 if (/^==/.test(self.operator)) return self.right.condition.negate(compressor);
20408 if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) { 21887 if (/^!=/.test(self.operator)) return self.right.condition;
20409 case "&&": 21888 }
20410 var ll = self.left.evaluate(compressor); 21889 }
20411 var rr = self.right.evaluate(compressor); 21890 if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) {
20412 if (ll.length > 1 && !ll[1] || rr.length > 1 && !rr[1]) { 21891 if (self.left.consequent instanceof AST_SymbolRef
20413 compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); 21892 && self.left.consequent.definition() === self.right.definition()) {
20414 return make_node(AST_False, self); 21893 if (/^==/.test(self.operator)) return self.left.condition;
20415 } 21894 if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor);
20416 if (ll.length > 1 && ll[1]) { 21895 }
20417 return rr[0]; 21896 if (self.left.alternative instanceof AST_SymbolRef
20418 } 21897 && self.left.alternative.definition() === self.right.definition()) {
20419 if (rr.length > 1 && rr[1]) { 21898 if (/^==/.test(self.operator)) return self.left.condition.negate(compressor);
20420 return ll[0]; 21899 if (/^!=/.test(self.operator)) return self.left.condition;
20421 } 21900 }
20422 break; 21901 }
20423 21902 }
20424 case "||": 21903 }
20425 var ll = self.left.evaluate(compressor); 21904 self = self.lift_sequences(compressor);
20426 var rr = self.right.evaluate(compressor); 21905 if (compressor.option("comparisons")) switch (self.operator) {
20427 if (ll.length > 1 && ll[1] || rr.length > 1 && rr[1]) { 21906 case "===":
20428 compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); 21907 case "!==":
20429 return make_node(AST_True, self); 21908 if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
20430 } 21909 (self.left.is_boolean() && self.right.is_boolean())) {
20431 if (ll.length > 1 && !ll[1]) { 21910 self.operator = self.operator.substr(0, 2);
20432 return rr[0]; 21911 }
20433 } 21912 // XXX: intentionally falling down to the next case
20434 if (rr.length > 1 && !rr[1]) { 21913 case "==":
20435 return ll[0]; 21914 case "!=":
20436 } 21915 if (self.left instanceof AST_String
20437 break; 21916 && self.left.value == "undefined"
20438 21917 && self.right instanceof AST_UnaryPrefix
20439 case "+": 21918 && self.right.operator == "typeof"
20440 var ll = self.left.evaluate(compressor); 21919 && compressor.option("unsafe")) {
20441 var rr = self.right.evaluate(compressor); 21920 if (!(self.right.expression instanceof AST_SymbolRef)
20442 if (ll.length > 1 && ll[0] instanceof AST_String && ll[1] || rr.length > 1 && rr[0] instanceof AST_String && rr[1]) { 21921 || !self.right.expression.undeclared()) {
20443 compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); 21922 self.right = self.right.expression;
20444 return make_node(AST_True, self); 21923 self.left = make_node(AST_Undefined, self.left).optimize(compressor);
20445 } 21924 if (self.operator.length == 2) self.operator += "=";
20446 break; 21925 }
20447 } 21926 }
20448 var exp = self.evaluate(compressor); 21927 break;
20449 if (exp.length > 1) { 21928 }
20450 if (best_of(exp[0], self) !== self) return exp[0]; 21929 if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
20451 } 21930 case "&&":
20452 if (compressor.option("comparisons")) { 21931 var ll = self.left.evaluate(compressor);
20453 if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) { 21932 var rr = self.right.evaluate(compressor);
20454 var negated = make_node(AST_UnaryPrefix, self, { 21933 if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
20455 operator: "!", 21934 compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
20456 expression: self.negate(compressor) 21935 return make_node(AST_False, self);
21936 }
21937 if (ll.length > 1 && ll[1]) {
21938 return rr[0];
21939 }
21940 if (rr.length > 1 && rr[1]) {
21941 return ll[0];
21942 }
21943 break;
21944 case "||":
21945 var ll = self.left.evaluate(compressor);
21946 var rr = self.right.evaluate(compressor);
21947 if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
21948 compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
21949 return make_node(AST_True, self);
21950 }
21951 if (ll.length > 1 && !ll[1]) {
21952 return rr[0];
21953 }
21954 if (rr.length > 1 && !rr[1]) {
21955 return ll[0];
21956 }
21957 break;
21958 case "+":
21959 var ll = self.left.evaluate(compressor);
21960 var rr = self.right.evaluate(compressor);
21961 if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
21962 (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
21963 compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
21964 return make_node(AST_True, self);
21965 }
21966 break;
21967 }
21968 if (compressor.option("comparisons")) {
21969 if (!(compressor.parent() instanceof AST_Binary)
21970 || compressor.parent() instanceof AST_Assign) {
21971 var negated = make_node(AST_UnaryPrefix, self, {
21972 operator: "!",
21973 expression: self.negate(compressor)
21974 });
21975 self = best_of(self, negated);
21976 }
21977 switch (self.operator) {
21978 case "<": reverse(">"); break;
21979 case "<=": reverse(">="); break;
21980 }
21981 }
21982 if (self.operator == "+" && self.right instanceof AST_String
21983 && self.right.getValue() === "" && self.left instanceof AST_Binary
21984 && self.left.operator == "+" && self.left.is_string(compressor)) {
21985 return self.left;
21986 }
21987 if (compressor.option("evaluate")) {
21988 if (self.operator == "+") {
21989 if (self.left instanceof AST_Constant
21990 && self.right instanceof AST_Binary
21991 && self.right.operator == "+"
21992 && self.right.left instanceof AST_Constant
21993 && self.right.is_string(compressor)) {
21994 self = make_node(AST_Binary, self, {
21995 operator: "+",
21996 left: make_node(AST_String, null, {
21997 value: "" + self.left.getValue() + self.right.left.getValue(),
21998 start: self.left.start,
21999 end: self.right.left.end
22000 }),
22001 right: self.right.right
20457 }); 22002 });
20458 self = best_of(self, negated); 22003 }
20459 } 22004 if (self.right instanceof AST_Constant
20460 switch (self.operator) { 22005 && self.left instanceof AST_Binary
20461 case "<": 22006 && self.left.operator == "+"
20462 reverse(">"); 22007 && self.left.right instanceof AST_Constant
20463 break; 22008 && self.left.is_string(compressor)) {
20464 22009 self = make_node(AST_Binary, self, {
20465 case "<=": 22010 operator: "+",
20466 reverse(">="); 22011 left: self.left.left,
20467 break; 22012 right: make_node(AST_String, null, {
20468 } 22013 value: "" + self.left.right.getValue() + self.right.getValue(),
20469 } 22014 start: self.left.right.start,
20470 if (self.operator == "+" && self.right instanceof AST_String && self.right.getValue() === "" && self.left instanceof AST_Binary && self.left.operator == "+" && self.left.is_string(compressor)) { 22015 end: self.right.end
20471 return self.left; 22016 })
20472 } 22017 });
20473 return self; 22018 }
22019 if (self.left instanceof AST_Binary
22020 && self.left.operator == "+"
22021 && self.left.is_string(compressor)
22022 && self.left.right instanceof AST_Constant
22023 && self.right instanceof AST_Binary
22024 && self.right.operator == "+"
22025 && self.right.left instanceof AST_Constant
22026 && self.right.is_string(compressor)) {
22027 self = make_node(AST_Binary, self, {
22028 operator: "+",
22029 left: make_node(AST_Binary, self.left, {
22030 operator: "+",
22031 left: self.left.left,
22032 right: make_node(AST_String, null, {
22033 value: "" + self.left.right.getValue() + self.right.left.getValue(),
22034 start: self.left.right.start,
22035 end: self.right.left.end
22036 })
22037 }),
22038 right: self.right.right
22039 });
22040 }
22041 }
22042 }
22043 // x * (y * z) ==> x * y * z
22044 if (self.right instanceof AST_Binary
22045 && self.right.operator == self.operator
22046 && (self.operator == "*" || self.operator == "&&" || self.operator == "||"))
22047 {
22048 self.left = make_node(AST_Binary, self.left, {
22049 operator : self.operator,
22050 left : self.left,
22051 right : self.right.left
22052 });
22053 self.right = self.right.right;
22054 return self.transform(compressor);
22055 }
22056 return self.evaluate(compressor)[0];
22057 });
22058
22059 OPT(AST_SymbolRef, function(self, compressor){
22060 if (self.undeclared()) {
22061 var defines = compressor.option("global_defs");
22062 if (defines && defines.hasOwnProperty(self.name)) {
22063 return make_node_from_constant(compressor, defines[self.name], self);
22064 }
22065 switch (self.name) {
22066 case "undefined":
22067 return make_node(AST_Undefined, self);
22068 case "NaN":
22069 return make_node(AST_NaN, self);
22070 case "Infinity":
22071 return make_node(AST_Infinity, self);
22072 }
22073 }
22074 return self;
22075 });
22076
22077 OPT(AST_Undefined, function(self, compressor){
22078 if (compressor.option("unsafe")) {
22079 var scope = compressor.find_parent(AST_Scope);
22080 var undef = scope.find_variable("undefined");
22081 if (undef) {
22082 var ref = make_node(AST_SymbolRef, self, {
22083 name : "undefined",
22084 scope : scope,
22085 thedef : undef
22086 });
22087 ref.reference();
22088 return ref;
22089 }
22090 }
22091 return self;
22092 });
22093
22094 var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
22095 OPT(AST_Assign, function(self, compressor){
22096 self = self.lift_sequences(compressor);
22097 if (self.operator == "="
22098 && self.left instanceof AST_SymbolRef
22099 && self.right instanceof AST_Binary
22100 && self.right.left instanceof AST_SymbolRef
22101 && self.right.left.name == self.left.name
22102 && member(self.right.operator, ASSIGN_OPS)) {
22103 self.operator = self.right.operator + "=";
22104 self.right = self.right.right;
22105 }
22106 return self;
22107 });
22108
22109 OPT(AST_Conditional, function(self, compressor){
22110 if (!compressor.option("conditionals")) return self;
22111 if (self.condition instanceof AST_Seq) {
22112 var car = self.condition.car;
22113 self.condition = self.condition.cdr;
22114 return AST_Seq.cons(car, self);
22115 }
22116 var cond = self.condition.evaluate(compressor);
22117 if (cond.length > 1) {
22118 if (cond[1]) {
22119 compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
22120 return self.consequent;
22121 } else {
22122 compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
22123 return self.alternative;
22124 }
22125 }
22126 var negated = cond[0].negate(compressor);
22127 if (best_of(cond[0], negated) === negated) {
22128 self = make_node(AST_Conditional, self, {
22129 condition: negated,
22130 consequent: self.alternative,
22131 alternative: self.consequent
22132 });
22133 }
22134 var consequent = self.consequent;
22135 var alternative = self.alternative;
22136 if (consequent instanceof AST_Assign
22137 && alternative instanceof AST_Assign
22138 && consequent.operator == alternative.operator
22139 && consequent.left.equivalent_to(alternative.left)
22140 ) {
22141 /*
22142 * Stuff like this:
22143 * if (foo) exp = something; else exp = something_else;
22144 * ==>
22145 * exp = foo ? something : something_else;
22146 */
22147 return make_node(AST_Assign, self, {
22148 operator: consequent.operator,
22149 left: consequent.left,
22150 right: make_node(AST_Conditional, self, {
22151 condition: self.condition,
22152 consequent: consequent.right,
22153 alternative: alternative.right
22154 })
22155 });
22156 }
22157 if (consequent instanceof AST_Call
22158 && alternative.TYPE === consequent.TYPE
22159 && consequent.args.length == alternative.args.length
22160 && consequent.expression.equivalent_to(alternative.expression)) {
22161 if (consequent.args.length == 0) {
22162 return make_node(AST_Seq, self, {
22163 car: self.condition,
22164 cdr: consequent
22165 });
22166 }
22167 if (consequent.args.length == 1) {
22168 consequent.args[0] = make_node(AST_Conditional, self, {
22169 condition: self.condition,
22170 consequent: consequent.args[0],
22171 alternative: alternative.args[0]
22172 });
22173 return consequent;
22174 }
22175 }
22176 // x?y?z:a:a --> x&&y?z:a
22177 if (consequent instanceof AST_Conditional
22178 && consequent.alternative.equivalent_to(alternative)) {
22179 return make_node(AST_Conditional, self, {
22180 condition: make_node(AST_Binary, self, {
22181 left: self.condition,
22182 operator: "&&",
22183 right: consequent.condition
22184 }),
22185 consequent: consequent.consequent,
22186 alternative: alternative
22187 });
22188 }
22189 return self;
22190 });
22191
22192 OPT(AST_Boolean, function(self, compressor){
22193 if (compressor.option("booleans")) {
22194 var p = compressor.parent();
22195 if (p instanceof AST_Binary && (p.operator == "=="
22196 || p.operator == "!=")) {
22197 compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
22198 operator : p.operator,
22199 value : self.value,
22200 file : p.start.file,
22201 line : p.start.line,
22202 col : p.start.col,
22203 });
22204 return make_node(AST_Number, self, {
22205 value: +self.value
22206 });
22207 }
22208 return make_node(AST_UnaryPrefix, self, {
22209 operator: "!",
22210 expression: make_node(AST_Number, self, {
22211 value: 1 - self.value
22212 })
22213 });
22214 }
22215 return self;
22216 });
22217
22218 OPT(AST_Sub, function(self, compressor){
22219 var prop = self.property;
22220 if (prop instanceof AST_String && compressor.option("properties")) {
22221 prop = prop.getValue();
22222 if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) {
22223 return make_node(AST_Dot, self, {
22224 expression : self.expression,
22225 property : prop
22226 });
22227 }
22228 var v = parseFloat(prop);
22229 if (!isNaN(v) && v.toString() == prop) {
22230 self.property = make_node(AST_Number, self.property, {
22231 value: v
22232 });
22233 }
22234 }
22235 return self;
22236 });
22237
22238 function literals_in_boolean_context(self, compressor) {
22239 if (compressor.option("booleans") && compressor.in_boolean_context()) {
22240 return make_node(AST_True, self);
22241 }
22242 return self;
22243 };
22244 OPT(AST_Array, literals_in_boolean_context);
22245 OPT(AST_Object, literals_in_boolean_context);
22246 OPT(AST_RegExp, literals_in_boolean_context);
22247
22248 })();
22249
22250 /***********************************************************************
22251
22252 A JavaScript tokenizer / parser / beautifier / compressor.
22253 https://github.com/mishoo/UglifyJS2
22254
22255 -------------------------------- (C) ---------------------------------
22256
22257 Author: Mihai Bazon
22258 <mihai.bazon@gmail.com>
22259 http://mihai.bazon.net/blog
22260
22261 Distributed under the BSD license:
22262
22263 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
22264
22265 Redistribution and use in source and binary forms, with or without
22266 modification, are permitted provided that the following conditions
22267 are met:
22268
22269 * Redistributions of source code must retain the above
22270 copyright notice, this list of conditions and the following
22271 disclaimer.
22272
22273 * Redistributions in binary form must reproduce the above
22274 copyright notice, this list of conditions and the following
22275 disclaimer in the documentation and/or other materials
22276 provided with the distribution.
22277
22278 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
22279 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22280 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22281 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22282 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22283 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22284 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22285 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22286 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22287 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
22288 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22289 SUCH DAMAGE.
22290
22291 ***********************************************************************/
22292
22293 "use strict";
22294
22295 // a small wrapper around fitzgen's source-map library
22296 function SourceMap(options) {
22297 options = defaults(options, {
22298 file : null,
22299 root : null,
22300 orig : null,
22301
22302 orig_line_diff : 0,
22303 dest_line_diff : 0,
22304 });
22305 var generator = new MOZ_SourceMap.SourceMapGenerator({
22306 file : options.file,
22307 sourceRoot : options.root
22308 });
22309 var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
22310 function add(source, gen_line, gen_col, orig_line, orig_col, name) {
22311 if (orig_map) {
22312 var info = orig_map.originalPositionFor({
22313 line: orig_line,
22314 column: orig_col
22315 });
22316 if (info.source === null) {
22317 return;
22318 }
22319 source = info.source;
22320 orig_line = info.line;
22321 orig_col = info.column;
22322 name = info.name;
22323 }
22324 generator.addMapping({
22325 generated : { line: gen_line + options.dest_line_diff, column: gen_col },
22326 original : { line: orig_line + options.orig_line_diff, column: orig_col },
22327 source : source,
22328 name : name
20474 }); 22329 });
20475 OPT(AST_SymbolRef, function(self, compressor) { 22330 };
20476 if (self.undeclared()) { 22331 return {
20477 var defines = compressor.option("global_defs"); 22332 add : add,
20478 if (defines && defines.hasOwnProperty(self.name)) { 22333 get : function() { return generator },
20479 return make_node_from_constant(compressor, defines[self.name], self); 22334 toString : function() { return generator.toString() }
20480 } 22335 };
20481 switch (self.name) { 22336 };
20482 case "undefined": 22337
20483 return make_node(AST_Undefined, self); 22338 /***********************************************************************
20484 22339
20485 case "NaN": 22340 A JavaScript tokenizer / parser / beautifier / compressor.
20486 return make_node(AST_NaN, self); 22341 https://github.com/mishoo/UglifyJS2
20487 22342
20488 case "Infinity": 22343 -------------------------------- (C) ---------------------------------
20489 return make_node(AST_Infinity, self); 22344
20490 } 22345 Author: Mihai Bazon
20491 } 22346 <mihai.bazon@gmail.com>
20492 return self; 22347 http://mihai.bazon.net/blog
22348
22349 Distributed under the BSD license:
22350
22351 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
22352
22353 Redistribution and use in source and binary forms, with or without
22354 modification, are permitted provided that the following conditions
22355 are met:
22356
22357 * Redistributions of source code must retain the above
22358 copyright notice, this list of conditions and the following
22359 disclaimer.
22360
22361 * Redistributions in binary form must reproduce the above
22362 copyright notice, this list of conditions and the following
22363 disclaimer in the documentation and/or other materials
22364 provided with the distribution.
22365
22366 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
22367 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22368 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22369 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22370 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22371 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22372 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22373 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22374 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22375 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
22376 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22377 SUCH DAMAGE.
22378
22379 ***********************************************************************/
22380
22381 "use strict";
22382
22383 (function(){
22384
22385 var MOZ_TO_ME = {
22386 TryStatement : function(M) {
22387 return new AST_Try({
22388 start : my_start_token(M),
22389 end : my_end_token(M),
22390 body : from_moz(M.block).body,
22391 bcatch : from_moz(M.handlers[0]),
22392 bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
22393 });
22394 },
22395 CatchClause : function(M) {
22396 return new AST_Catch({
22397 start : my_start_token(M),
22398 end : my_end_token(M),
22399 argname : from_moz(M.param),
22400 body : from_moz(M.body).body
22401 });
22402 },
22403 ObjectExpression : function(M) {
22404 return new AST_Object({
22405 start : my_start_token(M),
22406 end : my_end_token(M),
22407 properties : M.properties.map(function(prop){
22408 var key = prop.key;
22409 var name = key.type == "Identifier" ? key.name : key.value;
22410 var args = {
22411 start : my_start_token(key),
22412 end : my_end_token(prop.value),
22413 key : name,
22414 value : from_moz(prop.value)
22415 };
22416 switch (prop.kind) {
22417 case "init":
22418 return new AST_ObjectKeyVal(args);
22419 case "set":
22420 args.value.name = from_moz(key);
22421 return new AST_ObjectSetter(args);
22422 case "get":
22423 args.value.name = from_moz(key);
22424 return new AST_ObjectGetter(args);
22425 }
22426 })
22427 });
22428 },
22429 SequenceExpression : function(M) {
22430 return AST_Seq.from_array(M.expressions.map(from_moz));
22431 },
22432 MemberExpression : function(M) {
22433 return new (M.computed ? AST_Sub : AST_Dot)({
22434 start : my_start_token(M),
22435 end : my_end_token(M),
22436 property : M.computed ? from_moz(M.property) : M.property.name,
22437 expression : from_moz(M.object)
22438 });
22439 },
22440 SwitchCase : function(M) {
22441 return new (M.test ? AST_Case : AST_Default)({
22442 start : my_start_token(M),
22443 end : my_end_token(M),
22444 expression : from_moz(M.test),
22445 body : M.consequent.map(from_moz)
22446 });
22447 },
22448 Literal : function(M) {
22449 var val = M.value, args = {
22450 start : my_start_token(M),
22451 end : my_end_token(M)
22452 };
22453 if (val === null) return new AST_Null(args);
22454 switch (typeof val) {
22455 case "string":
22456 args.value = val;
22457 return new AST_String(args);
22458 case "number":
22459 args.value = val;
22460 return new AST_Number(args);
22461 case "boolean":
22462 return new (val ? AST_True : AST_False)(args);
22463 default:
22464 args.value = val;
22465 return new AST_RegExp(args);
22466 }
22467 },
22468 UnaryExpression: From_Moz_Unary,
22469 UpdateExpression: From_Moz_Unary,
22470 Identifier: function(M) {
22471 var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
22472 return new (M.name == "this" ? AST_This
22473 : p.type == "LabeledStatement" ? AST_Label
22474 : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
22475 : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
22476 : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
22477 : p.type == "CatchClause" ? AST_SymbolCatch
22478 : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
22479 : AST_SymbolRef)({
22480 start : my_start_token(M),
22481 end : my_end_token(M),
22482 name : M.name
22483 });
22484 }
22485 };
22486
22487 function From_Moz_Unary(M) {
22488 var prefix = "prefix" in M ? M.prefix
22489 : M.type == "UnaryExpression" ? true : false;
22490 return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
22491 start : my_start_token(M),
22492 end : my_end_token(M),
22493 operator : M.operator,
22494 expression : from_moz(M.argument)
20493 }); 22495 });
20494 OPT(AST_Undefined, function(self, compressor) { 22496 };
20495 if (compressor.option("unsafe")) { 22497
20496 var scope = compressor.find_parent(AST_Scope); 22498 var ME_TO_MOZ = {};
20497 var undef = scope.find_variable("undefined"); 22499
20498 if (undef) { 22500 map("Node", AST_Node);
20499 var ref = make_node(AST_SymbolRef, self, { 22501 map("Program", AST_Toplevel, "body@body");
20500 name: "undefined", 22502 map("Function", AST_Function, "id>name, params@argnames, body%body");
20501 scope: scope, 22503 map("EmptyStatement", AST_EmptyStatement);
20502 thedef: undef 22504 map("BlockStatement", AST_BlockStatement, "body@body");
20503 }); 22505 map("ExpressionStatement", AST_SimpleStatement, "expression>body");
20504 ref.reference(); 22506 map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
20505 return ref; 22507 map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
20506 } 22508 map("BreakStatement", AST_Break, "label>label");
20507 } 22509 map("ContinueStatement", AST_Continue, "label>label");
20508 return self; 22510 map("WithStatement", AST_With, "object>expression, body>body");
22511 map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
22512 map("ReturnStatement", AST_Return, "argument>value");
22513 map("ThrowStatement", AST_Throw, "argument>value");
22514 map("WhileStatement", AST_While, "test>condition, body>body");
22515 map("DoWhileStatement", AST_Do, "test>condition, body>body");
22516 map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
22517 map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
22518 map("DebuggerStatement", AST_Debugger);
22519 map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
22520 map("VariableDeclaration", AST_Var, "declarations@definitions");
22521 map("VariableDeclarator", AST_VarDef, "id>name, init>value");
22522
22523 map("ThisExpression", AST_This);
22524 map("ArrayExpression", AST_Array, "elements@elements");
22525 map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
22526 map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
22527 map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
22528 map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
22529 map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
22530 map("NewExpression", AST_New, "callee>expression, arguments@args");
22531 map("CallExpression", AST_Call, "callee>expression, arguments@args");
22532
22533 /* -----[ tools ]----- */
22534
22535 function my_start_token(moznode) {
22536 return new AST_Token({
22537 file : moznode.loc && moznode.loc.source,
22538 line : moznode.loc && moznode.loc.start.line,
22539 col : moznode.loc && moznode.loc.start.column,
22540 pos : moznode.start,
22541 endpos : moznode.start
20509 }); 22542 });
20510 var ASSIGN_OPS = [ "+", "-", "/", "*", "%", ">>", "<<", ">>>", "|", "^", "&" ]; 22543 };
20511 OPT(AST_Assign, function(self, compressor) { 22544
20512 self = self.lift_sequences(compressor); 22545 function my_end_token(moznode) {
20513 if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary && self.right.left instanceof AST_SymbolRef && self.right.left.name == self.left.name && member(self.right.operator, ASSIGN_OPS)) { 22546 return new AST_Token({
20514 self.operator = self.right.operator + "="; 22547 file : moznode.loc && moznode.loc.source,
20515 self.right = self.right.right; 22548 line : moznode.loc && moznode.loc.end.line,
20516 } 22549 col : moznode.loc && moznode.loc.end.column,
20517 return self; 22550 pos : moznode.end,
22551 endpos : moznode.end
20518 }); 22552 });
20519 OPT(AST_Conditional, function(self, compressor) { 22553 };
20520 if (!compressor.option("conditionals")) return self; 22554
20521 if (self.condition instanceof AST_Seq) { 22555 function map(moztype, mytype, propmap) {
20522 var car = self.condition.car; 22556 var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
20523 self.condition = self.condition.cdr; 22557 moz_to_me += "return new mytype({\n" +
20524 return AST_Seq.cons(car, self); 22558 "start: my_start_token(M),\n" +
20525 } 22559 "end: my_end_token(M)";
20526 var cond = self.condition.evaluate(compressor); 22560
20527 if (cond.length > 1) { 22561 if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
20528 if (cond[1]) { 22562 var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
20529 compressor.warn("Condition always true [{file}:{line},{col}]", self.start); 22563 if (!m) throw new Error("Can't understand property map: " + prop);
20530 return self.consequent; 22564 var moz = "M." + m[1], how = m[2], my = m[3];
20531 } else { 22565 moz_to_me += ",\n" + my + ": ";
20532 compressor.warn("Condition always false [{file}:{line},{col}]", self.start); 22566 if (how == "@") {
20533 return self.alternative; 22567 moz_to_me += moz + ".map(from_moz)";
20534 } 22568 } else if (how == ">") {
20535 } 22569 moz_to_me += "from_moz(" + moz + ")";
20536 var negated = cond[0].negate(compressor); 22570 } else if (how == "=") {
20537 if (best_of(cond[0], negated) === negated) { 22571 moz_to_me += moz;
20538 self = make_node(AST_Conditional, self, { 22572 } else if (how == "%") {
20539 condition: negated, 22573 moz_to_me += "from_moz(" + moz + ").body";
20540 consequent: self.alternative, 22574 } else throw new Error("Can't understand operator in propmap: " + prop);
20541 alternative: self.consequent
20542 });
20543 }
20544 var consequent = self.consequent;
20545 var alternative = self.alternative;
20546 if (consequent instanceof AST_Assign && alternative instanceof AST_Assign && consequent.operator == alternative.operator && consequent.left.equivalent_to(alternative.left)) {
20547 self = make_node(AST_Assign, self, {
20548 operator: consequent.operator,
20549 left: consequent.left,
20550 right: make_node(AST_Conditional, self, {
20551 condition: self.condition,
20552 consequent: consequent.right,
20553 alternative: alternative.right
20554 })
20555 });
20556 }
20557 return self;
20558 }); 22575 });
20559 OPT(AST_Boolean, function(self, compressor) { 22576 moz_to_me += "\n})}";
20560 if (compressor.option("booleans")) { 22577
20561 var p = compressor.parent(); 22578 // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
20562 if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) { 22579 // console.log(moz_to_me);
20563 compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { 22580
20564 operator: p.operator, 22581 moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
20565 value: self.value, 22582 mytype, my_start_token, my_end_token, from_moz
20566 file: p.start.file, 22583 );
20567 line: p.start.line, 22584 return MOZ_TO_ME[moztype] = moz_to_me;
20568 col: p.start.col 22585 };
20569 }); 22586
20570 return make_node(AST_Number, self, { 22587 var FROM_MOZ_STACK = null;
20571 value: +self.value 22588
20572 }); 22589 function from_moz(node) {
20573 } 22590 FROM_MOZ_STACK.push(node);
20574 return make_node(AST_UnaryPrefix, self, { 22591 var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
20575 operator: "!", 22592 FROM_MOZ_STACK.pop();
20576 expression: make_node(AST_Number, self, { 22593 return ret;
20577 value: 1 - self.value 22594 };
20578 }) 22595
20579 }); 22596 AST_Node.from_mozilla_ast = function(node){
20580 } 22597 var save_stack = FROM_MOZ_STACK;
20581 return self; 22598 FROM_MOZ_STACK = [];
20582 }); 22599 var ast = from_moz(node);
20583 OPT(AST_Sub, function(self, compressor) { 22600 FROM_MOZ_STACK = save_stack;
20584 var prop = self.property; 22601 return ast;
20585 if (prop instanceof AST_String && compressor.option("properties")) { 22602 };
20586 prop = prop.getValue(); 22603
20587 if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { 22604 })();
20588 return make_node(AST_Dot, self, { 22605
20589 expression: self.expression, 22606 AST_Node.warn_function = function(txt) { logger.error("uglifyjs2 WARN: " + txt); };
20590 property: prop
20591 });
20592 }
20593 }
20594 return self;
20595 });
20596 function literals_in_boolean_context(self, compressor) {
20597 if (compressor.option("booleans") && compressor.in_boolean_context()) {
20598 return make_node(AST_True, self);
20599 }
20600 return self;
20601 }
20602 OPT(AST_Array, literals_in_boolean_context);
20603 OPT(AST_Object, literals_in_boolean_context);
20604 OPT(AST_RegExp, literals_in_boolean_context);
20605 })();
20606 "use strict";
20607 function SourceMap(options) {
20608 options = defaults(options, {
20609 file: null,
20610 root: null,
20611 orig: null
20612 });
20613 var generator = new MOZ_SourceMap.SourceMapGenerator({
20614 file: options.file,
20615 sourceRoot: options.root
20616 });
20617 var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
20618 function add(source, gen_line, gen_col, orig_line, orig_col, name) {
20619 if (orig_map) {
20620 var info = orig_map.originalPositionFor({
20621 line: orig_line,
20622 column: orig_col
20623 });
20624 source = info.source;
20625 orig_line = info.line;
20626 orig_col = info.column;
20627 name = info.name;
20628 }
20629 generator.addMapping({
20630 generated: {
20631 line: gen_line,
20632 column: gen_col
20633 },
20634 original: {
20635 line: orig_line,
20636 column: orig_col
20637 },
20638 source: source,
20639 name: name
20640 });
20641 }
20642 return {
20643 add: add,
20644 get: function() {
20645 return generator;
20646 },
20647 toString: function() {
20648 return generator.toString();
20649 }
20650 };
20651 }
20652 "use strict";
20653 (function() {
20654 var MOZ_TO_ME = {
20655 TryStatement: function(M) {
20656 return new AST_Try({
20657 start: my_start_token(M),
20658 end: my_end_token(M),
20659 body: from_moz(M.block).body,
20660 bcatch: from_moz(M.handlers[0]),
20661 bfinally: M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
20662 });
20663 },
20664 CatchClause: function(M) {
20665 return new AST_Catch({
20666 start: my_start_token(M),
20667 end: my_end_token(M),
20668 argname: from_moz(M.param),
20669 body: from_moz(M.body).body
20670 });
20671 },
20672 ObjectExpression: function(M) {
20673 return new AST_Object({
20674 start: my_start_token(M),
20675 end: my_end_token(M),
20676 properties: M.properties.map(function(prop) {
20677 var key = prop.key;
20678 var name = key.type == "Identifier" ? key.name : key.value;
20679 var args = {
20680 start: my_start_token(key),
20681 end: my_end_token(prop.value),
20682 key: name,
20683 value: from_moz(prop.value)
20684 };
20685 switch (prop.kind) {
20686 case "init":
20687 return new AST_ObjectKeyVal(args);
20688
20689 case "set":
20690 args.value.name = from_moz(key);
20691 return new AST_ObjectSetter(args);
20692
20693 case "get":
20694 args.value.name = from_moz(key);
20695 return new AST_ObjectGetter(args);
20696 }
20697 })
20698 });
20699 },
20700 SequenceExpression: function(M) {
20701 return AST_Seq.from_array(M.expressions.map(from_moz));
20702 },
20703 MemberExpression: function(M) {
20704 return new (M.computed ? AST_Sub : AST_Dot)({
20705 start: my_start_token(M),
20706 end: my_end_token(M),
20707 property: M.computed ? from_moz(M.property) : M.property.name,
20708 expression: from_moz(M.object)
20709 });
20710 },
20711 SwitchCase: function(M) {
20712 return new (M.test ? AST_Case : AST_Default)({
20713 start: my_start_token(M),
20714 end: my_end_token(M),
20715 expression: from_moz(M.test),
20716 body: M.consequent.map(from_moz)
20717 });
20718 },
20719 Literal: function(M) {
20720 var val = M.value, args = {
20721 start: my_start_token(M),
20722 end: my_end_token(M)
20723 };
20724 if (val === null) return new AST_Null(args);
20725 switch (typeof val) {
20726 case "string":
20727 args.value = val;
20728 return new AST_String(args);
20729
20730 case "number":
20731 args.value = val;
20732 return new AST_Number(args);
20733
20734 case "boolean":
20735 return new (val ? AST_True : AST_False)(args);
20736
20737 default:
20738 args.value = val;
20739 return new AST_RegExp(args);
20740 }
20741 },
20742 UnaryExpression: From_Moz_Unary,
20743 UpdateExpression: From_Moz_Unary,
20744 Identifier: function(M) {
20745 var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
20746 return new (M.name == "this" ? AST_This : p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? p.kind == "const" ? AST_SymbolConst : AST_SymbolVar : p.type == "FunctionExpression" ? p.id === M ? AST_SymbolLambda : AST_SymbolFunarg : p.type == "FunctionDeclaration" ? p.id === M ? AST_SymbolDefun : AST_SymbolFunarg : p.type == "CatchClause" ? AST_SymbolCatch : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef : AST_SymbolRef)({
20747 start: my_start_token(M),
20748 end: my_end_token(M),
20749 name: M.name
20750 });
20751 }
20752 };
20753 function From_Moz_Unary(M) {
20754 var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false;
20755 return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
20756 start: my_start_token(M),
20757 end: my_end_token(M),
20758 operator: M.operator,
20759 expression: from_moz(M.argument)
20760 });
20761 }
20762 var ME_TO_MOZ = {};
20763 map("Node", AST_Node);
20764 map("Program", AST_Toplevel, "body@body");
20765 map("Function", AST_Function, "id>name, params@argnames, body%body");
20766 map("EmptyStatement", AST_EmptyStatement);
20767 map("BlockStatement", AST_BlockStatement, "body@body");
20768 map("ExpressionStatement", AST_SimpleStatement, "expression>body");
20769 map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
20770 map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
20771 map("BreakStatement", AST_Break, "label>label");
20772 map("ContinueStatement", AST_Continue, "label>label");
20773 map("WithStatement", AST_With, "object>expression, body>body");
20774 map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
20775 map("ReturnStatement", AST_Return, "argument>value");
20776 map("ThrowStatement", AST_Throw, "argument>value");
20777 map("WhileStatement", AST_While, "test>condition, body>body");
20778 map("DoWhileStatement", AST_Do, "test>condition, body>body");
20779 map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
20780 map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
20781 map("DebuggerStatement", AST_Debugger);
20782 map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
20783 map("VariableDeclaration", AST_Var, "declarations@definitions");
20784 map("VariableDeclarator", AST_VarDef, "id>name, init>value");
20785 map("ThisExpression", AST_This);
20786 map("ArrayExpression", AST_Array, "elements@elements");
20787 map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
20788 map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
20789 map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
20790 map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
20791 map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
20792 map("NewExpression", AST_New, "callee>expression, arguments@args");
20793 map("CallExpression", AST_Call, "callee>expression, arguments@args");
20794 function my_start_token(moznode) {
20795 return new AST_Token({
20796 file: moznode.loc && moznode.loc.source,
20797 line: moznode.loc && moznode.loc.start.line,
20798 col: moznode.loc && moznode.loc.start.column,
20799 pos: moznode.start,
20800 endpos: moznode.start
20801 });
20802 }
20803 function my_end_token(moznode) {
20804 return new AST_Token({
20805 file: moznode.loc && moznode.loc.source,
20806 line: moznode.loc && moznode.loc.end.line,
20807 col: moznode.loc && moznode.loc.end.column,
20808 pos: moznode.end,
20809 endpos: moznode.end
20810 });
20811 }
20812 function map(moztype, mytype, propmap) {
20813 var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
20814 moz_to_me += "return new mytype({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)";
20815 if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
20816 var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
20817 if (!m) throw new Error("Can't understand property map: " + prop);
20818 var moz = "M." + m[1], how = m[2], my = m[3];
20819 moz_to_me += ",\n" + my + ": ";
20820 if (how == "@") {
20821 moz_to_me += moz + ".map(from_moz)";
20822 } else if (how == ">") {
20823 moz_to_me += "from_moz(" + moz + ")";
20824 } else if (how == "=") {
20825 moz_to_me += moz;
20826 } else if (how == "%") {
20827 moz_to_me += "from_moz(" + moz + ").body";
20828 } else throw new Error("Can't understand operator in propmap: " + prop);
20829 });
20830 moz_to_me += "\n})}";
20831 moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(mytype, my_start_token, my_end_token, from_moz);
20832 return MOZ_TO_ME[moztype] = moz_to_me;
20833 }
20834 var FROM_MOZ_STACK = null;
20835 function from_moz(node) {
20836 FROM_MOZ_STACK.push(node);
20837 var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
20838 FROM_MOZ_STACK.pop();
20839 return ret;
20840 }
20841 AST_Node.from_mozilla_ast = function(node) {
20842 var save_stack = FROM_MOZ_STACK;
20843 FROM_MOZ_STACK = [];
20844 var ast = from_moz(node);
20845 FROM_MOZ_STACK = save_stack;
20846 return ast;
20847 };
20848 })();
20849 exports["array_to_hash"] = array_to_hash;
20850 exports["slice"] = slice;
20851 exports["characters"] = characters;
20852 exports["member"] = member;
20853 exports["find_if"] = find_if;
20854 exports["repeat_string"] = repeat_string;
20855 exports["DefaultsError"] = DefaultsError;
20856 exports["defaults"] = defaults;
20857 exports["merge"] = merge;
20858 exports["noop"] = noop;
20859 exports["MAP"] = MAP;
20860 exports["push_uniq"] = push_uniq;
20861 exports["string_template"] = string_template;
20862 exports["remove"] = remove;
20863 exports["mergeSort"] = mergeSort;
20864 exports["set_difference"] = set_difference;
20865 exports["set_intersection"] = set_intersection;
20866 exports["makePredicate"] = makePredicate;
20867 exports["all"] = all;
20868 exports["Dictionary"] = Dictionary;
20869 exports["DEFNODE"] = DEFNODE;
20870 exports["AST_Token"] = AST_Token;
20871 exports["AST_Node"] = AST_Node;
20872 exports["AST_Statement"] = AST_Statement;
20873 exports["AST_Debugger"] = AST_Debugger;
20874 exports["AST_Directive"] = AST_Directive;
20875 exports["AST_SimpleStatement"] = AST_SimpleStatement;
20876 exports["walk_body"] = walk_body;
20877 exports["AST_Block"] = AST_Block;
20878 exports["AST_BlockStatement"] = AST_BlockStatement;
20879 exports["AST_EmptyStatement"] = AST_EmptyStatement;
20880 exports["AST_StatementWithBody"] = AST_StatementWithBody;
20881 exports["AST_LabeledStatement"] = AST_LabeledStatement;
20882 exports["AST_DWLoop"] = AST_DWLoop;
20883 exports["AST_Do"] = AST_Do;
20884 exports["AST_While"] = AST_While;
20885 exports["AST_For"] = AST_For;
20886 exports["AST_ForIn"] = AST_ForIn;
20887 exports["AST_With"] = AST_With;
20888 exports["AST_Scope"] = AST_Scope;
20889 exports["AST_Toplevel"] = AST_Toplevel;
20890 exports["AST_Lambda"] = AST_Lambda;
20891 exports["AST_Accessor"] = AST_Accessor;
20892 exports["AST_Function"] = AST_Function;
20893 exports["AST_Defun"] = AST_Defun;
20894 exports["AST_Jump"] = AST_Jump;
20895 exports["AST_Exit"] = AST_Exit;
20896 exports["AST_Return"] = AST_Return;
20897 exports["AST_Throw"] = AST_Throw;
20898 exports["AST_LoopControl"] = AST_LoopControl;
20899 exports["AST_Break"] = AST_Break;
20900 exports["AST_Continue"] = AST_Continue;
20901 exports["AST_If"] = AST_If;
20902 exports["AST_Switch"] = AST_Switch;
20903 exports["AST_SwitchBranch"] = AST_SwitchBranch;
20904 exports["AST_Default"] = AST_Default;
20905 exports["AST_Case"] = AST_Case;
20906 exports["AST_Try"] = AST_Try;
20907 exports["AST_Catch"] = AST_Catch;
20908 exports["AST_Finally"] = AST_Finally;
20909 exports["AST_Definitions"] = AST_Definitions;
20910 exports["AST_Var"] = AST_Var;
20911 exports["AST_Const"] = AST_Const;
20912 exports["AST_VarDef"] = AST_VarDef;
20913 exports["AST_Call"] = AST_Call;
20914 exports["AST_New"] = AST_New;
20915 exports["AST_Seq"] = AST_Seq;
20916 exports["AST_PropAccess"] = AST_PropAccess;
20917 exports["AST_Dot"] = AST_Dot;
20918 exports["AST_Sub"] = AST_Sub;
20919 exports["AST_Unary"] = AST_Unary;
20920 exports["AST_UnaryPrefix"] = AST_UnaryPrefix;
20921 exports["AST_UnaryPostfix"] = AST_UnaryPostfix;
20922 exports["AST_Binary"] = AST_Binary;
20923 exports["AST_Conditional"] = AST_Conditional;
20924 exports["AST_Assign"] = AST_Assign;
20925 exports["AST_Array"] = AST_Array;
20926 exports["AST_Object"] = AST_Object;
20927 exports["AST_ObjectProperty"] = AST_ObjectProperty;
20928 exports["AST_ObjectKeyVal"] = AST_ObjectKeyVal;
20929 exports["AST_ObjectSetter"] = AST_ObjectSetter;
20930 exports["AST_ObjectGetter"] = AST_ObjectGetter;
20931 exports["AST_Symbol"] = AST_Symbol;
20932 exports["AST_SymbolAccessor"] = AST_SymbolAccessor;
20933 exports["AST_SymbolDeclaration"] = AST_SymbolDeclaration;
20934 exports["AST_SymbolVar"] = AST_SymbolVar;
20935 exports["AST_SymbolConst"] = AST_SymbolConst;
20936 exports["AST_SymbolFunarg"] = AST_SymbolFunarg;
20937 exports["AST_SymbolDefun"] = AST_SymbolDefun;
20938 exports["AST_SymbolLambda"] = AST_SymbolLambda;
20939 exports["AST_SymbolCatch"] = AST_SymbolCatch;
20940 exports["AST_Label"] = AST_Label;
20941 exports["AST_SymbolRef"] = AST_SymbolRef;
20942 exports["AST_LabelRef"] = AST_LabelRef;
20943 exports["AST_This"] = AST_This;
20944 exports["AST_Constant"] = AST_Constant;
20945 exports["AST_String"] = AST_String;
20946 exports["AST_Number"] = AST_Number;
20947 exports["AST_RegExp"] = AST_RegExp;
20948 exports["AST_Atom"] = AST_Atom;
20949 exports["AST_Null"] = AST_Null;
20950 exports["AST_NaN"] = AST_NaN;
20951 exports["AST_Undefined"] = AST_Undefined;
20952 exports["AST_Hole"] = AST_Hole;
20953 exports["AST_Infinity"] = AST_Infinity;
20954 exports["AST_Boolean"] = AST_Boolean;
20955 exports["AST_False"] = AST_False;
20956 exports["AST_True"] = AST_True;
20957 exports["TreeWalker"] = TreeWalker;
20958 exports["KEYWORDS"] = KEYWORDS;
20959 exports["KEYWORDS_ATOM"] = KEYWORDS_ATOM;
20960 exports["RESERVED_WORDS"] = RESERVED_WORDS;
20961 exports["KEYWORDS_BEFORE_EXPRESSION"] = KEYWORDS_BEFORE_EXPRESSION;
20962 exports["OPERATOR_CHARS"] = OPERATOR_CHARS;
20963 exports["RE_HEX_NUMBER"] = RE_HEX_NUMBER;
20964 exports["RE_OCT_NUMBER"] = RE_OCT_NUMBER;
20965 exports["RE_DEC_NUMBER"] = RE_DEC_NUMBER;
20966 exports["OPERATORS"] = OPERATORS;
20967 exports["WHITESPACE_CHARS"] = WHITESPACE_CHARS;
20968 exports["PUNC_BEFORE_EXPRESSION"] = PUNC_BEFORE_EXPRESSION;
20969 exports["PUNC_CHARS"] = PUNC_CHARS;
20970 exports["REGEXP_MODIFIERS"] = REGEXP_MODIFIERS;
20971 exports["UNICODE"] = UNICODE;
20972 exports["is_letter"] = is_letter;
20973 exports["is_digit"] = is_digit;
20974 exports["is_alphanumeric_char"] = is_alphanumeric_char;
20975 exports["is_unicode_combining_mark"] = is_unicode_combining_mark;
20976 exports["is_unicode_connector_punctuation"] = is_unicode_connector_punctuation;
20977 exports["is_identifier"] = is_identifier;
20978 exports["is_identifier_start"] = is_identifier_start;
20979 exports["is_identifier_char"] = is_identifier_char;
20980 exports["is_identifier_string"] = is_identifier_string;
20981 exports["parse_js_number"] = parse_js_number;
20982 exports["JS_Parse_Error"] = JS_Parse_Error;
20983 exports["js_error"] = js_error;
20984 exports["is_token"] = is_token;
20985 exports["EX_EOF"] = EX_EOF;
20986 exports["tokenizer"] = tokenizer;
20987 exports["UNARY_PREFIX"] = UNARY_PREFIX;
20988 exports["UNARY_POSTFIX"] = UNARY_POSTFIX;
20989 exports["ASSIGNMENT"] = ASSIGNMENT;
20990 exports["PRECEDENCE"] = PRECEDENCE;
20991 exports["STATEMENTS_WITH_LABELS"] = STATEMENTS_WITH_LABELS;
20992 exports["ATOMIC_START_TOKEN"] = ATOMIC_START_TOKEN;
20993 exports["parse"] = parse;
20994 exports["TreeTransformer"] = TreeTransformer;
20995 exports["SymbolDef"] = SymbolDef;
20996 exports["base54"] = base54;
20997 exports["OutputStream"] = OutputStream;
20998 exports["Compressor"] = Compressor;
20999 exports["SourceMap"] = SourceMap;
21000 })({}, function() {
21001 return exports;
21002 }());
21003
21004 var UglifyJS = exports.UglifyJS;
21005
21006 UglifyJS.AST_Node.warn_function = function(txt) {
21007 logger.error("uglifyjs2 WARN: " + txt);
21008 };
21009
21010 //JRB: MODIFIED FROM UGLIFY SOURCE
21011 //to take a name for the file, and then set toplevel.filename to be that name.
21012 exports.minify = function(files, options, name) { 22607 exports.minify = function(files, options, name) {
21013 options = UglifyJS.defaults(options, { 22608 options = defaults(options, {
22609 spidermonkey : false,
21014 outSourceMap : null, 22610 outSourceMap : null,
21015 sourceRoot : null, 22611 sourceRoot : null,
21016 inSourceMap : null, 22612 inSourceMap : null,
21017 fromString : false, 22613 fromString : false,
21018 warnings : false, 22614 warnings : false,
21019 mangle : {}, 22615 mangle : {},
21020 output : null, 22616 output : null,
21021 compress : {} 22617 compress : {}
21022 }); 22618 });
21023 if (typeof files == "string") 22619 base54.reset();
21024 files = [ files ];
21025
21026 UglifyJS.base54.reset();
21027 22620
21028 // 1. parse 22621 // 1. parse
21029 var toplevel = null; 22622 var toplevel = null,
21030 files.forEach(function(file){ 22623 sourcesContent = {};
21031 var code = options.fromString 22624
21032 ? file 22625 if (options.spidermonkey) {
21033 : rjsFile.readFile(file, "utf8"); 22626 toplevel = AST_Node.from_mozilla_ast(files);
21034 toplevel = UglifyJS.parse(code, { 22627 } else {
21035 filename: options.fromString ? name : file, 22628 if (typeof files == "string")
21036 toplevel: toplevel 22629 files = [ files ];
22630 files.forEach(function(file){
22631 var code = options.fromString
22632 ? file
22633 : rjsFile.readFile(file, "utf8");
22634 sourcesContent[file] = code;
22635 toplevel = parse(code, {
22636 filename: options.fromString ? name : file,
22637 toplevel: toplevel
22638 });
21037 }); 22639 });
21038 }); 22640 }
21039 22641
21040 // 2. compress 22642 // 2. compress
21041 if (options.compress) { 22643 if (options.compress) {
21042 var compress = { warnings: options.warnings }; 22644 var compress = { warnings: options.warnings };
21043 UglifyJS.merge(compress, options.compress); 22645 merge(compress, options.compress);
21044 toplevel.figure_out_scope(); 22646 toplevel.figure_out_scope();
21045 var sq = UglifyJS.Compressor(compress); 22647 var sq = Compressor(compress);
21046 toplevel = toplevel.transform(sq); 22648 toplevel = toplevel.transform(sq);
21047 } 22649 }
21048 22650
21049 // 3. mangle 22651 // 3. mangle
21050 if (options.mangle) { 22652 if (options.mangle) {
21058 var output = {}; 22660 var output = {};
21059 if (typeof options.inSourceMap == "string") { 22661 if (typeof options.inSourceMap == "string") {
21060 inMap = rjsFile.readFile(options.inSourceMap, "utf8"); 22662 inMap = rjsFile.readFile(options.inSourceMap, "utf8");
21061 } 22663 }
21062 if (options.outSourceMap) { 22664 if (options.outSourceMap) {
21063 output.source_map = UglifyJS.SourceMap({ 22665 output.source_map = SourceMap({
21064 file: options.outSourceMap, 22666 file: options.outSourceMap,
21065 orig: inMap, 22667 orig: inMap,
21066 root: options.sourceRoot 22668 root: options.sourceRoot
21067 }); 22669 });
22670 if (options.sourceMapIncludeSources) {
22671 for (var file in sourcesContent) {
22672 if (sourcesContent.hasOwnProperty(file)) {
22673 options.source_map.get().setSourceContent(file, sourcesContent[file]);
22674 }
22675 }
22676 }
22677
21068 } 22678 }
21069 if (options.output) { 22679 if (options.output) {
21070 UglifyJS.merge(output, options.output); 22680 merge(output, options.output);
21071 } 22681 }
21072 var stream = UglifyJS.OutputStream(output); 22682 var stream = OutputStream(output);
21073 toplevel.print(stream); 22683 toplevel.print(stream);
21074 return { 22684 return {
21075 code : stream + "", 22685 code : stream + "",
21076 map : output.source_map + "" 22686 map : output.source_map + ""
21077 }; 22687 };
21086 // var ret = {}; 22696 // var ret = {};
21087 // if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS; 22697 // if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
21088 // if (ctor.SUBCLASSES.length > 0) ret.sub = sub; 22698 // if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
21089 // return ret; 22699 // return ret;
21090 // } 22700 // }
21091 // return doitem(UglifyJS.AST_Node).sub; 22701 // return doitem(AST_Node).sub;
21092 // } 22702 // }
21093 22703
21094 exports.describe_ast = function() { 22704 exports.describe_ast = function() {
21095 var out = UglifyJS.OutputStream({ beautify: true }); 22705 var out = OutputStream({ beautify: true });
21096 function doitem(ctor) { 22706 function doitem(ctor) {
21097 out.print("AST_" + ctor.TYPE); 22707 out.print("AST_" + ctor.TYPE);
21098 var props = ctor.SELF_PROPS.filter(function(prop){ 22708 var props = ctor.SELF_PROPS.filter(function(prop){
21099 return !/^\$/.test(prop); 22709 return !/^\$/.test(prop);
21100 }); 22710 });
21120 out.newline(); 22730 out.newline();
21121 }); 22731 });
21122 }); 22732 });
21123 } 22733 }
21124 }; 22734 };
21125 doitem(UglifyJS.AST_Node); 22735 doitem(AST_Node);
21126 return out + ""; 22736 return out + "";
21127 }; 22737 };
21128 22738
22739
21129 }); 22740 });
21130 /** 22741 /**
21131 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 22742 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
21132 * Available via the MIT or new BSD license. 22743 * Available via the MIT or new BSD license.
21133 * see: http://github.com/jrburke/requirejs for details 22744 * see: http://github.com/jrburke/requirejs for details
21134 */ 22745 */
21135 22746
21136 /*jslint plusplus: true */ 22747 /*jslint plusplus: true */
21151 return output; 22762 return output;
21152 } 22763 }
21153 22764
21154 //This string is saved off because JSLint complains 22765 //This string is saved off because JSLint complains
21155 //about obj.arguments use, as 'reserved word' 22766 //about obj.arguments use, as 'reserved word'
21156 var argPropName = 'arguments'; 22767 var argPropName = 'arguments',
22768 //Default object to use for "scope" checking for UMD identifiers.
22769 emptyScope = {},
22770 mixin = lang.mixin,
22771 hasProp = lang.hasProp;
21157 22772
21158 //From an esprima example for traversing its ast. 22773 //From an esprima example for traversing its ast.
21159 function traverse(object, visitor) { 22774 function traverse(object, visitor) {
21160 var key, child; 22775 var key, child;
21161 22776
21193 } 22808 }
21194 for (key in object) { 22809 for (key in object) {
21195 if (object.hasOwnProperty(key)) { 22810 if (object.hasOwnProperty(key)) {
21196 child = object[key]; 22811 child = object[key];
21197 if (typeof child === 'object' && child !== null) { 22812 if (typeof child === 'object' && child !== null) {
21198 traverse(child, visitor); 22813 traverseBroad(child, visitor);
21199 } 22814 }
21200 } 22815 }
21201 } 22816 }
21202 } 22817 }
21203 22818
21253 result = '', 22868 result = '',
21254 moduleList = [], 22869 moduleList = [],
21255 needsDefine = true, 22870 needsDefine = true,
21256 astRoot = esprima.parse(fileContents); 22871 astRoot = esprima.parse(fileContents);
21257 22872
21258 parse.recurse(astRoot, function (callName, config, name, deps) { 22873 parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) {
21259 if (!deps) { 22874 if (!deps) {
21260 deps = []; 22875 deps = [];
21261 } 22876 }
21262 22877
21263 if (callName === 'define' && (!name || name === moduleName)) { 22878 if (callName === 'define' && (!name || name === moduleName)) {
21273 name: name, 22888 name: name,
21274 deps: deps 22889 deps: deps
21275 }); 22890 });
21276 } 22891 }
21277 22892
22893 if (callName === 'define' && factoryIdentifier && hasProp(fnExpScope, factoryIdentifier)) {
22894 return factoryIdentifier;
22895 }
22896
21278 //If define was found, no need to dive deeper, unless 22897 //If define was found, no need to dive deeper, unless
21279 //the config explicitly wants to dig deeper. 22898 //the config explicitly wants to dig deeper.
21280 return !!options.findNestedDependencies; 22899 return !!options.findNestedDependencies;
21281 }, options); 22900 }, options);
21282 22901
21322 * Handles parsing a file recursively for require calls. 22941 * Handles parsing a file recursively for require calls.
21323 * @param {Array} parentNode the AST node to start with. 22942 * @param {Array} parentNode the AST node to start with.
21324 * @param {Function} onMatch function to call on a parse match. 22943 * @param {Function} onMatch function to call on a parse match.
21325 * @param {Object} [options] This is normally the build config options if 22944 * @param {Object} [options] This is normally the build config options if
21326 * it is passed. 22945 * it is passed.
22946 * @param {Object} [fnExpScope] holds list of function expresssion
22947 * argument identifiers, set up internally, not passed in
21327 */ 22948 */
21328 parse.recurse = function (object, onMatch, options) { 22949 parse.recurse = function (object, onMatch, options, fnExpScope) {
21329 //Like traverse, but skips if branches that would not be processed 22950 //Like traverse, but skips if branches that would not be processed
21330 //after has application that results in tests of true or false boolean 22951 //after has application that results in tests of true or false boolean
21331 //literal values. 22952 //literal values.
21332 var key, child, 22953 var key, child, result, i, params, param,
21333 hasHas = options && options.has; 22954 hasHas = options && options.has;
22955
22956 fnExpScope = fnExpScope || emptyScope;
21334 22957
21335 if (!object) { 22958 if (!object) {
21336 return; 22959 return;
21337 } 22960 }
21338 22961
21340 //the appropriate branch and skip the other one. 22963 //the appropriate branch and skip the other one.
21341 if (hasHas && object.type === 'IfStatement' && object.test.type && 22964 if (hasHas && object.type === 'IfStatement' && object.test.type &&
21342 object.test.type === 'Literal') { 22965 object.test.type === 'Literal') {
21343 if (object.test.value) { 22966 if (object.test.value) {
21344 //Take the if branch 22967 //Take the if branch
21345 this.recurse(object.consequent, onMatch, options); 22968 this.recurse(object.consequent, onMatch, options, fnExpScope);
21346 } else { 22969 } else {
21347 //Take the else branch 22970 //Take the else branch
21348 this.recurse(object.alternate, onMatch, options); 22971 this.recurse(object.alternate, onMatch, options, fnExpScope);
21349 } 22972 }
21350 } else { 22973 } else {
21351 if (this.parseNode(object, onMatch) === false) { 22974 result = this.parseNode(object, onMatch, fnExpScope);
22975 if (result === false) {
21352 return; 22976 return;
21353 } 22977 } else if (typeof result === 'string') {
22978 return result;
22979 }
22980
22981 //Build up a "scope" object that informs nested recurse calls if
22982 //the define call references an identifier that is likely a UMD
22983 //wrapped function expresion argument.
22984 if (object.type === 'ExpressionStatement' && object.expression &&
22985 object.expression.type === 'CallExpression' && object.expression.callee &&
22986 object.expression.callee.type === 'FunctionExpression') {
22987 object = object.expression.callee;
22988
22989 if (object.params && object.params.length) {
22990 params = object.params;
22991 fnExpScope = mixin({}, fnExpScope, true);
22992 for (i = 0; i < params.length; i++) {
22993 param = params[i];
22994 if (param.type === 'Identifier') {
22995 fnExpScope[param.name] = true;
22996 }
22997 }
22998 }
22999 }
23000
21354 for (key in object) { 23001 for (key in object) {
21355 if (object.hasOwnProperty(key)) { 23002 if (object.hasOwnProperty(key)) {
21356 child = object[key]; 23003 child = object[key];
21357 if (typeof child === 'object' && child !== null) { 23004 if (typeof child === 'object' && child !== null) {
21358 this.recurse(child, onMatch, options); 23005 result = this.recurse(child, onMatch, options, fnExpScope);
23006 if (typeof result === 'string') {
23007 break;
23008 }
21359 } 23009 }
21360 } 23010 }
23011 }
23012
23013 //Check for an identifier for a factory function identifier being
23014 //passed in as a function expression, indicating a UMD-type of
23015 //wrapping.
23016 if (typeof result === 'string') {
23017 if (hasProp(fnExpScope, result)) {
23018 //Just a plain return, parsing can continue past this
23019 //point.
23020 return;
23021 }
23022
23023 return result;
21361 } 23024 }
21362 } 23025 }
21363 }; 23026 };
21364 23027
21365 /** 23028 /**
21830 * call. 23493 * call.
21831 * @param {Array} node 23494 * @param {Array} node
21832 * @param {Function} onMatch a function to call when a match is found. 23495 * @param {Function} onMatch a function to call when a match is found.
21833 * It is passed the match name, and the config, name, deps possible args. 23496 * It is passed the match name, and the config, name, deps possible args.
21834 * The config, name and deps args are not normalized. 23497 * The config, name and deps args are not normalized.
23498 * @param {Object} fnExpScope an object whose keys are all function
23499 * expression identifiers that should be in scope. Useful for UMD wrapper
23500 * detection to avoid parsing more into the wrapped UMD code.
21835 * 23501 *
21836 * @returns {String} a JS source string with the valid require/define call. 23502 * @returns {String} a JS source string with the valid require/define call.
21837 * Otherwise null. 23503 * Otherwise null.
21838 */ 23504 */
21839 parse.parseNode = function (node, onMatch) { 23505 parse.parseNode = function (node, onMatch, fnExpScope) {
21840 var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, 23506 var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode,
21841 args = node && node[argPropName], 23507 args = node && node[argPropName],
21842 callName = parse.hasRequire(node); 23508 callName = parse.hasRequire(node);
21843 23509
21844 if (callName === 'require' || callName === 'requirejs') { 23510 if (callName === 'require' || callName === 'requirejs') {
21907 //Just save off the name as a string instead of an AST object. 23573 //Just save off the name as a string instead of an AST object.
21908 if (name && name.type === 'Literal') { 23574 if (name && name.type === 'Literal') {
21909 name = name.value; 23575 name = name.value;
21910 } 23576 }
21911 23577
21912 return onMatch("define", null, name, deps, node); 23578 return onMatch("define", null, name, deps, node,
23579 (factory && factory.type === 'Identifier' ? factory.name : undefined),
23580 fnExpScope);
21913 } else if (node.type === 'CallExpression' && node.callee && 23581 } else if (node.type === 'CallExpression' && node.callee &&
21914 node.callee.type === 'FunctionExpression' && 23582 node.callee.type === 'FunctionExpression' &&
21915 node.callee.body && node.callee.body.body && 23583 node.callee.body && node.callee.body.body &&
21916 node.callee.body.body.length === 1 && 23584 node.callee.body.body.length === 1 &&
21917 node.callee.body.body[0].type === 'IfStatement') { 23585 node.callee.body.body[0].type === 'IfStatement') {
21934 return false; 23602 return false;
21935 } 23603 }
21936 }); 23604 });
21937 23605
21938 if (refsDefine) { 23606 if (refsDefine) {
21939 return onMatch("define", null, null, null, exp.expression); 23607 return onMatch("define", null, null, null, exp.expression,
23608 exp.expression.arguments[0].name, fnExpScope);
21940 } 23609 }
21941 } 23610 }
21942 } 23611 }
21943 } 23612 }
21944 }; 23613 };
22052 }; 23721 };
22053 23722
22054 return parse; 23723 return parse;
22055 }); 23724 });
22056 /** 23725 /**
22057 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. 23726 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
22058 * Available via the MIT or new BSD license. 23727 * Available via the MIT or new BSD license.
22059 * see: http://github.com/jrburke/requirejs for details 23728 * see: http://github.com/jrburke/requirejs for details
22060 */ 23729 */
22061 23730
22062 /*global define */ 23731 /*global define */
22084 23753
22085 var astRoot, contentLines, modLine, 23754 var astRoot, contentLines, modLine,
22086 foundAnon, 23755 foundAnon,
22087 scanCount = 0, 23756 scanCount = 0,
22088 scanReset = false, 23757 scanReset = false,
22089 defineInfos = []; 23758 defineInfos = [],
23759 applySourceUrl = function (contents) {
23760 if (options.useSourceUrl) {
23761 contents = 'eval("' + lang.jsEscape(contents) +
23762 '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') +
23763 path +
23764 '");\n';
23765 }
23766 return contents;
23767 };
22090 23768
22091 try { 23769 try {
22092 astRoot = esprima.parse(contents, { 23770 astRoot = esprima.parse(contents, {
22093 loc: true 23771 loc: true
22094 }); 23772 });
22097 e.toString()); 23775 e.toString());
22098 return contents; 23776 return contents;
22099 } 23777 }
22100 23778
22101 //Find the define calls and their position in the files. 23779 //Find the define calls and their position in the files.
22102 parse.traverseBroad(astRoot, function (node) { 23780 parse.traverse(astRoot, function (node) {
22103 var args, firstArg, firstArgLoc, factoryNode, 23781 var args, firstArg, firstArgLoc, factoryNode,
22104 needsId, depAction, foundId, 23782 needsId, depAction, foundId, init,
22105 sourceUrlData, range, 23783 sourceUrlData, range,
22106 namespaceExists = false; 23784 namespaceExists = false;
23785
23786 // If a bundle script with a define declaration, do not
23787 // parse any further at this level. Likely a built layer
23788 // by some other tool.
23789 if (node.type === 'VariableDeclarator' &&
23790 node.id && node.id.name === 'define' &&
23791 node.id.type === 'Identifier') {
23792 init = node.init;
23793 if (init && init.callee &&
23794 init.callee.type === 'CallExpression' &&
23795 init.callee.callee &&
23796 init.callee.callee.type === 'Identifier' &&
23797 init.callee.callee.name === 'require' &&
23798 init.callee.arguments && init.callee.arguments.length === 1 &&
23799 init.callee.arguments[0].type === 'Literal' &&
23800 init.callee.arguments[0].value &&
23801 init.callee.arguments[0].value.indexOf('amdefine') !== -1) {
23802 // the var define = require('amdefine')(module) case,
23803 // keep going in that case.
23804 } else {
23805 return false;
23806 }
23807 }
22107 23808
22108 namespaceExists = namespace && 23809 namespaceExists = namespace &&
22109 node.type === 'CallExpression' && 23810 node.type === 'CallExpression' &&
22110 node.callee && node.callee.object && 23811 node.callee && node.callee.object &&
22111 node.callee.object.type === 'Identifier' && 23812 node.callee.object.type === 'Identifier' &&
22227 } 23928 }
22228 } 23929 }
22229 } 23930 }
22230 }); 23931 });
22231 23932
23933
22232 if (!defineInfos.length) { 23934 if (!defineInfos.length) {
22233 return contents; 23935 return applySourceUrl(contents);
22234 } 23936 }
22235 23937
22236 //Reverse the matches, need to start from the bottom of 23938 //Reverse the matches, need to start from the bottom of
22237 //the file to modify it, so that the ranges are still true 23939 //the file to modify it, so that the ranges are still true
22238 //further up. 23940 //further up.
22300 } 24002 }
22301 }); 24003 });
22302 24004
22303 contents = contentLines.join('\n'); 24005 contents = contentLines.join('\n');
22304 24006
22305 if (options.useSourceUrl) { 24007 return applySourceUrl(contents);
22306 contents = 'eval("' + lang.jsEscape(contents) +
22307 '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') +
22308 path +
22309 '");\n';
22310 }
22311
22312 return contents;
22313 }, 24008 },
22314 24009
22315 /** 24010 /**
22316 * Modify the contents of a require.config/requirejs.config call. This 24011 * Modify the contents of a require.config/requirejs.config call. This
22317 * call will LOSE any existing comments that are in the config string. 24012 * call will LOSE any existing comments that are in the config string.
22470 }; 24165 };
22471 24166
22472 return transform; 24167 return transform;
22473 }); 24168 });
22474 /** 24169 /**
22475 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 24170 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
22476 * Available via the MIT or new BSD license. 24171 * Available via the MIT or new BSD license.
22477 * see: http://github.com/jrburke/requirejs for details 24172 * see: http://github.com/jrburke/requirejs for details
22478 */ 24173 */
22479 24174
22480 /*jslint regexp: true, plusplus: true */ 24175 /*jslint regexp: true, plusplus: true */
22507 useStrictRegExp: /['"]use strict['"];/g, 24202 useStrictRegExp: /['"]use strict['"];/g,
22508 hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g, 24203 hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
22509 configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g, 24204 configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g,
22510 nsWrapRegExp: /\/\*requirejs namespace: true \*\//, 24205 nsWrapRegExp: /\/\*requirejs namespace: true \*\//,
22511 apiDefRegExp: /var requirejs,\s*require,\s*define;/, 24206 apiDefRegExp: /var requirejs,\s*require,\s*define;/,
22512 defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, 24207 defineCheckRegExp: /typeof\s+define\s*===?\s*["']function["']\s*&&\s*define\s*\.\s*amd/g,
22513 defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, 24208 defineStringCheckRegExp: /typeof\s+define\s*===?\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g,
22514 defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, 24209 defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g,
22515 defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g, 24210 defineJQueryRegExp: /typeof\s+define\s*===?\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g,
22516 defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g, 24211 defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
22517 defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/, 24212 defineTernaryRegExp: /typeof\s+define\s*===?\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/,
22518 amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g, 24213 amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g,
22519 24214
22520 removeStrict: function (contents, config) { 24215 removeStrict: function (contents, config) {
22521 return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, ''); 24216 return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '');
22522 }, 24217 },
22719 fileName + ', skipping.'); 24414 fileName + ', skipping.');
22720 } 24415 }
22721 } 24416 }
22722 24417
22723 //Strip amdefine use for node-shared modules. 24418 //Strip amdefine use for node-shared modules.
22724 fileContents = fileContents.replace(pragma.amdefineRegExp, ''); 24419 if (!config.keepAmdefine) {
24420 fileContents = fileContents.replace(pragma.amdefineRegExp, '');
24421 }
22725 24422
22726 //Do namespacing 24423 //Do namespacing
22727 if (onLifecycleName === 'OnSave' && config.namespace) { 24424 if (onLifecycleName === 'OnSave' && config.namespace) {
22728 fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName); 24425 fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName);
22729 } 24426 }
22735 24432
22736 return pragma; 24433 return pragma;
22737 }); 24434 });
22738 if(env === 'browser') { 24435 if(env === 'browser') {
22739 /** 24436 /**
22740 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 24437 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
22741 * Available via the MIT or new BSD license. 24438 * Available via the MIT or new BSD license.
22742 * see: http://github.com/jrburke/requirejs for details 24439 * see: http://github.com/jrburke/requirejs for details
22743 */ 24440 */
22744 24441
22745 /*jslint strict: false */ 24442 /*jslint strict: false */
22749 24446
22750 } 24447 }
22751 24448
22752 if(env === 'node') { 24449 if(env === 'node') {
22753 /** 24450 /**
22754 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 24451 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
22755 * Available via the MIT or new BSD license. 24452 * Available via the MIT or new BSD license.
22756 * see: http://github.com/jrburke/requirejs for details 24453 * see: http://github.com/jrburke/requirejs for details
22757 */ 24454 */
22758 24455
22759 /*jslint strict: false */ 24456 /*jslint strict: false */
22763 24460
22764 } 24461 }
22765 24462
22766 if(env === 'rhino') { 24463 if(env === 'rhino') {
22767 /** 24464 /**
22768 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 24465 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
22769 * Available via the MIT or new BSD license. 24466 * Available via the MIT or new BSD license.
22770 * see: http://github.com/jrburke/requirejs for details 24467 * see: http://github.com/jrburke/requirejs for details
22771 */ 24468 */
22772 24469
22773 /*jslint sloppy: true, plusplus: true */ 24470 /*jslint sloppy: true, plusplus: true */
22808 var JSSourceFilefromCode, optimize, 24505 var JSSourceFilefromCode, optimize,
22809 mapRegExp = /"file":"[^"]+"/; 24506 mapRegExp = /"file":"[^"]+"/;
22810 24507
22811 //Bind to Closure compiler, but if it is not available, do not sweat it. 24508 //Bind to Closure compiler, but if it is not available, do not sweat it.
22812 try { 24509 try {
24510 // Try older closure compiler that worked on Java 6
22813 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]); 24511 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
22814 } catch (e) {} 24512 } catch (e) {
24513 try {
24514 // Try for newer closure compiler that needs Java 7+
24515 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.SourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
24516 } catch (e) {}
24517 }
22815 24518
22816 //Helper for closure compiler, because of weird Java-JavaScript interactions. 24519 //Helper for closure compiler, because of weird Java-JavaScript interactions.
22817 function closurefromCode(filename, content) { 24520 function closurefromCode(filename, content) {
22818 return JSSourceFilefromCode.invoke(null, [filename, content]); 24521 return JSSourceFilefromCode.invoke(null, [filename, content]);
22819 } 24522 }
22939 24642
22940 if(env === 'xpconnect') { 24643 if(env === 'xpconnect') {
22941 define('xpconnect/optimize', {}); 24644 define('xpconnect/optimize', {});
22942 } 24645 }
22943 /** 24646 /**
22944 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 24647 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
22945 * Available via the MIT or new BSD license. 24648 * Available via the MIT or new BSD license.
22946 * see: http://github.com/jrburke/requirejs for details 24649 * see: http://github.com/jrburke/requirejs for details
22947 */ 24650 */
22948 24651
22949 /*jslint plusplus: true, nomen: true, regexp: true */ 24652 /*jslint plusplus: true, nomen: true, regexp: true */
22959 24662
22960 var optimize, 24663 var optimize,
22961 cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig, 24664 cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig,
22962 cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g, 24665 cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g,
22963 cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g, 24666 cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g,
24667 protocolRegExp = /^\w+:/,
22964 SourceMapGenerator = sourceMap.SourceMapGenerator, 24668 SourceMapGenerator = sourceMap.SourceMapGenerator,
22965 SourceMapConsumer =sourceMap.SourceMapConsumer; 24669 SourceMapConsumer =sourceMap.SourceMapConsumer;
22966 24670
22967 /** 24671 /**
22968 * If an URL from a CSS url value contains start/end quotes, remove them. 24672 * If an URL from a CSS url value contains start/end quotes, remove them.
22983 return url; 24687 return url;
22984 } 24688 }
22985 24689
22986 function fixCssUrlPaths(fileName, path, contents, cssPrefix) { 24690 function fixCssUrlPaths(fileName, path, contents, cssPrefix) {
22987 return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { 24691 return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
22988 var colonIndex, parts, i, 24692 var firstChar, hasProtocol, parts, i,
22989 fixedUrlMatch = cleanCssUrlQuotes(urlMatch); 24693 fixedUrlMatch = cleanCssUrlQuotes(urlMatch);
22990 24694
22991 fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); 24695 fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/");
22992 24696
22993 //Only do the work for relative URLs. Skip things that start with / or have 24697 //Only do the work for relative URLs. Skip things that start with / or #, or have
22994 //a protocol. 24698 //a protocol.
22995 colonIndex = fixedUrlMatch.indexOf(":"); 24699 firstChar = fixedUrlMatch.charAt(0);
22996 if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { 24700 hasProtocol = protocolRegExp.test(fixedUrlMatch);
24701 if (firstChar !== "/" && firstChar !== "#" && !hasProtocol) {
22997 //It is a relative URL, tack on the cssPrefix and path prefix 24702 //It is a relative URL, tack on the cssPrefix and path prefix
22998 urlMatch = cssPrefix + path + fixedUrlMatch; 24703 urlMatch = cssPrefix + path + fixedUrlMatch;
22999 24704 } else if (!hasProtocol) {
23000 } else {
23001 logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); 24705 logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch);
23002 } 24706 }
23003 24707
23004 //Collapse .. and . 24708 //Collapse .. and .
23005 parts = urlMatch.split("/"); 24709 parts = urlMatch.split("/");
23179 } 24883 }
23180 24884
23181 optConfig = config[optimizerName] || {}; 24885 optConfig = config[optimizerName] || {};
23182 if (config.generateSourceMaps) { 24886 if (config.generateSourceMaps) {
23183 optConfig.generateSourceMaps = !!config.generateSourceMaps; 24887 optConfig.generateSourceMaps = !!config.generateSourceMaps;
24888 optConfig._buildSourceMap = config._buildSourceMap;
23184 } 24889 }
23185 24890
23186 try { 24891 try {
23187 if (config.preserveLicenseComments) { 24892 if (config.preserveLicenseComments) {
23188 //Pull out any license comments for prepending after optimization. 24893 //Pull out any license comments for prepending after optimization.
23196 fileContents = licenseContents + optFunc(fileName, 24901 fileContents = licenseContents + optFunc(fileName,
23197 fileContents, 24902 fileContents,
23198 outFileName, 24903 outFileName,
23199 keepLines, 24904 keepLines,
23200 optConfig); 24905 optConfig);
24906 if (optConfig._buildSourceMap && optConfig._buildSourceMap !== config._buildSourceMap) {
24907 config._buildSourceMap = optConfig._buildSourceMap;
24908 }
23201 } catch (e) { 24909 } catch (e) {
23202 if (config.throwWhen && config.throwWhen.optimize) { 24910 if (config.throwWhen && config.throwWhen.optimize) {
23203 throw e; 24911 throw e;
23204 } else { 24912 } else {
23205 logger.error(e); 24913 logger.error(e);
23206 } 24914 }
24915 }
24916 } else {
24917 if (config._buildSourceMap) {
24918 config._buildSourceMap = null;
23207 } 24919 }
23208 } 24920 }
23209 24921
23210 return fileContents; 24922 return fileContents;
23211 }, 24923 },
23265 fileContents = fileContents.replace(/\s\}/g, "}"); 24977 fileContents = fileContents.replace(/\s\}/g, "}");
23266 } else { 24978 } else {
23267 //Remove multiple empty lines. 24979 //Remove multiple empty lines.
23268 fileContents = fileContents.replace(/(\r\n)+/g, "\r\n"); 24980 fileContents = fileContents.replace(/(\r\n)+/g, "\r\n");
23269 fileContents = fileContents.replace(/(\n)+/g, "\n"); 24981 fileContents = fileContents.replace(/(\n)+/g, "\n");
24982 }
24983 //Remove unnecessary whitespace
24984 if (config.optimizeCss.indexOf(".keepWhitespace") === -1) {
24985 //Remove leading and trailing whitespace from lines
24986 fileContents = fileContents.replace(/^[ \t]+/gm, "");
24987 fileContents = fileContents.replace(/[ \t]+$/gm, "");
24988 //Remove whitespace after semicolon, colon, curly brackets and commas
24989 fileContents = fileContents.replace(/(;|:|\{|}|,)[ \t]+/g, "$1");
24990 //Remove whitespace before opening curly brackets
24991 fileContents = fileContents.replace(/[ \t]+(\{)/g, "$1");
24992 //Truncate double whitespace
24993 fileContents = fileContents.replace(/([ \t])+/g, "$1");
24994 //Remove empty lines
24995 fileContents = fileContents.replace(/^[ \t]*[\r\n]/gm,'');
23270 } 24996 }
23271 } catch (e) { 24997 } catch (e) {
23272 fileContents = originalFileContents; 24998 fileContents = originalFileContents;
23273 logger.error("Could not optimized CSS file: " + fileName + ", error: " + e); 24999 logger.error("Could not optimized CSS file: " + fileName + ", error: " + e);
23274 } 25000 }
23371 25097
23372 lang.mixin(uconfig, config, true); 25098 lang.mixin(uconfig, config, true);
23373 25099
23374 uconfig.fromString = true; 25100 uconfig.fromString = true;
23375 25101
23376 if (config.generateSourceMaps && outFileName) { 25102 if (config.generateSourceMaps && (outFileName || config._buildSourceMap)) {
23377 uconfig.outSourceMap = baseName; 25103 uconfig.outSourceMap = baseName;
23378 25104
23379 if (file.exists(existingMapPath)) { 25105 if (config._buildSourceMap) {
25106 existingMap = JSON.parse(config._buildSourceMap);
25107 uconfig.inSourceMap = existingMap;
25108 } else if (file.exists(existingMapPath)) {
23380 uconfig.inSourceMap = existingMapPath; 25109 uconfig.inSourceMap = existingMapPath;
23381 existingMap = JSON.parse(file.readFile(existingMapPath)); 25110 existingMap = JSON.parse(file.readFile(existingMapPath));
23382 } 25111 }
23383 } 25112 }
23384 25113
23392 if (existingMap) { 25121 if (existingMap) {
23393 resultMap = JSON.parse(resultMap); 25122 resultMap = JSON.parse(resultMap);
23394 finalMap = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(resultMap)); 25123 finalMap = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(resultMap));
23395 finalMap.applySourceMap(new SourceMapConsumer(existingMap)); 25124 finalMap.applySourceMap(new SourceMapConsumer(existingMap));
23396 resultMap = finalMap.toString(); 25125 resultMap = finalMap.toString();
23397 } else { 25126 } else if (!config._buildSourceMap) {
23398 file.saveFile(outFileName + '.src.js', fileContents); 25127 file.saveFile(outFileName + '.src.js', fileContents);
23399 } 25128 }
23400 file.saveFile(outFileName + '.map', resultMap); 25129
23401 fileContents = result.code + "\n//# sourceMappingURL=" + baseName + ".map"; 25130 fileContents = result.code;
25131
25132 if (config._buildSourceMap) {
25133 config._buildSourceMap = resultMap;
25134 } else {
25135 file.saveFile(outFileName + '.map', resultMap);
25136 fileContents += "\n//# sourceMappingURL=" + baseName + ".map";
25137 }
23402 } else { 25138 } else {
23403 fileContents = result.code; 25139 fileContents = result.code;
23404 } 25140 }
23405 } catch (e) { 25141 } catch (e) {
23406 throw new Error('Cannot uglify2 file: ' + fileName + '. Skipping it. Error is:\n' + e.toString()); 25142 throw new Error('Cannot uglify2 file: ' + fileName + '. Skipping it. Error is:\n' + e.toString());
23411 }; 25147 };
23412 25148
23413 return optimize; 25149 return optimize;
23414 }); 25150 });
23415 /** 25151 /**
23416 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 25152 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
23417 * Available via the MIT or new BSD license. 25153 * Available via the MIT or new BSD license.
23418 * see: http://github.com/jrburke/requirejs for details 25154 * see: http://github.com/jrburke/requirejs for details
23419 */ 25155 */
23420 /* 25156 /*
23421 * This file patches require.js to communicate with the build system. 25157 * This file patches require.js to communicate with the build system.
23441 25177
23442 var allowRun = true, 25178 var allowRun = true,
23443 hasProp = lang.hasProp, 25179 hasProp = lang.hasProp,
23444 falseProp = lang.falseProp, 25180 falseProp = lang.falseProp,
23445 getOwn = lang.getOwn; 25181 getOwn = lang.getOwn;
25182
25183 //Turn off throwing on resolution conflict, that was just an older prim
25184 //idea about finding errors early, but does not comply with how promises
25185 //should operate.
25186 prim.hideResolutionConflict = true;
23446 25187
23447 //This method should be called when the patches to require should take hold. 25188 //This method should be called when the patches to require should take hold.
23448 return function () { 25189 return function () {
23449 if (!allowRun) { 25190 if (!allowRun) {
23450 return; 25191 return;
23533 25274
23534 //Override the shim exports function generator to just 25275 //Override the shim exports function generator to just
23535 //spit out strings that can be used in the stringified 25276 //spit out strings that can be used in the stringified
23536 //build output. 25277 //build output.
23537 context.makeShimExports = function (value) { 25278 context.makeShimExports = function (value) {
23538 function fn() { 25279 var fn;
23539 return '(function (global) {\n' + 25280 if (context.config.wrapShim) {
23540 ' return function () {\n' + 25281 fn = function () {
23541 ' var ret, fn;\n' + 25282 var str = 'return ';
23542 (value.init ? 25283 // If specifies an export that is just a global
23543 (' fn = ' + value.init.toString() + ';\n' + 25284 // name, no dot for a `this.` and such, then also
23544 ' ret = fn.apply(global, arguments);\n') : '') + 25285 // attach to the global, for `var a = {}` files
23545 (value.exports ? 25286 // where the function closure would hide that from
23546 ' return ret || global.' + value.exports + ';\n' : 25287 // the global object.
23547 ' return ret;\n') + 25288 if (value.exports && value.exports.indexOf('.') === -1) {
23548 ' };\n' + 25289 str += 'root.' + value.exports + ' = ';
23549 '}(this))'; 25290 }
25291
25292 if (value.init) {
25293 str += '(' + value.init.toString() + '.apply(this, arguments))';
25294 }
25295 if (value.init && value.exports) {
25296 str += ' || ';
25297 }
25298 if (value.exports) {
25299 str += value.exports;
25300 }
25301 str += ';';
25302 return str;
25303 };
25304 } else {
25305 fn = function () {
25306 return '(function (global) {\n' +
25307 ' return function () {\n' +
25308 ' var ret, fn;\n' +
25309 (value.init ?
25310 (' fn = ' + value.init.toString() + ';\n' +
25311 ' ret = fn.apply(global, arguments);\n') : '') +
25312 (value.exports ?
25313 ' return ret || global.' + value.exports + ';\n' :
25314 ' return ret;\n') +
25315 ' };\n' +
25316 '}(this))';
25317 };
23550 } 25318 }
23551 25319
23552 return fn; 25320 return fn;
23553 }; 25321 };
23554 25322
23559 fullExec = context.fullExec, 25327 fullExec = context.fullExec,
23560 mod = getOwn(context.registry, id); 25328 mod = getOwn(context.registry, id);
23561 25329
23562 if (mod && !mod.defined) { 25330 if (mod && !mod.defined) {
23563 if (parentId && getOwn(needFullExec, parentId)) { 25331 if (parentId && getOwn(needFullExec, parentId)) {
23564 needFullExec[id] = true; 25332 needFullExec[id] = depMap;
23565 } 25333 }
23566 25334
23567 } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) || 25335 } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) ||
23568 (parentId && getOwn(needFullExec, parentId) && 25336 (parentId && getOwn(needFullExec, parentId) &&
23569 falseProp(fullExec, id))) { 25337 falseProp(fullExec, id))) {
23764 pluginMap = context.makeModuleMap(map.prefix), 25532 pluginMap = context.makeModuleMap(map.prefix),
23765 pluginId = pluginMap.id, 25533 pluginId = pluginMap.id,
23766 pluginMod = getOwn(context.registry, pluginId); 25534 pluginMod = getOwn(context.registry, pluginId);
23767 25535
23768 context.plugins[pluginId] = true; 25536 context.plugins[pluginId] = true;
23769 context.needFullExec[pluginId] = true; 25537 context.needFullExec[pluginId] = map;
23770 25538
23771 //If the module is not waiting to finish being defined, 25539 //If the module is not waiting to finish being defined,
23772 //undef it and start over, to get full execution. 25540 //undef it and start over, to get full execution.
23773 if (falseProp(context.fullExec, pluginId) && (!pluginMod || pluginMod.defined)) { 25541 if (falseProp(context.fullExec, pluginId) && (!pluginMod || pluginMod.defined)) {
23774 context.require.undef(pluginMap.id); 25542 context.require.undef(pluginMap.id);
23841 //what order of execution. 25609 //what order of execution.
23842 require.onResourceLoad = function (context, map) { 25610 require.onResourceLoad = function (context, map) {
23843 var id = map.id, 25611 var id = map.id,
23844 url; 25612 url;
23845 25613
25614 // Fix up any maps that need to be normalized as part of the fullExec
25615 // plumbing for plugins to participate in the build.
25616 if (context.plugins && lang.hasProp(context.plugins, id)) {
25617 lang.eachProp(context.needFullExec, function(value, prop) {
25618 // For plugin entries themselves, they do not have a map
25619 // value in needFullExec, just a "true" entry.
25620 if (value !== true && value.prefix === id && value.unnormalized) {
25621 var map = context.makeModuleMap(value.originalName, value.parentMap);
25622 context.needFullExec[map.id] = map;
25623 }
25624 });
25625 }
25626
23846 //If build needed a full execution, indicate it 25627 //If build needed a full execution, indicate it
23847 //has been done now. But only do it if the context is tracking 25628 //has been done now. But only do it if the context is tracking
23848 //that. Only valid for the context used in a build, not for 25629 //that. Only valid for the context used in a build, not for
23849 //other contexts being run, like for useLib, plain requirejs 25630 //other contexts being run, like for useLib, plain requirejs
23850 //use in node/rhino. 25631 //use in node/rhino.
23851 if (context.needFullExec && getOwn(context.needFullExec, id)) { 25632 if (context.needFullExec && getOwn(context.needFullExec, id)) {
23852 context.fullExec[id] = true; 25633 context.fullExec[id] = map;
23853 } 25634 }
23854 25635
23855 //A plugin. 25636 //A plugin.
23856 if (map.prefix) { 25637 if (map.prefix) {
23857 if (falseProp(layer.pathAdded, id)) { 25638 if (falseProp(layer.pathAdded, id)) {
23883 layer.needsDefine[moduleName] = true; 25664 layer.needsDefine[moduleName] = true;
23884 }; 25665 };
23885 }; 25666 };
23886 }); 25667 });
23887 /** 25668 /**
23888 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 25669 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
23889 * Available via the MIT or new BSD license. 25670 * Available via the MIT or new BSD license.
23890 * see: http://github.com/jrburke/requirejs for details 25671 * see: http://github.com/jrburke/requirejs for details
23891 */ 25672 */
23892 25673
23893 /*jslint */ 25674 /*jslint */
23987 }; 25768 };
23988 25769
23989 return commonJs; 25770 return commonJs;
23990 }); 25771 });
23991 /** 25772 /**
23992 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 25773 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
23993 * Available via the MIT or new BSD license. 25774 * Available via the MIT or new BSD license.
23994 * see: http://github.com/jrburke/requirejs for details 25775 * see: http://github.com/jrburke/requirejs for details
23995 */ 25776 */
23996 25777
23997 /*jslint plusplus: true, nomen: true, regexp: true */ 25778 /*jslint plusplus: true, nomen: true, regexp: true */
23998 /*global define, requirejs */ 25779 /*global define, requirejs, java, process, console */
23999 25780
24000 25781
24001 define('build', function (require) { 25782 define('build', function (require) {
24002 'use strict'; 25783 'use strict';
24003 25784
24004 var build, buildBaseConfig, 25785 var build,
24005 lang = require('lang'), 25786 lang = require('lang'),
24006 prim = require('prim'), 25787 prim = require('prim'),
24007 logger = require('logger'), 25788 logger = require('logger'),
24008 file = require('env!env/file'), 25789 file = require('env!env/file'),
24009 parse = require('parse'), 25790 parse = require('parse'),
24016 SourceMapGenerator = require('source-map/source-map-generator'), 25797 SourceMapGenerator = require('source-map/source-map-generator'),
24017 hasProp = lang.hasProp, 25798 hasProp = lang.hasProp,
24018 getOwn = lang.getOwn, 25799 getOwn = lang.getOwn,
24019 falseProp = lang.falseProp, 25800 falseProp = lang.falseProp,
24020 endsWithSemiColonRegExp = /;\s*$/, 25801 endsWithSemiColonRegExp = /;\s*$/,
25802 endsWithSlashRegExp = /[\/\\]$/,
24021 resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/; 25803 resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/;
24022 25804
24023 prim.nextTick = function (fn) { 25805 prim.nextTick = function (fn) {
24024 fn(); 25806 fn();
24025 }; 25807 };
24045 return text; 25827 return text;
24046 }); 25828 });
24047 } 25829 }
24048 }; 25830 };
24049 25831
24050 buildBaseConfig = { 25832 function makeBuildBaseConfig() {
24051 appDir: "", 25833 return {
24052 pragmas: {}, 25834 appDir: "",
24053 paths: {}, 25835 pragmas: {},
24054 optimize: "uglify", 25836 paths: {},
24055 optimizeCss: "standard.keepLines", 25837 optimize: "uglify",
24056 inlineText: true, 25838 optimizeCss: "standard.keepLines.keepWhitespace",
24057 isBuild: true, 25839 inlineText: true,
24058 optimizeAllPluginResources: false, 25840 isBuild: true,
24059 findNestedDependencies: false, 25841 optimizeAllPluginResources: false,
24060 preserveLicenseComments: true, 25842 findNestedDependencies: false,
24061 //By default, all files/directories are copied, unless 25843 preserveLicenseComments: true,
24062 //they match this regexp, by default just excludes .folders 25844 //By default, all files/directories are copied, unless
24063 dirExclusionRegExp: file.dirExclusionRegExp, 25845 //they match this regexp, by default just excludes .folders
24064 _buildPathToModuleIndex: {} 25846 dirExclusionRegExp: file.dirExclusionRegExp,
24065 }; 25847 _buildPathToModuleIndex: {}
25848 };
25849 }
24066 25850
24067 /** 25851 /**
24068 * Some JS may not be valid if concatenated with other JS, in particular 25852 * Some JS may not be valid if concatenated with other JS, in particular
24069 * the style of omitting semicolons and rely on ASI. Add a semicolon in 25853 * the style of omitting semicolons and rely on ASI. Add a semicolon in
24070 * those cases. 25854 * those cases.
24332 26116
24333 if (modules) { 26117 if (modules) {
24334 modules.forEach(function (module) { 26118 modules.forEach(function (module) {
24335 if (module.name) { 26119 if (module.name) {
24336 module._buildPath = buildContext.nameToUrl(module.name, null); 26120 module._buildPath = buildContext.nameToUrl(module.name, null);
26121
26122 //If buildPath and sourcePath are the same, throw since this
26123 //would result in modifying source. This condition can happen
26124 //with some more tricky paths: config and appDir/baseUrl
26125 //setting, which is a sign of incorrect config.
26126 if (module._buildPath === module._sourcePath) {
26127 throw new Error('Module ID \'' + module.name +
26128 '\' has a source path that is same as output path: ' +
26129 module._sourcePath +
26130 '. Stopping, config is malformed.');
26131 }
26132
24337 if (!module.create) { 26133 if (!module.create) {
24338 file.copyFile(module._sourcePath, module._buildPath); 26134 file.copyFile(module._sourcePath, module._buildPath);
24339 } 26135 }
24340 } 26136 }
24341 }); 26137 });
24454 }); 26250 });
24455 }; 26251 };
24456 })); 26252 }));
24457 } 26253 }
24458 }).then(function () { 26254 }).then(function () {
24459 var moduleName; 26255 var moduleName, outOrigSourceMap;
24460 if (modules) { 26256 if (modules) {
24461 //Now move the build layers to their final position. 26257 //Now move the build layers to their final position.
24462 modules.forEach(function (module) { 26258 modules.forEach(function (module) {
24463 var finalPath = module._buildPath; 26259 var finalPath = module._buildPath;
24464 if (finalPath !== 'FUNCTION') { 26260 if (finalPath !== 'FUNCTION') {
24504 //Do other optimizations. 26300 //Do other optimizations.
24505 if (config.out && !config.cssIn) { 26301 if (config.out && !config.cssIn) {
24506 //Just need to worry about one JS file. 26302 //Just need to worry about one JS file.
24507 fileName = config.modules[0]._buildPath; 26303 fileName = config.modules[0]._buildPath;
24508 if (fileName === 'FUNCTION') { 26304 if (fileName === 'FUNCTION') {
24509 config.modules[0]._buildText = optimize.js(fileName, 26305 outOrigSourceMap = config.modules[0]._buildSourceMap;
26306 config._buildSourceMap = outOrigSourceMap;
26307 config.modules[0]._buildText = optimize.js((config.modules[0].name ||
26308 config.modules[0].include[0] ||
26309 fileName) + '.build.js',
24510 config.modules[0]._buildText, 26310 config.modules[0]._buildText,
24511 null, 26311 null,
24512 config); 26312 config);
26313 if (config._buildSourceMap && config._buildSourceMap !== outOrigSourceMap) {
26314 config.modules[0]._buildSourceMap = config._buildSourceMap;
26315 config._buildSourceMap = null;
26316 }
24513 } else { 26317 } else {
24514 optimize.jsFile(fileName, null, fileName, config); 26318 optimize.jsFile(fileName, null, fileName, config);
24515 } 26319 }
24516 } else if (!config.cssIn) { 26320 } else if (!config.cssIn) {
24517 //Normal optimizations across modules. 26321 //Normal optimizations across modules.
24658 if (config.cssIn) { 26462 if (config.cssIn) {
24659 buildFileContents += optimize.cssFile(config.cssIn, config.out, config).buildText; 26463 buildFileContents += optimize.cssFile(config.cssIn, config.out, config).buildText;
24660 } 26464 }
24661 26465
24662 if (typeof config.out === 'function') { 26466 if (typeof config.out === 'function') {
24663 config.out(config.modules[0]._buildText); 26467 config.out(config.modules[0]._buildText, config.modules[0]._buildSourceMap);
24664 } 26468 }
24665 26469
24666 //Print out what was built into which layers. 26470 //Print out what was built into which layers.
24667 if (buildFileContents) { 26471 if (buildFileContents) {
24668 logger.info(buildFileContents); 26472 logger.info(buildFileContents);
24828 26632
24829 config[prop] = endsWithSlash(config[prop]); 26633 config[prop] = endsWithSlash(config[prop]);
24830 } 26634 }
24831 } 26635 }
24832 26636
24833 build.makeAbsObject(["out", "cssIn"], config, absFilePath); 26637 build.makeAbsObject((config.out === "stdout" ? ["cssIn"] : ["out", "cssIn"]),
26638 config, absFilePath);
24834 build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath); 26639 build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath);
24835 }; 26640 };
24836 26641
24837 /** 26642 /**
24838 * Creates a relative path to targetPath from refPath. 26643 * Creates a relative path to targetPath from refPath.
24839 * Only deals with file paths, not folders. If folders, 26644 * Only deals with file paths, not folders. If folders,
24840 * make sure paths end in a trailing '/'. 26645 * make sure paths end in a trailing '/'.
24841 */ 26646 */
24842 build.makeRelativeFilePath = function (refPath, targetPath) { 26647 build.makeRelativeFilePath = function (refPath, targetPath) {
24843 var i, dotLength, finalParts, length, 26648 var i, dotLength, finalParts, length, targetParts, targetName,
24844 refParts = refPath.split('/'), 26649 refParts = refPath.split('/'),
24845 targetParts = targetPath.split('/'), 26650 hasEndSlash = endsWithSlashRegExp.test(targetPath),
24846 //Pull off file name
24847 targetName = targetParts.pop(),
24848 dotParts = []; 26651 dotParts = [];
26652
26653 targetPath = file.normalize(targetPath);
26654 if (hasEndSlash && !endsWithSlashRegExp.test(targetPath)) {
26655 targetPath += '/';
26656 }
26657 targetParts = targetPath.split('/');
26658 //Pull off file name
26659 targetName = targetParts.pop();
24849 26660
24850 //Also pop off the ref file name to make the matches against 26661 //Also pop off the ref file name to make the matches against
24851 //targetParts equivalent. 26662 //targetParts equivalent.
24852 refParts.pop(); 26663 refParts.pop();
24853 26664
24882 26693
24883 /** 26694 /**
24884 * Mixes additional source config into target config, and merges some 26695 * Mixes additional source config into target config, and merges some
24885 * nested config, like paths, correctly. 26696 * nested config, like paths, correctly.
24886 */ 26697 */
24887 function mixConfig(target, source) { 26698 function mixConfig(target, source, skipArrays) {
24888 var prop, value; 26699 var prop, value, isArray, targetValue;
24889 26700
24890 for (prop in source) { 26701 for (prop in source) {
24891 if (hasProp(source, prop)) { 26702 if (hasProp(source, prop)) {
24892 //If the value of the property is a plain object, then 26703 //If the value of the property is a plain object, then
24893 //allow a one-level-deep mixing of it. 26704 //allow a one-level-deep mixing of it.
24894 value = source[prop]; 26705 value = source[prop];
26706 isArray = lang.isArray(value);
24895 if (typeof value === 'object' && value && 26707 if (typeof value === 'object' && value &&
24896 !lang.isArray(value) && !lang.isFunction(value) && 26708 !isArray && !lang.isFunction(value) &&
24897 !lang.isRegExp(value)) { 26709 !lang.isRegExp(value)) {
24898 target[prop] = lang.mixin({}, target[prop], value, true); 26710
26711 // TODO: need to generalize this work, maybe also reuse
26712 // the work done in requirejs configure, perhaps move to
26713 // just a deep copy/merge overall. However, given the
26714 // amount of observable change, wait for a dot release.
26715 // This change is in relation to #645
26716 if (prop === 'map') {
26717 if (!target.map) {
26718 target.map = {};
26719 }
26720 lang.deepMix(target.map, source.map);
26721 } else {
26722 target[prop] = lang.mixin({}, target[prop], value, true);
26723 }
26724 } else if (isArray) {
26725 if (!skipArrays) {
26726 // Some config, like packages, are arrays. For those,
26727 // just merge the results.
26728 targetValue = target[prop];
26729 if (lang.isArray(targetValue)) {
26730 target[prop] = targetValue.concat(value);
26731 } else {
26732 target[prop] = value;
26733 }
26734 }
24899 } else { 26735 } else {
24900 target[prop] = value; 26736 target[prop] = value;
24901 } 26737 }
24902 } 26738 }
24903 } 26739 }
24964 * 26800 *
24965 * @param {Object} the created config object. 26801 * @param {Object} the created config object.
24966 */ 26802 */
24967 build.createConfig = function (cfg) { 26803 build.createConfig = function (cfg) {
24968 /*jslint evil: true */ 26804 /*jslint evil: true */
24969 var config = {}, buildFileContents, buildFileConfig, mainConfig, 26805 var buildFileContents, buildFileConfig, mainConfig,
24970 mainConfigFile, mainConfigPath, buildFile, absFilePath; 26806 mainConfigFile, mainConfigPath, buildFile, absFilePath,
26807 config = {},
26808 buildBaseConfig = makeBuildBaseConfig();
24971 26809
24972 //Make sure all paths are relative to current directory. 26810 //Make sure all paths are relative to current directory.
24973 absFilePath = file.absPath('.'); 26811 absFilePath = file.absPath('.');
24974 build.makeAbsConfig(cfg, absFilePath); 26812 build.makeAbsConfig(cfg, absFilePath);
24975 build.makeAbsConfig(buildBaseConfig, absFilePath); 26813 build.makeAbsConfig(buildBaseConfig, absFilePath);
25012 } 26850 }
25013 } 26851 }
25014 26852
25015 mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile); 26853 mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile);
25016 if (mainConfigFile) { 26854 if (mainConfigFile) {
25017 mainConfigFile = build.makeAbsPath(mainConfigFile, absFilePath); 26855 if (typeof mainConfigFile === 'string') {
25018 if (!file.exists(mainConfigFile)) { 26856 mainConfigFile = [mainConfigFile];
25019 throw new Error(mainConfigFile + ' does not exist.'); 26857 }
25020 } 26858
25021 try { 26859 mainConfigFile.forEach(function (configFile) {
25022 mainConfig = parse.findConfig(file.readFile(mainConfigFile)).config; 26860 configFile = build.makeAbsPath(configFile, absFilePath);
25023 } catch (configError) { 26861 if (!file.exists(configFile)) {
25024 throw new Error('The config in mainConfigFile ' + 26862 throw new Error(configFile + ' does not exist.');
25025 mainConfigFile + 26863 }
25026 ' cannot be used because it cannot be evaluated' + 26864 try {
25027 ' correctly while running in the optimizer. Try only' + 26865 mainConfig = parse.findConfig(file.readFile(configFile)).config;
25028 ' using a config that is also valid JSON, or do not use' + 26866 } catch (configError) {
25029 ' mainConfigFile and instead copy the config values needed' + 26867 throw new Error('The config in mainConfigFile ' +
25030 ' into a build file or command line arguments given to the optimizer.\n' + 26868 configFile +
25031 'Source error from parsing: ' + mainConfigFile + ': ' + configError); 26869 ' cannot be used because it cannot be evaluated' +
25032 } 26870 ' correctly while running in the optimizer. Try only' +
25033 if (mainConfig) { 26871 ' using a config that is also valid JSON, or do not use' +
25034 mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/')); 26872 ' mainConfigFile and instead copy the config values needed' +
25035 26873 ' into a build file or command line arguments given to the optimizer.\n' +
25036 //Add in some existing config, like appDir, since they can be 26874 'Source error from parsing: ' + configFile + ': ' + configError);
25037 //used inside the mainConfigFile -- paths and baseUrl are 26875 }
25038 //relative to them. 26876 if (mainConfig) {
25039 if (config.appDir && !mainConfig.appDir) { 26877 mainConfigPath = configFile.substring(0, configFile.lastIndexOf('/'));
25040 mainConfig.appDir = config.appDir; 26878
25041 } 26879 //Add in some existing config, like appDir, since they can be
25042 26880 //used inside the configFile -- paths and baseUrl are
25043 //If no baseUrl, then use the directory holding the main config. 26881 //relative to them.
25044 if (!mainConfig.baseUrl) { 26882 if (config.appDir && !mainConfig.appDir) {
25045 mainConfig.baseUrl = mainConfigPath; 26883 mainConfig.appDir = config.appDir;
25046 } 26884 }
25047 26885
25048 build.makeAbsConfig(mainConfig, mainConfigPath); 26886 //If no baseUrl, then use the directory holding the main config.
25049 mixConfig(config, mainConfig); 26887 if (!mainConfig.baseUrl) {
25050 } 26888 mainConfig.baseUrl = mainConfigPath;
26889 }
26890
26891 build.makeAbsConfig(mainConfig, mainConfigPath);
26892 mixConfig(config, mainConfig);
26893 }
26894 });
25051 } 26895 }
25052 26896
25053 //Mix in build file config, but only after mainConfig has been mixed in. 26897 //Mix in build file config, but only after mainConfig has been mixed in.
26898 //Since this is a re-application, skip array merging.
25054 if (buildFileConfig) { 26899 if (buildFileConfig) {
25055 mixConfig(config, buildFileConfig); 26900 mixConfig(config, buildFileConfig, true);
25056 } 26901 }
25057 26902
25058 //Re-apply the override config values. Command line 26903 //Re-apply the override config values. Command line
25059 //args should take precedence over build file values. 26904 //args should take precedence over build file values.
25060 mixConfig(config, cfg); 26905 //Since this is a re-application, skip array merging.
26906 mixConfig(config, cfg, true);
25061 26907
25062 //Fix paths to full paths so that they can be adjusted consistently 26908 //Fix paths to full paths so that they can be adjusted consistently
25063 //lately to be in the output area. 26909 //lately to be in the output area.
25064 lang.eachProp(config.paths, function (value, prop) { 26910 lang.eachProp(config.paths, function (value, prop) {
25065 if (lang.isArray(value)) { 26911 if (lang.isArray(value)) {
25071 }); 26917 });
25072 26918
25073 //Set final output dir 26919 //Set final output dir
25074 if (hasProp(config, "baseUrl")) { 26920 if (hasProp(config, "baseUrl")) {
25075 if (config.appDir) { 26921 if (config.appDir) {
26922 if (!config.originalBaseUrl) {
26923 throw new Error('Please set a baseUrl in the build config');
26924 }
25076 config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir); 26925 config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir);
25077 } else { 26926 } else {
25078 config.dirBaseUrl = config.dir || config.baseUrl; 26927 config.dirBaseUrl = config.dir || config.baseUrl;
25079 } 26928 }
25080 //Make sure dirBaseUrl ends in a slash, since it is 26929 //Make sure dirBaseUrl ends in a slash, since it is
25081 //concatenated with other strings. 26930 //concatenated with other strings.
25082 config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); 26931 config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
26932 }
26933
26934
26935 //If out=stdout, write output to STDOUT instead of a file.
26936 if (config.out && config.out === 'stdout') {
26937 config.out = function (content) {
26938 var e = env.get();
26939 if (e === 'rhino') {
26940 var out = new java.io.PrintStream(java.lang.System.out, true, 'UTF-8');
26941 out.println(content);
26942 } else if (e === 'node') {
26943 process.stdout.setEncoding('utf8');
26944 process.stdout.write(content);
26945 } else {
26946 console.log(content);
26947 }
26948 };
25083 } 26949 }
25084 26950
25085 //Check for errors in config 26951 //Check for errors in config
25086 if (config.main) { 26952 if (config.main) {
25087 throw new Error('"main" passed as an option, but the ' + 26953 throw new Error('"main" passed as an option, but the ' +
25117 'where "out" with "baseUrl" is used to just ' + 26983 'where "out" with "baseUrl" is used to just ' +
25118 'optimize to one file.'); 26984 'optimize to one file.');
25119 } 26985 }
25120 if (config.out && config.dir) { 26986 if (config.out && config.dir) {
25121 throw new Error('The "out" and "dir" options are incompatible.' + 26987 throw new Error('The "out" and "dir" options are incompatible.' +
25122 ' Use "out" if you are targeting a single file for' + 26988 ' Use "out" if you are targeting a single file' +
25123 ' for optimization, and "dir" if you want the appDir' + 26989 ' for optimization, and "dir" if you want the appDir' +
25124 ' or baseUrl directories optimized.'); 26990 ' or baseUrl directories optimized.');
25125 } 26991 }
25126 26992
25127 if (config.dir) { 26993 if (config.dir) {
25128 // Make sure the output dir is not set to a parent of the 26994 // Make sure the output dir is not set to a parent of the
25129 // source dir or the same dir, as it will result in source 26995 // source dir or the same dir, as it will result in source
25130 // code deletion. 26996 // code deletion.
25131 if (config.dir === config.baseUrl || 26997 if (!config.allowSourceOverwrites && (config.dir === config.baseUrl ||
25132 config.dir === config.appDir || 26998 config.dir === config.appDir ||
25133 (config.baseUrl && build.makeRelativeFilePath(config.dir, 26999 (config.baseUrl && build.makeRelativeFilePath(config.dir,
25134 config.baseUrl).indexOf('..') !== 0) || 27000 config.baseUrl).indexOf('..') !== 0) ||
25135 (config.appDir && 27001 (config.appDir &&
25136 build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0)) { 27002 build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0))) {
25137 throw new Error('"dir" is set to a parent or same directory as' + 27003 throw new Error('"dir" is set to a parent or same directory as' +
25138 ' "appDir" or "baseUrl". This can result in' + 27004 ' "appDir" or "baseUrl". This can result in' +
25139 ' the deletion of source code. Stopping.'); 27005 ' the deletion of source code. Stopping. If' +
27006 ' you want to allow possible overwriting of' +
27007 ' source code, set "allowSourceOverwrites"' +
27008 ' to true in the build config, but do so at' +
27009 ' your own risk. In that case, you may want' +
27010 ' to also set "keepBuildDir" to true.');
25140 } 27011 }
25141 } 27012 }
25142 27013
25143 if (config.insertRequire && !lang.isArray(config.insertRequire)) { 27014 if (config.insertRequire && !lang.isArray(config.insertRequire)) {
25144 throw new Error('insertRequire should be a list of module IDs' + 27015 throw new Error('insertRequire should be a list of module IDs' +
25212 config.cssPrefix = endsWithSlash(config.cssPrefix); 27083 config.cssPrefix = endsWithSlash(config.cssPrefix);
25213 } else { 27084 } else {
25214 config.cssPrefix = ''; 27085 config.cssPrefix = '';
25215 } 27086 }
25216 27087
25217 //Cycle through modules and combine any local stubModules with 27088 //Cycle through modules and normalize
25218 //global values.
25219 if (config.modules && config.modules.length) { 27089 if (config.modules && config.modules.length) {
25220 config.modules.forEach(function (mod) { 27090 config.modules.forEach(function (mod) {
27091
27092 //Combine any local stubModules with global values.
25221 if (config.stubModules) { 27093 if (config.stubModules) {
25222 mod.stubModules = config.stubModules.concat(mod.stubModules || []); 27094 mod.stubModules = config.stubModules.concat(mod.stubModules || []);
25223 } 27095 }
25224 27096
25225 //Create a hash lookup for the stubModules config to make lookup 27097 //Create a hash lookup for the stubModules config to make lookup
25229 mod.stubModules.forEach(function (id) { 27101 mod.stubModules.forEach(function (id) {
25230 mod.stubModules._byName[id] = true; 27102 mod.stubModules._byName[id] = true;
25231 }); 27103 });
25232 } 27104 }
25233 27105
27106 // Legacy command support, which allowed a single string ID
27107 // for include.
27108 if (typeof mod.include === 'string') {
27109 mod.include = [mod.include];
27110 }
27111
25234 //Allow wrap config in overrides, but normalize it. 27112 //Allow wrap config in overrides, but normalize it.
25235 if (mod.override) { 27113 if (mod.override) {
25236 normalizeWrapConfig(mod.override, absFilePath); 27114 normalizeWrapConfig(mod.override, absFilePath);
25237 } 27115 }
25238 }); 27116 });
25269 //name for fileExclusionRegExp before 1.0.2. Support for backwards 27147 //name for fileExclusionRegExp before 1.0.2. Support for backwards
25270 //compatibility 27148 //compatibility
25271 file.exclusionRegExp = config.dirExclusionRegExp; 27149 file.exclusionRegExp = config.dirExclusionRegExp;
25272 } 27150 }
25273 27151
27152 //Track the deps, but in a different key, so that they are not loaded
27153 //as part of config seeding before all config is in play (#648). Was
27154 //going to merge this in with "include", but include is added after
27155 //the "name" target. To preserve what r.js has done previously, make
27156 //sure "deps" comes before the "name".
27157 if (config.deps) {
27158 config._depsInclude = config.deps;
27159 }
27160
27161
25274 //Remove things that may cause problems in the build. 27162 //Remove things that may cause problems in the build.
27163 //deps already merged above
27164 delete config.deps;
25275 delete config.jQuery; 27165 delete config.jQuery;
25276 delete config.enforceDefine; 27166 delete config.enforceDefine;
25277 delete config.urlArgs; 27167 delete config.urlArgs;
25278 27168
25279 return config; 27169 return config;
25346 require(lang.deeplikeCopy(baseLoaderConfig)); 27236 require(lang.deeplikeCopy(baseLoaderConfig));
25347 } 27237 }
25348 27238
25349 logger.trace("\nTracing dependencies for: " + (module.name || 27239 logger.trace("\nTracing dependencies for: " + (module.name ||
25350 (typeof module.out === 'function' ? 'FUNCTION' : module.out))); 27240 (typeof module.out === 'function' ? 'FUNCTION' : module.out)));
25351 include = module.name && !module.create ? [module.name] : []; 27241 include = config._depsInclude || [];
27242 include = include.concat(module.name && !module.create ? [module.name] : []);
25352 if (module.include) { 27243 if (module.include) {
25353 include = include.concat(module.include); 27244 include = include.concat(module.include);
25354 } 27245 }
25355 27246
25356 //If there are overrides to basic config, set that up now.; 27247 //If there are overrides to basic config, set that up now.;
25423 }; 27314 };
25424 27315
25425 build.checkForErrors = function (context) { 27316 build.checkForErrors = function (context) {
25426 //Check to see if it all loaded. If not, then throw, and give 27317 //Check to see if it all loaded. If not, then throw, and give
25427 //a message on what is left. 27318 //a message on what is left.
25428 var id, prop, mod, idParts, pluginId, 27319 var id, prop, mod, idParts, pluginId, pluginResources,
25429 errMessage = '', 27320 errMessage = '',
25430 failedPluginMap = {}, 27321 failedPluginMap = {},
25431 failedPluginIds = [], 27322 failedPluginIds = [],
25432 errIds = [], 27323 errIds = [],
25433 errUrlMap = {}, 27324 errUrlMap = {},
25436 hasUndefined = false, 27327 hasUndefined = false,
25437 defined = context.defined, 27328 defined = context.defined,
25438 registry = context.registry; 27329 registry = context.registry;
25439 27330
25440 function populateErrUrlMap(id, errUrl, skipNew) { 27331 function populateErrUrlMap(id, errUrl, skipNew) {
27332 // Loader plugins do not have an errUrl, so skip them.
27333 if (!errUrl) {
27334 return;
27335 }
27336
25441 if (!skipNew) { 27337 if (!skipNew) {
25442 errIds.push(id); 27338 errIds.push(id);
25443 } 27339 }
25444 27340
25445 if (errUrlMap[errUrl]) { 27341 if (errUrlMap[errUrl]) {
25459 27355
25460 for (id in registry) { 27356 for (id in registry) {
25461 if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { 27357 if (hasProp(registry, id) && id.indexOf('_@r') !== 0) {
25462 hasUndefined = true; 27358 hasUndefined = true;
25463 mod = getOwn(registry, id); 27359 mod = getOwn(registry, id);
27360 idParts = id.split('!');
27361 pluginId = idParts[0];
25464 27362
25465 if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { 27363 if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) {
25466 populateErrUrlMap(id, mod.map.url); 27364 populateErrUrlMap(id, mod.map.url);
25467 } 27365 }
25468 27366
25469 //Look for plugins that did not call load() 27367 //Look for plugins that did not call load()
25470 idParts = id.split('!'); 27368
25471 pluginId = idParts[0]; 27369 if (idParts.length > 1) {
25472 if (idParts.length > 1 && falseProp(failedPluginMap, pluginId)) { 27370 if (falseProp(failedPluginMap, pluginId)) {
25473 failedPluginIds.push(pluginId); 27371 failedPluginIds.push(pluginId);
25474 failedPluginMap[pluginId] = true; 27372 }
27373 pluginResources = failedPluginMap[pluginId];
27374 if (!pluginResources) {
27375 pluginResources = failedPluginMap[pluginId] = [];
27376 }
27377 pluginResources.push(id + (mod.error ? ': ' + mod.error : ''));
25475 } 27378 }
25476 } 27379 }
25477 } 27380 }
25478 27381
25479 // If have some modules that are not defined/stuck in the registry, 27382 // If have some modules that are not defined/stuck in the registry,
25489 if (errIds.length || failedPluginIds.length) { 27392 if (errIds.length || failedPluginIds.length) {
25490 if (failedPluginIds.length) { 27393 if (failedPluginIds.length) {
25491 errMessage += 'Loader plugin' + 27394 errMessage += 'Loader plugin' +
25492 (failedPluginIds.length === 1 ? '' : 's') + 27395 (failedPluginIds.length === 1 ? '' : 's') +
25493 ' did not call ' + 27396 ' did not call ' +
25494 'the load callback in the build: ' + 27397 'the load callback in the build:\n' +
25495 failedPluginIds.join(', ') + '\n'; 27398 failedPluginIds.map(function (pluginId) {
27399 var pluginResources = failedPluginMap[pluginId];
27400 return pluginId + ':\n ' + pluginResources.join('\n ');
27401 }).join('\n') + '\n';
25496 } 27402 }
25497 errMessage += 'Module loading did not complete for: ' + errIds.join(', '); 27403 errMessage += 'Module loading did not complete for: ' + errIds.join(', ');
25498 27404
25499 if (hasErrUrl) { 27405 if (hasErrUrl) {
25500 errMessage += '\nThe following modules share the same URL. This ' + 27406 errMessage += '\nThe following modules share the same URL. This ' +
25548 var fileContents, sourceMapGenerator, 27454 var fileContents, sourceMapGenerator,
25549 sourceMapBase, 27455 sourceMapBase,
25550 buildFileContents = ''; 27456 buildFileContents = '';
25551 27457
25552 return prim().start(function () { 27458 return prim().start(function () {
25553 var reqIndex, currContents, 27459 var reqIndex, currContents, fileForSourceMap,
25554 moduleName, shim, packageConfig, nonPackageName, 27460 moduleName, shim, packageMain, packageName,
25555 parts, builder, writeApi, 27461 parts, builder, writeApi,
25556 namespace, namespaceWithDot, stubModulesByName, 27462 namespace, namespaceWithDot, stubModulesByName,
25557 context = layer.context, 27463 context = layer.context,
25558 onLayerEnds = [], 27464 onLayerEnds = [],
25559 onLayerEndAdded = {}; 27465 onLayerEndAdded = {};
25588 } 27494 }
25589 } 27495 }
25590 27496
25591 if (config.generateSourceMaps) { 27497 if (config.generateSourceMaps) {
25592 sourceMapBase = config.dir || config.baseUrl; 27498 sourceMapBase = config.dir || config.baseUrl;
27499 fileForSourceMap = module._buildPath === 'FUNCTION' ?
27500 (module.name || module.include[0] || 'FUNCTION') + '.build.js' :
27501 module._buildPath.replace(sourceMapBase, '');
25593 sourceMapGenerator = new SourceMapGenerator.SourceMapGenerator({ 27502 sourceMapGenerator = new SourceMapGenerator.SourceMapGenerator({
25594 file: module._buildPath.replace(sourceMapBase, '') 27503 file: fileForSourceMap
25595 }); 27504 });
25596 } 27505 }
25597 27506
25598 //Write the built module to disk, and build up the build output. 27507 //Write the built module to disk, and build up the build output.
25599 fileContents = ""; 27508 fileContents = "";
25601 return function () { 27510 return function () {
25602 var lineCount, 27511 var lineCount,
25603 singleContents = ''; 27512 singleContents = '';
25604 27513
25605 moduleName = layer.buildFileToModule[path]; 27514 moduleName = layer.buildFileToModule[path];
27515 packageName = moduleName.split('/').shift();
27516
25606 //If the moduleName is for a package main, then update it to the 27517 //If the moduleName is for a package main, then update it to the
25607 //real main value. 27518 //real main value.
25608 packageConfig = layer.context.config.pkgs && 27519 packageMain = layer.context.config.pkgs &&
25609 getOwn(layer.context.config.pkgs, moduleName); 27520 getOwn(layer.context.config.pkgs, packageName);
25610 if (packageConfig) { 27521 if (packageMain !== moduleName) {
25611 nonPackageName = moduleName; 27522 // Not a match, clear packageMain
25612 moduleName += '/' + packageConfig.main; 27523 packageMain = undefined;
25613 } 27524 }
25614 27525
25615 return prim().start(function () { 27526 return prim().start(function () {
25616 //Figure out if the module is a result of a build plugin, and if so, 27527 //Figure out if the module is a result of a build plugin, and if so,
25617 //then delegate to that plugin. 27528 //then delegate to that plugin.
25670 27581
25671 if (config.onBuildRead) { 27582 if (config.onBuildRead) {
25672 currContents = config.onBuildRead(moduleName, path, currContents); 27583 currContents = config.onBuildRead(moduleName, path, currContents);
25673 } 27584 }
25674 27585
25675 if (packageConfig) { 27586 if (packageMain) {
25676 hasPackageName = (nonPackageName === parse.getNamedDefine(currContents)); 27587 hasPackageName = (packageName === parse.getNamedDefine(currContents));
25677 } 27588 }
25678 27589
25679 if (namespace) { 27590 if (namespace) {
25680 currContents = pragma.namespace(currContents, namespace); 27591 currContents = pragma.namespace(currContents, namespace);
25681 } 27592 }
25682 27593
25683 currContents = build.toTransport(namespace, moduleName, path, currContents, layer, { 27594 currContents = build.toTransport(namespace, moduleName, path, currContents, layer, {
25684 useSourceUrl: config.useSourceUrl 27595 useSourceUrl: config.useSourceUrl
25685 }); 27596 });
25686 27597
25687 if (packageConfig && !hasPackageName) { 27598 if (packageMain && !hasPackageName) {
25688 currContents = addSemiColon(currContents, config) + '\n'; 27599 currContents = addSemiColon(currContents, config) + '\n';
25689 currContents += namespaceWithDot + "define('" + 27600 currContents += namespaceWithDot + "define('" +
25690 packageConfig.name + "', ['" + moduleName + 27601 packageName + "', ['" + moduleName +
25691 "'], function (main) { return main; });\n"; 27602 "'], function (main) { return main; });\n";
25692 } 27603 }
25693 27604
25694 if (config.onBuildWrite) { 27605 if (config.onBuildWrite) {
25695 currContents = config.onBuildWrite(moduleName, path, currContents); 27606 currContents = config.onBuildWrite(moduleName, path, currContents);
25696 } 27607 }
25697 27608
25698 //Semicolon is for files that are not well formed when 27609 //Semicolon is for files that are not well formed when
25699 //concatenated with other content. 27610 //concatenated with other content.
25700 singleContents += "\n" + addSemiColon(currContents, config); 27611 singleContents += addSemiColon(currContents, config);
25701 }); 27612 });
25702 } 27613 }
25703 }).then(function () { 27614 }).then(function () {
25704 var refPath, pluginId, resourcePath, 27615 var refPath, pluginId, resourcePath,
25705 sourceMapPath, sourceMapLineNumber, 27616 sourceMapPath, sourceMapLineNumber,
25711 //Some files may not have declared a require module, and if so, 27622 //Some files may not have declared a require module, and if so,
25712 //put in a placeholder call so the require does not try to load them 27623 //put in a placeholder call so the require does not try to load them
25713 //after the module is processed. 27624 //after the module is processed.
25714 //If we have a name, but no defined module, then add in the placeholder. 27625 //If we have a name, but no defined module, then add in the placeholder.
25715 if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) { 27626 if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) {
25716 shim = config.shim && (getOwn(config.shim, moduleName) || (packageConfig && getOwn(config.shim, nonPackageName))); 27627 shim = config.shim && (getOwn(config.shim, moduleName) || (packageMain && getOwn(config.shim, moduleName) || getOwn(config.shim, packageName)));
25717 if (shim) { 27628 if (shim) {
25718 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' + 27629 if (config.wrapShim) {
25719 (shim.deps && shim.deps.length ? 27630 singleContents = '(function(root) {\n' +
25720 build.makeJsArrayString(shim.deps) + ', ' : '') + 27631 namespaceWithDot + 'define("' + moduleName + '", ' +
25721 (shim.exportsFn ? shim.exportsFn() : 'function(){}') + 27632 (shim.deps && shim.deps.length ?
25722 ');\n'; 27633 build.makeJsArrayString(shim.deps) + ', ' : '[], ') +
27634 'function() {\n' +
27635 ' return (function() {\n' +
27636 singleContents +
27637 // Start with a \n in case last line is a comment
27638 // in the singleContents, like a sourceURL comment.
27639 '\n' + (shim.exportsFn ? shim.exportsFn() : '') +
27640 '\n' +
27641 ' }).apply(root, arguments);\n' +
27642 '});\n' +
27643 '}(this));\n';
27644 } else {
27645 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' +
27646 (shim.deps && shim.deps.length ?
27647 build.makeJsArrayString(shim.deps) + ', ' : '') +
27648 (shim.exportsFn ? shim.exportsFn() : 'function(){}') +
27649 ');\n';
27650 }
25723 } else { 27651 } else {
25724 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n'; 27652 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n';
25725 } 27653 }
25726 } 27654 }
27655
27656 //Add line break at end of file, instead of at beginning,
27657 //so source map line numbers stay correct, but still allow
27658 //for some space separation between files in case ASI issues
27659 //for concatenation would cause an error otherwise.
27660 singleContents += '\n';
25727 27661
25728 //Add to the source map 27662 //Add to the source map
25729 if (sourceMapGenerator) { 27663 if (sourceMapGenerator) {
25730 refPath = config.out ? config.baseUrl : module._buildPath; 27664 refPath = config.out ? config.baseUrl : module._buildPath;
25731 parts = path.split('!'); 27665 parts = path.split('!');
25982 if (commandOption === 'o') { 27916 if (commandOption === 'o') {
25983 //Do the optimizer work. 27917 //Do the optimizer work.
25984 loadLib(); 27918 loadLib();
25985 27919
25986 /** 27920 /**
25987 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 27921 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
25988 * Available via the MIT or new BSD license. 27922 * Available via the MIT or new BSD license.
25989 * see: http://github.com/jrburke/requirejs for details 27923 * see: http://github.com/jrburke/requirejs for details
25990 */ 27924 */
25991 27925
25992 /* 27926 /*
26015 27949
26016 27950
26017 } else if (commandOption === 'v') { 27951 } else if (commandOption === 'v') {
26018 console.log('r.js: ' + version + 27952 console.log('r.js: ' + version +
26019 ', RequireJS: ' + this.requirejsVars.require.version + 27953 ', RequireJS: ' + this.requirejsVars.require.version +
26020 ', UglifyJS2: 2.4.0, UglifyJS: 1.3.4'); 27954 ', UglifyJS2: 2.4.13, UglifyJS: 1.3.4');
26021 } else if (commandOption === 'convert') { 27955 } else if (commandOption === 'convert') {
26022 loadLib(); 27956 loadLib();
26023 27957
26024 this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'], 27958 this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'],
26025 function (args, commonJs, print) { 27959 function (args, commonJs, print) {