1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599 |
- /**
- * @preserve Copyright 2012 Robert Gust-Bardon <http://robert.gust-bardon.org/>.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- /**
- * @fileoverview Enhances <a href="https://github.com/mishoo/UglifyJS/"
- * >UglifyJS</a> with consolidation of null, Boolean, and String values.
- * <p>Also known as aliasing, this feature has been deprecated in <a href=
- * "http://closure-compiler.googlecode.com/">the Closure Compiler</a> since its
- * initial release, where it is unavailable from the <abbr title=
- * "command line interface">CLI</a>. The Closure Compiler allows one to log and
- * influence this process. In contrast, this implementation does not introduce
- * any variable declarations in global code and derives String values from
- * identifier names used as property accessors.</p>
- * <p>Consolidating literals may worsen the data compression ratio when an <a
- * href="http://tools.ietf.org/html/rfc2616#section-3.5">encoding
- * transformation</a> is applied. For instance, <a href=
- * "http://code.jquery.com/jquery-1.7.1.js">jQuery 1.7.1</a> takes 248235 bytes.
- * Building it with <a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">
- * UglifyJS v1.2.5</a> results in 93647 bytes (37.73% of the original) which are
- * then compressed to 33154 bytes (13.36% of the original) using <a href=
- * "http://linux.die.net/man/1/gzip">gzip(1)</a>. Building it with the same
- * version of UglifyJS 1.2.5 patched with the implementation of consolidation
- * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison
- * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes
- * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned
- * 33154 bytes).</p>
- * <p>Written in <a href="http://es5.github.com/#x4.2.2">the strict variant</a>
- * of <a href="http://es5.github.com/">ECMA-262 5.1 Edition</a>. Encoded in <a
- * href="http://tools.ietf.org/html/rfc3629">UTF-8</a>. Follows <a href=
- * "http://google-styleguide.googlecode.com/svn-history/r76/trunk/javascriptguide.xml"
- * >Revision 2.28 of the Google JavaScript Style Guide</a> (except for the
- * discouraged use of the {@code function} tag and the {@code namespace} tag).
- * 100% typed for the <a href=
- * "http://closure-compiler.googlecode.com/files/compiler-20120123.tar.gz"
- * >Closure Compiler Version 1741</a>.</p>
- * <p>Should you find this software useful, please consider <a href=
- * "https://paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JZLW72X8FD4WG"
- * >a donation</a>.</p>
- * @author follow.me@RGustBardon (Robert Gust-Bardon)
- * @supported Tested with:
- * <ul>
- * <li><a href="http://nodejs.org/dist/v0.6.10/">Node v0.6.10</a>,</li>
- * <li><a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">UglifyJS
- * v1.2.5</a>.</li>
- * </ul>
- */
- /*global console:false, exports:true, module:false, require:false */
- /*jshint sub:true */
- /**
- * Consolidates null, Boolean, and String values found inside an <abbr title=
- * "abstract syntax tree">AST</abbr>.
- * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object
- * representing an <abbr title="abstract syntax tree">AST</abbr>.
- * @return {!TSyntacticCodeUnit} An array-like object representing an <abbr
- * title="abstract syntax tree">AST</abbr> with its null, Boolean, and
- * String values consolidated.
- */
- // TODO(user) Consolidation of mathematical values found in numeric literals.
- // TODO(user) Unconsolidation.
- // TODO(user) Consolidation of ECMA-262 6th Edition programs.
- // TODO(user) Rewrite in ECMA-262 6th Edition.
- exports['ast_consolidate'] = function(oAbstractSyntaxTree) {
- 'use strict';
- /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
- latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
- onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
- sub:false, trailing:true */
- var _,
- /**
- * A record consisting of data about one or more source elements.
- * @constructor
- * @nosideeffects
- */
- TSourceElementsData = function() {
- /**
- * The category of the elements.
- * @type {number}
- * @see ESourceElementCategories
- */
- this.nCategory = ESourceElementCategories.N_OTHER;
- /**
- * The number of occurrences (within the elements) of each primitive
- * value that could be consolidated.
- * @type {!Array.<!Object.<string, number>>}
- */
- this.aCount = [];
- this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {};
- this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {};
- this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] =
- {};
- /**
- * Identifier names found within the elements.
- * @type {!Array.<string>}
- */
- this.aIdentifiers = [];
- /**
- * Prefixed representation Strings of each primitive value that could be
- * consolidated within the elements.
- * @type {!Array.<string>}
- */
- this.aPrimitiveValues = [];
- },
- /**
- * A record consisting of data about a primitive value that could be
- * consolidated.
- * @constructor
- * @nosideeffects
- */
- TPrimitiveValue = function() {
- /**
- * The difference in the number of terminal symbols between the original
- * source text and the one with the primitive value consolidated. If the
- * difference is positive, the primitive value is considered worthwhile.
- * @type {number}
- */
- this.nSaving = 0;
- /**
- * An identifier name of the variable that will be declared and assigned
- * the primitive value if the primitive value is consolidated.
- * @type {string}
- */
- this.sName = '';
- },
- /**
- * A record consisting of data on what to consolidate within the range of
- * source elements that is currently being considered.
- * @constructor
- * @nosideeffects
- */
- TSolution = function() {
- /**
- * An object whose keys are prefixed representation Strings of each
- * primitive value that could be consolidated within the elements and
- * whose values are corresponding data about those primitive values.
- * @type {!Object.<string, {nSaving: number, sName: string}>}
- * @see TPrimitiveValue
- */
- this.oPrimitiveValues = {};
- /**
- * The difference in the number of terminal symbols between the original
- * source text and the one with all the worthwhile primitive values
- * consolidated.
- * @type {number}
- * @see TPrimitiveValue#nSaving
- */
- this.nSavings = 0;
- },
- /**
- * The processor of <abbr title="abstract syntax tree">AST</abbr>s found
- * in UglifyJS.
- * @namespace
- * @type {!TProcessor}
- */
- oProcessor = (/** @type {!TProcessor} */ require('./process')),
- /**
- * A record consisting of a number of constants that represent the
- * difference in the number of terminal symbols between a source text with
- * a modified syntactic code unit and the original one.
- * @namespace
- * @type {!Object.<string, number>}
- */
- oWeights = {
- /**
- * The difference in the number of punctuators required by the bracket
- * notation and the dot notation.
- * <p><code>'[]'.length - '.'.length</code></p>
- * @const
- * @type {number}
- */
- N_PROPERTY_ACCESSOR: 1,
- /**
- * The number of punctuators required by a variable declaration with an
- * initialiser.
- * <p><code>':'.length + ';'.length</code></p>
- * @const
- * @type {number}
- */
- N_VARIABLE_DECLARATION: 2,
- /**
- * The number of terminal symbols required to introduce a variable
- * statement (excluding its variable declaration list).
- * <p><code>'var '.length</code></p>
- * @const
- * @type {number}
- */
- N_VARIABLE_STATEMENT_AFFIXATION: 4,
- /**
- * The number of terminal symbols needed to enclose source elements
- * within a function call with no argument values to a function with an
- * empty parameter list.
- * <p><code>'(function(){}());'.length</code></p>
- * @const
- * @type {number}
- */
- N_CLOSURE: 17
- },
- /**
- * Categories of primary expressions from which primitive values that
- * could be consolidated are derivable.
- * @namespace
- * @enum {number}
- */
- EPrimaryExpressionCategories = {
- /**
- * Identifier names used as property accessors.
- * @type {number}
- */
- N_IDENTIFIER_NAMES: 0,
- /**
- * String literals.
- * @type {number}
- */
- N_STRING_LITERALS: 1,
- /**
- * Null and Boolean literals.
- * @type {number}
- */
- N_NULL_AND_BOOLEAN_LITERALS: 2
- },
- /**
- * Prefixes of primitive values that could be consolidated.
- * The String values of the prefixes must have same number of characters.
- * The prefixes must not be used in any properties defined in any version
- * of <a href=
- * "http://www.ecma-international.org/publications/standards/Ecma-262.htm"
- * >ECMA-262</a>.
- * @namespace
- * @enum {string}
- */
- EValuePrefixes = {
- /**
- * Identifies String values.
- * @type {string}
- */
- S_STRING: '#S',
- /**
- * Identifies null and Boolean values.
- * @type {string}
- */
- S_SYMBOLIC: '#O'
- },
- /**
- * Categories of source elements in terms of their appropriateness of
- * having their primitive values consolidated.
- * @namespace
- * @enum {number}
- */
- ESourceElementCategories = {
- /**
- * Identifies a source element that includes the <a href=
- * "http://es5.github.com/#x12.10">{@code with}</a> statement.
- * @type {number}
- */
- N_WITH: 0,
- /**
- * Identifies a source element that includes the <a href=
- * "http://es5.github.com/#x15.1.2.1">{@code eval}</a> identifier name.
- * @type {number}
- */
- N_EVAL: 1,
- /**
- * Identifies a source element that must be excluded from the process
- * unless its whole scope is examined.
- * @type {number}
- */
- N_EXCLUDABLE: 2,
- /**
- * Identifies source elements not posing any problems.
- * @type {number}
- */
- N_OTHER: 3
- },
- /**
- * The list of literals (other than the String ones) whose primitive
- * values can be consolidated.
- * @const
- * @type {!Array.<string>}
- */
- A_OTHER_SUBSTITUTABLE_LITERALS = [
- 'null', // The null literal.
- 'false', // The Boolean literal {@code false}.
- 'true' // The Boolean literal {@code true}.
- ];
- (/**
- * Consolidates all worthwhile primitive values in a syntactic code unit.
- * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object
- * representing the branch of the abstract syntax tree representing the
- * syntactic code unit along with its scope.
- * @see TPrimitiveValue#nSaving
- */
- function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) {
- var _,
- /**
- * Indicates whether the syntactic code unit represents global code.
- * @type {boolean}
- */
- bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0],
- /**
- * Indicates whether the whole scope is being examined.
- * @type {boolean}
- */
- bIsWhollyExaminable = !bIsGlobal,
- /**
- * An array-like object representing source elements that constitute a
- * syntactic code unit.
- * @type {!TSyntacticCodeUnit}
- */
- oSourceElements,
- /**
- * A record consisting of data about the source element that is
- * currently being examined.
- * @type {!TSourceElementsData}
- */
- oSourceElementData,
- /**
- * The scope of the syntactic code unit.
- * @type {!TScope}
- */
- oScope,
- /**
- * An instance of an object that allows the traversal of an <abbr
- * title="abstract syntax tree">AST</abbr>.
- * @type {!TWalker}
- */
- oWalker,
- /**
- * An object encompassing collections of functions used during the
- * traversal of an <abbr title="abstract syntax tree">AST</abbr>.
- * @namespace
- * @type {!Object.<string, !Object.<string, function(...[*])>>}
- */
- oWalkers = {
- /**
- * A collection of functions used during the surveyance of source
- * elements.
- * @namespace
- * @type {!Object.<string, function(...[*])>}
- */
- oSurveySourceElement: {
- /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- /**
- * Classifies the source element as excludable if it does not
- * contain a {@code with} statement or the {@code eval} identifier
- * name. Adds the identifier of the function and its formal
- * parameters to the list of identifier names found.
- * @param {string} sIdentifier The identifier of the function.
- * @param {!Array.<string>} aFormalParameterList Formal parameters.
- * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
- */
- 'defun': function(
- sIdentifier,
- aFormalParameterList,
- oFunctionBody) {
- fClassifyAsExcludable();
- fAddIdentifier(sIdentifier);
- aFormalParameterList.forEach(fAddIdentifier);
- },
- /**
- * Increments the count of the number of occurrences of the String
- * value that is equivalent to the sequence of terminal symbols
- * that constitute the encountered identifier name.
- * @param {!TSyntacticCodeUnit} oExpression The nonterminal
- * MemberExpression.
- * @param {string} sIdentifierName The identifier name used as the
- * property accessor.
- * @return {!Array} The encountered branch of an <abbr title=
- * "abstract syntax tree">AST</abbr> with its nonterminal
- * MemberExpression traversed.
- */
- 'dot': function(oExpression, sIdentifierName) {
- fCountPrimaryExpression(
- EPrimaryExpressionCategories.N_IDENTIFIER_NAMES,
- EValuePrefixes.S_STRING + sIdentifierName);
- return ['dot', oWalker.walk(oExpression), sIdentifierName];
- },
- /**
- * Adds the optional identifier of the function and its formal
- * parameters to the list of identifier names found.
- * @param {?string} sIdentifier The optional identifier of the
- * function.
- * @param {!Array.<string>} aFormalParameterList Formal parameters.
- * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
- */
- 'function': function(
- sIdentifier,
- aFormalParameterList,
- oFunctionBody) {
- if ('string' === typeof sIdentifier) {
- fAddIdentifier(sIdentifier);
- }
- aFormalParameterList.forEach(fAddIdentifier);
- },
- /**
- * Either increments the count of the number of occurrences of the
- * encountered null or Boolean value or classifies a source element
- * as containing the {@code eval} identifier name.
- * @param {string} sIdentifier The identifier encountered.
- */
- 'name': function(sIdentifier) {
- if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) {
- fCountPrimaryExpression(
- EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS,
- EValuePrefixes.S_SYMBOLIC + sIdentifier);
- } else {
- if ('eval' === sIdentifier) {
- oSourceElementData.nCategory =
- ESourceElementCategories.N_EVAL;
- }
- fAddIdentifier(sIdentifier);
- }
- },
- /**
- * Classifies the source element as excludable if it does not
- * contain a {@code with} statement or the {@code eval} identifier
- * name.
- * @param {TSyntacticCodeUnit} oExpression The expression whose
- * value is to be returned.
- */
- 'return': function(oExpression) {
- fClassifyAsExcludable();
- },
- /**
- * Increments the count of the number of occurrences of the
- * encountered String value.
- * @param {string} sStringValue The String value of the string
- * literal encountered.
- */
- 'string': function(sStringValue) {
- if (sStringValue.length > 0) {
- fCountPrimaryExpression(
- EPrimaryExpressionCategories.N_STRING_LITERALS,
- EValuePrefixes.S_STRING + sStringValue);
- }
- },
- /**
- * Adds the identifier reserved for an exception to the list of
- * identifier names found.
- * @param {!TSyntacticCodeUnit} oTry A block of code in which an
- * exception can occur.
- * @param {Array} aCatch The identifier reserved for an exception
- * and a block of code to handle the exception.
- * @param {TSyntacticCodeUnit} oFinally An optional block of code
- * to be evaluated regardless of whether an exception occurs.
- */
- 'try': function(oTry, aCatch, oFinally) {
- if (Array.isArray(aCatch)) {
- fAddIdentifier(aCatch[0]);
- }
- },
- /**
- * Classifies the source element as excludable if it does not
- * contain a {@code with} statement or the {@code eval} identifier
- * name. Adds the identifier of each declared variable to the list
- * of identifier names found.
- * @param {!Array.<!Array>} aVariableDeclarationList Variable
- * declarations.
- */
- 'var': function(aVariableDeclarationList) {
- fClassifyAsExcludable();
- aVariableDeclarationList.forEach(fAddVariable);
- },
- /**
- * Classifies a source element as containing the {@code with}
- * statement.
- * @param {!TSyntacticCodeUnit} oExpression An expression whose
- * value is to be converted to a value of type Object and
- * become the binding object of a new object environment
- * record of a new lexical environment in which the statement
- * is to be executed.
- * @param {!TSyntacticCodeUnit} oStatement The statement to be
- * executed in the augmented lexical environment.
- * @return {!Array} An empty array to stop the traversal.
- */
- 'with': function(oExpression, oStatement) {
- oSourceElementData.nCategory = ESourceElementCategories.N_WITH;
- return [];
- }
- /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- },
- /**
- * A collection of functions used while looking for nested functions.
- * @namespace
- * @type {!Object.<string, function(...[*])>}
- */
- oExamineFunctions: {
- /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- /**
- * Orders an examination of a nested function declaration.
- * @this {!TSyntacticCodeUnit} An array-like object representing
- * the branch of an <abbr title="abstract syntax tree"
- * >AST</abbr> representing the syntactic code unit along with
- * its scope.
- * @return {!Array} An empty array to stop the traversal.
- */
- 'defun': function() {
- fExamineSyntacticCodeUnit(this);
- return [];
- },
- /**
- * Orders an examination of a nested function expression.
- * @this {!TSyntacticCodeUnit} An array-like object representing
- * the branch of an <abbr title="abstract syntax tree"
- * >AST</abbr> representing the syntactic code unit along with
- * its scope.
- * @return {!Array} An empty array to stop the traversal.
- */
- 'function': function() {
- fExamineSyntacticCodeUnit(this);
- return [];
- }
- /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- }
- },
- /**
- * Records containing data about source elements.
- * @type {Array.<TSourceElementsData>}
- */
- aSourceElementsData = [],
- /**
- * The index (in the source text order) of the source element
- * immediately following a <a href="http://es5.github.com/#x14.1"
- * >Directive Prologue</a>.
- * @type {number}
- */
- nAfterDirectivePrologue = 0,
- /**
- * The index (in the source text order) of the source element that is
- * currently being considered.
- * @type {number}
- */
- nPosition,
- /**
- * The index (in the source text order) of the source element that is
- * the last element of the range of source elements that is currently
- * being considered.
- * @type {(undefined|number)}
- */
- nTo,
- /**
- * Initiates the traversal of a source element.
- * @param {!TWalker} oWalker An instance of an object that allows the
- * traversal of an abstract syntax tree.
- * @param {!TSyntacticCodeUnit} oSourceElement A source element from
- * which the traversal should commence.
- * @return {function(): !TSyntacticCodeUnit} A function that is able to
- * initiate the traversal from a given source element.
- */
- cContext = function(oWalker, oSourceElement) {
- /**
- * @return {!TSyntacticCodeUnit} A function that is able to
- * initiate the traversal from a given source element.
- */
- var fLambda = function() {
- return oWalker.walk(oSourceElement);
- };
- return fLambda;
- },
- /**
- * Classifies the source element as excludable if it does not
- * contain a {@code with} statement or the {@code eval} identifier
- * name.
- */
- fClassifyAsExcludable = function() {
- if (oSourceElementData.nCategory ===
- ESourceElementCategories.N_OTHER) {
- oSourceElementData.nCategory =
- ESourceElementCategories.N_EXCLUDABLE;
- }
- },
- /**
- * Adds an identifier to the list of identifier names found.
- * @param {string} sIdentifier The identifier to be added.
- */
- fAddIdentifier = function(sIdentifier) {
- if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) {
- oSourceElementData.aIdentifiers.push(sIdentifier);
- }
- },
- /**
- * Adds the identifier of a variable to the list of identifier names
- * found.
- * @param {!Array} aVariableDeclaration A variable declaration.
- */
- fAddVariable = function(aVariableDeclaration) {
- fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]);
- },
- /**
- * Increments the count of the number of occurrences of the prefixed
- * String representation attributed to the primary expression.
- * @param {number} nCategory The category of the primary expression.
- * @param {string} sName The prefixed String representation attributed
- * to the primary expression.
- */
- fCountPrimaryExpression = function(nCategory, sName) {
- if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) {
- oSourceElementData.aCount[nCategory][sName] = 0;
- if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) {
- oSourceElementData.aPrimitiveValues.push(sName);
- }
- }
- oSourceElementData.aCount[nCategory][sName] += 1;
- },
- /**
- * Consolidates all worthwhile primitive values in a range of source
- * elements.
- * @param {number} nFrom The index (in the source text order) of the
- * source element that is the first element of the range.
- * @param {number} nTo The index (in the source text order) of the
- * source element that is the last element of the range.
- * @param {boolean} bEnclose Indicates whether the range should be
- * enclosed within a function call with no argument values to a
- * function with an empty parameter list if any primitive values
- * are consolidated.
- * @see TPrimitiveValue#nSaving
- */
- fExamineSourceElements = function(nFrom, nTo, bEnclose) {
- var _,
- /**
- * The index of the last mangled name.
- * @type {number}
- */
- nIndex = oScope.cname,
- /**
- * The index of the source element that is currently being
- * considered.
- * @type {number}
- */
- nPosition,
- /**
- * A collection of functions used during the consolidation of
- * primitive values and identifier names used as property
- * accessors.
- * @namespace
- * @type {!Object.<string, function(...[*])>}
- */
- oWalkersTransformers = {
- /**
- * If the String value that is equivalent to the sequence of
- * terminal symbols that constitute the encountered identifier
- * name is worthwhile, a syntactic conversion from the dot
- * notation to the bracket notation ensues with that sequence
- * being substituted by an identifier name to which the value
- * is assigned.
- * Applies to property accessors that use the dot notation.
- * @param {!TSyntacticCodeUnit} oExpression The nonterminal
- * MemberExpression.
- * @param {string} sIdentifierName The identifier name used as
- * the property accessor.
- * @return {!Array} A syntactic code unit that is equivalent to
- * the one encountered.
- * @see TPrimitiveValue#nSaving
- */
- 'dot': function(oExpression, sIdentifierName) {
- /**
- * The prefixed String value that is equivalent to the
- * sequence of terminal symbols that constitute the
- * encountered identifier name.
- * @type {string}
- */
- var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName;
- return oSolutionBest.oPrimitiveValues.hasOwnProperty(
- sPrefixed) &&
- oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
- ['sub',
- oWalker.walk(oExpression),
- ['name',
- oSolutionBest.oPrimitiveValues[sPrefixed].sName]] :
- ['dot', oWalker.walk(oExpression), sIdentifierName];
- },
- /**
- * If the encountered identifier is a null or Boolean literal
- * and its value is worthwhile, the identifier is substituted
- * by an identifier name to which that value is assigned.
- * Applies to identifier names.
- * @param {string} sIdentifier The identifier encountered.
- * @return {!Array} A syntactic code unit that is equivalent to
- * the one encountered.
- * @see TPrimitiveValue#nSaving
- */
- 'name': function(sIdentifier) {
- /**
- * The prefixed representation String of the identifier.
- * @type {string}
- */
- var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier;
- return [
- 'name',
- oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) &&
- oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
- oSolutionBest.oPrimitiveValues[sPrefixed].sName :
- sIdentifier
- ];
- },
- /**
- * If the encountered String value is worthwhile, it is
- * substituted by an identifier name to which that value is
- * assigned.
- * Applies to String values.
- * @param {string} sStringValue The String value of the string
- * literal encountered.
- * @return {!Array} A syntactic code unit that is equivalent to
- * the one encountered.
- * @see TPrimitiveValue#nSaving
- */
- 'string': function(sStringValue) {
- /**
- * The prefixed representation String of the primitive value
- * of the literal.
- * @type {string}
- */
- var sPrefixed =
- EValuePrefixes.S_STRING + sStringValue;
- return oSolutionBest.oPrimitiveValues.hasOwnProperty(
- sPrefixed) &&
- oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
- ['name',
- oSolutionBest.oPrimitiveValues[sPrefixed].sName] :
- ['string', sStringValue];
- }
- },
- /**
- * Such data on what to consolidate within the range of source
- * elements that is currently being considered that lead to the
- * greatest known reduction of the number of the terminal symbols
- * in comparison to the original source text.
- * @type {!TSolution}
- */
- oSolutionBest = new TSolution(),
- /**
- * Data representing an ongoing attempt to find a better
- * reduction of the number of the terminal symbols in comparison
- * to the original source text than the best one that is
- * currently known.
- * @type {!TSolution}
- * @see oSolutionBest
- */
- oSolutionCandidate = new TSolution(),
- /**
- * A record consisting of data about the range of source elements
- * that is currently being examined.
- * @type {!TSourceElementsData}
- */
- oSourceElementsData = new TSourceElementsData(),
- /**
- * Variable declarations for each primitive value that is to be
- * consolidated within the elements.
- * @type {!Array.<!Array>}
- */
- aVariableDeclarations = [],
- /**
- * Augments a list with a prefixed representation String.
- * @param {!Array.<string>} aList A list that is to be augmented.
- * @return {function(string)} A function that augments a list
- * with a prefixed representation String.
- */
- cAugmentList = function(aList) {
- /**
- * @param {string} sPrefixed Prefixed representation String of
- * a primitive value that could be consolidated within the
- * elements.
- */
- var fLambda = function(sPrefixed) {
- if (-1 === aList.indexOf(sPrefixed)) {
- aList.push(sPrefixed);
- }
- };
- return fLambda;
- },
- /**
- * Adds the number of occurrences of a primitive value of a given
- * category that could be consolidated in the source element with
- * a given index to the count of occurrences of that primitive
- * value within the range of source elements that is currently
- * being considered.
- * @param {number} nPosition The index (in the source text order)
- * of a source element.
- * @param {number} nCategory The category of the primary
- * expression from which the primitive value is derived.
- * @return {function(string)} A function that performs the
- * addition.
- * @see cAddOccurrencesInCategory
- */
- cAddOccurrences = function(nPosition, nCategory) {
- /**
- * @param {string} sPrefixed The prefixed representation String
- * of a primitive value.
- */
- var fLambda = function(sPrefixed) {
- if (!oSourceElementsData.aCount[nCategory].hasOwnProperty(
- sPrefixed)) {
- oSourceElementsData.aCount[nCategory][sPrefixed] = 0;
- }
- oSourceElementsData.aCount[nCategory][sPrefixed] +=
- aSourceElementsData[nPosition].aCount[nCategory][
- sPrefixed];
- };
- return fLambda;
- },
- /**
- * Adds the number of occurrences of each primitive value of a
- * given category that could be consolidated in the source
- * element with a given index to the count of occurrences of that
- * primitive values within the range of source elements that is
- * currently being considered.
- * @param {number} nPosition The index (in the source text order)
- * of a source element.
- * @return {function(number)} A function that performs the
- * addition.
- * @see fAddOccurrences
- */
- cAddOccurrencesInCategory = function(nPosition) {
- /**
- * @param {number} nCategory The category of the primary
- * expression from which the primitive value is derived.
- */
- var fLambda = function(nCategory) {
- Object.keys(
- aSourceElementsData[nPosition].aCount[nCategory]
- ).forEach(cAddOccurrences(nPosition, nCategory));
- };
- return fLambda;
- },
- /**
- * Adds the number of occurrences of each primitive value that
- * could be consolidated in the source element with a given index
- * to the count of occurrences of that primitive values within
- * the range of source elements that is currently being
- * considered.
- * @param {number} nPosition The index (in the source text order)
- * of a source element.
- */
- fAddOccurrences = function(nPosition) {
- Object.keys(aSourceElementsData[nPosition].aCount).forEach(
- cAddOccurrencesInCategory(nPosition));
- },
- /**
- * Creates a variable declaration for a primitive value if that
- * primitive value is to be consolidated within the elements.
- * @param {string} sPrefixed Prefixed representation String of a
- * primitive value that could be consolidated within the
- * elements.
- * @see aVariableDeclarations
- */
- cAugmentVariableDeclarations = function(sPrefixed) {
- if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) {
- aVariableDeclarations.push([
- oSolutionBest.oPrimitiveValues[sPrefixed].sName,
- [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ?
- 'name' : 'string',
- sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)]
- ]);
- }
- },
- /**
- * Sorts primitive values with regard to the difference in the
- * number of terminal symbols between the original source text
- * and the one with those primitive values consolidated.
- * @param {string} sPrefixed0 The prefixed representation String
- * of the first of the two primitive values that are being
- * compared.
- * @param {string} sPrefixed1 The prefixed representation String
- * of the second of the two primitive values that are being
- * compared.
- * @return {number}
- * <dl>
- * <dt>-1</dt>
- * <dd>if the first primitive value must be placed before
- * the other one,</dd>
- * <dt>0</dt>
- * <dd>if the first primitive value may be placed before
- * the other one,</dd>
- * <dt>1</dt>
- * <dd>if the first primitive value must not be placed
- * before the other one.</dd>
- * </dl>
- * @see TSolution.oPrimitiveValues
- */
- cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) {
- /**
- * The difference between:
- * <ol>
- * <li>the difference in the number of terminal symbols
- * between the original source text and the one with the
- * first primitive value consolidated, and</li>
- * <li>the difference in the number of terminal symbols
- * between the original source text and the one with the
- * second primitive value consolidated.</li>
- * </ol>
- * @type {number}
- */
- var nDifference =
- oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving -
- oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving;
- return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0;
- },
- /**
- * Assigns an identifier name to a primitive value and calculates
- * whether instances of that primitive value are worth
- * consolidating.
- * @param {string} sPrefixed The prefixed representation String
- * of a primitive value that is being evaluated.
- */
- fEvaluatePrimitiveValue = function(sPrefixed) {
- var _,
- /**
- * The index of the last mangled name.
- * @type {number}
- */
- nIndex,
- /**
- * The representation String of the primitive value that is
- * being evaluated.
- * @type {string}
- */
- sName =
- sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length),
- /**
- * The number of source characters taken up by the
- * representation String of the primitive value that is
- * being evaluated.
- * @type {number}
- */
- nLengthOriginal = sName.length,
- /**
- * The number of source characters taken up by the
- * identifier name that could substitute the primitive
- * value that is being evaluated.
- * substituted.
- * @type {number}
- */
- nLengthSubstitution,
- /**
- * The number of source characters taken up by by the
- * representation String of the primitive value that is
- * being evaluated when it is represented by a string
- * literal.
- * @type {number}
- */
- nLengthString = oProcessor.make_string(sName).length;
- oSolutionCandidate.oPrimitiveValues[sPrefixed] =
- new TPrimitiveValue();
- do { // Find an identifier unused in this or any nested scope.
- nIndex = oScope.cname;
- oSolutionCandidate.oPrimitiveValues[sPrefixed].sName =
- oScope.next_mangled();
- } while (-1 !== oSourceElementsData.aIdentifiers.indexOf(
- oSolutionCandidate.oPrimitiveValues[sPrefixed].sName));
- nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[
- sPrefixed].sName.length;
- if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) {
- // foo:null, or foo:null;
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
- nLengthSubstitution + nLengthOriginal +
- oWeights.N_VARIABLE_DECLARATION;
- // null vs foo
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
- oSourceElementsData.aCount[
- EPrimaryExpressionCategories.
- N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] *
- (nLengthOriginal - nLengthSubstitution);
- } else {
- // foo:'fromCharCode';
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
- nLengthSubstitution + nLengthString +
- oWeights.N_VARIABLE_DECLARATION;
- // .fromCharCode vs [foo]
- if (oSourceElementsData.aCount[
- EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
- ].hasOwnProperty(sPrefixed)) {
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
- oSourceElementsData.aCount[
- EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
- ][sPrefixed] *
- (nLengthOriginal - nLengthSubstitution -
- oWeights.N_PROPERTY_ACCESSOR);
- }
- // 'fromCharCode' vs foo
- if (oSourceElementsData.aCount[
- EPrimaryExpressionCategories.N_STRING_LITERALS
- ].hasOwnProperty(sPrefixed)) {
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
- oSourceElementsData.aCount[
- EPrimaryExpressionCategories.N_STRING_LITERALS
- ][sPrefixed] *
- (nLengthString - nLengthSubstitution);
- }
- }
- if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving >
- 0) {
- oSolutionCandidate.nSavings +=
- oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving;
- } else {
- oScope.cname = nIndex; // Free the identifier name.
- }
- },
- /**
- * Adds a variable declaration to an existing variable statement.
- * @param {!Array} aVariableDeclaration A variable declaration
- * with an initialiser.
- */
- cAddVariableDeclaration = function(aVariableDeclaration) {
- (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift(
- aVariableDeclaration);
- };
- if (nFrom > nTo) {
- return;
- }
- // If the range is a closure, reuse the closure.
- if (nFrom === nTo &&
- 'stat' === oSourceElements[nFrom][0] &&
- 'call' === oSourceElements[nFrom][1][0] &&
- 'function' === oSourceElements[nFrom][1][1][0]) {
- fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]);
- return;
- }
- // Create a list of all derived primitive values within the range.
- for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
- aSourceElementsData[nPosition].aPrimitiveValues.forEach(
- cAugmentList(oSourceElementsData.aPrimitiveValues));
- }
- if (0 === oSourceElementsData.aPrimitiveValues.length) {
- return;
- }
- for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
- // Add the number of occurrences to the total count.
- fAddOccurrences(nPosition);
- // Add identifiers of this or any nested scope to the list.
- aSourceElementsData[nPosition].aIdentifiers.forEach(
- cAugmentList(oSourceElementsData.aIdentifiers));
- }
- // Distribute identifier names among derived primitive values.
- do { // If there was any progress, find a better distribution.
- oSolutionBest = oSolutionCandidate;
- if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) {
- // Sort primitive values descending by their worthwhileness.
- oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues);
- }
- oSolutionCandidate = new TSolution();
- oSourceElementsData.aPrimitiveValues.forEach(
- fEvaluatePrimitiveValue);
- oScope.cname = nIndex;
- } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings);
- // Take the necessity of adding a variable statement into account.
- if ('var' !== oSourceElements[nFrom][0]) {
- oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION;
- }
- if (bEnclose) {
- // Take the necessity of forming a closure into account.
- oSolutionBest.nSavings -= oWeights.N_CLOSURE;
- }
- if (oSolutionBest.nSavings > 0) {
- // Create variable declarations suitable for UglifyJS.
- Object.keys(oSolutionBest.oPrimitiveValues).forEach(
- cAugmentVariableDeclarations);
- // Rewrite expressions that contain worthwhile primitive values.
- for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
- oWalker = oProcessor.ast_walker();
- oSourceElements[nPosition] =
- oWalker.with_walkers(
- oWalkersTransformers,
- cContext(oWalker, oSourceElements[nPosition]));
- }
- if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement.
- (/** @type {!Array.<!Array>} */ aVariableDeclarations.reverse(
- )).forEach(cAddVariableDeclaration);
- } else { // Add a variable statement.
- Array.prototype.splice.call(
- oSourceElements,
- nFrom,
- 0,
- ['var', aVariableDeclarations]);
- nTo += 1;
- }
- if (bEnclose) {
- // Add a closure.
- Array.prototype.splice.call(
- oSourceElements,
- nFrom,
- 0,
- ['stat', ['call', ['function', null, [], []], []]]);
- // Copy source elements into the closure.
- for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) {
- Array.prototype.unshift.call(
- oSourceElements[nFrom][1][1][3],
- oSourceElements[nPosition]);
- }
- // Remove source elements outside the closure.
- Array.prototype.splice.call(
- oSourceElements,
- nFrom + 1,
- nTo - nFrom + 1);
- }
- }
- if (bEnclose) {
- // Restore the availability of identifier names.
- oScope.cname = nIndex;
- }
- };
- oSourceElements = (/** @type {!TSyntacticCodeUnit} */
- oSyntacticCodeUnit[bIsGlobal ? 1 : 3]);
- if (0 === oSourceElements.length) {
- return;
- }
- oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope;
- // Skip a Directive Prologue.
- while (nAfterDirectivePrologue < oSourceElements.length &&
- 'stat' === oSourceElements[nAfterDirectivePrologue][0] &&
- 'string' === oSourceElements[nAfterDirectivePrologue][1][0]) {
- nAfterDirectivePrologue += 1;
- aSourceElementsData.push(null);
- }
- if (oSourceElements.length === nAfterDirectivePrologue) {
- return;
- }
- for (nPosition = nAfterDirectivePrologue;
- nPosition < oSourceElements.length;
- nPosition += 1) {
- oSourceElementData = new TSourceElementsData();
- oWalker = oProcessor.ast_walker();
- // Classify a source element.
- // Find its derived primitive values and count their occurrences.
- // Find all identifiers used (including nested scopes).
- oWalker.with_walkers(
- oWalkers.oSurveySourceElement,
- cContext(oWalker, oSourceElements[nPosition]));
- // Establish whether the scope is still wholly examinable.
- bIsWhollyExaminable = bIsWhollyExaminable &&
- ESourceElementCategories.N_WITH !== oSourceElementData.nCategory &&
- ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory;
- aSourceElementsData.push(oSourceElementData);
- }
- if (bIsWhollyExaminable) { // Examine the whole scope.
- fExamineSourceElements(
- nAfterDirectivePrologue,
- oSourceElements.length - 1,
- false);
- } else { // Examine unexcluded ranges of source elements.
- for (nPosition = oSourceElements.length - 1;
- nPosition >= nAfterDirectivePrologue;
- nPosition -= 1) {
- oSourceElementData = (/** @type {!TSourceElementsData} */
- aSourceElementsData[nPosition]);
- if (ESourceElementCategories.N_OTHER ===
- oSourceElementData.nCategory) {
- if ('undefined' === typeof nTo) {
- nTo = nPosition; // Indicate the end of a range.
- }
- // Examine the range if it immediately follows a Directive Prologue.
- if (nPosition === nAfterDirectivePrologue) {
- fExamineSourceElements(nPosition, nTo, true);
- }
- } else {
- if ('undefined' !== typeof nTo) {
- // Examine the range that immediately follows this source element.
- fExamineSourceElements(nPosition + 1, nTo, true);
- nTo = void 0; // Obliterate the range.
- }
- // Examine nested functions.
- oWalker = oProcessor.ast_walker();
- oWalker.with_walkers(
- oWalkers.oExamineFunctions,
- cContext(oWalker, oSourceElements[nPosition]));
- }
- }
- }
- }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree)));
- return oAbstractSyntaxTree;
- };
- /*jshint sub:false */
- if (require.main === module) {
- (function() {
- 'use strict';
- /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
- latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
- onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
- sub:false, trailing:true */
- var _,
- /**
- * NodeJS module for unit testing.
- * @namespace
- * @type {!TAssert}
- * @see http://nodejs.org/docs/v0.6.10/api/all.html#assert
- */
- oAssert = (/** @type {!TAssert} */ require('assert')),
- /**
- * The parser of ECMA-262 found in UglifyJS.
- * @namespace
- * @type {!TParser}
- */
- oParser = (/** @type {!TParser} */ require('./parse-js')),
- /**
- * The processor of <abbr title="abstract syntax tree">AST</abbr>s
- * found in UglifyJS.
- * @namespace
- * @type {!TProcessor}
- */
- oProcessor = (/** @type {!TProcessor} */ require('./process')),
- /**
- * An instance of an object that allows the traversal of an <abbr
- * title="abstract syntax tree">AST</abbr>.
- * @type {!TWalker}
- */
- oWalker,
- /**
- * A collection of functions for the removal of the scope information
- * during the traversal of an <abbr title="abstract syntax tree"
- * >AST</abbr>.
- * @namespace
- * @type {!Object.<string, function(...[*])>}
- */
- oWalkersPurifiers = {
- /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- /**
- * Deletes the scope information from the branch of the abstract
- * syntax tree representing the encountered function declaration.
- * @param {string} sIdentifier The identifier of the function.
- * @param {!Array.<string>} aFormalParameterList Formal parameters.
- * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
- */
- 'defun': function(
- sIdentifier,
- aFormalParameterList,
- oFunctionBody) {
- delete oFunctionBody.scope;
- },
- /**
- * Deletes the scope information from the branch of the abstract
- * syntax tree representing the encountered function expression.
- * @param {?string} sIdentifier The optional identifier of the
- * function.
- * @param {!Array.<string>} aFormalParameterList Formal parameters.
- * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
- */
- 'function': function(
- sIdentifier,
- aFormalParameterList,
- oFunctionBody) {
- delete oFunctionBody.scope;
- }
- /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
- },
- /**
- * Initiates the traversal of a source element.
- * @param {!TWalker} oWalker An instance of an object that allows the
- * traversal of an abstract syntax tree.
- * @param {!TSyntacticCodeUnit} oSourceElement A source element from
- * which the traversal should commence.
- * @return {function(): !TSyntacticCodeUnit} A function that is able to
- * initiate the traversal from a given source element.
- */
- cContext = function(oWalker, oSourceElement) {
- /**
- * @return {!TSyntacticCodeUnit} A function that is able to
- * initiate the traversal from a given source element.
- */
- var fLambda = function() {
- return oWalker.walk(oSourceElement);
- };
- return fLambda;
- },
- /**
- * A record consisting of configuration for the code generation phase.
- * @type {!Object}
- */
- oCodeGenerationOptions = {
- beautify: true
- },
- /**
- * Tests whether consolidation of an ECMAScript program yields expected
- * results.
- * @param {{
- * sTitle: string,
- * sInput: string,
- * sOutput: string
- * }} oUnitTest A record consisting of data about a unit test: its
- * name, an ECMAScript program, and, if consolidation is to take
- * place, the resulting ECMAScript program.
- */
- cAssert = function(oUnitTest) {
- var _,
- /**
- * An array-like object representing the <abbr title=
- * "abstract syntax tree">AST</abbr> obtained after consolidation.
- * @type {!TSyntacticCodeUnit}
- */
- oSyntacticCodeUnitActual =
- exports.ast_consolidate(oParser.parse(oUnitTest.sInput)),
- /**
- * An array-like object representing the expected <abbr title=
- * "abstract syntax tree">AST</abbr>.
- * @type {!TSyntacticCodeUnit}
- */
- oSyntacticCodeUnitExpected = oParser.parse(
- oUnitTest.hasOwnProperty('sOutput') ?
- oUnitTest.sOutput : oUnitTest.sInput);
- delete oSyntacticCodeUnitActual.scope;
- oWalker = oProcessor.ast_walker();
- oWalker.with_walkers(
- oWalkersPurifiers,
- cContext(oWalker, oSyntacticCodeUnitActual));
- try {
- oAssert.deepEqual(
- oSyntacticCodeUnitActual,
- oSyntacticCodeUnitExpected);
- } catch (oException) {
- console.error(
- '########## A unit test has failed.\n' +
- oUnitTest.sTitle + '\n' +
- '##### actual code (' +
- oProcessor.gen_code(oSyntacticCodeUnitActual).length +
- ' bytes)\n' +
- oProcessor.gen_code(
- oSyntacticCodeUnitActual,
- oCodeGenerationOptions) + '\n' +
- '##### expected code (' +
- oProcessor.gen_code(oSyntacticCodeUnitExpected).length +
- ' bytes)\n' +
- oProcessor.gen_code(
- oSyntacticCodeUnitExpected,
- oCodeGenerationOptions));
- }
- };
- [
- // 7.6.1 Reserved Words.
- {
- sTitle:
- 'Omission of keywords while choosing an identifier name.',
- sInput:
- '(function() {' +
- ' var a, b, c, d, e, f, g, h, i, j, k, l, m,' +
- ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
- ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
- ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
- ' $, _,' +
- ' aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am,' +
- ' an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az,' +
- ' aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM,' +
- ' aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ,' +
- ' a$, a_,' +
- ' ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm,' +
- ' bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz,' +
- ' bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, bM,' +
- ' bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, bX, bY, bZ,' +
- ' b$, b_,' +
- ' ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm,' +
- ' cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz,' +
- ' cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM,' +
- ' cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ,' +
- ' c$, c_,' +
- ' da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm,' +
- ' dn, dq, dr, ds, dt, du, dv, dw, dx, dy, dz,' +
- ' dA, dB, dC, dD, dE, dF, dG, dH, dI, dJ, dK, dL, dM,' +
- ' dN, dO, dP, dQ, dR, dS, dT, dU, dV, dW, dX, dY, dZ,' +
- ' d$, d_;' +
- ' void ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",' +
- ' "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var dp =' +
- ' "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",' +
- ' a, b, c, d, e, f, g, h, i, j, k, l, m,' +
- ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
- ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
- ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
- ' $, _,' +
- ' aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am,' +
- ' an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az,' +
- ' aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM,' +
- ' aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ,' +
- ' a$, a_,' +
- ' ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm,' +
- ' bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz,' +
- ' bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, bM,' +
- ' bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, bX, bY, bZ,' +
- ' b$, b_,' +
- ' ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm,' +
- ' cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz,' +
- ' cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM,' +
- ' cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ,' +
- ' c$, c_,' +
- ' da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm,' +
- ' dn, dq, dr, ds, dt, du, dv, dw, dx, dy, dz,' +
- ' dA, dB, dC, dD, dE, dF, dG, dH, dI, dJ, dK, dL, dM,' +
- ' dN, dO, dP, dQ, dR, dS, dT, dU, dV, dW, dX, dY, dZ,' +
- ' d$, d_;' +
- ' void [dp, dp];' +
- '}());'
- },
- // 7.8.1 Null Literals.
- {
- sTitle:
- 'Evaluation with regard to the null value.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var foo;' +
- ' void [null, null, null];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [null, null];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var a = null, foo;' +
- ' void [a, a, a];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [null, null];' +
- '}());'
- },
- // 7.8.2 Boolean Literals.
- {
- sTitle:
- 'Evaluation with regard to the false value.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var foo;' +
- ' void [false, false, false];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [false, false];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var a = false, foo;' +
- ' void [a, a, a];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [false, false];' +
- '}());'
- },
- {
- sTitle:
- 'Evaluation with regard to the true value.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var foo;' +
- ' void [true, true, true];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [true, true];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var a = true, foo;' +
- ' void [a, a, a];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void [true, true];' +
- '}());'
- },
- // 7.8.4 String Literals.
- {
- sTitle:
- 'Evaluation with regard to the String value of a string literal.',
- sInput:
- '(function() {' +
- ' var foo;' +
- ' void ["abcd", "abcd", "abc", "abc"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "abcd", foo;' +
- ' void [a, a, "abc", "abc"];' +
- '}());'
- },
- // 7.8.5 Regular Expression Literals.
- {
- sTitle:
- 'Preservation of the pattern of a regular expression literal.',
- sInput:
- 'void [/abcdefghijklmnopqrstuvwxyz/, /abcdefghijklmnopqrstuvwxyz/];'
- },
- {
- sTitle:
- 'Preservation of the flags of a regular expression literal.',
- sInput:
- 'void [/(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim,' +
- ' /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim,' +
- ' /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim];'
- },
- // 10.2 Lexical Environments.
- {
- sTitle:
- 'Preservation of identifier names in the same scope.',
- sInput:
- '/*jshint shadow:true */' +
- 'var a;' +
- 'function b(i) {' +
- '}' +
- 'for (var c; 0 === Math.random(););' +
- 'for (var d in {});' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- 'void [b(a), b(c), b(d)];' +
- 'void [typeof e];' +
- 'i: for (; 0 === Math.random();) {' +
- ' if (42 === (new Date()).getMinutes()) {' +
- ' continue i;' +
- ' } else {' +
- ' break i;' +
- ' }' +
- '}' +
- 'try {' +
- '} catch (f) {' +
- '} finally {' +
- '}' +
- '(function g(h) {' +
- '}());' +
- 'void [{' +
- ' i: 42,' +
- ' "j": 42,' +
- ' \'k\': 42' +
- '}];' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- '/*jshint shadow:true */' +
- 'var a;' +
- 'function b(i) {' +
- '}' +
- 'for (var c; 0 === Math.random(););' +
- 'for (var d in {});' +
- '(function() {' +
- ' var i = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [i];' +
- ' void [b(a), b(c), b(d)];' +
- ' void [typeof e];' +
- ' i: for (; 0 === Math.random();) {' +
- ' if (42 === (new Date()).getMinutes()) {' +
- ' continue i;' +
- ' } else {' +
- ' break i;' +
- ' }' +
- ' }' +
- ' try {' +
- ' } catch (f) {' +
- ' } finally {' +
- ' }' +
- ' (function g(h) {' +
- ' }());' +
- ' void [{' +
- ' i: 42,' +
- ' "j": 42,' +
- ' \'k\': 42' +
- ' }];' +
- ' void [i];' +
- '}());'
- },
- {
- sTitle:
- 'Preservation of identifier names in nested function code.',
- sInput:
- '(function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' (function() {' +
- ' var a;' +
- ' for (var b; 0 === Math.random(););' +
- ' for (var c in {});' +
- ' void [typeof d];' +
- ' h: for (; 0 === Math.random();) {' +
- ' if (42 === (new Date()).getMinutes()) {' +
- ' continue h;' +
- ' } else {' +
- ' break h;' +
- ' }' +
- ' }' +
- ' try {' +
- ' } catch (e) {' +
- ' } finally {' +
- ' }' +
- ' (function f(g) {' +
- ' }());' +
- ' void [{' +
- ' h: 42,' +
- ' "i": 42,' +
- ' \'j\': 42' +
- ' }];' +
- ' }());' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var h = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [h];' +
- ' (function() {' +
- ' var a;' +
- ' for (var b; 0 === Math.random(););' +
- ' for (var c in {});' +
- ' void [typeof d];' +
- ' h: for (; 0 === Math.random();) {' +
- ' if (42 === (new Date()).getMinutes()) {' +
- ' continue h;' +
- ' } else {' +
- ' break h;' +
- ' }' +
- ' }' +
- ' try {' +
- ' } catch (e) {' +
- ' } finally {' +
- ' }' +
- ' (function f(g) {' +
- ' }());' +
- ' void [{' +
- ' h: 42,' +
- ' "i": 42,' +
- ' \'j\': 42' +
- ' }];' +
- ' }());' +
- ' void [h];' +
- '}());'
- },
- {
- sTitle:
- 'Consolidation of a closure with other source elements.',
- sInput:
- '(function(foo) {' +
- '}("abcdefghijklmnopqrstuvwxyz"));' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' (function(foo) {' +
- ' })(a);' +
- ' void [a];' +
- '}());'
- },
- {
- sTitle:
- 'Consolidation of function code instead of a sole closure.',
- sInput:
- '(function(foo, bar) {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"));',
- sOutput:
- '(function(foo, bar) {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"));'
- },
- // 11.1.5 Object Initialiser.
- {
- sTitle:
- 'Preservation of property names of an object initialiser.',
- sInput:
- 'var foo = {' +
- ' abcdefghijklmnopqrstuvwxyz: 42,' +
- ' "zyxwvutsrqponmlkjihgfedcba": 42,' +
- ' \'mlkjihgfedcbanopqrstuvwxyz\': 42' +
- '};' +
- 'void [' +
- ' foo.abcdefghijklmnopqrstuvwxyz,' +
- ' "zyxwvutsrqponmlkjihgfedcba",' +
- ' \'mlkjihgfedcbanopqrstuvwxyz\'' +
- '];'
- },
- {
- sTitle:
- 'Evaluation with regard to String values derived from identifier ' +
- 'names used as property accessors.',
- sInput:
- '(function() {' +
- ' var foo;' +
- ' void [' +
- ' Math.abcdefghij,' +
- ' Math.abcdefghij,' +
- ' Math.abcdefghi,' +
- ' Math.abcdefghi' +
- ' ];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "abcdefghij", foo;' +
- ' void [' +
- ' Math[a],' +
- ' Math[a],' +
- ' Math.abcdefghi,' +
- ' Math.abcdefghi' +
- ' ];' +
- '}());'
- },
- // 11.2.1 Property Accessors.
- {
- sTitle:
- 'Preservation of identifiers in the nonterminal MemberExpression.',
- sInput:
- 'void [' +
- ' Math.E,' +
- ' Math.LN10,' +
- ' Math.LN2,' +
- ' Math.LOG2E,' +
- ' Math.LOG10E,' +
- ' Math.PI,' +
- ' Math.SQRT1_2,' +
- ' Math.SQRT2,' +
- ' Math.abs,' +
- ' Math.acos' +
- '];'
- },
- // 12.2 Variable Statement.
- {
- sTitle:
- 'Preservation of the identifier of a variable that is being ' +
- 'declared in a variable statement.',
- sInput:
- '(function() {' +
- ' var abcdefghijklmnopqrstuvwxyz;' +
- ' void [abcdefghijklmnopqrstuvwxyz];' +
- '}());'
- },
- {
- sTitle:
- 'Exclusion of a variable statement in global code.',
- sInput:
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- 'var foo = "abcdefghijklmnopqrstuvwxyz",' +
- ' bar = "abcdefghijklmnopqrstuvwxyz";' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- {
- sTitle:
- 'Exclusion of a variable statement in function code that ' +
- 'contains a with statement.',
- sInput:
- '(function() {' +
- ' with ({});' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' var foo;' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());'
- },
- {
- sTitle:
- 'Exclusion of a variable statement in function code that ' +
- 'contains a direct call to the eval function.',
- sInput:
- '/*jshint evil:true */' +
- 'void [' +
- ' function() {' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' var foo;' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' }' +
- '];'
- },
- {
- sTitle:
- 'Consolidation within a variable statement in global code.',
- sInput:
- 'var foo = function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '};',
- sOutput:
- 'var foo = function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '};'
- },
- {
- sTitle:
- 'Consolidation within a variable statement excluded in function ' +
- 'code due to the presence of a with statement.',
- sInput:
- '(function() {' +
- ' with ({});' +
- ' var foo = function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' };' +
- '}());',
- sOutput:
- '(function() {' +
- ' with ({});' +
- ' var foo = function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' };' +
- '}());'
- },
- {
- sTitle:
- 'Consolidation within a variable statement excluded in function ' +
- 'code due to the presence of a direct call to the eval function.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' eval("");' +
- ' var foo = function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' };' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' eval("");' +
- ' var foo = function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' };' +
- '}());'
- },
- {
- sTitle:
- 'Inclusion of a variable statement in function code that ' +
- 'contains no with statement and no direct call to the eval ' +
- 'function.',
- sInput:
- '(function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' var foo;' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a];' +
- ' var foo;' +
- ' void [a];' +
- '}());'
- },
- {
- sTitle:
- 'Ignorance with regard to a variable statement in global code.',
- sInput:
- 'var foo = "abcdefghijklmnopqrstuvwxyz";' +
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- 'var foo = "abcdefghijklmnopqrstuvwxyz";' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- // 12.4 Expression Statement.
- {
- sTitle:
- 'Preservation of identifiers in an expression statement.',
- sInput:
- 'void [typeof abcdefghijklmnopqrstuvwxyz,' +
- ' typeof abcdefghijklmnopqrstuvwxyz];'
- },
- // 12.6.3 The {@code for} Statement.
- {
- sTitle:
- 'Preservation of identifiers in the variable declaration list of ' +
- 'a for statement.',
- sInput:
- 'for (var abcdefghijklmnopqrstuvwxyz; 0 === Math.random(););' +
- 'for (var abcdefghijklmnopqrstuvwxyz; 0 === Math.random(););'
- },
- // 12.6.4 The {@code for-in} Statement.
- {
- sTitle:
- 'Preservation of identifiers in the variable declaration list of ' +
- 'a for-in statement.',
- sInput:
- 'for (var abcdefghijklmnopqrstuvwxyz in {});' +
- 'for (var abcdefghijklmnopqrstuvwxyz in {});'
- },
- // 12.7 The {@code continue} Statement.
- {
- sTitle:
- 'Preservation of the identifier in a continue statement.',
- sInput:
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
- ' continue abcdefghijklmnopqrstuvwxyz;' +
- '}' +
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
- ' continue abcdefghijklmnopqrstuvwxyz;' +
- '}'
- },
- // 12.8 The {@code break} Statement.
- {
- sTitle:
- 'Preservation of the identifier in a break statement.',
- sInput:
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
- ' break abcdefghijklmnopqrstuvwxyz;' +
- '}' +
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
- ' break abcdefghijklmnopqrstuvwxyz;' +
- '}'
- },
- // 12.9 The {@code return} Statement.
- {
- sTitle:
- 'Exclusion of a return statement in function code that contains ' +
- 'a with statement.',
- sInput:
- '(function() {' +
- ' with ({});' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' if (0 === Math.random()) {' +
- ' return;' +
- ' } else {' +
- ' }' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());'
- },
- {
- sTitle:
- 'Exclusion of a return statement in function code that contains ' +
- 'a direct call to the eval function.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' if (0 === Math.random()) {' +
- ' return;' +
- ' } else {' +
- ' }' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());'
- },
- {
- sTitle:
- 'Consolidation within a return statement excluded in function ' +
- 'code due to the presence of a with statement.',
- sInput:
- '(function() {' +
- ' with ({});' +
- ' return function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' };' +
- '}());',
- sOutput:
- '(function() {' +
- ' with ({});' +
- ' return function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' };' +
- '}());'
- },
- {
- sTitle:
- 'Consolidation within a return statement excluded in function ' +
- 'code due to the presence of a direct call to the eval function.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' eval("");' +
- ' return function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' };' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' eval("");' +
- ' return function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' };' +
- '}());'
- },
- {
- sTitle:
- 'Inclusion of a return statement in function code that contains ' +
- 'no with statement and no direct call to the eval function.',
- sInput:
- '(function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- ' if (0 === Math.random()) {' +
- ' return;' +
- ' } else {' +
- ' }' +
- ' void ["abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a];' +
- ' if (0 === Math.random()) {' +
- ' return;' +
- ' } else {' +
- ' }' +
- ' void [a];' +
- '}());'
- },
- // 12.10 The {@code with} Statement.
- {
- sTitle:
- 'Preservation of the statement in a with statement.',
- sInput:
- 'with ({}) {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}'
- },
- {
- sTitle:
- 'Exclusion of a with statement in the same syntactic code unit.',
- sInput:
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- 'with ({' +
- ' foo: "abcdefghijklmnopqrstuvwxyz",' +
- ' bar: "abcdefghijklmnopqrstuvwxyz"' +
- '}) {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- {
- sTitle:
- 'Exclusion of a with statement in nested function code.',
- sInput:
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- '(function() {' +
- ' with ({' +
- ' foo: "abcdefghijklmnopqrstuvwxyz",' +
- ' bar: "abcdefghijklmnopqrstuvwxyz"' +
- ' }) {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' }' +
- '}());' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- // 12.12 Labelled Statements.
- {
- sTitle:
- 'Preservation of the label of a labelled statement.',
- sInput:
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random(););' +
- 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random(););'
- },
- // 12.14 The {@code try} Statement.
- {
- sTitle:
- 'Preservation of the identifier in the catch clause of a try' +
- 'statement.',
- sInput:
- 'try {' +
- '} catch (abcdefghijklmnopqrstuvwxyz) {' +
- '} finally {' +
- '}' +
- 'try {' +
- '} catch (abcdefghijklmnopqrstuvwxyz) {' +
- '} finally {' +
- '}'
- },
- // 13 Function Definition.
- {
- sTitle:
- 'Preservation of the identifier of a function declaration.',
- sInput:
- 'function abcdefghijklmnopqrstuvwxyz() {' +
- '}' +
- 'void [abcdefghijklmnopqrstuvwxyz];'
- },
- {
- sTitle:
- 'Preservation of the identifier of a function expression.',
- sInput:
- 'void [' +
- ' function abcdefghijklmnopqrstuvwxyz() {' +
- ' },' +
- ' function abcdefghijklmnopqrstuvwxyz() {' +
- ' }' +
- '];'
- },
- {
- sTitle:
- 'Preservation of a formal parameter of a function declaration.',
- sInput:
- 'function foo(abcdefghijklmnopqrstuvwxyz) {' +
- '}' +
- 'function bar(abcdefghijklmnopqrstuvwxyz) {' +
- '}'
- },
- {
- sTitle:
- 'Preservation of a formal parameter in a function expression.',
- sInput:
- 'void [' +
- ' function(abcdefghijklmnopqrstuvwxyz) {' +
- ' },' +
- ' function(abcdefghijklmnopqrstuvwxyz) {' +
- ' }' +
- '];'
- },
- {
- sTitle:
- 'Exclusion of a function declaration.',
- sInput:
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- 'function foo() {' +
- '}' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- {
- sTitle:
- 'Consolidation within a function declaration.',
- sInput:
- 'function foo() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}',
- sOutput:
- 'function foo() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}'
- },
- // 14 Program.
- {
- sTitle:
- 'Preservation of a program without source elements.',
- sInput:
- ''
- },
- // 14.1 Directive Prologues and the Use Strict Directive.
- {
- sTitle:
- 'Preservation of a Directive Prologue in global code.',
- sInput:
- '"abcdefghijklmnopqrstuvwxyz";' +
- '\'zyxwvutsrqponmlkjihgfedcba\';'
- },
- {
- sTitle:
- 'Preservation of a Directive Prologue in a function declaration.',
- sInput:
- 'function foo() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' \'zyxwvutsrqponmlkjihgfedcba\';' +
- '}'
- },
- {
- sTitle:
- 'Preservation of a Directive Prologue in a function expression.',
- sInput:
- 'void [' +
- ' function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' \'zyxwvutsrqponmlkjihgfedcba\';' +
- ' }' +
- '];'
- },
- {
- sTitle:
- 'Ignorance with regard to a Directive Prologue in global code.',
- sInput:
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- '"abcdefghijklmnopqrstuvwxyz";' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- {
- sTitle:
- 'Ignorance with regard to a Directive Prologue in a function' +
- 'declaration.',
- sInput:
- 'function foo() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}',
- sOutput:
- 'function foo() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}'
- },
- {
- sTitle:
- 'Ignorance with regard to a Directive Prologue in a function' +
- 'expression.',
- sInput:
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- // 15.1 The Global Object.
- {
- sTitle:
- 'Preservation of a property of the global object.',
- sInput:
- 'void [undefined, undefined, undefined, undefined, undefined];'
- },
- // 15.1.2.1.1 Direct Call to Eval.
- {
- sTitle:
- 'Exclusion of a direct call to the eval function in the same ' +
- 'syntactic code unit.',
- sInput:
- '/*jshint evil:true */' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- 'eval("");' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- {
- sTitle:
- 'Exclusion of a direct call to the eval function in nested ' +
- 'function code.',
- sInput:
- '/*jshint evil:true */' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];' +
- '(function() {' +
- ' eval("");' +
- '}());' +
- 'void ["abcdefghijklmnopqrstuvwxyz"];'
- },
- {
- sTitle:
- 'Consolidation within a direct call to the eval function.',
- sInput:
- '/*jshint evil:true */' +
- 'eval(function() {' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- 'eval(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- // Consolidation proper.
- {
- sTitle:
- 'No consolidation if it does not result in a reduction of the ' +
- 'number of source characters.',
- sInput:
- '(function() {' +
- ' var foo;' +
- ' void ["ab", "ab", "abc", "abc"];' +
- '}());'
- },
- {
- sTitle:
- 'Identification of a range of source elements at the beginning ' +
- 'of global code.',
- sInput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- 'eval("");',
- sOutput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());' +
- 'eval("");'
- },
- {
- sTitle:
- 'Identification of a range of source elements in the middle of ' +
- 'global code.',
- sInput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'eval("");' +
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- 'eval("");',
- sOutput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'eval("");' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());' +
- 'eval("");'
- },
- {
- sTitle:
- 'Identification of a range of source elements at the end of ' +
- 'global code.',
- sInput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'eval("");' +
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- '/*jshint evil:true */' +
- '"abcdefghijklmnopqrstuvwxyz";' +
- 'eval("");' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- {
- sTitle:
- 'Identification of a range of source elements at the beginning ' +
- 'of function code.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' eval("");' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' (function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' }());' +
- ' eval("");' +
- '}());'
- },
- {
- sTitle:
- 'Identification of a range of source elements in the middle of ' +
- 'function code.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- ' eval("");' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' eval("");' +
- ' (function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' }());' +
- ' eval("");' +
- '}());'
- },
- {
- sTitle:
- 'Identification of a range of source elements at the end of ' +
- 'function code.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' "abcdefghijklmnopqrstuvwxyz";' +
- ' eval("");' +
- ' (function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- ' }());' +
- '}());'
- },
- {
- sTitle:
- 'Evaluation with regard to String values of String literals and ' +
- 'String values derived from identifier names used as property' +
- 'accessors.',
- sInput:
- '(function() {' +
- ' var foo;' +
- ' void ["abcdefg", Math.abcdefg, "abcdef", Math.abcdef];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "abcdefg", foo;' +
- ' void [a, Math[a], "abcdef", Math.abcdef];' +
- '}());'
- },
- {
- sTitle:
- 'Evaluation with regard to the necessity of adding a variable ' +
- 'statement.',
- sInput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' void ["abcdefgh", "abcdefgh"];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' void ["abcdefg", "abcdefg"];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var foo;' +
- ' void ["abcd", "abcd"];' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var a = "abcdefgh";' +
- ' void [a, a];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' void ["abcdefg", "abcdefg"];' +
- '}());' +
- 'eval("");' +
- '(function() {' +
- ' var a = "abcd", foo;' +
- ' void [a, a];' +
- '}());'
- },
- {
- sTitle:
- 'Evaluation with regard to the necessity of enclosing source ' +
- 'elements.',
- sInput:
- '/*jshint evil:true */' +
- 'void ["abcdefghijklmnopqrstuvwxy", "abcdefghijklmnopqrstuvwxy"];' +
- 'eval("");' +
- 'void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
- 'eval("");' +
- '(function() {' +
- ' void ["abcdefgh", "abcdefgh"];' +
- '}());' +
- '(function() {' +
- ' void ["abcdefghijklmnopqrstuvwxy",' +
- ' "abcdefghijklmnopqrstuvwxy"];' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwx",' +
- ' "abcdefghijklmnopqrstuvwx"];' +
- ' eval("");' +
- ' (function() {' +
- ' void ["abcdefgh", "abcdefgh"];' +
- ' }());' +
- '}());',
- sOutput:
- '/*jshint evil:true */' +
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxy";' +
- ' void [a, a];' +
- '}());' +
- 'eval("");' +
- 'void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
- 'eval("");' +
- '(function() {' +
- ' var a = "abcdefgh";' +
- ' void [a, a];' +
- '}());' +
- '(function() {' +
- ' (function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxy";' +
- ' void [a, a];' +
- ' }());' +
- ' eval("");' +
- ' void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
- ' eval("");' +
- ' (function() {' +
- ' var a = "abcdefgh";' +
- ' void [a, a];' +
- ' }());' +
- '}());'
- },
- {
- sTitle:
- 'Employment of a closure while consolidating in global code.',
- sInput:
- 'void ["abcdefghijklmnopqrstuvwxyz",' +
- ' "abcdefghijklmnopqrstuvwxyz"];',
- sOutput:
- '(function() {' +
- ' var a = "abcdefghijklmnopqrstuvwxyz";' +
- ' void [a, a];' +
- '}());'
- },
- {
- sTitle:
- 'Assignment of a shorter identifier to a value whose ' +
- 'consolidation results in a greater reduction of the number of ' +
- 'source characters.',
- sInput:
- '(function() {' +
- ' var b, c, d, e, f, g, h, i, j, k, l, m,' +
- ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
- ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
- ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
- ' $, _;' +
- ' void ["abcde", "abcde", "edcba", "edcba", "edcba"];' +
- '}());',
- sOutput:
- '(function() {' +
- ' var a = "edcba",' +
- ' b, c, d, e, f, g, h, i, j, k, l, m,' +
- ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
- ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
- ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
- ' $, _;' +
- ' void ["abcde", "abcde", a, a, a];' +
- '}());'
- }
- ].forEach(cAssert);
- }());
- }
- /* Local Variables: */
- /* mode: js */
- /* coding: utf-8 */
- /* indent-tabs-mode: nil */
- /* tab-width: 2 */
- /* End: */
- /* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */
- /* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */
|