Intcode assembler: add tests
This commit is contained in:
parent
b933c30bea
commit
cbbd6d8692
|
@ -67,16 +67,39 @@ defmodule Assembler do
|
||||||
it -> it
|
it -> it
|
||||||
end)
|
end)
|
||||||
|
|
||||||
IO.inspect(labels)
|
# IO.inspect(labels)
|
||||||
Enum.reverse(memory)
|
Enum.reverse(memory)
|
||||||
end
|
end
|
||||||
|
|
||||||
def repeat(_, 0), do: []
|
@doc """
|
||||||
def repeat(n, count), do: [n | repeat(n, count - 1)]
|
Raises the base to to the given power.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.pow(10, 3)
|
||||||
|
1000
|
||||||
|
iex> Assembler.pow(5, 4)
|
||||||
|
625
|
||||||
|
"""
|
||||||
def pow(base, 1), do: base
|
def pow(base, 1), do: base
|
||||||
def pow(base, exp), do: base * pow(base, exp - 1)
|
def pow(base, exp), do: base * pow(base, exp - 1)
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Parses assembly instruction parameter values and modes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.parse_params("1 2 3", [:read, :read, :read])
|
||||||
|
{[1, 2, 3], 11100}
|
||||||
|
iex> Assembler.parse_params("1 2 3", [:read, :read, :write])
|
||||||
|
{[1, 2, 3], 1100}
|
||||||
|
iex> Assembler.parse_params("1 2 $3", [:read, :read, :write])
|
||||||
|
{[1, 2, 3], 1100}
|
||||||
|
iex> Assembler.parse_params("$1 2 3", [:read, :read, :write])
|
||||||
|
{[1, 2, 3], 1000}
|
||||||
|
iex> Assembler.parse_params("$label 2 3", [:read, :read, :write])
|
||||||
|
{[{:label, "label"}, 2, 3], 1000}
|
||||||
|
iex> Assembler.parse_params("1 label 3", [:read, :read, :write])
|
||||||
|
{[1, {:label, "label"}, 3], 1100}
|
||||||
|
"""
|
||||||
def parse_params(params, param_types) do
|
def parse_params(params, param_types) do
|
||||||
params
|
params
|
||||||
|> String.split(" ")
|
|> String.split(" ")
|
||||||
|
@ -110,54 +133,130 @@ defmodule Assembler do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assembles the given instruction and adds it to the memory (in reverse order).
|
||||||
|
"""
|
||||||
def assemble_instruction(insn, memory \\ [])
|
def assemble_instruction(insn, memory \\ [])
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble add instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("add 1 2 3")
|
||||||
|
[3, 2, 1, 1101]
|
||||||
|
"""
|
||||||
def assemble_instruction("add " <> params, memory) do
|
def assemble_instruction("add " <> params, memory) do
|
||||||
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
||||||
|
|
||||||
[dest, b, a, 1 + modes | memory]
|
[dest, b, a, 1 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble multiply instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("mul 1 2 3")
|
||||||
|
[3, 2, 1, 1102]
|
||||||
|
"""
|
||||||
def assemble_instruction("mul " <> params, memory) do
|
def assemble_instruction("mul " <> params, memory) do
|
||||||
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
||||||
|
|
||||||
[dest, b, a, 2 + modes | memory]
|
[dest, b, a, 2 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble halt instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("hlt")
|
||||||
|
[99]
|
||||||
|
"""
|
||||||
def assemble_instruction("hlt", memory) do
|
def assemble_instruction("hlt", memory) do
|
||||||
[99 | memory]
|
[99 | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble input instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("in 7")
|
||||||
|
[7, 3]
|
||||||
|
"""
|
||||||
def assemble_instruction("in " <> params, memory) do
|
def assemble_instruction("in " <> params, memory) do
|
||||||
{[dest], modes} = parse_params(params, [:write])
|
{[dest], modes} = parse_params(params, [:write])
|
||||||
|
|
||||||
[dest, 3 + modes | memory]
|
[dest, 3 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble input instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("out 7")
|
||||||
|
[7, 104]
|
||||||
|
iex> Assembler.assemble_instruction("out $7")
|
||||||
|
[7, 4]
|
||||||
|
"""
|
||||||
def assemble_instruction("out " <> params, memory) do
|
def assemble_instruction("out " <> params, memory) do
|
||||||
{[val], modes} = parse_params(params, [:read])
|
{[val], modes} = parse_params(params, [:read])
|
||||||
|
|
||||||
[val, 4 + modes | memory]
|
[val, 4 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble jump-if-non-zero instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("jnz 1 2")
|
||||||
|
[2, 1, 105]
|
||||||
|
iex> Assembler.assemble_instruction("jnz $var 2")
|
||||||
|
[2, {:label, "var"}, 5]
|
||||||
|
"""
|
||||||
def assemble_instruction("jnz " <> params, memory) do
|
def assemble_instruction("jnz " <> params, memory) do
|
||||||
{[target, dest], modes} = parse_params(params, [:read, :read])
|
{[target, dest], modes} = parse_params(params, [:read, :read])
|
||||||
|
|
||||||
[dest, target, 5 + modes | memory]
|
[dest, target, 5 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble jump-if-zero instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("jez 1 2")
|
||||||
|
[2, 1, 106]
|
||||||
|
iex> Assembler.assemble_instruction("jez $var 2")
|
||||||
|
[2, {:label, "var"}, 6]
|
||||||
|
"""
|
||||||
def assemble_instruction("jez " <> params, memory) do
|
def assemble_instruction("jez " <> params, memory) do
|
||||||
{[target, dest], modes} = parse_params(params, [:read, :read])
|
{[target, dest], modes} = parse_params(params, [:read, :read])
|
||||||
|
|
||||||
[dest, target, 6 + modes | memory]
|
[dest, target, 6 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble compare-less-than instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("clt 1 2 3")
|
||||||
|
[3, 2, 1, 1107]
|
||||||
|
iex> Assembler.assemble_instruction("clt $1 $2 3")
|
||||||
|
[3, 2, 1, 7]
|
||||||
|
"""
|
||||||
def assemble_instruction("clt " <> params, memory) do
|
def assemble_instruction("clt " <> params, memory) do
|
||||||
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
||||||
|
|
||||||
[dest, b, a, 7 + modes | memory]
|
[dest, b, a, 7 + modes | memory]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Assemble compare-equal instruction.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
iex> Assembler.assemble_instruction("ceq 1 2 3")
|
||||||
|
[3, 2, 1, 1108]
|
||||||
|
iex> Assembler.assemble_instruction("ceq $1 $2 3")
|
||||||
|
[3, 2, 1, 8]
|
||||||
|
"""
|
||||||
def assemble_instruction("ceq " <> params, memory) do
|
def assemble_instruction("ceq " <> params, memory) do
|
||||||
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
{[a, b, dest], modes} = parse_params(params, [:read, :read, :write])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
defmodule AssemblerTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Assembler
|
||||||
|
|
||||||
|
test "assembles empty program" do
|
||||||
|
assert Assembler.assemble("") == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "assembles simple program" do
|
||||||
|
program = """
|
||||||
|
add 1 2 10
|
||||||
|
mul 2 3 11
|
||||||
|
add $10 $11 12
|
||||||
|
hlt
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert Assembler.assemble(program) == [
|
||||||
|
1101,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
1102,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
11,
|
||||||
|
1,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
12,
|
||||||
|
99
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "assembles simple program with a label" do
|
||||||
|
program = """
|
||||||
|
add 1 2 10
|
||||||
|
jnz $10 nonZero
|
||||||
|
nonZero:
|
||||||
|
hlt
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert Assembler.assemble(program) == [
|
||||||
|
1101,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
1005,
|
||||||
|
10,
|
||||||
|
7,
|
||||||
|
99
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "assembles a simple program with a data label" do
|
||||||
|
program = """
|
||||||
|
add 1 2 var
|
||||||
|
out $var
|
||||||
|
var: 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert Assembler.assemble(program) == [
|
||||||
|
1101,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
6,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue