aboutsummaryrefslogtreecommitdiff
path: root/lib/scope.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/scope.js')
-rw-r--r--lib/scope.js95
1 files changed, 51 insertions, 44 deletions
diff --git a/lib/scope.js b/lib/scope.js
index 8ce3e4da..ab207d60 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -118,11 +118,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
descend();
scope = save_scope;
defun = save_defun;
- return true; // don't descend again in TreeWalker
+ return true;
}
if (node instanceof AST_With) {
- for (var s = scope; s; s = s.parent_scope)
- s.uses_with = true;
+ for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
return;
}
if (node instanceof AST_Symbol) {
@@ -132,18 +131,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
node.thedef = node;
node.references = [];
}
- if (node instanceof AST_SymbolDefun || options.ie8 && node instanceof AST_SymbolLambda) {
- // Careful here, the scope where this should be defined is
- // the parent scope. The reason is that we enter a new
- // scope when we encounter the AST_Defun node (which is
- // instanceof AST_Scope) but we get to the symbol a bit
- // later.
- (node.scope = defun.parent_scope).def_function(node, defun);
- }
- else if (node instanceof AST_SymbolLambda) {
+ if (node instanceof AST_SymbolDefun) {
+ // This should be defined in the parent scope, as we encounter the
+ // AST_Defun node before getting to its AST_Symbol.
+ (node.scope = defun.parent_scope.resolve()).def_function(node, defun);
+ } else if (node instanceof AST_SymbolLambda) {
defun.def_function(node, node.name == "arguments" ? undefined : defun);
- }
- else if (node instanceof AST_SymbolVar) {
+ } else if (node instanceof AST_SymbolVar) {
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
if (defun !== scope) {
node.mark_enclosed(options);
@@ -153,8 +147,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
node.reference(options);
}
- }
- else if (node instanceof AST_SymbolCatch) {
+ } else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun;
}
});
@@ -162,9 +155,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// pass 2: find back references and eval
self.globals = new Dictionary();
- var tw = new TreeWalker(function(node, descend) {
- if (node instanceof AST_LoopControl && node.label) {
- node.label.thedef.references.push(node);
+ var tw = new TreeWalker(function(node) {
+ if (node instanceof AST_LoopControl) {
+ if (node.label) node.label.thedef.references.push(node);
return true;
}
if (node instanceof AST_SymbolRef) {
@@ -185,35 +178,43 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
return true;
}
// ensure mangling works if catch reuses a scope variable
- var def;
- if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
- var s = node.scope;
- while (s) {
+ if (node instanceof AST_SymbolCatch) {
+ var def = node.definition().redefined();
+ if (def) for (var s = node.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (s === def.scope) break;
- s = s.parent_scope;
}
+ return true;
}
});
self.walk(tw);
// pass 3: fix up any scoping issue with IE8
- if (options.ie8) {
- self.walk(new TreeWalker(function(node, descend) {
- if (node instanceof AST_SymbolCatch) {
- var name = node.name;
- var refs = node.thedef.references;
- var scope = node.thedef.defun;
- var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
- refs.forEach(function(ref) {
- ref.thedef = def;
- ref.reference(options);
- });
- node.thedef = def;
- node.reference(options);
- return true;
+ if (options.ie8) self.walk(new TreeWalker(function(node) {
+ if (node instanceof AST_SymbolCatch) {
+ redefine(node, node.thedef.defun);
+ return true;
+ }
+ if (node instanceof AST_SymbolLambda) {
+ var def = node.thedef;
+ if (def.orig.length == 1) {
+ redefine(node, node.scope.parent_scope);
+ node.thedef.init = def.init;
}
- }));
+ return true;
+ }
+ }));
+
+ function redefine(node, scope) {
+ var name = node.name;
+ var refs = node.thedef.references;
+ var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
+ refs.forEach(function(ref) {
+ ref.thedef = def;
+ ref.reference(options);
+ });
+ node.thedef = def;
+ node.reference(options);
}
});
@@ -252,8 +253,7 @@ AST_Lambda.DEFMETHOD("init_scope_vars", function() {
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
- var s = this.scope;
- while (s) {
+ for (var s = this.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (options.keep_fnames) {
s.functions.each(function(d) {
@@ -261,7 +261,6 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
});
}
if (s === def.scope) break;
- s = s.parent_scope;
}
});
@@ -298,6 +297,12 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
return symbol.thedef = def;
});
+AST_Lambda.DEFMETHOD("resolve", return_this);
+AST_Scope.DEFMETHOD("resolve", function() {
+ return this.parent_scope;
+});
+AST_Toplevel.DEFMETHOD("resolve", return_this);
+
function names_in_use(scope, options) {
var names = scope.names_in_use;
if (!names) {
@@ -410,7 +415,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
var save_nesting = lname;
descend();
lname = save_nesting;
- return true; // don't descend again in TreeWalker
+ return true;
}
if (node instanceof AST_Scope) {
descend();
@@ -422,7 +427,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
}
if (node instanceof AST_Label) {
var name;
- do name = base54(++lname); while (!is_identifier(name));
+ do {
+ name = base54(++lname);
+ } while (!is_identifier(name));
node.mangled_name = name;
return true;
}