Fix 8262: allow unparenthesized parameter in async arrow-function (#8444)

* Allow unparenthesize of parameter in async arrow-function

* Add tests and baselines

* Address PR

* Address PR: refactor to use "parseSimpleArrowFunctionExpression"

* Address PR: add comment

* Address PR
This commit is contained in:
Yui
2016-05-04 17:00:28 -07:00
parent e9122a9f34
commit 7521891760
5 changed files with 107 additions and 7 deletions

View File

@@ -2685,7 +2685,8 @@ namespace ts {
// 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
// 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
// 4) ArrowFunctionExpression[?in,?yield]
// 5) [+Yield] YieldExpression[?In]
// 5) AsyncArrowFunctionExpression[in,yield,await]
// 6) [+Yield] YieldExpression[?In]
//
// Note: for ease of implementation we treat productions '2' and '3' as the same thing.
// (i.e. they're both BinaryExpressions with an assignment operator in it).
@@ -2695,11 +2696,18 @@ namespace ts {
return parseYieldExpression();
}
// Then, check if we have an arrow function (production '4') that starts with a parenthesized
// parameter list. If we do, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
// Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
// parameter list or is an async arrow function.
// AsyncArrowFunctionExpression:
// 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
// 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
// Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
// And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
//
// If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
// not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done
// with AssignmentExpression if we see one.
const arrowExpression = tryParseParenthesizedArrowFunctionExpression();
const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression();
if (arrowExpression) {
return arrowExpression;
}
@@ -2791,10 +2799,17 @@ namespace ts {
}
}
function parseSimpleArrowFunctionExpression(identifier: Identifier): Expression {
function parseSimpleArrowFunctionExpression(identifier: Identifier, asyncModifier?: ModifiersArray): ArrowFunction {
Debug.assert(token === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
let node: ArrowFunction;
if (asyncModifier) {
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, asyncModifier.pos);
setModifiers(node, asyncModifier);
}
else {
node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos);
}
const parameter = <ParameterDeclaration>createNode(SyntaxKind.Parameter, identifier.pos);
parameter.name = identifier;
@@ -2805,7 +2820,7 @@ namespace ts {
node.parameters.end = parameter.end;
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false);
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier);
return finishNode(node);
}
@@ -2973,6 +2988,32 @@ namespace ts {
return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
}
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction {
const isUnParenthesizedAsyncArrowFunction = lookAhead(isUnParenthesizedAsyncArrowFunctionWorker);
if (isUnParenthesizedAsyncArrowFunction === Tristate.True) {
const asyncModifier = parseModifiersForArrowFunction();
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
return parseSimpleArrowFunctionExpression(<Identifier>expr, asyncModifier);
}
return undefined;
}
function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {
if (token === SyntaxKind.AsyncKeyword) {
nextToken();
if (scanner.hasPrecedingLineBreak()) {
return Tristate.False;
}
// Check for un-parenthesized AsyncArrowFunction
const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0);
if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token === SyntaxKind.EqualsGreaterThanToken) {
return Tristate.True;
}
}
return Tristate.False;
}
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
setModifiers(node, parseModifiersForArrowFunction());