clean up scope-related variables (#4179)
This commit is contained in:
@@ -251,9 +251,10 @@ var AST_Block = DEFNODE("Block", "body", {
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||
var AST_BlockScope = DEFNODE("BlockScope", "cname enclosed functions make_def parent_scope variables", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||
@@ -443,10 +444,9 @@ var AST_With = DEFNODE("With", "expression", {
|
||||
|
||||
/* -----[ scope and functions ]----- */
|
||||
|
||||
var AST_Scope = DEFNODE("Scope", "cname uses_eval uses_with", {
|
||||
var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
},
|
||||
|
||||
@@ -6778,7 +6778,7 @@ merge(Compressor.prototype, {
|
||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||
argnames: [],
|
||||
body: []
|
||||
}).init_scope_vars(exp.scope);
|
||||
}).init_vars(exp.scope);
|
||||
if (all(self.args, function(x) {
|
||||
return x instanceof AST_String;
|
||||
})) {
|
||||
@@ -9071,7 +9071,7 @@ merge(Compressor.prototype, {
|
||||
self.expression = make_node(AST_Function, self.expression, {
|
||||
argnames: [],
|
||||
body: []
|
||||
}).init_scope_vars(exp.scope);
|
||||
}).init_vars(exp.scope);
|
||||
break;
|
||||
case "Number":
|
||||
self.expression = make_node(AST_Number, self.expression, {
|
||||
|
||||
34
lib/scope.js
34
lib/scope.js
@@ -127,7 +127,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
|
||||
var s = scope;
|
||||
do {
|
||||
s = s.resolve();
|
||||
if (s.uses_with) break;
|
||||
s.uses_with = true;
|
||||
} while (s = s.parent_scope);
|
||||
return;
|
||||
}
|
||||
if (node instanceof AST_Symbol) {
|
||||
@@ -154,7 +159,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
|
||||
function walk_scope(descend) {
|
||||
node.init_scope_vars(scope);
|
||||
node.init_vars(scope);
|
||||
var save_defun = defun;
|
||||
var save_scope = scope;
|
||||
if (node instanceof AST_Scope) defun = node;
|
||||
@@ -197,9 +202,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
if (name == "eval") {
|
||||
var parent = tw.parent();
|
||||
if (parent.TYPE == "Call" && parent.expression === node) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||
var s = node.scope;
|
||||
do {
|
||||
s = s.resolve();
|
||||
if (s.uses_eval) break;
|
||||
s.uses_eval = true;
|
||||
}
|
||||
} while (s = s.parent_scope);
|
||||
} else if (sym.undeclared) {
|
||||
self.uses_eval = true;
|
||||
}
|
||||
@@ -281,22 +289,28 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
}
|
||||
});
|
||||
|
||||
function init_scope_vars(scope, parent) {
|
||||
function init_block_vars(scope, parent) {
|
||||
scope.cname = -1; // the current index for mangling functions/variables
|
||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
||||
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
|
||||
}
|
||||
|
||||
AST_BlockScope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
function init_scope_vars(scope, parent) {
|
||||
init_block_vars(scope, parent);
|
||||
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
}
|
||||
|
||||
AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_block_vars(this, parent_scope);
|
||||
});
|
||||
AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
this.uses_arguments = false;
|
||||
this.def_variable(new AST_SymbolFunarg({
|
||||
|
||||
Reference in New Issue
Block a user