Compare commits

...

12 Commits

Author SHA1 Message Date
Alex Lam S.L
6335b5fd8a v3.13.3 2021-03-29 06:58:06 +08:00
Alex Lam S.L
daa8319b8a fix corner cases with logical assignment operators (#4828)
fixes #4827
2021-03-28 03:44:45 +08:00
Alex Lam S.L
d5599604e8 enhance collapse_vars (#4826) 2021-03-27 22:14:37 +08:00
Alex Lam S.L
072933f1d5 diagnose GitHub Actions (#4825) 2021-03-25 18:44:39 +08:00
Alex Lam S.L
39df3a1680 fix corner case in functions (#4824)
fixes #4823
2021-03-25 08:49:01 +08:00
Alex Lam S.L
03c5ecb2e3 fix corner cases with class (#4822)
fixes #4821
2021-03-25 04:36:50 +08:00
Alex Lam S.L
40ef074cb3 fix corner case in comparisons (#4820)
fixes #4819
2021-03-24 10:10:02 +08:00
Alex Lam S.L
78e3936cd4 fix corner case in inline (#4818)
fixes #4817
2021-03-23 22:33:24 +08:00
Alex Lam S.L
e7be38b42a fix corner cases with logical assignment operators (#4816)
fixes #4815
2021-03-23 13:02:45 +08:00
Alex Lam S.L
44394e61c9 workaround toString() quirks on global context (#4814) 2021-03-23 11:15:41 +08:00
Alex Lam S.L
f9055df44d support logical assignment operators (#4813) 2021-03-23 04:59:43 +08:00
Alex Lam S.L
51bdb7281b improve global context enumeration under sandbox (#4812)
fixes #4811
2021-03-22 22:43:33 +08:00
13 changed files with 576 additions and 108 deletions

View File

@@ -814,14 +814,91 @@ merge(Compressor.prototype, {
def(AST_Assign, function(tw, descend, compressor) {
var node = this;
var left = node.left;
if (node.operator == "=" && left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
node.right.walk(tw);
walk_prop(left);
node.__drop = true;
} else if (!(left instanceof AST_Destructured || left instanceof AST_SymbolRef)) {
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
switch (node.operator) {
case "=":
if (left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
node.right.walk(tw);
walk_prop(left);
node.__drop = true;
return true;
}
if (scan) {
walk_assign();
return true;
}
mark_assignment_to_arguments(left);
return;
} else if (node.operator == "=") {
case "&&=":
case "||=":
case "??=":
left.walk(tw);
push(tw);
if (scan) {
walk_assign();
} else {
mark_assignment_to_arguments(left);
node.right.walk(tw);
}
pop(tw);
return true;
default:
if (!scan) {
mark_assignment_to_arguments(left);
return;
}
var d = left.definition();
d.assignments++;
var fixed = d.fixed;
if (is_modified(compressor, tw, node, node, 0)) {
d.fixed = false;
return;
}
var safe = safe_to_read(tw, d);
node.right.walk(tw);
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
push_ref(d, left);
mark(tw, d);
if (d.single_use) d.single_use = false;
left.fixed = d.fixed = function() {
return make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: make_ref(left, fixed),
right: node.right
});
};
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
left.fixed.assigns.push(node);
} else {
left.walk(tw);
d.fixed = false;
}
return true;
}
function walk_prop(lhs) {
if (lhs instanceof AST_Dot) {
walk_prop(lhs.expression);
} else if (lhs instanceof AST_Sub) {
walk_prop(lhs.expression);
lhs.property.walk(tw);
} else if (lhs instanceof AST_SymbolRef) {
var d = lhs.definition();
push_ref(d, lhs);
if (d.fixed) {
lhs.fixed = d.fixed;
if (lhs.fixed.assigns) {
lhs.fixed.assigns.push(node);
} else {
lhs.fixed.assigns = [ node ];
}
}
} else {
lhs.walk(tw);
}
}
function walk_assign() {
node.right.walk(tw);
scan_declaration(tw, compressor, left, function() {
return node.right;
@@ -849,56 +926,6 @@ merge(Compressor.prototype, {
d.fixed = false;
}
});
} else {
var d = left.definition();
d.assignments++;
var fixed = d.fixed;
if (is_modified(compressor, tw, node, node, 0)) {
d.fixed = false;
return;
}
var safe = safe_to_read(tw, d);
node.right.walk(tw);
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
push_ref(d, left);
mark(tw, d);
if (d.single_use) d.single_use = false;
left.fixed = d.fixed = function() {
return make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: make_ref(left, fixed),
right: node.right
});
};
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
left.fixed.assigns.push(node);
} else {
left.walk(tw);
d.fixed = false;
}
}
return true;
function walk_prop(lhs) {
if (lhs instanceof AST_Dot) {
walk_prop(lhs.expression);
} else if (lhs instanceof AST_Sub) {
walk_prop(lhs.expression);
lhs.property.walk(tw);
} else if (lhs instanceof AST_SymbolRef) {
var d = lhs.definition();
push_ref(d, lhs);
if (d.fixed) {
lhs.fixed = d.fixed;
if (lhs.fixed.assigns) {
lhs.fixed.assigns.push(node);
} else {
lhs.fixed.assigns = [ node ];
}
}
} else {
lhs.walk(tw);
}
}
});
def(AST_Binary, function(tw) {
@@ -971,7 +998,7 @@ merge(Compressor.prototype, {
if (prop.key instanceof AST_Node) prop.key.walk(tw);
return prop.value;
}).forEach(function(prop) {
if (prop.static) {
if (prop.static && (prop.value instanceof AST_Lambda || !prop.value.contains_this())) {
prop.value.walk(tw);
} else {
push(tw);
@@ -1799,6 +1826,18 @@ merge(Compressor.prototype, {
can_replace = replace;
return signal_abort(node);
}
// Scan but don't replace inside block scope with colliding variable
if (node instanceof AST_BlockScope
&& !(node instanceof AST_Scope)
&& !(node.variables && node.variables.all(function(def) {
return !lvalues.has(def.name);
}))) {
var replace = can_replace;
can_replace = false;
if (!handle_custom_scan_order(node, scanner)) descend(node, scanner);
can_replace = replace;
return signal_abort(node);
}
return handle_custom_scan_order(node, scanner);
}, signal_abort);
var multi_replacer = new TreeTransformer(function(node) {
@@ -1937,13 +1976,6 @@ merge(Compressor.prototype, {
}
// Skip (non-executed) functions
if (node instanceof AST_Scope) return node;
// Stop upon collision with block-scoped variables
if (!(node.variables && node.variables.all(function(def) {
return !lvalues.has(def.name);
}))) {
abort = true;
return node;
}
// Scan object only in a for-in/of statement
if (node instanceof AST_ForEnumeration) {
node.object = node.object.transform(tt);
@@ -1979,7 +2011,9 @@ merge(Compressor.prototype, {
function should_stop(node, parent) {
if (node === rvalue) return true;
if (parent instanceof AST_For) return node !== parent.init;
if (parent instanceof AST_For) {
if (node !== parent.init) return true;
}
if (node instanceof AST_Assign) {
return node.operator != "=" && lhs.equivalent_to(node.left);
}
@@ -2014,7 +2048,8 @@ merge(Compressor.prototype, {
}
function in_conditional(node, parent) {
if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
if (parent instanceof AST_Assign) return parent.left !== node && lazy_op[parent.operator.slice(0, -1)];
if (parent instanceof AST_Binary) return parent.left !== node && lazy_op[parent.operator];
if (parent instanceof AST_Case) return parent.expression !== node;
if (parent instanceof AST_Conditional) return parent.condition !== node;
return parent instanceof AST_If && parent.condition !== node;
@@ -2356,21 +2391,36 @@ merge(Compressor.prototype, {
return null;
}
function find_stop_logical(parent, op, level) {
var node;
do {
node = parent;
parent = scanner.parent(++level);
} while (parent instanceof AST_Assign && parent.operator.slice(0, -1) == op
|| parent instanceof AST_Binary && parent.operator == op);
return node;
}
function find_stop_value(node, level) {
var parent = scanner.parent(level);
if (parent instanceof AST_Array) return find_stop_value(parent, level + 1);
if (parent instanceof AST_Assign) return may_throw(parent) || parent.left.match_symbol(function(ref) {
return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
}) ? node : find_stop_value(parent, level + 1);
if (parent instanceof AST_Binary) {
if (lazy_op[parent.operator] && parent.left !== node) {
do {
node = parent;
parent = scanner.parent(++level);
} while (parent instanceof AST_Binary && parent.operator == node.operator);
return node;
if (parent instanceof AST_Assign) {
if (may_throw(parent)) return node;
if (parent.left.match_symbol(function(ref) {
return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
})) return node;
var op;
if (parent.left === node || !lazy_op[op = parent.operator.slice(0, -1)]) {
return find_stop_value(parent, level + 1);
}
return find_stop_value(parent, level + 1);
return find_stop_logical(parent, op, level);
}
if (parent instanceof AST_Binary) {
var op;
if (parent.left === node || !lazy_op[op = parent.operator]) {
return find_stop_value(parent, level + 1);
}
return find_stop_logical(parent, op, level);
}
if (parent instanceof AST_Call) return parent;
if (parent instanceof AST_Case) {
@@ -3659,20 +3709,25 @@ merge(Compressor.prototype, {
(function(def) {
def(AST_Node, return_false);
def(AST_Array, return_true);
def(AST_Assign, function(compressor) {
return this.operator != "=" || this.right.is_defined(compressor);
});
def(AST_Binary, function(compressor) {
switch (this.operator) {
function is_binary_defined(compressor, op, node) {
switch (op) {
case "&&":
return this.left.is_defined(compressor) && this.right.is_defined(compressor);
return node.left.is_defined(compressor) && node.right.is_defined(compressor);
case "||":
return this.left.is_truthy() || this.right.is_defined(compressor);
return node.left.is_truthy() || node.right.is_defined(compressor);
case "??":
return this.left.is_defined(compressor) || this.right.is_defined(compressor);
return node.left.is_defined(compressor) || node.right.is_defined(compressor);
default:
return true;
}
}
def(AST_Assign, function(compressor) {
var op = this.operator;
if (op == "=") return this.right.is_defined(compressor);
return is_binary_defined(compressor, op.slice(0, -1), this);
});
def(AST_Binary, function(compressor) {
return is_binary_defined(compressor, this.operator, this);
});
def(AST_Conditional, function(compressor) {
return this.consequent.is_defined(compressor) && this.alternative.is_defined(compressor);
@@ -5285,8 +5340,9 @@ merge(Compressor.prototype, {
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Assign) {
var lhs = node.left;
var rhs = node.right;
if (lhs instanceof AST_Destructured) {
node.right.walk(tw);
rhs.walk(tw);
var marker = new TreeWalker(function(node) {
if (node instanceof AST_Destructured) return;
if (node instanceof AST_DefaultValue) {
@@ -5314,9 +5370,17 @@ merge(Compressor.prototype, {
lhs.walk(marker);
return true;
}
if (lazy_op[node.operator.slice(0, -1)]) {
lhs.walk(tw);
push();
rhs.walk(tw);
if (lhs instanceof AST_SymbolRef) mark(lhs);
pop();
return true;
}
if (lhs instanceof AST_SymbolRef) {
if (node.operator != "=") mark(lhs, true);
node.right.walk(tw);
rhs.walk(tw);
mark(lhs);
return true;
}
@@ -6191,6 +6255,7 @@ merge(Compressor.prototype, {
&& var_defs[sym.id] == 1
&& sym.assignments == 0
&& value instanceof AST_LambdaExpression
&& !is_arguments(sym)
&& !is_arrow(value)
&& assigned_once(value, sym.references)
&& can_declare_defun(value)
@@ -7211,9 +7276,14 @@ merge(Compressor.prototype, {
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
}
if (left.has_side_effects(compressor)) return this;
this.write_only = true;
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
return this.right.drop_side_effect_free(compressor);
var right = this.right;
if (lazy_op[this.operator.slice(0, -1)]) {
this.write_only = !right.has_side_effects(compressor);
} else {
this.write_only = true;
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
return right.drop_side_effect_free(compressor);
}
}
return this;
});
@@ -7340,10 +7410,18 @@ merge(Compressor.prototype, {
});
def(AST_Class, function(compressor, first_in_statement) {
var exprs = [], values = [];
this.properties.forEach(function(prop) {
var props = this.properties;
for (var i = 0; i < props.length; i++) {
var prop = props[i];
if (prop.key instanceof AST_Node) exprs.push(prop.key);
if (prop instanceof AST_ClassField && prop.static && prop.value) values.push(prop.value);
});
if (prop instanceof AST_ClassField
&& prop.static
&& prop.value
&& !(prop.value instanceof AST_Lambda)) {
if (prop.value.contains_this()) return this;
values.push(prop.value);
}
}
var base = this.extends;
if (base) {
if (base instanceof AST_SymbolRef) base = base.fixed_value();
@@ -8752,7 +8830,7 @@ merge(Compressor.prototype, {
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
if (can_inline && stat instanceof AST_Return) {
var value = stat.value;
if (exp === fn && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) {
if (exp === fn && !fn.name && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) {
return make_sequence(self, convert_args(value)).optimize(compressor);
}
}
@@ -11352,7 +11430,7 @@ merge(Compressor.prototype, {
AST_Arrow.DEFMETHOD("contains_this", return_false);
AST_AsyncArrow.DEFMETHOD("contains_this", return_false);
AST_Scope.DEFMETHOD("contains_this", function() {
AST_Node.DEFMETHOD("contains_this", function() {
var result;
var self = this;
self.walk(new TreeWalker(function(node) {

View File

@@ -104,12 +104,15 @@ var OPERATORS = makePredicate([
">>=",
"<<=",
">>>=",
"&=",
"|=",
"^=",
"&=",
"&&",
"||",
"??",
"&&=",
"||=",
"??=",
]);
var NEWLINE_CHARS = "\n\r\u2028\u2029";
@@ -653,7 +656,7 @@ var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
var UNARY_POSTFIX = makePredicate("-- ++");
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= |= ^= &=");
var ASSIGNMENT = makePredicate("= += -= /= *= %= **= >>= <<= >>>= &= |= ^= &&= ||= ??=");
var PRECEDENCE = function(a, ret) {
for (var i = 0; i < a.length;) {

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.13.2",
"version": "3.13.3",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -475,3 +475,200 @@ issue_4521: {
}
expect_stdout: "42"
}
logical_assignments: {
input: {
var a = 42, b = null, c;
a &&= "foo";
b ||= "bar";
c ??= "baz";
console.log(a, b, c);
}
expect_exact: 'var a=42,b=null,c;a&&="foo";b||="bar";c??="baz";console.log(a,b,c);'
expect_stdout: "foo bar baz"
node_version: ">=15"
}
logical_collapse_vars: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL", b = false;
a = "PASS";
b ??= a;
console.log(a);
}
expect: {
var a = "FAIL", b = false;
a = "PASS";
b ??= a;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=15"
}
logical_reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS", b = 42;
b ??= a = "FAIL";
console.log(a);
}
expect: {
var a = "PASS", b = 42;
b ??= a = "FAIL";
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=15"
}
logical_side_effects: {
options = {
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS", b = 42;
b ??= a = "FAIL";
console.log(a);
}
expect: {
var a = "PASS", b = 42;
b ??= a = "FAIL";
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4815_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
42..p &&= a = "FAIL";
console.log(a);
}
expect: {
var a = "PASS";
42..p &&= a = "FAIL";
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4815_2: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
var a = "PASS";
42..p &&= a = "FAIL";
console.log(a);
}
expect: {
var a = "PASS";
42..p &&= a = "FAIL";
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4819: {
options = {
comparisons: true,
}
input: {
console.log(void 0 === ([].p &&= 42));
}
expect: {
console.log(void 0 === ([].p &&= 42));
}
expect_stdout: "true"
node_version: ">=15"
}
issue_4827_1: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
A = "FAIL";
var a = A, b = "PASS", c;
c &&= b = a, console.log(b);
}
expect: {
A = "FAIL";
var a = A, b = "PASS", c;
c &&= b = a, console.log(b);
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4827_2: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 0, b = "PASS";
function f(c) {
a++,
c &&= b = a;
}
f();
console.log(b);
}
expect: {
var a = 0, b = "PASS";
a++,
c &&= b = a;
var c;
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4827_3: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
var a = 0, b, c;
a++;
c &&= b = a;
console.log(b);
}
expect: {
var a = 0, b, c;
a++;
c &&= b = a;
console.log(b);
}
expect_stdout: "undefined"
node_version: ">=15"
}

View File

@@ -1296,3 +1296,51 @@ issue_4756: {
]
node_version: ">=12"
}
issue_4821_1: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
class A {
static p = void (a = this);
}
console.log(typeof a);
}
expect: {
var a;
class A {
static p = void (a = this);
}
console.log(typeof a);
}
expect_stdout: "function"
node_version: ">=12"
}
issue_4821_2: {
options = {
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
class A {
static p = void (a = this);
}
console.log(typeof a);
}
expect: {
var a;
(class {
static p = void (a = this);
});
console.log(typeof a);
}
expect_stdout: "function"
node_version: ">=12"
}

View File

@@ -2868,7 +2868,7 @@ lvalues_def: {
expect_stdout: true
}
compound_assignment: {
compound_assignment_1: {
options = {
collapse_vars: true,
}
@@ -2887,6 +2887,23 @@ compound_assignment: {
expect_stdout: "4"
}
compound_assignment_2: {
options = {
collapse_vars: true,
}
input: {
var a;
a = 1;
for (a += a + 2; console.log(a););
}
expect: {
var a;
a = 1;
for (a += a + 2; console.log(a););
}
expect_stdout: "4"
}
issue_2187_1: {
options = {
collapse_vars: true,

View File

@@ -1661,3 +1661,23 @@ issue_4588_2_evaluate: {
expect_stdout: "1"
node_version: ">=6"
}
issue_4817: {
options = {
ie8: true,
inline: true,
unused: true,
}
input: {
(function f(a = console.log(typeof f)) {
return 42;
})();
}
expect: {
(function f(a = console.log(typeof f)) {
return 42;
})();
}
expect_stdout: "function"
node_version: ">=6"
}

View File

@@ -5991,3 +5991,33 @@ issue_4788: {
}
expect_stdout: "PASS"
}
issue_4823: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(typeof function() {
{
function f() {}
var arguments = f();
function g() {}
var arguments = g;
}
return f && arguments;
}());
}
expect: {
console.log(typeof function() {
{
function f() {}
arguments = f();
var arguments = function() {};
}
return f && arguments;
}());
}
expect_stdout: "function"
}

View File

@@ -172,3 +172,32 @@ issue_4054: {
}
expect_stdout: "{ p: [Setter] }"
}
issue_4811_1: {
input: {
for (var PASS in this);
console.log(PASS, this, {} < this);
}
expect: {
for (var PASS in this);
console.log(PASS, this, {} < this);
}
expect_stdout: "PASS [object global] true"
}
issue_4811_2: {
options = {
side_effects: true,
}
input: {
(async function() {});
for (var PASS in this);
console.log(PASS, this, {} < this);
}
expect: {
for (var PASS in this);
console.log(PASS, this, {} < this);
}
expect_stdout: "PASS [object global] true"
node_version: ">=8"
}

View File

@@ -361,4 +361,22 @@ describe("test/reduce.js", function() {
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/destructured_catch.reduced.js"));
});
it("Should not enumerate `toString` over global context", function() {
if (semver.satisfies(process.version, "<8")) return;
var code = [
"(async function() {});",
"for (var k in this);",
"console.log(k, 42 + this);",
].join("\n");
var result = reduce_test(code, {
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "mangle": false',
"// }",
].join("\n"));
});
});

View File

@@ -1,3 +1,24 @@
echo "::group::GitHub Environment Variables"
echo "CI: $CI"
echo "GITHUB_WORKFLOW: $GITHUB_WORKFLOW"
echo "GITHUB_RUN_ID: $GITHUB_RUN_ID"
echo "GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER"
echo "GITHUB_ACTION: $GITHUB_ACTION"
echo "GITHUB_ACTIONS: $GITHUB_ACTIONS"
echo "GITHUB_ACTOR: $GITHUB_ACTOR"
echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
echo "GITHUB_EVENT_NAME: $GITHUB_EVENT_NAME"
echo "GITHUB_EVENT_PATH: $GITHUB_EVENT_PATH"
echo "GITHUB_WORKSPACE: $GITHUB_WORKSPACE"
echo "GITHUB_SHA: $GITHUB_SHA"
echo "GITHUB_REF: $GITHUB_REF"
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
echo "GITHUB_SERVER_URL: $GITHUB_SERVER_URL"
echo "GITHUB_API_URL: $GITHUB_API_URL"
echo "GITHUB_GRAPHQL_URL: $GITHUB_GRAPHQL_URL"
echo "::endgroup::"
if command -v timeout &> /dev/null; then NATIVE=1; fi
timeout() {
T=$1

View File

@@ -200,9 +200,13 @@ function setup(global, builtins, setup_log, setup_tty) {
});
Object.defineProperties(global, props);
// for Node.js v8+
global.toString = function() {
return "[object global]";
};
if (global.toString !== Object.prototype.toString) {
global.__proto__ = Object.defineProperty(Object.create(global.__proto__), "toString", {
value: function() {
return "[object global]";
},
});
}
function self() {
return this;

View File

@@ -149,6 +149,7 @@ var SUPPORT = function(matrix) {
for_of: "for (var a of []);",
generator: "function* f(){}",
let: "let a;",
logical_assignment: "[].p ??= 0;",
new_target: "function f() { new.target; }",
nullish: "0 ?? 0",
rest: "var [...a] = [];",
@@ -262,10 +263,13 @@ ASSIGNMENTS = ASSIGNMENTS.concat([
">>=",
">>>=",
]);
if (SUPPORT.exponentiation) {
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
ASSIGNMENTS.push("**=");
}
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
if (SUPPORT.exponentiation) ASSIGNMENTS.push("**=");
if (SUPPORT.logical_assignment) ASSIGNMENTS = ASSIGNMENTS.concat([
"&&=",
"||=",
"??=",
]);
var UNARY_SAFE = [
"+",
@@ -2202,8 +2206,7 @@ function log(options) {
function sort_globals(code) {
var globals = run_code("throw Object.keys(this).sort(" + function(global) {
return function(m, n) {
return (n == "toString") - (m == "toString")
|| (typeof global[n] == "function") - (typeof global[m] == "function")
return (typeof global[n] == "function") - (typeof global[m] == "function")
|| (m < n ? -1 : m > n ? 1 : 0);
};
} + "(this));" + code);