Packages

A simple Push programming language interpreter implemented in Elixir.

Current section

Files

Jump to
elixush lib instructions io.ex
Raw

lib/instructions/io.ex

defmodule Elixush.Instructions.IO do
import Elixush.PushState
import Elixush.Util
import Elixush.Globals.Agent
def print_exec(state) do
if Enum.empty?(state[:exec]) do
state
else
top_thing = top_item(:exec, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:exec, state)
)
end
end
end
def print_integer(state) do
if Enum.empty?(state[:integer]) do
state
else
top_thing = top_item(:integer, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:integer, state)
)
end
end
end
def print_float(state) do
if Enum.empty?(state[:float]) do
state
else
top_thing = top_item(:float, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:float, state)
)
end
end
end
def print_code(state) do
if Enum.empty?(state[:code]) do
state
else
top_thing = top_item(:code, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:code, state)
)
end
end
end
def print_boolean(state) do
if Enum.empty?(state[:boolean]) do
state
else
top_thing = top_item(:boolean, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:boolean, state)
)
end
end
end
def print_string(state) do
if Enum.empty?(state[:string]) do
state
else
top_thing = top_item(:string, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:string, state)
)
end
end
end
def print_char(state) do
if Enum.empty?(state[:char]) do
state
else
top_thing = top_item(:char, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:char, state)
)
end
end
end
def print_vector_integer(state) do
if Enum.empty?(state[:vector_integer]) do
state
else
top_thing = top_item(:vector_integer, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:vector_integer, state)
)
end
end
end
def print_vector_float(state) do
if Enum.empty?(state[:vector_float]) do
state
else
top_thing = top_item(:vector_float, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:vector_float, state)
)
end
end
end
def print_vector_boolean(state) do
if Enum.empty?(state[:vector_boolean]) do
state
else
top_thing = top_item(:vector_boolean, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:vector_boolean, state)
)
end
end
end
def print_vector_string(state) do
if Enum.empty?(state[:vector_string]) do
state
else
top_thing = top_item(:vector_string, state)
top_thing_string = Macro.to_string(top_thing)
if get_globals(:max_string_length) < length(to_string(stack_ref(:output, 0, state)) <> top_thing_string) do
state
else
stack_assoc(
to_string(stack_ref(:output, 0, state)) <> top_thing_string,
:output,
0,
pop_item(:vector_string, state)
)
end
end
end
def print_newline(state) do
if get_globals(:max_string_length) < (stack_ref(:output, 0, state) |> to_string) <> "\n" |> length do
state
else
stack_assoc(to_string(stack_ref(:output, 0, state)) <> "\n", :output, 0, state)
end
end
@doc """
Allows Push to handle inN instructions, e.g. in2, using things from the input
stack. We can tell whether a particular inN instruction is valid if N-1
values are on the input stack. Recognizes vectors, simple literals and quoted code.
"""
def handle_input_instruction(instr, state) do
n = Regex.run(~r/in(\d+)/, Atom.to_string(instr)) |> Enum.at(1) |> String.to_integer
if n > length(state[:input]) or n < 1 do
raise(ArgumentError, message: "Undefined instruction: #{instr} \nNOTE: Likely not same number of items on input stack as input instructions.")
else
item = stack_ref(:input, n - 1, state)
literal_type = recognize_literal(item)
cond do
is_list(item) && item == [] -> push_item([], :vector_integer, push_item([], :vector_float, push_item([], :vector_string, push_item([], :vector_boolean, state))))
is_tuple(item) -> push_item(item, :exec, state)
true -> push_item(item, literal_type, state)
end
end
end
end