Moved the character execution's to the pointer in order to handle the k command

This commit is contained in:
Julien Dessaux 2021-09-23 14:59:14 +02:00
parent 759ee2aa10
commit f86b5724e5
5 changed files with 78 additions and 26 deletions

View file

@ -1,8 +1,6 @@
package interpreter
import (
"log"
"git.adyxax.org/adyxax/gofunge/pkg/field"
"git.adyxax.org/adyxax/gofunge/pkg/pointer"
)
@ -16,31 +14,29 @@ func NewInterpreter(f *field.Field, p *pointer.Pointer) *Interpreter {
return &Interpreter{f: f, p: p}
}
func (i *Interpreter) Run() {
func (i *Interpreter) Run() int {
for i.p != nil {
i.Step()
if v := i.Step(); v != nil {
return *v
}
}
return 0
}
func (i *Interpreter) Step() {
func (i *Interpreter) Step() *int {
var prev *pointer.Pointer = nil
for p := i.p; p != nil; p = p.Next {
c := p.Get(*i.f)
switch c {
case '@':
done, v := p.Exec(i.f)
if v != nil {
return v
}
if done {
if prev == nil {
i.p = p.Next
} else {
prev.Next = p.Next
}
break
case '#':
p.Step(*i.f)
default:
if !p.Redirect(c) {
log.Fatalf("Non implemented instruction code %d : %c", c, c)
}
}
p.Step(*i.f)
}
return nil
}

39
pkg/pointer/exec.go Normal file
View file

@ -0,0 +1,39 @@
package pointer
import (
"log"
"git.adyxax.org/adyxax/gofunge/pkg/field"
)
func (p *Pointer) Exec(f *field.Field) (done bool, returnValue *int) {
c := p.Get(*f)
for jumpingMode := false; jumpingMode || c == ' ' || c == ';'; c = p.StepAndGet(*f) {
if jumpingMode {
if c == ';' {
jumpingMode = false
}
continue
}
}
switch c {
case '@':
return true, nil
case '#':
p.Step(*f)
case 'j':
n := p.Ss.Pop()
for j := 0; j < n; j++ {
p.Step(*f)
}
case 'q':
v := p.Ss.Pop()
return true, &v
default:
if !p.Redirect(c) {
log.Fatalf("Non implemented instruction code %d : %c", c, c)
}
}
p.Step(*f)
return
}

View file

@ -17,13 +17,13 @@ type Pointer struct {
sox int
soy int
// The stack
ss *StackStack
Ss *StackStack
// The next element for the multi-"threaded" b98 interpreter
Next *Pointer
}
func NewPointer() *Pointer {
return &Pointer{dx: 1, ss: NewStackStack()}
return &Pointer{dx: 1, Ss: NewStackStack()}
}
func (p Pointer) Split() *Pointer {
@ -38,6 +38,11 @@ func (p Pointer) Get(f field.Field) int {
return f.Get(p.x, p.y)
}
func (p *Pointer) StepAndGet(f field.Field) int {
p.Step(f)
return p.Get(f)
}
func (p *Pointer) Set(x, y int) {
p.x, p.y = x, y
}
@ -71,8 +76,8 @@ func (p *Pointer) Redirect(c int) bool {
case 'r':
p.Reverse()
case 'x':
dy := p.ss.Pop()
dx := p.ss.Pop()
dy := p.Ss.Pop()
dx := p.Ss.Pop()
p.RedirectTo(dx, dy)
default:
return false

View file

@ -9,7 +9,7 @@ import (
)
func TestNewPointer(t *testing.T) {
require.Equal(t, NewPointer(), &Pointer{dx: 1, ss: NewStackStack()})
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, ss: NewStackStack()}, p)
require.Equal(t, &Pointer{x: 1, y: 0, dx: 1, ss: NewStackStack()}, 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
@ -51,6 +51,17 @@ func TestGet(t *testing.T) {
require.Equal(t, int('@'), v)
}
func TestStepAndGet(t *testing.T) {
// File of one char
file, err := os.Open("../field/test_data/minimal.b98")
require.NoError(t, err, "Failed to open file")
defer file.Close()
f, err := field.Load(file)
p := NewPointer()
v := p.StepAndGet(*f)
require.Equal(t, int('@'), v)
}
func TestSet(t *testing.T) {
p := NewPointer()
p.Set(3, 14)
@ -93,8 +104,8 @@ func TestRedirect(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
p := NewPointer()
p.RedirectTo(3, 14)
p.ss.Push(2)
p.ss.Push(7)
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")