Refactoring : isolate stack manipulation into their own package

This commit is contained in:
Julien Dessaux 2021-11-12 15:26:16 +01:00
parent 71099a8a4e
commit c913c2ae46
7 changed files with 195 additions and 146 deletions

View file

@ -185,12 +185,7 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) {
now := time.Now() now := time.Now()
x, y, lx, ly := f.Dump() x, y, lx, ly := f.Dump()
const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64 const uintSize = 32 << (^uint(0) >> 32 & 1) // 32 or 64
heights := make([]int, p.ss.height) heights := p.ss.GetHeights()
s := p.ss.head
for i := p.ss.height - 1; i >= 0; i-- {
heights[i] = s.height
s = s.next
}
// 20 // 20
for _, e := range os.Environ() { for _, e := range os.Environ() {
vars := strings.SplitN(e, "=", 2) vars := strings.SplitN(e, "=", 2)
@ -255,14 +250,7 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) {
// 1 // 1
p.ss.head.Push(0b00000) // TODO update when implementing t, i, o and = p.ss.head.Push(0b00000) // TODO update when implementing t, i, o and =
if n > 0 { if n > 0 {
if n > p.ss.head.height { p.ss.YCommandPick(n, heights[0])
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)
}
} }
case '(': case '(':
n := p.ss.head.Pop() n := p.ss.head.Pop()

View file

@ -1,13 +1,15 @@
package pointer package pointer
import "git.adyxax.org/adyxax/gofunge98/pkg/stack"
type StackStack struct { type StackStack struct {
head *Stack head *stack.Stack
height int height int
} }
func NewStackStack() *StackStack { func NewStackStack() *StackStack {
return &StackStack{ return &StackStack{
head: NewStack(), head: stack.NewStack(32, nil),
height: 1, height: 1,
} }
} }
@ -20,24 +22,10 @@ func (ss *StackStack) Begin(p *Pointer) {
if np < 0 { if np < 0 {
np = -np np = -np
} }
toss := &Stack{ toss := stack.NewStack(np, soss)
size: np,
data: make([]int, np),
next: soss,
}
ss.head = toss ss.head = toss
if n > 0 { if n > 0 {
toss.height = n toss.Transfert(soss, 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
} else if n < 0 { } else if n < 0 {
for i := 0; i < np; i++ { for i := 0; i < np; i++ {
soss.Push(0) soss.Push(0)
@ -53,31 +41,16 @@ func (ss *StackStack) End(p *Pointer) (reflect bool) {
if ss.height == 1 { if ss.height == 1 {
return true return true
} }
soss := ss.head.next toss := ss.head
soss := ss.head.Next()
n := ss.head.Pop() n := ss.head.Pop()
y := soss.Pop() y := soss.Pop()
x := soss.Pop() x := soss.Pop()
p.SetStorageOffset(x, y) p.SetStorageOffset(x, y)
if n > 0 { if n > 0 {
if n > ss.head.height { soss.Transfert(toss, n)
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]
}
} else if n < 0 { } else if n < 0 {
soss.height += n soss.Discard(-n)
if soss.height < 0 {
soss.height = 0
}
} }
ss.height-- ss.height--
ss.head = soss ss.head = soss
@ -91,12 +64,16 @@ func (ss *StackStack) Under() (reflect bool) {
n := ss.head.Pop() n := ss.head.Pop()
if n > 0 { if n > 0 {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
ss.head.Push(ss.head.next.Pop()) ss.head.Push(ss.head.Next().Pop())
} }
} else { } else {
for i := 0; i < -n; i++ { for i := 0; i < -n; i++ {
ss.head.next.Push(ss.head.Pop()) ss.head.Next().Push(ss.head.Pop())
} }
} }
return false return false
} }
func (s StackStack) GetHeights() []int {
return s.head.GetHeights()
}

View file

@ -5,15 +5,16 @@ import (
"testing" "testing"
"git.adyxax.org/adyxax/gofunge98/pkg/field" "git.adyxax.org/adyxax/gofunge98/pkg/field"
"git.adyxax.org/adyxax/gofunge98/pkg/stack"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestBegin(t *testing.T) { func TestBegin(t *testing.T) {
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
expected := NewStackStack() expected := NewStackStack()
expected.head = &Stack{data: make([]int, 0), next: expected.head} expected.head = stack.NewStack(0, expected.head)
expected.head.next.Push(0) expected.head.Next().Push(0)
expected.head.next.Push(0) expected.head.Next().Push(0)
expected.height++ expected.height++
p := NewPointer() p := NewPointer()
ss := p.ss ss := p.ss
@ -23,9 +24,9 @@ func TestBegin(t *testing.T) {
require.Equal(t, 1, x) require.Equal(t, 1, x)
require.Equal(t, 0, y) require.Equal(t, 0, y)
// Let's push another one // Let's push another one
expected.head = &Stack{data: make([]int, 0), next: expected.head} expected.head = stack.NewStack(0, expected.head)
expected.head.next.Push(1) expected.head.Next().Push(1)
expected.head.next.Push(0) expected.head.Next().Push(0)
expected.height++ expected.height++
ss.Begin(p) ss.Begin(p)
require.Equal(t, expected, ss) require.Equal(t, expected, ss)
@ -35,14 +36,14 @@ func TestBegin(t *testing.T) {
}) })
t.Run("negative", func(t *testing.T) { t.Run("negative", func(t *testing.T) {
expected := NewStackStack() expected := NewStackStack()
expected.head = &Stack{size: 5, height: 0, data: make([]int, 5), next: expected.head} 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.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++ expected.height++
p := NewPointer() p := NewPointer()
file, err := os.Open("../field/test_data/hello.b98") 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) { t.Run("ask to copy more than we have", func(t *testing.T) {
expected := NewStackStack() expected := NewStackStack()
expected.head = &Stack{size: 34, height: 34, data: make([]int, 34), next: expected.head} expected.head = stack.NewStack(34, expected.head)
expected.head.data[33] = 18 for i := 0; i < 33; i++ {
expected.head.next.Push(2) expected.head.Push(0)
expected.head.next.Push(3) }
expected.head.Push(18)
expected.head.Next().Push(2)
expected.head.Next().Push(3)
expected.height++ expected.height++
p := NewPointer() p := NewPointer()
p.SetStorageOffset(2, 3) p.SetStorageOffset(2, 3)
@ -81,16 +85,20 @@ func TestBegin(t *testing.T) {
}) })
t.Run("normal", func(t *testing.T) { t.Run("normal", func(t *testing.T) {
expected := NewStackStack() expected := NewStackStack()
expected.head = &Stack{size: 4, height: 4, data: []int{12, 14, -2, 5}, next: expected.head} expected.head = stack.NewStack(4, expected.head)
expected.head.next.Push(7) expected.head.Push(12)
expected.head.next.Push(36) expected.head.Push(14)
expected.head.next.Push(42) expected.head.Push(-2)
expected.head.next.Push(-2) expected.head.Push(5)
expected.head.next.Push(5) expected.head.Next().Push(7)
expected.head.next.Push(4) expected.head.Next().Push(36)
expected.head.next.Pop() expected.head.Next().Push(42)
expected.head.next.Pop() expected.head.Next().Push(-2)
expected.head.next.Pop() expected.head.Next().Push(5)
expected.head.Next().Push(4)
expected.head.Next().Pop()
expected.head.Next().Pop()
expected.head.Next().Pop()
expected.height++ expected.height++
p := NewPointer() p := NewPointer()
p.SetStorageOffset(36, 42) p.SetStorageOffset(36, 42)
@ -162,8 +170,6 @@ func TestEnd(t *testing.T) {
}) })
t.Run("transfert", func(t *testing.T) { t.Run("transfert", func(t *testing.T) {
expected := NewStackStack() expected := NewStackStack()
expected.head.size = 5
expected.head.data = make([]int, 5)
expected.head.Push(7) expected.head.Push(7)
expected.head.Push(12) expected.head.Push(12)
expected.head.Push(14) expected.head.Push(14)
@ -171,8 +177,6 @@ func TestEnd(t *testing.T) {
expected.head.Push(5) expected.head.Push(5)
p := NewPointer() p := NewPointer()
ss := p.ss ss := p.ss
ss.head.size = 4
ss.head.data = make([]int, 4)
ss.head.Push(7) ss.head.Push(7)
ss.head.Push(0) ss.head.Push(0)
ss.Begin(p) ss.Begin(p)
@ -211,9 +215,9 @@ func TestUnder(t *testing.T) {
expected.head.Push(0) expected.head.Push(0)
expected.head.Push(0) expected.head.Push(0)
expected.head.Push(6) 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() p := NewPointer()
ss := p.ss ss := p.ss
ss.head.Push(1) ss.head.Push(1)
@ -231,9 +235,9 @@ func TestUnder(t *testing.T) {
pe := NewPointer() pe := NewPointer()
expected := NewStackStack() expected := NewStackStack()
expected.Begin(pe) expected.Begin(pe)
expected.head.next.Push(12) expected.head.Next().Push(12)
expected.head.next.Push(5) expected.head.Next().Push(5)
expected.head.next.Push(8) expected.head.Next().Push(8)
expected.head.Push(8) expected.head.Push(8)
expected.head.Push(5) expected.head.Push(5)
expected.head.Push(12) expected.head.Push(12)

View file

@ -1,54 +1,13 @@
package pointer package pointer
type Stack struct { func (ss *StackStack) Pop() int {
size int return ss.head.Pop()
height int
data []int
next *Stack // Pointer to the next element in the stack stack
} }
func NewStack() *Stack { func (ss *StackStack) Push(v int) {
return &Stack{ ss.head.Push(v)
size: 32,
height: 0,
data: make([]int, 32),
next: nil,
}
} }
func (s *Stack) Clear() { func (s *StackStack) YCommandPick(n int, h int) {
s.height = 0 s.head.YCommandPick(n, h)
}
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)
} }

8
pkg/stack/min.go Normal file
View file

@ -0,0 +1,8 @@
package stack
func min(a, b int) int {
if a < b {
return a
}
return b
}

105
pkg/stack/stack.go Normal file
View file

@ -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)
}
}

View file

@ -1,4 +1,4 @@
package pointer package stack
import ( import (
"testing" "testing"
@ -7,15 +7,15 @@ import (
) )
func TestClear(t *testing.T) { func TestClear(t *testing.T) {
s := NewStack() s := NewStack(32, nil)
s.Clear() s.Clear()
require.Equal(t, 0, s.height) require.Equal(t, 0, s.height)
} }
func TestDupicate(t *testing.T) { func TestDupicate(t *testing.T) {
expected := NewStack() expected := NewStack(32, nil)
expected.height = 2 expected.height = 2
s := NewStack() s := NewStack(32, nil)
s.Duplicate() s.Duplicate()
require.Equal(t, expected.height, s.height) require.Equal(t, expected.height, s.height)
s.Push(12) s.Push(12)
@ -27,7 +27,7 @@ func TestDupicate(t *testing.T) {
} }
func TestPop(t *testing.T) { func TestPop(t *testing.T) {
s := NewStack() s := NewStack(32, nil)
v := s.Pop() v := s.Pop()
require.Equal(t, 0, v) require.Equal(t, 0, v)
s.Push(12) s.Push(12)
@ -41,7 +41,7 @@ func TestPop(t *testing.T) {
} }
func TestPush(t *testing.T) { func TestPush(t *testing.T) {
s := NewStack() s := NewStack(32, nil)
for i := 0; i < 32; i++ { for i := 0; i < 32; i++ {
s.Push(i) s.Push(i)
} }
@ -51,8 +51,8 @@ func TestPush(t *testing.T) {
} }
func TestSwap(t *testing.T) { func TestSwap(t *testing.T) {
s := NewStack() s := NewStack(32, nil)
s2 := NewStack() s2 := NewStack(32, nil)
s.Swap() s.Swap()
s2.Push(0) s2.Push(0)
s2.Push(0) s2.Push(0)
@ -73,3 +73,11 @@ func TestSwap(t *testing.T) {
s.Swap() s.Swap()
require.Equal(t, s2, s) require.Equal(t, s2, s)
} }
func TestHeights(t *testing.T) {
// TODO
}
func TestTransfert(t *testing.T) {
// TODO
}