Skip to content

Commit

Permalink
fix(parser): fixed async await edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed Jun 3, 2019
1 parent 05cd9cc commit 7ffdea3
Show file tree
Hide file tree
Showing 11 changed files with 662 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img width="260" height="200" src="https://github.com/meriyah/meriyah/blob/master/scripts/logo.png">
</p>

<h3 align="center">A 100% compliant, self-hosted javascript parser with high focus on both performance and stability</h3>
<h4 align="center">A 100% compliant, self-hosted javascript parser with high focus on both performance and stability</h4>

<p align="center">

Expand Down
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.2.4",
"version": "0.2.5",
"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
30 changes: 17 additions & 13 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2791,7 +2791,10 @@ export function parseMemberOrUpdateExpression(
});
} else if (parser.token === Token.LeftBracket) {
nextToken(parser, context | Context.AllowRegExp);
const property = parseExpressions(parser, context & ~Context.DisallowIn, /* assignable */ 1, parser.tokenIndex);
const idxAfterLeftBracket = parser.tokenIndex;
let property = parseExpression(parser, context, 1, inGroup, idxAfterLeftBracket);
if (parser.token === Token.Comma)
property = parseSequenceExpression(parser, context, idxAfterLeftBracket, property);
consume(parser, context, Token.RightBracket);
parser.assignable = AssignmentKind.IsAssignable;
expr = finishNode(parser, context, start, {
Expand Down Expand Up @@ -3031,7 +3034,7 @@ export function parsePrimaryExpressionExtended(
case Token.TemplateContinuation:
return parseTemplate(parser, context, start);
case Token.NewKeyword:
return parseNewExpression(parser, context, start);
return parseNewExpression(parser, context, inGroup, start);
case Token.BigIntLiteral:
parser.assignable = AssignmentKind.CannotAssign;
return parseBigIntLiteral(parser, context);
Expand Down Expand Up @@ -3642,20 +3645,13 @@ export function parseArrayExpressionOrPattern(
if (token & Token.IsIdentifier) {
left = parsePrimaryExpressionExtended(parser, context, type, 0, 1, inGroup, tokenIndex);

destructible |=
parser.destructible & DestructuringKind.Yield
? DestructuringKind.Yield
: 0 | (parser.destructible & DestructuringKind.Await)
? DestructuringKind.Await
: 0;

if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
if (parser.assignable & AssignmentKind.CannotAssign) {
reportAt(parser, parser.index, parser.line, parser.index - 3, Errors.InvalidLHS);
}

const right = parseExpression(parser, context, /* assignable */ 1, inGroup, parser.tokenIndex);
destructible |= parser.destructible & DestructuringKind.Await ? DestructuringKind.Await : 0;

left = finishNode(parser, context, tokenIndex, {
type: 'AssignmentExpression',
operator: '=',
Expand All @@ -3682,6 +3678,13 @@ export function parseArrayExpressionOrPattern(
: DestructuringKind.AssignableDestruct;
}
}

destructible |=
parser.destructible & DestructuringKind.Yield
? DestructuringKind.Yield
: 0 | (parser.destructible & DestructuringKind.Await)
? DestructuringKind.Await
: 0;
} else if (parser.token & Token.IsPatternStart) {
left =
parser.token === Token.LeftBrace
Expand Down Expand Up @@ -5217,6 +5220,7 @@ export function parseFormalParametersOrFormalList(parser: ParserState, context:
export function parseNewExpression(
parser: ParserState,
context: Context,
inGroup: 0 | 1,
start: number
): ESTree.NewExpression | ESTree.Expression | ESTree.MetaProperty {
// NewExpression ::
Expand Down Expand Up @@ -5248,15 +5252,15 @@ export function parseNewExpression(
report(parser, Errors.InvalidNewTarget);
}
parser.assignable = AssignmentKind.CannotAssign;
let callee = parsePrimaryExpressionExtended(parser, context, BindingType.None, 1, 0, 0, startIdx);
callee = parseMemberOrUpdateExpression(parser, context, callee, /* inNewExpression*/ 1, 0, 0, startIdx);
let callee = parsePrimaryExpressionExtended(parser, context, BindingType.None, 1, 0, inGroup, startIdx);
callee = parseMemberOrUpdateExpression(parser, context, callee, /* inNewExpression*/ 1, 0, inGroup, startIdx);
parser.assignable = AssignmentKind.CannotAssign;
return finishNode(parser, context, start, {
type: 'NewExpression',
callee,
arguments:
parser.token === Token.LeftParen
? parseArguments(parser, context & ~Context.DisallowIn, /* isImportCall */ 0, 0)
? parseArguments(parser, context & ~Context.DisallowIn, /* isImportCall */ 0, inGroup)
: []
} as ESTree.NewExpression);
}
Expand Down
16 changes: 14 additions & 2 deletions test/parser/declarations/async-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ describe('Declarations - Async Function', () => {
`function f() { ({ async [yield]() {} }); }`,
`function* g() { ({ async [yield]() {} }); }`,
'async function* a() { yield; (r = a) => {} }',
'async function* x(a, b, ...c) { await 1; }',
'async function* x(a, b = 2) { await 1; }',
'async function* x(a) { yield 1; }',
'async function* x(a, b = 2) { yield 1; }',
'async function* x(a, b, ...c) { yield 1; }',
'async function x() { let x = await 1; eval("var i = 5"); let y = await 2; debugger; }',
'new (async function*() {})',
'(async function*() {}).caller',
'(async function*() {}).arguments',
'async function fib(n) { return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2); }',
'var hardcoreFib = async function fib2(n) { return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2); }',
'() => class extends (async function() {}) {}',
`async function yield() {}`,
'async function x () { a = { a: await(a) } }',
'async function* a(){}',
Expand Down Expand Up @@ -216,8 +228,8 @@ describe('Declarations - Async Function', () => {
'async function foo (foo) { super() };',
'async function foo() { (async function await() { }) }',
`(async function() { 0, { await } = {}; });`,
// 'async function f(){ (x = new (await x)) => {} }',
// 'async function f(){ (x = new f[await x]) => {} }',
'async function f(){ (x = new (await x)) => {} }',
'async function f(){ (x = new f[await x]) => {} }',
`async function f(x = () => await x){}`,
'async function x({await}) { return 1 }',
'async function f() { return {await}; }',
Expand Down
3 changes: 3 additions & 0 deletions test/parser/expressions/async-arrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,9 @@ describe('Expressions - Async arrow', () => {
'async (argMath139 = (/a/ instanceof ((typeof Boolean == "function" ) ? Boolean : Object)),argMath140,argMath141) => { return await ("valueOf" in i32); }',
'async x => { return x => x; }',
'async (a = b => await (0)) => {}',
'(async(a, b, ...c) => await 1)',
'() => (async(foo, { a = NaN }) => foo + a)("1", { a: "0" })',
'() => (async(foo, { a = "0" }) => foo + a)("2", { a: undefined })',
//'async(a = (await) => {}) => {};',
'var f = cond ? x=>{x.foo } : x=>x + x + x + x + x + x + (x =>x)'
]) {
Expand Down
2 changes: 2 additions & 0 deletions test/parser/expressions/await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ describe('Expressions - Await', () => {
['async function g(){ function f(foo = [h, {m: t(await bar)}]){} }', Context.None],
['async function g(){class x {async *f(foo = await bar){}} }', Context.None],
['async function g(){class x {*f(foo = await bar){}} }', Context.None],
['async function af(a, b = await a) { }', Context.None],
['var o = { async\nam() { } };', Context.None],
['async function g(){class x {async f(foo = await bar){}} }', Context.None],
['async function g(){class x {f(foo = await bar){}} }', Context.None],
['async function g(){let o = {async *f(foo = await bar){}} }', Context.None],
Expand Down
4 changes: 4 additions & 0 deletions test/parser/miscellaneous/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ describe('Miscellaneous - Comments', () => {
'/*a\rb*/ 0',
'/*a\nb*/ 0',
'/*a\nc*/ 0',
`/*
Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or http://ckeditor.com/license
*/`,
'let a = () => /* = */ { return "b" }',
'let a = () => { /* = */ return "b" }',
'let a = () /* = */ => { return "b" }',
Expand Down
10 changes: 5 additions & 5 deletions test/parser/miscellaneous/early-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ describe('Miscellaneous - Early errors', () => {
'\\u{110000}',
'\\u{FFFFFFF}',
`/./\\u{69}`,
// `async function a(){ (a = await (0)) => {}; }`,
//`async function a(b = await (0)) {}`,
//'(async function(b = await (0)) {})',
//'({ async a(b = await (0)) {} })',
//`async function a(){ (a = await (0)) => {}; }`,
`async function a(b = await (0)) {}`,
'(async function(b = await (0)) {})',
'({ async a(b = await (0)) {} })',
'(class { async constructor(){} })',
"'use strict'; +implements;",
"'use strict'; let:0;",
Expand Down Expand Up @@ -239,7 +239,7 @@ describe('Miscellaneous - Early errors', () => {
'function* a(){ (b = yield c) => 1; }',
// 'class a {static [static](){};}',
'function* a(){ function* b(c = yield){} }',
// 'function a(){ c: while(1) continue b; }',
'function a(){ c: while(1) continue b; }',
'for(const a;;);',
'/[a-z]/z',
`var af = x
Expand Down
59 changes: 25 additions & 34 deletions test/parser/miscellaneous/failure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('Miscellaneous - Failure', () => {
'async (eval) => {"use strict";}',
'arguments => {"use strict";}',
'async arguments => {"use strict";}',
'function f(x=(yield z)=y){}',
'`a${await foo}d`',
`for (a+b in c) d;`,
`for (a+b of c) d;`,
Expand Down Expand Up @@ -56,10 +57,7 @@ describe('Miscellaneous - Failure', () => {
`do x
while ({ [y = [yy]]: { x = (y)} ? null : false })`,
'"use strict"; for (let in x);',
// `for (let [x, x] of y);`,
`function* f(){ yield↵/foo }`,
//`function* f(){ yield
///foo/g }`,
`wrap({get 123: x});`,
'for (let {x}.y of x);',
'for (let {x}.y in x);',
Expand All @@ -74,7 +72,7 @@ describe('Miscellaneous - Failure', () => {
' var [(a)] = 0',
'const [(x)] = []',
'let [(x().foo)] = x',
//'let [(x) = y] = [];',
'let [(x) = y] = [];',
'let [(x)] = [];',
// '['++([])',
// '['(++[])',
Expand Down Expand Up @@ -261,8 +259,6 @@ describe('Miscellaneous - Failure', () => {
'function foo(foo, bar, a = 25) { "a"; "use strict"; }',
'function foo(foo, bar, baz, ...rest) { "use strict"; }',
'function foo(foo, bar, baz, ...rest) { "a"; "use strict"; }',
//'function foo(a = function() { }) { "use strict"; a(); }',
//'function foo(a = function() { }) { "a"; "use strict"; a(); }',
'let foo = (...restParam) => { "use strict"; }',
'let foo = (...restParam) => { "a"; "use strict"; }',
'let foo = ({x}) => { "use strict"; }',
Expand All @@ -277,8 +273,8 @@ describe('Miscellaneous - Failure', () => {
'let foo = (foo, bar, a = 25) => { "a"; "use strict"; }',
'let foo = (foo, bar, baz, ...rest) => { "use strict"; }',
'let foo = (foo, bar, baz, ...rest) => { "a"; "use strict"; }',
//'let foo = (a = function() { }) => { "use strict"; a(); }',
//'let foo = (a = function() { }) => { "a"; "use strict"; a(); }',
'let foo = (a = function() { }) => { "use strict"; a(); }',
'let foo = (a = function() { }) => { "a"; "use strict"; a(); }',
`async ({} + 1) => x;`,
'({a=b}.x) => x',
'({a=b}[x]) => x',
Expand Down Expand Up @@ -324,11 +320,7 @@ describe('Miscellaneous - Failure', () => {
'async function f(){ async function g(x=(await)=y){} }',
'async function f(){ async function g(x=(await z)=y){} }',
'(x=(await z)=y)',

// '(x=(yield)=y)=>z',
// '(x=(yield z)=y)',
// 'function f(x=(yield)=y){}',
// 'function f(x=(yield z)=y){}',
'(x=(yield z)=y)',
'function *f(x=(yield)=y){}',
'function *f(x=(yield z)=y){}',
`(a,)`,
Expand Down Expand Up @@ -884,7 +876,6 @@ describe('Miscellaneous - Failure', () => {
'function f() { a = async function(a = await) {}; }',
'async function f() { a = async function(a = await) {}; }',
'async (a = await) => {}',
// 'async (a = async () => { await 1; }) => {}',
'throw\n10;',
'async function f() { async function await() {} }',
"'use strict'; ({ async [yield]() {} });",
Expand Down Expand Up @@ -968,7 +959,7 @@ describe('Miscellaneous - Failure', () => {
'if (true) function* g() { }',
'if (false) ; else function* g() { }',
'foo: function* g() { }',
//'`x${await x}y`',
'`x${await x}y`',
`async () \n => x`,
`(async () \n => x)`,
`1.a`,
Expand Down Expand Up @@ -1002,7 +993,7 @@ describe('Miscellaneous - Failure', () => {
`[...x in y] = []`,
`function foo() { 'use strict'; return {yield} }`,
`function* wrap() { function* foo(a = 1 + (yield)) {} }`,
// `function* wrap() { return (a = 1 + (yield)) => a }`,
`function* wrap() { return (a = 1 + (yield)) => a }`,
`(function* g() {\nfor (yield '' in {}; ; ) ;\n }`,
`(function* yield() {})`,
`function* wrap() {\nfunction* yield() {}\n}`,
Expand Down Expand Up @@ -1033,8 +1024,8 @@ describe('Miscellaneous - Failure', () => {
`3in[]`,
`3x0`,
`\\ua`,
//'continue',
//'break',
'continue',
'break',
'if (x) continue y',
`1 + { t:t `,
`1 + {`,
Expand Down Expand Up @@ -1171,7 +1162,7 @@ describe('Miscellaneous - Failure', () => {
' [a, ...(b = c)] = 0',
`if (false) ; else const x = null;`,
`class A { static set prototype() {} }`,
// `function* g(){ ([a = yield]) => 0; }`,
`function* g(){ ([a = yield]) => 0; }`,
`for(let a;;) label: function f(){}`,
'for (;;) const x = 10;',
`x = { set f(...y) {} }`,
Expand Down Expand Up @@ -1286,8 +1277,8 @@ describe('Miscellaneous - Failure', () => {
`function(...[b = !b]) { }`,
'"\\u{FFFF"',
'([function] = [10])',
// 'while(true)break if;',
// 'while(true)continue if;',
'while(true)break if;',
'while(true)continue if;',
'foo:break;',
'foo++("toString");',
'async("foo".bar) => x',
Expand Down Expand Up @@ -1820,7 +1811,7 @@ describe('Miscellaneous - Failure', () => {
'function*g() { var yield; }',
'(class {[3]:0})',
'(function ({e: a.b}) {})',
// 'async function f(){ (fail = class A extends await foo {}) => fail }',
'async function f(){ (fail = class A extends await foo {}) => fail }',
'foo: class X {}',
'() => { super(); }',
'super',
Expand Down Expand Up @@ -1885,7 +1876,7 @@ describe('Miscellaneous - Failure', () => {
'for (;b\n++c);',
'yield x + y',
'a b;',
// `do { test262: { continue test262; } } while (a)`,
`do { test262: { continue test262; } } while (a)`,
"('\\x0')",
'({a: b += 0} = {})',
'[...{a = b} = c] = x',
Expand Down Expand Up @@ -2007,17 +1998,17 @@ describe('Miscellaneous - Failure', () => {
'async function f(foo = [{m: t(+await bar)}]){}',
'async ([x] = await bar);',
'(foo = +await bar) => {}',
//'async (foo = +await bar) => {}',
//'(foo = [{m: 5 + t(+await bar)}]) => {}',
//'async (foo = [{m: 5 + t(+await bar)}]) => {}',
//'async function g(){ function f(foo = +await bar){} }',
//'async function g(){async function f(foo = +await bar){} }',
//'async function g(){ function f(foo = [h, {m: t(+await bar)}]){} }',
//'async function g(){async function f(foo = [h, {m: t(+await bar)}]){} }',
//'async function a(){ (foo = +await bar) => {} }',
//'async function a(){ async (foo = +await bar) => {} }',
//'async function a(){ (foo = [{m: 5 + t(+await bar)}]) => {} }',
//'async function a(){ async (foo = [{m: 5 + t(+await bar)}]) => {} }',
'async (foo = +await bar) => {}',
'(foo = [{m: 5 + t(+await bar)}]) => {}',
'async (foo = [{m: 5 + t(+await bar)}]) => {}',
'async function g(){ function f(foo = +await bar){} }',
'async function g(){async function f(foo = +await bar){} }',
'async function g(){ function f(foo = [h, {m: t(+await bar)}]){} }',
'async function g(){async function f(foo = [h, {m: t(+await bar)}]){} }',
'async function a(){ (foo = +await bar) => {} }',
'async function a(){ async (foo = +await bar) => {} }',
'async function a(){ (foo = [{m: 5 + t(+await bar)}]) => {} }',
'async function a(){ async (foo = [{m: 5 + t(+await bar)}]) => {} }',
'++(x) => b'
]) {
it(`${arg}`, () => {
Expand Down

0 comments on commit 7ffdea3

Please sign in to comment.