(P: ParseState)
| 2427 | } |
| 2428 | |
| 2429 | function parseDollarLike(P: ParseState): TsNode | null { |
| 2430 | const c1 = peek(P.L, 1) |
| 2431 | const dStart = P.L.b |
| 2432 | if (c1 === '(' && peek(P.L, 2) === '(') { |
| 2433 | // $(( arithmetic )) |
| 2434 | advance(P.L) |
| 2435 | advance(P.L) |
| 2436 | advance(P.L) |
| 2437 | const open = mk(P, '$((', dStart, P.L.b, []) |
| 2438 | const exprs = parseArithCommaList(P, '))', 'var') |
| 2439 | skipBlanks(P.L) |
| 2440 | let close: TsNode |
| 2441 | if (peek(P.L) === ')' && peek(P.L, 1) === ')') { |
| 2442 | const cStart = P.L.b |
| 2443 | advance(P.L) |
| 2444 | advance(P.L) |
| 2445 | close = mk(P, '))', cStart, P.L.b, []) |
| 2446 | } else { |
| 2447 | close = mk(P, '))', P.L.b, P.L.b, []) |
| 2448 | } |
| 2449 | return mk(P, 'arithmetic_expansion', dStart, close.endIndex, [ |
| 2450 | open, |
| 2451 | ...exprs, |
| 2452 | close, |
| 2453 | ]) |
| 2454 | } |
| 2455 | if (c1 === '[') { |
| 2456 | // $[ arithmetic ] — legacy bash syntax, same as $((...)) |
| 2457 | advance(P.L) |
| 2458 | advance(P.L) |
| 2459 | const open = mk(P, '$[', dStart, P.L.b, []) |
| 2460 | const exprs = parseArithCommaList(P, ']', 'var') |
| 2461 | skipBlanks(P.L) |
| 2462 | let close: TsNode |
| 2463 | if (peek(P.L) === ']') { |
| 2464 | const cStart = P.L.b |
| 2465 | advance(P.L) |
| 2466 | close = mk(P, ']', cStart, P.L.b, []) |
| 2467 | } else { |
| 2468 | close = mk(P, ']', P.L.b, P.L.b, []) |
| 2469 | } |
| 2470 | return mk(P, 'arithmetic_expansion', dStart, close.endIndex, [ |
| 2471 | open, |
| 2472 | ...exprs, |
| 2473 | close, |
| 2474 | ]) |
| 2475 | } |
| 2476 | if (c1 === '(') { |
| 2477 | advance(P.L) |
| 2478 | advance(P.L) |
| 2479 | const open = mk(P, '$(', dStart, P.L.b, []) |
| 2480 | let body = parseStatements(P, ')') |
| 2481 | skipBlanks(P.L) |
| 2482 | let close: TsNode |
| 2483 | if (peek(P.L) === ')') { |
| 2484 | const cStart = P.L.b |
| 2485 | advance(P.L) |
| 2486 | close = mk(P, ')', cStart, P.L.b, []) |
no test coverage detected