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