Skip to content

Commit e37f4ce

Browse files
Add clarifying comments to parsing binary expressions.
1 parent 114987e commit e37f4ce

1 file changed

Lines changed: 51 additions & 23 deletions

File tree

src/compiler/parser.ts

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,9 +2240,16 @@ module ts {
22402240
return arrowExpression;
22412241
}
22422242

2243-
// Now try to handle the rest of the cases. First, see if we can parse out up to and
2244-
// including a conditional expression.
2245-
var expr = parseConditionalExpression();
2243+
// Now try to see if we're in production '1', '2' or '3'. A conditional expression can
2244+
// start with a LogicalOrExpression, while the assignment productions can only start with
2245+
// LeftHandSideExpressions.
2246+
//
2247+
// So, first, we try to just parse out a BinaryExpression. If we get something that is a
2248+
// LeftHandSide or higher, then we can try to parse out the assignment expression part.
2249+
// Otherwise, we try to parse out the conditional expression bit. We want to allow any
2250+
// binary expression here, so we pass in the 'lowest' precedence here so that it matches
2251+
// and consumes anything.
2252+
var expr = parseBinaryExpressionOrHigher(/*precedence:*/ 0);
22462253

22472254
// To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized
22482255
// parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single
@@ -2254,14 +2261,17 @@ module ts {
22542261
// Now see if we might be in cases '2' or '3'.
22552262
// If the expression was a LHS expression, and we have an assignment operator, then
22562263
// we're in '2' or '3'. Consume the assignment and return.
2257-
if (isLeftHandSideExpression(expr) && isAssignmentOperator(token)) {
2264+
//
2265+
// Note: we call reScanGreaterToken so that we get an appropriately merged token
2266+
// for cases like > > = becoming >>=
2267+
if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) {
22582268
var operator = token;
22592269
nextToken();
22602270
return makeBinaryExpression(expr, operator, parseAssignmentExpressionOrHigher());
22612271
}
22622272

2263-
// otherwise this was production '1'. Return whatever we parsed so far.
2264-
return expr;
2273+
// It wasn't an assignment or a lambda. This is a conditional expression:
2274+
return parseConditionalExpressionRest(expr);
22652275
}
22662276

22672277
function isYieldExpression(): boolean {
@@ -2505,35 +2515,50 @@ module ts {
25052515
return makeFunctionExpression(SyntaxKind.ArrowFunction, pos, /*asteriskToken:*/ undefined, /*name:*/ undefined, sig, body);
25062516
}
25072517

2508-
function parseConditionalExpression(): Expression {
2509-
// Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
2510-
// we do not that for the 'whenFalse' part.
2511-
2512-
var expr = parseBinaryOperators(parseUnaryExpression(), /*minPrecedence:*/ 0);
2518+
function parseConditionalExpressionRest(leftOperand: Expression): Expression {
2519+
// Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.
25132520
if (!parseOptional(SyntaxKind.QuestionToken)) {
2514-
return expr;
2521+
return leftOperand;
25152522
}
25162523

2517-
var node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression, expr.pos);
2518-
node.condition = expr;
2524+
// Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
2525+
// we do not that for the 'whenFalse' part.
2526+
var node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression, leftOperand.pos);
2527+
node.condition = leftOperand;
25192528
node.whenTrue = allowInAnd(parseAssignmentExpressionOrHigher);
25202529
parseExpected(SyntaxKind.ColonToken);
25212530
node.whenFalse = parseAssignmentExpressionOrHigher();
25222531
return finishNode(node);
25232532
}
25242533

2525-
function parseBinaryOperators(expr: Expression, minPrecedence: number): Expression {
2534+
function parseBinaryExpressionOrHigher(precedence: number): Expression {
2535+
var leftOperand = parseUnaryExpression();
2536+
return parseBinaryExpressionRest(precedence, leftOperand);
2537+
}
2538+
2539+
function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression {
25262540
while (true) {
2541+
// We either have a binary operator here, or we're finished. We call
2542+
// reScanGreaterToken so that we merge token sequences like > and = into >=
2543+
25272544
reScanGreaterToken();
2528-
var precedence = getOperatorPrecedence();
2529-
if (precedence && precedence > minPrecedence && (!inDisallowInContext() || token !== SyntaxKind.InKeyword)) {
2530-
var operator = token;
2531-
nextToken();
2532-
expr = makeBinaryExpression(expr, operator, parseBinaryOperators(parseUnaryExpression(), precedence));
2533-
continue;
2545+
var newPrecedence = getOperatorPrecedence();
2546+
2547+
// Check the precedence to see if we should "take" this operator
2548+
if (newPrecedence <= precedence) {
2549+
break;
25342550
}
2535-
return expr;
2551+
2552+
if (token === SyntaxKind.InKeyword && inDisallowInContext()) {
2553+
break;
2554+
}
2555+
2556+
var operator = token;
2557+
nextToken();
2558+
leftOperand = makeBinaryExpression(leftOperand, operator, parseBinaryExpressionOrHigher(newPrecedence));
25362559
}
2560+
2561+
return leftOperand;
25372562
}
25382563

25392564
function getOperatorPrecedence(): number {
@@ -2572,7 +2597,10 @@ module ts {
25722597
case SyntaxKind.PercentToken:
25732598
return 10;
25742599
}
2575-
return undefined;
2600+
2601+
// -1 is lower than all other precedences. Returning it will cause binary expression
2602+
// parsing to stop.
2603+
return -1;
25762604
}
25772605

25782606
function makeBinaryExpression(left: Expression, operator: SyntaxKind, right: Expression): BinaryExpression {

0 commit comments

Comments
 (0)