(&mut self, _can_assign: bool)
| 1600 | } |
| 1601 | |
| 1602 | fn grouping(&mut self, _can_assign: bool) -> Option<Expr<'gc>> { |
| 1603 | if self.check(TokenType::CloseParen) { |
| 1604 | // Empty tuple |
| 1605 | self.advance(); |
| 1606 | return Some(Expr::List { |
| 1607 | kind: ListKind::Tuple, |
| 1608 | elements: Vec::new(), |
| 1609 | line: self.previous.line, |
| 1610 | }); |
| 1611 | } |
| 1612 | |
| 1613 | // Parse the first expression |
| 1614 | let expr = self.expression()?; |
| 1615 | |
| 1616 | if self.match_token(TokenType::Comma) { |
| 1617 | // It's a tuple with at least one element |
| 1618 | let mut elements = vec![expr]; |
| 1619 | |
| 1620 | // Parse remaining elements if any |
| 1621 | while !self.check(TokenType::CloseParen) && !self.is_at_end() { |
| 1622 | if self.match_token(TokenType::Comma) && self.check(TokenType::CloseParen) { |
| 1623 | break; // Allow trailing comma |
| 1624 | } |
| 1625 | |
| 1626 | elements.push(self.expression()?); |
| 1627 | |
| 1628 | if !self.check(TokenType::CloseParen) { |
| 1629 | self.consume(TokenType::Comma, "Expect ',' after tuple element."); |
| 1630 | } |
| 1631 | } |
| 1632 | |
| 1633 | self.consume(TokenType::CloseParen, "Expect ')' after tuple elements."); |
| 1634 | |
| 1635 | Some(Expr::List { |
| 1636 | kind: ListKind::Tuple, |
| 1637 | elements, |
| 1638 | line: self.previous.line, |
| 1639 | }) |
| 1640 | } else { |
| 1641 | // Just a parenthesized expression |
| 1642 | self.consume(TokenType::CloseParen, "Expect ')' after expression."); |
| 1643 | Some(Expr::Grouping { |
| 1644 | expression: Box::new(expr), |
| 1645 | line: self.previous.line, |
| 1646 | }) |
| 1647 | } |
| 1648 | } |
| 1649 | |
| 1650 | fn env_lookup(&mut self, _can_assign: bool) -> Option<Expr<'gc>> { |
| 1651 | let line = self.previous.line; |
nothing calls this directly
no test coverage detected