Current section

Files

Jump to
eyeon lib eyeon text_decoder.ex
Raw

lib/eyeon/text_decoder.ex

defmodule Eyeon.TextDecoder do
@moduledoc """
Decodes Ion text format to Elixir values.
Delegates to Eyeon.TextParser for single-pass recursive descent parsing.
"""
alias Eyeon.Catalog
@ivm_pattern ~r/^\$ion_\d+_\d+$/
@spec decode_all(iodata(), Catalog.t(), map()) :: {:ok, [any()]} | {:error, any()}
def decode_all(data, catalog \\ Catalog.new([]), options \\ %{}) do
case Eyeon.TextParser.parse(data, %{catalog: catalog, options: options}) do
{:ok, values} when is_list(values) -> {:ok, strip_directives(values)}
{:ok, value} -> {:ok, strip_directives([value])}
other -> other
end
end
@spec decode(iodata(), Catalog.t(), map()) :: {:ok, any()} | {:error, any()}
def decode(data, catalog \\ Catalog.new([]), options \\ %{}) do
case Eyeon.TextParser.parse(data, %{catalog: catalog, options: options}) do
{:ok, values} when is_list(values) ->
{:ok, strip_directives(values)}
{:ok, value} ->
if directive_value?(value), do: {:ok, []}, else: {:ok, value}
other ->
other
end
end
# IVM symbols ($ion_N_M) and $ion_symbol_table structs are directives,
# not data values — filter from output.
defp directive_value?({:symbol, name}), do: Regex.match?(@ivm_pattern, name)
defp directive_value?({:annotated, {:symbol, "$ion_symbol_table"}, val}) when is_map(val),
do: true
defp directive_value?(_), do: false
defp strip_directives(decoded) do
Enum.reject(decoded, &directive_value?/1)
end
end