Skip to content

Commit

Permalink
fix(parser): Fix a bunch of edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed May 24, 2019
1 parent 372277f commit edfe03c
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 54 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "meriyah",
"version": "0.1.11",
"description": "Fast and lightweight, standard-compliant javascript parser written in ECMAScript",
"version": "0.1.12",
"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",
"jsnext:main": "dist/meriyah.esm.js",
Expand Down
93 changes: 55 additions & 38 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ export function parseModuleItem(
nextToken(parser, context | Context.AllowRegExp);

const statements: (ReturnType<typeof parseDirective | typeof parseModuleItem>)[] = [];
[] = [];

// Avoid this if we're not going to create any directive nodes. This is likely to be the case
// most of the time, considering the prevalence of strict mode and the fact modules
Expand Down Expand Up @@ -1433,8 +1432,8 @@ export function parseForStatement(
} else if ((token & Token.IsPatternStart) === Token.IsPatternStart) {
init =
token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, BindingType.None);
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, BindingType.None);

destructible = parser.destructible;

Expand Down Expand Up @@ -3038,7 +3037,7 @@ function parseArrayLiteral(parser: ParserState, context: Context, skipInitialize
* ... AssignmentExpression
*
*/
const expr = parseArrayExpressionOrPattern(parser, context, skipInitializer, BindingType.None);
const expr = parseArrayExpressionOrPattern(parser, context, skipInitializer, /* inGroup */ 0, BindingType.None);

if (context & Context.OptionsWebCompat && parser.destructible & DestructuringKind.SeenProto) {
report(parser, Errors.DuplicateProto);
Expand All @@ -3065,6 +3064,7 @@ export function parseArrayExpressionOrPattern(
parser: ParserState,
context: Context,
skipInitializer: 0 | 1,
inGroup: 0 | 1,
type: BindingType
): ESTree.ArrayExpression | ESTree.ArrayPattern {
/* ArrayLiteral :
Expand Down Expand Up @@ -3141,7 +3141,7 @@ export function parseArrayExpressionOrPattern(
? DestructuringKind.CannotDestruct
: 0 |
(token === Token.AwaitKeyword ? DestructuringKind.Await : 0) |
(token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
(inGroup && token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
} else {
if (type) destructible |= DestructuringKind.CannotDestruct;

Expand All @@ -3162,8 +3162,8 @@ export function parseArrayExpressionOrPattern(
} else if (parser.token & Token.IsPatternStart) {
left =
parser.token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer*/ 0, type)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer*/ 0, type);
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer*/ 0, inGroup, type)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer*/ 0, inGroup, type);

destructible |= parser.destructible;

