Skip to content

Commit

Permalink
Correctly parse async oneParam => ....
Browse files Browse the repository at this point in the history
It appears the spec has changed to allow async arrow functions without parentheses
around a single parameter.

Closes #2244

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=146429894
  • Loading branch information
brad4d authored and blickly committed Feb 4, 2017
1 parent 67ec1c3 commit bdfdaed
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 25 deletions.
49 changes: 29 additions & 20 deletions src/com/google/javascript/jscomp/parsing/parser/Parser.java
Expand Up @@ -2817,6 +2817,10 @@ private ParseTree parseAssignment(Expression expressionIn) {
return parseYield(expressionIn);
}

if (peekAsyncArrowFunction()) {
return parseAsyncArrowFunction(expressionIn);
}

SourcePosition start = getTreeStartLocation();
// TODO(blickly): Allow TypeScript syntax in arrow function parameters
ParseTree left = parseConditional(expressionIn);
Expand All @@ -2839,12 +2843,20 @@ private ParseTree parseAssignment(Expression expressionIn) {
return left;
}

private boolean peekAsyncArrowFunction() {
if (!peekPredefinedString(ASYNC)) {
return false;
} else if (peekImplicitSemiColon(1)) {
// No newline allowed between `async` and argument list.
return false;
} else {
return peek(1, TokenType.OPEN_PAREN) || peek(1, TokenType.IDENTIFIER);
}
}

private ParseTree completeAssignmentExpressionParseAtArrow(
ParseTree leftOfArrow, Expression expressionIn) {
if (leftOfArrow.type == ParseTreeType.CALL_EXPRESSION) {
// Could be:
// ... async (args) => ...
// or
// ... someAssignmentExpression // implicit semicolon
// (args) =>
return completeAssignmentExpressionParseAtArrow(leftOfArrow.asCallExpression(), expressionIn);
Expand Down Expand Up @@ -2909,10 +2921,6 @@ private ParseTree completeAssignmentExpressionParseAtArrow(
// () => { doSomething; };
resetScannerAfter(operand);
result = operand;
} else if (isAsyncId(operand)) {
// e.g. async () => { doSomething; };
resetScanner(operand);
result = parseAsyncArrowFunction(expressionIn);
} else {
reportError("'=>' unexpected");
result = callExpression;
Expand All @@ -2924,8 +2932,20 @@ private ParseTree parseAsyncArrowFunction(Expression expressionIn) {
SourcePosition start = getTreeStartLocation();
features = features.require(Feature.ARROW_FUNCTIONS).require(Feature.ASYNC_FUNCTIONS);
eatPredefinedString(ASYNC);
FormalParameterListTree arrowParameterList =
parseFormalParameterList(ParamContext.IMPLEMENTATION);
if (peekImplicitSemiColon()) {
reportError("No newline allowed between `async` and arrow function parameter list");
}
FormalParameterListTree arrowParameterList = null;
if (peek(TokenType.OPEN_PAREN)) {
// async (...) =>
arrowParameterList = parseFormalParameterList(ParamContext.IMPLEMENTATION);
} else {
// async arg =>
final IdentifierExpressionTree singleParameter = parseIdentifierExpression();
arrowParameterList =
new FormalParameterListTree(
singleParameter.location, ImmutableList.<ParseTree>of(singleParameter));
}
if (peekImplicitSemiColon()) {
reportError("No newline allowed before '=>'");
}
Expand Down Expand Up @@ -2956,17 +2976,6 @@ private FormalParameterListTree newEmptyFormalParameterList(SourceRange location
return new FormalParameterListTree(location, ImmutableList.<ParseTree>of());
}

/**
* Does {@code parseTree} represent the 'async' keyword?
*/
private boolean isAsyncId(ParseTree parseTree) {
if (parseTree.type == ParseTreeType.IDENTIFIER_EXPRESSION) {
return parseTree.asIdentifierExpression().identifierToken.value.equals(ASYNC);
} else {
return false;
}
}

/**
* Transforms a LeftHandSideExpression into a LeftHandSidePattern if possible.
* This returns the transformed tree if it parses as a LeftHandSidePattern,
Expand Down
10 changes: 5 additions & 5 deletions test/com/google/javascript/jscomp/parsing/ParserTest.java
Expand Up @@ -2977,7 +2977,11 @@ public void testInvalidAsyncFunction() {
}

public void testAsyncArrowFunction() {
String arrowFunctionSource = "f = async (x) => x + 1";
doAsyncArrowFunctionTest("f = async (x) => x + 1");
doAsyncArrowFunctionTest("f = async x => x + 1");
}

private void doAsyncArrowFunctionTest(String arrowFunctionSource) {
expectFeatures(Feature.ASYNC_FUNCTIONS, Feature.ARROW_FUNCTIONS);

for (LanguageMode m : LanguageMode.values()) {
Expand All @@ -3002,10 +3006,6 @@ public void testAsyncArrowInvalid() {
mode = LanguageMode.ECMASCRIPT8;
strictMode = STRICT;
parseError("f = not_async (x) => x + 1;", "'=>' unexpected");

expectFeatures(Feature.ARROW_FUNCTIONS);
// async requires parens
parseError("f = async x => x + 1;", SEMICOLON_EXPECTED);
}

public void testAsyncMethod() {
Expand Down

0 comments on commit bdfdaed

Please sign in to comment.