From 759ee2aa10323d1960405c93f7cd4cf6d383ae7a Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Thu, 23 Sep 2021 11:45:49 +0200 Subject: Each pointer needs its own stack, merging the two packages to avoid a circular dependency --- pkg/interpreter/interpreter.go | 10 +- pkg/interpreter/interpreter_test.go | 50 +++++++ pkg/pointer/pointer.go | 52 +++++++- pkg/pointer/pointer_test.go | 64 ++++++++- pkg/pointer/stack-stack.go | 95 +++++++++++++ pkg/pointer/stack-stack_test.go | 260 ++++++++++++++++++++++++++++++++++++ pkg/pointer/stack.go | 51 +++++++ pkg/pointer/stack_test.go | 74 ++++++++++ pkg/stack/stack-stack.go | 91 ------------- pkg/stack/stack-stack_test.go | 251 ---------------------------------- pkg/stack/stack.go | 51 ------- pkg/stack/stack_test.go | 74 ---------- 12 files changed, 649 insertions(+), 474 deletions(-) create mode 100644 pkg/interpreter/interpreter_test.go create mode 100644 pkg/pointer/stack-stack.go create mode 100644 pkg/pointer/stack-stack_test.go create mode 100644 pkg/pointer/stack.go create mode 100644 pkg/pointer/stack_test.go delete mode 100644 pkg/stack/stack-stack.go delete mode 100644 pkg/stack/stack-stack_test.go delete mode 100644 pkg/stack/stack.go delete mode 100644 pkg/stack/stack_test.go 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/pointer/stack-stack.go b/pkg/pointer/stack-stack.go new file mode 100644 index 0000000..6d22f51 --- /dev/null +++ b/pkg/pointer/stack-stack.go @@ -0,0 +1,95 @@ +package pointer + +type StackStack struct { + head *Stack + height int +} + +func NewStackStack() *StackStack { + return &StackStack{ + head: NewStack(), + height: 1, + } +} + +func (ss *StackStack) Begin(p *Pointer) { + ss.height++ + soss := ss.head + n := soss.Pop() + np := n + if np < 0 { + np = -np + } + toss := &Stack{ + size: np, + height: np, + data: make([]int, np), + next: soss, + } + ss.head = toss + max := n - soss.height + if max < 0 { + max = 0 + } + for i := n - 1; i >= max; i-- { + toss.data[i] = soss.data[soss.height-n+i] + } + x, y := p.GetStorageOffset() + soss.Push(x) + soss.Push(y) + p.CalculateNewStorageOffset() +} + +func (ss *StackStack) End(p *Pointer) (reflect bool) { + if ss.height == 1 { + return true + } + soss := ss.head.next + n := ss.head.Pop() + y := soss.Pop() + x := soss.Pop() + p.SetStorageOffset(x, y) + if n > 0 { + soss.height += n + if soss.size < soss.height { + soss.data = append(soss.data, make([]int, soss.height-soss.size)...) + soss.size = soss.height + } + for i := n; i > 0; i-- { + soss.data[soss.height-i] = ss.head.data[ss.head.height-i] + } + } else { + soss.height += n + if soss.height < 0 { + soss.height = 0 + } + } + ss.height-- + ss.head = ss.head.next + return false +} + +func (ss *StackStack) Under() (reflect bool) { + if ss.height == 1 { + return true + } + n := ss.head.Pop() + if n > 0 { + for i := 0; i < n; i++ { + ss.head.Push(ss.head.next.Pop()) + } + } else { + for i := 0; i < -n; i++ { + ss.head.next.Push(ss.head.Pop()) + } + } + 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/pointer/stack-stack_test.go b/pkg/pointer/stack-stack_test.go new file mode 100644 index 0000000..fd4c9ea --- /dev/null +++ b/pkg/pointer/stack-stack_test.go @@ -0,0 +1,260 @@ +package pointer + +import ( + "os" + "testing" + + "git.adyxax.org/adyxax/gofunge/pkg/field" + "github.com/stretchr/testify/require" +) + +func TestBegin(t *testing.T) { + t.Run("empty", func(t *testing.T) { + expected := NewStackStack() + expected.head = &Stack{data: make([]int, 0), next: expected.head} + expected.head.next.Push(0) + expected.head.next.Push(0) + expected.height++ + ss := NewStackStack() + p := NewPointer() + ss.Begin(p) + require.Equal(t, expected, ss) + x, y := p.GetStorageOffset() + require.Equal(t, 1, x) + require.Equal(t, 0, y) + // Let's push another one + expected.head = &Stack{data: make([]int, 0), next: expected.head} + expected.head.next.Push(1) + expected.head.next.Push(0) + expected.height++ + ss.Begin(p) + require.Equal(t, expected, ss) + x, y = p.GetStorageOffset() + require.Equal(t, 1, x) + require.Equal(t, 0, y) + }) + t.Run("negative", func(t *testing.T) { + expected := NewStackStack() + expected.head = &Stack{size: 5, height: 5, data: make([]int, 5), next: expected.head} + expected.head.next.Push(0) + expected.head.next.Push(0) + expected.height++ + p := NewPointer() + file, err := os.Open("../field/test_data/hello.b98") + require.NoError(t, err, "Failed to open file") + f, err := field.Load(file) + p.Step(*f) + ss := NewStackStack() + ss.head.Push(-5) + ss.Begin(p) + require.Equal(t, expected, ss) + x, y := p.GetStorageOffset() + require.Equal(t, 2, x) + require.Equal(t, 0, y) + }) + t.Run("ask to copy more than we have", func(t *testing.T) { + expected := NewStackStack() + expected.head = &Stack{size: 34, height: 34, data: make([]int, 34), next: expected.head} + expected.head.data[33] = 18 + expected.head.next.Push(18) + expected.head.next.Push(2) + expected.head.next.Push(3) + expected.height++ + p := NewPointer() + p.SetStorageOffset(2, 3) + file, err := os.Open("../field/test_data/hello.b98") + require.NoError(t, err, "Failed to open file") + f, err := field.Load(file) + p.Step(*f) + ss := NewStackStack() + ss.head.Push(18) + ss.head.Push(34) + ss.Begin(p) + require.Equal(t, expected, ss) + x, y := p.GetStorageOffset() + require.Equal(t, 2, x) + require.Equal(t, 0, y) + }) + t.Run("normal", func(t *testing.T) { + expected := NewStackStack() + expected.head = &Stack{size: 4, height: 4, data: []int{12, 14, -2, 5}, next: expected.head} + expected.head.next.Push(7) + expected.head.next.Push(12) + expected.head.next.Push(14) + expected.head.next.Push(-2) + expected.head.next.Push(5) + expected.head.next.Push(36) + expected.head.next.Push(42) + expected.height++ + p := NewPointer() + p.SetStorageOffset(36, 42) + ss := NewStackStack() + ss.head.Push(7) + ss.head.Push(12) + ss.head.Push(14) + ss.head.Push(-2) + ss.head.Push(5) + ss.head.Push(4) + ss.Begin(p) + require.Equal(t, expected, ss) + }) +} + +func TestEnd(t *testing.T) { + t.Run("empty", func(t *testing.T) { + expected := NewStackStack() + p := NewPointer() + ss := NewStackStack() + ss.Begin(p) + reflect := ss.End(p) + require.Equal(t, false, reflect) + require.Equal(t, expected, ss) + }) + t.Run("drop", func(t *testing.T) { + expected := NewStackStack() + expected.head.Push(7) + expected.head.Push(12) + expected.head.Push(14) + expected.head.Push(-2) + expected.head.Push(5) + expected.head.Pop() + expected.head.Pop() + expected.head.Pop() + p := NewPointer() + ss := NewStackStack() + ss.head.Push(7) + ss.head.Push(12) + ss.head.Push(14) + ss.head.Push(-2) + ss.head.Push(5) + ss.head.Push(0) + ss.Begin(p) + ss.head.Push(18) + ss.head.Push(42) + ss.head.Push(-3) + reflect := ss.End(p) + require.Equal(t, false, reflect) + require.Equal(t, expected, ss) + }) + t.Run("drop too much", func(t *testing.T) { + expected := NewStackStack() + p := NewPointer() + ss := NewStackStack() + ss.Begin(p) + ss.head.Push(-3) + reflect := ss.End(p) + require.Equal(t, false, reflect) + require.Equal(t, expected, ss) + }) + t.Run("reflect", func(t *testing.T) { + expected := NewStackStack() + p := NewPointer() + ss := NewStackStack() + reflect := ss.End(p) + require.Equal(t, true, reflect) + require.Equal(t, expected, ss) + }) + t.Run("transfert", func(t *testing.T) { + expected := NewStackStack() + expected.head.size = 5 + expected.head.data = make([]int, 5) + expected.head.Push(7) + expected.head.Push(12) + expected.head.Push(14) + expected.head.Push(-2) + expected.head.Push(5) + p := NewPointer() + ss := NewStackStack() + ss.head.size = 4 + ss.head.data = make([]int, 4) + ss.head.Push(7) + ss.head.Push(0) + ss.Begin(p) + ss.head.Push(0) + ss.head.Push(18) + ss.head.Push(42) + ss.head.Push(7) + ss.head.Push(12) + ss.head.Push(14) + ss.head.Push(-2) + ss.head.Push(5) + ss.head.Push(4) + reflect := ss.End(p) + require.Equal(t, false, reflect) + require.Equal(t, expected, ss) + }) +} + +func TestUnder(t *testing.T) { + t.Run("empty", func(t *testing.T) { + expected := NewStackStack() + ss := NewStackStack() + reflect := ss.Under() + require.Equal(t, true, reflect) + require.Equal(t, expected, ss) + }) + t.Run("positive", func(t *testing.T) { + pe := NewPointer() + expected := NewStackStack() + expected.head.Push(1) + expected.head.Push(2) + expected.head.Push(3) + expected.head.Push(6) + expected.head.Push(0) + expected.Begin(pe) + expected.head.Push(0) + expected.head.Push(0) + expected.head.Push(6) + expected.head.next.Pop() + expected.head.next.Pop() + expected.head.next.Pop() + p := NewPointer() + ss := NewStackStack() + ss.head.Push(1) + ss.head.Push(2) + ss.head.Push(3) + ss.head.Push(6) + ss.head.Push(0) + ss.Begin(p) + ss.head.Push(3) + reflect := ss.Under() + require.Equal(t, false, reflect) + require.Equal(t, expected, ss) + }) + t.Run("negative", func(t *testing.T) { + pe := NewPointer() + expected := NewStackStack() + expected.Begin(pe) + expected.head.next.Push(12) + expected.head.next.Push(5) + expected.head.next.Push(8) + expected.head.Push(8) + expected.head.Push(5) + expected.head.Push(12) + expected.head.Push(-3) + expected.head.Pop() + expected.head.Pop() + expected.head.Pop() + expected.head.Pop() + p := NewPointer() + ss := NewStackStack() + ss.Begin(p) + ss.head.Push(8) + ss.head.Push(5) + ss.head.Push(12) + ss.head.Push(-3) + reflect := ss.Under() + require.Equal(t, false, reflect) + 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/pointer/stack.go b/pkg/pointer/stack.go new file mode 100644 index 0000000..1832dbb --- /dev/null +++ b/pkg/pointer/stack.go @@ -0,0 +1,51 @@ +package pointer + +type Stack struct { + size int + height int + data []int + next *Stack // Pointer to the next element in the stack stack +} + +func NewStack() *Stack { + return &Stack{ + size: 32, + height: 0, + data: make([]int, 32), + next: nil, + } +} + +func (s *Stack) Clear() { + s.height = 0 +} + +func (s *Stack) Duplicate() { + if s.height > 0 { + s.Push(s.data[s.height-1]) + } +} + +func (s *Stack) Pop() int { + if s.height > 0 { + s.height-- + return s.data[s.height] + } + return 0 +} + +func (s *Stack) Push(value int) { + if s.height >= s.size { + s.size += 32 + s.data = append(s.data, make([]int, 32)...) + } + s.data[s.height] = value + s.height++ +} + +func (s *Stack) Swap() { + a := s.Pop() + b := s.Pop() + s.Push(a) + s.Push(b) +} diff --git a/pkg/pointer/stack_test.go b/pkg/pointer/stack_test.go new file mode 100644 index 0000000..1b16085 --- /dev/null +++ b/pkg/pointer/stack_test.go @@ -0,0 +1,74 @@ +package pointer + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClear(t *testing.T) { + s := NewStack() + s.Clear() + require.Equal(t, 0, s.height) +} + +func TestDupicate(t *testing.T) { + s := NewStack() + s2 := NewStack() + s.Duplicate() + require.Equal(t, s2.height, s.height) + s.Push(12) + s.Duplicate() + s2.Push(12) + s2.Push(12) + require.Equal(t, s2.height, s.height) + require.Equal(t, s2.data, s.data) +} + +func TestPop(t *testing.T) { + s := NewStack() + v := s.Pop() + require.Equal(t, 0, v) + s.Push(12) + s.Push(14) + v = s.Pop() + require.Equal(t, 14, v) + v = s.Pop() + require.Equal(t, 12, v) + v = s.Pop() + require.Equal(t, 0, v) +} + +func TestPush(t *testing.T) { + s := NewStack() + for i := 0; i < 32; i++ { + s.Push(i) + } + require.Equal(t, 32, s.size) + s.Push(-1) + require.Equal(t, 64, s.size) +} + +func TestSwap(t *testing.T) { + s := NewStack() + s2 := NewStack() + s.Swap() + s2.Push(0) + s2.Push(0) + require.Equal(t, s2, s) + s.Clear() + s.Push(1) + s.Swap() + s2.Clear() + s2.Push(1) + s2.Push(0) + require.Equal(t, s2, s) + s.Clear() + s.Push(1) + s.Push(2) + s2.Clear() + s2.Push(2) + s2.Push(1) + s.Swap() + require.Equal(t, s2, s) +} diff --git a/pkg/stack/stack-stack.go b/pkg/stack/stack-stack.go deleted file mode 100644 index 9b80079..0000000 --- a/pkg/stack/stack-stack.go +++ /dev/null @@ -1,91 +0,0 @@ -package stack - -import ( - "git.adyxax.org/adyxax/gofunge/pkg/pointer" -) - -type StackStack struct { - head *Stack - height int -} - -func NewStackStack() *StackStack { - return &StackStack{ - head: NewStack(), - height: 1, - } -} - -func (ss *StackStack) Begin(p *pointer.Pointer) { - ss.height++ - soss := ss.head - n := soss.Pop() - np := n - if np < 0 { - np = -np - } - toss := &Stack{ - size: np, - height: np, - data: make([]int, np), - next: soss, - } - ss.head = toss - max := n - soss.height - if max < 0 { - max = 0 - } - for i := n - 1; i >= max; i-- { - toss.data[i] = soss.data[soss.height-n+i] - } - x, y := p.GetStorageOffset() - soss.Push(x) - soss.Push(y) - p.CalculateNewStorageOffset() -} - -func (ss *StackStack) End(p *pointer.Pointer) (reflect bool) { - if ss.height == 1 { - return true - } - soss := ss.head.next - n := ss.head.Pop() - y := soss.Pop() - x := soss.Pop() - p.SetStorageOffset(x, y) - if n > 0 { - soss.height += n - if soss.size < soss.height { - soss.data = append(soss.data, make([]int, soss.height-soss.size)...) - soss.size = soss.height - } - for i := n; i > 0; i-- { - soss.data[soss.height-i] = ss.head.data[ss.head.height-i] - } - } else { - soss.height += n - if soss.height < 0 { - soss.height = 0 - } - } - ss.height-- - ss.head = ss.head.next - return false -} - -func (ss *StackStack) Under() (reflect bool) { - if ss.height == 1 { - return true - } - n := ss.head.Pop() - if n > 0 { - for i := 0; i < n; i++ { - ss.head.Push(ss.head.next.Pop()) - } - } else { - for i := 0; i < -n; i++ { - ss.head.next.Push(ss.head.Pop()) - } - } - return false -} diff --git a/pkg/stack/stack-stack_test.go b/pkg/stack/stack-stack_test.go deleted file mode 100644 index d2a7949..0000000 --- a/pkg/stack/stack-stack_test.go +++ /dev/null @@ -1,251 +0,0 @@ -package stack - -import ( - "os" - "testing" - - "git.adyxax.org/adyxax/gofunge/pkg/field" - "git.adyxax.org/adyxax/gofunge/pkg/pointer" - "github.com/stretchr/testify/require" -) - -func TestBegin(t *testing.T) { - t.Run("empty", func(t *testing.T) { - expected := NewStackStack() - expected.head = &Stack{data: make([]int, 0), next: expected.head} - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.height++ - ss := NewStackStack() - p := pointer.NewPointer() - ss.Begin(p) - require.Equal(t, expected, ss) - x, y := p.GetStorageOffset() - require.Equal(t, 1, x) - require.Equal(t, 0, y) - // Let's push another one - expected.head = &Stack{data: make([]int, 0), next: expected.head} - expected.head.next.Push(1) - expected.head.next.Push(0) - expected.height++ - ss.Begin(p) - require.Equal(t, expected, ss) - x, y = p.GetStorageOffset() - require.Equal(t, 1, x) - require.Equal(t, 0, y) - }) - t.Run("negative", func(t *testing.T) { - expected := NewStackStack() - expected.head = &Stack{size: 5, height: 5, data: make([]int, 5), next: expected.head} - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.height++ - p := pointer.NewPointer() - file, err := os.Open("../field/test_data/hello.b98") - require.NoError(t, err, "Failed to open file") - f, err := field.Load(file) - p.Step(*f) - ss := NewStackStack() - ss.head.Push(-5) - ss.Begin(p) - require.Equal(t, expected, ss) - x, y := p.GetStorageOffset() - require.Equal(t, 2, x) - require.Equal(t, 0, y) - }) - t.Run("ask to copy more than we have", func(t *testing.T) { - expected := NewStackStack() - expected.head = &Stack{size: 34, height: 34, data: make([]int, 34), next: expected.head} - expected.head.data[33] = 18 - expected.head.next.Push(18) - expected.head.next.Push(2) - expected.head.next.Push(3) - expected.height++ - p := pointer.NewPointer() - p.SetStorageOffset(2, 3) - file, err := os.Open("../field/test_data/hello.b98") - require.NoError(t, err, "Failed to open file") - f, err := field.Load(file) - p.Step(*f) - ss := NewStackStack() - ss.head.Push(18) - ss.head.Push(34) - ss.Begin(p) - require.Equal(t, expected, ss) - x, y := p.GetStorageOffset() - require.Equal(t, 2, x) - require.Equal(t, 0, y) - }) - t.Run("normal", func(t *testing.T) { - expected := NewStackStack() - expected.head = &Stack{size: 4, height: 4, data: []int{12, 14, -2, 5}, next: expected.head} - expected.head.next.Push(7) - expected.head.next.Push(12) - expected.head.next.Push(14) - expected.head.next.Push(-2) - expected.head.next.Push(5) - expected.head.next.Push(36) - expected.head.next.Push(42) - expected.height++ - p := pointer.NewPointer() - p.SetStorageOffset(36, 42) - ss := NewStackStack() - ss.head.Push(7) - ss.head.Push(12) - ss.head.Push(14) - ss.head.Push(-2) - ss.head.Push(5) - ss.head.Push(4) - ss.Begin(p) - require.Equal(t, expected, ss) - }) -} - -func TestEnd(t *testing.T) { - t.Run("empty", func(t *testing.T) { - expected := NewStackStack() - p := pointer.NewPointer() - ss := NewStackStack() - ss.Begin(p) - reflect := ss.End(p) - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) - t.Run("drop", func(t *testing.T) { - expected := NewStackStack() - expected.head.Push(7) - expected.head.Push(12) - expected.head.Push(14) - expected.head.Push(-2) - expected.head.Push(5) - expected.head.Pop() - expected.head.Pop() - expected.head.Pop() - p := pointer.NewPointer() - ss := NewStackStack() - ss.head.Push(7) - ss.head.Push(12) - ss.head.Push(14) - ss.head.Push(-2) - ss.head.Push(5) - ss.head.Push(0) - ss.Begin(p) - ss.head.Push(18) - ss.head.Push(42) - ss.head.Push(-3) - reflect := ss.End(p) - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) - t.Run("drop too much", func(t *testing.T) { - expected := NewStackStack() - p := pointer.NewPointer() - ss := NewStackStack() - ss.Begin(p) - ss.head.Push(-3) - reflect := ss.End(p) - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) - t.Run("reflect", func(t *testing.T) { - expected := NewStackStack() - p := pointer.NewPointer() - ss := NewStackStack() - reflect := ss.End(p) - require.Equal(t, true, reflect) - require.Equal(t, expected, ss) - }) - t.Run("transfert", func(t *testing.T) { - expected := NewStackStack() - expected.head.size = 5 - expected.head.data = make([]int, 5) - expected.head.Push(7) - expected.head.Push(12) - expected.head.Push(14) - expected.head.Push(-2) - expected.head.Push(5) - p := pointer.NewPointer() - ss := NewStackStack() - ss.head.size = 4 - ss.head.data = make([]int, 4) - ss.head.Push(7) - ss.head.Push(0) - ss.Begin(p) - ss.head.Push(0) - ss.head.Push(18) - ss.head.Push(42) - ss.head.Push(7) - ss.head.Push(12) - ss.head.Push(14) - ss.head.Push(-2) - ss.head.Push(5) - ss.head.Push(4) - reflect := ss.End(p) - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) -} - -func TestUnder(t *testing.T) { - t.Run("empty", func(t *testing.T) { - expected := NewStackStack() - ss := NewStackStack() - reflect := ss.Under() - require.Equal(t, true, reflect) - require.Equal(t, expected, ss) - }) - t.Run("positive", func(t *testing.T) { - pe := pointer.NewPointer() - expected := NewStackStack() - expected.head.Push(1) - expected.head.Push(2) - expected.head.Push(3) - expected.head.Push(6) - expected.head.Push(0) - expected.Begin(pe) - expected.head.Push(0) - expected.head.Push(0) - expected.head.Push(6) - expected.head.next.Pop() - expected.head.next.Pop() - expected.head.next.Pop() - p := pointer.NewPointer() - ss := NewStackStack() - ss.head.Push(1) - ss.head.Push(2) - ss.head.Push(3) - ss.head.Push(6) - ss.head.Push(0) - ss.Begin(p) - ss.head.Push(3) - reflect := ss.Under() - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) - t.Run("negative", func(t *testing.T) { - pe := pointer.NewPointer() - expected := NewStackStack() - expected.Begin(pe) - expected.head.next.Push(12) - expected.head.next.Push(5) - expected.head.next.Push(8) - expected.head.Push(8) - expected.head.Push(5) - expected.head.Push(12) - expected.head.Push(-3) - expected.head.Pop() - expected.head.Pop() - expected.head.Pop() - expected.head.Pop() - p := pointer.NewPointer() - ss := NewStackStack() - ss.Begin(p) - ss.head.Push(8) - ss.head.Push(5) - ss.head.Push(12) - ss.head.Push(-3) - reflect := ss.Under() - require.Equal(t, false, reflect) - require.Equal(t, expected, ss) - }) -} diff --git a/pkg/stack/stack.go b/pkg/stack/stack.go deleted file mode 100644 index 4dbb72c..0000000 --- a/pkg/stack/stack.go +++ /dev/null @@ -1,51 +0,0 @@ -package stack - -type Stack struct { - size int - height int - data []int - next *Stack // Pointer to the next element in the stack stack -} - -func NewStack() *Stack { - return &Stack{ - size: 32, - height: 0, - data: make([]int, 32), - next: nil, - } -} - -func (s *Stack) Clear() { - s.height = 0 -} - -func (s *Stack) Duplicate() { - if s.height > 0 { - s.Push(s.data[s.height-1]) - } -} - -func (s *Stack) Pop() int { - if s.height > 0 { - s.height-- - return s.data[s.height] - } - return 0 -} - -func (s *Stack) Push(value int) { - if s.height >= s.size { - s.size += 32 - s.data = append(s.data, make([]int, 32)...) - } - s.data[s.height] = value - s.height++ -} - -func (s *Stack) Swap() { - a := s.Pop() - b := s.Pop() - s.Push(a) - s.Push(b) -} diff --git a/pkg/stack/stack_test.go b/pkg/stack/stack_test.go deleted file mode 100644 index e48c615..0000000 --- a/pkg/stack/stack_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package stack - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestClear(t *testing.T) { - s := NewStack() - s.Clear() - require.Equal(t, 0, s.height) -} - -func TestDupicate(t *testing.T) { - s := NewStack() - s2 := NewStack() - s.Duplicate() - require.Equal(t, s2.height, s.height) - s.Push(12) - s.Duplicate() - s2.Push(12) - s2.Push(12) - require.Equal(t, s2.height, s.height) - require.Equal(t, s2.data, s.data) -} - -func TestPop(t *testing.T) { - s := NewStack() - v := s.Pop() - require.Equal(t, 0, v) - s.Push(12) - s.Push(14) - v = s.Pop() - require.Equal(t, 14, v) - v = s.Pop() - require.Equal(t, 12, v) - v = s.Pop() - require.Equal(t, 0, v) -} - -func TestPush(t *testing.T) { - s := NewStack() - for i := 0; i < 32; i++ { - s.Push(i) - } - require.Equal(t, 32, s.size) - s.Push(-1) - require.Equal(t, 64, s.size) -} - -func TestSwap(t *testing.T) { - s := NewStack() - s2 := NewStack() - s.Swap() - s2.Push(0) - s2.Push(0) - require.Equal(t, s2, s) - s.Clear() - s.Push(1) - s.Swap() - s2.Clear() - s2.Push(1) - s2.Push(0) - require.Equal(t, s2, s) - s.Clear() - s.Push(1) - s.Push(2) - s2.Clear() - s2.Push(2) - s2.Push(1) - s.Swap() - require.Equal(t, s2, s) -} -- cgit v1.2.3