Skip to content

Commit

Permalink
Disallow await in function parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed May 14, 2018
1 parent dca2631 commit 6ebdcf6
Show file tree
Hide file tree
Showing 23 changed files with 693 additions and 32 deletions.
98 changes: 71 additions & 27 deletions packages/babylon/src/parser/expression.js
Expand Up @@ -533,10 +533,15 @@ export default class ExpressionParser extends LValParser {
}
return this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.match(tt.parenL)) {
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
this.state.maybeInArrowParameters = true;
this.state.yieldOrAwaitInPossibleArrowParameters = null;

const possibleAsync = this.atPossibleAsync(base);
this.next();

const node = this.startNodeAt(startPos, startLoc);
let node = this.startNodeAt(startPos, startLoc);
node.callee = base;

// TODO: Clean up/merge this into `this.state` or a class like acorn's
Expand Down Expand Up @@ -565,13 +570,22 @@ export default class ExpressionParser extends LValParser {
);
}

return this.parseAsyncArrowFromCallExpression(
node = this.parseAsyncArrowFromCallExpression(
this.startNodeAt(startPos, startLoc),
node,
);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
} else {
this.toReferencedList(node.arguments);

// We keep the old value if it isn't null, for cases like
// (x = async(yield)) => {}
this.state.yieldOrAwaitInPossibleArrowParameters =
this.state.yieldOrAwaitInPossibleArrowParameters || oldYOAIPAP;
}

this.state.maybeInArrowParameters = oldMaybeInArrowParameters;

return node;
} else if (this.match(tt.backQuote)) {
const node = this.startNodeAt(startPos, startLoc);
Expand Down Expand Up @@ -677,11 +691,8 @@ export default class ExpressionParser extends LValParser {
node: N.ArrowFunctionExpression,
call: N.CallExpression,
): N.ArrowFunctionExpression {
const oldYield = this.state.yieldInPossibleArrowParameters;
this.state.yieldInPossibleArrowParameters = null;
this.expect(tt.arrow);
this.parseArrowExpression(node, call.arguments, true);
this.state.yieldInPossibleArrowParameters = oldYield;
return node;
}

Expand Down Expand Up @@ -787,21 +798,24 @@ export default class ExpressionParser extends LValParser {
this.next();
return this.parseFunction(node, false, false, true);
} else if (canBeArrow && id.name === "async" && this.match(tt.name)) {
const oldYield = this.state.yieldInPossibleArrowParameters;
this.state.yieldInPossibleArrowParameters = null;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
const oldInAsync = this.state.inAsync;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.state.inAsync = true;
const params = [this.parseIdentifier()];
this.expect(tt.arrow);
// let foo = bar => {};
this.parseArrowExpression(node, params, true);
this.state.yieldInPossibleArrowParameters = oldYield;
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
this.state.inAsync = oldInAsync;
return node;
}

if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
const oldYield = this.state.yieldInPossibleArrowParameters;
this.state.yieldInPossibleArrowParameters = null;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.parseArrowExpression(node, [id]);
this.state.yieldInPossibleArrowParameters = oldYield;
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
return node;
}

Expand Down Expand Up @@ -1024,9 +1038,9 @@ export default class ExpressionParser extends LValParser {
this.expect(tt.parenL);

const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYield = this.state.yieldInPossibleArrowParameters;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
this.state.maybeInArrowParameters = true;
this.state.yieldInPossibleArrowParameters = null;
this.state.yieldOrAwaitInPossibleArrowParameters = null;

const innerStartPos = this.state.start;
const innerStartLoc = this.state.startLoc;
Expand Down Expand Up @@ -1099,11 +1113,14 @@ export default class ExpressionParser extends LValParser {
}

this.parseArrowExpression(arrowNode, exprList);
this.state.yieldInPossibleArrowParameters = oldYield;
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
return arrowNode;
}

this.state.yieldInPossibleArrowParameters = oldYield;
// We keep the old value if it isn't null, for cases like
// (x = (yield)) => {}
this.state.yieldOrAwaitInPossibleArrowParameters =
this.state.yieldOrAwaitInPossibleArrowParameters || oldYOAIPAP;

