Merge branch 'master' into harmony-v2.8.17

This commit is contained in:
alexlamsl
2017-03-28 22:03:46 +08:00
30 changed files with 2842 additions and 232 deletions

View File

@@ -261,7 +261,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) {
var d = node.definition();
d.references.push(node);
if (!d.fixed || !is_safe(d)
if (d.fixed === undefined || !is_safe(d)
|| is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
d.fixed = false;
}
@@ -274,10 +274,10 @@ merge(Compressor.prototype, {
node.name.walk(suppressor);
} else {
var d = node.name.definition();
if (d.fixed === undefined) {
d.fixed = node.value || make_node(AST_Undefined, node);
if (d.fixed == null) {
d.fixed = node.value;
mark_as_safe(d);
} else {
} else if (node.value) {
d.fixed = false;
}
}
@@ -346,7 +346,7 @@ merge(Compressor.prototype, {
pop();
return true;
}
if (node instanceof AST_Catch) {
if (node instanceof AST_Catch || node instanceof AST_SwitchBranch) {
push();
descend();
pop();
@@ -362,7 +362,14 @@ merge(Compressor.prototype, {
function is_safe(def) {
for (var i = safe_ids.length, id = def.id; --i >= 0;) {
if (safe_ids[i][id]) return true;
if (safe_ids[i][id]) {
if (def.fixed == null) {
var orig = def.orig[0];
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
def.fixed = make_node(AST_Undefined, orig);
}
return true;
}
}
}
@@ -488,15 +495,6 @@ merge(Compressor.prototype, {
return x;
};
var readOnlyPrefix = makePredicate("! ~ + - void typeof");
function statement_to_expression(stat) {
if (stat.body instanceof AST_UnaryPrefix && readOnlyPrefix(stat.body.operator)) {
return stat.body.expression;
} else {
return stat.body;
}
}
function is_iife_call(node) {
if (node instanceof AST_Call && !(node instanceof AST_New)) {
return node.expression instanceof AST_Function || is_iife_call(node.expression);
@@ -606,9 +604,10 @@ merge(Compressor.prototype, {
// Restrict var replacement to constants if side effects encountered.
if (side_effects_encountered |= lvalues_encountered) continue;
var value_has_side_effects = var_decl.value.has_side_effects(compressor);
// Non-constant single use vars can only be replaced in same scope.
if (ref.scope.get_defun_scope() !== self) {
side_effects_encountered |= var_decl.value.has_side_effects(compressor);
side_effects_encountered |= value_has_side_effects;
continue;
}
@@ -635,6 +634,7 @@ merge(Compressor.prototype, {
|| (parent instanceof AST_If && node !== parent.condition)
|| (parent instanceof AST_Conditional && node !== parent.condition)
|| (node instanceof AST_SymbolRef
&& value_has_side_effects
&& !are_references_in_scope(node.definition(), self))
|| (parent instanceof AST_Binary
&& (parent.operator == "&&" || parent.operator == "||")
@@ -998,10 +998,10 @@ merge(Compressor.prototype, {
};
statements.forEach(function(stat){
if (stat instanceof AST_SimpleStatement) {
if (seqLength(seq) >= compressor.sequences_limit) {
push_seq();
}
seq.push(seq.length > 0 ? statement_to_expression(stat) : stat.body);
if (seqLength(seq) >= compressor.sequences_limit) push_seq();
var body = stat.body;
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
if (body) seq.push(body);
} else {
push_seq();
ret.push(stat);
@@ -1050,7 +1050,7 @@ merge(Compressor.prototype, {
stat.init = cons_seq(stat.init);
}
else if (!stat.init) {
stat.init = statement_to_expression(prev);
stat.init = prev.body.drop_side_effect_free(compressor);
ret.pop();
}
} catch(ex) {
@@ -1190,9 +1190,9 @@ merge(Compressor.prototype, {
&& this.left.is_number(compressor)
&& this.right.is_number(compressor);
});
var assign = makePredicate("-= *= /= %= &= |= ^= <<= >>= >>>=");
def(AST_Assign, function(compressor){
return assign(this.operator) || this.right.is_number(compressor);
return binary(this.operator.slice(0, -1))
|| this.operator == "=" && this.right.is_number(compressor);
});
def(AST_Seq, function(compressor){
return this.cdr.is_number(compressor);
@@ -1231,8 +1231,10 @@ merge(Compressor.prototype, {
node.DEFMETHOD("is_string", func);
});
var unary_side_effects = makePredicate("delete ++ --");
function isLHS(node, parent) {
return parent instanceof AST_Unary && (parent.operator == "++" || parent.operator == "--")
return parent instanceof AST_Unary && unary_side_effects(parent.operator)
|| parent instanceof AST_Assign && parent.left === node;
}
@@ -1636,14 +1638,37 @@ merge(Compressor.prototype, {
return false;
});
def(AST_Block, function(compressor){
for (var i = this.body.length; --i >= 0;) {
if (this.body[i].has_side_effects(compressor))
function any(list, compressor) {
for (var i = list.length; --i >= 0;)
if (list[i].has_side_effects(compressor))
return true;
}
return false;
});
}
def(AST_Block, function(compressor){
return any(this.body, compressor);
});
def(AST_Switch, function(compressor){
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
def(AST_Case, function(compressor){
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
def(AST_Try, function(compressor){
return any(this.body, compressor)
|| this.bcatch && this.bcatch.has_side_effects(compressor)
|| this.bfinally && this.bfinally.has_side_effects(compressor);
});
def(AST_If, function(compressor){
return this.condition.has_side_effects(compressor)
|| this.body && this.body.has_side_effects(compressor)
|| this.alternative && this.alternative.has_side_effects(compressor);
});
def(AST_LabeledStatement, function(compressor){
return this.body.has_side_effects(compressor);
});
def(AST_SimpleStatement, function(compressor){
return this.body.has_side_effects(compressor);
});
@@ -1662,17 +1687,14 @@ merge(Compressor.prototype, {
|| this.alternative.has_side_effects(compressor);
});
def(AST_Unary, function(compressor){
return member(this.operator, ["delete", "++", "--"])
return unary_side_effects(this.operator)
|| this.expression.has_side_effects(compressor);
});
def(AST_SymbolRef, function(compressor){
return this.global() && this.undeclared();
});
def(AST_Object, function(compressor){
for (var i = this.properties.length; --i >= 0;)
if (this.properties[i].has_side_effects(compressor))
return true;
return false;
return any(this.properties, compressor);
});
def(AST_ObjectProperty, function(compressor){
if (this.key instanceof AST_ObjectKeyVal &&
@@ -1681,10 +1703,7 @@ merge(Compressor.prototype, {
return this.value.has_side_effects(compressor);
});
def(AST_Array, function(compressor){
for (var i = this.elements.length; --i >= 0;)
if (this.elements[i].has_side_effects(compressor))
return true;
return false;
return any(this.elements, compressor);
});
def(AST_Dot, function(compressor){
if (!compressor.option("pure_getters")) return true;
@@ -1927,9 +1946,13 @@ merge(Compressor.prototype, {
function before(node, descend, in_list) {
if (node instanceof AST_Function
&& node.name
&& !compressor.option("keep_fnames")
&& !(node.name.definition().id in in_use_ids)) {
node.name = null;
&& !compressor.option("keep_fnames")) {
var def = node.name.definition();
// any declarations with same name will overshadow
// name of this anonymous function and can therefore
// never be used anywhere
if (!(def.id in in_use_ids) || def.orig.length > 1)
node.name = null;
}
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
var trim = !compressor.option("keep_fargs");
@@ -1980,9 +2003,14 @@ merge(Compressor.prototype, {
var def = node.definitions.filter(function(def){
if (def.value) def.value = def.value.transform(tt);
if (def.name instanceof AST_Destructuring) return true;
if (def.name.definition().id in in_use_ids) return true;
if (!drop_vars && def.name.definition().global) return true;
var sym = def.name.definition();
if (sym.id in in_use_ids) return true;
if (!drop_vars && sym.global) return true;
if (sym.orig[0] instanceof AST_SymbolCatch
&& sym.scope.parent_scope.find_variable(def.name).orig[0] === def.name) {
def.value = def.value && def.value.drop_side_effect_free(compressor);
return true;
}
var w = {
name : def.name.name,
file : def.name.start.file,
@@ -2069,6 +2097,9 @@ merge(Compressor.prototype, {
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
body: body
});
} else if (is_empty(node.init)) {
node.init = null;
return node;
}
}
if (node instanceof AST_BlockStatement) {
@@ -2266,6 +2297,7 @@ merge(Compressor.prototype, {
switch (this.operator) {
case "&&":
case "||":
if (right === this.right) return this;
var node = this.clone();
node.right = right;
return node;
@@ -2299,26 +2331,19 @@ merge(Compressor.prototype, {
return node;
});
def(AST_Unary, function(compressor, first_in_statement){
switch (this.operator) {
case "delete":
case "++":
case "--":
return this;
case "typeof":
if (this.expression instanceof AST_SymbolRef) return null;
default:
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (first_in_statement
&& this instanceof AST_UnaryPrefix
&& is_iife_call(expression)) {
if (expression === this.expression && this.operator.length === 1) return this;
return make_node(AST_UnaryPrefix, this, {
operator: this.operator.length === 1 ? this.operator : "!",
expression: expression
});
}
return expression;
if (unary_side_effects(this.operator)) return this;
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (first_in_statement
&& this instanceof AST_UnaryPrefix
&& is_iife_call(expression)) {
if (expression === this.expression && this.operator.length === 1) return this;
return make_node(AST_UnaryPrefix, this, {
operator: this.operator.length === 1 ? this.operator : "!",
expression: expression
});
}
return expression;
});
def(AST_SymbolRef, function() {
return this.undeclared() ? this : null;
@@ -2526,8 +2551,8 @@ merge(Compressor.prototype, {
return make_node(AST_SimpleStatement, self, {
body: make_node(AST_Conditional, self, {
condition : self.condition,
consequent : statement_to_expression(self.body),
alternative : statement_to_expression(self.alternative)
consequent : self.body.body,
alternative : self.alternative.body
})
}).optimize(compressor);
}
@@ -2543,25 +2568,24 @@ merge(Compressor.prototype, {
body: make_node(AST_Binary, self, {
operator : "||",
left : negated,
right : statement_to_expression(self.body)
right : self.body.body
})
}).optimize(compressor);
return make_node(AST_SimpleStatement, self, {
body: make_node(AST_Binary, self, {
operator : "&&",
left : self.condition,
right : statement_to_expression(self.body)
right : self.body.body
})
}).optimize(compressor);
}
if (self.body instanceof AST_EmptyStatement
&& self.alternative
&& self.alternative instanceof AST_SimpleStatement) {
return make_node(AST_SimpleStatement, self, {
body: make_node(AST_Binary, self, {
operator : "||",
left : self.condition,
right : statement_to_expression(self.alternative)
right : self.alternative.body
})
}).optimize(compressor);
}
@@ -2611,105 +2635,93 @@ merge(Compressor.prototype, {
});
OPT(AST_Switch, function(self, compressor){
if (self.body.length == 0 && compressor.option("conditionals")) {
return make_node(AST_SimpleStatement, self, {
body: self.expression
}).transform(compressor);
var branch;
var value = self.expression.evaluate(compressor);
if (value !== self.expression) {
var expression = make_node_from_constant(value, self.expression).transform(compressor);
self.expression = best_of_expression(expression, self.expression);
}
for(;;) {
var last_branch = self.body[self.body.length - 1];
if (last_branch) {
var stat = last_branch.body[last_branch.body.length - 1]; // last statement
if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
last_branch.body.pop();
if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
self.body.pop();
if (!compressor.option("dead_code")) return self;
var prev_block;
var decl = [];
var body = [];
var default_branch;
var exact_match;
var fallthrough;
for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
branch = self.body[i];
if (branch instanceof AST_Default) {
if (!default_branch) default_branch = branch;
else if (!fallthrough) {
extract_declarations_from_unreachable_code(compressor, branch, decl);
continue;
}
} else if (value !== self.expression) {
var exp = branch.expression.evaluate(compressor);
if (exp === value) {
exact_match = branch;
if (default_branch) {
body.splice(body.indexOf(default_branch), 1);
extract_declarations_from_unreachable_code(compressor, default_branch, decl);
default_branch = null;
}
} else if (exp !== branch.expression && !fallthrough) {
extract_declarations_from_unreachable_code(compressor, branch, decl);
continue;
}
}
break;
if (aborts(branch)) {
var block = make_node(AST_BlockStatement, branch, branch).print_to_string();
if (!fallthrough && prev_block === block) body[body.length - 1].body = [];
body.push(branch);
prev_block = block;
fallthrough = false;
} else {
body.push(branch);
prev_block = null;
fallthrough = true;
}
}
var value = self.expression.evaluate(compressor);
out: if (value !== self.expression) try {
// constant expression
var expression = make_node_from_constant(value, self.expression);
self.expression = best_of_expression(expression, self.expression);
if (!compressor.option("dead_code")) break out;
var in_if = false;
var in_block = false;
var started = false;
var stopped = false;
var ruined = false;
var tt = new TreeTransformer(function(node, descend, in_list){
if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
// no need to descend these node types
return node;
}
else if (node instanceof AST_Switch && node === self) {
node = node.clone();
descend(node, this);
return ruined ? node : make_node(AST_BlockStatement, node, {
body: node.body.reduce(function(a, branch){
return a.concat(branch.body);
}, [])
}).transform(compressor);
}
else if (node instanceof AST_If || node instanceof AST_Try) {
var save = in_if;
in_if = !in_block;
descend(node, this);
in_if = save;
return node;
}
else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
var save = in_block;
in_block = true;
descend(node, this);
in_block = save;
return node;
}
else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
if (in_if) {
ruined = true;
return node;
}
if (in_block) return node;
stopped = true;
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
}
else if (node instanceof AST_SwitchBranch && this.parent() === self) {
if (stopped) return MAP.skip;
if (node instanceof AST_Case) {
var exp = node.expression.evaluate(compressor);
if (exp === node.expression) {
// got a case with non-constant expression, baling out
throw self;
}
if (exp === value || started) {
started = true;
if (aborts(node)) stopped = true;
descend(node, this);
return node;
}
return MAP.skip;
}
descend(node, this);
return node;
}
for (; i < len && fallthrough; i++) {
branch = self.body[i];
exact_match.body = exact_match.body.concat(branch.body);
fallthrough = !aborts(exact_match);
}
while (i < len) extract_declarations_from_unreachable_code(compressor, self.body[i++], decl);
if (body.length > 0) {
body[0].body = decl.concat(body[0].body);
}
self.body = body;
while (branch = body[body.length - 1]) {
var stat = branch.body[branch.body.length - 1];
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat.label) === self)
branch.body.pop();
if (branch.body.length || branch instanceof AST_Case
&& (default_branch || branch.expression.has_side_effects(compressor))) break;
if (body.pop() === default_branch) default_branch = null;
}
if (body.length == 0) {
return make_node(AST_BlockStatement, self, {
body: decl.concat(make_node(AST_SimpleStatement, self.expression, {
body: self.expression
}))
}).optimize(compressor);
}
if (body.length == 1 && (body[0] === exact_match || body[0] === default_branch)) {
var has_break = false;
var tw = new TreeWalker(function(node) {
if (has_break
|| node instanceof AST_Lambda
|| node instanceof AST_SimpleStatement) return true;
if (node instanceof AST_Break && tw.loopcontrol_target(node.label) === self)
has_break = true;
});
tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
self = self.transform(tt);
} catch(ex) {
if (ex !== self) throw ex;
self.walk(tw);
if (!has_break) return make_node(AST_BlockStatement, self, body[0]).optimize(compressor);
}
return self;
});
OPT(AST_Case, function(self, compressor){
self.body = tighten_body(self.body, compressor);
return self;
});
OPT(AST_Try, function(self, compressor){
self.body = tighten_body(self.body, compressor);
return self;
@@ -3056,7 +3068,9 @@ merge(Compressor.prototype, {
&& (self.car.operator == "++" || self.car.operator == "--")) {
left = self.car.expression;
}
if (left) {
if (left
&& !(left instanceof AST_SymbolRef
&& left.definition().orig[0] instanceof AST_SymbolLambda)) {
var parent, field;
var cdr = self.cdr;
while (true) {
@@ -3072,9 +3086,14 @@ merge(Compressor.prototype, {
return car;
}
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
field = cdr.left.is_constant() ? "right" : "left";
if (cdr.left.is_constant()) {
if (cdr.operator == "||" || cdr.operator == "&&") break;
field = "right";
} else {
field = "left";
}
} else if (cdr instanceof AST_Call
|| cdr instanceof AST_Unary && cdr.operator != "++" && cdr.operator != "--") {
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
field = "expression";
} else break;
parent = cdr;
@@ -3139,10 +3158,10 @@ merge(Compressor.prototype, {
// typeof always returns a non-empty string, thus it's
// always true in booleans
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
return make_node(AST_Seq, self, {
return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_node(AST_Seq, self, {
car: e,
cdr: make_node(AST_True, self)
}).optimize(compressor);
})).optimize(compressor);
}
}
// avoids infinite recursion of numerals
@@ -3424,6 +3443,7 @@ merge(Compressor.prototype, {
left: self.left,
right: self.right.expression
});
break;
}
// -a + b => b - a
if (self.left instanceof AST_UnaryPrefix
@@ -3435,6 +3455,7 @@ merge(Compressor.prototype, {
left: self.right,
right: self.left.expression
});
break;
}
case "*":
associative = compressor.option("unsafe_math");
@@ -3698,21 +3719,30 @@ merge(Compressor.prototype, {
alternative: self.consequent
});
}
var condition = self.condition;
var consequent = self.consequent;
var alternative = self.alternative;
// x?x:y --> x||y
if (condition instanceof AST_SymbolRef
&& consequent instanceof AST_SymbolRef
&& condition.definition() === consequent.definition()) {
return make_node(AST_Binary, self, {
operator: "||",
left: condition,
right: alternative
});
}
// if (foo) exp = something; else exp = something_else;
// |
// v
// exp = foo ? something : something_else;
if (consequent instanceof AST_Assign
&& alternative instanceof AST_Assign
&& consequent.operator == alternative.operator
&& consequent.left.equivalent_to(alternative.left)
&& (!consequent.left.has_side_effects(compressor)
|| !self.condition.has_side_effects(compressor))
) {
/*
* Stuff like this:
* if (foo) exp = something; else exp = something_else;
* ==>
* exp = foo ? something : something_else;
*/
&& (!self.condition.has_side_effects(compressor)
|| consequent.operator == "="
&& !consequent.left.has_side_effects(compressor))) {
return make_node(AST_Assign, self, {
operator: consequent.operator,
left: consequent.left,

View File

@@ -904,7 +904,7 @@ function OutputStream(options) {
output.print("for");
output.space();
output.with_parens(function(){
if (self.init && !(self.init instanceof AST_EmptyStatement)) {
if (self.init) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
} else {

View File

@@ -852,6 +852,7 @@ function parse($TEXT, options) {
html5_comments : true,
bare_returns : false,
shebang : true,
cli : false,
});
var S = {
@@ -2418,7 +2419,7 @@ function parse($TEXT, options) {
function make_unary(ctor, op, expr) {
if ((op == "++" || op == "--") && !is_assignable(expr))
croak("Invalid use of " + op + " operator");
croak("Invalid use of " + op + " operator", null, ctor === AST_UnaryPrefix ? expr.start.col - 1 : null);
return new ctor({ operator: op, expression: expr });
};
@@ -2467,6 +2468,7 @@ function parse($TEXT, options) {
};
function is_assignable(expr) {
if (options.cli) return true;
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
};

View File

@@ -83,9 +83,16 @@ SymbolDef.prototype = {
}
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
var sym = this.orig[0];
if (!options.screw_ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
this.mangled_name = s.next_mangled(options, this);
var def;
if (options.screw_ie8
&& sym instanceof AST_SymbolCatch
&& (def = s.parent_scope.find_variable(sym))) {
this.mangled_name = def.mangled_name || def.name;
} else
this.mangled_name = s.next_mangled(options, this);
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
@@ -111,8 +118,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
if (node.is_block_scope()) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars();
scope.parent_scope = save_scope;
scope.init_scope_vars(save_scope);
if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with;
scope.uses_eval = save_scope.uses_eval;
@@ -129,8 +135,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars();
var save_scope = node.parent_scope = scope;
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
@@ -213,6 +219,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|| node instanceof AST_SymbolConst) {
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export, in_block);
def.destructuring = in_destructuring;
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
node.reference(options);
}
}
}
else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node, in_export, in_block);
@@ -309,14 +323,14 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(){
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.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
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
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
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.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
this.parent_scope = parent_scope; // 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
});
AST_Node.DEFMETHOD("is_block_scope", function(){
@@ -339,15 +353,15 @@ AST_IterationStatement.DEFMETHOD("is_block_scope", function(){
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
var def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
this.def_variable(new AST_SymbolVar({
name: "arguments",
start: this.start,
end: this.end
}));
});
AST_SymbolRef.DEFMETHOD("reference", function(options) {
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
def.references.push(this);
var s = this.scope;
while (s) {
push_uniq(s.enclosed, def);
@@ -361,6 +375,11 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
}
});
AST_Symbol.DEFMETHOD("reference", function(options) {
this.definition().references.push(this);
this.mark_enclosed(options);
});
AST_Scope.DEFMETHOD("find_variable", function(name){
if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name)