(P: ParseState, forTok: Token)
| 3194 | } |
| 3195 | |
| 3196 | function parseFor(P: ParseState, forTok: Token): TsNode { |
| 3197 | const forKw = leaf(P, forTok.value, forTok) |
| 3198 | skipBlanks(P.L) |
| 3199 | // C-style for (( ; ; )) — only for `for`, not `select` |
| 3200 | if (forTok.value === 'for' && peek(P.L) === '(' && peek(P.L, 1) === '(') { |
| 3201 | const oStart = P.L.b |
| 3202 | advance(P.L) |
| 3203 | advance(P.L) |
| 3204 | const open = mk(P, '((', oStart, P.L.b, []) |
| 3205 | const kids: TsNode[] = [forKw, open] |
| 3206 | // init; cond; update — all three use 'assign' mode so `c = expr` emits |
| 3207 | // variable_assignment, while bare idents (c in `c<=5`) → word. Each |
| 3208 | // clause may be a comma-separated list. |
| 3209 | for (let k = 0; k < 3; k++) { |
| 3210 | skipBlanks(P.L) |
| 3211 | const es = parseArithCommaList(P, k < 2 ? ';' : '))', 'assign') |
| 3212 | kids.push(...es) |
| 3213 | if (k < 2) { |
| 3214 | if (peek(P.L) === ';') { |
| 3215 | const s = P.L.b |
| 3216 | advance(P.L) |
| 3217 | kids.push(mk(P, ';', s, P.L.b, [])) |
| 3218 | } |
| 3219 | } |
| 3220 | } |
| 3221 | skipBlanks(P.L) |
| 3222 | if (peek(P.L) === ')' && peek(P.L, 1) === ')') { |
| 3223 | const cStart = P.L.b |
| 3224 | advance(P.L) |
| 3225 | advance(P.L) |
| 3226 | kids.push(mk(P, '))', cStart, P.L.b, [])) |
| 3227 | } |
| 3228 | // Optional ; or newline |
| 3229 | const save = saveLex(P.L) |
| 3230 | const sep = nextToken(P.L, 'cmd') |
| 3231 | if (sep.type === 'OP' && sep.value === ';') { |
| 3232 | kids.push(leaf(P, ';', sep)) |
| 3233 | } else if (sep.type !== 'NEWLINE') { |
| 3234 | restoreLex(P.L, save) |
| 3235 | } |
| 3236 | const dg = parseDoGroup(P) |
| 3237 | if (dg) { |
| 3238 | kids.push(dg) |
| 3239 | } else { |
| 3240 | // C-style for can also use `{ ... }` body instead of `do ... done` |
| 3241 | skipNewlines(P) |
| 3242 | skipBlanks(P.L) |
| 3243 | if (peek(P.L) === '{') { |
| 3244 | const bOpen = P.L.b |
| 3245 | advance(P.L) |
| 3246 | const brace = mk(P, '{', bOpen, P.L.b, []) |
| 3247 | const body = parseStatements(P, '}') |
| 3248 | let bClose: TsNode |
| 3249 | if (peek(P.L) === '}') { |
| 3250 | const cs = P.L.b |
| 3251 | advance(P.L) |
| 3252 | bClose = mk(P, '}', cs, P.L.b, []) |
| 3253 | } else { |
no test coverage detected