From c913c2ae46fd81a3274ef16c64c78ea2ed421de8 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Fri, 12 Nov 2021 15:26:16 +0100 Subject: Refactoring : isolate stack manipulation into their own package --- pkg/pointer/exec.go | 16 +----- pkg/pointer/stack-stack.go | 55 ++++++--------------- pkg/pointer/stack-stack_test.go | 80 +++++++++++++++--------------- pkg/pointer/stack.go | 53 +++----------------- pkg/pointer/stack_test.go | 75 ---------------------------- pkg/stack/min.go | 8 +++ pkg/stack/stack.go | 105 ++++++++++++++++++++++++++++++++++++++++ pkg/stack/stack_test.go | 83 +++++++++++++++++++++++++++++++ 8 files changed, 262 insertions(+), 213 deletions(-) delete mode 100644 pkg/pointer/stack_test.go create mode 100644 pkg/stack/min.go create mode 100644 pkg/stack/stack.go create mode 100644 pkg/stack/stack_test.go diff --git a/pkg/pointer/exec.go b/pkg/pointer/exec.go index e2c55e3..8bb9dba 100644 --- a/pkg/pointer/exec.go +++ b/pkg/pointer/exec.go @@ -185,12 +185,7 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { now := time.Now() x, y, lx, ly := f.Dump() const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64 - heights := make([]int, p.ss.height) - s := p.ss.head - for i := p.ss.height - 1; i >= 0; i-- { - heights[i] = s.height - s = s.next - } + heights := p.ss.GetHeights() // 20 for _, e := range os.Environ() { vars := strings.SplitN(e, "=", 2) @@ -255,14 +250,7 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { // 1 p.ss.head.Push(0b00000) // TODO update when implementing t, i, o and = if n > 0 { - if n > p.ss.head.height { - p.ss.head.height = 1 - p.ss.head.data[0] = 0 - } else { - v := p.ss.head.data[p.ss.head.height-n] - p.ss.head.height = heights[0] - p.ss.head.Push(v) - } + p.ss.YCommandPick(n, heights[0]) } case '(': n := p.ss.head.Pop() diff --git a/pkg/pointer/stack-stack.go b/pkg/pointer/stack-stack.go index 4bbfb73..9d4336a 100644 --- a/pkg/pointer/stack-stack.go +++ b/pkg/pointer/stack-stack.go @@ -1,13 +1,15 @@ package pointer +import "git.adyxax.org/adyxax/gofunge98/pkg/stack" + type StackStack struct { - head *Stack + head *stack.Stack height int } func NewStackStack() *StackStack { return &StackStack{ - head: NewStack(), + head: stack.NewStack(32, nil), height: 1, } } @@ -20,24 +22,10 @@ func (ss *StackStack) Begin(p *Pointer) { if np < 0 { np = -np } - toss := &Stack{ - size: np, - data: make([]int, np), - next: soss, - } + toss := stack.NewStack(np, soss) ss.head = toss if n > 0 { - toss.height = n - elts := soss.height - n - if elts < 0 { - elts = soss.height - } else { - elts = n - } - for i := 1; i <= elts; i++ { - toss.data[toss.height-i] = soss.data[soss.height-i] - } - soss.height -= elts + toss.Transfert(soss, n) } else if n < 0 { for i := 0; i < np; i++ { soss.Push(0) @@ -53,31 +41,16 @@ func (ss *StackStack) End(p *Pointer) (reflect bool) { if ss.height == 1 { return true } - soss := ss.head.next + toss := ss.head + soss := ss.head.Next() n := ss.head.Pop() y := soss.Pop() x := soss.Pop() p.SetStorageOffset(x, y) if n > 0 { - if n > ss.head.height { - for i := n; i > ss.head.height; i-- { - soss.Push(0) - } - n = ss.head.height - } - 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] - } + soss.Transfert(toss, n) } else if n < 0 { - soss.height += n - if soss.height < 0 { - soss.height = 0 - } + soss.Discard(-n) } ss.height-- ss.head = soss @@ -91,12 +64,16 @@ func (ss *StackStack) Under() (reflect bool) { n := ss.head.Pop() if n > 0 { for i := 0; i < n; i++ { - ss.head.Push(ss.head.next.Pop()) + ss.head.Push(ss.head.Next().Pop()) } } else { for i := 0; i < -n; i++ { - ss.head.next.Push(ss.head.Pop()) + ss.head.Next().Push(ss.head.Pop()) } } return false } + +func (s StackStack) GetHeights() []int { + return s.head.GetHeights() +} diff --git a/pkg/pointer/stack-stack_test.go b/pkg/pointer/stack-stack_test.go index dcb1960..959153d 100644 --- a/pkg/pointer/stack-stack_test.go +++ b/pkg/pointer/stack-stack_test.go @@ -5,15 +5,16 @@ import ( "testing" "git.adyxax.org/adyxax/gofunge98/pkg/field" + "git.adyxax.org/adyxax/gofunge98/pkg/stack" "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.head = stack.NewStack(0, expected.head) + expected.head.Next().Push(0) + expected.head.Next().Push(0) expected.height++ p := NewPointer() ss := p.ss @@ -23,9 +24,9 @@ func TestBegin(t *testing.T) { 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.head = stack.NewStack(0, expected.head) + expected.head.Next().Push(1) + expected.head.Next().Push(0) expected.height++ ss.Begin(p) require.Equal(t, expected, ss) @@ -35,14 +36,14 @@ func TestBegin(t *testing.T) { }) t.Run("negative", func(t *testing.T) { expected := NewStackStack() - expected.head = &Stack{size: 5, height: 0, data: make([]int, 5), next: expected.head} - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.head.next.Push(0) - expected.head.next.Push(0) + expected.head = stack.NewStack(5, expected.head) + expected.head.Next().Push(0) + expected.head.Next().Push(0) + expected.head.Next().Push(0) + expected.head.Next().Push(0) + expected.head.Next().Push(0) + expected.head.Next().Push(0) + expected.head.Next().Push(0) expected.height++ p := NewPointer() file, err := os.Open("../field/test_data/hello.b98") @@ -59,10 +60,13 @@ func TestBegin(t *testing.T) { }) 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(2) - expected.head.next.Push(3) + expected.head = stack.NewStack(34, expected.head) + for i := 0; i < 33; i++ { + expected.head.Push(0) + } + expected.head.Push(18) + expected.head.Next().Push(2) + expected.head.Next().Push(3) expected.height++ p := NewPointer() p.SetStorageOffset(2, 3) @@ -81,16 +85,20 @@ func TestBegin(t *testing.T) { }) 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(36) - expected.head.next.Push(42) - expected.head.next.Push(-2) - expected.head.next.Push(5) - expected.head.next.Push(4) - expected.head.next.Pop() - expected.head.next.Pop() - expected.head.next.Pop() + expected.head = stack.NewStack(4, expected.head) + expected.head.Push(12) + expected.head.Push(14) + expected.head.Push(-2) + expected.head.Push(5) + expected.head.Next().Push(7) + expected.head.Next().Push(36) + expected.head.Next().Push(42) + expected.head.Next().Push(-2) + expected.head.Next().Push(5) + expected.head.Next().Push(4) + expected.head.Next().Pop() + expected.head.Next().Pop() + expected.head.Next().Pop() expected.height++ p := NewPointer() p.SetStorageOffset(36, 42) @@ -162,8 +170,6 @@ func TestEnd(t *testing.T) { }) 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) @@ -171,8 +177,6 @@ func TestEnd(t *testing.T) { expected.head.Push(5) p := NewPointer() ss := p.ss - ss.head.size = 4 - ss.head.data = make([]int, 4) ss.head.Push(7) ss.head.Push(0) ss.Begin(p) @@ -211,9 +215,9 @@ func TestUnder(t *testing.T) { expected.head.Push(0) expected.head.Push(0) expected.head.Push(6) - expected.head.next.Pop() - expected.head.next.Pop() - expected.head.next.Pop() + expected.head.Next().Pop() + expected.head.Next().Pop() + expected.head.Next().Pop() p := NewPointer() ss := p.ss ss.head.Push(1) @@ -231,9 +235,9 @@ func TestUnder(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.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) diff --git a/pkg/pointer/stack.go b/pkg/pointer/stack.go index ba51c7c..b08b354 100644 --- a/pkg/pointer/stack.go +++ b/pkg/pointer/stack.go @@ -1,54 +1,13 @@ package pointer -type Stack struct { - size int - height int - data []int - next *Stack // Pointer to the next element in the stack stack +func (ss *StackStack) Pop() int { + return ss.head.Pop() } -func NewStack() *Stack { - return &Stack{ - size: 32, - height: 0, - data: make([]int, 32), - next: nil, - } +func (ss *StackStack) Push(v int) { + ss.head.Push(v) } -func (s *Stack) Clear() { - s.height = 0 -} - -func (s *Stack) Duplicate() { - if s.height > 0 { - s.Push(s.data[s.height-1]) - } else { - s.Push(0) - s.Push(0) - } -} - -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) +func (s *StackStack) YCommandPick(n int, h int) { + s.head.YCommandPick(n, h) } diff --git a/pkg/pointer/stack_test.go b/pkg/pointer/stack_test.go deleted file mode 100644 index 35700fd..0000000 --- a/pkg/pointer/stack_test.go +++ /dev/null @@ -1,75 +0,0 @@ -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) { - expected := NewStack() - expected.height = 2 - s := NewStack() - s.Duplicate() - require.Equal(t, expected.height, s.height) - s.Push(12) - s.Duplicate() - expected.Push(12) - expected.Push(12) - require.Equal(t, expected.height, s.height) - require.Equal(t, expected.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/min.go b/pkg/stack/min.go new file mode 100644 index 0000000..e97aaed --- /dev/null +++ b/pkg/stack/min.go @@ -0,0 +1,8 @@ +package stack + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/pkg/stack/stack.go b/pkg/stack/stack.go new file mode 100644 index 0000000..c307133 --- /dev/null +++ b/pkg/stack/stack.go @@ -0,0 +1,105 @@ +package stack + +type Stack struct { + size int + height int + data []int + next *Stack // Pointer to the next element in the stack stack +} + +func NewStack(size int, next *Stack) *Stack { + return &Stack{ + size: size, + height: 0, + data: make([]int, size), + next: next, + } +} + +func (s *Stack) Clear() { + s.height = 0 +} + +func (s *Stack) Duplicate() { + if s.height > 0 { + s.Push(s.data[s.height-1]) + } else { + s.Push(0) + s.Push(0) + } +} + +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) +} + +func (s Stack) GetHeights() []int { + if s.next != nil { + return append(s.next.GetHeights(), s.height) + } else { + return []int{s.height} + } +} + +func (toss *Stack) Transfert(soss *Stack, n int) { + // Implements a value transfert between two stacks, intended for use with the '{' + // (aka begin) and '}' (aka end) stackstack commands + toss.height += n + if toss.height > toss.size { + toss.data = append(toss.data, make([]int, toss.height-toss.size)...) + toss.size = toss.height + } + for i := 1; i <= min(soss.height, n); i++ { + toss.data[toss.height-i] = soss.data[soss.height-i] + for i := min(soss.height, n) + 1; i <= n; i++ { + toss.data[toss.height-i] = 0 + } + } + soss.height -= n + if soss.height < 0 { + soss.height = 0 + } +} + +func (s Stack) Next() *Stack { + return s.next +} + +func (s *Stack) Discard(n int) { + // Implements a discard mechanism intended for use with the '}'(aka end) stackstack command + s.height -= n + if s.height < 0 { + s.height = 0 + } +} + +func (s *Stack) YCommandPick(n int, h int) { + if n > s.height { + s.height = 1 + s.data[0] = 0 + } else { + v := s.data[s.height-n] + s.height = h + s.Push(v) + } +} diff --git a/pkg/stack/stack_test.go b/pkg/stack/stack_test.go new file mode 100644 index 0000000..2f15d3a --- /dev/null +++ b/pkg/stack/stack_test.go @@ -0,0 +1,83 @@ +package stack + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClear(t *testing.T) { + s := NewStack(32, nil) + s.Clear() + require.Equal(t, 0, s.height) +} + +func TestDupicate(t *testing.T) { + expected := NewStack(32, nil) + expected.height = 2 + s := NewStack(32, nil) + s.Duplicate() + require.Equal(t, expected.height, s.height) + s.Push(12) + s.Duplicate() + expected.Push(12) + expected.Push(12) + require.Equal(t, expected.height, s.height) + require.Equal(t, expected.data, s.data) +} + +func TestPop(t *testing.T) { + s := NewStack(32, nil) + 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(32, nil) + 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(32, nil) + s2 := NewStack(32, nil) + 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) +} + +func TestHeights(t *testing.T) { + // TODO +} + +func TestTransfert(t *testing.T) { + // TODO +} -- cgit v1.2.3