improve compatibility with use strict (#5440)
This commit is contained in:
21
lib/ast.js
21
lib/ast.js
@@ -827,6 +827,9 @@ var AST_Class = DEFNODE("Class", "extends name properties", {
|
||||
extends: "[AST_Node?] the super class, or null if not specified",
|
||||
properties: "[AST_ClassProperty*] array of class properties",
|
||||
},
|
||||
resolve: function(def_class) {
|
||||
return def_class ? this : this.parent_scope.resolve();
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
@@ -851,9 +854,6 @@ var AST_DefClass = DEFNODE("DefClass", null, {
|
||||
$propdoc: {
|
||||
name: "[AST_SymbolDefClass] the name of this class",
|
||||
},
|
||||
resolve: function(def_class) {
|
||||
return def_class ? this : this.parent_scope.resolve();
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
|
||||
},
|
||||
@@ -1837,7 +1837,7 @@ var AST_Label = DEFNODE("Label", "references", {
|
||||
initialize: function() {
|
||||
this.references = [];
|
||||
this.thedef = this;
|
||||
}
|
||||
},
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
|
||||
@@ -2039,16 +2039,21 @@ TreeWalker.prototype = {
|
||||
return this.stack[this.stack.length - 2 - (n || 0)];
|
||||
},
|
||||
push: function(node) {
|
||||
if (node instanceof AST_Lambda) {
|
||||
var value;
|
||||
if (node instanceof AST_Class) {
|
||||
this.directives = Object.create(this.directives);
|
||||
value = "use strict";
|
||||
} else if (node instanceof AST_Directive) {
|
||||
value = node.value;
|
||||
} else if (node instanceof AST_Lambda) {
|
||||
this.directives = Object.create(this.directives);
|
||||
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
|
||||
this.directives[node.value] = node;
|
||||
}
|
||||
if (value && !this.directives[value]) this.directives[value] = node;
|
||||
this.stack.push(node);
|
||||
},
|
||||
pop: function() {
|
||||
var node = this.stack.pop();
|
||||
if (node instanceof AST_Lambda) {
|
||||
if (node instanceof AST_Class || node instanceof AST_Lambda) {
|
||||
this.directives = Object.getPrototypeOf(this.directives);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2552,8 +2552,7 @@ Compressor.prototype.compress = function(node) {
|
||||
&& all(iife.args, function(arg) {
|
||||
return !(arg instanceof AST_Spread);
|
||||
})) {
|
||||
var fn_strict = compressor.has_directive("use strict");
|
||||
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
|
||||
var fn_strict = fn.in_strict_mode() && !fn.parent_scope.resolve(true).in_strict_mode();
|
||||
var has_await = is_async(fn) ? function(node) {
|
||||
return node instanceof AST_Symbol && node.name == "await";
|
||||
} : function(node) {
|
||||
@@ -4120,6 +4119,25 @@ Compressor.prototype.compress = function(node) {
|
||||
&& !(compressor && node.expression.has_side_effects(compressor));
|
||||
}
|
||||
|
||||
// in_strict_mode()
|
||||
// return true if scope executes in Strict Mode
|
||||
(function(def) {
|
||||
def(AST_Class, return_this);
|
||||
def(AST_Scope, function() {
|
||||
var body = this.body;
|
||||
for (var i = 0; i < body.length; i++) {
|
||||
var stat = body[i];
|
||||
if (!(stat instanceof AST_Directive)) break;
|
||||
if (stat.value == "use strict") return true;
|
||||
}
|
||||
var parent = this.parent_scope;
|
||||
if (!parent) return false;
|
||||
return parent.resolve(true).in_strict_mode();
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("in_strict_mode", func);
|
||||
});
|
||||
|
||||
// is_truthy()
|
||||
// return true if `!!node === true`
|
||||
(function(def) {
|
||||
@@ -9882,6 +9900,10 @@ Compressor.prototype.compress = function(node) {
|
||||
return safe;
|
||||
}
|
||||
|
||||
function safe_from_strict_mode(fn, compressor) {
|
||||
return fn.in_strict_mode() || !compressor.has_directive("use strict");
|
||||
}
|
||||
|
||||
OPT(AST_Call, function(self, compressor) {
|
||||
var exp = self.expression;
|
||||
var terminated = trim_optional_chain(self, compressor);
|
||||
@@ -10206,7 +10228,10 @@ Compressor.prototype.compress = function(node) {
|
||||
}
|
||||
return true;
|
||||
}) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest));
|
||||
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||
var can_inline = can_drop
|
||||
&& compressor.option("inline")
|
||||
&& !self.is_expr_pure(compressor)
|
||||
&& (exp === fn || safe_from_strict_mode(fn, compressor));
|
||||
if (can_inline && stat instanceof AST_Return) {
|
||||
var value = stat.value;
|
||||
if (exp === fn
|
||||
@@ -11813,8 +11838,9 @@ Compressor.prototype.compress = function(node) {
|
||||
} else if (fixed.name && fixed.name.definition() !== def) {
|
||||
single_use = false;
|
||||
} else if (fixed.parent_scope !== self.scope || is_funarg(def)) {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
if (!safe_from_strict_mode(fixed, compressor)) {
|
||||
single_use = false;
|
||||
} else if ((single_use = fixed.is_constant_expression(self.scope)) == "f") {
|
||||
var scope = self.scope;
|
||||
do {
|
||||
if (scope instanceof AST_LambdaDefinition || scope instanceof AST_LambdaExpression) {
|
||||
|
||||
11
lib/parse.js
11
lib/parse.js
@@ -636,8 +636,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
next_token.add_directive = function(directive) {
|
||||
S.directive_stack[S.directive_stack.length - 1].push(directive);
|
||||
if (S.directives[directive]) S.directives[directive]++;
|
||||
else S.directives[directive] = 1;
|
||||
S.directives[directive] = (S.directives[directive] || 0) + 1;
|
||||
}
|
||||
|
||||
next_token.push_directives_stack = function() {
|
||||
@@ -1340,8 +1339,6 @@ function parse($TEXT, options) {
|
||||
var loop = S.in_loop;
|
||||
var labels = S.labels;
|
||||
++S.in_function;
|
||||
S.in_directives = true;
|
||||
S.input.push_directives_stack();
|
||||
S.in_loop = 0;
|
||||
S.labels = [];
|
||||
if (is("punc", "{")) {
|
||||
@@ -1352,8 +1349,6 @@ function parse($TEXT, options) {
|
||||
handle_regexp();
|
||||
value = maybe_assign();
|
||||
}
|
||||
var is_strict = S.input.has_directive("use strict");
|
||||
S.input.pop_directives_stack();
|
||||
--S.in_function;
|
||||
S.in_loop = loop;
|
||||
S.labels = labels;
|
||||
@@ -1367,7 +1362,7 @@ function parse($TEXT, options) {
|
||||
value: value,
|
||||
end: prev(),
|
||||
});
|
||||
if (is_strict) node.each_argname(strict_verify_symbol);
|
||||
if (S.input.has_directive("use strict")) node.each_argname(strict_verify_symbol);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1412,7 +1407,7 @@ function parse($TEXT, options) {
|
||||
name: name,
|
||||
argnames: argnames,
|
||||
rest: argnames.rest || null,
|
||||
body: body
|
||||
body: body,
|
||||
});
|
||||
if (is_strict) {
|
||||
if (name) strict_verify_symbol(name);
|
||||
|
||||
Reference in New Issue
Block a user