consolidator.js 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599
  1. /**
  2. * @preserve Copyright 2012 Robert Gust-Bardon <http://robert.gust-bardon.org/>.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * * Redistributions of source code must retain the above
  10. * copyright notice, this list of conditions and the following
  11. * disclaimer.
  12. *
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials
  16. * provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  22. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  23. * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  27. * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  28. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. /**
  32. * @fileoverview Enhances <a href="https://github.com/mishoo/UglifyJS/"
  33. * >UglifyJS</a> with consolidation of null, Boolean, and String values.
  34. * <p>Also known as aliasing, this feature has been deprecated in <a href=
  35. * "http://closure-compiler.googlecode.com/">the Closure Compiler</a> since its
  36. * initial release, where it is unavailable from the <abbr title=
  37. * "command line interface">CLI</a>. The Closure Compiler allows one to log and
  38. * influence this process. In contrast, this implementation does not introduce
  39. * any variable declarations in global code and derives String values from
  40. * identifier names used as property accessors.</p>
  41. * <p>Consolidating literals may worsen the data compression ratio when an <a
  42. * href="http://tools.ietf.org/html/rfc2616#section-3.5">encoding
  43. * transformation</a> is applied. For instance, <a href=
  44. * "http://code.jquery.com/jquery-1.7.1.js">jQuery 1.7.1</a> takes 248235 bytes.
  45. * Building it with <a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">
  46. * UglifyJS v1.2.5</a> results in 93647 bytes (37.73% of the original) which are
  47. * then compressed to 33154 bytes (13.36% of the original) using <a href=
  48. * "http://linux.die.net/man/1/gzip">gzip(1)</a>. Building it with the same
  49. * version of UglifyJS 1.2.5 patched with the implementation of consolidation
  50. * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison
  51. * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes
  52. * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned
  53. * 33154 bytes).</p>
  54. * <p>Written in <a href="http://es5.github.com/#x4.2.2">the strict variant</a>
  55. * of <a href="http://es5.github.com/">ECMA-262 5.1 Edition</a>. Encoded in <a
  56. * href="http://tools.ietf.org/html/rfc3629">UTF-8</a>. Follows <a href=
  57. * "http://google-styleguide.googlecode.com/svn-history/r76/trunk/javascriptguide.xml"
  58. * >Revision 2.28 of the Google JavaScript Style Guide</a> (except for the
  59. * discouraged use of the {@code function} tag and the {@code namespace} tag).
  60. * 100% typed for the <a href=
  61. * "http://closure-compiler.googlecode.com/files/compiler-20120123.tar.gz"
  62. * >Closure Compiler Version 1741</a>.</p>
  63. * <p>Should you find this software useful, please consider <a href=
  64. * "https://paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JZLW72X8FD4WG"
  65. * >a donation</a>.</p>
  66. * @author follow.me@RGustBardon (Robert Gust-Bardon)
  67. * @supported Tested with:
  68. * <ul>
  69. * <li><a href="http://nodejs.org/dist/v0.6.10/">Node v0.6.10</a>,</li>
  70. * <li><a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">UglifyJS
  71. * v1.2.5</a>.</li>
  72. * </ul>
  73. */
  74. /*global console:false, exports:true, module:false, require:false */
  75. /*jshint sub:true */
  76. /**
  77. * Consolidates null, Boolean, and String values found inside an <abbr title=
  78. * "abstract syntax tree">AST</abbr>.
  79. * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object
  80. * representing an <abbr title="abstract syntax tree">AST</abbr>.
  81. * @return {!TSyntacticCodeUnit} An array-like object representing an <abbr
  82. * title="abstract syntax tree">AST</abbr> with its null, Boolean, and
  83. * String values consolidated.
  84. */
  85. // TODO(user) Consolidation of mathematical values found in numeric literals.
  86. // TODO(user) Unconsolidation.
  87. // TODO(user) Consolidation of ECMA-262 6th Edition programs.
  88. // TODO(user) Rewrite in ECMA-262 6th Edition.
  89. exports['ast_consolidate'] = function(oAbstractSyntaxTree) {
  90. 'use strict';
  91. /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
  92. latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
  93. onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
  94. sub:false, trailing:true */
  95. var _,
  96. /**
  97. * A record consisting of data about one or more source elements.
  98. * @constructor
  99. * @nosideeffects
  100. */
  101. TSourceElementsData = function() {
  102. /**
  103. * The category of the elements.
  104. * @type {number}
  105. * @see ESourceElementCategories
  106. */
  107. this.nCategory = ESourceElementCategories.N_OTHER;
  108. /**
  109. * The number of occurrences (within the elements) of each primitive
  110. * value that could be consolidated.
  111. * @type {!Array.<!Object.<string, number>>}
  112. */
  113. this.aCount = [];
  114. this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {};
  115. this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {};
  116. this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] =
  117. {};
  118. /**
  119. * Identifier names found within the elements.
  120. * @type {!Array.<string>}
  121. */
  122. this.aIdentifiers = [];
  123. /**
  124. * Prefixed representation Strings of each primitive value that could be
  125. * consolidated within the elements.
  126. * @type {!Array.<string>}
  127. */
  128. this.aPrimitiveValues = [];
  129. },
  130. /**
  131. * A record consisting of data about a primitive value that could be
  132. * consolidated.
  133. * @constructor
  134. * @nosideeffects
  135. */
  136. TPrimitiveValue = function() {
  137. /**
  138. * The difference in the number of terminal symbols between the original
  139. * source text and the one with the primitive value consolidated. If the
  140. * difference is positive, the primitive value is considered worthwhile.
  141. * @type {number}
  142. */
  143. this.nSaving = 0;
  144. /**
  145. * An identifier name of the variable that will be declared and assigned
  146. * the primitive value if the primitive value is consolidated.
  147. * @type {string}
  148. */
  149. this.sName = '';
  150. },
  151. /**
  152. * A record consisting of data on what to consolidate within the range of
  153. * source elements that is currently being considered.
  154. * @constructor
  155. * @nosideeffects
  156. */
  157. TSolution = function() {
  158. /**
  159. * An object whose keys are prefixed representation Strings of each
  160. * primitive value that could be consolidated within the elements and
  161. * whose values are corresponding data about those primitive values.
  162. * @type {!Object.<string, {nSaving: number, sName: string}>}
  163. * @see TPrimitiveValue
  164. */
  165. this.oPrimitiveValues = {};
  166. /**
  167. * The difference in the number of terminal symbols between the original
  168. * source text and the one with all the worthwhile primitive values
  169. * consolidated.
  170. * @type {number}
  171. * @see TPrimitiveValue#nSaving
  172. */
  173. this.nSavings = 0;
  174. },
  175. /**
  176. * The processor of <abbr title="abstract syntax tree">AST</abbr>s found
  177. * in UglifyJS.
  178. * @namespace
  179. * @type {!TProcessor}
  180. */
  181. oProcessor = (/** @type {!TProcessor} */ require('./process')),
  182. /**
  183. * A record consisting of a number of constants that represent the
  184. * difference in the number of terminal symbols between a source text with
  185. * a modified syntactic code unit and the original one.
  186. * @namespace
  187. * @type {!Object.<string, number>}
  188. */
  189. oWeights = {
  190. /**
  191. * The difference in the number of punctuators required by the bracket
  192. * notation and the dot notation.
  193. * <p><code>'[]'.length - '.'.length</code></p>
  194. * @const
  195. * @type {number}
  196. */
  197. N_PROPERTY_ACCESSOR: 1,
  198. /**
  199. * The number of punctuators required by a variable declaration with an
  200. * initialiser.
  201. * <p><code>':'.length + ';'.length</code></p>
  202. * @const
  203. * @type {number}
  204. */
  205. N_VARIABLE_DECLARATION: 2,
  206. /**
  207. * The number of terminal symbols required to introduce a variable
  208. * statement (excluding its variable declaration list).
  209. * <p><code>'var '.length</code></p>
  210. * @const
  211. * @type {number}
  212. */
  213. N_VARIABLE_STATEMENT_AFFIXATION: 4,
  214. /**
  215. * The number of terminal symbols needed to enclose source elements
  216. * within a function call with no argument values to a function with an
  217. * empty parameter list.
  218. * <p><code>'(function(){}());'.length</code></p>
  219. * @const
  220. * @type {number}
  221. */
  222. N_CLOSURE: 17
  223. },
  224. /**
  225. * Categories of primary expressions from which primitive values that
  226. * could be consolidated are derivable.
  227. * @namespace
  228. * @enum {number}
  229. */
  230. EPrimaryExpressionCategories = {
  231. /**
  232. * Identifier names used as property accessors.
  233. * @type {number}
  234. */
  235. N_IDENTIFIER_NAMES: 0,
  236. /**
  237. * String literals.
  238. * @type {number}
  239. */
  240. N_STRING_LITERALS: 1,
  241. /**
  242. * Null and Boolean literals.
  243. * @type {number}
  244. */
  245. N_NULL_AND_BOOLEAN_LITERALS: 2
  246. },
  247. /**
  248. * Prefixes of primitive values that could be consolidated.
  249. * The String values of the prefixes must have same number of characters.
  250. * The prefixes must not be used in any properties defined in any version
  251. * of <a href=
  252. * "http://www.ecma-international.org/publications/standards/Ecma-262.htm"
  253. * >ECMA-262</a>.
  254. * @namespace
  255. * @enum {string}
  256. */
  257. EValuePrefixes = {
  258. /**
  259. * Identifies String values.
  260. * @type {string}
  261. */
  262. S_STRING: '#S',
  263. /**
  264. * Identifies null and Boolean values.
  265. * @type {string}
  266. */
  267. S_SYMBOLIC: '#O'
  268. },
  269. /**
  270. * Categories of source elements in terms of their appropriateness of
  271. * having their primitive values consolidated.
  272. * @namespace
  273. * @enum {number}
  274. */
  275. ESourceElementCategories = {
  276. /**
  277. * Identifies a source element that includes the <a href=
  278. * "http://es5.github.com/#x12.10">{@code with}</a> statement.
  279. * @type {number}
  280. */
  281. N_WITH: 0,
  282. /**
  283. * Identifies a source element that includes the <a href=
  284. * "http://es5.github.com/#x15.1.2.1">{@code eval}</a> identifier name.
  285. * @type {number}
  286. */
  287. N_EVAL: 1,
  288. /**
  289. * Identifies a source element that must be excluded from the process
  290. * unless its whole scope is examined.
  291. * @type {number}
  292. */
  293. N_EXCLUDABLE: 2,
  294. /**
  295. * Identifies source elements not posing any problems.
  296. * @type {number}
  297. */
  298. N_OTHER: 3
  299. },
  300. /**
  301. * The list of literals (other than the String ones) whose primitive
  302. * values can be consolidated.
  303. * @const
  304. * @type {!Array.<string>}
  305. */
  306. A_OTHER_SUBSTITUTABLE_LITERALS = [
  307. 'null', // The null literal.
  308. 'false', // The Boolean literal {@code false}.
  309. 'true' // The Boolean literal {@code true}.
  310. ];
  311. (/**
  312. * Consolidates all worthwhile primitive values in a syntactic code unit.
  313. * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object
  314. * representing the branch of the abstract syntax tree representing the
  315. * syntactic code unit along with its scope.
  316. * @see TPrimitiveValue#nSaving
  317. */
  318. function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) {
  319. var _,
  320. /**
  321. * Indicates whether the syntactic code unit represents global code.
  322. * @type {boolean}
  323. */
  324. bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0],
  325. /**
  326. * Indicates whether the whole scope is being examined.
  327. * @type {boolean}
  328. */
  329. bIsWhollyExaminable = !bIsGlobal,
  330. /**
  331. * An array-like object representing source elements that constitute a
  332. * syntactic code unit.
  333. * @type {!TSyntacticCodeUnit}
  334. */
  335. oSourceElements,
  336. /**
  337. * A record consisting of data about the source element that is
  338. * currently being examined.
  339. * @type {!TSourceElementsData}
  340. */
  341. oSourceElementData,
  342. /**
  343. * The scope of the syntactic code unit.
  344. * @type {!TScope}
  345. */
  346. oScope,
  347. /**
  348. * An instance of an object that allows the traversal of an <abbr
  349. * title="abstract syntax tree">AST</abbr>.
  350. * @type {!TWalker}
  351. */
  352. oWalker,
  353. /**
  354. * An object encompassing collections of functions used during the
  355. * traversal of an <abbr title="abstract syntax tree">AST</abbr>.
  356. * @namespace
  357. * @type {!Object.<string, !Object.<string, function(...[*])>>}
  358. */
  359. oWalkers = {
  360. /**
  361. * A collection of functions used during the surveyance of source
  362. * elements.
  363. * @namespace
  364. * @type {!Object.<string, function(...[*])>}
  365. */
  366. oSurveySourceElement: {
  367. /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  368. /**
  369. * Classifies the source element as excludable if it does not
  370. * contain a {@code with} statement or the {@code eval} identifier
  371. * name. Adds the identifier of the function and its formal
  372. * parameters to the list of identifier names found.
  373. * @param {string} sIdentifier The identifier of the function.
  374. * @param {!Array.<string>} aFormalParameterList Formal parameters.
  375. * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
  376. */
  377. 'defun': function(
  378. sIdentifier,
  379. aFormalParameterList,
  380. oFunctionBody) {
  381. fClassifyAsExcludable();
  382. fAddIdentifier(sIdentifier);
  383. aFormalParameterList.forEach(fAddIdentifier);
  384. },
  385. /**
  386. * Increments the count of the number of occurrences of the String
  387. * value that is equivalent to the sequence of terminal symbols
  388. * that constitute the encountered identifier name.
  389. * @param {!TSyntacticCodeUnit} oExpression The nonterminal
  390. * MemberExpression.
  391. * @param {string} sIdentifierName The identifier name used as the
  392. * property accessor.
  393. * @return {!Array} The encountered branch of an <abbr title=
  394. * "abstract syntax tree">AST</abbr> with its nonterminal
  395. * MemberExpression traversed.
  396. */
  397. 'dot': function(oExpression, sIdentifierName) {
  398. fCountPrimaryExpression(
  399. EPrimaryExpressionCategories.N_IDENTIFIER_NAMES,
  400. EValuePrefixes.S_STRING + sIdentifierName);
  401. return ['dot', oWalker.walk(oExpression), sIdentifierName];
  402. },
  403. /**
  404. * Adds the optional identifier of the function and its formal
  405. * parameters to the list of identifier names found.
  406. * @param {?string} sIdentifier The optional identifier of the
  407. * function.
  408. * @param {!Array.<string>} aFormalParameterList Formal parameters.
  409. * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
  410. */
  411. 'function': function(
  412. sIdentifier,
  413. aFormalParameterList,
  414. oFunctionBody) {
  415. if ('string' === typeof sIdentifier) {
  416. fAddIdentifier(sIdentifier);
  417. }
  418. aFormalParameterList.forEach(fAddIdentifier);
  419. },
  420. /**
  421. * Either increments the count of the number of occurrences of the
  422. * encountered null or Boolean value or classifies a source element
  423. * as containing the {@code eval} identifier name.
  424. * @param {string} sIdentifier The identifier encountered.
  425. */
  426. 'name': function(sIdentifier) {
  427. if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) {
  428. fCountPrimaryExpression(
  429. EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS,
  430. EValuePrefixes.S_SYMBOLIC + sIdentifier);
  431. } else {
  432. if ('eval' === sIdentifier) {
  433. oSourceElementData.nCategory =
  434. ESourceElementCategories.N_EVAL;
  435. }
  436. fAddIdentifier(sIdentifier);
  437. }
  438. },
  439. /**
  440. * Classifies the source element as excludable if it does not
  441. * contain a {@code with} statement or the {@code eval} identifier
  442. * name.
  443. * @param {TSyntacticCodeUnit} oExpression The expression whose
  444. * value is to be returned.
  445. */
  446. 'return': function(oExpression) {
  447. fClassifyAsExcludable();
  448. },
  449. /**
  450. * Increments the count of the number of occurrences of the
  451. * encountered String value.
  452. * @param {string} sStringValue The String value of the string
  453. * literal encountered.
  454. */
  455. 'string': function(sStringValue) {
  456. if (sStringValue.length > 0) {
  457. fCountPrimaryExpression(
  458. EPrimaryExpressionCategories.N_STRING_LITERALS,
  459. EValuePrefixes.S_STRING + sStringValue);
  460. }
  461. },
  462. /**
  463. * Adds the identifier reserved for an exception to the list of
  464. * identifier names found.
  465. * @param {!TSyntacticCodeUnit} oTry A block of code in which an
  466. * exception can occur.
  467. * @param {Array} aCatch The identifier reserved for an exception
  468. * and a block of code to handle the exception.
  469. * @param {TSyntacticCodeUnit} oFinally An optional block of code
  470. * to be evaluated regardless of whether an exception occurs.
  471. */
  472. 'try': function(oTry, aCatch, oFinally) {
  473. if (Array.isArray(aCatch)) {
  474. fAddIdentifier(aCatch[0]);
  475. }
  476. },
  477. /**
  478. * Classifies the source element as excludable if it does not
  479. * contain a {@code with} statement or the {@code eval} identifier
  480. * name. Adds the identifier of each declared variable to the list
  481. * of identifier names found.
  482. * @param {!Array.<!Array>} aVariableDeclarationList Variable
  483. * declarations.
  484. */
  485. 'var': function(aVariableDeclarationList) {
  486. fClassifyAsExcludable();
  487. aVariableDeclarationList.forEach(fAddVariable);
  488. },
  489. /**
  490. * Classifies a source element as containing the {@code with}
  491. * statement.
  492. * @param {!TSyntacticCodeUnit} oExpression An expression whose
  493. * value is to be converted to a value of type Object and
  494. * become the binding object of a new object environment
  495. * record of a new lexical environment in which the statement
  496. * is to be executed.
  497. * @param {!TSyntacticCodeUnit} oStatement The statement to be
  498. * executed in the augmented lexical environment.
  499. * @return {!Array} An empty array to stop the traversal.
  500. */
  501. 'with': function(oExpression, oStatement) {
  502. oSourceElementData.nCategory = ESourceElementCategories.N_WITH;
  503. return [];
  504. }
  505. /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  506. },
  507. /**
  508. * A collection of functions used while looking for nested functions.
  509. * @namespace
  510. * @type {!Object.<string, function(...[*])>}
  511. */
  512. oExamineFunctions: {
  513. /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  514. /**
  515. * Orders an examination of a nested function declaration.
  516. * @this {!TSyntacticCodeUnit} An array-like object representing
  517. * the branch of an <abbr title="abstract syntax tree"
  518. * >AST</abbr> representing the syntactic code unit along with
  519. * its scope.
  520. * @return {!Array} An empty array to stop the traversal.
  521. */
  522. 'defun': function() {
  523. fExamineSyntacticCodeUnit(this);
  524. return [];
  525. },
  526. /**
  527. * Orders an examination of a nested function expression.
  528. * @this {!TSyntacticCodeUnit} An array-like object representing
  529. * the branch of an <abbr title="abstract syntax tree"
  530. * >AST</abbr> representing the syntactic code unit along with
  531. * its scope.
  532. * @return {!Array} An empty array to stop the traversal.
  533. */
  534. 'function': function() {
  535. fExamineSyntacticCodeUnit(this);
  536. return [];
  537. }
  538. /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  539. }
  540. },
  541. /**
  542. * Records containing data about source elements.
  543. * @type {Array.<TSourceElementsData>}
  544. */
  545. aSourceElementsData = [],
  546. /**
  547. * The index (in the source text order) of the source element
  548. * immediately following a <a href="http://es5.github.com/#x14.1"
  549. * >Directive Prologue</a>.
  550. * @type {number}
  551. */
  552. nAfterDirectivePrologue = 0,
  553. /**
  554. * The index (in the source text order) of the source element that is
  555. * currently being considered.
  556. * @type {number}
  557. */
  558. nPosition,
  559. /**
  560. * The index (in the source text order) of the source element that is
  561. * the last element of the range of source elements that is currently
  562. * being considered.
  563. * @type {(undefined|number)}
  564. */
  565. nTo,
  566. /**
  567. * Initiates the traversal of a source element.
  568. * @param {!TWalker} oWalker An instance of an object that allows the
  569. * traversal of an abstract syntax tree.
  570. * @param {!TSyntacticCodeUnit} oSourceElement A source element from
  571. * which the traversal should commence.
  572. * @return {function(): !TSyntacticCodeUnit} A function that is able to
  573. * initiate the traversal from a given source element.
  574. */
  575. cContext = function(oWalker, oSourceElement) {
  576. /**
  577. * @return {!TSyntacticCodeUnit} A function that is able to
  578. * initiate the traversal from a given source element.
  579. */
  580. var fLambda = function() {
  581. return oWalker.walk(oSourceElement);
  582. };
  583. return fLambda;
  584. },
  585. /**
  586. * Classifies the source element as excludable if it does not
  587. * contain a {@code with} statement or the {@code eval} identifier
  588. * name.
  589. */
  590. fClassifyAsExcludable = function() {
  591. if (oSourceElementData.nCategory ===
  592. ESourceElementCategories.N_OTHER) {
  593. oSourceElementData.nCategory =
  594. ESourceElementCategories.N_EXCLUDABLE;
  595. }
  596. },
  597. /**
  598. * Adds an identifier to the list of identifier names found.
  599. * @param {string} sIdentifier The identifier to be added.
  600. */
  601. fAddIdentifier = function(sIdentifier) {
  602. if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) {
  603. oSourceElementData.aIdentifiers.push(sIdentifier);
  604. }
  605. },
  606. /**
  607. * Adds the identifier of a variable to the list of identifier names
  608. * found.
  609. * @param {!Array} aVariableDeclaration A variable declaration.
  610. */
  611. fAddVariable = function(aVariableDeclaration) {
  612. fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]);
  613. },
  614. /**
  615. * Increments the count of the number of occurrences of the prefixed
  616. * String representation attributed to the primary expression.
  617. * @param {number} nCategory The category of the primary expression.
  618. * @param {string} sName The prefixed String representation attributed
  619. * to the primary expression.
  620. */
  621. fCountPrimaryExpression = function(nCategory, sName) {
  622. if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) {
  623. oSourceElementData.aCount[nCategory][sName] = 0;
  624. if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) {
  625. oSourceElementData.aPrimitiveValues.push(sName);
  626. }
  627. }
  628. oSourceElementData.aCount[nCategory][sName] += 1;
  629. },
  630. /**
  631. * Consolidates all worthwhile primitive values in a range of source
  632. * elements.
  633. * @param {number} nFrom The index (in the source text order) of the
  634. * source element that is the first element of the range.
  635. * @param {number} nTo The index (in the source text order) of the
  636. * source element that is the last element of the range.
  637. * @param {boolean} bEnclose Indicates whether the range should be
  638. * enclosed within a function call with no argument values to a
  639. * function with an empty parameter list if any primitive values
  640. * are consolidated.
  641. * @see TPrimitiveValue#nSaving
  642. */
  643. fExamineSourceElements = function(nFrom, nTo, bEnclose) {
  644. var _,
  645. /**
  646. * The index of the last mangled name.
  647. * @type {number}
  648. */
  649. nIndex = oScope.cname,
  650. /**
  651. * The index of the source element that is currently being
  652. * considered.
  653. * @type {number}
  654. */
  655. nPosition,
  656. /**
  657. * A collection of functions used during the consolidation of
  658. * primitive values and identifier names used as property
  659. * accessors.
  660. * @namespace
  661. * @type {!Object.<string, function(...[*])>}
  662. */
  663. oWalkersTransformers = {
  664. /**
  665. * If the String value that is equivalent to the sequence of
  666. * terminal symbols that constitute the encountered identifier
  667. * name is worthwhile, a syntactic conversion from the dot
  668. * notation to the bracket notation ensues with that sequence
  669. * being substituted by an identifier name to which the value
  670. * is assigned.
  671. * Applies to property accessors that use the dot notation.
  672. * @param {!TSyntacticCodeUnit} oExpression The nonterminal
  673. * MemberExpression.
  674. * @param {string} sIdentifierName The identifier name used as
  675. * the property accessor.
  676. * @return {!Array} A syntactic code unit that is equivalent to
  677. * the one encountered.
  678. * @see TPrimitiveValue#nSaving
  679. */
  680. 'dot': function(oExpression, sIdentifierName) {
  681. /**
  682. * The prefixed String value that is equivalent to the
  683. * sequence of terminal symbols that constitute the
  684. * encountered identifier name.
  685. * @type {string}
  686. */
  687. var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName;
  688. return oSolutionBest.oPrimitiveValues.hasOwnProperty(
  689. sPrefixed) &&
  690. oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
  691. ['sub',
  692. oWalker.walk(oExpression),
  693. ['name',
  694. oSolutionBest.oPrimitiveValues[sPrefixed].sName]] :
  695. ['dot', oWalker.walk(oExpression), sIdentifierName];
  696. },
  697. /**
  698. * If the encountered identifier is a null or Boolean literal
  699. * and its value is worthwhile, the identifier is substituted
  700. * by an identifier name to which that value is assigned.
  701. * Applies to identifier names.
  702. * @param {string} sIdentifier The identifier encountered.
  703. * @return {!Array} A syntactic code unit that is equivalent to
  704. * the one encountered.
  705. * @see TPrimitiveValue#nSaving
  706. */
  707. 'name': function(sIdentifier) {
  708. /**
  709. * The prefixed representation String of the identifier.
  710. * @type {string}
  711. */
  712. var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier;
  713. return [
  714. 'name',
  715. oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) &&
  716. oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
  717. oSolutionBest.oPrimitiveValues[sPrefixed].sName :
  718. sIdentifier
  719. ];
  720. },
  721. /**
  722. * If the encountered String value is worthwhile, it is
  723. * substituted by an identifier name to which that value is
  724. * assigned.
  725. * Applies to String values.
  726. * @param {string} sStringValue The String value of the string
  727. * literal encountered.
  728. * @return {!Array} A syntactic code unit that is equivalent to
  729. * the one encountered.
  730. * @see TPrimitiveValue#nSaving
  731. */
  732. 'string': function(sStringValue) {
  733. /**
  734. * The prefixed representation String of the primitive value
  735. * of the literal.
  736. * @type {string}
  737. */
  738. var sPrefixed =
  739. EValuePrefixes.S_STRING + sStringValue;
  740. return oSolutionBest.oPrimitiveValues.hasOwnProperty(
  741. sPrefixed) &&
  742. oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
  743. ['name',
  744. oSolutionBest.oPrimitiveValues[sPrefixed].sName] :
  745. ['string', sStringValue];
  746. }
  747. },
  748. /**
  749. * Such data on what to consolidate within the range of source
  750. * elements that is currently being considered that lead to the
  751. * greatest known reduction of the number of the terminal symbols
  752. * in comparison to the original source text.
  753. * @type {!TSolution}
  754. */
  755. oSolutionBest = new TSolution(),
  756. /**
  757. * Data representing an ongoing attempt to find a better
  758. * reduction of the number of the terminal symbols in comparison
  759. * to the original source text than the best one that is
  760. * currently known.
  761. * @type {!TSolution}
  762. * @see oSolutionBest
  763. */
  764. oSolutionCandidate = new TSolution(),
  765. /**
  766. * A record consisting of data about the range of source elements
  767. * that is currently being examined.
  768. * @type {!TSourceElementsData}
  769. */
  770. oSourceElementsData = new TSourceElementsData(),
  771. /**
  772. * Variable declarations for each primitive value that is to be
  773. * consolidated within the elements.
  774. * @type {!Array.<!Array>}
  775. */
  776. aVariableDeclarations = [],
  777. /**
  778. * Augments a list with a prefixed representation String.
  779. * @param {!Array.<string>} aList A list that is to be augmented.
  780. * @return {function(string)} A function that augments a list
  781. * with a prefixed representation String.
  782. */
  783. cAugmentList = function(aList) {
  784. /**
  785. * @param {string} sPrefixed Prefixed representation String of
  786. * a primitive value that could be consolidated within the
  787. * elements.
  788. */
  789. var fLambda = function(sPrefixed) {
  790. if (-1 === aList.indexOf(sPrefixed)) {
  791. aList.push(sPrefixed);
  792. }
  793. };
  794. return fLambda;
  795. },
  796. /**
  797. * Adds the number of occurrences of a primitive value of a given
  798. * category that could be consolidated in the source element with
  799. * a given index to the count of occurrences of that primitive
  800. * value within the range of source elements that is currently
  801. * being considered.
  802. * @param {number} nPosition The index (in the source text order)
  803. * of a source element.
  804. * @param {number} nCategory The category of the primary
  805. * expression from which the primitive value is derived.
  806. * @return {function(string)} A function that performs the
  807. * addition.
  808. * @see cAddOccurrencesInCategory
  809. */
  810. cAddOccurrences = function(nPosition, nCategory) {
  811. /**
  812. * @param {string} sPrefixed The prefixed representation String
  813. * of a primitive value.
  814. */
  815. var fLambda = function(sPrefixed) {
  816. if (!oSourceElementsData.aCount[nCategory].hasOwnProperty(
  817. sPrefixed)) {
  818. oSourceElementsData.aCount[nCategory][sPrefixed] = 0;
  819. }
  820. oSourceElementsData.aCount[nCategory][sPrefixed] +=
  821. aSourceElementsData[nPosition].aCount[nCategory][
  822. sPrefixed];
  823. };
  824. return fLambda;
  825. },
  826. /**
  827. * Adds the number of occurrences of each primitive value of a
  828. * given category that could be consolidated in the source
  829. * element with a given index to the count of occurrences of that
  830. * primitive values within the range of source elements that is
  831. * currently being considered.
  832. * @param {number} nPosition The index (in the source text order)
  833. * of a source element.
  834. * @return {function(number)} A function that performs the
  835. * addition.
  836. * @see fAddOccurrences
  837. */
  838. cAddOccurrencesInCategory = function(nPosition) {
  839. /**
  840. * @param {number} nCategory The category of the primary
  841. * expression from which the primitive value is derived.
  842. */
  843. var fLambda = function(nCategory) {
  844. Object.keys(
  845. aSourceElementsData[nPosition].aCount[nCategory]
  846. ).forEach(cAddOccurrences(nPosition, nCategory));
  847. };
  848. return fLambda;
  849. },
  850. /**
  851. * Adds the number of occurrences of each primitive value that
  852. * could be consolidated in the source element with a given index
  853. * to the count of occurrences of that primitive values within
  854. * the range of source elements that is currently being
  855. * considered.
  856. * @param {number} nPosition The index (in the source text order)
  857. * of a source element.
  858. */
  859. fAddOccurrences = function(nPosition) {
  860. Object.keys(aSourceElementsData[nPosition].aCount).forEach(
  861. cAddOccurrencesInCategory(nPosition));
  862. },
  863. /**
  864. * Creates a variable declaration for a primitive value if that
  865. * primitive value is to be consolidated within the elements.
  866. * @param {string} sPrefixed Prefixed representation String of a
  867. * primitive value that could be consolidated within the
  868. * elements.
  869. * @see aVariableDeclarations
  870. */
  871. cAugmentVariableDeclarations = function(sPrefixed) {
  872. if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) {
  873. aVariableDeclarations.push([
  874. oSolutionBest.oPrimitiveValues[sPrefixed].sName,
  875. [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ?
  876. 'name' : 'string',
  877. sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)]
  878. ]);
  879. }
  880. },
  881. /**
  882. * Sorts primitive values with regard to the difference in the
  883. * number of terminal symbols between the original source text
  884. * and the one with those primitive values consolidated.
  885. * @param {string} sPrefixed0 The prefixed representation String
  886. * of the first of the two primitive values that are being
  887. * compared.
  888. * @param {string} sPrefixed1 The prefixed representation String
  889. * of the second of the two primitive values that are being
  890. * compared.
  891. * @return {number}
  892. * <dl>
  893. * <dt>-1</dt>
  894. * <dd>if the first primitive value must be placed before
  895. * the other one,</dd>
  896. * <dt>0</dt>
  897. * <dd>if the first primitive value may be placed before
  898. * the other one,</dd>
  899. * <dt>1</dt>
  900. * <dd>if the first primitive value must not be placed
  901. * before the other one.</dd>
  902. * </dl>
  903. * @see TSolution.oPrimitiveValues
  904. */
  905. cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) {
  906. /**
  907. * The difference between:
  908. * <ol>
  909. * <li>the difference in the number of terminal symbols
  910. * between the original source text and the one with the
  911. * first primitive value consolidated, and</li>
  912. * <li>the difference in the number of terminal symbols
  913. * between the original source text and the one with the
  914. * second primitive value consolidated.</li>
  915. * </ol>
  916. * @type {number}
  917. */
  918. var nDifference =
  919. oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving -
  920. oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving;
  921. return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0;
  922. },
  923. /**
  924. * Assigns an identifier name to a primitive value and calculates
  925. * whether instances of that primitive value are worth
  926. * consolidating.
  927. * @param {string} sPrefixed The prefixed representation String
  928. * of a primitive value that is being evaluated.
  929. */
  930. fEvaluatePrimitiveValue = function(sPrefixed) {
  931. var _,
  932. /**
  933. * The index of the last mangled name.
  934. * @type {number}
  935. */
  936. nIndex,
  937. /**
  938. * The representation String of the primitive value that is
  939. * being evaluated.
  940. * @type {string}
  941. */
  942. sName =
  943. sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length),
  944. /**
  945. * The number of source characters taken up by the
  946. * representation String of the primitive value that is
  947. * being evaluated.
  948. * @type {number}
  949. */
  950. nLengthOriginal = sName.length,
  951. /**
  952. * The number of source characters taken up by the
  953. * identifier name that could substitute the primitive
  954. * value that is being evaluated.
  955. * substituted.
  956. * @type {number}
  957. */
  958. nLengthSubstitution,
  959. /**
  960. * The number of source characters taken up by by the
  961. * representation String of the primitive value that is
  962. * being evaluated when it is represented by a string
  963. * literal.
  964. * @type {number}
  965. */
  966. nLengthString = oProcessor.make_string(sName).length;
  967. oSolutionCandidate.oPrimitiveValues[sPrefixed] =
  968. new TPrimitiveValue();
  969. do { // Find an identifier unused in this or any nested scope.
  970. nIndex = oScope.cname;
  971. oSolutionCandidate.oPrimitiveValues[sPrefixed].sName =
  972. oScope.next_mangled();
  973. } while (-1 !== oSourceElementsData.aIdentifiers.indexOf(
  974. oSolutionCandidate.oPrimitiveValues[sPrefixed].sName));
  975. nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[
  976. sPrefixed].sName.length;
  977. if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) {
  978. // foo:null, or foo:null;
  979. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
  980. nLengthSubstitution + nLengthOriginal +
  981. oWeights.N_VARIABLE_DECLARATION;
  982. // null vs foo
  983. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
  984. oSourceElementsData.aCount[
  985. EPrimaryExpressionCategories.
  986. N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] *
  987. (nLengthOriginal - nLengthSubstitution);
  988. } else {
  989. // foo:'fromCharCode';
  990. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
  991. nLengthSubstitution + nLengthString +
  992. oWeights.N_VARIABLE_DECLARATION;
  993. // .fromCharCode vs [foo]
  994. if (oSourceElementsData.aCount[
  995. EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
  996. ].hasOwnProperty(sPrefixed)) {
  997. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
  998. oSourceElementsData.aCount[
  999. EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
  1000. ][sPrefixed] *
  1001. (nLengthOriginal - nLengthSubstitution -
  1002. oWeights.N_PROPERTY_ACCESSOR);
  1003. }
  1004. // 'fromCharCode' vs foo
  1005. if (oSourceElementsData.aCount[
  1006. EPrimaryExpressionCategories.N_STRING_LITERALS
  1007. ].hasOwnProperty(sPrefixed)) {
  1008. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
  1009. oSourceElementsData.aCount[
  1010. EPrimaryExpressionCategories.N_STRING_LITERALS
  1011. ][sPrefixed] *
  1012. (nLengthString - nLengthSubstitution);
  1013. }
  1014. }
  1015. if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving >
  1016. 0) {
  1017. oSolutionCandidate.nSavings +=
  1018. oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving;
  1019. } else {
  1020. oScope.cname = nIndex; // Free the identifier name.
  1021. }
  1022. },
  1023. /**
  1024. * Adds a variable declaration to an existing variable statement.
  1025. * @param {!Array} aVariableDeclaration A variable declaration
  1026. * with an initialiser.
  1027. */
  1028. cAddVariableDeclaration = function(aVariableDeclaration) {
  1029. (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift(
  1030. aVariableDeclaration);
  1031. };
  1032. if (nFrom > nTo) {
  1033. return;
  1034. }
  1035. // If the range is a closure, reuse the closure.
  1036. if (nFrom === nTo &&
  1037. 'stat' === oSourceElements[nFrom][0] &&
  1038. 'call' === oSourceElements[nFrom][1][0] &&
  1039. 'function' === oSourceElements[nFrom][1][1][0]) {
  1040. fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]);
  1041. return;
  1042. }
  1043. // Create a list of all derived primitive values within the range.
  1044. for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
  1045. aSourceElementsData[nPosition].aPrimitiveValues.forEach(
  1046. cAugmentList(oSourceElementsData.aPrimitiveValues));
  1047. }
  1048. if (0 === oSourceElementsData.aPrimitiveValues.length) {
  1049. return;
  1050. }
  1051. for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
  1052. // Add the number of occurrences to the total count.
  1053. fAddOccurrences(nPosition);
  1054. // Add identifiers of this or any nested scope to the list.
  1055. aSourceElementsData[nPosition].aIdentifiers.forEach(
  1056. cAugmentList(oSourceElementsData.aIdentifiers));
  1057. }
  1058. // Distribute identifier names among derived primitive values.
  1059. do { // If there was any progress, find a better distribution.
  1060. oSolutionBest = oSolutionCandidate;
  1061. if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) {
  1062. // Sort primitive values descending by their worthwhileness.
  1063. oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues);
  1064. }
  1065. oSolutionCandidate = new TSolution();
  1066. oSourceElementsData.aPrimitiveValues.forEach(
  1067. fEvaluatePrimitiveValue);
  1068. oScope.cname = nIndex;
  1069. } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings);
  1070. // Take the necessity of adding a variable statement into account.
  1071. if ('var' !== oSourceElements[nFrom][0]) {
  1072. oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION;
  1073. }
  1074. if (bEnclose) {
  1075. // Take the necessity of forming a closure into account.
  1076. oSolutionBest.nSavings -= oWeights.N_CLOSURE;
  1077. }
  1078. if (oSolutionBest.nSavings > 0) {
  1079. // Create variable declarations suitable for UglifyJS.
  1080. Object.keys(oSolutionBest.oPrimitiveValues).forEach(
  1081. cAugmentVariableDeclarations);
  1082. // Rewrite expressions that contain worthwhile primitive values.
  1083. for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
  1084. oWalker = oProcessor.ast_walker();
  1085. oSourceElements[nPosition] =
  1086. oWalker.with_walkers(
  1087. oWalkersTransformers,
  1088. cContext(oWalker, oSourceElements[nPosition]));
  1089. }
  1090. if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement.
  1091. (/** @type {!Array.<!Array>} */ aVariableDeclarations.reverse(
  1092. )).forEach(cAddVariableDeclaration);
  1093. } else { // Add a variable statement.
  1094. Array.prototype.splice.call(
  1095. oSourceElements,
  1096. nFrom,
  1097. 0,
  1098. ['var', aVariableDeclarations]);
  1099. nTo += 1;
  1100. }
  1101. if (bEnclose) {
  1102. // Add a closure.
  1103. Array.prototype.splice.call(
  1104. oSourceElements,
  1105. nFrom,
  1106. 0,
  1107. ['stat', ['call', ['function', null, [], []], []]]);
  1108. // Copy source elements into the closure.
  1109. for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) {
  1110. Array.prototype.unshift.call(
  1111. oSourceElements[nFrom][1][1][3],
  1112. oSourceElements[nPosition]);
  1113. }
  1114. // Remove source elements outside the closure.
  1115. Array.prototype.splice.call(
  1116. oSourceElements,
  1117. nFrom + 1,
  1118. nTo - nFrom + 1);
  1119. }
  1120. }
  1121. if (bEnclose) {
  1122. // Restore the availability of identifier names.
  1123. oScope.cname = nIndex;
  1124. }
  1125. };
  1126. oSourceElements = (/** @type {!TSyntacticCodeUnit} */
  1127. oSyntacticCodeUnit[bIsGlobal ? 1 : 3]);
  1128. if (0 === oSourceElements.length) {
  1129. return;
  1130. }
  1131. oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope;
  1132. // Skip a Directive Prologue.
  1133. while (nAfterDirectivePrologue < oSourceElements.length &&
  1134. 'stat' === oSourceElements[nAfterDirectivePrologue][0] &&
  1135. 'string' === oSourceElements[nAfterDirectivePrologue][1][0]) {
  1136. nAfterDirectivePrologue += 1;
  1137. aSourceElementsData.push(null);
  1138. }
  1139. if (oSourceElements.length === nAfterDirectivePrologue) {
  1140. return;
  1141. }
  1142. for (nPosition = nAfterDirectivePrologue;
  1143. nPosition < oSourceElements.length;
  1144. nPosition += 1) {
  1145. oSourceElementData = new TSourceElementsData();
  1146. oWalker = oProcessor.ast_walker();
  1147. // Classify a source element.
  1148. // Find its derived primitive values and count their occurrences.
  1149. // Find all identifiers used (including nested scopes).
  1150. oWalker.with_walkers(
  1151. oWalkers.oSurveySourceElement,
  1152. cContext(oWalker, oSourceElements[nPosition]));
  1153. // Establish whether the scope is still wholly examinable.
  1154. bIsWhollyExaminable = bIsWhollyExaminable &&
  1155. ESourceElementCategories.N_WITH !== oSourceElementData.nCategory &&
  1156. ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory;
  1157. aSourceElementsData.push(oSourceElementData);
  1158. }
  1159. if (bIsWhollyExaminable) { // Examine the whole scope.
  1160. fExamineSourceElements(
  1161. nAfterDirectivePrologue,
  1162. oSourceElements.length - 1,
  1163. false);
  1164. } else { // Examine unexcluded ranges of source elements.
  1165. for (nPosition = oSourceElements.length - 1;
  1166. nPosition >= nAfterDirectivePrologue;
  1167. nPosition -= 1) {
  1168. oSourceElementData = (/** @type {!TSourceElementsData} */
  1169. aSourceElementsData[nPosition]);
  1170. if (ESourceElementCategories.N_OTHER ===
  1171. oSourceElementData.nCategory) {
  1172. if ('undefined' === typeof nTo) {
  1173. nTo = nPosition; // Indicate the end of a range.
  1174. }
  1175. // Examine the range if it immediately follows a Directive Prologue.
  1176. if (nPosition === nAfterDirectivePrologue) {
  1177. fExamineSourceElements(nPosition, nTo, true);
  1178. }
  1179. } else {
  1180. if ('undefined' !== typeof nTo) {
  1181. // Examine the range that immediately follows this source element.
  1182. fExamineSourceElements(nPosition + 1, nTo, true);
  1183. nTo = void 0; // Obliterate the range.
  1184. }
  1185. // Examine nested functions.
  1186. oWalker = oProcessor.ast_walker();
  1187. oWalker.with_walkers(
  1188. oWalkers.oExamineFunctions,
  1189. cContext(oWalker, oSourceElements[nPosition]));
  1190. }
  1191. }
  1192. }
  1193. }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree)));
  1194. return oAbstractSyntaxTree;
  1195. };
  1196. /*jshint sub:false */
  1197. if (require.main === module) {
  1198. (function() {
  1199. 'use strict';
  1200. /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
  1201. latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
  1202. onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
  1203. sub:false, trailing:true */
  1204. var _,
  1205. /**
  1206. * NodeJS module for unit testing.
  1207. * @namespace
  1208. * @type {!TAssert}
  1209. * @see http://nodejs.org/docs/v0.6.10/api/all.html#assert
  1210. */
  1211. oAssert = (/** @type {!TAssert} */ require('assert')),
  1212. /**
  1213. * The parser of ECMA-262 found in UglifyJS.
  1214. * @namespace
  1215. * @type {!TParser}
  1216. */
  1217. oParser = (/** @type {!TParser} */ require('./parse-js')),
  1218. /**
  1219. * The processor of <abbr title="abstract syntax tree">AST</abbr>s
  1220. * found in UglifyJS.
  1221. * @namespace
  1222. * @type {!TProcessor}
  1223. */
  1224. oProcessor = (/** @type {!TProcessor} */ require('./process')),
  1225. /**
  1226. * An instance of an object that allows the traversal of an <abbr
  1227. * title="abstract syntax tree">AST</abbr>.
  1228. * @type {!TWalker}
  1229. */
  1230. oWalker,
  1231. /**
  1232. * A collection of functions for the removal of the scope information
  1233. * during the traversal of an <abbr title="abstract syntax tree"
  1234. * >AST</abbr>.
  1235. * @namespace
  1236. * @type {!Object.<string, function(...[*])>}
  1237. */
  1238. oWalkersPurifiers = {
  1239. /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  1240. /**
  1241. * Deletes the scope information from the branch of the abstract
  1242. * syntax tree representing the encountered function declaration.
  1243. * @param {string} sIdentifier The identifier of the function.
  1244. * @param {!Array.<string>} aFormalParameterList Formal parameters.
  1245. * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
  1246. */
  1247. 'defun': function(
  1248. sIdentifier,
  1249. aFormalParameterList,
  1250. oFunctionBody) {
  1251. delete oFunctionBody.scope;
  1252. },
  1253. /**
  1254. * Deletes the scope information from the branch of the abstract
  1255. * syntax tree representing the encountered function expression.
  1256. * @param {?string} sIdentifier The optional identifier of the
  1257. * function.
  1258. * @param {!Array.<string>} aFormalParameterList Formal parameters.
  1259. * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
  1260. */
  1261. 'function': function(
  1262. sIdentifier,
  1263. aFormalParameterList,
  1264. oFunctionBody) {
  1265. delete oFunctionBody.scope;
  1266. }
  1267. /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
  1268. },
  1269. /**
  1270. * Initiates the traversal of a source element.
  1271. * @param {!TWalker} oWalker An instance of an object that allows the
  1272. * traversal of an abstract syntax tree.
  1273. * @param {!TSyntacticCodeUnit} oSourceElement A source element from
  1274. * which the traversal should commence.
  1275. * @return {function(): !TSyntacticCodeUnit} A function that is able to
  1276. * initiate the traversal from a given source element.
  1277. */
  1278. cContext = function(oWalker, oSourceElement) {
  1279. /**
  1280. * @return {!TSyntacticCodeUnit} A function that is able to
  1281. * initiate the traversal from a given source element.
  1282. */
  1283. var fLambda = function() {
  1284. return oWalker.walk(oSourceElement);
  1285. };
  1286. return fLambda;
  1287. },
  1288. /**
  1289. * A record consisting of configuration for the code generation phase.
  1290. * @type {!Object}
  1291. */
  1292. oCodeGenerationOptions = {
  1293. beautify: true
  1294. },
  1295. /**
  1296. * Tests whether consolidation of an ECMAScript program yields expected
  1297. * results.
  1298. * @param {{
  1299. * sTitle: string,
  1300. * sInput: string,
  1301. * sOutput: string
  1302. * }} oUnitTest A record consisting of data about a unit test: its
  1303. * name, an ECMAScript program, and, if consolidation is to take
  1304. * place, the resulting ECMAScript program.
  1305. */
  1306. cAssert = function(oUnitTest) {
  1307. var _,
  1308. /**
  1309. * An array-like object representing the <abbr title=
  1310. * "abstract syntax tree">AST</abbr> obtained after consolidation.
  1311. * @type {!TSyntacticCodeUnit}
  1312. */
  1313. oSyntacticCodeUnitActual =
  1314. exports.ast_consolidate(oParser.parse(oUnitTest.sInput)),
  1315. /**
  1316. * An array-like object representing the expected <abbr title=
  1317. * "abstract syntax tree">AST</abbr>.
  1318. * @type {!TSyntacticCodeUnit}
  1319. */
  1320. oSyntacticCodeUnitExpected = oParser.parse(
  1321. oUnitTest.hasOwnProperty('sOutput') ?
  1322. oUnitTest.sOutput : oUnitTest.sInput);
  1323. delete oSyntacticCodeUnitActual.scope;
  1324. oWalker = oProcessor.ast_walker();
  1325. oWalker.with_walkers(
  1326. oWalkersPurifiers,
  1327. cContext(oWalker, oSyntacticCodeUnitActual));
  1328. try {
  1329. oAssert.deepEqual(
  1330. oSyntacticCodeUnitActual,
  1331. oSyntacticCodeUnitExpected);
  1332. } catch (oException) {
  1333. console.error(
  1334. '########## A unit test has failed.\n' +
  1335. oUnitTest.sTitle + '\n' +
  1336. '##### actual code (' +
  1337. oProcessor.gen_code(oSyntacticCodeUnitActual).length +
  1338. ' bytes)\n' +
  1339. oProcessor.gen_code(
  1340. oSyntacticCodeUnitActual,
  1341. oCodeGenerationOptions) + '\n' +
  1342. '##### expected code (' +
  1343. oProcessor.gen_code(oSyntacticCodeUnitExpected).length +
  1344. ' bytes)\n' +
  1345. oProcessor.gen_code(
  1346. oSyntacticCodeUnitExpected,
  1347. oCodeGenerationOptions));
  1348. }
  1349. };
  1350. [
  1351. // 7.6.1 Reserved Words.
  1352. {
  1353. sTitle:
  1354. 'Omission of keywords while choosing an identifier name.',
  1355. sInput:
  1356. '(function() {' +
  1357. ' var a, b, c, d, e, f, g, h, i, j, k, l, m,' +
  1358. ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
  1359. ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
  1360. ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
  1361. ' $, _,' +
  1362. ' aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am,' +
  1363. ' an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az,' +
  1364. ' aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM,' +
  1365. ' aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ,' +
  1366. ' a$, a_,' +
  1367. ' ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm,' +
  1368. ' bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz,' +
  1369. ' bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, bM,' +
  1370. ' bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, bX, bY, bZ,' +
  1371. ' b$, b_,' +
  1372. ' ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm,' +
  1373. ' cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz,' +
  1374. ' cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM,' +
  1375. ' cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ,' +
  1376. ' c$, c_,' +
  1377. ' da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm,' +
  1378. ' dn, dq, dr, ds, dt, du, dv, dw, dx, dy, dz,' +
  1379. ' dA, dB, dC, dD, dE, dF, dG, dH, dI, dJ, dK, dL, dM,' +
  1380. ' dN, dO, dP, dQ, dR, dS, dT, dU, dV, dW, dX, dY, dZ,' +
  1381. ' d$, d_;' +
  1382. ' void ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",' +
  1383. ' "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"];' +
  1384. '}());',
  1385. sOutput:
  1386. '(function() {' +
  1387. ' var dp =' +
  1388. ' "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",' +
  1389. ' a, b, c, d, e, f, g, h, i, j, k, l, m,' +
  1390. ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
  1391. ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
  1392. ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
  1393. ' $, _,' +
  1394. ' aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am,' +
  1395. ' an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az,' +
  1396. ' aA, aB, aC, aD, aE, aF, aG, aH, aI, aJ, aK, aL, aM,' +
  1397. ' aN, aO, aP, aQ, aR, aS, aT, aU, aV, aW, aX, aY, aZ,' +
  1398. ' a$, a_,' +
  1399. ' ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm,' +
  1400. ' bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz,' +
  1401. ' bA, bB, bC, bD, bE, bF, bG, bH, bI, bJ, bK, bL, bM,' +
  1402. ' bN, bO, bP, bQ, bR, bS, bT, bU, bV, bW, bX, bY, bZ,' +
  1403. ' b$, b_,' +
  1404. ' ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm,' +
  1405. ' cn, co, cp, cq, cr, cs, ct, cu, cv, cw, cx, cy, cz,' +
  1406. ' cA, cB, cC, cD, cE, cF, cG, cH, cI, cJ, cK, cL, cM,' +
  1407. ' cN, cO, cP, cQ, cR, cS, cT, cU, cV, cW, cX, cY, cZ,' +
  1408. ' c$, c_,' +
  1409. ' da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm,' +
  1410. ' dn, dq, dr, ds, dt, du, dv, dw, dx, dy, dz,' +
  1411. ' dA, dB, dC, dD, dE, dF, dG, dH, dI, dJ, dK, dL, dM,' +
  1412. ' dN, dO, dP, dQ, dR, dS, dT, dU, dV, dW, dX, dY, dZ,' +
  1413. ' d$, d_;' +
  1414. ' void [dp, dp];' +
  1415. '}());'
  1416. },
  1417. // 7.8.1 Null Literals.
  1418. {
  1419. sTitle:
  1420. 'Evaluation with regard to the null value.',
  1421. sInput:
  1422. '/*jshint evil:true */' +
  1423. '(function() {' +
  1424. ' var foo;' +
  1425. ' void [null, null, null];' +
  1426. '}());' +
  1427. 'eval("");' +
  1428. '(function() {' +
  1429. ' var foo;' +
  1430. ' void [null, null];' +
  1431. '}());',
  1432. sOutput:
  1433. '/*jshint evil:true */' +
  1434. '(function() {' +
  1435. ' var a = null, foo;' +
  1436. ' void [a, a, a];' +
  1437. '}());' +
  1438. 'eval("");' +
  1439. '(function() {' +
  1440. ' var foo;' +
  1441. ' void [null, null];' +
  1442. '}());'
  1443. },
  1444. // 7.8.2 Boolean Literals.
  1445. {
  1446. sTitle:
  1447. 'Evaluation with regard to the false value.',
  1448. sInput:
  1449. '/*jshint evil:true */' +
  1450. '(function() {' +
  1451. ' var foo;' +
  1452. ' void [false, false, false];' +
  1453. '}());' +
  1454. 'eval("");' +
  1455. '(function() {' +
  1456. ' var foo;' +
  1457. ' void [false, false];' +
  1458. '}());',
  1459. sOutput:
  1460. '/*jshint evil:true */' +
  1461. '(function() {' +
  1462. ' var a = false, foo;' +
  1463. ' void [a, a, a];' +
  1464. '}());' +
  1465. 'eval("");' +
  1466. '(function() {' +
  1467. ' var foo;' +
  1468. ' void [false, false];' +
  1469. '}());'
  1470. },
  1471. {
  1472. sTitle:
  1473. 'Evaluation with regard to the true value.',
  1474. sInput:
  1475. '/*jshint evil:true */' +
  1476. '(function() {' +
  1477. ' var foo;' +
  1478. ' void [true, true, true];' +
  1479. '}());' +
  1480. 'eval("");' +
  1481. '(function() {' +
  1482. ' var foo;' +
  1483. ' void [true, true];' +
  1484. '}());',
  1485. sOutput:
  1486. '/*jshint evil:true */' +
  1487. '(function() {' +
  1488. ' var a = true, foo;' +
  1489. ' void [a, a, a];' +
  1490. '}());' +
  1491. 'eval("");' +
  1492. '(function() {' +
  1493. ' var foo;' +
  1494. ' void [true, true];' +
  1495. '}());'
  1496. },
  1497. // 7.8.4 String Literals.
  1498. {
  1499. sTitle:
  1500. 'Evaluation with regard to the String value of a string literal.',
  1501. sInput:
  1502. '(function() {' +
  1503. ' var foo;' +
  1504. ' void ["abcd", "abcd", "abc", "abc"];' +
  1505. '}());',
  1506. sOutput:
  1507. '(function() {' +
  1508. ' var a = "abcd", foo;' +
  1509. ' void [a, a, "abc", "abc"];' +
  1510. '}());'
  1511. },
  1512. // 7.8.5 Regular Expression Literals.
  1513. {
  1514. sTitle:
  1515. 'Preservation of the pattern of a regular expression literal.',
  1516. sInput:
  1517. 'void [/abcdefghijklmnopqrstuvwxyz/, /abcdefghijklmnopqrstuvwxyz/];'
  1518. },
  1519. {
  1520. sTitle:
  1521. 'Preservation of the flags of a regular expression literal.',
  1522. sInput:
  1523. 'void [/(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim,' +
  1524. ' /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim,' +
  1525. ' /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim, /(?:)/gim];'
  1526. },
  1527. // 10.2 Lexical Environments.
  1528. {
  1529. sTitle:
  1530. 'Preservation of identifier names in the same scope.',
  1531. sInput:
  1532. '/*jshint shadow:true */' +
  1533. 'var a;' +
  1534. 'function b(i) {' +
  1535. '}' +
  1536. 'for (var c; 0 === Math.random(););' +
  1537. 'for (var d in {});' +
  1538. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  1539. 'void [b(a), b(c), b(d)];' +
  1540. 'void [typeof e];' +
  1541. 'i: for (; 0 === Math.random();) {' +
  1542. ' if (42 === (new Date()).getMinutes()) {' +
  1543. ' continue i;' +
  1544. ' } else {' +
  1545. ' break i;' +
  1546. ' }' +
  1547. '}' +
  1548. 'try {' +
  1549. '} catch (f) {' +
  1550. '} finally {' +
  1551. '}' +
  1552. '(function g(h) {' +
  1553. '}());' +
  1554. 'void [{' +
  1555. ' i: 42,' +
  1556. ' "j": 42,' +
  1557. ' \'k\': 42' +
  1558. '}];' +
  1559. 'void ["abcdefghijklmnopqrstuvwxyz"];',
  1560. sOutput:
  1561. '/*jshint shadow:true */' +
  1562. 'var a;' +
  1563. 'function b(i) {' +
  1564. '}' +
  1565. 'for (var c; 0 === Math.random(););' +
  1566. 'for (var d in {});' +
  1567. '(function() {' +
  1568. ' var i = "abcdefghijklmnopqrstuvwxyz";' +
  1569. ' void [i];' +
  1570. ' void [b(a), b(c), b(d)];' +
  1571. ' void [typeof e];' +
  1572. ' i: for (; 0 === Math.random();) {' +
  1573. ' if (42 === (new Date()).getMinutes()) {' +
  1574. ' continue i;' +
  1575. ' } else {' +
  1576. ' break i;' +
  1577. ' }' +
  1578. ' }' +
  1579. ' try {' +
  1580. ' } catch (f) {' +
  1581. ' } finally {' +
  1582. ' }' +
  1583. ' (function g(h) {' +
  1584. ' }());' +
  1585. ' void [{' +
  1586. ' i: 42,' +
  1587. ' "j": 42,' +
  1588. ' \'k\': 42' +
  1589. ' }];' +
  1590. ' void [i];' +
  1591. '}());'
  1592. },
  1593. {
  1594. sTitle:
  1595. 'Preservation of identifier names in nested function code.',
  1596. sInput:
  1597. '(function() {' +
  1598. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1599. ' (function() {' +
  1600. ' var a;' +
  1601. ' for (var b; 0 === Math.random(););' +
  1602. ' for (var c in {});' +
  1603. ' void [typeof d];' +
  1604. ' h: for (; 0 === Math.random();) {' +
  1605. ' if (42 === (new Date()).getMinutes()) {' +
  1606. ' continue h;' +
  1607. ' } else {' +
  1608. ' break h;' +
  1609. ' }' +
  1610. ' }' +
  1611. ' try {' +
  1612. ' } catch (e) {' +
  1613. ' } finally {' +
  1614. ' }' +
  1615. ' (function f(g) {' +
  1616. ' }());' +
  1617. ' void [{' +
  1618. ' h: 42,' +
  1619. ' "i": 42,' +
  1620. ' \'j\': 42' +
  1621. ' }];' +
  1622. ' }());' +
  1623. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1624. '}());',
  1625. sOutput:
  1626. '(function() {' +
  1627. ' var h = "abcdefghijklmnopqrstuvwxyz";' +
  1628. ' void [h];' +
  1629. ' (function() {' +
  1630. ' var a;' +
  1631. ' for (var b; 0 === Math.random(););' +
  1632. ' for (var c in {});' +
  1633. ' void [typeof d];' +
  1634. ' h: for (; 0 === Math.random();) {' +
  1635. ' if (42 === (new Date()).getMinutes()) {' +
  1636. ' continue h;' +
  1637. ' } else {' +
  1638. ' break h;' +
  1639. ' }' +
  1640. ' }' +
  1641. ' try {' +
  1642. ' } catch (e) {' +
  1643. ' } finally {' +
  1644. ' }' +
  1645. ' (function f(g) {' +
  1646. ' }());' +
  1647. ' void [{' +
  1648. ' h: 42,' +
  1649. ' "i": 42,' +
  1650. ' \'j\': 42' +
  1651. ' }];' +
  1652. ' }());' +
  1653. ' void [h];' +
  1654. '}());'
  1655. },
  1656. {
  1657. sTitle:
  1658. 'Consolidation of a closure with other source elements.',
  1659. sInput:
  1660. '(function(foo) {' +
  1661. '}("abcdefghijklmnopqrstuvwxyz"));' +
  1662. 'void ["abcdefghijklmnopqrstuvwxyz"];',
  1663. sOutput:
  1664. '(function() {' +
  1665. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1666. ' (function(foo) {' +
  1667. ' })(a);' +
  1668. ' void [a];' +
  1669. '}());'
  1670. },
  1671. {
  1672. sTitle:
  1673. 'Consolidation of function code instead of a sole closure.',
  1674. sInput:
  1675. '(function(foo, bar) {' +
  1676. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1677. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1678. '}("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"));',
  1679. sOutput:
  1680. '(function(foo, bar) {' +
  1681. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1682. ' void [a, a];' +
  1683. '}("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"));'
  1684. },
  1685. // 11.1.5 Object Initialiser.
  1686. {
  1687. sTitle:
  1688. 'Preservation of property names of an object initialiser.',
  1689. sInput:
  1690. 'var foo = {' +
  1691. ' abcdefghijklmnopqrstuvwxyz: 42,' +
  1692. ' "zyxwvutsrqponmlkjihgfedcba": 42,' +
  1693. ' \'mlkjihgfedcbanopqrstuvwxyz\': 42' +
  1694. '};' +
  1695. 'void [' +
  1696. ' foo.abcdefghijklmnopqrstuvwxyz,' +
  1697. ' "zyxwvutsrqponmlkjihgfedcba",' +
  1698. ' \'mlkjihgfedcbanopqrstuvwxyz\'' +
  1699. '];'
  1700. },
  1701. {
  1702. sTitle:
  1703. 'Evaluation with regard to String values derived from identifier ' +
  1704. 'names used as property accessors.',
  1705. sInput:
  1706. '(function() {' +
  1707. ' var foo;' +
  1708. ' void [' +
  1709. ' Math.abcdefghij,' +
  1710. ' Math.abcdefghij,' +
  1711. ' Math.abcdefghi,' +
  1712. ' Math.abcdefghi' +
  1713. ' ];' +
  1714. '}());',
  1715. sOutput:
  1716. '(function() {' +
  1717. ' var a = "abcdefghij", foo;' +
  1718. ' void [' +
  1719. ' Math[a],' +
  1720. ' Math[a],' +
  1721. ' Math.abcdefghi,' +
  1722. ' Math.abcdefghi' +
  1723. ' ];' +
  1724. '}());'
  1725. },
  1726. // 11.2.1 Property Accessors.
  1727. {
  1728. sTitle:
  1729. 'Preservation of identifiers in the nonterminal MemberExpression.',
  1730. sInput:
  1731. 'void [' +
  1732. ' Math.E,' +
  1733. ' Math.LN10,' +
  1734. ' Math.LN2,' +
  1735. ' Math.LOG2E,' +
  1736. ' Math.LOG10E,' +
  1737. ' Math.PI,' +
  1738. ' Math.SQRT1_2,' +
  1739. ' Math.SQRT2,' +
  1740. ' Math.abs,' +
  1741. ' Math.acos' +
  1742. '];'
  1743. },
  1744. // 12.2 Variable Statement.
  1745. {
  1746. sTitle:
  1747. 'Preservation of the identifier of a variable that is being ' +
  1748. 'declared in a variable statement.',
  1749. sInput:
  1750. '(function() {' +
  1751. ' var abcdefghijklmnopqrstuvwxyz;' +
  1752. ' void [abcdefghijklmnopqrstuvwxyz];' +
  1753. '}());'
  1754. },
  1755. {
  1756. sTitle:
  1757. 'Exclusion of a variable statement in global code.',
  1758. sInput:
  1759. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  1760. 'var foo = "abcdefghijklmnopqrstuvwxyz",' +
  1761. ' bar = "abcdefghijklmnopqrstuvwxyz";' +
  1762. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  1763. },
  1764. {
  1765. sTitle:
  1766. 'Exclusion of a variable statement in function code that ' +
  1767. 'contains a with statement.',
  1768. sInput:
  1769. '(function() {' +
  1770. ' with ({});' +
  1771. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1772. ' var foo;' +
  1773. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1774. '}());'
  1775. },
  1776. {
  1777. sTitle:
  1778. 'Exclusion of a variable statement in function code that ' +
  1779. 'contains a direct call to the eval function.',
  1780. sInput:
  1781. '/*jshint evil:true */' +
  1782. 'void [' +
  1783. ' function() {' +
  1784. ' eval("");' +
  1785. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1786. ' var foo;' +
  1787. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1788. ' }' +
  1789. '];'
  1790. },
  1791. {
  1792. sTitle:
  1793. 'Consolidation within a variable statement in global code.',
  1794. sInput:
  1795. 'var foo = function() {' +
  1796. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1797. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1798. '};',
  1799. sOutput:
  1800. 'var foo = function() {' +
  1801. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1802. ' void [a, a];' +
  1803. '};'
  1804. },
  1805. {
  1806. sTitle:
  1807. 'Consolidation within a variable statement excluded in function ' +
  1808. 'code due to the presence of a with statement.',
  1809. sInput:
  1810. '(function() {' +
  1811. ' with ({});' +
  1812. ' var foo = function() {' +
  1813. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1814. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1815. ' };' +
  1816. '}());',
  1817. sOutput:
  1818. '(function() {' +
  1819. ' with ({});' +
  1820. ' var foo = function() {' +
  1821. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1822. ' void [a, a];' +
  1823. ' };' +
  1824. '}());'
  1825. },
  1826. {
  1827. sTitle:
  1828. 'Consolidation within a variable statement excluded in function ' +
  1829. 'code due to the presence of a direct call to the eval function.',
  1830. sInput:
  1831. '/*jshint evil:true */' +
  1832. '(function() {' +
  1833. ' eval("");' +
  1834. ' var foo = function() {' +
  1835. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1836. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1837. ' };' +
  1838. '}());',
  1839. sOutput:
  1840. '/*jshint evil:true */' +
  1841. '(function() {' +
  1842. ' eval("");' +
  1843. ' var foo = function() {' +
  1844. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1845. ' void [a, a];' +
  1846. ' };' +
  1847. '}());'
  1848. },
  1849. {
  1850. sTitle:
  1851. 'Inclusion of a variable statement in function code that ' +
  1852. 'contains no with statement and no direct call to the eval ' +
  1853. 'function.',
  1854. sInput:
  1855. '(function() {' +
  1856. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1857. ' var foo;' +
  1858. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1859. '}());',
  1860. sOutput:
  1861. '(function() {' +
  1862. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1863. ' void [a];' +
  1864. ' var foo;' +
  1865. ' void [a];' +
  1866. '}());'
  1867. },
  1868. {
  1869. sTitle:
  1870. 'Ignorance with regard to a variable statement in global code.',
  1871. sInput:
  1872. 'var foo = "abcdefghijklmnopqrstuvwxyz";' +
  1873. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  1874. ' "abcdefghijklmnopqrstuvwxyz"];',
  1875. sOutput:
  1876. 'var foo = "abcdefghijklmnopqrstuvwxyz";' +
  1877. '(function() {' +
  1878. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1879. ' void [a, a];' +
  1880. '}());'
  1881. },
  1882. // 12.4 Expression Statement.
  1883. {
  1884. sTitle:
  1885. 'Preservation of identifiers in an expression statement.',
  1886. sInput:
  1887. 'void [typeof abcdefghijklmnopqrstuvwxyz,' +
  1888. ' typeof abcdefghijklmnopqrstuvwxyz];'
  1889. },
  1890. // 12.6.3 The {@code for} Statement.
  1891. {
  1892. sTitle:
  1893. 'Preservation of identifiers in the variable declaration list of ' +
  1894. 'a for statement.',
  1895. sInput:
  1896. 'for (var abcdefghijklmnopqrstuvwxyz; 0 === Math.random(););' +
  1897. 'for (var abcdefghijklmnopqrstuvwxyz; 0 === Math.random(););'
  1898. },
  1899. // 12.6.4 The {@code for-in} Statement.
  1900. {
  1901. sTitle:
  1902. 'Preservation of identifiers in the variable declaration list of ' +
  1903. 'a for-in statement.',
  1904. sInput:
  1905. 'for (var abcdefghijklmnopqrstuvwxyz in {});' +
  1906. 'for (var abcdefghijklmnopqrstuvwxyz in {});'
  1907. },
  1908. // 12.7 The {@code continue} Statement.
  1909. {
  1910. sTitle:
  1911. 'Preservation of the identifier in a continue statement.',
  1912. sInput:
  1913. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
  1914. ' continue abcdefghijklmnopqrstuvwxyz;' +
  1915. '}' +
  1916. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
  1917. ' continue abcdefghijklmnopqrstuvwxyz;' +
  1918. '}'
  1919. },
  1920. // 12.8 The {@code break} Statement.
  1921. {
  1922. sTitle:
  1923. 'Preservation of the identifier in a break statement.',
  1924. sInput:
  1925. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
  1926. ' break abcdefghijklmnopqrstuvwxyz;' +
  1927. '}' +
  1928. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random();) {' +
  1929. ' break abcdefghijklmnopqrstuvwxyz;' +
  1930. '}'
  1931. },
  1932. // 12.9 The {@code return} Statement.
  1933. {
  1934. sTitle:
  1935. 'Exclusion of a return statement in function code that contains ' +
  1936. 'a with statement.',
  1937. sInput:
  1938. '(function() {' +
  1939. ' with ({});' +
  1940. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1941. ' if (0 === Math.random()) {' +
  1942. ' return;' +
  1943. ' } else {' +
  1944. ' }' +
  1945. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1946. '}());'
  1947. },
  1948. {
  1949. sTitle:
  1950. 'Exclusion of a return statement in function code that contains ' +
  1951. 'a direct call to the eval function.',
  1952. sInput:
  1953. '/*jshint evil:true */' +
  1954. '(function() {' +
  1955. ' eval("");' +
  1956. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1957. ' if (0 === Math.random()) {' +
  1958. ' return;' +
  1959. ' } else {' +
  1960. ' }' +
  1961. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  1962. '}());'
  1963. },
  1964. {
  1965. sTitle:
  1966. 'Consolidation within a return statement excluded in function ' +
  1967. 'code due to the presence of a with statement.',
  1968. sInput:
  1969. '(function() {' +
  1970. ' with ({});' +
  1971. ' return function() {' +
  1972. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1973. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1974. ' };' +
  1975. '}());',
  1976. sOutput:
  1977. '(function() {' +
  1978. ' with ({});' +
  1979. ' return function() {' +
  1980. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  1981. ' void [a, a];' +
  1982. ' };' +
  1983. '}());'
  1984. },
  1985. {
  1986. sTitle:
  1987. 'Consolidation within a return statement excluded in function ' +
  1988. 'code due to the presence of a direct call to the eval function.',
  1989. sInput:
  1990. '/*jshint evil:true */' +
  1991. '(function() {' +
  1992. ' eval("");' +
  1993. ' return function() {' +
  1994. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  1995. ' "abcdefghijklmnopqrstuvwxyz"];' +
  1996. ' };' +
  1997. '}());',
  1998. sOutput:
  1999. '/*jshint evil:true */' +
  2000. '(function() {' +
  2001. ' eval("");' +
  2002. ' return function() {' +
  2003. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2004. ' void [a, a];' +
  2005. ' };' +
  2006. '}());'
  2007. },
  2008. {
  2009. sTitle:
  2010. 'Inclusion of a return statement in function code that contains ' +
  2011. 'no with statement and no direct call to the eval function.',
  2012. sInput:
  2013. '(function() {' +
  2014. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  2015. ' if (0 === Math.random()) {' +
  2016. ' return;' +
  2017. ' } else {' +
  2018. ' }' +
  2019. ' void ["abcdefghijklmnopqrstuvwxyz"];' +
  2020. '}());',
  2021. sOutput:
  2022. '(function() {' +
  2023. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2024. ' void [a];' +
  2025. ' if (0 === Math.random()) {' +
  2026. ' return;' +
  2027. ' } else {' +
  2028. ' }' +
  2029. ' void [a];' +
  2030. '}());'
  2031. },
  2032. // 12.10 The {@code with} Statement.
  2033. {
  2034. sTitle:
  2035. 'Preservation of the statement in a with statement.',
  2036. sInput:
  2037. 'with ({}) {' +
  2038. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2039. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2040. '}'
  2041. },
  2042. {
  2043. sTitle:
  2044. 'Exclusion of a with statement in the same syntactic code unit.',
  2045. sInput:
  2046. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  2047. 'with ({' +
  2048. ' foo: "abcdefghijklmnopqrstuvwxyz",' +
  2049. ' bar: "abcdefghijklmnopqrstuvwxyz"' +
  2050. '}) {' +
  2051. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2052. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2053. '}' +
  2054. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  2055. },
  2056. {
  2057. sTitle:
  2058. 'Exclusion of a with statement in nested function code.',
  2059. sInput:
  2060. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  2061. '(function() {' +
  2062. ' with ({' +
  2063. ' foo: "abcdefghijklmnopqrstuvwxyz",' +
  2064. ' bar: "abcdefghijklmnopqrstuvwxyz"' +
  2065. ' }) {' +
  2066. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2067. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2068. ' }' +
  2069. '}());' +
  2070. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  2071. },
  2072. // 12.12 Labelled Statements.
  2073. {
  2074. sTitle:
  2075. 'Preservation of the label of a labelled statement.',
  2076. sInput:
  2077. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random(););' +
  2078. 'abcdefghijklmnopqrstuvwxyz: for (; 0 === Math.random(););'
  2079. },
  2080. // 12.14 The {@code try} Statement.
  2081. {
  2082. sTitle:
  2083. 'Preservation of the identifier in the catch clause of a try' +
  2084. 'statement.',
  2085. sInput:
  2086. 'try {' +
  2087. '} catch (abcdefghijklmnopqrstuvwxyz) {' +
  2088. '} finally {' +
  2089. '}' +
  2090. 'try {' +
  2091. '} catch (abcdefghijklmnopqrstuvwxyz) {' +
  2092. '} finally {' +
  2093. '}'
  2094. },
  2095. // 13 Function Definition.
  2096. {
  2097. sTitle:
  2098. 'Preservation of the identifier of a function declaration.',
  2099. sInput:
  2100. 'function abcdefghijklmnopqrstuvwxyz() {' +
  2101. '}' +
  2102. 'void [abcdefghijklmnopqrstuvwxyz];'
  2103. },
  2104. {
  2105. sTitle:
  2106. 'Preservation of the identifier of a function expression.',
  2107. sInput:
  2108. 'void [' +
  2109. ' function abcdefghijklmnopqrstuvwxyz() {' +
  2110. ' },' +
  2111. ' function abcdefghijklmnopqrstuvwxyz() {' +
  2112. ' }' +
  2113. '];'
  2114. },
  2115. {
  2116. sTitle:
  2117. 'Preservation of a formal parameter of a function declaration.',
  2118. sInput:
  2119. 'function foo(abcdefghijklmnopqrstuvwxyz) {' +
  2120. '}' +
  2121. 'function bar(abcdefghijklmnopqrstuvwxyz) {' +
  2122. '}'
  2123. },
  2124. {
  2125. sTitle:
  2126. 'Preservation of a formal parameter in a function expression.',
  2127. sInput:
  2128. 'void [' +
  2129. ' function(abcdefghijklmnopqrstuvwxyz) {' +
  2130. ' },' +
  2131. ' function(abcdefghijklmnopqrstuvwxyz) {' +
  2132. ' }' +
  2133. '];'
  2134. },
  2135. {
  2136. sTitle:
  2137. 'Exclusion of a function declaration.',
  2138. sInput:
  2139. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  2140. 'function foo() {' +
  2141. '}' +
  2142. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  2143. },
  2144. {
  2145. sTitle:
  2146. 'Consolidation within a function declaration.',
  2147. sInput:
  2148. 'function foo() {' +
  2149. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2150. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2151. '}',
  2152. sOutput:
  2153. 'function foo() {' +
  2154. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2155. ' void [a, a];' +
  2156. '}'
  2157. },
  2158. // 14 Program.
  2159. {
  2160. sTitle:
  2161. 'Preservation of a program without source elements.',
  2162. sInput:
  2163. ''
  2164. },
  2165. // 14.1 Directive Prologues and the Use Strict Directive.
  2166. {
  2167. sTitle:
  2168. 'Preservation of a Directive Prologue in global code.',
  2169. sInput:
  2170. '"abcdefghijklmnopqrstuvwxyz";' +
  2171. '\'zyxwvutsrqponmlkjihgfedcba\';'
  2172. },
  2173. {
  2174. sTitle:
  2175. 'Preservation of a Directive Prologue in a function declaration.',
  2176. sInput:
  2177. 'function foo() {' +
  2178. ' "abcdefghijklmnopqrstuvwxyz";' +
  2179. ' \'zyxwvutsrqponmlkjihgfedcba\';' +
  2180. '}'
  2181. },
  2182. {
  2183. sTitle:
  2184. 'Preservation of a Directive Prologue in a function expression.',
  2185. sInput:
  2186. 'void [' +
  2187. ' function() {' +
  2188. ' "abcdefghijklmnopqrstuvwxyz";' +
  2189. ' \'zyxwvutsrqponmlkjihgfedcba\';' +
  2190. ' }' +
  2191. '];'
  2192. },
  2193. {
  2194. sTitle:
  2195. 'Ignorance with regard to a Directive Prologue in global code.',
  2196. sInput:
  2197. '"abcdefghijklmnopqrstuvwxyz";' +
  2198. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  2199. ' "abcdefghijklmnopqrstuvwxyz"];',
  2200. sOutput:
  2201. '"abcdefghijklmnopqrstuvwxyz";' +
  2202. '(function() {' +
  2203. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2204. ' void [a, a];' +
  2205. '}());'
  2206. },
  2207. {
  2208. sTitle:
  2209. 'Ignorance with regard to a Directive Prologue in a function' +
  2210. 'declaration.',
  2211. sInput:
  2212. 'function foo() {' +
  2213. ' "abcdefghijklmnopqrstuvwxyz";' +
  2214. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2215. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2216. '}',
  2217. sOutput:
  2218. 'function foo() {' +
  2219. ' "abcdefghijklmnopqrstuvwxyz";' +
  2220. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2221. ' void [a, a];' +
  2222. '}'
  2223. },
  2224. {
  2225. sTitle:
  2226. 'Ignorance with regard to a Directive Prologue in a function' +
  2227. 'expression.',
  2228. sInput:
  2229. '(function() {' +
  2230. ' "abcdefghijklmnopqrstuvwxyz";' +
  2231. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2232. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2233. '}());',
  2234. sOutput:
  2235. '(function() {' +
  2236. ' "abcdefghijklmnopqrstuvwxyz";' +
  2237. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2238. ' void [a, a];' +
  2239. '}());'
  2240. },
  2241. // 15.1 The Global Object.
  2242. {
  2243. sTitle:
  2244. 'Preservation of a property of the global object.',
  2245. sInput:
  2246. 'void [undefined, undefined, undefined, undefined, undefined];'
  2247. },
  2248. // 15.1.2.1.1 Direct Call to Eval.
  2249. {
  2250. sTitle:
  2251. 'Exclusion of a direct call to the eval function in the same ' +
  2252. 'syntactic code unit.',
  2253. sInput:
  2254. '/*jshint evil:true */' +
  2255. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  2256. 'eval("");' +
  2257. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  2258. },
  2259. {
  2260. sTitle:
  2261. 'Exclusion of a direct call to the eval function in nested ' +
  2262. 'function code.',
  2263. sInput:
  2264. '/*jshint evil:true */' +
  2265. 'void ["abcdefghijklmnopqrstuvwxyz"];' +
  2266. '(function() {' +
  2267. ' eval("");' +
  2268. '}());' +
  2269. 'void ["abcdefghijklmnopqrstuvwxyz"];'
  2270. },
  2271. {
  2272. sTitle:
  2273. 'Consolidation within a direct call to the eval function.',
  2274. sInput:
  2275. '/*jshint evil:true */' +
  2276. 'eval(function() {' +
  2277. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2278. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2279. '}());',
  2280. sOutput:
  2281. '/*jshint evil:true */' +
  2282. 'eval(function() {' +
  2283. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2284. ' void [a, a];' +
  2285. '}());'
  2286. },
  2287. // Consolidation proper.
  2288. {
  2289. sTitle:
  2290. 'No consolidation if it does not result in a reduction of the ' +
  2291. 'number of source characters.',
  2292. sInput:
  2293. '(function() {' +
  2294. ' var foo;' +
  2295. ' void ["ab", "ab", "abc", "abc"];' +
  2296. '}());'
  2297. },
  2298. {
  2299. sTitle:
  2300. 'Identification of a range of source elements at the beginning ' +
  2301. 'of global code.',
  2302. sInput:
  2303. '/*jshint evil:true */' +
  2304. '"abcdefghijklmnopqrstuvwxyz";' +
  2305. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  2306. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2307. 'eval("");',
  2308. sOutput:
  2309. '/*jshint evil:true */' +
  2310. '"abcdefghijklmnopqrstuvwxyz";' +
  2311. '(function() {' +
  2312. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2313. ' void [a, a];' +
  2314. '}());' +
  2315. 'eval("");'
  2316. },
  2317. {
  2318. sTitle:
  2319. 'Identification of a range of source elements in the middle of ' +
  2320. 'global code.',
  2321. sInput:
  2322. '/*jshint evil:true */' +
  2323. '"abcdefghijklmnopqrstuvwxyz";' +
  2324. 'eval("");' +
  2325. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  2326. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2327. 'eval("");',
  2328. sOutput:
  2329. '/*jshint evil:true */' +
  2330. '"abcdefghijklmnopqrstuvwxyz";' +
  2331. 'eval("");' +
  2332. '(function() {' +
  2333. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2334. ' void [a, a];' +
  2335. '}());' +
  2336. 'eval("");'
  2337. },
  2338. {
  2339. sTitle:
  2340. 'Identification of a range of source elements at the end of ' +
  2341. 'global code.',
  2342. sInput:
  2343. '/*jshint evil:true */' +
  2344. '"abcdefghijklmnopqrstuvwxyz";' +
  2345. 'eval("");' +
  2346. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  2347. ' "abcdefghijklmnopqrstuvwxyz"];',
  2348. sOutput:
  2349. '/*jshint evil:true */' +
  2350. '"abcdefghijklmnopqrstuvwxyz";' +
  2351. 'eval("");' +
  2352. '(function() {' +
  2353. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2354. ' void [a, a];' +
  2355. '}());'
  2356. },
  2357. {
  2358. sTitle:
  2359. 'Identification of a range of source elements at the beginning ' +
  2360. 'of function code.',
  2361. sInput:
  2362. '/*jshint evil:true */' +
  2363. '(function() {' +
  2364. ' "abcdefghijklmnopqrstuvwxyz";' +
  2365. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2366. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2367. ' eval("");' +
  2368. '}());',
  2369. sOutput:
  2370. '/*jshint evil:true */' +
  2371. '(function() {' +
  2372. ' "abcdefghijklmnopqrstuvwxyz";' +
  2373. ' (function() {' +
  2374. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2375. ' void [a, a];' +
  2376. ' }());' +
  2377. ' eval("");' +
  2378. '}());'
  2379. },
  2380. {
  2381. sTitle:
  2382. 'Identification of a range of source elements in the middle of ' +
  2383. 'function code.',
  2384. sInput:
  2385. '/*jshint evil:true */' +
  2386. '(function() {' +
  2387. ' "abcdefghijklmnopqrstuvwxyz";' +
  2388. ' eval("");' +
  2389. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2390. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2391. ' eval("");' +
  2392. '}());',
  2393. sOutput:
  2394. '/*jshint evil:true */' +
  2395. '(function() {' +
  2396. ' "abcdefghijklmnopqrstuvwxyz";' +
  2397. ' eval("");' +
  2398. ' (function() {' +
  2399. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2400. ' void [a, a];' +
  2401. ' }());' +
  2402. ' eval("");' +
  2403. '}());'
  2404. },
  2405. {
  2406. sTitle:
  2407. 'Identification of a range of source elements at the end of ' +
  2408. 'function code.',
  2409. sInput:
  2410. '/*jshint evil:true */' +
  2411. '(function() {' +
  2412. ' "abcdefghijklmnopqrstuvwxyz";' +
  2413. ' eval("");' +
  2414. ' void ["abcdefghijklmnopqrstuvwxyz",' +
  2415. ' "abcdefghijklmnopqrstuvwxyz"];' +
  2416. '}());',
  2417. sOutput:
  2418. '/*jshint evil:true */' +
  2419. '(function() {' +
  2420. ' "abcdefghijklmnopqrstuvwxyz";' +
  2421. ' eval("");' +
  2422. ' (function() {' +
  2423. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2424. ' void [a, a];' +
  2425. ' }());' +
  2426. '}());'
  2427. },
  2428. {
  2429. sTitle:
  2430. 'Evaluation with regard to String values of String literals and ' +
  2431. 'String values derived from identifier names used as property' +
  2432. 'accessors.',
  2433. sInput:
  2434. '(function() {' +
  2435. ' var foo;' +
  2436. ' void ["abcdefg", Math.abcdefg, "abcdef", Math.abcdef];' +
  2437. '}());',
  2438. sOutput:
  2439. '(function() {' +
  2440. ' var a = "abcdefg", foo;' +
  2441. ' void [a, Math[a], "abcdef", Math.abcdef];' +
  2442. '}());'
  2443. },
  2444. {
  2445. sTitle:
  2446. 'Evaluation with regard to the necessity of adding a variable ' +
  2447. 'statement.',
  2448. sInput:
  2449. '/*jshint evil:true */' +
  2450. '(function() {' +
  2451. ' void ["abcdefgh", "abcdefgh"];' +
  2452. '}());' +
  2453. 'eval("");' +
  2454. '(function() {' +
  2455. ' void ["abcdefg", "abcdefg"];' +
  2456. '}());' +
  2457. 'eval("");' +
  2458. '(function() {' +
  2459. ' var foo;' +
  2460. ' void ["abcd", "abcd"];' +
  2461. '}());',
  2462. sOutput:
  2463. '/*jshint evil:true */' +
  2464. '(function() {' +
  2465. ' var a = "abcdefgh";' +
  2466. ' void [a, a];' +
  2467. '}());' +
  2468. 'eval("");' +
  2469. '(function() {' +
  2470. ' void ["abcdefg", "abcdefg"];' +
  2471. '}());' +
  2472. 'eval("");' +
  2473. '(function() {' +
  2474. ' var a = "abcd", foo;' +
  2475. ' void [a, a];' +
  2476. '}());'
  2477. },
  2478. {
  2479. sTitle:
  2480. 'Evaluation with regard to the necessity of enclosing source ' +
  2481. 'elements.',
  2482. sInput:
  2483. '/*jshint evil:true */' +
  2484. 'void ["abcdefghijklmnopqrstuvwxy", "abcdefghijklmnopqrstuvwxy"];' +
  2485. 'eval("");' +
  2486. 'void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
  2487. 'eval("");' +
  2488. '(function() {' +
  2489. ' void ["abcdefgh", "abcdefgh"];' +
  2490. '}());' +
  2491. '(function() {' +
  2492. ' void ["abcdefghijklmnopqrstuvwxy",' +
  2493. ' "abcdefghijklmnopqrstuvwxy"];' +
  2494. ' eval("");' +
  2495. ' void ["abcdefghijklmnopqrstuvwx",' +
  2496. ' "abcdefghijklmnopqrstuvwx"];' +
  2497. ' eval("");' +
  2498. ' (function() {' +
  2499. ' void ["abcdefgh", "abcdefgh"];' +
  2500. ' }());' +
  2501. '}());',
  2502. sOutput:
  2503. '/*jshint evil:true */' +
  2504. '(function() {' +
  2505. ' var a = "abcdefghijklmnopqrstuvwxy";' +
  2506. ' void [a, a];' +
  2507. '}());' +
  2508. 'eval("");' +
  2509. 'void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
  2510. 'eval("");' +
  2511. '(function() {' +
  2512. ' var a = "abcdefgh";' +
  2513. ' void [a, a];' +
  2514. '}());' +
  2515. '(function() {' +
  2516. ' (function() {' +
  2517. ' var a = "abcdefghijklmnopqrstuvwxy";' +
  2518. ' void [a, a];' +
  2519. ' }());' +
  2520. ' eval("");' +
  2521. ' void ["abcdefghijklmnopqrstuvwx", "abcdefghijklmnopqrstuvwx"];' +
  2522. ' eval("");' +
  2523. ' (function() {' +
  2524. ' var a = "abcdefgh";' +
  2525. ' void [a, a];' +
  2526. ' }());' +
  2527. '}());'
  2528. },
  2529. {
  2530. sTitle:
  2531. 'Employment of a closure while consolidating in global code.',
  2532. sInput:
  2533. 'void ["abcdefghijklmnopqrstuvwxyz",' +
  2534. ' "abcdefghijklmnopqrstuvwxyz"];',
  2535. sOutput:
  2536. '(function() {' +
  2537. ' var a = "abcdefghijklmnopqrstuvwxyz";' +
  2538. ' void [a, a];' +
  2539. '}());'
  2540. },
  2541. {
  2542. sTitle:
  2543. 'Assignment of a shorter identifier to a value whose ' +
  2544. 'consolidation results in a greater reduction of the number of ' +
  2545. 'source characters.',
  2546. sInput:
  2547. '(function() {' +
  2548. ' var b, c, d, e, f, g, h, i, j, k, l, m,' +
  2549. ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
  2550. ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
  2551. ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
  2552. ' $, _;' +
  2553. ' void ["abcde", "abcde", "edcba", "edcba", "edcba"];' +
  2554. '}());',
  2555. sOutput:
  2556. '(function() {' +
  2557. ' var a = "edcba",' +
  2558. ' b, c, d, e, f, g, h, i, j, k, l, m,' +
  2559. ' n, o, p, q, r, s, t, u, v, w, x, y, z,' +
  2560. ' A, B, C, D, E, F, G, H, I, J, K, L, M,' +
  2561. ' N, O, P, Q, R, S, T, U, V, W, X, Y, Z,' +
  2562. ' $, _;' +
  2563. ' void ["abcde", "abcde", a, a, a];' +
  2564. '}());'
  2565. }
  2566. ].forEach(cAssert);
  2567. }());
  2568. }
  2569. /* Local Variables: */
  2570. /* mode: js */
  2571. /* coding: utf-8 */
  2572. /* indent-tabs-mode: nil */
  2573. /* tab-width: 2 */
  2574. /* End: */
  2575. /* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */
  2576. /* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */