Skip to content

Commit

Permalink
fix(parser): simplified async arrow parsing
Browse files Browse the repository at this point in the history
Should be a more permanent solution to #22
  • Loading branch information
KFlash committed Jul 31, 2019
1 parent b7cc2f8 commit fb046c7
Showing 1 changed file with 79 additions and 47 deletions.
126 changes: 79 additions & 47 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,6 @@ export function parseStatementListItem(
// LexicalDeclaration[In, Yield] :
// LetOrConst BindingList[?In, ?Yield] ;

parser.assignable = AssignmentKind.Assignable;

switch (parser.token) {
// HoistableDeclaration[?Yield, ~Default]
case Token.FunctionKeyword:
Expand Down Expand Up @@ -1041,27 +1039,16 @@ export function parseAsyncArrowOrAsyncFunctionDeclaration(

// async Identifier => ...
if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.InvalidAsyncParamList);
if (parser.token === Token.AwaitKeyword) report(parser, Errors.AwaitInParameter);
if (context & (Context.Strict | Context.InYieldContext) && parser.token === Token.YieldKeyword) {
report(parser, Errors.YieldInParameter);
}

if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
parser.flags |= Flags.SimpleParameterList;
}

if (scope) {
scope = addChildScope(createScope(), ScopeKind.FunctionBody);
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
}
const param = [parseIdentifier(parser, context, 0)];

// This has to be an async arrow, so let the caller throw on missing arrows etc
expr = parseArrowFunctionExpression(parser, context, scope, param, 1, start, line, column);

/** ArrowFunction[In, Yield, Await]:
* ArrowParameters[?Yield, ?Await][no LineTerminator here]=>ConciseBody[?In]
*/
expr = parseAsyncArrowAfterIdent(parser, context, scope, /* assignable */ 1, start, line, column);
if (parser.token === Token.Comma) expr = parseSequenceExpression(parser, context, 0, start, line, column, expr);

/**
* ExpressionStatement[Yield, Await]:
* [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }]Expression[+In, ?Yield, ?Await]
*/
return parseExpressionStatement(parser, context, expr, start, line, column);
}
}
Expand All @@ -1083,14 +1070,7 @@ export function parseAsyncArrowOrAsyncFunctionDeclaration(
column
);
} else {
if (parser.token === Token.Arrow) {
if (scope) {
scope = addChildScope(createScope(), ScopeKind.FunctionBody);
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
}
expr = parseArrowFunctionExpression(parser, context, scope, [expr], /* isAsync */ 0, start, line, column);
}

expr = parseAsyncArrow(parser, context, expr, /* inNewExpression */ 0, start, line, column);
parser.assignable = AssignmentKind.Assignable;
}

Expand Down Expand Up @@ -7172,6 +7152,7 @@ export function parseMetaProperty(
* @param inNewExpression
* @param assignable
*/

export function parseAsyncExpression(
parser: ParserState,
context: Context,
Expand All @@ -7184,34 +7165,24 @@ export function parseAsyncExpression(
column: number
): ESTree.Expression {
const { flags } = parser;
let scope: ScopeState | undefined = void 0;

if ((flags & Flags.NewLine) < 1) {
// async function ...
if (parser.token === Token.FunctionKeyword)
if (parser.token === Token.FunctionKeyword) {
return parseFunctionExpression(parser, context, /* isAsync */ 1, inGroup, start, line, column);
}

// async Identifier => ...
if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
if (parser.assignable & AssignmentKind.CannotAssign) report(parser, Errors.InvalidAsyncParamList);
if (parser.token === Token.AwaitKeyword) report(parser, Errors.AwaitInParameter);

if (context & Context.OptionsLexical) {
scope = addChildScope(createScope(), ScopeKind.FunctionBody);
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
}

const param = [parseIdentifier(parser, context, 0)];

// This has to be an async arrow, so let the caller throw on missing arrows etc
return parseArrowFunctionExpression(parser, context, scope, param, 1, start, line, column);
return parseAsyncArrowAfterIdent(parser, context, void 0, assignable, start, line, column);
}
}

// async (...) => ...
if (!inNewExpression && parser.token === Token.LeftParen) {
return parseAsyncArrowOrCallExpression(
parser,
(context | Context.DisallowIn) ^ Context.DisallowIn,
context,
expr,
assignable,
BindingKind.ArgumentList,
Expand All @@ -7223,21 +7194,82 @@ export function parseAsyncExpression(
);
}

// async => ...
return parseAsyncArrow(parser, context, expr, inNewExpression, start, line, column);
}

/**
* Parses async arrow
*
* @param parser Parser object
* @param context Context masks
* @param expr AST node
* @param inNewExpression Either true or false
* @param start Start pos of node
* @param line Line pos of node
* @param column Column pos of node
*/
export function parseAsyncArrow(
parser: ParserState,
context: Context,
expr: any,
inNewExpression: 0 | 1,
start: number,
line: number,
column: number
) {
if (parser.token === Token.Arrow) {
if (inNewExpression) report(parser, Errors.InvalidAsyncArrow);

let scope: ScopeState | undefined = void 0;

if (context & Context.OptionsLexical) {
scope = addChildScope(createScope(), ScopeKind.FunctionBody);
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
}

return parseArrowFunctionExpression(parser, context, scope, [expr], 0, start, line, column);
}
return expr;
}

parser.assignable = AssignmentKind.Assignable;
/**
* Parses async arrow after identifier
*
* @param parser Parser object
* @param context Context masks
* @param scope Scope object
* @param assignable Either true or false
* @param start Start pos of node
* @param line Line pos of node
* @param column Column pos of node
*/
function parseAsyncArrowAfterIdent(
parser: ParserState,
context: Context,
scope: ScopeState | undefined,
assignable: 0 | 1,
start: number,
line: number,
column: number
) {
if (!assignable) report(parser, Errors.InvalidAsyncParamList);
if (parser.token === Token.AwaitKeyword) report(parser, Errors.AwaitInParameter);
if (context & (Context.Strict | Context.InYieldContext) && parser.token === Token.YieldKeyword) {
report(parser, Errors.YieldInParameter);
}

return expr;
if ((parser.token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) {
parser.flags |= Flags.SimpleParameterList;
}

if (context & Context.OptionsLexical) {
scope = addChildScope(createScope(), ScopeKind.FunctionBody);
addBlockName(parser, context, scope, parser.tokenValue, BindingKind.ArgumentList, Origin.None);
}
const param = [parseIdentifier(parser, context, 0)];

// This has to be an async arrow, so let the caller throw on missing arrows etc
return parseArrowFunctionExpression(parser, context, scope, param, 1, start, line, column);
}

/**
Expand Down

0 comments on commit fb046c7

Please sign in to comment.