"yield" parsing inside function name and parameters (#689)

* Use parseFunctionParams to parse method parameters

* [funct] Set this.state.inGenerator before parsing the function name/params

This allows "yield" inside generator parameters to be actually
parsed as a yield expression

* [funct] Disallow yield in function parameters

* [arrow] "yield" can start an arrow function (e.g. "yield => {}")

* [arrow] Disallow YieldExpressions inside arrow parameters.

* [err msg] Disallow yield as fn name in strict mode using checkReservedWord.

So Babylon throws "yield is a reserved word" instead of
a custom "Binding yield in strict mode"

* [err msg] "X is reserved in strict mode" should have precedence over "X is reserved", since it is more specific.

This was observable if "checkKeywords" is true and the word is both a keyword and a reserved
word in strict mode

* Disallow "yield" as an identifier inside generators

* [tests] Add tests, update wrong esprima tests and enable disabled esprima tests

* [tests] Move uncategorized tests to es2015/yield

* [tests] Update test262 whitelist

* Fix regression introduced by 8c77073

* [tests] Update flow whitelist

* Fix flow errors
This commit is contained in:
Daniel Tschinder
2017-11-01 16:04:22 +01:00
committed by Daniel Tschinder
parent 29a4aea27b
commit 1b612148bf
171 changed files with 3067 additions and 163 deletions

View File

@@ -780,6 +780,7 @@ export default class StatementParser extends ExpressionParser {
): T {
const oldInFunc = this.state.inFunction;
const oldInMethod = this.state.inMethod;
const oldInGenerator = this.state.inGenerator;
this.state.inFunction = true;
this.state.inMethod = false;
@@ -802,9 +803,19 @@ export default class StatementParser extends ExpressionParser {
this.unexpected();
}
// When parsing function expression, the binding identifier is parsed
// according to the rules inside the function.
// e.g. (function* yield() {}) is invalid because "yield" is disallowed in
// generators.
// This isn't the case with function declarations: function* yield() {} is
// valid because yield is parsed as if it was outside the generator.
// Therefore, this.state.inGenerator is set before or after parsing the
// function id according to the "isStatement" parameter.
if (!isStatement) this.state.inGenerator = node.generator;
if (this.match(tt.name) || this.match(tt._yield)) {
node.id = this.parseBindingIdentifier();
}
if (isStatement) this.state.inGenerator = node.generator;
this.parseFunctionParams(node);
this.parseFunctionBodyAndFinish(
@@ -812,14 +823,26 @@ export default class StatementParser extends ExpressionParser {
isStatement ? "FunctionDeclaration" : "FunctionExpression",
allowExpressionBody,
);
this.state.inFunction = oldInFunc;
this.state.inMethod = oldInMethod;
this.state.inGenerator = oldInGenerator;
return node;
}
parseFunctionParams(node: N.Function): void {
parseFunctionParams(node: N.Function, allowModifiers?: boolean): void {
const oldInParameters = this.state.inParameters;
this.state.inParameters = true;
this.expect(tt.parenL);
node.params = this.parseBindingList(tt.parenR);
node.params = this.parseBindingList(
tt.parenR,
/* allowEmpty */ false,
allowModifiers,
);
this.state.inParameters = oldInParameters;
}
// Parse a class declaration or literal (depending on the