if (!exprList.length) {
this.unexpected(this.state.lastTokStart);
Expand Down Expand Up @@ -1601,9 +1618,11 @@ export default class ExpressionParser extends LValParser {
): T {
const oldInFunc = this.state.inFunction;
const oldInMethod = this.state.inMethod;
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
this.state.inFunction = true;
this.state.inMethod = node.kind || true;
this.state.inAsync = isAsync;
this.state.inGenerator = isGenerator;

this.initFunction(node, isAsync);
Expand All @@ -1614,6 +1633,7 @@ export default class ExpressionParser extends LValParser {

this.state.inFunction = oldInFunc;
this.state.inMethod = oldInMethod;
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;

return node;
Expand All @@ -1629,24 +1649,36 @@ export default class ExpressionParser extends LValParser {
): N.ArrowFunctionExpression {
// if we got there, it's no more "yield in possible arrow parameters";
// it's just "yield in arrow parameters"
if (this.state.yieldInPossibleArrowParameters) {
this.raise(
this.state.yieldInPossibleArrowParameters.start,
"yield is not allowed in the parameters of an arrow function" +
" inside a generator",
);
const yOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
if (yOAIPAP) {
if (yOAIPAP.type === "YieldExpression") {
this.raise(
yOAIPAP.start,
"yield is not allowed in the parameters of an arrow function" +
" inside a generator",
);
} else {
this.raise(
yOAIPAP.start,
"await is not allowed in the parameters of an arrow function" +
" inside an async function",
);
}
}

const oldInFunc = this.state.inFunction;
this.state.inFunction = true;
this.initFunction(node, isAsync);
if (params) this.setArrowFunctionParameters(node, params);

const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
this.state.inAsync = true;
this.state.inGenerator = false;
this.state.maybeInArrowParameters = false;
this.parseFunctionBody(node, true);
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
this.state.inFunction = oldInFunc;
this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
Expand Down Expand Up @@ -1694,9 +1726,7 @@ export default class ExpressionParser extends LValParser {
const isExpression = allowExpression && !this.match(tt.braceL);

const oldInParameters = this.state.inParameters;
const oldInAsync = this.state.inAsync;
this.state.inParameters = false;
this.state.inAsync = node.async;

if (isExpression) {
node.body = this.parseMaybeAssign();
Expand All @@ -1714,7 +1744,6 @@ export default class ExpressionParser extends LValParser {
this.state.inGenerator = oldInGen;
this.state.labels = oldLabels;
}
this.state.inAsync = oldInAsync;

this.checkFunctionNameAndParams(node, allowExpression);
this.state.inParameters = oldInParameters;
Expand Down Expand Up @@ -1891,12 +1920,27 @@ export default class ExpressionParser extends LValParser {
) {
this.unexpected();
}
if (this.state.inParameters) {
this.raise(
node.start,
"await is not allowed in async function parameters",
);
}
if (this.match(tt.star)) {
this.raise(
node.start,
"await* has been removed from the async functions proposal. Use Promise.all() instead.",
);
}
if (
this.state.maybeInArrowParameters &&
// We only set yieldOrAwaitInPossibleArrowParameters if we haven't already
// found a possible invalid AwaitExpression.
!this.state.yieldOrAwaitInPossibleArrowParameters
) {
this.state.yieldOrAwaitInPossibleArrowParameters = node;
}

node.argument = this.parseMaybeUnary();
return this.finishNode(node, "AwaitExpression");
}
Expand All @@ -1911,11 +1955,11 @@ export default class ExpressionParser extends LValParser {
}
if (
this.state.maybeInArrowParameters &&
// We only set yieldInPossibleArrowParameters if we haven't already
// We only set yieldOrAwaitInPossibleArrowParameters if we haven't already
// found a possible invalid YieldExpression.
!this.state.yieldInPossibleArrowParameters
!this.state.yieldOrAwaitInPossibleArrowParameters
) {
this.state.yieldInPossibleArrowParameters = node;
this.state.yieldOrAwaitInPossibleArrowParameters = node;
}

this.next();
Expand Down
3 changes: 3 additions & 0 deletions packages/babylon/src/parser/statement.js
Expand Up @@ -821,10 +821,12 @@ export default class StatementParser extends ExpressionParser {
): T {
const oldInFunc = this.state.inFunction;
const oldInMethod = this.state.inMethod;
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldInClassProperty = this.state.inClassProperty;
this.state.inFunction = true;
this.state.inMethod = false;
this.state.inAsync = isAsync;
this.state.inClassProperty = false;

this.initFunction(node, isAsync);
Expand Down Expand Up @@ -869,6 +871,7 @@ export default class StatementParser extends ExpressionParser {

this.state.inFunction = oldInFunc;
this.state.inMethod = oldInMethod;
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
this.state.inClassProperty = oldInClassProperty;

Expand Down
10 changes: 5 additions & 5 deletions packages/babylon/src/tokenizer/state.js
Expand Up @@ -39,7 +39,7 @@ export default class State {

this.decoratorStack = [[]];

this.yieldInPossibleArrowParameters = null;
this.yieldOrAwaitInPossibleArrowParameters = null;

this.tokens = [];

Expand Down Expand Up @@ -122,10 +122,10 @@ export default class State {
// where @foo belongs to the outer class and @bar to the inner
decoratorStack: Array<Array<N.Decorator>>;

// The first yield expression inside parenthesized expressions and arrow
// function parameters. It is used to disallow yield in arrow function
// parameters.
yieldInPossibleArrowParameters: ?N.YieldExpression;
// The first yield or await expression inside parenthesized expressions
// and arrow function parameters. It is used to disallow yield and await in
// arrow function parameters.
yieldOrAwaitInPossibleArrowParameters: ?N.YieldExpression;

// Token store.
tokens: Array<Token | N.Comment>;
Expand Down
@@ -0,0 +1,3 @@
function* fn() {
(x = (yield)) => {};
}
@@ -0,0 +1,3 @@
{
"throws": "yield is not allowed in the parameters of an arrow function inside a generator (2:8)"
}
@@ -0,0 +1,3 @@
async function fn() {
function g(x = await) {}
}

0 comments on commit 6ebdcf6

Please sign in to comment.