1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | "use strict";
|
45 |
|
46 | function SymbolDef(id, scope, orig, init) {
|
47 | this.eliminated = 0;
|
48 | this.exported = false;
|
49 | this.global = false;
|
50 | this.id = id;
|
51 | this.init = init;
|
52 | this.mangled_name = null;
|
53 | this.name = orig.name;
|
54 | this.orig = [ orig ];
|
55 | this.references = [];
|
56 | this.replaced = 0;
|
57 | this.scope = scope;
|
58 | this.undeclared = false;
|
59 | }
|
60 |
|
61 | SymbolDef.prototype = {
|
62 | forEach: function(fn) {
|
63 | this.orig.forEach(fn);
|
64 | this.references.forEach(fn);
|
65 | },
|
66 | mangle: function(options) {
|
67 | var cache = options.cache && options.cache.props;
|
68 | if (this.global && cache && cache.has(this.name)) {
|
69 | this.mangled_name = cache.get(this.name);
|
70 | } else if (!this.mangled_name && !this.unmangleable(options)) {
|
71 | var def = this.redefined();
|
72 | if (def) {
|
73 | this.mangled_name = def.mangled_name || def.name;
|
74 | } else {
|
75 | this.mangled_name = next_mangled_name(this, options);
|
76 | }
|
77 | if (this.global && cache) {
|
78 | cache.set(this.name, this.mangled_name);
|
79 | }
|
80 | }
|
81 | },
|
82 | redefined: function() {
|
83 | var self = this;
|
84 | var scope = self.defun;
|
85 | if (!scope) return;
|
86 | var name = self.name;
|
87 | var def = scope.variables.get(name)
|
88 | || scope instanceof AST_Toplevel && scope.globals.get(name)
|
89 | || self.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
|
90 | return def.name == name;
|
91 | }, scope.enclosed);
|
92 | if (def && def !== self) return def.redefined() || def;
|
93 | },
|
94 | unmangleable: function(options) {
|
95 | return this.global && !options.toplevel
|
96 | || this.exported
|
97 | || this.undeclared
|
98 | || !options.eval && this.scope.pinned()
|
99 | || options.keep_fnames
|
100 | && (this.orig[0] instanceof AST_SymbolClass
|
101 | || this.orig[0] instanceof AST_SymbolDefClass
|
102 | || this.orig[0] instanceof AST_SymbolDefun
|
103 | || this.orig[0] instanceof AST_SymbolLambda);
|
104 | },
|
105 | };
|
106 |
|
107 | var unary_side_effects = makePredicate("delete ++ --");
|
108 |
|
109 | function is_lhs(node, parent) {
|
110 | if (parent instanceof AST_Assign) return parent.left === node && node;
|
111 | if (parent instanceof AST_DefaultValue) return parent.name === node && node;
|
112 | if (parent instanceof AST_Destructured) return node;
|
113 | if (parent instanceof AST_DestructuredKeyVal) return node;
|
114 | if (parent instanceof AST_ForEnumeration) return parent.init === node && node;
|
115 | if (parent instanceof AST_Unary) return unary_side_effects[parent.operator] && parent.expression;
|
116 | }
|
117 |
|
118 | AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
119 | options = defaults(options, {
|
120 | cache: null,
|
121 | ie: false,
|
122 | });
|
123 |
|
124 |
|
125 | var self = this;
|
126 | var defun = null;
|
127 | var exported = false;
|
128 | var next_def_id = 0;
|
129 | var scope = self.parent_scope = null;
|
130 | var tw = new TreeWalker(function(node, descend) {
|
131 | if (node instanceof AST_DefClass) {
|
132 | var save_exported = exported;
|
133 | exported = tw.parent() instanceof AST_ExportDeclaration;
|
134 | node.name.walk(tw);
|
135 | exported = save_exported;
|
136 | walk_scope(function() {
|
137 | if (node.extends) node.extends.walk(tw);
|
138 | node.properties.forEach(function(prop) {
|
139 | prop.walk(tw);
|
140 | });
|
141 | });
|
142 | return true;
|
143 | }
|
144 | if (node instanceof AST_Definitions) {
|
145 | var save_exported = exported;
|
146 | exported = tw.parent() instanceof AST_ExportDeclaration;
|
147 | descend();
|
148 | exported = save_exported;
|
149 | return true;
|
150 | }
|
151 | if (node instanceof AST_LambdaDefinition) {
|
152 | var save_exported = exported;
|
153 | exported = tw.parent() instanceof AST_ExportDeclaration;
|
154 | node.name.walk(tw);
|
155 | exported = save_exported;
|
156 | walk_scope(function() {
|
157 | node.argnames.forEach(function(argname) {
|
158 | argname.walk(tw);
|
159 | });
|
160 | if (node.rest) node.rest.walk(tw);
|
161 | walk_body(node, tw);
|
162 | });
|
163 | return true;
|
164 | }
|
165 | if (node instanceof AST_SwitchBranch) {
|
166 | node.init_vars(scope);
|
167 | descend();
|
168 | return true;
|
169 | }
|
170 | if (node instanceof AST_Try) {
|
171 | walk_scope(function() {
|
172 | walk_body(node, tw);
|
173 | });
|
174 | if (node.bcatch) node.bcatch.walk(tw);
|
175 | if (node.bfinally) node.bfinally.walk(tw);
|
176 | return true;
|
177 | }
|
178 | if (node instanceof AST_With) {
|
179 | var s = scope;
|
180 | do {
|
181 | s = s.resolve();
|
182 | if (s.uses_with) break;
|
183 | s.uses_with = true;
|
184 | } while (s = s.parent_scope);
|
185 | walk_scope(descend);
|
186 | return true;
|
187 | }
|
188 | if (node instanceof AST_BlockScope) {
|
189 | walk_scope(descend);
|
190 | return true;
|
191 | }
|
192 | if (node instanceof AST_Symbol) {
|
193 | node.scope = scope;
|
194 | }
|
195 | if (node instanceof AST_Label) {
|
196 | node.thedef = node;
|
197 | node.references = [];
|
198 | }
|
199 | if (node instanceof AST_SymbolCatch) {
|
200 | scope.def_variable(node).defun = defun;
|
201 | } else if (node instanceof AST_SymbolConst) {
|
202 | var def = scope.def_variable(node);
|
203 | def.defun = defun;
|
204 | if (exported) def.exported = true;
|
205 | } else if (node instanceof AST_SymbolDefun) {
|
206 | var def = defun.def_function(node, tw.parent());
|
207 | if (exported) def.exported = true;
|
208 | entangle(defun, scope);
|
209 | } else if (node instanceof AST_SymbolFunarg) {
|
210 | defun.def_variable(node);
|
211 | entangle(defun, scope);
|
212 | } else if (node instanceof AST_SymbolLambda) {
|
213 | var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
214 | if (options.ie) def.defun = defun.parent_scope.resolve();
|
215 | } else if (node instanceof AST_SymbolLet) {
|
216 | var def = scope.def_variable(node);
|
217 | if (exported) def.exported = true;
|
218 | } else if (node instanceof AST_SymbolVar) {
|
219 | var def = defun.def_variable(node, node instanceof AST_SymbolImport ? undefined : null);
|
220 | if (exported) def.exported = true;
|
221 | entangle(defun, scope);
|
222 | }
|
223 |
|
224 | function walk_scope(descend) {
|
225 | node.init_vars(scope);
|
226 | var save_defun = defun;
|
227 | var save_scope = scope;
|
228 | if (node instanceof AST_Scope) defun = node;
|
229 | scope = node;
|
230 | descend();
|
231 | scope = save_scope;
|
232 | defun = save_defun;
|
233 | }
|
234 |
|
235 | function entangle(defun, scope) {
|
236 | if (defun === scope) return;
|
237 | node.mark_enclosed(options);
|
238 | var def = scope.find_variable(node.name);
|
239 | if (node.thedef === def) return;
|
240 | node.thedef = def;
|
241 | def.orig.push(node);
|
242 | node.mark_enclosed(options);
|
243 | }
|
244 | });
|
245 | self.make_def = function(orig, init) {
|
246 | return new SymbolDef(++next_def_id, this, orig, init);
|
247 | };
|
248 | self.walk(tw);
|
249 |
|
250 |
|
251 | self.globals = new Dictionary();
|
252 | var in_arg = [];
|
253 | var tw = new TreeWalker(function(node) {
|
254 | if (node instanceof AST_Catch) {
|
255 | if (!(node.argname instanceof AST_Destructured)) return;
|
256 | in_arg.push(node);
|
257 | node.argname.walk(tw);
|
258 | in_arg.pop();
|
259 | walk_body(node, tw);
|
260 | return true;
|
261 | }
|
262 | if (node instanceof AST_Lambda) {
|
263 | in_arg.push(node);
|
264 | node.argnames.forEach(function(argname) {
|
265 | argname.walk(tw);
|
266 | });
|
267 | if (node.rest) node.rest.walk(tw);
|
268 | in_arg.pop();
|
269 | walk_lambda(node, tw);
|
270 | return true;
|
271 | }
|
272 | if (node instanceof AST_LoopControl) {
|
273 | if (node.label) node.label.thedef.references.push(node);
|
274 | return true;
|
275 | }
|
276 | if (node instanceof AST_SymbolDeclaration) {
|
277 | var def = node.definition();
|
278 | def.preinit = def.references.length;
|
279 | if (node instanceof AST_SymbolCatch) {
|
280 |
|
281 | var redef = def.redefined();
|
282 | if (redef) for (var s = node.scope; s; s = s.parent_scope) {
|
283 | push_uniq(s.enclosed, redef);
|
284 | if (s === redef.scope) break;
|
285 | }
|
286 | } else if (node instanceof AST_SymbolConst) {
|
287 |
|
288 | var redef = def.redefined();
|
289 | if (redef) redef.const_redefs = true;
|
290 | }
|
291 | if (node.name != "arguments") return true;
|
292 | var parent = node instanceof AST_SymbolVar && tw.parent();
|
293 | if (parent instanceof AST_VarDef && !parent.value) return true;
|
294 | var sym = node.scope.resolve().find_variable("arguments");
|
295 | if (sym && is_arguments(sym)) sym.scope.uses_arguments = 3;
|
296 | return true;
|
297 | }
|
298 | if (node instanceof AST_SymbolRef) {
|
299 | var name = node.name;
|
300 | var sym = node.scope.find_variable(name);
|
301 | for (var i = in_arg.length; i > 0 && sym;) {
|
302 | i = in_arg.lastIndexOf(sym.scope, i - 1);
|
303 | if (i < 0) break;
|
304 | var decl = sym.orig[0];
|
305 | if (decl instanceof AST_SymbolCatch
|
306 | || decl instanceof AST_SymbolFunarg
|
307 | || decl instanceof AST_SymbolLambda) {
|
308 | node.in_arg = true;
|
309 | break;
|
310 | }
|
311 | sym = sym.scope.parent_scope.find_variable(name);
|
312 | }
|
313 | if (!sym) {
|
314 | sym = self.def_global(node);
|
315 | } else if (name == "arguments" && is_arguments(sym)) {
|
316 | var parent = tw.parent();
|
317 | if (is_lhs(node, parent)) {
|
318 | sym.scope.uses_arguments = 3;
|
319 | } else if (sym.scope.uses_arguments < 2
|
320 | && !(parent instanceof AST_PropAccess && parent.expression === node)) {
|
321 | sym.scope.uses_arguments = 2;
|
322 | } else if (!sym.scope.uses_arguments) {
|
323 | sym.scope.uses_arguments = true;
|
324 | }
|
325 | }
|
326 | if (name == "eval") {
|
327 | var parent = tw.parent();
|
328 | if (parent.TYPE == "Call" && parent.expression === node) {
|
329 | var s = node.scope;
|
330 | do {
|
331 | s = s.resolve();
|
332 | if (s.uses_eval) break;
|
333 | s.uses_eval = true;
|
334 | } while (s = s.parent_scope);
|
335 | } else if (sym.undeclared) {
|
336 | self.uses_eval = true;
|
337 | }
|
338 | }
|
339 | if (sym.init instanceof AST_LambdaDefinition && sym.scope !== sym.init.name.scope) {
|
340 | var scope = node.scope;
|
341 | do {
|
342 | if (scope === sym.init.name.scope) break;
|
343 | } while (scope = scope.parent_scope);
|
344 | if (!scope) sym.init = undefined;
|
345 | }
|
346 | node.thedef = sym;
|
347 | node.reference(options);
|
348 | return true;
|
349 | }
|
350 | });
|
351 | self.walk(tw);
|
352 |
|
353 |
|
354 | if (options.ie) self.walk(new TreeWalker(function(node) {
|
355 | if (node instanceof AST_SymbolCatch) {
|
356 | var scope = node.thedef.defun;
|
357 | if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
|
358 | scope = scope.parent_scope.resolve();
|
359 | }
|
360 | redefine(node, scope);
|
361 | return true;
|
362 | }
|
363 | if (node instanceof AST_SymbolLambda) {
|
364 | var def = node.thedef;
|
365 | if (!redefine(node, node.scope.parent_scope.resolve())) {
|
366 | delete def.defun;
|
367 | } else if (typeof node.thedef.init !== "undefined") {
|
368 | node.thedef.init = false;
|
369 | } else if (def.init) {
|
370 | node.thedef.init = def.init;
|
371 | }
|
372 | return true;
|
373 | }
|
374 | }));
|
375 |
|
376 | function is_arguments(sym) {
|
377 | return sym.orig[0] instanceof AST_SymbolFunarg
|
378 | && !(sym.orig[1] instanceof AST_SymbolFunarg || sym.orig[2] instanceof AST_SymbolFunarg)
|
379 | && !is_arrow(sym.scope);
|
380 | }
|
381 |
|
382 | function redefine(node, scope) {
|
383 | var name = node.name;
|
384 | var old_def = node.thedef;
|
385 | if (!all(old_def.orig, function(sym) {
|
386 | return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet);
|
387 | })) return false;
|
388 | var new_def = scope.find_variable(name);
|
389 | if (new_def) {
|
390 | var redef = new_def.redefined();
|
391 | if (redef) new_def = redef;
|
392 | } else {
|
393 | new_def = self.globals.get(name);
|
394 | }
|
395 | if (new_def) {
|
396 | new_def.orig.push(node);
|
397 | } else {
|
398 | new_def = scope.def_variable(node);
|
399 | }
|
400 | if (new_def.undeclared) self.variables.set(name, new_def);
|
401 | if (name == "arguments" && is_arguments(old_def) && node instanceof AST_SymbolLambda) return true;
|
402 | old_def.defun = new_def.scope;
|
403 | old_def.forEach(function(node) {
|
404 | node.redef = old_def;
|
405 | node.thedef = new_def;
|
406 | node.reference(options);
|
407 | });
|
408 | return true;
|
409 | }
|
410 | });
|
411 |
|
412 | AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
413 | var globals = this.globals, name = node.name;
|
414 | if (globals.has(name)) {
|
415 | return globals.get(name);
|
416 | } else {
|
417 | var g = this.make_def(node);
|
418 | g.undeclared = true;
|
419 | g.global = true;
|
420 | globals.set(name, g);
|
421 | return g;
|
422 | }
|
423 | });
|
424 |
|
425 | function init_block_vars(scope, parent) {
|
426 | scope.enclosed = [];
|
427 | scope.parent_scope = parent;
|
428 | scope.functions = new Dictionary();
|
429 | scope.variables = new Dictionary();
|
430 | if (parent) scope.make_def = parent.make_def;
|
431 | }
|
432 |
|
433 | function init_scope_vars(scope, parent) {
|
434 | init_block_vars(scope, parent);
|
435 | scope.uses_eval = false;
|
436 | scope.uses_with = false;
|
437 | }
|
438 |
|
439 | AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) {
|
440 | init_block_vars(this, parent_scope);
|
441 | });
|
442 | AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
|
443 | init_scope_vars(this, parent_scope);
|
444 | });
|
445 | AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) {
|
446 | init_scope_vars(this, parent_scope);
|
447 | return this;
|
448 | });
|
449 | AST_AsyncArrow.DEFMETHOD("init_vars", function(parent_scope) {
|
450 | init_scope_vars(this, parent_scope);
|
451 | });
|
452 | AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
453 | init_scope_vars(this, parent_scope);
|
454 | this.uses_arguments = false;
|
455 | this.def_variable(new AST_SymbolFunarg({
|
456 | name: "arguments",
|
457 | start: this.start,
|
458 | end: this.end,
|
459 | }));
|
460 | return this;
|
461 | });
|
462 |
|
463 | AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
464 | var def = this.definition();
|
465 | for (var s = this.scope; s; s = s.parent_scope) {
|
466 | push_uniq(s.enclosed, def);
|
467 | if (!options) {
|
468 | delete s._var_names;
|
469 | } else if (options.keep_fnames) {
|
470 | s.functions.each(function(d) {
|
471 | push_uniq(def.scope.enclosed, d);
|
472 | });
|
473 | }
|
474 | if (s === def.scope) break;
|
475 | }
|
476 | });
|
477 |
|
478 | AST_Symbol.DEFMETHOD("reference", function(options) {
|
479 | this.definition().references.push(this);
|
480 | this.mark_enclosed(options);
|
481 | });
|
482 |
|
483 | AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
484 | return this.variables.get(name)
|
485 | || this.parent_scope && this.parent_scope.find_variable(name);
|
486 | });
|
487 |
|
488 | AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
489 | var def = this.def_variable(symbol, init);
|
490 | if (!def.init || def.init instanceof AST_LambdaDefinition) def.init = init;
|
491 | this.functions.set(symbol.name, def);
|
492 | return def;
|
493 | });
|
494 |
|
495 | AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
496 | var def = this.variables.get(symbol.name);
|
497 | if (def) {
|
498 | def.orig.push(symbol);
|
499 | if (def.init instanceof AST_LambdaExpression) def.init = init;
|
500 | } else {
|
501 | def = this.make_def(symbol, init);
|
502 | this.variables.set(symbol.name, def);
|
503 | def.global = !this.parent_scope;
|
504 | }
|
505 | return symbol.thedef = def;
|
506 | });
|
507 |
|
508 | function names_in_use(scope, options) {
|
509 | var names = scope.names_in_use;
|
510 | if (!names) {
|
511 | scope.cname = -1;
|
512 | scope.cname_holes = [];
|
513 | scope.names_in_use = names = Object.create(null);
|
514 | var cache = options.cache && options.cache.props;
|
515 | scope.enclosed.forEach(function(def) {
|
516 | if (def.unmangleable(options)) names[def.name] = true;
|
517 | if (def.global && cache && cache.has(def.name)) {
|
518 | names[cache.get(def.name)] = true;
|
519 | }
|
520 | });
|
521 | }
|
522 | return names;
|
523 | }
|
524 |
|
525 | function next_mangled_name(def, options) {
|
526 | var scope = def.scope;
|
527 | var in_use = names_in_use(scope, options);
|
528 | var holes = scope.cname_holes;
|
529 | var names = Object.create(null);
|
530 | var scopes = [ scope ];
|
531 | def.forEach(function(sym) {
|
532 | var scope = sym.scope;
|
533 | do {
|
534 | if (scopes.indexOf(scope) < 0) {
|
535 | for (var name in names_in_use(scope, options)) {
|
536 | names[name] = true;
|
537 | }
|
538 | scopes.push(scope);
|
539 | } else break;
|
540 | } while (scope = scope.parent_scope);
|
541 | });
|
542 | var name;
|
543 | for (var i = 0; i < holes.length; i++) {
|
544 | name = base54(holes[i]);
|
545 | if (names[name]) continue;
|
546 | holes.splice(i, 1);
|
547 | in_use[name] = true;
|
548 | return name;
|
549 | }
|
550 | while (true) {
|
551 | name = base54(++scope.cname);
|
552 | if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
|
553 | if (!names[name]) break;
|
554 | holes.push(scope.cname);
|
555 | }
|
556 | in_use[name] = true;
|
557 | return name;
|
558 | }
|
559 |
|
560 | AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
561 | var def = this.definition();
|
562 | return !def || def.unmangleable(options);
|
563 | });
|
564 |
|
565 |
|
566 | AST_Label.DEFMETHOD("unmangleable", return_false);
|
567 |
|
568 | AST_Symbol.DEFMETHOD("definition", function() {
|
569 | return this.thedef;
|
570 | });
|
571 |
|
572 | function _default_mangler_options(options) {
|
573 | options = defaults(options, {
|
574 | eval : false,
|
575 | ie : false,
|
576 | keep_fnames : false,
|
577 | reserved : [],
|
578 | toplevel : false,
|
579 | v8 : false,
|
580 | webkit : false,
|
581 | });
|
582 | if (!Array.isArray(options.reserved)) options.reserved = [];
|
583 |
|
584 | push_uniq(options.reserved, "arguments");
|
585 | options.reserved.has = makePredicate(options.reserved);
|
586 | return options;
|
587 | }
|
588 |
|
589 | AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
590 | options = _default_mangler_options(options);
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 | var lname = -1;
|
597 |
|
598 | if (options.cache && options.cache.props) {
|
599 | var mangled_names = names_in_use(this, options);
|
600 | options.cache.props.each(function(mangled_name) {
|
601 | mangled_names[mangled_name] = true;
|
602 | });
|
603 | }
|
604 |
|
605 | var redefined = [];
|
606 | var tw = new TreeWalker(function(node, descend) {
|
607 | if (node instanceof AST_LabeledStatement) {
|
608 |
|
609 | var save_nesting = lname;
|
610 | descend();
|
611 | if (!options.v8 || !in_label(tw)) lname = save_nesting;
|
612 | return true;
|
613 | }
|
614 | if (node instanceof AST_BlockScope) {
|
615 | if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
616 | node.init.definitions.forEach(function(defn) {
|
617 | defn.name.match_symbol(function(sym) {
|
618 | if (!(sym instanceof AST_SymbolLet)) return;
|
619 | var def = sym.definition();
|
620 | var scope = sym.scope.parent_scope;
|
621 | var redef = scope.def_variable(sym);
|
622 | sym.thedef = def;
|
623 | scope.to_mangle.push(redef);
|
624 | def.redefined = function() {
|
625 | return redef;
|
626 | };
|
627 | });
|
628 | }, true);
|
629 | }
|
630 | node.to_mangle = [];
|
631 | node.variables.each(function(def) {
|
632 | if (!defer_redef(def)) node.to_mangle.push(def);
|
633 | });
|
634 | descend();
|
635 | if (options.cache && node instanceof AST_Toplevel) {
|
636 | node.globals.each(mangle);
|
637 | }
|
638 | if (node instanceof AST_Defun && tw.has_directive("use asm")) {
|
639 | var sym = new AST_SymbolRef(node.name);
|
640 | sym.scope = node;
|
641 | sym.reference(options);
|
642 | }
|
643 | node.to_mangle.forEach(mangle);
|
644 | return true;
|
645 | }
|
646 | if (node instanceof AST_Label) {
|
647 | var name;
|
648 | do {
|
649 | name = base54(++lname);
|
650 | } while (RESERVED_WORDS[name]);
|
651 | node.mangled_name = name;
|
652 | return true;
|
653 | }
|
654 | });
|
655 | this.walk(tw);
|
656 | redefined.forEach(mangle);
|
657 |
|
658 | function mangle(def) {
|
659 | if (options.reserved.has[def.name]) return;
|
660 | def.mangle(options);
|
661 | }
|
662 |
|
663 | function defer_redef(def) {
|
664 | var sym = def.orig[0];
|
665 | var redef = def.redefined();
|
666 | if (!redef) {
|
667 | if (!(sym instanceof AST_SymbolConst)) return false;
|
668 | var scope = def.scope.resolve();
|
669 | if (def.scope === scope) return false;
|
670 | if (def.scope.parent_scope.find_variable(sym.name)) return false;
|
671 | redef = scope.def_variable(sym);
|
672 | scope.to_mangle.push(redef);
|
673 | }
|
674 | redefined.push(def);
|
675 | def.references.forEach(reference);
|
676 | if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
677 | return true;
|
678 |
|
679 | function reference(sym) {
|
680 | sym.thedef = redef;
|
681 | sym.reference(options);
|
682 | sym.thedef = def;
|
683 | }
|
684 | }
|
685 |
|
686 | function in_label(tw) {
|
687 | var level = 0, parent;
|
688 | while (parent = tw.parent(level++)) {
|
689 | if (parent instanceof AST_Block) return parent instanceof AST_Toplevel && !options.toplevel;
|
690 | if (parent instanceof AST_LabeledStatement) return true;
|
691 | }
|
692 | }
|
693 | });
|
694 |
|
695 | AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
696 | var cache = options.cache && options.cache.props;
|
697 | var avoid = Object.create(RESERVED_WORDS);
|
698 | options.reserved.forEach(to_avoid);
|
699 | this.globals.each(add_def);
|
700 | this.walk(new TreeWalker(function(node) {
|
701 | if (node instanceof AST_BlockScope) node.variables.each(add_def);
|
702 | }));
|
703 | return avoid;
|
704 |
|
705 | function to_avoid(name) {
|
706 | avoid[name] = true;
|
707 | }
|
708 |
|
709 | function add_def(def) {
|
710 | var name = def.name;
|
711 | if (def.global && cache && cache.has(name)) name = cache.get(name);
|
712 | else if (!def.unmangleable(options)) return;
|
713 | to_avoid(name);
|
714 | }
|
715 | });
|
716 |
|
717 | AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
718 | base54.reset();
|
719 | base54.sort();
|
720 | options = _default_mangler_options(options);
|
721 | var avoid = this.find_colliding_names(options);
|
722 | var cname = 0;
|
723 | this.globals.each(rename);
|
724 | this.walk(new TreeWalker(function(node) {
|
725 | if (node instanceof AST_BlockScope) node.variables.each(rename);
|
726 | }));
|
727 |
|
728 | function next_name() {
|
729 | var name;
|
730 | do {
|
731 | name = base54(cname++);
|
732 | } while (avoid[name]);
|
733 | return name;
|
734 | }
|
735 |
|
736 | function rename(def) {
|
737 | if (def.global && options.cache) return;
|
738 | if (def.unmangleable(options)) return;
|
739 | if (options.reserved.has[def.name]) return;
|
740 | var redef = def.redefined();
|
741 | var name = redef ? redef.rename || redef.name : next_name();
|
742 | def.rename = name;
|
743 | def.forEach(function(sym) {
|
744 | if (sym.definition() === def) sym.name = name;
|
745 | });
|
746 | }
|
747 | });
|
748 |
|
749 | AST_Node.DEFMETHOD("tail_node", return_this);
|
750 | AST_Sequence.DEFMETHOD("tail_node", function() {
|
751 | return this.expressions[this.expressions.length - 1];
|
752 | });
|
753 |
|
754 | AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
755 | options = _default_mangler_options(options);
|
756 | base54.reset();
|
757 | var fn = AST_Symbol.prototype.add_source_map;
|
758 | try {
|
759 | AST_Symbol.prototype.add_source_map = function() {
|
760 | if (!this.unmangleable(options)) base54.consider(this.name, -1);
|
761 | };
|
762 | if (options.properties) {
|
763 | AST_Dot.prototype.add_source_map = function() {
|
764 | base54.consider(this.property, -1);
|
765 | };
|
766 | AST_Sub.prototype.add_source_map = function() {
|
767 | skip_string(this.property);
|
768 | };
|
769 | }
|
770 | base54.consider(this.print_to_string(), 1);
|
771 | } finally {
|
772 | AST_Symbol.prototype.add_source_map = fn;
|
773 | delete AST_Dot.prototype.add_source_map;
|
774 | delete AST_Sub.prototype.add_source_map;
|
775 | }
|
776 | base54.sort();
|
777 |
|
778 | function skip_string(node) {
|
779 | if (node instanceof AST_String) {
|
780 | base54.consider(node.value, -1);
|
781 | } else if (node instanceof AST_Conditional) {
|
782 | skip_string(node.consequent);
|
783 | skip_string(node.alternative);
|
784 | } else if (node instanceof AST_Sequence) {
|
785 | skip_string(node.tail_node());
|
786 | }
|
787 | }
|
788 | });
|
789 |
|
790 | var base54 = (function() {
|
791 | var freq = Object.create(null);
|
792 | function init(chars) {
|
793 | var array = [];
|
794 | for (var i = 0; i < chars.length; i++) {
|
795 | var ch = chars[i];
|
796 | array.push(ch);
|
797 | freq[ch] = -1e-2 * i;
|
798 | }
|
799 | return array;
|
800 | }
|
801 | var digits = init("0123456789");
|
802 | var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
|
803 | var chars, frequency;
|
804 | function reset() {
|
805 | chars = null;
|
806 | frequency = Object.create(freq);
|
807 | }
|
808 | base54.consider = function(str, delta) {
|
809 | for (var i = str.length; --i >= 0;) {
|
810 | frequency[str[i]] += delta;
|
811 | }
|
812 | };
|
813 | function compare(a, b) {
|
814 | return frequency[b] - frequency[a];
|
815 | }
|
816 | base54.sort = function() {
|
817 | chars = leading.sort(compare).concat(digits).sort(compare);
|
818 | };
|
819 | base54.reset = reset;
|
820 | reset();
|
821 | function base54(num) {
|
822 | var ret = leading[num % 54];
|
823 | for (num = Math.floor(num / 54); --num >= 0; num >>= 6) {
|
824 | ret += chars[num & 0x3F];
|
825 | }
|
826 | return ret;
|
827 | }
|
828 | return base54;
|
829 | })();
|