"use strict";
-function SymbolDef(scope, orig) {
+function SymbolDef(scope, index, orig) {
this.name = orig.name;
this.orig = [ orig ];
this.scope = scope;
this.mangled_name = null;
this.undeclared = false;
this.constant = false;
+ this.index = index;
};
SymbolDef.prototype = {
- unmangleable: function() {
- return this.global || this.undeclared || this.scope.uses_eval || this.scope.uses_with;
+ unmangleable: function(options) {
+ return this.global
+ || this.undeclared
+ || (!options.eval && (this.scope.uses_eval || this.scope.uses_with));
},
- mangle: function() {
- if (!this.mangled_name && !this.unmangleable())
- this.mangled_name = this.scope.next_mangled();
+ mangle: function(options) {
+ if (!this.mangled_name && !this.unmangleable(options))
+ this.mangled_name = this.scope.next_mangled(options);
}
};
var self = this;
var scope = self.parent_scope = null;
var labels = new Dictionary();
+ var nesting = 0;
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Scope) {
- node.init_scope_vars();
+ node.init_scope_vars(nesting);
var save_scope = node.parent_scope = scope;
+ ++nesting;
scope = node;
descend();
scope = save_scope;
+ --nesting;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Directive) {
if (globals.has(name)) {
g = globals.get(name);
} else {
- g = new SymbolDef(self, node);
+ g = new SymbolDef(self, globals.size(), node);
g.undeclared = true;
globals.set(name, g);
}
self.walk(tw);
});
-AST_Scope.DEFMETHOD("init_scope_vars", function(){
+AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.parent_scope = null; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables
+ this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
});
AST_Scope.DEFMETHOD("strict", function(){
});
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
- AST_Scope.prototype.init_scope_vars.call(this);
+ AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
});
if (s === def.scope) break;
s = s.parent_scope;
}
+ this.frame = this.scope.nesting - def.scope.nesting;
});
AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
- def = new SymbolDef(this, symbol);
+ def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
def.global = !this.parent_scope;
} else {
return symbol.thedef = def;
});
-AST_Scope.DEFMETHOD("next_mangled", function(){
+AST_Scope.DEFMETHOD("next_mangled", function(options){
var ext = this.enclosed, n = ext.length;
out: while (true) {
var m = base54(++this.cname);
// inner scopes.
for (var i = n; --i >= 0;) {
var sym = ext[i];
- var name = sym.mangled_name || (sym.unmangleable() && sym.name);
+ var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
if (m == name) continue out;
}
return m;
return this.enclosed.indexOf(sym) < 0 ? null : sym;
});
-AST_Symbol.DEFMETHOD("unmangleable", function(){
- return this.definition().unmangleable();
+AST_Symbol.DEFMETHOD("unmangleable", function(options){
+ return this.definition().unmangleable(options);
});
// labels are always mangleable
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = defaults(options, {
- except : []
+ except : [],
+ eval : false,
});
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
to_mangle.forEach(function(def){ def.mangle(options) });
});
-AST_Toplevel.DEFMETHOD("compute_char_frequency", function(){
+AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
var tw = new TreeWalker(function(node){
if (node instanceof AST_Constant)
base54.consider(node.print_to_string());
base54.consider("catch");
else if (node instanceof AST_Finally)
base54.consider("finally");
- else if (node instanceof AST_Symbol && node.unmangleable())
+ else if (node instanceof AST_Symbol && node.unmangleable(options))
base54.consider(node.name);
else if (node instanceof AST_Unary || node instanceof AST_Binary)
base54.consider(node.operator);