# `with` blocks

## Usage

```ops
with git.sign() {
  bash.shellcheck()
}
```

## Grammar

```
WithBlock       = 'with' Step '{' Statement* '}'
```

## IR representation

Canonical control-flow shape lives in [control-flow](../ir/control-flow.md).

```json
{
  "role": "with",
  "payload": [
    { "role": "call", "payload": [
      { "role": "target", "payload": "git.sign" },
      { "role": "args", "payload": [] }
    ]},
    ...
  ]
}
```

## Runtime

- **`--undo FN`** — cleanup function for `with` blocks. The op runs before the body; `--undo` runs on exit.
- **`@defer`** — pushes cleanup onto a LIFO stack, drained at group completion (Go-style `defer`).

## Implementation

| | |
|---|---|
| **Tier 9** (if / try / `with`) | `ast.rs`: `Statement::With`. `parser.rs`: parse `with` block. `lower.rs`: emit `with` IR. |
| **Tier 19** (Emitter: parallel, skip & defer) | Defer drain: `@defer` stack drained at group completion or via `trap … EXIT`. |

**Validates:** bats tests for `with` variants.

## Design decisions

- **`with` wraps an op that has a registered `--undo` function.** The op runs before the body; `--undo` runs on exit.
- **Ops without `--undo` used in a `with` block produce a compile error.**
- **Deferred failures** do not prevent other deferred cleanups from running.

## Caveats

- **`std.defer` is currently broken in bash** — `__run_deferred` is never called. The emitter must generate drain calls or `trap … EXIT`.

## Open questions

None recorded for this feature.
