# `CEL.Expr`
[🔗](https://github.com/hansihe/pb_ex/blob/v0.2.0/cel_ex/lib/cel/expr.ex#L1)

A read-only view of a checked CEL expression, in the spirit of cel-go's
`common/ast`. Get one with `CEL.Checked.expr/1`.

The view is a tree of node structs, each with the expression's `id` and its
checked `type` (a `t:CEL.Type.t/0`, or `nil` for a node the checker did
not type):

  * `CEL.Expr.Const` — a literal.
  * `CEL.Expr.Ident` — a variable, type or enum value, by full name.
  * `CEL.Expr.Select` — `operand.field`, `has(operand.field)` and
    `operand.?field`.
  * `CEL.Expr.Call` — a function call, operator or enum constructor.
  * `CEL.Expr.MacroCall` — a macro as written, such as `l.exists(x, p)`
    or `cel.bind(v, init, body)`.
  * `CEL.Expr.ListLiteral`, `CEL.Expr.MapLiteral` and
    `CEL.Expr.MessageLiteral`.
  * `CEL.Expr.Comprehension` — the loop a macro expands to.

`id` is the one `CEL.Checked.type/2`, `CEL.Checked.position/2` and
`CEL.Checked.references/1` use.

Match on the structs to inspect the tree, and use `reduce/3`, `filter/2` or
`children/1` to walk it. They visit what the author wrote: a `MacroCall`'s
target and arguments, not its expansion.

    alias CEL.Expr.Call

    checked
    |> CEL.Checked.expr()
    |> CEL.Expr.filter(&match?(%Call{function: "lookup"}, &1))

The view is derived from the checked expression; evaluation does not read
it, so it stays stable as the evaluator changes.

# `map_entry`

```elixir
@type map_entry() :: %{key: t(), value: t(), optional: boolean()}
```

An entry of a `CEL.Expr.MapLiteral`.

# `message_field`

```elixir
@type message_field() :: %{field: String.t(), value: t(), optional: boolean()}
```

A field of a `CEL.Expr.MessageLiteral`.

# `scope`

```elixir
@type scope() :: :var | :local | :type | :enum
```

What `CEL.Expr.Ident`'s `scope` says a name is.

# `t`

```elixir
@type t() ::
  CEL.Expr.Const.t()
  | CEL.Expr.Ident.t()
  | CEL.Expr.Select.t()
  | CEL.Expr.Call.t()
  | CEL.Expr.ListLiteral.t()
  | CEL.Expr.MapLiteral.t()
  | CEL.Expr.MessageLiteral.t()
  | CEL.Expr.MacroCall.t()
  | CEL.Expr.Comprehension.t()
```

Any node.

# `type`

```elixir
@type type() :: CEL.Type.t() | nil
```

A node's checked type, or `nil` for a node the checker did not type.

# `children`

```elixir
@spec children(t()) :: [t()]
```

Returns the direct children of a node in evaluation order.

# `filter`

```elixir
@spec filter(t(), (t() -&gt; as_boolean(term()))) :: [t()]
```

Returns the nodes, in visiting order, for which `fun` returns a truthy value.

# `reduce`

```elixir
@spec reduce(t(), acc, (t(), acc -&gt; acc)) :: acc when acc: term()
```

Folds `fun` over a node and its descendants, visiting each node before its
children.

---

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