     end
 
     test "rotate top 3 elements of stack up" do # what's "up" on a stack? Assumes the last element of the stack is on the bottom in the minds' eye
-      assert RPNForthThing.initialize(~w[ 1 2 3 rot3^ / / ]) == 0.6666666666666666
+      assert RPNForthThing.initialize(~w[ 2 4 8 rot3^ / / ]) == 1
     end
 
     test "rotate top 3 elements of stack down" do
-      assert RPNForthThing.initialize(~w[ 1 2 3 rot3v / / ]) == 6.0
+      assert RPNForthThing.initialize(~w[ 8 4 2 rot3v / / ]) == 1
     end
 
     # test "rotate entire stack up" do # what's "up" on a stack? Assumes the last element of the stack is on the bottom in the minds' eye

    end

    test "dividing 2 numbers" do
      assert RPNForthThing.initialize(~w[3 2 /]) === 1.5
    end

    test "sequence of simple math operations" do
      assert RPNForthThing.initialize(~w[ 1 2 3 4 5 * + + + 2 /]) === 13.0
    end

    test "power" do
      assert RPNForthThing.initialize(~w[ 10.0 3.0 ** ]) === 1000.0
    end

    test "pi" do

    ) #Enum.map
  end

  # defp validate_num(num) when is_float(num), do: num
  defp validate_num(num) when is_integer(num), do: num
  defp validate_num(num) when is_binary(num) do
    cond do
      num =~ ~r/^-?[0-9]+$/              -> String.to_integer(num)
      # num =~ ~r/^-?[0-9]+(?:\.[0-9]+)?$/ -> String.to_float(num)
      true                           -> :NaN
    end
  end

  def compute([], [last_val], _, _) do
    last_val
  end

  def compute([], [], _, _) do
    # just bail
  end

  def compute([ "end" | _ ], data_stack, [], _) do
    if Enum.count(data_stack) == 1 do
      List.first(data_stack)
    else
      data_stack
    end
  end

  def compute([ "do" | remainder ], [x, y | data_stack], loop_stack, dict) do
    # The way this works is:
    # DO moves the index (0) and the control (5) over to the loop stack.
    # I copies the top of the loop stack to the data stack.
    # LOOP increments the index (top of loop stack).
    # If the index is less than the control (one below the top of loop stack),
    # then it reruns the commands from DO back to LOOP.
    # If the index is >=, then it pops the index and control from the
    # loop stack, and control resumes as normal.
    compute(remainder, data_stack, [x, y, %{do: remainder} | loop_stack], dict)
  end

  def compute([ "i" | remainder ], data_stack, [x, _y, %{do: _do_block} | _rest_of_loop_stack] = loop_stack, dict) do
    compute(remainder, [x | data_stack], loop_stack, dict)
  end

  def compute([ "j" | remainder ], data_stack, [_x, _y, %{do: _do_block}, z | _rest_of_loop_stack] = loop_stack, dict) do
    compute(remainder, [z | data_stack], loop_stack, dict)
  end

  # loops. holy crap NESTED LOOPS WORK.
  def compute([ "loop" | remainder ], data_stack, [x, y, %{do: do_block} | loop_stack], dict) do
    x = x + 1
    if x < y do
      compute(do_block, data_stack, [x, y, %{do: do_block} | loop_stack], dict)
    else
      compute(remainder, data_stack, loop_stack, dict)
    end
  end

  def compute([ "+" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [x + y | data_stack], loop_stack, dict)
  end

  def compute([ "-" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [x - y | data_stack], loop_stack, dict)
  end

  def compute([ "*/" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(["*", x, "/" | remaining_input], data_stack, loop_stack, dict)
  end

  def compute([ "*" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [x * y | data_stack], loop_stack, dict)
  end

  def compute([ "/" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [trunc(x / y) | data_stack], loop_stack, dict)
  end

  def compute([ "**" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [trunc(:math.pow(x, y)) | data_stack], loop_stack, dict)
  end

  # note: allowing these conflicts with integer-only arithmetic
  def compute([ "pi" | remaining_input], data_stack, loop_stack, dict) do
    compute(remaining_input, [:math.pi | data_stack], loop_stack, dict)
  end

  def compute([ "sin" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [:math.sin(x) | data_stack], loop_stack, dict)
  end

  def compute([ "cos" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [:math.cos(x) | data_stack], loop_stack, dict)
  end

  def compute([ "tan" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [:math.tan(x) | data_stack], loop_stack, dict)
  end

  def compute([ "sqrt" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [:math.sqrt(x) | data_stack], loop_stack, dict)
  end

  def compute([ "drop" | remaining_input], [_ | data_stack], loop_stack, dict) do
    compute(remaining_input, data_stack, loop_stack, dict)
  end

  def compute([ "dup" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [x, x | data_stack], loop_stack, dict)
  end

  def compute([ "swap" | remaining_input], [y, x | data_stack], loop_stack, dict) do
    compute(remaining_input, [x, y | data_stack], loop_stack, dict)
  end

  # In-place decrement
  def compute([ "1-" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [(x - 1) | data_stack], loop_stack, dict)
  end

  # In-place increment
  def compute([ "1+" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [(x + 1) | data_stack], loop_stack, dict)
  end

  # In-place negation
  def compute([ "@-" | remaining_input], [x | data_stack], loop_stack, dict) do
    compute(remaining_input, [-x | data_stack], loop_stack, dict)
  end

  # random numbers
  def compute([ "rand" | remaining_input], data_stack, loop_stack, dict) do
    compute(remaining_input, [:rand.uniform | data_stack], loop_stack, dict)
  end

  # max
  def compute([ "max" | remaining_input], [a, b | data_stack], loop_stack, dict) do
    max = case a < b do
      true -> b
      false -> a
    end
    compute(remaining_input, [max | data_stack], loop_stack, dict)
  end

  # min
  def compute([ "min" | remaining_input], [a, b | data_stack], loop_stack, dict) do
    min = case a < b do
      true -> a
      false -> b
    end
    compute(remaining_input, [min | data_stack], loop_stack, dict)
  end

  # inspection. just spits out the remaining instructions, and the data_stack and dict states
  # Sort of, shockingly simple?
  def compute([ "inspect" | remaining_input], data_stack, loop_stack, dict) do
    IO.puts "Remaining instructions:"
    IO.inspect remaining_input
    IO.puts "Data Stack:"
    IO.inspect data_stack
    IO.puts "Loop Stack:"
    IO.inspect loop_stack
    IO.puts "Dictionary:"
    IO.inspect dict
    compute(remaining_input, data_stack, loop_stack, dict)
  end

  # Logic/Booleans
