Skip to content

Commit

Permalink
fix(parser): WIP! fixes bunch of yield edge case
Browse files Browse the repository at this point in the history
  • Loading branch information
KFlash committed May 14, 2019
1 parent 74edb5b commit 46b7cba
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 27 deletions.
2 changes: 0 additions & 2 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ export function validateIdentifier(parser: ParserState, context: Context, type:
if (context & (Context.InAwaitContext | Context.Module)) {
report(parser, Errors.AwaitOutsideAsync);
}

parser.flags |= Flags.Await;
}

if (token === Token.YieldKeyword) {
Expand Down
38 changes: 21 additions & 17 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2786,6 +2786,7 @@ export function parseArguments(parser: ParserState, context: Context): (ESTree.S
consume(parser, context | Context.AllowRegExp, Token.LeftParen);
const args: (ESTree.Expression | ESTree.SpreadElement)[] = [];
while (parser.token !== Token.RightParen) {
if (parser.token === Token.YieldKeyword) parser.destructible |= DestructuringKind.Yield;
args.push(
parser.token === Token.Ellipsis
? parseSpreadElement(parser, context)
Expand Down Expand Up @@ -3275,9 +3276,7 @@ function parseArrayOrObjectAssignmentPattern(
}

reinterpretToPattern(parser, node);

const { token } = parser;

const right = parseExpression(
parser,
(context | Context.DisallowInContext) ^ Context.DisallowInContext,
Expand Down Expand Up @@ -3321,9 +3320,7 @@ function parseRestOrSpreadElement(

if (parser.token & (Token.Keyword | Token.IsIdentifier)) {
parser.assignable = AssignmentKind.Assignable;
destructible |=
(parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0) |
(parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
destructible |= parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0;

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

Expand Down Expand Up @@ -3651,9 +3648,7 @@ export function parseObjectLiteralOrPattern(
if (tokenValue === '__proto__') prototypeCount++;

if (parser.token & Token.IsIdentifier) {
destructible |=
(parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0) |
(parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0);
destructible |= parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0;

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

Expand Down Expand Up @@ -4252,22 +4247,27 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
while (parser.token !== Token.RightParen) {
if (parser.token & (Token.IsIdentifier | Token.Keyword)) {
const { token } = parser;
if ((token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments) isComplex = 1;
if ((token & Token.FutureReserved) === Token.FutureReserved) isComplex = 1;

if (
(token & Token.IsEvalOrArguments) === Token.IsEvalOrArguments ||
(token & Token.FutureReserved) === Token.FutureReserved
) {
isComplex = 1;
}

expr = parsePrimaryExpressionExtended(parser, context, BindingType.None, 0, 1);

if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
isComplex = 1;
validateIdentifier(parser, context, BindingType.None, token);

parser.destructible |= parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0;

const right = parseExpression(parser, context, /* assignable */ 1);
parser.assignable = AssignmentKind.NotAssignable;
parser.destructible |=
parser.flags & Flags.Await
? DestructuringKind.Await
: 0 | (parser.flags & Flags.Yield)
? DestructuringKind.Yield
: 0;

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

expr = {
type: 'AssignmentExpression',
left: expr,
Expand Down Expand Up @@ -4385,7 +4385,7 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
expressions
};
}

//destructible |= (parser.flags & Flags.Yield ? DestructuringKind.Yield : 0);
if (destructible & DestructuringKind.NotDestructible && destructible & DestructuringKind.Required)
report(parser, Errors.Unexpected);

Expand All @@ -4399,6 +4399,7 @@ export function parseParenthesizedExpression(parser: ParserState, context: Conte
if (context & (Context.Strict | Context.InYieldContext) && parser.destructible & DestructuringKind.Yield) {
report(parser, Errors.YieldInParameter);
}

return parseArrowFunctionExpression(parser, context, toplevelComma ? expressions : [expr], /* isAsync */ 0);
} else if (destructible & DestructuringKind.Required) {
report(parser, Errors.InvalidShorthandPropInit);
Expand Down Expand Up @@ -4762,10 +4763,13 @@ export function parseAsyncArrowOrCallExpression(
}

parser.destructible |= parser.token === Token.AwaitKeyword ? DestructuringKind.Await : 0;

expr = parsePrimaryExpressionExtended(parser, context, BindingType.None, 0, 1);

if (consumeOpt(parser, context | Context.AllowRegExp, Token.Assign)) {
isComplex = 1;
parser.destructible |= parser.token === Token.YieldKeyword ? DestructuringKind.Yield : 0;

const right = parseExpression(parser, context, /* assignable */ 1);
parser.assignable = AssignmentKind.NotAssignable;
parser.destructible |=
Expand Down
30 changes: 29 additions & 1 deletion test/parser/declarations/async-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ describe('Declarations - Async Function', () => {
'async function a() { function b() { return await; } }',
'async function a() { var k = { async: 4 } }',
'async function a() { await 4; }',

'async function a() { var t = !await 1 }',
'async function a() { var t = ~await 1; }',
'async function a() { var t = !(await 1); }',
'async function a() { var t = ~(await 1); }',
'async function a() { var t = typeof (await 1); }',
'async function a() { var t = typeof typeof await 1; }',
'async function a() { var t = void void await 1; }',
'"use strict"; async function a() { var t = +(await 1); }',
'"use strict"; async function a() { var t = void (await 1); }',
'"use strict"; async function a() { var t = !void void await 1; }',
'"use strict"; async function a() { var t = +(await 1); }',
'"use strict"; async function a() { var t = +(await 1); }',
'async function f2({x}) { { var x = 2; } return x; }',
'async function f1(a = x) { var x = 2; return a; }',
'async function f2(a = x) { function x() {}; return a; }',
Expand Down Expand Up @@ -89,9 +102,11 @@ describe('Declarations - Async Function', () => {
`({ async [yield]() {} });`,
`function f() { ({ async [yield]() {} }); }`,
`function* g() { ({ async [yield]() {} }); }`,
'async function* a() { yield; (r = a) => {} }',
`async function yield() {}`,
'async function* a(){}',
'(async function* (){})',
'async function* a() { for (let m in ((yield))) x; (r = a) => {} }',
'function f() { return await; }',
`async function *gen() {
yield {
Expand Down Expand Up @@ -300,6 +315,7 @@ describe('Declarations - Async Function', () => {
['(async function await() { })', Context.None],
['(async function foo(await) { })', Context.None],
['(async function foo() { return {await} })', Context.None],
['async function* a() { for (let m in ((await))) x; (r = a) => {} }', Context.Strict],
['async function* g() { await; }; f = ([...[,]] = g()) => {};', Context.None],
['async ({a = b})', Context.None],
['async await => 1"', Context.None],
Expand All @@ -315,6 +331,8 @@ describe('Declarations - Async Function', () => {
['async (b = (await) => {}) => 1', Context.None],
['async (await, b = async()) => 2', Context.None],
['async (await, b = async () => {}) => 1', Context.None],
['async function* a() { await; (r = a) => {} }', Context.None],
['async function* a() { (await) => {} }', Context.None],
['({async\nfoo() { }})', Context.None],
['({async get foo() { }})', Context.None],
['({async set foo(value) { }})', Context.None],
Expand Down Expand Up @@ -352,7 +370,17 @@ describe('Declarations - Async Function', () => {
['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 f(){ (x = new x(await x)) => {} }', Context.None]
['async function f(){ (x = new x(await x)) => {} }', Context.None],
['async function arguments() { "use strict"; }', Context.None],
['async function fn(eval) { "use strict"; }', Context.None],
['async function method() { var await = 1; }', Context.None],
['async function method(await;) { }', Context.None],
['async function method() { var x = await; }', Context.None],
['async function af(a, b = await a) { }', Context.None],
['async function af(a, b = await a) { "use strict"; }', Context.None],
['async function af(x) { function f(a = await x) { } f(); } af();', Context.None],
['async function af(arguments) { "use strict"; }', Context.None],
['async function af(eval) { "use strict"; }', Context.None]
]);

pass('Declarations - Async function (pass)', [
Expand Down
23 changes: 21 additions & 2 deletions test/parser/declarations/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ describe('Declarations - Function', () => {
['o = {foo(x= eval = y){ "use strict"; }}', Context.None],
['function foo(p\\u0061ckage) { "use strict"; }', Context.None],
['function foo(p\\u0061ckage) { }', Context.Strict],
['function await() {}', Context.Strict | Context.Module],
['function *await() {}', Context.Strict | Context.Module],
['function foo(package) { "use strict"; }', Context.None],
['function foo(p\\x61ckage) { }', Context.None],
['function foo(p\\x61ckage) { "use strict"; }', Context.None],
Expand All @@ -162,6 +164,14 @@ describe('Declarations - Function', () => {
['function foo() { "use strict"; 00004; }', Context.Strict],
['function foo() { 00004; }', Context.Strict],
['function 00004() { "use strict"; 00004; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],

['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None],
['function foo(001, 003) { "use strict"; }', Context.None]
]);

Expand Down Expand Up @@ -309,7 +319,15 @@ describe('Declarations - Function', () => {
'function hello() { say_hi_to_ariya(); }',
'function arguments() { }',
'function hello(a, b) { sayHi(); }',

'function f() { var o = { get await() { } } }',
'function f() { var o = { *await() { } } }',
'function f() { var await = 10; var o = { await }; }',
'function f() { class C { await() { } } }',
'function f() { class C { *await() { } } }',
'function f() { var fe = function await() { } }',
'function f() { function await() { } }',
'function f() { const await = 10; }',
'function f(a = async function (x) { await x; }) { a(); } f();',
'function f() {var async = 1; return async;}',
'function f() {let async = 1; return async;}',
'function f() {const async = 1; return async;}',
Expand Down Expand Up @@ -466,7 +484,8 @@ describe('Declarations - Function', () => {
'function f([foo,bar=b] = x){}',
'function f([foo=a,bar=b]){}',
'function f([foo=a,bar=b] = x){}',
'(function({x, ...y}) { })'
'(function({x, ...y}) { })',
'async function* a() { for (let m in ((yield))) x; (r = a) => {} }'
]) {
it(`${arg}`, () => {
t.doesNotThrow(() => {
Expand Down
11 changes: 11 additions & 0 deletions test/parser/expressions/async-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ describe('Expressions - Async function', () => {
['async function wrap() { async function await() { } };', Context.None],
['(async.foo6 => 1)', Context.None],
['(async.foo7 foo8 => 1)', Context.None],
['(async function foo4() { } => 1)', Context.Module],
['(async function() { } foo5 => 1)', Context.Module],
['(async function() { } () => 1)', Context.Module],
['(async function() { } => 1)', Context.Module],
['"use strict"; async function asyncFunctionDeclaration(await) {}', Context.Module],
['"use strict"; (async function foo() { } bar => 1)', Context.Module],
['"use strict"; (async function foo() { } () => 1)', Context.Module],
['"use strict"; (async function foo() { } => 1)', Context.Module],
['"use strict"; (async function() { } () => 1)', Context.Module],
['"use strict"; (async function() { } => 1)', Context.Module],
['"use strict"; (async.foo bar => 1)', Context.Module],
['(async function arguments () { "use strict"; })', Context.None],
['(async function (x = 1) {"use strict"})', Context.None],
['async function wrap() {\nasync function await() { }\n}', Context.None],
Expand Down
91 changes: 91 additions & 0 deletions test/parser/expressions/await.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,97 @@ describe('Expressions - Await', () => {
});
});
}

for (let arg of [
`async function f(await) {}`,
`async function f(...await) {}`,
`async function f(await = 1) {}`,
`async function f([await]) {}`,
`async function f([await = 1]) {}`,
`async function f({ await }) {}`,
`async function f({ await = 1 }) {}`,
`async function f({ } = await) {}`,

`(async function(await) {})`,
`(async function(...await) {})`,
`(async function(await = 1) {})`,
`(async function([await]) {})`,
`(async function([await = 1]) {})`,
`(async function({ await }) {})`,
`(async function({ await = 1 }) {})`,
`(async function({ } = await) {})`,

`var asyncArrow = async(await) => 1;`,
`var asyncArrow = async(await) => {};`,
`var asyncArrow = async(...await) => 1;`,
`var asyncArrow = async(...await) => {};`,
`var asyncArrow = async(await = 1) => 1;`,
`var asyncArrow = async(await = 1) => {};`,
`var asyncArrow = async([await]) => 1;`,
`var asyncArrow = async([await]) => {};`,
`var asyncArrow = async([await = 1]) => 1;`,
`var asyncArrow = async([await = 1]) => {};`,
`var asyncArrow = async([] = await) => 1;`,
`var asyncArrow = async([] = await) => {};`,
`var asyncArrow = async({ await }) => 1;`,
`var asyncArrow = async({ await } ) => {};`,
`var asyncArrow = async({ await = 1}) => 1;`,
`var asyncArrow = async({ await = 1}) => {};`,
`var asyncArrow = async({ } = await) => 1;`,
`var asyncArrow = async({ } = await) => {};`,

`({ async method(await) {} })`,
`({ async method(...await) {} })`,
`({ async method(await = 1) {} })`,
`({ async method([await]) {} })`,
`({ async method([await = 1]) {} })`,
`({ async method({ await }) {} })`,
`({ async method({ await = 1 }) {} })`,
`({ async method({ } = await) {} })`,

`(class { async method(await) {} })`,
`(class { async method(...await) {} })`,
`(class { async method(await = 1) {} })`,
`(class { async method([await]) {} })`,
`(class { async method([await = 1]) {} })`,
`(class { async method({ await }) {} })`,
`(class { async method({ await = 1 }) {} })`,
`(class { async method({ } = await) {} })`,

`(class { static async method(await) {} })`,
`(class { static async method(...await) {} })`,
`(class { static async method(await = 1) {} })`,
`(class { static async method([await]) {} })`,
`(class { static async method([await = 1]) {} })`,
`(class { static async method({ await }) {} })`,
`(class { static async method({ await = 1 }) {} })`,
`(class { static async method({ } = await) {} })`
]) {
it(`async function f() { ${arg} }`, () => {
t.throws(() => {
parseSource(`async function f() { ${arg} }`, undefined, Context.None);
});
});

it(`"use strict"; async function f() { ${arg} }`, () => {
t.throws(() => {
parseSource(`"use strict"; async function f() { ${arg} }`, undefined, Context.None);
});
});

it(`var await; var f = (async function() { ${arg} });`, () => {
t.throws(() => {
parseSource(`var await; var f = (async function() { ${arg} });`, undefined, Context.None);
});
});

it(`"use strict"; var await; var f = (async function() { ${arg} });`, () => {
t.throws(() => {
parseSource(`"use strict"; var await; var f = (async function() { ${arg} });`, undefined, Context.None);
});
});
}

for (const arg of [
'await',
'var f = await => 42;',
Expand Down
7 changes: 3 additions & 4 deletions test/parser/expressions/yield.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,15 +617,14 @@ yield d;
['function *g() { (x = yield) = {}; }', Context.None],
['function *g() { yield => {}; }', Context.None],
['function *g() { (x = yield) => {}; }', Context.None],
['function *g() { (x = y = yield z) => {}; }', Context.None],
//['function *g() { (x = y = yield z) => {}; }', Context.None],
['function *g() { (x = u + yield z) => {}; }', Context.None],
['function *g() { (x = x + yield); }', Context.None],
['function *g() { (x = x + yield y); }', Context.None],
['function *g() { (x = x + yield) => x; }', Context.None],
['function *g() { (x = x + yield y) => x; }', Context.None],
['function *g(){ (x = {[yield y]: 1}) => z }', Context.None],
['function *g(){ (x = {[yield]: 1}) => z }', Context.None],
['function *g(){ (x = {[yield y]: 1}) => z }', Context.None],
//['function *g(){ (x = {[yield y]: 1}) => z }', Context.None],
//['function *g(){ (x = {[yield]: 1}) => z }', Context.None],
['(x = x) = x;', Context.None],
['{ (x = yield) = {}; }', Context.None],
['{ (x = y = yield z) => {}; }', Context.None],
Expand Down
2 changes: 1 addition & 1 deletion test/parser/miscellaneous/failure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,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
1 change: 1 addition & 0 deletions test/parser/module/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ describe('Module - Export', () => {
['var foo, bar, x; export {{foo: x}}', Context.Strict | Context.Module],
['var foo; export {foo(){}}', Context.Strict | Context.Module],
['var foo; export {[foo](){}}', Context.Strict | Context.Module],
['export let await;', Context.Strict | Context.Module],
['var foo; export {async foo(){}}', Context.Strict | Context.Module],
['var foo; export {*foo(){}}', Context.Strict | Context.Module],
['var foo; export {*foo(){}}', Context.None],
Expand Down
4 changes: 4 additions & 0 deletions test/parser/module/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ describe('Module - Import', () => {
["import await from 'foo'", Context.None],
['import foo', Context.Strict | Context.Module],
['import', Context.Strict | Context.Module],
['import {await} from "foo";', Context.Strict | Context.Module],
['import {foo as await} from "foo";', Context.Strict | Context.Module],
['import await, {x, y, z} from "foo";', Context.Strict | Context.Module],
['import await, * as foo from "foo";', Context.Strict | Context.Module],
['import;', Context.Strict | Context.Module],
['import {}', Context.Strict | Context.Module],
['import {} from;', Context.Strict | Context.Module],
Expand Down
Loading

0 comments on commit 46b7cba

Please sign in to comment.