Expand Down Expand Up @@ -3192,7 +3192,7 @@ export function parseArrayExpressionOrPattern(
}
}
} else if (parser.token === Token.Ellipsis) {
left = parseRestOrSpreadElement(parser, context, Token.RightBracket, type, /* isAsync */ 0);
left = parseRestOrSpreadElement(parser, context, Token.RightBracket, type, /* isAsync */ 0, inGroup);
destructible |= parser.destructible;
if (parser.token !== Token.Comma && parser.token !== Token.RightBracket)
report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
Expand Down Expand Up @@ -3232,7 +3232,7 @@ export function parseArrayExpressionOrPattern(
} as ESTree.ArrayExpression;

if (!skipInitializer && parser.token & Token.IsAssignOp) {
return parseArrayOrObjectAssignmentPattern(parser, context, destructible, node) as any;
return parseArrayOrObjectAssignmentPattern(parser, context, destructible, inGroup, node) as any;
}

parser.destructible = destructible;
Expand All @@ -3253,6 +3253,7 @@ function parseArrayOrObjectAssignmentPattern(
parser: ParserState,
context: Context,
destructible: AssignmentKind | DestructuringKind,
inGroup: 0 | 1,
node: ESTree.ArrayExpression | ESTree.ObjectExpression
): ESTree.AssignmentExpression {
// ArrayAssignmentPattern[Yield] :
Expand Down Expand Up @@ -3293,7 +3294,7 @@ function parseArrayOrObjectAssignmentPattern(
((destructible | DestructuringKind.SeenProto | DestructuringKind.MustDestruct) ^
(DestructuringKind.MustDestruct | DestructuringKind.SeenProto)) |
(parser.flags & Flags.Await ? DestructuringKind.Await : 0) |
(token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
(inGroup && token === Token.YieldKeyword ? DestructuringKind.Yield : 0);

return {
type: 'AssignmentExpression',
Expand All @@ -3317,7 +3318,8 @@ function parseRestOrSpreadElement(
context: Context,
closingToken: Token,
type: BindingType,
isAsync: 0 | 1
isAsync: 0 | 1,
inGroup: 0 | 1
): ESTree.SpreadElement {
nextToken(parser, context | Context.AllowRegExp); // skip '...'

Expand Down Expand Up @@ -3354,8 +3356,8 @@ function parseRestOrSpreadElement(
} else if (parser.token & Token.IsPatternStart) {
argument =
parser.token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, type)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, type);
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, inGroup, type)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, inGroup, type);

const { token } = parser;

Expand Down Expand Up @@ -3534,7 +3536,7 @@ function parseObjectLiteral(parser: ParserState, context: Context, skipInitializ
* Initializer:
* =AssignmentExpression
*/
const expr = parseObjectLiteralOrPattern(parser, context, skipInitializer, BindingType.None);
const expr = parseObjectLiteralOrPattern(parser, context, skipInitializer, /* inGroup */ 0, BindingType.None);

if (context & Context.OptionsWebCompat && parser.destructible & DestructuringKind.SeenProto) {
report(parser, Errors.DuplicateProto);
Expand All @@ -3559,6 +3561,7 @@ export function parseObjectLiteralOrPattern(
parser: ParserState,
context: Context,
skipInitializer: 0 | 1,
inGroup: 0 | 1,
type: BindingType
): ESTree.ObjectExpression | ESTree.ObjectPattern | ESTree.AssignmentExpression {
/**
Expand Down Expand Up @@ -3612,7 +3615,7 @@ export function parseObjectLiteralOrPattern(

while (parser.token !== Token.RightBrace) {
if (parser.token === Token.Ellipsis) {
properties.push(parseRestOrSpreadElement(parser, context, Token.RightBrace, type, /* isAsync */ 0));
properties.push(parseRestOrSpreadElement(parser, context, Token.RightBrace, type, /* isAsync */ 0, inGroup));
} else {
let state = PropertyKind.None;
let key: ESTree.Expression | null = null;
Expand All @@ -3637,7 +3640,7 @@ export function parseObjectLiteralOrPattern(
destructible |=
DestructuringKind.MustDestruct |
(parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0) |
(parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
(inGroup && parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0);

value = {
type: 'AssignmentPattern',
Expand Down Expand Up @@ -3683,8 +3686,8 @@ export function parseObjectLiteralOrPattern(
} else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
value =
parser.token === Token.LeftBracket
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, type);
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type);

destructible = parser.destructible;

Expand Down Expand Up @@ -3853,8 +3856,8 @@ export function parseObjectLiteralOrPattern(
} else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
value =
parser.token === Token.LeftBracket
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, type);
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type);

destructible = parser.destructible;

Expand Down Expand Up @@ -3953,8 +3956,8 @@ export function parseObjectLiteralOrPattern(
} else if ((parser.token & Token.IsPatternStart) === Token.IsPatternStart) {
value =
parser.token === Token.LeftBracket
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, type);
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 0, inGroup, type);

destructible = parser.destructible;

Expand Down Expand Up @@ -4090,7 +4093,7 @@ export function parseObjectLiteralOrPattern(
} as any;

if (!skipInitializer && parser.token & Token.IsAssignOp) {
return parseArrayOrObjectAssignmentPattern(parser, context, destructible, node);
return parseArrayOrObjectAssignmentPattern(parser, context, destructible, inGroup, node);
}

parser.destructible = destructible;
Expand Down Expand Up @@ -4146,11 +4149,11 @@ export function parseMethodFormals(
left = parseAndClassifyIdentifier(parser, context, type);
} else {
if (parser.token === Token.LeftBrace) {
left = parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, type);
left = parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type);
} else if (parser.token === Token.LeftBracket) {
left = parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, type);
left = parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type);
} else if (parser.token === Token.Ellipsis) {
left = parseRestOrSpreadElement(parser, context, Token.RightParen, type, /* isAsync */ 0);
left = parseRestOrSpreadElement(parser, context, Token.RightParen, type, /* isAsync */ 0, /* inGroup */ 0);
} else {
report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
}
Expand Down Expand Up @@ -4284,8 +4287,8 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
} else if (parser.token & Token.IsPatternStart) {
expr =
parser.token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /*skipInitializer */ 0, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /*skipInitializer */ 0, BindingType.None);
? parseObjectLiteralOrPattern(parser, context, /*skipInitializer */ 0, /* inGroup */ 1, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /*skipInitializer */ 0, /* inGroup */ 1, BindingType.None);

