lib/forthvm/words/data.ex

defmodule ForthVM.Words.Data do
  @moduledoc """
  Custom data words
  """

  alias ForthVM.Process

  @doc """
  l[: ( x y z -- l ) collect all tokens till ] is found and store on the data stack as a list
  """
  def list_start(tokens, data_stack, return_stack, dictionary, meta) do
    {list_tokens, tokens, _depth} = collect_list_tokens(tokens, "l[", "]", [], 1)

    Process.next(
      tokens,
      [list_tokens | data_stack],
      return_stack,
      dictionary,
      meta
    )
  end

  # start collecting tokens between start and end elements. handles recursive entries
  defp collect_list_tokens([token | tokens], start_token, end_token, collected_tokens, depth)
       when token == start_token do
    {list_tokens, tokens, depth} =
      collect_list_tokens(tokens, start_token, end_token, [], depth + 1)

    case depth == 0 do
      true ->
        {[list_tokens | collected_tokens], tokens, 0}

      false ->
        collect_list_tokens(
          tokens,
          start_token,
          end_token,
          [list_tokens | collected_tokens],
          depth
        )
    end
  end

  # stop collecting tokens
  defp collect_list_tokens([token | tokens], _start_token, end_token, collected_tokens, depth)
       when token == end_token do
    {Enum.reverse(collected_tokens), tokens, depth - 1}
  end

  # collecting tokens
  defp collect_list_tokens([token | tokens], start_token, end_token, collected_tokens, depth) do
    collect_list_tokens(tokens, start_token, end_token, [token | collected_tokens], depth)
  end
end