Skip to content

Commit

Permalink
fix(parser): dedupe some code and improved performance
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jul 31, 2019
1 parent fb046c7 commit b972e90
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 84 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "meriyah",
"version": "1.4.10",
"version": "1.5.0",
"description": "A 100% compliant, self-hosted javascript parser with high focus on both performance and stability",
"main": "dist/meriyah.umd.js",
"module": "dist/meriyah.esm.js",
Expand Down
2 changes: 1 addition & 1 deletion src/meriyah.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ export function parse(source: string, options?: Options): ESTree.Program {
export { ESTree, Options };

// Export current version
export const version = '1.4.10';
export const version = '1.5.0';
127 changes: 45 additions & 82 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,17 @@ export function parseAsyncArrowOrAsyncFunctionDeclaration(
column
);
} else {
expr = parseAsyncArrow(parser, context, expr, /* inNewExpression */ 0, start, line, column);
if (parser.token === Token.Arrow) {
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);
}

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

parser.assignable = AssignmentKind.Assignable;
}

Expand Down Expand Up @@ -3854,22 +3864,54 @@ export function parsePrimaryExpressionExtended(
if (context & Context.Strict) report(parser, Errors.StrictInvalidLetInExprPos);
if (kind & (BindingKind.Let | BindingKind.Const)) report(parser, Errors.InvalidLetBoundName);
}

if (context & Context.InClass && parser.token === Token.Arguments) {
report(parser, Errors.InvalidClassFieldArgEval);
}

if ((token & Token.IsIdentifier) === Token.IsIdentifier) {
const tokenValue = parser.tokenValue;
const { tokenValue } = parser;

const expr = parseIdentifier(parser, context | Context.TaggedTemplate, identifierPattern);

if (token === Token.AsyncKeyword) {
return parseAsyncExpression(parser, context, expr, inNewExpression, allowAssign, inGroup, start, line, column);
const { flags } = parser;

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

// async Identifier => ...
if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
return parseAsyncArrowAfterIdent(parser, context, void 0, allowAssign, start, line, column);
}
}

// async (...) => ...
if (!inNewExpression && parser.token === Token.LeftParen) {
return parseAsyncArrowOrCallExpression(
parser,
context,
expr,
allowAssign,
BindingKind.ArgumentList,
Origin.None,
flags,
start,
line,
column
);
}
}

if (token === Token.EscapedReserved) report(parser, Errors.InvalidEscapedKeyword);

const IsEvalOrArguments = (token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments;

if (parser.token === Token.Arrow) {
if (inNewExpression) report(parser, Errors.InvalidAsyncArrow);
parser.flags = (parser.flags | Flags.SimpleParameterList) ^ Flags.SimpleParameterList;
if (IsEvalOrArguments) {
if (context & Context.Strict) report(parser, Errors.StrictEvalArguments);
Expand Down Expand Up @@ -7153,85 +7195,6 @@ export function parseMetaProperty(
* @param assignable
*/

export function parseAsyncExpression(
parser: ParserState,
context: Context,
expr: ESTree.Identifier,
inNewExpression: 0 | 1,
assignable: 0 | 1,
inGroup: 0 | 1,
start: number,
line: number,
column: number
): ESTree.Expression {
const { flags } = parser;

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

// async Identifier => ...
if ((parser.token & Token.IsIdentifier) === Token.IsIdentifier) {
return parseAsyncArrowAfterIdent(parser, context, void 0, assignable, start, line, column);
}
}

// async (...) => ...
if (!inNewExpression && parser.token === Token.LeftParen) {
return parseAsyncArrowOrCallExpression(
parser,
context,
expr,
assignable,
BindingKind.ArgumentList,
Origin.None,
flags,
start,
line,
column
);
}

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;
}

/**
* Parses async arrow after identifier
*
Expand Down

1 comment on commit b972e90

@KFlash
Copy link
Contributor Author

@KFlash KFlash commented on b972e90 Jul 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes are more in line with how V8 does async expression parsing. Also removed a few member access calls to improve async performance.

Please sign in to comment.