# `Yarnspinnex.Analysis`
[🔗](https://github.com/atavistock/yarnspinnex/blob/main/lib/yarnspinnex/analysis.ex#L1)

Static walks over parsed statements, for compile-time checks and tooling. `bodies/1` is the one
place that knows how statements nest; `flatten/1` and the walks built on it follow from that.

# `bodies`

```elixir
@spec bodies(Yarnspinnex.Parser.Body.statement()) :: [
  [Yarnspinnex.Parser.Body.statement()]
]
```

The statement lists nested directly inside `statement`: `<<if>>` branches, else, option bodies.

# `expressions`

```elixir
@spec expressions(Yarnspinnex.Parser.Body.statement()) :: [
  {Yarnspinnex.Parser.Expression.ast(), Yarnspinnex.Parser.Body.line()}
]
```

The expressions `statement` evaluates itself, without nested statements, with their lines.

# `flatten`

```elixir
@spec flatten([Yarnspinnex.Parser.Body.statement()]) :: [
  Yarnspinnex.Parser.Body.statement()
]
```

Every statement, depth first, including those nested in branches and options.

# `jump_targets`

```elixir
@spec jump_targets([Yarnspinnex.Parser.Body.statement()]) :: [
  {String.t(), Yarnspinnex.Parser.Body.line()}
]
```

Every `<<jump>>` target, with its line, including inside options and `<<if>>` branches.

# `reads`

```elixir
@spec reads([Yarnspinnex.Parser.Body.statement()]) :: [
  {String.t(), Yarnspinnex.Parser.Body.line()}
]
```

Every `$name` read, with the line of the statement reading it.

# `strip_lines`

```elixir
@spec strip_lines([Yarnspinnex.Parser.Body.statement()]) :: [tuple() | :stop]
```

The statements with their source lines removed. A script's fingerprint is taken over this, so
editing comments or blank lines does not invalidate stored cursors while changing a statement does.

# `writes`

```elixir
@spec writes([Yarnspinnex.Parser.Body.statement()]) :: [String.t()]
```

Every `$name` assigned by `<<set>>` or `<<declare>>`, anywhere in the statements.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
