From 37c63613771e5bc6e23b7da2d92e992c60dafc5a Mon Sep 17 00:00:00 2001 From: Chunpeng Huo Date: Thu, 31 Mar 2022 16:07:10 +1100 Subject: [PATCH] fix(parser): allow top level await in expressions Such as foo[await 1], foo(await 1). closes #212 --- src/parser.ts | 6 +-- test/parser/expressions/await.ts | 57 ++++++++++++++++++++ test/parser/expressions/optional-chaining.ts | 3 +- test/parser/miscellaneous/escaped-keyword.ts | 1 + 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/parser.ts b/src/parser.ts index d859ca52..94f2b0a8 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -3859,12 +3859,12 @@ export function parseMemberOrUpdateExpression( if ((parser.token & Token.IsUpdateOp) === Token.IsUpdateOp && (parser.flags & Flags.NewLine) < 1) { expr = parseUpdateExpression(parser, context, expr, start, line, column); } else if ((parser.token & Token.IsMemberOrCallExpression) === Token.IsMemberOrCallExpression) { - context = (context | Context.DisallowIn | Context.InGlobal) ^ (Context.DisallowIn | Context.InGlobal); + context = (context | Context.DisallowIn) ^ Context.DisallowIn; switch (parser.token) { /* Property */ case Token.Period: { - nextToken(parser, context | Context.AllowEscapedKeyword); + nextToken(parser, (context | Context.AllowEscapedKeyword | Context.InGlobal) ^ Context.InGlobal); parser.assignable = AssignmentKind.Assignable; @@ -3940,7 +3940,7 @@ export function parseMemberOrUpdateExpression( /* Optional chaining */ case Token.QuestionMarkPeriod: { - nextToken(parser, context); // skips: '?.' + nextToken(parser, (context | Context.AllowEscapedKeyword | Context.InGlobal) ^ Context.InGlobal); // skips: '?.' parser.flags |= Flags.HasOptionalChaining; parser.assignable = AssignmentKind.CannotAssign; expr = parseOptionalChain(parser, context, expr, start, line, column); diff --git a/test/parser/expressions/await.ts b/test/parser/expressions/await.ts index 6b3f4521..52660c16 100644 --- a/test/parser/expressions/await.ts +++ b/test/parser/expressions/await.ts @@ -3282,6 +3282,63 @@ describe('Expressions - Await', () => { } ] } + ], + [ + 'foo[await 1]', + Context.Module, + { + type: 'Program', + sourceType: 'module', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'foo' + }, + computed: true, + property: { + type: 'AwaitExpression', + argument: { + type: 'Literal', + value: 1 + } + } + } + } + ] + } + ], + [ + 'foo(await bar)', + Context.Module, + { + type: 'Program', + sourceType: 'module', + body: [ + { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: 'foo' + }, + arguments: [ + { + type: 'AwaitExpression', + argument: { + type: 'Identifier', + name: 'bar' + } + } + ] + } + } + ] + } ] ]); }); diff --git a/test/parser/expressions/optional-chaining.ts b/test/parser/expressions/optional-chaining.ts index 77b7b824..9c82893d 100644 --- a/test/parser/expressions/optional-chaining.ts +++ b/test/parser/expressions/optional-chaining.ts @@ -6,7 +6,8 @@ import { parseSource } from '../../../src/parser'; describe('Optional chaining', () => { for (const arg of [ 'func?.()', - 'obj?.prop ', + 'obj?.prop', + 'obj?.def\\u{61}ult', 'func?.(...args)', 'a?.[x]', 'a?.()', diff --git a/test/parser/miscellaneous/escaped-keyword.ts b/test/parser/miscellaneous/escaped-keyword.ts index 760b7f17..2d7395e4 100644 --- a/test/parser/miscellaneous/escaped-keyword.ts +++ b/test/parser/miscellaneous/escaped-keyword.ts @@ -11,6 +11,7 @@ describe('Miscellaneous - Escaped keywords', () => { '(\\u0069nterface = 1);', '({ def\\u0061ult: 0 })', '({ def\\u{61}ult: 0 })', + 'foo = {}; foo?.def\\u{61}ult + 3;', 'foo = {}; foo.def\\u{61}ult = 3;', 'var int\\u0065rface = 1;', 'var { int\\u0065rface } = {};',