destructible |= parser.destructible;

Expand All @@ -4305,7 +4308,14 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
}
}
} else if (parser.token === Token.Ellipsis) {
expr = parseRestOrSpreadElement(parser, context, Token.RightParen, BindingType.ArgumentList, /* isAsync */ 0);
expr = parseRestOrSpreadElement(
parser,
context,
Token.RightParen,
BindingType.ArgumentList,
/* isAsync */ 0,
/* inGroup */ 1
);

if (parser.destructible & DestructuringKind.CannotDestruct) report(parser, Errors.InvalidRestArg);

Expand Down Expand Up @@ -4548,11 +4558,11 @@ export function parseFormalParametersOrFormalList(parser: ParserState, context:
left = parseAndClassifyIdentifier(parser, context, type);
} else {
if (parser.token === Token.LeftBrace) {
left = parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, type);
left = parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type);
} else if (parser.token === Token.LeftBracket) {
left = parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, type);
left = parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type);
} else if (parser.token === Token.Ellipsis) {
left = parseRestOrSpreadElement(parser, context, Token.RightParen, type, /* isAsync */ 0);
left = parseRestOrSpreadElement(parser, context, Token.RightParen, type, /* isAsync */ 0, /* inGroup */ 0);
} else {
report(parser, Errors.UnexpectedToken, KeywordDescTable[parser.token & Token.Type]);
}
Expand All @@ -4575,7 +4585,7 @@ export function parseFormalParametersOrFormalList(parser: ParserState, context:
left = {
type: 'AssignmentPattern',
left,
right: parseExpression(parser, context, /* assignable */ 1)
right: parseExpression(parser, (context | Context.DisallowIn) ^ Context.DisallowIn, /* assignable */ 1)
} as any;
}

Expand Down Expand Up @@ -4789,8 +4799,8 @@ export function parseAsyncArrowOrCallExpression(
} else if (parser.token & Token.IsPatternStart) {
expr =
parser.token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /*skipInitializer */ 0, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /*skipInitializer */ 0, BindingType.None);
? parseObjectLiteralOrPattern(parser, context, /*skipInitializer */ 0, /* inGroup */ 1, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /*skipInitializer */ 0, /* inGroup */ 1, BindingType.None);

destructible |= parser.destructible;

Expand All @@ -4809,7 +4819,14 @@ export function parseAsyncArrowOrCallExpression(
expr = parseAssignmentExpression(parser, context, expr);
}
} else if (parser.token === Token.Ellipsis) {
expr = parseRestOrSpreadElement(parser, context, Token.RightParen, BindingType.ArgumentList, /* isAsync */ 1);
expr = parseRestOrSpreadElement(
parser,
context,
Token.RightParen,
BindingType.ArgumentList,
/* isAsync */ 1,
/* inGroup */ 1
);

destructible |= parser.destructible;

Expand Down Expand Up @@ -5379,8 +5396,8 @@ export function parseBindingPattern(parser: ParserState, context: Context, type:

const left =
parser.token === Token.LeftBracket
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, type);
? parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type)
: parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, /* inGroup */ 0, type);

reinterpretToPattern(parser, left);

