# `A2UICore.Expression`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_core/lib/a2ui_core/expression.ex#L1)

Parser for A2UI expression templates — the `${…}` interpolation
language used by `formatString` and by dynamic string values.

`parse/1` turns a template into a list of *parts*:

  * literal text (a string),
  * a literal value from inside an interpolation: a string (`'x'`,
    `"x"`), a number (`42`, `-1.5`, `1e5`) or a boolean,
  * a data binding `%{"path" => path}` (`${/user/name}`, `${count}`),
  * a function call `%{"call" => name, "args" => %{…}, "returnType" => "any"}`
    (`${add(a: 1, b: /x)}`); arguments are themselves expressions. A
    system function is named with `@` and must be called:
    `${@index(offset: 1)}`.

`\${` is an escaped marker and yields the literal `${`. `null` yields
nothing. Whitespace inside an interpolation is ignored.

Limits (shared by every reference engine so they accept the same
inputs): templates up to 10 000 characters, 1 000 parts, nesting
depth 100.

Errors are `{:error, %A2UICore.Error{category: :expression}}`:
unclosed interpolation, a missing `:` or `)` in a call, trailing
characters, an invalid or out-of-range number literal, and exceeded
limits.

    iex> A2UICore.Expression.parse("Hello, ${/user/name}!")
    {:ok, ["Hello, ", %{"path" => "/user/name"}, "!"]}
    iex> A2UICore.Expression.parse("${add(a: 1, b: 2)}")
    {:ok, [%{"call" => "add", "args" => %{"a" => 1, "b" => 2}, "returnType" => "any"}]}
    iex> {:error, error} = A2UICore.Expression.parse("${oops")
    iex> error.message
    "Unclosed interpolation: missing '}'"

# `part`
*since 0.1.0* 

```elixir
@type part() :: String.t() | number() | boolean() | map()
```

One element of a parsed template.

# `max_depth`
*since 0.1.0* 

```elixir
@spec max_depth() :: pos_integer()
```

The recursion limit for nested interpolations and call arguments.

# `parse`
*since 0.1.0* 

```elixir
@spec parse(String.t()) :: {:ok, [part()]} | {:error, A2UICore.Error.t()}
```

Parses a template into parts. Adjacent literal runs may be split
across several string parts; join them to compare.

# `parse!`
*since 0.1.0* 

```elixir
@spec parse!(String.t()) :: [part()]
```

Like `parse/1`, raising `A2UICore.Error` on failure.

---

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