function shouldNotThrow(func) { let error; try { func(); } catch (e) { error = e; } if (error) throw new Error(`bad error: ${String(error)}`); } function shouldThrow(func, errorMessage) { let errorThrown = false; let error; try { func(); } catch (e) { errorThrown = true; error = e; } if (!errorThrown) throw new Error('not thrown'); if (String(error) !== errorMessage) throw new Error(`bad error: ${String(error)}`); } function checkClassicNoSyntaxError(source) { shouldNotThrow(() => eval(source)); } function checkClassicSyntaxError(source, errorMessage) { shouldThrow(() => eval(source), errorMessage); } function checkStrictSyntaxError(source, errorMessage) { shouldThrow(() => checkModuleSyntax(source), errorMessage); } function checkNoSyntaxErrorCases(source) { checkClassicNoSyntaxError(source); // A nested function within a generator is allowed to use the "yield" name again // within its body because they have FunctionBody[~Yield]. Same with method bodies. checkClassicNoSyntaxError(`function *gen() { function f() { ${source} } }`); checkClassicNoSyntaxError(`function *gen() { async function f() { ${source} } }`); checkClassicNoSyntaxError(`function *gen() { let f = () => { ${source} } }`); checkClassicNoSyntaxError(`function *gen() { let f = async () => { ${source} } }`); checkClassicNoSyntaxError(`function *gen() { var o = { f() { ${source} } } }`); checkClassicNoSyntaxError(`function *gen() { var o = { async f() { ${source} } } }`); checkClassicNoSyntaxError(`function *gen() { var o = { get f() { ${source} } } }`); checkClassicNoSyntaxError(`function *gen() { var o = { set f(x) { ${source} } } }`); } checkNoSyntaxErrorCases(`var yield`); checkNoSyntaxErrorCases(`let yield`); checkNoSyntaxErrorCases(`const yield = 1`); checkNoSyntaxErrorCases(`var {yield} = {}`); checkNoSyntaxErrorCases(`yield: 1`); checkNoSyntaxErrorCases(`function yield(){}`); checkNoSyntaxErrorCases(`function foo(yield){}`); checkNoSyntaxErrorCases(`(class { *yield(){} })`); // GeneratorMethod allows "yield" due to PropertyName[?Yield]. checkNoSyntaxErrorCases(`function *yield(){}`); // GeneratorDeclaration allows "yield" name due to BindingIdentifier[?Yield]. checkNoSyntaxErrorCases(`var o = { yield(yield){ var yield } }`); // PropertyName[?Yield] ( UniqueFormalParameters[~Yield] ) { FunctionBody[~Yield] } checkNoSyntaxErrorCases(`var o = { *yield(){} }`); // GeneratorMethod[?Yield] checkNoSyntaxErrorCases(`var o = { async yield(){} }`); // AsyncMethod[?Yield] checkNoSyntaxErrorCases(`var o = { get x(){ var yield } }`); // get PropertyName[?Yield] () { FunctionBody[~Yield] } checkNoSyntaxErrorCases(`var o = { set x(yield){} }`); // set PropertyName[?Yield] ( PropertySetParameterList) { FunctionBody[~Yield] } checkNoSyntaxErrorCases(`var o = { set x(yield){} }`); // PropertySetParameterList : FormalParameter[~Yield] // Disallowed inside a generator. checkClassicSyntaxError(` function* foo() { yield: 1; } `, `SyntaxError: Cannot use 'yield' as a label in a generator function.`); checkClassicSyntaxError(` function* foo() { var yield; } `, `SyntaxError: Cannot use 'yield' as a variable name in a generator function.`); checkClassicSyntaxError(` function* foo() { let yield; } `, `SyntaxError: Cannot use 'yield' as a lexical variable name in a generator function.`); checkClassicSyntaxError(` function* foo() { var {yield} = {}; } `, `SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'yield'.`); checkClassicSyntaxError(` function* foo(yield){} `, `SyntaxError: Cannot use 'yield' as a parameter name in a generator function.`); // GeneratorExpression BindingIdentifier[+Yield] on the name. checkClassicSyntaxError(` (function* yield() { }) `, `SyntaxError: Cannot declare generator function named 'yield'.`); // GeneratorDeclaration BindingIdentifier[?Yield] on the name. checkClassicSyntaxError(` function* foo() { function* yield(){} } `, `SyntaxError: Cannot use 'yield' as a generator function name in a generator function.`); // class BindingIdentifier[?Yield] on the name. checkClassicSyntaxError(` function* gen() { (class yield {}) } `, `SyntaxError: Unexpected keyword 'yield'. Expected opening '{' at the start of a class body.`); // Disallowed in strict code. checkStrictSyntaxError(` function* foo() { yield: 1; } `, `SyntaxError: Cannot use 'yield' as a label in strict mode.:2`); checkStrictSyntaxError(` var yield; `, `SyntaxError: Cannot use 'yield' as a variable name in strict mode.:2`); checkStrictSyntaxError(` let yield; `, `SyntaxError: Cannot use 'yield' as a lexical variable name in strict mode.:2`); checkStrictSyntaxError(` var {yield} = {}; `, `SyntaxError: Cannot use abbreviated destructuring syntax for keyword 'yield'.:2`); checkStrictSyntaxError(` yield: 1 `, `SyntaxError: Cannot use 'yield' as a label in strict mode.:2`); checkStrictSyntaxError(` import {yield} from 'foo' `, `SyntaxError: Cannot use keyword as imported binding name.:2`); checkStrictSyntaxError(` function* foo(yield){} `, `SyntaxError: Cannot use 'yield' as a parameter name in strict mode.:2`); checkStrictSyntaxError(` function* yield(){} `, `SyntaxError: Cannot use 'yield' as a generator function name in strict mode.:2`); checkStrictSyntaxError(` (function* yield(){}) `, `SyntaxError: Cannot use 'yield' as a generator function name in strict mode.:2`); checkStrictSyntaxError(` function* gen() { (class yield {}) } `, `SyntaxError: Unexpected keyword 'yield'. Expected opening '{' at the start of a class body.:2`); checkClassicSyntaxError(` function *get() { var o = { yield }; } `, `SyntaxError: Cannot use 'yield' as a shorthand property name in a generator function.`); // Edge cases where ~Yield re-enables use of yield in non-strict code. // FunctionDeclaration[Yield]: // function BindingIdentifier[?Yield] ( FormalParameters[~Yield] ) { FunctionBody[~Yield] } checkClassicSyntaxError(`function *gen() { function yield() {} }`, `SyntaxError: Unexpected keyword 'yield'`); checkClassicNoSyntaxError(`function *gen() { function f(yield) {} }`); // FunctionExpression: // function BindingIdentifier[~Yield]opt ( FormalParameters[~Yield] ) { FunctionBody[~Yield] } checkClassicNoSyntaxError(`function *gen() { (function yield() {}) }`); checkClassicNoSyntaxError(`function *gen() { (function f(yield) {}) }`) checkClassicNoSyntaxError(`function *gen() { (function yield(yield) {}) }`) checkClassicNoSyntaxError(`function *gen() { (function(yield) {}) }`); // AsyncFunctionDeclaration[Yield]: // async function BindingIdentifier[?Yield] ( FormalParameters[~Yield]) { AsyncFunctionBody } checkClassicSyntaxError(`function *gen() { async function yield() {} }`, `SyntaxError: Unexpected keyword 'yield'`); checkClassicNoSyntaxError(`function *gen() { async function f(yield) {} }`); // AsyncFunctionExpression: // async function BindingIdentifier[~Yield]opt ( FormalParameters[~Yield] ) { AsyncFunctionBody } checkClassicNoSyntaxError(`function *gen() { (async function yield() {}) }`); checkClassicNoSyntaxError(`function *gen() { (async function f(yield) {}) }`) checkClassicNoSyntaxError(`function *gen() { (async function yield(yield) {}) }`); checkClassicNoSyntaxError(`function *gen() { (async function(yield) {}) }`); // ArrowFunction[Yield]: // ArrowParameters[?Yield] => ConciseBody checkClassicSyntaxError(`function *gen() { let f = (yield) => {} }`, `SyntaxError: Cannot use 'yield' as a parameter name in a generator function.`); // ArrowFunction[Yield]: // ArrowParameters[?Yield] => ConciseBody checkClassicSyntaxError(`function *gen() { let f = (yield) => {} }`, `SyntaxError: Cannot use 'yield' as a parameter name in a generator function.`); // AsyncArrowFunction[Yield]: // async AsyncArrowBindingIdentifier[?Yield] => AsyncConciseBody checkClassicSyntaxError(`function *gen() { let f = async (yield) => {} }`, `SyntaxError: Cannot use 'yield' as a parameter name in a generator function.`);