Expand Down
3 changes: 3 additions & 0 deletions test/parser/declarations/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ describe('Declarations - const', () => {
['const [...bar = foo] = obj;', Context.None],
['const [... ...foo] = obj;', Context.None],
['const [...] = obj;', Context.None],
['const const', Context.None],
['const', Context.None],
['const a = 2,', Context.None],
['const [...,] = obj;', Context.None],
['const [.x] = obj;', Context.None],
['const [..x] = obj;', Context.None],
Expand Down
11 changes: 10 additions & 1 deletion test/parser/declarations/var.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ describe('Declarations - Var', () => {
'var foo = async ({x}) => { function x() { return 2 }; return x(); }',
'var foo = async ({x}) => { { function x() { return 2 } } return x(); }',
'var foo = async (x = 1) => { return x };',
'var [,,a,b,,,c=2,...d] = a;',
'var foo = async (x, y = x) => { return x + y; };',
'var foo = async (x, y = () => x) => { return x + y(); };',
'var foo = async (x = () => 1) => { return x() };',
Expand All @@ -256,6 +257,10 @@ describe('Declarations - Var', () => {
'var {[key]: y, ...x} = {1: 1, a: 1};',
'var { ...y } = { ...z} ;',
'var z = { b: 1}',
'var [,,,,] = a;',
'var [a, [b, c, d=2], ...rest] = test;',
'const [...[x, ...[y, ...{z}]]] = [3, 4, 5];',
'var [a, b,,,,] = test;',
'var { 1.5: x, 2: y, ...z } = { 1.5: 1, 2: 2, 3:3 };',
'var g4 = async (a = eval("x")) => { var x; return a; };',
'var f13 = async function f(x = f) { function f() {}; return x; }',
Expand Down Expand Up @@ -620,7 +625,8 @@ describe('Declarations - Var', () => {
['var { key: await /foo/g } = {}', Context.None],
['var { key: bar + x } = {}', Context.None],
['var { "foo": 123 } = {}', Context.None],
['var { "foo": 123 } = {}', Context.None],
['var t4 = ++await 1;', Context.None],
['var t5 = --await 1;', Context.None],
['var { ...y, ...y } = {}', Context.None],
['var { foo: true / false } = {}', Context.None],
['var { *static() {} } = {}', Context.None],
Expand All @@ -639,6 +645,9 @@ describe('Declarations - Var', () => {
['var [a + 1] = [];', Context.None],
['var [++a] = [];', Context.None],
['var {...x = 1} = {}', Context.None],
['var [a a, b] = c;', Context.None],
['var [a, b', Context.None],
['var [a, ...rest, b] = c;', Context.None],
['var a; [a--] = [];', Context.None],
['var a; [++a] = [];', Context.None],
['var [1] = [];', Context.None],
Expand Down
8 changes: 7 additions & 1 deletion test/parser/expressions/await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ describe('Expressions - Await', () => {
'x = await(y);',
'class X { await() {} }',
'let async = await;',
'x = { await: false }'
'x = { await: false }',
'class test{ async method (param){ await foo(); } method2(){} }',
'async function test() { await foo(); }',
'var a = async function test() { await foo(); }',
'var test = async a => await test();'
]) {
it(`${arg}`, () => {
t.doesNotThrow(() => {
Expand Down Expand Up @@ -448,6 +452,8 @@ describe('Expressions - Await', () => {
['async function a(){ async ([y] = [{m: 5 + t(await bar)}]) => {} }', Context.None],
['async function a(){ async ({g} = [{m: 5 + t(await bar)}]) => {} }', Context.None],
// ['async function a(){ ({g} = [{m: 5 + t(await bar)}]) => {} }', Context.None],
['class test { async get method(){} }', Context.None],
['var test = => { await test(); }', Context.None],
['async function a(){ async (foo = [{m: 5 + t(await bar)}]) => {} }', Context.None],
['async function a(){ (foo = [{m: 5 + t(await bar)}]) => {} }', Context.None],
['async function a(){ async ([v] = await bar) => {} }', Context.None],
Expand Down

0 comments on commit edfe03c

Please sign in to comment.