Skip to content

Commit

Permalink
fix(parser): Fixed a bunch of edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed May 15, 2019
1 parent 0bd2a60 commit 9854a83
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 62 deletions.
23 changes: 9 additions & 14 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,7 @@ export function parseForStatement(
consume(parser, context | Context.AllowRegExp, Token.LeftParen);
let test: ESTree.Expression | null = null;
let update: ESTree.Expression | null = null;
let destructible: AssignmentKind | DestructuringKind = 0;
let init = null;
let isVarDecl: number = parser.token & Token.VarDecl;
let right;
Expand Down Expand Up @@ -1434,11 +1435,9 @@ export function parseForStatement(
token === Token.LeftBrace
? parseObjectLiteralOrPattern(parser, context, /* skipInitializer */ 1, BindingType.None)
: parseArrayExpressionOrPattern(parser, context, /* skipInitializer */ 1, BindingType.None);

destructible = parser.destructible;
parser.assignable =
parser.destructible & DestructuringKind.NotDestructible
? AssignmentKind.NotAssignable
: AssignmentKind.Assignable;
destructible & DestructuringKind.NotDestructible ? AssignmentKind.NotAssignable : AssignmentKind.Assignable;

init = parseMemberOrUpdateExpression(
parser,
Expand Down Expand Up @@ -1472,6 +1471,7 @@ export function parseForStatement(
((context | Context.TopLevel) ^ Context.TopLevel) | Context.InIteration,
LabelledFunctionStatement.Disallow
);

return isOf
? {
type: 'ForOfStatement',
Expand All @@ -1495,7 +1495,7 @@ export function parseForStatement(
if (!isVarDecl) {
init = parseAssignmentExpression(parser, context | Context.DisallowInContext, init);

if (parser.destructible & DestructuringKind.Required) report(parser, Errors.ForLoopInvalidLHS);
if (destructible & DestructuringKind.Required) report(parser, Errors.ForLoopInvalidLHS);
}

if (parser.token === Token.Comma) init = parseSequenceExpression(parser, context, init);
Expand Down Expand Up @@ -3171,7 +3171,7 @@ export function parseArrayExpressionOrPattern(
if (parser.assignable & AssignmentKind.NotAssignable) {
destructible |= DestructuringKind.NotDestructible;
}
} else if (destructible & DestructuringKind.Required) {
} else if (parser.destructible & DestructuringKind.Required) {
report(parser, Errors.InvalidDestructuringTarget);
} else {
left = parseMemberOrUpdateExpression(parser, context, left, /* assignable */ 0);
Expand Down Expand Up @@ -3403,7 +3403,7 @@ function parseRestOrSpreadElement(
argument = parseAssignmentExpression(parser, context, argument);
}

destructible =
destructible |=
parser.assignable & AssignmentKind.Assignable
? DestructuringKind.Assignable
: DestructuringKind.NotDestructible;
Expand Down Expand Up @@ -3705,21 +3705,16 @@ export function parseObjectLiteralOrPattern(

if (parser.token === Token.Comma || parser.token === Token.RightBrace) {
if (parser.assignable & AssignmentKind.NotAssignable) destructible |= DestructuringKind.NotDestructible;
} else if (destructible & DestructuringKind.Required) {
} else if (parser.destructible & DestructuringKind.Required) {
report(parser, Errors.InvalidDestructuringTarget);
} else {
value = parseMemberOrUpdateExpression(parser, context, value, /* inNewExpression */ 0);

destructible =
parser.assignable & AssignmentKind.Assignable
? DestructuringKind.Assignable
: DestructuringKind.NotDestructible;
destructible = parser.assignable & AssignmentKind.NotAssignable ? DestructuringKind.NotDestructible : 0;

const { token } = parser;

if (token !== Token.Comma && token !== Token.RightBrace) {
if (token !== Token.Assign) destructible |= DestructuringKind.NotDestructible;

value = parseAssignmentExpression(
parser,
(context | Context.DisallowInContext) ^ Context.DisallowInContext,
Expand Down
69 changes: 69 additions & 0 deletions test/parser/declarations/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,75 @@ describe('Declarations - Function', () => {
sourceType: 'script'
}
],
[
'function a([ { a = x }, {} = b]) {}',
Context.None,
{
type: 'Program',
sourceType: 'script',
body: [
{
type: 'FunctionDeclaration',
params: [
{
type: 'ArrayPattern',
elements: [
{
type: 'ObjectPattern',
properties: [
{
type: 'Property',
kind: 'init',
key: {
type: 'Identifier',
name: 'a'
},
computed: false,
value: {
type: 'AssignmentPattern',
left: {
type: 'Identifier',
name: 'a'
},
right: {
type: 'Identifier',
name: 'x'
}
},
method: false,
shorthand: true
}
]
},
{
type: 'AssignmentPattern',
left: {
type: 'ObjectPattern',
properties: []
},
right: {
type: 'Identifier',
name: 'b'
}
}
]
}
],
body: {
type: 'BlockStatement',
body: []
},
async: false,
generator: false,
expression: false,
id: {
type: 'Identifier',
name: 'a'
}
}
]
}
],
[
'function f(){} function f(){}',
Context.None,
Expand Down
6 changes: 6 additions & 0 deletions test/parser/expressions/arrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,11 @@ describe('Expressions - Arrow', () => {
['((x, y)) => 0', Context.None],
['(x, (y)) => 0', Context.None],
['((x, y, z)) => 0', Context.None],
['([...x.y]) => z', Context.None],
['([...(x), y] = z) => 0', Context.None],
['((x, y, z)) => 0', Context.None],
['((x, y, z)) => 0', Context.None],
['((x, y, z)) => 0', Context.None],
['([...x.y] = z) => z', Context.None],
['(x, (y, z)) => 0', Context.None],
['((x, y), z) => 0', Context.None],
Expand Down Expand Up @@ -1075,6 +1080,7 @@ describe('Expressions - Arrow', () => {
`() => {}
a()
async()`,
`(z = [...x.y]) => z`,
`a => a => a => async a => a`,
`a => a => a => a => a => a => a => a => a => a => a => a => a => a => a => async a => a`,
'var f = (function() { return z => arguments[0]; }(5));'
Expand Down
89 changes: 89 additions & 0 deletions test/parser/expressions/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,95 @@ describe('Expressions - Class', () => {
]
}
],
[
'class a extends [] { static set [a] ({w=a}) { for (;;) a } }',
Context.None,
{
type: 'Program',
sourceType: 'script',
body: [
{
type: 'ClassDeclaration',
id: {
type: 'Identifier',
name: 'a'
},
superClass: {
type: 'ArrayExpression',
elements: []
},
body: {
type: 'ClassBody',
body: [
{
type: 'MethodDefinition',
kind: 'set',
static: true,
computed: true,
key: {
type: 'Identifier',
name: 'a'
},
value: {
type: 'FunctionExpression',
params: [
{
type: 'ObjectPattern',
properties: [
{
type: 'Property',
kind: 'init',
key: {
type: 'Identifier',
name: 'w'
},
computed: false,
value: {
type: 'AssignmentPattern',
left: {
type: 'Identifier',
name: 'w'
},
right: {
type: 'Identifier',
name: 'a'
}
},
method: false,
shorthand: true
}
]
}
],
body: {
type: 'BlockStatement',
body: [
{
type: 'ForStatement',
body: {
type: 'ExpressionStatement',
expression: {
type: 'Identifier',
name: 'a'
}
},
init: null,
test: null,
update: null
}
]
},
async: false,
generator: false,
id: null
}
}
]
}
}
]
}
],
[
'class x extends {} {}',
Context.None,
Expand Down
15 changes: 7 additions & 8 deletions test/parser/miscellaneous/failure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ describe('Miscellaneous - Failure', () => {
`for (a);`,
'(((x)))\n++;',
'(((x)))\n--;',
// `[...(x), y] = z`,
`[...(x), y] = z`,
'function* g() { async function yield() {} }',
'async function k() { function a() { await 4; } }',
'function* a() { await 4; }',
Expand Down Expand Up @@ -983,7 +983,6 @@ describe('Miscellaneous - Failure', () => {
`function* wrap() {\n(a = yield b) => a\n}`,
`class B { constructor(a = super()) { return a }}`,
`({*foo: 1})`,
`for (let x of y, z) {}`,
`for (let [...foo, bar] in qux);`,
'(class A extends B { method() { super() } })',
'for(;;) function a(){}',
Expand Down Expand Up @@ -1953,14 +1952,14 @@ describe('Miscellaneous - Failure', () => {
'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(){ 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(){ 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 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
9 changes: 8 additions & 1 deletion test/parser/miscellaneous/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ describe('Miscellaneous - Cover grammar', () => {
'[this = 1]',
'var {a};',
'[new.target]',
`({"x": [y].z(0)})`,
`({"x": [y].z(0)} = x)`,
`({"x": [y].z(0)}) => x`,
'[new.target = 1]',
'[import.meta]',
'var [a.b] = 0',
Expand All @@ -267,8 +270,11 @@ describe('Miscellaneous - Cover grammar', () => {
'[async function f() {}]',
'[function* f() {}]',
'([arguments] = []);',
'({a: {a=b}.x}) => x',
'([{a=b}.x]) => x',
'[{ get x() {} }] = [{}];',
'[...x, y] = [];',
`({ident: {x}.join("")}) => x`,
'[...[(x, y)]] = [[]];',
'"use strict"; ({ eval } = {});',
'assignmentResult = { x: x = yield } = value;',
Expand Down Expand Up @@ -2702,7 +2708,8 @@ describe('Miscellaneous - Cover grammar', () => {
'for (const x of [ a[i++] = () => eval("x") ]) { b[j++] = () => eval("x"); }',
'((a, { b = 0, c = 3 }) => { return a === 1 && b === 2 && c === 3; })(1, { b: 2 });',
'((a, x) => { let { b = 0, c = 3 } = y; return a === 1 && b === 2 && c === 3; })(1, { b: 2 });',
'({ [key]: y, z, ...x } = {2: "two", z: "zee"});'
'({ [key]: y, z, ...x } = {2: "two", z: "zee"});',
'({...x}[y])'
]) {
it(` ${arg}`, () => {
t.doesNotThrow(() => {
Expand Down
40 changes: 1 addition & 39 deletions test/parser/miscellaneous/pass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,44 +19,7 @@ describe('Miscellaneous - Pass', () => {
'function f() { function f() {} }',
'function f(a,b) {}',
`class x extends {} {}`,
'for (C = class { get ["x" in empty]() { return "via get"; } }; ; ) { break; }',
`for (;;);`,
`for (a+b;;) c;`,
`for (var x of y);`,
`for (var x;;);`,
`for (;;);`,
`for (x in y);`,
`for (x of y);`,
'for (var x of y);',
`for (var x;;);`,
`for (let x of y);`,
`for (let x;;);`,
`for (let x of y);`,
`for (let x of y);`,
`for (let [x] in y);`,
`for (let {x} of y);`,
`for (let x of y);`,
`for (let {x} = x;;);`,
`for (let [x] = x;;);`,
`for (let x;;);`,
`for (let {x} of y);`,
`for (let [x] in y);`,
`for (let in x);`,
`for (let in x) {}`,
`for (let x of y);`,
`for (let[x] in y);`,
`for (let[x] of y);`,
`for (let , x;;);`,
`for (let + x;;);`,
`for (let.x;;);`,
`for (let.foo in x);`,
`for (let();;);`,
`for (let().foo in x);`,
`for (let=10;;);`,
`for (let.foo;;);`,
`for (let;;);`,
`for (const x of y);`,
`for (let.x in y);`,
'[...(x), y]',
`class MyClass {
async asyncMethod(a) { return a; }
async async(a) { return a; }
Expand Down Expand Up @@ -151,7 +114,6 @@ describe('Miscellaneous - Pass', () => {
'for ([] instanceof obj;;);',
'for (12 instanceof obj;;);',
'for (a instanceof b;;);',
'[...(x), y]',
`[...a, b]`,
`[...(x), y]`,
`({a: b = x} = d)`,
Expand Down
Loading

0 comments on commit 9854a83

Please sign in to comment.