Restrict yield outside generators in strict mode
* Move some yield/generic tests from compress/harmony.js to compress/yield.js * Adjust error messages to conform ecmascript standards
This commit is contained in:
committed by
Richard van Velzen
parent
6b03b800b3
commit
ca04508cd1
26
lib/parse.js
26
lib/parse.js
@@ -795,14 +795,14 @@ function parse($TEXT, options) {
|
||||
function unexpected(token) {
|
||||
if (token == null)
|
||||
token = S.token;
|
||||
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
|
||||
token_error(token, "SyntaxError: Unexpected token: " + token.type + " (" + token.value + ")");
|
||||
};
|
||||
|
||||
function expect_token(type, val) {
|
||||
if (is(type, val)) {
|
||||
return next();
|
||||
}
|
||||
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||
token_error(S.token, "SyntaxError: Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||
};
|
||||
|
||||
function expect(punc) { return expect_token("punc", punc); };
|
||||
@@ -993,7 +993,7 @@ function parse($TEXT, options) {
|
||||
var label = as_symbol(AST_Label);
|
||||
if (label.name === "yield" && is_in_generator()) {
|
||||
// Ecma-262, 12.1.1 Static Semantics: Early Errors
|
||||
croak("Yield cannot be used as label inside generators");
|
||||
token_error(S.prev, "SyntaxError: Yield cannot be used as label inside generators");
|
||||
}
|
||||
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
|
||||
// ECMA-262, 12.12: An ECMAScript program is considered
|
||||
@@ -1873,9 +1873,12 @@ function parse($TEXT, options) {
|
||||
expect("]");
|
||||
return ex;
|
||||
} else unexpected();
|
||||
case "num":
|
||||
case "string":
|
||||
case "name":
|
||||
if (tmp.value === "yield" && S.input.has_directive("use strict") && !is_in_generator()) {
|
||||
token_error(tmp, "SyntaxError: Unexpected yield identifier inside strict mode");
|
||||
}
|
||||
case "string":
|
||||
case "num":
|
||||
case "operator":
|
||||
case "keyword":
|
||||
case "atom":
|
||||
@@ -1915,6 +1918,9 @@ function parse($TEXT, options) {
|
||||
if (!noerror) croak("Name expected");
|
||||
return null;
|
||||
}
|
||||
if (is("name", "yield") && S.input.has_directive("use strict")) {
|
||||
token_error(S.prev, "SyntaxError: Unexpected yield identifier inside strict mode");
|
||||
}
|
||||
var sym = _make_symbol(type);
|
||||
next();
|
||||
return sym;
|
||||
@@ -2050,9 +2056,13 @@ function parse($TEXT, options) {
|
||||
var maybe_assign = function(no_in) {
|
||||
var start = S.token;
|
||||
|
||||
if (start.type == "name" && start.value == "yield" && is_in_generator()) {
|
||||
next();
|
||||
return _yield_expression();
|
||||
if (start.type == "name" && start.value == "yield") {
|
||||
if (is_in_generator()) {
|
||||
next();
|
||||
return _yield_expression();
|
||||
} else if (S.input.has_directive("use strict")) {
|
||||
token_error(S.token, "SyntaxError: Unexpected yield identifier inside strict mode")
|
||||
}
|
||||
}
|
||||
|
||||
if (start.type == "punc" && start.value == "(" && peek().value == ")") {
|
||||
|
||||
@@ -449,110 +449,4 @@ regression_cannot_use_of: {
|
||||
x.of;
|
||||
foo(); /* Label statement missing? No prob. */
|
||||
}
|
||||
}
|
||||
|
||||
generators: {
|
||||
input: {
|
||||
function* fn() {};
|
||||
}
|
||||
expect_exact: "function*fn(){}"
|
||||
}
|
||||
|
||||
generators_yield: {
|
||||
input: {
|
||||
function* fn() {
|
||||
yield remote();
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){yield remote()}"
|
||||
}
|
||||
|
||||
generators_yield_assign: {
|
||||
input: {
|
||||
function* fn() {
|
||||
var x = {};
|
||||
x.prop = yield 5;
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){var x={};x.prop=yield 5}"
|
||||
}
|
||||
|
||||
generator_yield_undefined: {
|
||||
input: {
|
||||
function* fn() {
|
||||
yield;
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){yield}"
|
||||
}
|
||||
|
||||
yield_optimize_expression: {
|
||||
options = {
|
||||
}
|
||||
input: {
|
||||
function* f1() { yield; }
|
||||
function* f2() { yield undefined; }
|
||||
function* f3() { yield null; }
|
||||
function* f4() { yield* undefined; }
|
||||
}
|
||||
expect: {
|
||||
function* f1() { yield }
|
||||
function* f2() { yield; }
|
||||
function* f3() { yield null; }
|
||||
function* f4() { yield* void 0; }
|
||||
}
|
||||
}
|
||||
|
||||
yield_statements: {
|
||||
input: {
|
||||
function* fn() {
|
||||
var a = (yield 1) + (yield 2);
|
||||
var b = (yield 3) === (yield 4);
|
||||
var c = (yield 5) << (yield 6);
|
||||
var d = yield 7;
|
||||
var e = (yield 8) ? yield 9 : yield 10;
|
||||
var f = -(yield 11);
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){var a=(yield 1)+(yield 2);var b=(yield 3)===(yield 4);var c=(yield 5)<<(yield 6);var d=yield 7;var e=(yield 8)?yield 9:yield 10;var f=-(yield 11)}"
|
||||
}
|
||||
|
||||
yield_as_identifier_in_function_in_generator: {
|
||||
input: {
|
||||
var g = function*() {
|
||||
function h() {
|
||||
yield = 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
expect: {
|
||||
var g = function*() {
|
||||
function h() {
|
||||
yield = 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
yield_before_punctuators: {
|
||||
input: {
|
||||
iter = (function*() {
|
||||
assignmentResult = [ x = yield ] = value;
|
||||
})();
|
||||
function* g1() { (yield) }
|
||||
function* g2() { [yield] }
|
||||
function* g3() { return {yield} } // Added return to avoid {} drop
|
||||
function* g4() { yield, yield; }
|
||||
function* g5() { (yield) ? yield : yield; }
|
||||
}
|
||||
expect: {
|
||||
iter = (function*() {
|
||||
assignmentResult = [ x = yield ] = value;
|
||||
})();
|
||||
function* g1() { (yield) }
|
||||
function* g2() { [yield] }
|
||||
function* g3() { return {yield} }
|
||||
function* g4() { yield, yield; }
|
||||
function* g5() { (yield) ? yield : yield; }
|
||||
}
|
||||
}
|
||||
142
test/compress/yield.js
Normal file
142
test/compress/yield.js
Normal file
@@ -0,0 +1,142 @@
|
||||
generators: {
|
||||
input: {
|
||||
function* fn() {};
|
||||
}
|
||||
expect_exact: "function*fn(){}"
|
||||
}
|
||||
|
||||
generators_yield: {
|
||||
input: {
|
||||
function* fn() {
|
||||
yield remote();
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){yield remote()}"
|
||||
}
|
||||
|
||||
generators_yield_assign: {
|
||||
input: {
|
||||
function* fn() {
|
||||
var x = {};
|
||||
x.prop = yield 5;
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){var x={};x.prop=yield 5}"
|
||||
}
|
||||
|
||||
generator_yield_undefined: {
|
||||
input: {
|
||||
function* fn() {
|
||||
yield;
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){yield}"
|
||||
}
|
||||
|
||||
yield_optimize_expression: {
|
||||
options = {
|
||||
}
|
||||
input: {
|
||||
function* f1() { yield; }
|
||||
function* f2() { yield undefined; }
|
||||
function* f3() { yield null; }
|
||||
function* f4() { yield* undefined; }
|
||||
}
|
||||
expect: {
|
||||
function* f1() { yield }
|
||||
function* f2() { yield; }
|
||||
function* f3() { yield null; }
|
||||
function* f4() { yield* void 0; }
|
||||
}
|
||||
}
|
||||
|
||||
yield_statements: {
|
||||
input: {
|
||||
function* fn() {
|
||||
var a = (yield 1) + (yield 2);
|
||||
var b = (yield 3) === (yield 4);
|
||||
var c = (yield 5) << (yield 6);
|
||||
var d = yield 7;
|
||||
var e = (yield 8) ? yield 9 : yield 10;
|
||||
var f = -(yield 11);
|
||||
}
|
||||
}
|
||||
expect_exact: "function*fn(){var a=(yield 1)+(yield 2);var b=(yield 3)===(yield 4);var c=(yield 5)<<(yield 6);var d=yield 7;var e=(yield 8)?yield 9:yield 10;var f=-(yield 11)}"
|
||||
}
|
||||
|
||||
yield_as_identifier_in_function_in_generator: {
|
||||
input: {
|
||||
var g = function*() {
|
||||
function h() {
|
||||
yield = 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
expect: {
|
||||
var g = function*() {
|
||||
function h() {
|
||||
yield = 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
yield_before_punctuators: {
|
||||
input: {
|
||||
iter = (function*() {
|
||||
assignmentResult = [ x = yield ] = value;
|
||||
})();
|
||||
function* g1() { (yield) }
|
||||
function* g2() { [yield] }
|
||||
function* g3() { return {yield} } // Added return to avoid {} drop
|
||||
function* g4() { yield, yield; }
|
||||
function* g5() { (yield) ? yield : yield; }
|
||||
}
|
||||
expect: {
|
||||
iter = (function*() {
|
||||
assignmentResult = [ x = yield ] = value;
|
||||
})();
|
||||
function* g1() { (yield) }
|
||||
function* g2() { [yield] }
|
||||
function* g3() { return {yield} }
|
||||
function* g4() { yield, yield; }
|
||||
function* g5() { (yield) ? yield : yield; }
|
||||
}
|
||||
}
|
||||
|
||||
yield_as_identifier_outside_strict_mode: {
|
||||
input: {
|
||||
import yield from "bar";
|
||||
yield = 123;
|
||||
while (true) {
|
||||
yield:
|
||||
for(;;) break yield;
|
||||
|
||||
foo();
|
||||
}
|
||||
while (true)
|
||||
yield: for(;;) continue yield;
|
||||
function yield(){}
|
||||
function foo(...yield){}
|
||||
try { new Error("") } catch (yield) {}
|
||||
var yield = "foo";
|
||||
class yield {}
|
||||
}
|
||||
expect: {
|
||||
import yield from "bar";
|
||||
yield = 123;
|
||||
while (true) {
|
||||
yield:
|
||||
for(;;) break yield;
|
||||
|
||||
foo();
|
||||
}
|
||||
while (true)
|
||||
yield: for(;;) continue yield;
|
||||
function yield(){}
|
||||
function foo(...yield){}
|
||||
try { new Error("") } catch (yield) {}
|
||||
var yield = "foo";
|
||||
class yield {}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@ describe("Arrow functions", function() {
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: expand (...)";
|
||||
e.message === "SyntaxError: Unexpected token: expand (...)";
|
||||
}
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,11 +16,11 @@ describe("Class", function() {
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: expand (...)";
|
||||
e.message === "SyntaxError: Unexpected token: expand (...)";
|
||||
}
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,11 +20,11 @@ describe("Function", function() {
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: expand (...)";
|
||||
e.message === "SyntaxError: Unexpected token: expand (...)";
|
||||
}
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ describe("Yield", function() {
|
||||
}
|
||||
var expect = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||
e.message === "Yield cannot be used as label inside generators";
|
||||
e.message === "SyntaxError: Yield cannot be used as label inside generators";
|
||||
}
|
||||
assert.throws(test, expect);
|
||||
});
|
||||
@@ -27,7 +27,7 @@ describe("Yield", function() {
|
||||
}
|
||||
var expect = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: punc (;)";
|
||||
e.message === "SyntaxError: Unexpected token: punc (;)";
|
||||
}
|
||||
assert.throws(test, expect);
|
||||
});
|
||||
@@ -39,7 +39,7 @@ describe("Yield", function() {
|
||||
}
|
||||
var expect = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: operator (*)";
|
||||
e.message === "SyntaxError: Unexpected token: operator (*)";
|
||||
}
|
||||
assert.throws(test, expect);
|
||||
});
|
||||
@@ -64,4 +64,43 @@ describe("Yield", function() {
|
||||
"function*f(){yield,yield,yield*void 0,yield}"
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not allow yield to be used as symbol, identifier or property outside generators in strict mode", function() {
|
||||
var tests = [
|
||||
// Fail as as_symbol
|
||||
'"use strict"; import yield from "bar";',
|
||||
'"use strict"; yield = 123;',
|
||||
'"use strict"; yield: "123";',
|
||||
'"use strict"; for(;;){break yield;}',
|
||||
'"use strict"; for(;;){continue yield;}',
|
||||
'"use strict"; function yield(){}',
|
||||
'"use strict"; function foo(...yield){}',
|
||||
'"use strict"; try { new Error("")} catch (yield) {}',
|
||||
'"use strict"; var yield = "foo";',
|
||||
'"use strict"; class yield {}',
|
||||
|
||||
// Fail as maybe_assign
|
||||
'"use strict"; var foo = yield;',
|
||||
'"use strict"; var foo = bar = yield',
|
||||
|
||||
// Fail as as_property_name
|
||||
'"use strict"; var foo = {yield};',
|
||||
'"use strict"; var bar = {yield: "foo"};'
|
||||
];
|
||||
|
||||
var fail = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||
e.message === "SyntaxError: Unexpected yield identifier inside strict mode";
|
||||
}
|
||||
|
||||
var test = function(input) {
|
||||
return function() {
|
||||
UglifyJS.parse(input);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), fail, tests[i]);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user