Factor parseSubscript out of parseSubscripts (#576)

This commit is contained in:
Andy 2017-06-13 15:26:12 -07:00 committed by Daniel Tschinder
parent dc87d99713
commit 50ae16de38

View File

@ -294,99 +294,109 @@ export default class ExpressionParser extends LValParser {
return this.parseSubscripts(expr, startPos, startLoc); return this.parseSubscripts(expr, startPos, startLoc);
} }
parseSubscripts(base: N.Expression, startPos: number, startLoc: Position, noCalls?: boolean): N.Expression { parseSubscripts(base: N.Expression, startPos: number, startLoc: Position, noCalls?: ?boolean) {
for (;;) { const state = { stop: false };
if (!noCalls && this.eat(tt.doubleColon)) { do {
const node = this.startNodeAt(startPos, startLoc); base = this.parseSubscript(base, startPos, startLoc, noCalls, state);
node.object = base; } while (!state.stop);
node.callee = this.parseNoCallExpr(); return base;
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls); }
} else if (this.match(tt.questionDot)) { /** @param state Set 'state.stop = true' to indicate that we should stop parsing subscripts. */
if (!this.hasPlugin("optionalChaining")) { parseSubscript(base: N.Expression, startPos: number, startLoc: Position, noCalls: ?boolean, state: { stop: boolean }): N.Expression {
this.raise(startPos, "You can only use optional-chaining when the 'optionalChaining' plugin is enabled."); if (!noCalls && this.eat(tt.doubleColon)) {
} const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.callee = this.parseNoCallExpr();
state.stop = true;
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
if (noCalls && this.lookahead().type == tt.parenL) { } else if (this.match(tt.questionDot)) {
return base; if (!this.hasPlugin("optionalChaining")) {
} this.raise(startPos, "You can only use optional-chaining when the 'optionalChaining' plugin is enabled.");
this.next(); }
const node = this.startNodeAt(startPos, startLoc); if (noCalls && this.lookahead().type == tt.parenL) {
state.stop = true;
return base;
}
this.next();
if (this.eat(tt.bracketL)) { const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseExpression();
node.computed = true;
node.optional = true;
this.expect(tt.bracketR);
base = this.finishNode(node, "MemberExpression");
} else if (this.eat(tt.parenL)) {
const possibleAsync = this.state.potentialArrowAt === base.start &&
base.type === "Identifier" &&
base.name === "async" &&
!this.canInsertSemicolon();
node.callee = base; if (this.eat(tt.bracketL)) {
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync);
node.optional = true;
base = this.finishNode(node, "CallExpression");
} else {
node.object = base;
node.property = this.parseIdentifier(true);
node.computed = false;
node.optional = true;
base = this.finishNode(node, "MemberExpression");
}
} else if (this.eat(tt.dot)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.hasPlugin("classPrivateProperties") ? this.parseMaybePrivateName() : this.parseIdentifier(true);
node.computed = false;
base = this.finishNode(node, "MemberExpression");
} else if (this.eat(tt.bracketL)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base; node.object = base;
node.property = this.parseExpression(); node.property = this.parseExpression();
node.computed = true; node.computed = true;
node.optional = true;
this.expect(tt.bracketR); this.expect(tt.bracketR);
base = this.finishNode(node, "MemberExpression"); return this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.match(tt.parenL)) { } else if (this.eat(tt.parenL)) {
const possibleAsync = this.state.potentialArrowAt === base.start && base.type === "Identifier" && base.name === "async" && !this.canInsertSemicolon(); const possibleAsync = this.state.potentialArrowAt === base.start &&
this.next(); base.type === "Identifier" &&
base.name === "async" &&
!this.canInsertSemicolon();
const node = this.startNodeAt(startPos, startLoc);
node.callee = base; node.callee = base;
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync); node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync);
if (node.callee.type === "Import") { node.optional = true;
if (node.arguments.length !== 1) {
this.raise(node.start, "import() requires exactly one argument");
}
const importArg = node.arguments[0]; return this.finishNode(node, "CallExpression");
if (importArg && importArg.type === "SpreadElement") {
this.raise(importArg.start, "... is not allowed in import()");
}
}
base = this.finishNode(node, "CallExpression");
if (possibleAsync && this.shouldParseAsyncArrow()) {
return this.parseAsyncArrowFromCallExpression(this.startNodeAt(startPos, startLoc), node);
} else {
this.toReferencedList(node.arguments);
}
} else if (this.match(tt.backQuote)) {
const node = this.startNodeAt(startPos, startLoc);
node.tag = base;
node.quasi = this.parseTemplate(true);
base = this.finishNode(node, "TaggedTemplateExpression");
} else { } else {
return base; node.object = base;
node.property = this.parseIdentifier(true);
node.computed = false;
node.optional = true;
return this.finishNode(node, "MemberExpression");
} }
} else if (this.eat(tt.dot)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.hasPlugin("classPrivateProperties") ? this.parseMaybePrivateName() : this.parseIdentifier(true);
node.computed = false;
return this.finishNode(node, "MemberExpression");
} else if (this.eat(tt.bracketL)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseExpression();
node.computed = true;
this.expect(tt.bracketR);
return this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.match(tt.parenL)) {
const possibleAsync = this.state.potentialArrowAt === base.start && base.type === "Identifier" && base.name === "async" && !this.canInsertSemicolon();
this.next();
const node = this.startNodeAt(startPos, startLoc);
node.callee = base;
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync);
if (node.callee.type === "Import") {
if (node.arguments.length !== 1) {
this.raise(node.start, "import() requires exactly one argument");
}
const importArg = node.arguments[0];
if (importArg && importArg.type === "SpreadElement") {
this.raise(importArg.start, "... is not allowed in import()");
}
}
this.finishNode(node, "CallExpression");
if (possibleAsync && this.shouldParseAsyncArrow()) {
state.stop = true;
return this.parseAsyncArrowFromCallExpression(this.startNodeAt(startPos, startLoc), node);
} else {
this.toReferencedList(node.arguments);
}
return node;
} else if (this.match(tt.backQuote)) {
const node = this.startNodeAt(startPos, startLoc);
node.tag = base;
node.quasi = this.parseTemplate(true);
return this.finishNode(node, "TaggedTemplateExpression");
} else {
state.stop = true;
return base;
} }
// istanbul ignore next
throw new Error("Unreachable");
} }
parseCallExpressionArguments(close: TokenType, possibleAsyncArrow: boolean): $ReadOnlyArray<?N.Expression> { parseCallExpressionArguments(close: TokenType, possibleAsyncArrow: boolean): $ReadOnlyArray<?N.Expression> {