Packages

A simple Push programming language interpreter implemented in Elixir.

Current section

Files

Jump to
elixush lib instructions float.ex
Raw

lib/instructions/float.ex

defmodule Elixush.Instructions.Float do
import Elixush.PushState
import Elixush.Util
@doc "Pushes the sum of the top two items."
def float_add(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
push_item(keep_number_reasonable(first + second), :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc "Pushes the difference of the top two items."
def float_sub(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
push_item(keep_number_reasonable(second - first), :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc "Pushes the product of the top two items."
def float_mult(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) and not(stack_ref(:float, 0, state) == 0) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = (second * first) |> keep_number_reasonable
push_item(item, :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc "Returns a function that pushes the product of the top two items."
def float_div(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) and not(stack_ref(:float, 0, state) == 0) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = (second / first) |> keep_number_reasonable
push_item(item, :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc """
Returns a function that pushes the modulus of the top two items. Does
nothing if the denominator would be zero.
"""
def float_mod(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) and not(stack_ref(:float, 0, state) == 0) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = (rem(second, first)) |> keep_number_reasonable
push_item(item, :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
### Comparers
@doc """
Returns a function that pushes the result of comparator of the top two items
on the ':float' stack onto the boolean stack.
"""
def float_lt(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = second < first
push_item(item, :boolean, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc """
Returns a function that pushes the result of comparator of the top two items
on the ':float' stack onto the boolean stack.
"""
def float_lte(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = second <= first
push_item(item, :boolean, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc """
Returns a function that pushes the result of comparator of the top two items
on the ':float' stack onto the boolean stack.
"""
def float_gt(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = second > first
push_item(item, :boolean, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc """
Returns a function that pushes the result of comparator of the top two items
on the ':float' stack onto the boolean stack.
"""
def float_gte(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
item = second >= first
push_item(item, :boolean, pop_item(:float, pop_item(:float, state)))
else
state
end
end
def float_fromboolean(state) do
if not(Enum.empty?(state[:boolean])) do
item = stack_ref(:boolean, 0, state)
to_push = if item do 1.0 else 0.0 end
push_item(to_push, :float, pop_item(:boolean, state))
else
state
end
end
def float_frominteger(state) do
if not(Enum.empty?(state[:integer])) do
item = stack_ref(:integer, 0, state)
push_item(item * 1.0, :float, pop_item(:integer, state))
else
state
end
end
def float_fromstring(state) do
if not(Enum.empty?(state[:string])) do
try do
pop_item(:string, push_item(keep_number_reasonable(String.to_float(top_item(:string, state))), :float, state))
rescue
e in ArgumentError -> {e, state}
end
else
state
end
end
# TODO: Add float_fromchar
@doc "Returns a function that pushes the minimum of the top two items."
def float_min(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
push_item(min(second, first), :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
@doc "Returns a function that pushes the maximum of the top two items."
def float_max(state) do
if not(Enum.empty?(Enum.drop(state[:float], 1))) do
first = stack_ref(:float, 0, state)
second = stack_ref(:float, 1, state)
push_item(max(second, first), :float, pop_item(:float, pop_item(:float, state)))
else
state
end
end
def float_sin(state) do
if not(Enum.empty?(state[:float])) do
push_item(keep_number_reasonable(:math.sin(stack_ref(:float, 0, state))), :float, pop_item(:float, state))
else
state
end
end
def float_cos(state) do
if not(Enum.empty?(state[:float])) do
push_item(keep_number_reasonable(:math.cos(stack_ref(:float, 0, state))), :float, pop_item(:float, state))
else
state
end
end
def float_tan(state) do
if not(Enum.empty?(state[:float])) do
push_item(keep_number_reasonable(:math.tan(stack_ref(:float, 0, state))), :float, pop_item(:float, state))
else
state
end
end
def float_inc(state) do
if not(Enum.empty?(state[:float])) do
push_item(keep_number_reasonable(stack_ref(:float, 0, state)) + 1.0, :float, pop_item(:float, state))
else
state
end
end
def float_dec(state) do
if not(Enum.empty?(state[:float])) do
push_item(keep_number_reasonable(stack_ref(:float, 0, state)) - 1.0, :float, pop_item(:float, state))
else
state
end
end
end