(&mut self)
| 1111 | } |
| 1112 | |
| 1113 | fn for_statement(&mut self) -> Option<Stmt<'gc>> { |
| 1114 | let initializer = if self.match_token(TokenType::Semicolon) { |
| 1115 | None |
| 1116 | } else if self.match_token(TokenType::Let) { |
| 1117 | Some(Box::new(self.var_declaration(Visibility::Private)?)) |
| 1118 | } else { |
| 1119 | Some(Box::new(self.expression_statement()?)) |
| 1120 | }; |
| 1121 | |
| 1122 | let condition = if !self.check(TokenType::Semicolon) { |
| 1123 | self.expression()? |
| 1124 | } else { |
| 1125 | Expr::Literal { |
| 1126 | value: Literal::Boolean(true), |
| 1127 | line: self.previous.line, |
| 1128 | } |
| 1129 | }; |
| 1130 | self.consume(TokenType::Semicolon, "Expect ';' after loop condition."); |
| 1131 | |
| 1132 | // Parse increment - optional |
| 1133 | let increment = if !self.check(TokenType::OpenBrace) { |
| 1134 | self.stop_at_brace = true; |
| 1135 | let expr = self.parse_precedence(Precedence::Assignment)?; |
| 1136 | self.stop_at_brace = false; |
| 1137 | Some(expr) |
| 1138 | } else { |
| 1139 | // Peek ahead to check for empty object literal |
| 1140 | if self.check(TokenType::OpenBrace) |
| 1141 | && matches!(self.peek_next(), Some(t) if t.kind == TokenType::CloseBrace) |
| 1142 | { |
| 1143 | self.error_at_current("Empty object literal not allowed in for loop increment"); |
| 1144 | return None; |
| 1145 | } |
| 1146 | None |
| 1147 | }; |
| 1148 | |
| 1149 | self.consume(TokenType::OpenBrace, "Expect '{' before loop body."); |
| 1150 | self.loop_depth += 1; |
| 1151 | let body = Box::new(self.block_statement()?); |
| 1152 | self.loop_depth -= 1; |
| 1153 | |
| 1154 | Some(Stmt::Loop { |
| 1155 | initializer, |
| 1156 | condition, |
| 1157 | increment, |
| 1158 | body, |
| 1159 | line: self.previous.line, |
| 1160 | }) |
| 1161 | } |
| 1162 | |
| 1163 | fn if_statement(&mut self) -> Option<Stmt<'gc>> { |
| 1164 | // Set the flag before parsing condition |
no test coverage detected