Skip to content

Commit

Permalink
fix(parser): WIP: fixed and optimized await edge cases
Browse files Browse the repository at this point in the history
This is WIP! Still need to tweak and optimize it, and do the same with yield.
  • Loading branch information
KFlash committed May 13, 2019
1 parent 2c1bf99 commit 7f006fc
Show file tree
Hide file tree
Showing 15 changed files with 354 additions and 335 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": "0.1.3",
"version": "0.1.4",
"description": "Fast and lightweight, standard-compliant javascript parser written in ECMAScript",
"main": "dist/meriyah.umd.js",
"module": "dist/meriyah.esm.js",
Expand Down
18 changes: 11 additions & 7 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ export const enum BindingOrigin {
export const enum AssignmentKind {
None = 0,
Assignable = 1 << 0,
NotAssignable = 1 << 1
NotAssignable = 1 << 1,
Await = 1 << 2,
Yield = 1 << 3,
}

export const enum DestructuringKind {
Expand All @@ -89,8 +91,8 @@ export const enum DestructuringKind {
Assignable = 1 << 5,
// `__proto__` is a special case and only valid to parse if destructible
SeenProto = 1 << 6,
HasAWait = 1 << 7,
HasYield = 1 << 8
Await = 1 << 7,
Yield = 1 << 8,
}

/**
Expand All @@ -99,11 +101,12 @@ export const enum DestructuringKind {
export const enum Flags {
None = 0,
NewLine = 1 << 0,
SeenAwait = 1 << 1,
SeenYield = 1 << 2,
HasConstructor = 1 << 5,
Octals = 1 << 6,
SimpleParameterList = 1 << 7
SimpleParameterList = 1 << 7,
Await = 1 << 8,
Yield = 1 << 9,
}

export const enum ParseFunctionFlag {
Expand Down Expand Up @@ -256,7 +259,8 @@ export function validateIdentifier(parser: ParserState, context: Context, type:
if (context & (Context.InAwaitContext | Context.Module)) {
report(parser, Errors.AwaitOutsideAsync);
}
parser.flags |= Flags.SeenAwait;

parser.flags |= Flags.Await;
}

if (token === Token.YieldKeyword) {
Expand All @@ -281,7 +285,7 @@ export function validateIdentifier(parser: ParserState, context: Context, type:
export function isStrictReservedWord(parser: ParserState, context: Context, t: Token): boolean {
if (t === Token.AwaitKeyword) {
if (context & (Context.InAwaitContext | Context.Module)) report(parser, Errors.AwaitOutsideAsync);
parser.flags |= Flags.SeenAwait;
parser.destructible |= DestructuringKind.Await;
}

if (t === Token.YieldKeyword && context & Context.InYieldContext) report(parser, Errors.DisallowedInContext, 'yield');
Expand Down
52 changes: 34 additions & 18 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2199,7 +2199,7 @@ export function parseAwaitExpressionOrIdentifier(
context: Context,
inNewExpression: 0 | 1
): ESTree.Identifier | ESTree.Expression | ESTree.ArrowFunctionExpression | ESTree.AwaitExpression {
parser.flags |= Flags.SeenAwait;
parser.flags |= Flags.Await;

if (context & Context.InAwaitContext) {
if (inNewExpression) {
Expand Down Expand Up @@ -2265,7 +2265,8 @@ export function parseFunctionBody(
if (
context & Context.Strict &&
firstRestricted &&
(firstRestricted & Token.IsEvalOrArguments) === Token.IsEvalOrArguments
((firstRestricted & Token.IsEvalOrArguments) === Token.IsEvalOrArguments ||
(firstRestricted & Token.FutureReserved) === Token.FutureReserved)
) {
report(parser, Errors.StrictFunctionName);
}
Expand All @@ -2275,6 +2276,10 @@ export function parseFunctionBody(
body.push(parseStatementListItem(parser, context) as ESTree.Statement);
}

if (parser.flags & Flags.SeenYield) {
parser.flags = (parser.flags | Flags.SeenYield) ^ Flags.SeenYield;
}

consume(
parser,
origin & (BindingOrigin.Arrow | BindingOrigin.Declaration) ? context | Context.AllowRegExp : context,
Expand Down Expand Up @@ -3109,6 +3114,8 @@ export function parseArrayExpressionOrPattern(
let left: any;

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

left = parsePrimaryExpressionExtended(parser, context, type, /* inNewExpression */ 0, /* assignable */ 1);
if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
if (parser.assignable & AssignmentKind.NotAssignable) {
Expand Down Expand Up @@ -3267,15 +3274,18 @@ function parseArrayOrObjectAssignmentPattern(

reinterpretToPattern(parser, node);

const { token } = parser;

const right = parseExpression(
parser,
(context | Context.DisallowInContext) ^ Context.DisallowInContext,
/* assignable */ 1
);

parser.destructible =
(destructible | DestructuringKind.SeenProto | DestructuringKind.Required) ^
(DestructuringKind.Required | DestructuringKind.SeenProto);
((destructible | DestructuringKind.SeenProto | DestructuringKind.Required) ^
(DestructuringKind.Required | DestructuringKind.SeenProto)) |
(token === Token.AwaitKeyword ? DestructuringKind.Await : 0);

return {
type: 'AssignmentExpression',
Expand Down Expand Up @@ -3379,7 +3389,9 @@ function parseRestOrSpreadElement(

destructible |= DestructuringKind.NotDestructible;
} else {
if (token !== Token.Comma && token !== closingToken) {
if (token === Token.Comma) {
destructible |= DestructuringKind.NotDestructible;
} else if (token !== closingToken) {
argument = parseAssignmentExpression(parser, context, argument);
}

Expand Down Expand Up @@ -3615,7 +3627,8 @@ export function parseObjectLiteralOrPattern(
}

if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
destructible |= DestructuringKind.Required;
destructible |=
DestructuringKind.Required | (parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0);
value = {
type: 'AssignmentPattern',
left: key,
Expand Down Expand Up @@ -3809,6 +3822,8 @@ export function parseObjectLiteralOrPattern(
if (tokenValue === '__proto__') prototypeCount++;

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

value = parsePrimaryExpressionExtended(parser, context, type, /* inNewExpression */ 0, /* assignable */ 1);

const { token } = parser;
Expand Down Expand Up @@ -4041,9 +4056,6 @@ export function parseObjectLiteralOrPattern(
report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
}

if (parser.flags & Flags.SeenAwait) destructible |= DestructuringKind.HasAWait;
if (parser.flags & Flags.SeenYield) destructible |= DestructuringKind.HasYield;

parser.destructible = destructible;

properties.push({
Expand Down Expand Up @@ -4242,6 +4254,7 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
operator: '=',
right
};
parser.destructible |= parser.flags & Flags.Await ? DestructuringKind.Await : 0;
} else {
destructible |=
(parser.token & Token.IsCommaOrRightParen) === Token.IsCommaOrRightParen
Expand Down Expand Up @@ -4319,7 +4332,6 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
expressions
};
}

consume(parser, context, Token.RightParen);

parser.destructible = destructible;
Expand Down Expand Up @@ -4355,6 +4367,8 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
};
}

if (parser.flags & Flags.Await) destructible |= DestructuringKind.Await;

if (destructible & DestructuringKind.NotDestructible && destructible & DestructuringKind.Required)
report(parser, Errors.Unexpected);

Expand All @@ -4363,11 +4377,11 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
if (!assignable) report(parser, Errors.IllegalArrowFunctionParams);
if (destructible & DestructuringKind.NotDestructible) report(parser, Errors.IllegalArrowFunctionParams);
if (destructible & DestructuringKind.Assignable) report(parser, Errors.InvalidArrowDestructLHS);
if (context & (Context.Module | Context.InAwaitContext) && parser.flags & Flags.SeenAwait)
report(parser, Errors.IllegalArrowFunctionParams);
if (context & (Context.Strict | Context.InYieldContext) && parser.destructible & DestructuringKind.HasYield)
if (context & (Context.InAwaitContext | Context.Module) && parser.destructible & DestructuringKind.Await)
report(parser, Errors.AwaitInParameter);
if (context & (Context.Strict | Context.InYieldContext) && parser.flags & Flags.SeenYield) {
report(parser, Errors.YieldInParameter);
if (parser.destructible & DestructuringKind.HasAWait) report(parser, Errors.InvalidArrowDefaultYield);
}
return parseArrowFunctionExpression(parser, context, toplevelComma ? expressions : [expr], /* isAsync */ 0);
} else if (destructible & DestructuringKind.Required) {
report(parser, Errors.InvalidShorthandPropInit);
Expand Down Expand Up @@ -4810,18 +4824,19 @@ export function parseAsyncArrowOrCallExpression(
if (!consumeOpt(parser, context | Context.AllowRegExp, Token.Comma)) break;
}

parser.destructible |= parser.flags & Flags.Await ? DestructuringKind.Await : 0;

consume(parser, context, Token.RightParen);

if (parser.token === Token.Arrow) {
if (isComplex) parser.flags |= Flags.SimpleParameterList;
if (!assignable) report(parser, Errors.IllegalArrowFunctionParams);
if (destructible & DestructuringKind.NotDestructible) report(parser, Errors.InvalidLHSInAsyncArrow);
if (destructible & DestructuringKind.Assignable) report(parser, Errors.InvalidArrowDestructLHS);
if (context & (Context.Module | Context.InAwaitContext) && parser.flags & Flags.SeenAwait)
report(parser, Errors.IllegalArrowFunctionParams);
if (parser.destructible & DestructuringKind.HasAWait) report(parser, Errors.InvalidArrowDefaultYield);
if (parser.flags & Flags.NewLine || asyncNewLine) report(parser, Errors.InvalidLineBreak);
if (parser.flags & Flags.SeenAwait) report(parser, Errors.AwaitInParameter);
if (parser.destructible & DestructuringKind.Await) report(parser, Errors.YieldInParameter);
if (context & (Context.Strict | Context.InYieldContext) && parser.flags & Flags.SeenYield)
report(parser, Errors.YieldInParameter);
return parseArrowFunctionExpression(parser, context, params as any, /* isAsync */ 1) as any;
} else if (destructible & DestructuringKind.Required) {
report(parser, Errors.InvalidShorthandPropInit);
Expand Down Expand Up @@ -4951,6 +4966,7 @@ export function parseClassExpression(parser: ParserState, context: Context): EST
report(parser, Errors.StrictEvalArguments);
id = parseIdentifier(parser, context);
}

if (consumeOpt(parser, context | Context.AllowRegExp, Token.ExtendsKeyword)) {
superClass = parseLeftHandSideExpression(parser, context, /* assignable */ 0);
context |= Context.SuperCall;
Expand Down
9 changes: 4 additions & 5 deletions test/parser/declarations/async-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ describe('Declarations - Async Function', () => {
'async function foo (foo) { super() };',
'async function foo() { (async function await() { }) }',
`(async function() { 0, { await } = {}; });`,
'async function f(){ (x = new x(await x)) => {} }',
'async function f(){ (x = new (await x)) => {} }',
'async function f(){ (x = new f[await x]) => {} }',
`async function f(x = () => await x){}`,
Expand Down Expand Up @@ -289,7 +288,6 @@ describe('Declarations - Async Function', () => {
['async await => 1"', Context.None],
['async function f() { for await (let.x of a); }', Context.None],
['async (...await) => 1', Context.None],
['async ({await}) => 1', Context.None],
['async ([await]) => 1', Context.None],
['async ([...await]) => 1', Context.None],
['async (b = {await}) => 1', Context.None],
Expand Down Expand Up @@ -323,12 +321,13 @@ describe('Declarations - Async Function', () => {
['({async foo() { await }})', Context.None],
['async function foo(a = await b) {}', Context.None],
['(async function foo(a = await b) {})', Context.None],
['sync (a = await b) => {}', Context.None],
['async (a = await b) => {}', Context.None],
['async function wrapper() {\nasync (a = await b) => {}\n}', Context.None],
['({async foo(a = await b) {}})', Context.None],
['async function wrap() {\n(a = await b) => a\n}', Context.None],
['async function wrap() {\n({a = await b} = obj) => a\n}', Context.None]
//['function* wrap() {\nasync(a = yield b) => a\n}', Context.None]
['async function wrap() {\n({a = await b} = obj) => a\n}', Context.None],
['function* wrap() {\nasync(a = yield b) => a\n}', Context.None],
['async function f(){ (x = new x(await x)) => {} }', Context.None]
]);

pass('Declarations - Async function (pass)', [
Expand Down

0 comments on commit 7f006fc

Please sign in to comment.