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