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
22
lib/parse.js
22
lib/parse.js
@@ -795,14 +795,14 @@ function parse($TEXT, options) {
|
|||||||
function unexpected(token) {
|
function unexpected(token) {
|
||||||
if (token == null)
|
if (token == null)
|
||||||
token = S.token;
|
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) {
|
function expect_token(type, val) {
|
||||||
if (is(type, val)) {
|
if (is(type, val)) {
|
||||||
return next();
|
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); };
|
function expect(punc) { return expect_token("punc", punc); };
|
||||||
@@ -993,7 +993,7 @@ function parse($TEXT, options) {
|
|||||||
var label = as_symbol(AST_Label);
|
var label = as_symbol(AST_Label);
|
||||||
if (label.name === "yield" && is_in_generator()) {
|
if (label.name === "yield" && is_in_generator()) {
|
||||||
// Ecma-262, 12.1.1 Static Semantics: Early Errors
|
// 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)) {
|
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
|
||||||
// ECMA-262, 12.12: An ECMAScript program is considered
|
// ECMA-262, 12.12: An ECMAScript program is considered
|
||||||
@@ -1873,9 +1873,12 @@ function parse($TEXT, options) {
|
|||||||
expect("]");
|
expect("]");
|
||||||
return ex;
|
return ex;
|
||||||
} else unexpected();
|
} else unexpected();
|
||||||
case "num":
|
|
||||||
case "string":
|
|
||||||
case "name":
|
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 "operator":
|
||||||
case "keyword":
|
case "keyword":
|
||||||
case "atom":
|
case "atom":
|
||||||
@@ -1915,6 +1918,9 @@ function parse($TEXT, options) {
|
|||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
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);
|
var sym = _make_symbol(type);
|
||||||
next();
|
next();
|
||||||
return sym;
|
return sym;
|
||||||
@@ -2050,9 +2056,13 @@ function parse($TEXT, options) {
|
|||||||
var maybe_assign = function(no_in) {
|
var maybe_assign = function(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
|
|
||||||
if (start.type == "name" && start.value == "yield" && is_in_generator()) {
|
if (start.type == "name" && start.value == "yield") {
|
||||||
|
if (is_in_generator()) {
|
||||||
next();
|
next();
|
||||||
return _yield_expression();
|
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 == ")") {
|
if (start.type == "punc" && start.value == "(" && peek().value == ")") {
|
||||||
|
|||||||
@@ -450,109 +450,3 @@ regression_cannot_use_of: {
|
|||||||
foo(); /* Label statement missing? No prob. */
|
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,7 +15,7 @@ describe("Arrow functions", function() {
|
|||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
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++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe("Class", function() {
|
|||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
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++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe("Function", function() {
|
|||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
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++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ describe("Yield", function() {
|
|||||||
}
|
}
|
||||||
var expect = function(e) {
|
var expect = function(e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
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);
|
assert.throws(test, expect);
|
||||||
});
|
});
|
||||||
@@ -27,7 +27,7 @@ describe("Yield", function() {
|
|||||||
}
|
}
|
||||||
var expect = function(e) {
|
var expect = function(e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "Unexpected token: punc (;)";
|
e.message === "SyntaxError: Unexpected token: punc (;)";
|
||||||
}
|
}
|
||||||
assert.throws(test, expect);
|
assert.throws(test, expect);
|
||||||
});
|
});
|
||||||
@@ -39,7 +39,7 @@ describe("Yield", function() {
|
|||||||
}
|
}
|
||||||
var expect = function(e) {
|
var expect = function(e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "Unexpected token: operator (*)";
|
e.message === "SyntaxError: Unexpected token: operator (*)";
|
||||||
}
|
}
|
||||||
assert.throws(test, expect);
|
assert.throws(test, expect);
|
||||||
});
|
});
|
||||||
@@ -64,4 +64,43 @@ describe("Yield", function() {
|
|||||||
"function*f(){yield,yield,yield*void 0,yield}"
|
"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