parseBinaryOps calls itself recursively to work through all of the operator precedence groups, and then eventually calls parseExpressionTerm for each operand.
(ops []map[TokenType]*Operation)
| 544 | // operator precedence groups, and then eventually calls parseExpressionTerm |
| 545 | // for each operand. |
| 546 | func (p *parser) parseBinaryOps(ops []map[TokenType]*Operation) (Expression, hcl.Diagnostics) { |
| 547 | if len(ops) == 0 { |
| 548 | // We've run out of operators, so now we'll just try to parse a term. |
| 549 | return p.parseExpressionWithTraversals() |
| 550 | } |
| 551 | |
| 552 | thisLevel := ops[0] |
| 553 | remaining := ops[1:] |
| 554 | |
| 555 | var lhs, rhs Expression |
| 556 | var operation *Operation |
| 557 | var diags hcl.Diagnostics |
| 558 | |
| 559 | // Parse a term that might be the first operand of a binary |
| 560 | // operation or it might just be a standalone term. |
| 561 | // We won't know until we've parsed it and can look ahead |
| 562 | // to see if there's an operator token for this level. |
| 563 | lhs, lhsDiags := p.parseBinaryOps(remaining) |
| 564 | diags = append(diags, lhsDiags...) |
| 565 | if p.recovery && lhsDiags.HasErrors() { |
| 566 | return lhs, diags |
| 567 | } |
| 568 | |
| 569 | // We'll keep eating up operators until we run out, so that operators |
| 570 | // with the same precedence will combine in a left-associative manner: |
| 571 | // a+b+c => (a+b)+c, not a+(b+c) |
| 572 | // |
| 573 | // Should we later want to have right-associative operators, a way |
| 574 | // to achieve that would be to call back up to ParseExpression here |
| 575 | // instead of iteratively parsing only the remaining operators. |
| 576 | for { |
| 577 | next := p.Peek() |
| 578 | var newOp *Operation |
| 579 | var ok bool |
| 580 | if newOp, ok = thisLevel[next.Type]; !ok { |
| 581 | break |
| 582 | } |
| 583 | |
| 584 | // Are we extending an expression started on the previous iteration? |
| 585 | if operation != nil { |
| 586 | lhs = &BinaryOpExpr{ |
| 587 | LHS: lhs, |
| 588 | Op: operation, |
| 589 | RHS: rhs, |
| 590 | |
| 591 | SrcRange: hcl.RangeBetween(lhs.Range(), rhs.Range()), |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | operation = newOp |
| 596 | p.Read() // eat operator token |
| 597 | var rhsDiags hcl.Diagnostics |
| 598 | rhs, rhsDiags = p.parseBinaryOps(remaining) |
| 599 | diags = append(diags, rhsDiags...) |
| 600 | if p.recovery && rhsDiags.HasErrors() { |
| 601 | return lhs, diags |
| 602 | } |
| 603 | } |
no test coverage detected