aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/interpreter/interpreter.go10
-rw-r--r--pkg/interpreter/interpreter_test.go50
-rw-r--r--pkg/pointer/pointer.go52
-rw-r--r--pkg/pointer/pointer_test.go64
-rw-r--r--pkg/pointer/stack-stack.go (renamed from pkg/stack/stack-stack.go)18
-rw-r--r--pkg/pointer/stack-stack_test.go (renamed from pkg/stack/stack-stack_test.go)39
-rw-r--r--pkg/pointer/stack.go (renamed from pkg/stack/stack.go)2
-rw-r--r--pkg/pointer/stack_test.go (renamed from pkg/stack/stack_test.go)2
8 files changed, 206 insertions, 31 deletions
diff --git a/pkg/interpreter/interpreter.go b/pkg/interpreter/interpreter.go
index ce2499d..b64e90a 100644
--- a/pkg/interpreter/interpreter.go
+++ b/pkg/interpreter/interpreter.go
@@ -25,7 +25,8 @@ func (i *Interpreter) Run() {
func (i *Interpreter) Step() {
var prev *pointer.Pointer = nil
for p := i.p; p != nil; p = p.Next {
- switch p.Get(*i.f) {
+ c := p.Get(*i.f)
+ switch c {
case '@':
if prev == nil {
i.p = p.Next
@@ -33,8 +34,13 @@ func (i *Interpreter) Step() {
prev.Next = p.Next
}
break
+ case '#':
+ p.Step(*i.f)
default:
- log.Fatalf("Non implemented instruction code %d : %c", p.Get(*i.f), p.Get(*i.f))
+ if !p.Redirect(c) {
+ log.Fatalf("Non implemented instruction code %d : %c", c, c)
+ }
}
+ p.Step(*i.f)
}
}
diff --git a/pkg/interpreter/interpreter_test.go b/pkg/interpreter/interpreter_test.go
new file mode 100644
index 0000000..ff633a2
--- /dev/null
+++ b/pkg/interpreter/interpreter_test.go
@@ -0,0 +1,50 @@
+package interpreter
+
+import (
+ "os"
+ "testing"
+
+ "git.adyxax.org/adyxax/gofunge/pkg/field"
+ "git.adyxax.org/adyxax/gofunge/pkg/pointer"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRun(t *testing.T) {
+ file, err := os.Open("../field/test_data/minimal.b98")
+ require.NoError(t, err)
+ defer file.Close()
+ f, err := field.Load(file)
+ require.NoError(t, err)
+ NewInterpreter(f, pointer.NewPointer()).Run()
+}
+
+func TestStep(t *testing.T) {
+ testCases := []struct {
+ name string
+ filename string
+ pointer *pointer.Pointer
+ expectedField *field.Field
+ expectedPointer *pointer.Pointer
+ }{
+ {"minimal", "../field/test_data/minimal.b98", nil, nil, nil},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ file, err := os.Open(tc.filename)
+ require.NoError(t, err)
+ defer file.Close()
+ f, err := field.Load(file)
+ require.NoError(t, err)
+ if tc.pointer == nil {
+ tc.pointer = pointer.NewPointer()
+ }
+ NewInterpreter(f, tc.pointer).Step()
+ if tc.expectedField != nil {
+ require.Equal(t, tc.expectedField, f)
+ }
+ if tc.expectedPointer != nil {
+ require.Equal(t, tc.expectedPointer, tc.pointer)
+ }
+ })
+ }
+}
diff --git a/pkg/pointer/pointer.go b/pkg/pointer/pointer.go
index a833f5b..4d847bf 100644
--- a/pkg/pointer/pointer.go
+++ b/pkg/pointer/pointer.go
@@ -1,6 +1,10 @@
package pointer
-import "git.adyxax.org/adyxax/gofunge/pkg/field"
+import (
+ "math/rand"
+
+ "git.adyxax.org/adyxax/gofunge/pkg/field"
+)
type Pointer struct {
// the position
@@ -12,12 +16,14 @@ type Pointer struct {
// The Storage offset
sox int
soy int
+ // The stack
+ ss *StackStack
// The next element for the multi-"threaded" b98 interpreter
Next *Pointer
}
func NewPointer() *Pointer {
- return &Pointer{dx: 1}
+ return &Pointer{dx: 1, ss: NewStackStack()}
}
func (p Pointer) Split() *Pointer {
@@ -31,3 +37,45 @@ func (p *Pointer) Step(f field.Field) {
func (p Pointer) Get(f field.Field) int {
return f.Get(p.x, p.y)
}
+
+func (p *Pointer) Set(x, y int) {
+ p.x, p.y = x, y
+}
+
+func (p *Pointer) RedirectTo(dx, dy int) {
+ p.dx, p.dy = dx, dy
+}
+
+func (p *Pointer) Reverse() {
+ p.dx, p.dy = -p.dx, -p.dy
+}
+
+func (p *Pointer) Redirect(c int) bool {
+ switch c {
+ case '^':
+ p.dx, p.dy = 0, -1
+ case '>':
+ p.dx, p.dy = 1, 0
+ case 'v':
+ p.dx, p.dy = 0, 1
+ case '<':
+ p.dx, p.dy = -1, 0
+ case '?':
+ directions := []int{0, -1, 1, 0, 0, 1, -1, 0}
+ r := 2 * rand.Intn(4)
+ p.dx, p.dy = directions[r], directions[r+1]
+ case '[':
+ p.dx, p.dy = p.dy, -p.dx
+ case ']':
+ p.dx, p.dy = -p.dy, p.dx
+ case 'r':
+ p.Reverse()
+ case 'x':
+ dy := p.ss.Pop()
+ dx := p.ss.Pop()
+ p.RedirectTo(dx, dy)
+ default:
+ return false
+ }
+ return true
+}
diff --git a/pkg/pointer/pointer_test.go b/pkg/pointer/pointer_test.go
index ccbf486..4885d6b 100644
--- a/pkg/pointer/pointer_test.go
+++ b/pkg/pointer/pointer_test.go
@@ -9,7 +9,7 @@ import (
)
func TestNewPointer(t *testing.T) {
- require.Equal(t, NewPointer(), &Pointer{dx: 1})
+ require.Equal(t, NewPointer(), &Pointer{dx: 1, ss: NewStackStack()})
}
func TestSplit(t *testing.T) {
@@ -23,8 +23,8 @@ func TestSplit(t *testing.T) {
// We check that p2 is a real copy
p.Step(*f)
p2.Step(*f)
- require.Equal(t, &Pointer{x: 1, y: 0, dx: 1}, p)
- require.Equal(t, &Pointer{x: 1, y: 0, dx: 1}, p2)
+ require.Equal(t, &Pointer{x: 1, y: 0, dx: 1, ss: NewStackStack()}, p)
+ require.Equal(t, &Pointer{x: 1, y: 0, dx: 1, ss: NewStackStack()}, p2)
}
func TestStep(t *testing.T) { // Step is thoroughly tested in the field package
@@ -50,3 +50,61 @@ func TestGet(t *testing.T) {
v := p.Get(*f)
require.Equal(t, int('@'), v)
}
+
+func TestSet(t *testing.T) {
+ p := NewPointer()
+ p.Set(3, 14)
+ require.Equal(t, 3, p.x)
+ require.Equal(t, 14, p.y)
+}
+
+func TestRedirectTo(t *testing.T) {
+ p := NewPointer()
+ p.RedirectTo(3, 14)
+ require.Equal(t, 3, p.dx)
+ require.Equal(t, 14, p.dy)
+}
+
+func TestReverse(t *testing.T) {
+ p := NewPointer()
+ p.RedirectTo(3, 14)
+ p.Reverse()
+ require.Equal(t, -3, p.dx)
+ require.Equal(t, -14, p.dy)
+}
+
+func TestRedirect(t *testing.T) {
+ testCases := []struct {
+ name string
+ input byte
+ expectedDx int
+ expectedDy int
+ }{
+ {"up", '^', 0, -1},
+ {"right", '>', 1, 0},
+ {"down", 'v', 0, 1},
+ {"left", '<', -1, 0},
+ {"turn left", '[', 14, -3},
+ {"turn right", ']', -14, 3},
+ {"reverse", 'r', -3, -14},
+ {"redirectTo", 'x', 2, 7},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := NewPointer()
+ p.RedirectTo(3, 14)
+ p.ss.Push(2)
+ p.ss.Push(7)
+ v := p.Redirect(int(tc.input))
+ require.Equal(t, true, v)
+ require.Equal(t, tc.expectedDx, p.dx, "Invalid dx value")
+ require.Equal(t, tc.expectedDy, p.dy, "Invalid dy value")
+ })
+ }
+ // We cannot really test random, can we? This just gives coverage
+ p := NewPointer()
+ v := p.Redirect(int('?'))
+ require.Equal(t, true, v)
+ // A character that does not redirect should return false
+ require.Equal(t, false, p.Redirect(int('@')))
+}
diff --git a/pkg/stack/stack-stack.go b/pkg/pointer/stack-stack.go
index 9b80079..6d22f51 100644
--- a/pkg/stack/stack-stack.go
+++ b/pkg/pointer/stack-stack.go
@@ -1,8 +1,4 @@
-package stack
-
-import (
- "git.adyxax.org/adyxax/gofunge/pkg/pointer"
-)
+package pointer
type StackStack struct {
head *Stack
@@ -16,7 +12,7 @@ func NewStackStack() *StackStack {
}
}
-func (ss *StackStack) Begin(p *pointer.Pointer) {
+func (ss *StackStack) Begin(p *Pointer) {
ss.height++
soss := ss.head
n := soss.Pop()
@@ -44,7 +40,7 @@ func (ss *StackStack) Begin(p *pointer.Pointer) {
p.CalculateNewStorageOffset()
}
-func (ss *StackStack) End(p *pointer.Pointer) (reflect bool) {
+func (ss *StackStack) End(p *Pointer) (reflect bool) {
if ss.height == 1 {
return true
}
@@ -89,3 +85,11 @@ func (ss *StackStack) Under() (reflect bool) {
}
return false
}
+
+func (ss StackStack) Pop() int {
+ return ss.head.Pop()
+}
+
+func (ss StackStack) Push(v int) {
+ ss.head.Push(v)
+}
diff --git a/pkg/stack/stack-stack_test.go b/pkg/pointer/stack-stack_test.go
index d2a7949..fd4c9ea 100644
--- a/pkg/stack/stack-stack_test.go
+++ b/pkg/pointer/stack-stack_test.go
@@ -1,11 +1,10 @@
-package stack
+package pointer
import (
"os"
"testing"
"git.adyxax.org/adyxax/gofunge/pkg/field"
- "git.adyxax.org/adyxax/gofunge/pkg/pointer"
"github.com/stretchr/testify/require"
)
@@ -17,7 +16,7 @@ func TestBegin(t *testing.T) {
expected.head.next.Push(0)
expected.height++
ss := NewStackStack()
- p := pointer.NewPointer()
+ p := NewPointer()
ss.Begin(p)
require.Equal(t, expected, ss)
x, y := p.GetStorageOffset()
@@ -40,7 +39,7 @@ func TestBegin(t *testing.T) {
expected.head.next.Push(0)
expected.head.next.Push(0)
expected.height++
- p := pointer.NewPointer()
+ p := NewPointer()
file, err := os.Open("../field/test_data/hello.b98")
require.NoError(t, err, "Failed to open file")
f, err := field.Load(file)
@@ -61,7 +60,7 @@ func TestBegin(t *testing.T) {
expected.head.next.Push(2)
expected.head.next.Push(3)
expected.height++
- p := pointer.NewPointer()
+ p := NewPointer()
p.SetStorageOffset(2, 3)
file, err := os.Open("../field/test_data/hello.b98")
require.NoError(t, err, "Failed to open file")
@@ -87,7 +86,7 @@ func TestBegin(t *testing.T) {
expected.head.next.Push(36)
expected.head.next.Push(42)
expected.height++
- p := pointer.NewPointer()
+ p := NewPointer()
p.SetStorageOffset(36, 42)
ss := NewStackStack()
ss.head.Push(7)
@@ -104,7 +103,7 @@ func TestBegin(t *testing.T) {
func TestEnd(t *testing.T) {
t.Run("empty", func(t *testing.T) {
expected := NewStackStack()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.Begin(p)
reflect := ss.End(p)
@@ -121,7 +120,7 @@ func TestEnd(t *testing.T) {
expected.head.Pop()
expected.head.Pop()
expected.head.Pop()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.head.Push(7)
ss.head.Push(12)
@@ -139,7 +138,7 @@ func TestEnd(t *testing.T) {
})
t.Run("drop too much", func(t *testing.T) {
expected := NewStackStack()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.Begin(p)
ss.head.Push(-3)
@@ -149,7 +148,7 @@ func TestEnd(t *testing.T) {
})
t.Run("reflect", func(t *testing.T) {
expected := NewStackStack()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
reflect := ss.End(p)
require.Equal(t, true, reflect)
@@ -164,7 +163,7 @@ func TestEnd(t *testing.T) {
expected.head.Push(14)
expected.head.Push(-2)
expected.head.Push(5)
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.head.size = 4
ss.head.data = make([]int, 4)
@@ -195,7 +194,7 @@ func TestUnder(t *testing.T) {
require.Equal(t, expected, ss)
})
t.Run("positive", func(t *testing.T) {
- pe := pointer.NewPointer()
+ pe := NewPointer()
expected := NewStackStack()
expected.head.Push(1)
expected.head.Push(2)
@@ -209,7 +208,7 @@ func TestUnder(t *testing.T) {
expected.head.next.Pop()
expected.head.next.Pop()
expected.head.next.Pop()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.head.Push(1)
ss.head.Push(2)
@@ -223,7 +222,7 @@ func TestUnder(t *testing.T) {
require.Equal(t, expected, ss)
})
t.Run("negative", func(t *testing.T) {
- pe := pointer.NewPointer()
+ pe := NewPointer()
expected := NewStackStack()
expected.Begin(pe)
expected.head.next.Push(12)
@@ -237,7 +236,7 @@ func TestUnder(t *testing.T) {
expected.head.Pop()
expected.head.Pop()
expected.head.Pop()
- p := pointer.NewPointer()
+ p := NewPointer()
ss := NewStackStack()
ss.Begin(p)
ss.head.Push(8)
@@ -249,3 +248,13 @@ func TestUnder(t *testing.T) {
require.Equal(t, expected, ss)
})
}
+
+func TestPushPop(t *testing.T) {
+ ss := NewStackStack()
+ ss.Push(12)
+ ss.Push(5)
+ v := ss.Pop()
+ require.Equal(t, 5, v)
+ v = ss.Pop()
+ require.Equal(t, 12, v)
+}
diff --git a/pkg/stack/stack.go b/pkg/pointer/stack.go
index 4dbb72c..1832dbb 100644
--- a/pkg/stack/stack.go
+++ b/pkg/pointer/stack.go
@@ -1,4 +1,4 @@
-package stack
+package pointer
type Stack struct {
size int
diff --git a/pkg/stack/stack_test.go b/pkg/pointer/stack_test.go
index e48c615..1b16085 100644
--- a/pkg/stack/stack_test.go
+++ b/pkg/pointer/stack_test.go
@@ -1,4 +1,4 @@
-package stack
+package pointer
import (
"testing"