Packages

A simple Push programming language interpreter implemented in Elixir.

Current section

Files

Jump to
elixush lib instructions vectors.ex
Raw

lib/instructions/vectors.ex

defmodule Elixush.Instructions.Vectors do
import Elixush.PushState
import Elixush.Instructions.Common
import Elixush.Globals.Agent, only: [get_globals: 1]
def vector_integer_pop(state), do: popper(:vector_integer, state)
def vector_float_pop(state), do: popper(:vector_float, state)
def vector_boolean_pop(state), do: popper(:vector_boolean, state)
def vector_string_pop(state), do: popper(:vector_string, state)
def vector_integer_dup(state), do: duper(:vector_integer, state)
def vector_float_dup(state), do: duper(:vector_float, state)
def vector_boolean_dup(state), do: duper(:vector_boolean, state)
def vector_string_dup(state), do: duper(:vector_string, state)
def vector_integer_swap(state), do: swapper(:vector_integer, state)
def vector_float_swap(state), do: swapper(:vector_float, state)
def vector_boolean_swap(state), do: swapper(:vector_boolean, state)
def vector_string_swap(state), do: swapper(:vector_string, state)
def vector_integer_rot(state), do: rotter(:vector_integer, state)
def vector_float_rot(state), do: rotter(:vector_float, state)
def vector_boolean_rot(state), do: rotter(:vector_boolean, state)
def vector_string_rot(state), do: rotter(:vector_string, state)
def vector_integer_flush(state), do: flusher(:vector_integer, state)
def vector_float_flush(state), do: flusher(:vector_float, state)
def vector_boolean_flush(state), do: flusher(:vector_boolean, state)
def vector_string_flush(state), do: flusher(:vector_string, state)
def vector_integer_eq(state), do: eqer(:vector_integer, state)
def vector_float_eq(state), do: eqer(:vector_float, state)
def vector_boolean_eq(state), do: eqer(:vector_boolean, state)
def vector_string_eq(state), do: eqer(:vector_string, state)
def vector_integer_stackdepth(state), do: stackdepther(:vector_integer, state)
def vector_float_stackdepth(state), do: stackdepther(:vector_float, state)
def vector_boolean_stackdepth(state), do: stackdepther(:vector_boolean, state)
def vector_string_stackdepth(state), do: stackdepther(:vector_string, state)
def vector_integer_yank(state), do: yanker(:vector_integer, state)
def vector_float_yank(state), do: yanker(:vector_float, state)
def vector_boolean_yank(state), do: yanker(:vector_boolean, state)
def vector_string_yank(state), do: yanker(:vector_string, state)
def vector_integer_yankdup(state), do: yankduper(:vector_integer, state)
def vector_float_yankdup(state), do: yankduper(:vector_float, state)
def vector_boolean_yankdup(state), do: yankduper(:vector_boolean, state)
def vector_string_yankdup(state), do: yankduper(:vector_string, state)
def vector_integer_shove(state), do: shover(:vector_integer, state)
def vector_float_shove(state), do: shover(:vector_float, state)
def vector_boolean_shove(state), do: shover(:vector_boolean, state)
def vector_string_shove(state), do: shover(:vector_string, state)
def vector_integer_empty(state), do: emptyer(:vector_integer, state)
def vector_float_empty(state), do: emptyer(:vector_float, state)
def vector_boolean_empty(state), do: emptyer(:vector_boolean, state)
def vector_string_empty(state), do: emptyer(:vector_string, state)
### common instructions for vectors
@doc "Takes a type and a state and concats two vectors on the type stack."
def concater(type, state) do
if not(Enum.empty?(Enum.drop(state[type], 1))) do
first_item = stack_ref(type, 0, state)
second_item = stack_ref(type, 1, state)
if get_globals(:max_vector_length) >= Enum.count(first_item) + Enum.count(second_item) do
Enum.concat(second_item, first_item) |> push_item(type, pop_item(type, pop_item(type, state)))
else
state
end
else
state
end
end
def vector_integer_concat(state), do: concater(:vector_integer, state)
def vector_float_concat(state), do: concater(:vector_float, state)
def vector_boolean_concat(state), do: concater(:vector_boolean, state)
def vector_string_concat(state), do: concater(:vector_string, state)
@doc "Takes a vec_type, a lit_type, and a state and conj's an item onto the type stack."
def conjer(vec_type, lit_type, state) do
if not(Enum.empty?(state[vec_type])) and not(Enum.empty?(state[lit_type])) do
result = top_item(lit_type, state) |> List.insert_at(-1, top_item(vec_type, state))
if get_globals(:max_vector_length) >= Enum.count(result) do
push_item(result, vec_type, pop_item(lit_type, pop_item(vec_type, state)))
else
state
end
else
state
end
end
def vector_integer_conj(state), do: conjer(:vector_integer, :integer, state)
def vector_float_conj(state), do: conjer(:vector_float, :float, state)
def vector_boolean_conj(state), do: conjer(:vector_boolean, :boolean, state)
def vector_string_conj(state), do: conjer(:vector_string, :string, state)
@doc "Takes a type and a state and takes the first N items from the type stack, where N is from the integer stack."
def taker(type, state) do
if not(Enum.empty?(state[type])) and not(Enum.empty?(state[:integer])) do
top_item(type, state) |> Enum.take(top_item(:integer, state)) |> push_item(type, pop_item(type, pop_item(:integer, state)))
else
state
end
end
def vector_integer_take(state), do: taker(:vector_integer, state)
def vector_float_take(state), do: taker(:vector_float, state)
def vector_boolean_take(state), do: taker(:vector_boolean, state)
def vector_string_take(state), do: taker(:vector_string, state)
@doc "Takes a type and a state and takes the subvec of the top item on the type stack."
def subvecer(type, state) do
if not(Enum.empty?(state[type])) and not(Enum.empty?(Enum.drop(state[:integer], 1))) do
vect = top_item(type, state)
first_index = min(Enum.count(vect), max(0, stack_ref(:integer, 1, state)))
second_index = min(Enum.count(vect), max(first_index, stack_ref(:integer, 0, state)))
Enum.slice(vect, first_index, second_index - first_index)
|> push_item(type, pop_item(type, pop_item(:integer, pop_item(:integer, state))))
else
state
end
end
def vector_integer_subvec(state), do: subvecer(:vector_integer, state)
def vector_float_subvec(state), do: subvecer(:vector_float, state)
def vector_boolean_subvec(state), do: subvecer(:vector_boolean, state)
def vector_string_subvec(state), do: subvecer(:vector_string, state)
@doc "Takes a type and a state and gets the first item from the type stack."
def firster(type, lit_type, state) do
if not(Enum.empty?(state[type])) and not(Enum.empty?(List.first(state[type]))) do
push_item(List.first(top_item(type, state)), lit_type, pop_item(type, state))
else
state
end
end
def vector_integer_first(state), do: firster(:vector_integer, :integer, state)
def vector_float_first(state), do: firster(:vector_float, :float, state)
def vector_boolean_first(state), do: firster(:vector_boolean, :boolean, state)
def vector_string_first(state), do: firster(:vector_string, :string, state)
@doc "Takes a type and a state and gets the last item from the type stack."
def laster(type, lit_type, state) do
if not(Enum.empty?(state[type])) and not(Enum.empty?(List.first(state[type]))) do
push_item(List.last(top_item(type, state)), lit_type, pop_item(type, state))
else
state
end
end
def vector_integer_last(state), do: laster(:vector_integer, :integer, state)
def vector_float_last(state), do: laster(:vector_float, :float, state)
def vector_boolean_last(state), do: laster(:vector_boolean, :boolean, state)
def vector_string_last(state), do: laster(:vector_string, :string, state)
@doc "Takes a type and a state and gets the nth item from the type stack."
def nther(type, lit_type, state) do
if (not(Enum.empty?(state[type])) and not(Enum.empty?(List.first(state[type])))) and not(Enum.empty?(state[:integr])) do
vect = stack_ref(type, 0, state)
index = rem(stack_ref(:integer, 0, state), Enum.count(vect))
Enum.at(vect, index) |> push_item(lit_type, pop_item(:integer, pop_item(type, state)))
else
state
end
end
def vector_integer_nth(state), do: nther(:vector_integer, :integer, state)
def vector_float_nth(state), do: nther(:vector_float, :float, state)
def vector_boolean_nth(state), do: nther(:vector_boolean, :boolean, state)
def vector_string_nth(state), do: nther(:vector_string, :string, state)
@doc "Takes a type and a state and takes the rest of the top item on the type stack."
def rester(type, state) do
if (not(Enum.empty?(state[type]))) do
top_item(type, state) |> Enum.drop(1) |> push_item(type, pop_item(type, state))
else
state
end
end
def vector_integer_rest(state), do: rester(:vector_integer, state)
def vector_float_rest(state), do: rester(:vector_float, state)
def vector_boolean_rest(state), do: rester(:vector_boolean, state)
def vector_string_rest(state), do: rester(:vector_string, state)
@doc "Takes a type and a state and takes the butlast of the top item on the type stack."
def butlaster(type, state) do
if (not(Enum.empty?(state[type]))) do
top_item(type, state) |> Enum.drop(-1) |> push_item(type, pop_item(type, state))
else
state
end
end
def vector_integer_butlast(state), do: butlaster(:vector_integer, state)
def vector_float_butlast(state), do: butlaster(:vector_float, state)
def vector_boolean_butlast(state), do: butlaster(:vector_boolean, state)
def vector_string_butlast(state), do: butlaster(:vector_string, state)
@doc "Takes a type and a state and takes the length of the top item on the type stack."
def lengther(type, state) do
if (not(Enum.empty?(state[type]))) do
top_item(type, state) |> Enum.count |> push_item(:integer, pop_item(type, state))
else
state
end
end
def vector_integer_length(state), do: lengther(:vector_integer, state)
def vector_float_length(state), do: lengther(:vector_float, state)
def vector_boolean_length(state), do: lengther(:vector_boolean, state)
def vector_string_length(state), do: lengther(:vector_string, state)
@doc "Takes a type and a state and takes the reverse of the top item on the type stack."
def reverser(type, state) do
if (not(Enum.empty?(state[type]))) do
top_item(type, state) |> Enum.reverse |> push_item(type, pop_item(type, state))
else
state
end
end
def vector_integer_reverse(state), do: reverser(:vector_integer, state)
def vector_float_reverse(state), do: reverser(:vector_float, state)
def vector_boolean_reverse(state), do: reverser(:vector_boolean, state)
def vector_string_reverse(state), do: reverser(:vector_string, state)
@doc "Takes a type and a state and pushes every item from the first vector onto the appropriate stack."
def pushaller(type, lit_type, state) do
if Enum.empty?(state[type]) do
state
else
loop = fn(f, lit_list, loop_state) ->
if Enum.empty?(lit_list) do
loop_state
else
f.(f, Enum.drop(lit_list, 1), push_item(List.first(lit_list), lit_type, loop_state))
end
end
loop.(loop, Enum.reverse(top_item(type, state)), pop_item(type, state))
end
end
def vector_integer_pushall(state), do: pushaller(:vector_integer, :integer, state)
def vector_float_pushall(state), do: pushaller(:vector_float, :float, state)
def vector_boolean_pushall(state), do: pushaller(:vector_boolean, :boolean, state)
def vector_string_pushall(state), do: pushaller(:vector_string, :string, state)
@doc "Takes a type and a state and pushes a boolean of whether the top vector is empty."
def emptyvectorer(type, state) do
if (not(Enum.empty?(state[type]))) do
top_item(type, state) |> Enum.empty? |> push_item(:boolean, pop_item(type, state))
else
state
end
end
def vector_integer_emptyvector(state), do: emptyvectorer(:vector_integer, state)
def vector_float_emptyvector(state), do: emptyvectorer(:vector_float, state)
def vector_boolean_emptyvector(state), do: emptyvectorer(:vector_boolean, state)
def vector_string_emptyvector(state), do: emptyvectorer(:vector_string, state)
@doc "Takes a type and a state and tells whether the top lit_type item is in the top type vector."
def containser(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(state[lit_type]) do
state
else
item = top_item(lit_type, state)
vect = top_item(type, state)
Enum.member?(vect, item) |> push_item(:boolean, pop_item(lit_type, pop_item(type, state)))
end
end
def vector_integer_contains(state), do: containser(:vector_integer, :integer, state)
def vector_float_contains(state), do: containser(:vector_float, :float, state)
def vector_boolean_contains(state), do: containser(:vector_boolean, :boolean, state)
def vector_string_contains(state), do: containser(:vector_string, :string, state)
@doc "Takes a type and a state and finds the index of the top lit_type item in the top type vector."
def indexofer(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(state[lit_type]) do
state
else
item = top_item(lit_type, state)
vect = top_item(type, state)
result = Enum.find_index(vect, item)
(if result == nil, do: -1, else: result) |> push_item(:integer, pop_item(lit_type, pop_item(type, state)))
end
end
def vector_integer_indexof(state), do: indexofer(:vector_integer, :integer, state)
def vector_float_indexof(state), do: indexofer(:vector_float, :float, state)
def vector_boolean_indexof(state), do: indexofer(:vector_boolean, :boolean, state)
def vector_string_indexof(state), do: indexofer(:vector_string, :string, state)
@doc "Takes a type and a state and counts the occurrences of the top lit_type item in the top type vector."
def occurrencesofer(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(state[lit_type]) do
state
else
item = top_item(lit_type, state)
vect = top_item(type, state)
result = vect |> Enum.filter(&(&1 == item)) |> Enum.count
result |> push_item(:integer, pop_item(lit_type, pop_item(type, state)))
end
end
def vector_integer_occurrencesof(state), do: occurrencesofer(:vector_integer, :integer, state)
def vector_float_occurrencesof(state), do: occurrencesofer(:vector_float, :float, state)
def vector_boolean_occurrencesof(state), do: occurrencesofer(:vector_boolean, :boolean, state)
def vector_string_occurrencesof(state), do: occurrencesofer(:vector_string, :string, state)
@doc """
Takes a type and a state and replaces, in the top type vector, item at index
(from integer stack) with the first lit_type item.
"""
def seter(type, lit_type, state) do
if (Enum.empty?(state[type]) or Enum.empty?(state[lit_type])) or (Enum.empty?(state[:integer]) or (lit_type == :integer and Enum.empty?(Enum.drop(state[:integer], 1)))) do
state
else
vect = top_item(type, state)
item = if lit_type == :integer, do: stack_ref(:integer, 1, state), else: top_item(lit_type, state)
index = if Enum.empty?(vect), do: 0, else: rem(top_item(:integer, state), Enum.count(vect))
result = if Enum.empty?(vect), do: vect, else: List.replace_at(vect, index, item)
result |> push_item(type, pop_item(lit_type, pop_item(:integer, pop_item(type, state))))
end
end
def vector_integer_set(state), do: seter(:vector_integer, :integer, state)
def vector_float_set(state), do: seter(:vector_float, :float, state)
def vector_boolean_set(state), do: seter(:vector_boolean, :boolean, state)
def vector_string_set(state), do: seter(:vector_string, :string, state)
@doc """
Takes a type and a state and replaces all occurrences of the second lit_type
item with the first lit_type item in the top type vector.
"""
def replaceer(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(Enum.drop(state[lit_type], 1)) do
state
else
replace_with = stack_ref(lit_type, 0, state)
to_replace = stack_ref(lit_type, 1, state)
vect = top_item(type, state)
result = vect |> Enum.map(&(if &1 == to_replace, do: replace_with, else: &1))
result |> push_item(type, pop_item(lit_type, pop_item(lit_type, pop_item(type, state))))
end
end
def vector_integer_replace(state), do: replaceer(:vector_integer, :integer, state)
def vector_float_replace(state), do: replaceer(:vector_float, :float, state)
def vector_boolean_replace(state), do: replaceer(:vector_boolean, :boolean, state)
def vector_string_replace(state), do: replaceer(:vector_string, :string, state)
@doc """
Takes a type and a state and replaces the first occurrence of the second
lit_type item with the first lit_type item in the top type vector.
"""
def replacefirster(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(Enum.drop(state[lit_type], 1)) do
state
else
replace_with = stack_ref(lit_type, 0, state)
to_replace = stack_ref(lit_type, 1, state)
vect = top_item(type, state)
index = vect |> Enum.find(&(&1 == to_replace))
index = if index == nil, do: -1, else: index
result = List.replace_at(vect, index, replace_with)
result |> push_item(type, pop_item(lit_type, pop_item(lit_type, pop_item(type, state))))
end
end
def vector_integer_replacefirst(state), do: replacefirster(:vector_integer, :integer, state)
def vector_float_replacefirst(state), do: replacefirster(:vector_float, :float, state)
def vector_boolean_replacefirst(state), do: replacefirster(:vector_boolean, :boolean, state)
def vector_string_replacefirst(state), do: replacefirster(:vector_string, :string, state)
@doc """
Takes a type and a state and removes all occurrences of the first lit_type item
in the top type vector.
"""
def removeer(type, lit_type, state) do
if Enum.empty?(state[type]) or Enum.empty?(state[lit_type]) do
state
else
vect = top_item(type, state)
item = top_item(lit_type, state)
result = vect |> Enum.filter(&(&1 != top_item(lit_type, state)))
result |> push_item(type, pop_item(lit_type, pop_item(type, state)))
end
end
def vector_integer_remove(state), do: removeer(:vector_integer, :integer, state)
def vector_float_remove(state), do: removeer(:vector_float, :float, state)
def vector_boolean_remove(state), do: removeer(:vector_boolean, :boolean, state)
def vector_string_remove(state), do: removeer(:vector_string, :string, state)
@doc """
Takes a type and a state and iterates over the type vector using the code on the
exec stack. If the vector isn't empty, expands to:
((first vector) (top-item :exec state) (rest vector) exec_do*vector_type (top-item :exec state) rest_of_program)
"""
def iterateer(type, lit_type, instr, state) do
if Enum.empty?(state[type]) or Enum.empty?(state[:exec]) do
state
else
vect = top_item(type, state)
cond do
Enum.empty?(vect) -> pop_item(:exec, pop_item(type, state))
Enum.empty?(Enum.drop(vect, 1)) -> push_item(List.first(vect), lit_type, pop_item(type, state))
true -> push_item(List.first(vect), lit_type, push_item(top_item(:exec, state), :exec, push_item(Enum.drop(vect, 1), :exec, push_item(instr, :exec, pop_item(type, state)))))
end
end
end
def exec_do_star_vector_integer(state), do: iterateer(:vector_integer, :integer, :exec_do_star_vector_integer, state)
def exec_do_star_vector_float(state), do: iterateer(:vector_float, :float, :exec_do_star_vector_float, state)
def exec_do_star_vector_boolean(state), do: iterateer(:vector_boolean, :boolean, :exec_do_star_vector_boolean, state)
def exec_do_star_vector_string(state), do: iterateer(:vector_string, :string, :exec_do_star_vector_string, state)
end