Refactor [In] production parameter tracking (#11930)

* refactor: track [In] parameter in prodParam

* Apply suggestions from code review
This commit is contained in:
Huáng Jùnliàng 2020-08-10 07:32:38 -04:00 committed by GitHub
parent fccf31aca6
commit 4bb1e164da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 106 deletions

View File

@ -44,6 +44,7 @@ import {
import { ExpressionErrors } from "./util"; import { ExpressionErrors } from "./util";
import { import {
PARAM_AWAIT, PARAM_AWAIT,
PARAM_IN,
PARAM_RETURN, PARAM_RETURN,
PARAM, PARAM,
functionFlags, functionFlags,
@ -153,11 +154,9 @@ export default class ExpressionParser extends LValParser {
// the AST node that the inner parser gave them in another node. // the AST node that the inner parser gave them in another node.
// Parse a full expression. // Parse a full expression.
// - `noIn` // - `disallowIn`
// is used to forbid the `in` operator (in for loops initialization expressions) // is used to forbid the `in` operator (in for loops initialization expressions)
// When `noIn` is true, the production parameter [In] is not present. // When `disallowIn` is true, the production parameter [In] is not present.
// Whenever [?In] appears in the right-hand sides of a production, we pass
// `noIn` to the subroutine calls.
// - `refExpressionErrors ` // - `refExpressionErrors `
// provides reference for storing '=' operator inside shorthand // provides reference for storing '=' operator inside shorthand
@ -165,19 +164,28 @@ export default class ExpressionParser extends LValParser {
// and object pattern might appear (so it's possible to raise // and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position). // delayed syntax error at correct position).
// https://tc39.es/ecma262/#prod-Expression
parseExpression( parseExpression(
noIn?: boolean, disallowIn?: boolean,
refExpressionErrors?: ExpressionErrors, refExpressionErrors?: ExpressionErrors,
): N.Expression { ): N.Expression {
if (disallowIn) {
return this.disallowInAnd(() =>
this.parseExpressionBase(refExpressionErrors),
);
}
return this.allowInAnd(() => this.parseExpressionBase(refExpressionErrors));
}
// https://tc39.es/ecma262/#prod-Expression
parseExpressionBase(refExpressionErrors?: ExpressionErrors): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
const expr = this.parseMaybeAssign(noIn, refExpressionErrors); const expr = this.parseMaybeAssign(refExpressionErrors);
if (this.match(tt.comma)) { if (this.match(tt.comma)) {
const node = this.startNodeAt(startPos, startLoc); const node = this.startNodeAt(startPos, startLoc);
node.expressions = [expr]; node.expressions = [expr];
while (this.eat(tt.comma)) { while (this.eat(tt.comma)) {
node.expressions.push(this.parseMaybeAssign(noIn, refExpressionErrors)); node.expressions.push(this.parseMaybeAssign(refExpressionErrors));
} }
this.toReferencedList(node.expressions); this.toReferencedList(node.expressions);
return this.finishNode(node, "SequenceExpression"); return this.finishNode(node, "SequenceExpression");
@ -185,12 +193,41 @@ export default class ExpressionParser extends LValParser {
return expr; return expr;
} }
// Set [~In] parameter for assignment expression
parseMaybeAssignDisallowIn(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
) {
return this.disallowInAnd(() =>
this.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
);
}
// Set [+In] parameter for assignment expression
parseMaybeAssignAllowIn(
refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos,
) {
return this.allowInAnd(() =>
this.parseMaybeAssign(
refExpressionErrors,
afterLeftParse,
refNeedsArrowPos,
),
);
}
// Parse an assignment expression. This includes applications of // Parse an assignment expression. This includes applications of
// operators like `+=`. // operators like `+=`.
// https://tc39.es/ecma262/#prod-AssignmentExpression // https://tc39.es/ecma262/#prod-AssignmentExpression
parseMaybeAssign( parseMaybeAssign(
noIn?: ?boolean,
refExpressionErrors?: ?ExpressionErrors, refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function, afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
@ -199,7 +236,7 @@ export default class ExpressionParser extends LValParser {
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
if (this.isContextual("yield")) { if (this.isContextual("yield")) {
if (this.prodParam.hasYield) { if (this.prodParam.hasYield) {
let left = this.parseYield(noIn); let left = this.parseYield();
if (afterLeftParse) { if (afterLeftParse) {
left = afterLeftParse.call(this, left, startPos, startLoc); left = afterLeftParse.call(this, left, startPos, startLoc);
} }
@ -224,7 +261,6 @@ export default class ExpressionParser extends LValParser {
} }
let left = this.parseMaybeConditional( let left = this.parseMaybeConditional(
noIn,
refExpressionErrors, refExpressionErrors,
refNeedsArrowPos, refNeedsArrowPos,
); );
@ -250,7 +286,7 @@ export default class ExpressionParser extends LValParser {
this.checkLVal(left, undefined, undefined, "assignment expression"); this.checkLVal(left, undefined, undefined, "assignment expression");
this.next(); this.next();
node.right = this.parseMaybeAssign(noIn); node.right = this.parseMaybeAssign();
return this.finishNode(node, "AssignmentExpression"); return this.finishNode(node, "AssignmentExpression");
} else if (ownExpressionErrors) { } else if (ownExpressionErrors) {
this.checkExpressionErrors(refExpressionErrors, true); this.checkExpressionErrors(refExpressionErrors, true);
@ -263,31 +299,23 @@ export default class ExpressionParser extends LValParser {
// https://tc39.es/ecma262/#prod-ConditionalExpression // https://tc39.es/ecma262/#prod-ConditionalExpression
parseMaybeConditional( parseMaybeConditional(
noIn: ?boolean,
refExpressionErrors: ExpressionErrors, refExpressionErrors: ExpressionErrors,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
): N.Expression { ): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt; const potentialArrowAt = this.state.potentialArrowAt;
const expr = this.parseExprOps(noIn, refExpressionErrors); const expr = this.parseExprOps(refExpressionErrors);
if (this.shouldExitDescending(expr, potentialArrowAt)) { if (this.shouldExitDescending(expr, potentialArrowAt)) {
return expr; return expr;
} }
return this.parseConditional( return this.parseConditional(expr, startPos, startLoc, refNeedsArrowPos);
expr,
noIn,
startPos,
startLoc,
refNeedsArrowPos,
);
} }
parseConditional( parseConditional(
expr: N.Expression, expr: N.Expression,
noIn: ?boolean,
startPos: number, startPos: number,
startLoc: Position, startLoc: Position,
// FIXME: Disabling this for now since can't seem to get it to play nicely // FIXME: Disabling this for now since can't seem to get it to play nicely
@ -297,9 +325,9 @@ export default class ExpressionParser extends LValParser {
if (this.eat(tt.question)) { if (this.eat(tt.question)) {
const node = this.startNodeAt(startPos, startLoc); const node = this.startNodeAt(startPos, startLoc);
node.test = expr; node.test = expr;
node.consequent = this.parseMaybeAssign(); node.consequent = this.parseMaybeAssignAllowIn();
this.expect(tt.colon); this.expect(tt.colon);
node.alternate = this.parseMaybeAssign(noIn); node.alternate = this.parseMaybeAssign();
return this.finishNode(node, "ConditionalExpression"); return this.finishNode(node, "ConditionalExpression");
} }
return expr; return expr;
@ -308,10 +336,7 @@ export default class ExpressionParser extends LValParser {
// Start the precedence parser. // Start the precedence parser.
// https://tc39.es/ecma262/#prod-ShortCircuitExpression // https://tc39.es/ecma262/#prod-ShortCircuitExpression
parseExprOps( parseExprOps(refExpressionErrors: ExpressionErrors): N.Expression {
noIn: ?boolean,
refExpressionErrors: ExpressionErrors,
): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
const potentialArrowAt = this.state.potentialArrowAt; const potentialArrowAt = this.state.potentialArrowAt;
@ -321,7 +346,7 @@ export default class ExpressionParser extends LValParser {
return expr; return expr;
} }
return this.parseExprOp(expr, startPos, startLoc, -1, noIn); return this.parseExprOp(expr, startPos, startLoc, -1);
} }
// Parse binary operators with the operator precedence parsing // Parse binary operators with the operator precedence parsing
@ -335,10 +360,9 @@ export default class ExpressionParser extends LValParser {
leftStartPos: number, leftStartPos: number,
leftStartLoc: Position, leftStartLoc: Position,
minPrec: number, minPrec: number,
noIn: ?boolean,
): N.Expression { ): N.Expression {
let prec = this.state.type.binop; let prec = this.state.type.binop;
if (prec != null && (!noIn || !this.match(tt._in))) { if (prec != null && (this.prodParam.hasIn || !this.match(tt._in))) {
if (prec > minPrec) { if (prec > minPrec) {
const op = this.state.type; const op = this.state.type;
if (op === tt.pipeline) { if (op === tt.pipeline) {
@ -391,7 +415,7 @@ export default class ExpressionParser extends LValParser {
} }
} }
node.right = this.parseExprOpRightExpr(op, prec, noIn); node.right = this.parseExprOpRightExpr(op, prec);
this.finishNode( this.finishNode(
node, node,
logical || coalesce ? "LogicalExpression" : "BinaryExpression", logical || coalesce ? "LogicalExpression" : "BinaryExpression",
@ -409,13 +433,7 @@ export default class ExpressionParser extends LValParser {
throw this.raise(this.state.start, Errors.MixingCoalesceWithLogical); throw this.raise(this.state.start, Errors.MixingCoalesceWithLogical);
} }
return this.parseExprOp( return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec);
node,
leftStartPos,
leftStartLoc,
minPrec,
noIn,
);
} }
} }
return left; return left;
@ -424,11 +442,7 @@ export default class ExpressionParser extends LValParser {
// Helper function for `parseExprOp`. Parse the right-hand side of binary- // Helper function for `parseExprOp`. Parse the right-hand side of binary-
// operator expressions, then apply any operator-specific functions. // operator expressions, then apply any operator-specific functions.
parseExprOpRightExpr( parseExprOpRightExpr(op: TokenType, prec: number): N.Expression {
op: TokenType,
prec: number,
noIn: ?boolean,
): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
switch (op) { switch (op) {
@ -437,31 +451,27 @@ export default class ExpressionParser extends LValParser {
case "smart": case "smart":
return this.withTopicPermittingContext(() => { return this.withTopicPermittingContext(() => {
return this.parseSmartPipelineBody( return this.parseSmartPipelineBody(
this.parseExprOpBaseRightExpr(op, prec, noIn), this.parseExprOpBaseRightExpr(op, prec),
startPos, startPos,
startLoc, startLoc,
); );
}); });
case "fsharp": case "fsharp":
return this.withSoloAwaitPermittingContext(() => { return this.withSoloAwaitPermittingContext(() => {
return this.parseFSharpPipelineBody(prec, noIn); return this.parseFSharpPipelineBody(prec);
}); });
} }
// falls through // falls through
default: default:
return this.parseExprOpBaseRightExpr(op, prec, noIn); return this.parseExprOpBaseRightExpr(op, prec);
} }
} }
// Helper function for `parseExprOpRightExpr`. Parse the right-hand side of // Helper function for `parseExprOpRightExpr`. Parse the right-hand side of
// binary-operator expressions without applying any operator-specific functions. // binary-operator expressions without applying any operator-specific functions.
parseExprOpBaseRightExpr( parseExprOpBaseRightExpr(op: TokenType, prec: number): N.Expression {
op: TokenType,
prec: number,
noIn: ?boolean,
): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
@ -470,7 +480,6 @@ export default class ExpressionParser extends LValParser {
startPos, startPos,
startLoc, startLoc,
op.rightAssociative ? prec - 1 : prec, op.rightAssociative ? prec - 1 : prec,
noIn,
); );
} }
@ -1415,8 +1424,7 @@ export default class ExpressionParser extends LValParser {
break; break;
} else { } else {
exprList.push( exprList.push(
this.parseMaybeAssign( this.parseMaybeAssignAllowIn(
false,
refExpressionErrors, refExpressionErrors,
this.parseParenItem, this.parseParenItem,
refNeedsArrowPos, refNeedsArrowPos,
@ -1858,7 +1866,7 @@ export default class ExpressionParser extends LValParser {
if (this.eat(tt.colon)) { if (this.eat(tt.colon)) {
prop.value = isPattern prop.value = isPattern
? this.parseMaybeDefault(this.state.start, this.state.startLoc) ? this.parseMaybeDefault(this.state.start, this.state.startLoc)
: this.parseMaybeAssign(false, refExpressionErrors); : this.parseMaybeAssignAllowIn(refExpressionErrors);
return this.finishNode(prop, "ObjectProperty"); return this.finishNode(prop, "ObjectProperty");
} }
@ -1932,7 +1940,7 @@ export default class ExpressionParser extends LValParser {
): N.Expression | N.Identifier { ): N.Expression | N.Identifier {
if (this.eat(tt.bracketL)) { if (this.eat(tt.bracketL)) {
(prop: $FlowSubtype<N.ObjectOrClassMember>).computed = true; (prop: $FlowSubtype<N.ObjectOrClassMember>).computed = true;
prop.key = this.parseMaybeAssign(); prop.key = this.parseMaybeAssignAllowIn();
this.expect(tt.bracketR); this.expect(tt.bracketR);
} else { } else {
const oldInPropertyName = this.state.inPropertyName; const oldInPropertyName = this.state.inPropertyName;
@ -2049,7 +2057,12 @@ export default class ExpressionParser extends LValParser {
trailingCommaPos: ?number, trailingCommaPos: ?number,
): N.ArrowFunctionExpression { ): N.ArrowFunctionExpression {
this.scope.enter(SCOPE_FUNCTION | SCOPE_ARROW); this.scope.enter(SCOPE_FUNCTION | SCOPE_ARROW);
this.prodParam.enter(functionFlags(isAsync, false)); let flags = functionFlags(isAsync, false);
// ConciseBody and AsyncConciseBody inherit [In]
if (!this.match(tt.bracketL) && this.prodParam.hasIn) {
flags |= PARAM_IN;
}
this.prodParam.enter(flags);
this.initFunction(node, isAsync); this.initFunction(node, isAsync);
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters; const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYieldPos = this.state.yieldPos; const oldYieldPos = this.state.yieldPos;
@ -2102,7 +2115,7 @@ export default class ExpressionParser extends LValParser {
this.state.inParameters = false; this.state.inParameters = false;
if (isExpression) { if (isExpression) {
node.body = this.parseMaybeAssign(); node.body = this.parseMaybeAssignAllowIn();
this.checkParams(node, false, allowExpression, false); this.checkParams(node, false, allowExpression, false);
} else { } else {
const oldStrict = this.state.strict; const oldStrict = this.state.strict;
@ -2261,8 +2274,7 @@ export default class ExpressionParser extends LValParser {
this.next(); this.next();
elt = this.finishNode(node, "ArgumentPlaceholder"); elt = this.finishNode(node, "ArgumentPlaceholder");
} else { } else {
elt = this.parseMaybeAssign( elt = this.parseMaybeAssignAllowIn(
false,
refExpressionErrors, refExpressionErrors,
this.parseParenItem, this.parseParenItem,
refNeedsArrowPos, refNeedsArrowPos,
@ -2440,7 +2452,7 @@ export default class ExpressionParser extends LValParser {
// Parses yield expression inside generator. // Parses yield expression inside generator.
parseYield(noIn?: ?boolean): N.YieldExpression { parseYield(): N.YieldExpression {
const node = this.startNode(); const node = this.startNode();
if (this.state.inParameters) { if (this.state.inParameters) {
@ -2459,7 +2471,7 @@ export default class ExpressionParser extends LValParser {
node.argument = null; node.argument = null;
} else { } else {
node.delegate = this.eat(tt.star); node.delegate = this.eat(tt.star);
node.argument = this.parseMaybeAssign(noIn); node.argument = this.parseMaybeAssign();
} }
return this.finishNode(node, "YieldExpression"); return this.finishNode(node, "YieldExpression");
} }
@ -2594,6 +2606,34 @@ export default class ExpressionParser extends LValParser {
} }
} }
allowInAnd<T>(callback: () => T): T {
const flags = this.prodParam.currentFlags();
const prodParamToSet = PARAM_IN & ~flags;
if (prodParamToSet) {
this.prodParam.enter(flags | PARAM_IN);
try {
return callback();
} finally {
this.prodParam.exit();
}
}
return callback();
}
disallowInAnd<T>(callback: () => T): T {
const flags = this.prodParam.currentFlags();
const prodParamToClear = PARAM_IN & flags;
if (prodParamToClear) {
this.prodParam.enter(flags & ~PARAM_IN);
try {
return callback();
} finally {
this.prodParam.exit();
}
}
return callback();
}
// Register the use of a primary topic reference (`#`) within the current // Register the use of a primary topic reference (`#`) within the current
// topic context. // topic context.
registerTopicReference(): void { registerTopicReference(): void {
@ -2611,7 +2651,7 @@ export default class ExpressionParser extends LValParser {
); );
} }
parseFSharpPipelineBody(prec: number, noIn: ?boolean): N.Expression { parseFSharpPipelineBody(prec: number): N.Expression {
const startPos = this.state.start; const startPos = this.state.start;
const startLoc = this.state.startLoc; const startLoc = this.state.startLoc;
@ -2624,7 +2664,6 @@ export default class ExpressionParser extends LValParser {
startPos, startPos,
startLoc, startLoc,
prec, prec,
noIn,
); );
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody; this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;

View File

@ -34,13 +34,12 @@ export default class LValParser extends NodeUtils {
// Forward-declaration: defined in expression.js // Forward-declaration: defined in expression.js
/*:: /*::
+parseIdentifier: (liberal?: boolean) => Identifier; +parseIdentifier: (liberal?: boolean) => Identifier;
+parseMaybeAssign: ( +parseMaybeAssignAllowIn: (
noIn?: ?boolean,
refExpressionErrors?: ?ExpressionErrors, refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function, afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
) => Expression; ) => Expression;
+parseObj: <T: ObjectPattern | ObjectExpression>( +parseObjectLike: <T: ObjectPattern | ObjectExpression>(
close: TokenType, close: TokenType,
isPattern: boolean, isPattern: boolean,
isRecord?: ?boolean, isRecord?: ?boolean,
@ -226,8 +225,7 @@ export default class LValParser extends NodeUtils {
): SpreadElement { ): SpreadElement {
const node = this.startNode(); const node = this.startNode();
this.next(); this.next();
node.argument = this.parseMaybeAssign( node.argument = this.parseMaybeAssignAllowIn(
false,
refExpressionErrors, refExpressionErrors,
undefined, undefined,
refNeedsArrowPos, refNeedsArrowPos,
@ -340,7 +338,7 @@ export default class LValParser extends NodeUtils {
const node = this.startNodeAt(startPos, startLoc); const node = this.startNodeAt(startPos, startLoc);
node.left = left; node.left = left;
node.right = this.parseMaybeAssign(); node.right = this.parseMaybeAssignAllowIn();
return this.finishNode(node, "AssignmentPattern"); return this.finishNode(node, "AssignmentPattern");
} }

View File

@ -973,7 +973,9 @@ export default class StatementParser extends ExpressionParser {
} }
node.left = init; node.left = init;
node.right = isForIn ? this.parseExpression() : this.parseMaybeAssign(); node.right = isForIn
? this.parseExpression()
: this.parseMaybeAssignAllowIn();
this.expect(tt.parenR); this.expect(tt.parenR);
node.body = node.body =
@ -1005,7 +1007,9 @@ export default class StatementParser extends ExpressionParser {
const decl = this.startNode(); const decl = this.startNode();
this.parseVarId(decl, kind); this.parseVarId(decl, kind);
if (this.eat(tt.eq)) { if (this.eat(tt.eq)) {
decl.init = this.parseMaybeAssign(isFor); decl.init = isFor
? this.parseMaybeAssignDisallowIn()
: this.parseMaybeAssignAllowIn();
} else { } else {
if ( if (
kind === "const" && kind === "const" &&
@ -1618,10 +1622,9 @@ export default class StatementParser extends ExpressionParser {
node: N.ClassPrivateProperty, node: N.ClassPrivateProperty,
): N.ClassPrivateProperty { ): N.ClassPrivateProperty {
this.scope.enter(SCOPE_CLASS | SCOPE_SUPER); this.scope.enter(SCOPE_CLASS | SCOPE_SUPER);
// [In] production parameter is tracked in parseMaybeAssign
this.prodParam.enter(PARAM); this.prodParam.enter(PARAM);
node.value = this.eat(tt.eq) ? this.parseMaybeAssign() : null; node.value = this.eat(tt.eq) ? this.parseMaybeAssignAllowIn() : null;
this.semicolon(); this.semicolon();
this.prodParam.exit(); this.prodParam.exit();
@ -1636,13 +1639,12 @@ export default class StatementParser extends ExpressionParser {
} }
this.scope.enter(SCOPE_CLASS | SCOPE_SUPER); this.scope.enter(SCOPE_CLASS | SCOPE_SUPER);
// [In] production parameter is tracked in parseMaybeAssign
this.prodParam.enter(PARAM); this.prodParam.enter(PARAM);
if (this.match(tt.eq)) { if (this.match(tt.eq)) {
this.expectPlugin("classProperties"); this.expectPlugin("classProperties");
this.next(); this.next();
node.value = this.parseMaybeAssign(); node.value = this.parseMaybeAssignAllowIn();
} else { } else {
node.value = null; node.value = null;
} }
@ -1841,7 +1843,7 @@ export default class StatementParser extends ExpressionParser {
} else if (this.match(tt._const) || this.match(tt._var) || this.isLet()) { } else if (this.match(tt._const) || this.match(tt._var) || this.isLet()) {
throw this.raise(this.state.start, Errors.UnsupportedDefaultExport); throw this.raise(this.state.start, Errors.UnsupportedDefaultExport);
} else { } else {
const res = this.parseMaybeAssign(); const res = this.parseMaybeAssignAllowIn();
this.semicolon(); this.semicolon();
return res; return res;
} }

View File

@ -1816,7 +1816,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parseConditional( parseConditional(
expr: N.Expression, expr: N.Expression,
noIn: ?boolean,
startPos: number, startPos: number,
startLoc: Position, startLoc: Position,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
@ -1827,7 +1826,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// and if we come from inside parens // and if we come from inside parens
if (refNeedsArrowPos) { if (refNeedsArrowPos) {
const result = this.tryParse(() => const result = this.tryParse(() =>
super.parseConditional(expr, noIn, startPos, startLoc), super.parseConditional(expr, startPos, startLoc),
); );
if (!result.node) { if (!result.node) {
@ -1886,7 +1885,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.test = expr; node.test = expr;
node.consequent = consequent; node.consequent = consequent;
node.alternate = this.forwardNoArrowParamsConversionAt(node, () => node.alternate = this.forwardNoArrowParamsConversionAt(node, () =>
this.parseMaybeAssign(noIn, undefined, undefined, undefined), this.parseMaybeAssign(undefined, undefined, undefined),
); );
return this.finishNode(node, "ConditionalExpression"); return this.finishNode(node, "ConditionalExpression");
@ -1898,7 +1897,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} { } {
this.state.noArrowParamsConversionAt.push(this.state.start); this.state.noArrowParamsConversionAt.push(this.state.start);
const consequent = this.parseMaybeAssign(); const consequent = this.parseMaybeAssignAllowIn();
const failed = !this.match(tt.colon); const failed = !this.match(tt.colon);
this.state.noArrowParamsConversionAt.pop(); this.state.noArrowParamsConversionAt.pop();
@ -2632,7 +2631,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// there // there
// 3. This is neither. Just call the super method // 3. This is neither. Just call the super method
parseMaybeAssign( parseMaybeAssign(
noIn?: ?boolean,
refExpressionErrors?: ?ExpressionErrors, refExpressionErrors?: ?ExpressionErrors,
afterLeftParse?: Function, afterLeftParse?: Function,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
@ -2650,7 +2648,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
jsx = this.tryParse( jsx = this.tryParse(
() => () =>
super.parseMaybeAssign( super.parseMaybeAssign(
noIn,
refExpressionErrors, refExpressionErrors,
afterLeftParse, afterLeftParse,
refNeedsArrowPos, refNeedsArrowPos,
@ -2684,7 +2681,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
typeParameters, typeParameters,
() => () =>
super.parseMaybeAssign( super.parseMaybeAssign(
noIn,
refExpressionErrors, refExpressionErrors,
afterLeftParse, afterLeftParse,
refNeedsArrowPos, refNeedsArrowPos,
@ -2730,7 +2726,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
return super.parseMaybeAssign( return super.parseMaybeAssign(
noIn,
refExpressionErrors, refExpressionErrors,
afterLeftParse, afterLeftParse,
refNeedsArrowPos, refNeedsArrowPos,

View File

@ -356,7 +356,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const node = this.startNode(); const node = this.startNode();
if (this.eat(tt.braceL)) { if (this.eat(tt.braceL)) {
this.expect(tt.ellipsis); this.expect(tt.ellipsis);
node.argument = this.parseMaybeAssign(); node.argument = this.parseMaybeAssignAllowIn();
this.expect(tt.braceR); this.expect(tt.braceR);
return this.finishNode(node, "JSXSpreadAttribute"); return this.finishNode(node, "JSXSpreadAttribute");
} }

View File

@ -1285,7 +1285,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
? this.parseExprAtom() ? this.parseExprAtom()
: this.parseIdentifier(/* liberal */ true); : this.parseIdentifier(/* liberal */ true);
if (this.eat(tt.eq)) { if (this.eat(tt.eq)) {
node.initializer = this.parseMaybeAssign(); node.initializer = this.parseMaybeAssignAllowIn();
} }
return this.finishNode(node, "TSEnumMember"); return this.finishNode(node, "TSEnumMember");
} }
@ -1865,7 +1865,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
leftStartPos: number, leftStartPos: number,
leftStartLoc: Position, leftStartLoc: Position,
minPrec: number, minPrec: number,
noIn: ?boolean,
) { ) {
if ( if (
nonNull(tt._in.binop) > minPrec && nonNull(tt._in.binop) > minPrec &&
@ -1886,16 +1885,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.finishNode(node, "TSAsExpression"); this.finishNode(node, "TSAsExpression");
// rescan `<`, `>` because they were scanned when this.state.inType was true // rescan `<`, `>` because they were scanned when this.state.inType was true
this.reScan_lt_gt(); this.reScan_lt_gt();
return this.parseExprOp( return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec);
node,
leftStartPos,
leftStartLoc,
minPrec,
noIn,
);
} }
return super.parseExprOp(left, leftStartPos, leftStartLoc, minPrec, noIn); return super.parseExprOp(left, leftStartPos, leftStartLoc, minPrec);
} }
checkReservedWord( checkReservedWord(
@ -2135,7 +2128,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// An apparent conditional expression could actually be an optional parameter in an arrow function. // An apparent conditional expression could actually be an optional parameter in an arrow function.
parseConditional( parseConditional(
expr: N.Expression, expr: N.Expression,
noIn: ?boolean,
startPos: number, startPos: number,
startLoc: Position, startLoc: Position,
refNeedsArrowPos?: ?Pos, refNeedsArrowPos?: ?Pos,
@ -2145,7 +2137,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (!refNeedsArrowPos || !this.match(tt.question)) { if (!refNeedsArrowPos || !this.match(tt.question)) {
return super.parseConditional( return super.parseConditional(
expr, expr,
noIn,
startPos, startPos,
startLoc, startLoc,
refNeedsArrowPos, refNeedsArrowPos,
@ -2153,7 +2144,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
const result = this.tryParse(() => const result = this.tryParse(() =>
super.parseConditional(expr, noIn, startPos, startLoc), super.parseConditional(expr, startPos, startLoc),
); );
if (!result.node) { if (!result.node) {

View File

@ -1,13 +1,13 @@
// @flow // @flow
export const PARAM = 0b000, // Initial Parameter flags export const PARAM = 0b0000, // Initial Parameter flags
PARAM_YIELD = 0b001, // track [Yield] production parameter PARAM_YIELD = 0b0001, // track [Yield] production parameter
PARAM_AWAIT = 0b010, // track [Await] production parameter PARAM_AWAIT = 0b0010, // track [Await] production parameter
PARAM_RETURN = 0b100; // track [Return] production parameter PARAM_RETURN = 0b0100, // track [Return] production parameter
PARAM_IN = 0b1000; // track [In] production parameter
// ProductionParameterHandler is a stack fashioned production parameter tracker // ProductionParameterHandler is a stack fashioned production parameter tracker
// https://tc39.es/ecma262/#sec-grammar-notation // https://tc39.es/ecma262/#sec-grammar-notation
// The tracked parameters are defined above. Note that the [In] parameter is // The tracked parameters are defined above.
// tracked in `noIn` argument of `parseExpression`.
// //
// Whenever [+Await]/[+Yield] appears in the right-hand sides of a production, // Whenever [+Await]/[+Yield] appears in the right-hand sides of a production,
// we must enter a new tracking stack. For example when parsing // we must enter a new tracking stack. For example when parsing
@ -53,6 +53,10 @@ export default class ProductionParameterHandler {
get hasReturn(): boolean { get hasReturn(): boolean {
return (this.currentFlags() & PARAM_RETURN) > 0; return (this.currentFlags() & PARAM_RETURN) > 0;
} }
get hasIn(): boolean {
return (this.currentFlags() & PARAM_IN) > 0;
}
} }
export function functionFlags( export function functionFlags(