* ```abnf * Each = "each" "(" "let" Dest "," Expr ")" BlockOrStatement * / "each" "let" Dest "," Expr BlockOrStatement * ```
(s: ITokenStream)
| 242 | * ``` |
| 243 | */ |
| 244 | function parseEach(s: ITokenStream): Ast.Each { |
| 245 | const startPos = s.getPos(); |
| 246 | let hasParen = false; |
| 247 | |
| 248 | s.expect(TokenKind.EachKeyword); |
| 249 | s.next(); |
| 250 | |
| 251 | if (s.is(TokenKind.OpenParen)) { |
| 252 | hasParen = true; |
| 253 | s.next(); |
| 254 | } |
| 255 | |
| 256 | s.expect(TokenKind.LetKeyword); |
| 257 | s.next(); |
| 258 | |
| 259 | const dest = parseDest(s); |
| 260 | |
| 261 | if (s.is(TokenKind.Comma)) { |
| 262 | s.next(); |
| 263 | } else { |
| 264 | throw new AiScriptSyntaxError('separator expected', s.getPos()); |
| 265 | } |
| 266 | |
| 267 | const items = parseExpr(s, false); |
| 268 | |
| 269 | if (hasParen) { |
| 270 | s.expect(TokenKind.CloseParen); |
| 271 | s.next(); |
| 272 | } |
| 273 | |
| 274 | const body = parseBlockOrStatement(s); |
| 275 | |
| 276 | return NODE('each', { |
| 277 | var: dest, |
| 278 | items: items, |
| 279 | for: body, |
| 280 | }, startPos, s.getPos()); |
| 281 | } |
| 282 | |
| 283 | /** |
| 284 | * ```abnf |
no test coverage detected