# `Sml.Parser`
[🔗](https://github.com/emischorr/sml_ex/blob/v0.1.0/lib/sml/parser.ex#L1)

Low-level parser for the SML binary encoding (type-length-value).

Every element starts with one or more TL bytes:

    bit 7     more TL bytes follow
    bits 6-4  type: 000 octet string, 100 boolean, 101 integer,
                    110 unsigned, 111 list
    bits 3-0  length nibble

With multiple TL bytes the length nibbles are concatenated. For lists the
length is the number of elements; for all other types it is the number of
bytes *including* the TL bytes.

Elements are mapped to plain Elixir terms:

| SML                       | Elixir                |
| ------------------------- | --------------------- |
| octet string              | binary                |
| boolean                   | `true` / `false`      |
| integer / unsigned        | integer               |
| list                      | list                  |
| `0x01` (optional, absent) | `nil`                 |
| `0x00` (end of message)   | `:end_of_message`     |

Signedness is lost in this representation; `Sml.Decoder` knows the schema
and does not need it.

# `error`

```elixir
@type error() :: {:error, reason :: atom() | tuple(), rest :: binary()}
```

# `term_t`

```elixir
@type term_t() ::
  binary() | boolean() | integer() | nil | :end_of_message | [term_t()]
```

# `parse`

```elixir
@spec parse(binary()) :: {:ok, term_t(), binary()} | error()
```

Parses one element from the beginning of `data`.

Returns the element and the remaining bytes. On failure the remaining bytes
point at the element that could not be parsed.

    iex> Sml.Parser.parse(<<0x62, 0x1E, 0xFF>>)
    {:ok, 30, <<0xFF>>}

    iex> Sml.Parser.parse(<<0x72, 0x03, "EM", 0x52, 0xFF>>)
    {:ok, ["EM", -1], ""}

# `parse_all`

```elixir
@spec parse_all(binary()) :: {:ok, [term_t()]} | error()
```

Parses all elements in `data` until it is exhausted.

Handy for inspecting unknown data:

    iex> Sml.Parser.parse_all(<<0x01, 0x42, 0x01, 0x00>>)
    {:ok, [nil, true, :end_of_message]}

# `parse_list_header`

```elixir
@spec parse_list_header(binary()) :: {:ok, non_neg_integer(), binary()} | error()
```

Parses only the TL header of a list and returns its element count.

# `parse_many`

```elixir
@spec parse_many(binary(), non_neg_integer()) :: {:ok, [term_t()], binary()} | error()
```

Parses `count` consecutive elements.

---

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