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

@ -38,5 +38,6 @@ func main() {
os.Exit(3) os.Exit(3)
} }
interpreter.NewInterpreter(f, pointer.NewPointer()).Run() v := interpreter.NewInterpreter(f, pointer.NewPointer()).Run()
os.Exit(v)
} }

View file

@ -1,8 +1,6 @@
package interpreter package interpreter
import ( import (
"log"
"git.adyxax.org/adyxax/gofunge/pkg/field" "git.adyxax.org/adyxax/gofunge/pkg/field"
"git.adyxax.org/adyxax/gofunge/pkg/pointer" "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} return &Interpreter{f: f, p: p}
} }
func (i *Interpreter) Run() { func (i *Interpreter) Run() int {
for i.p != nil { 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 var prev *pointer.Pointer = nil
for p := i.p; p != nil; p = p.Next { for p := i.p; p != nil; p = p.Next {
c := p.Get(*i.f) done, v := p.Exec(i.f)
switch c { if v != nil {
case '@': return v
}
if done {
if prev == nil { if prev == nil {
i.p = p.Next i.p = p.Next
} else { } else {
prev.Next = p.Next 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 sox int
soy int soy int
// The stack // The stack
ss *StackStack Ss *StackStack
// The next element for the multi-"threaded" b98 interpreter // The next element for the multi-"threaded" b98 interpreter
Next *Pointer Next *Pointer
} }
func NewPointer() *Pointer { func NewPointer() *Pointer {
return &Pointer{dx: 1, ss: NewStackStack()} return &Pointer{dx: 1, Ss: NewStackStack()}
} }
func (p Pointer) Split() *Pointer { func (p Pointer) Split() *Pointer {
@ -38,6 +38,11 @@ func (p Pointer) Get(f field.Field) int {
return f.Get(p.x, p.y) 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) { func (p *Pointer) Set(x, y int) {
p.x, p.y = x, y p.x, p.y = x, y
} }
@ -71,8 +76,8 @@ func (p *Pointer) Redirect(c int) bool {
case 'r': case 'r':
p.Reverse() p.Reverse()
case 'x': case 'x':
dy := p.ss.Pop() dy := p.Ss.Pop()
dx := p.ss.Pop() dx := p.Ss.Pop()
p.RedirectTo(dx, dy) p.RedirectTo(dx, dy)
default: default:
return false return false

View file

@ -9,7 +9,7 @@ import (
) )
func TestNewPointer(t *testing.T) { 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) { func TestSplit(t *testing.T) {
@ -23,8 +23,8 @@ func TestSplit(t *testing.T) {
// We check that p2 is a real copy // We check that p2 is a real copy
p.Step(*f) p.Step(*f)
p2.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()}, 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()}, p2)
} }
func TestStep(t *testing.T) { // Step is thoroughly tested in the field package 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) 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) { func TestSet(t *testing.T) {
p := NewPointer() p := NewPointer()
p.Set(3, 14) p.Set(3, 14)
@ -93,8 +104,8 @@ func TestRedirect(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
p := NewPointer() p := NewPointer()
p.RedirectTo(3, 14) p.RedirectTo(3, 14)
p.ss.Push(2) p.Ss.Push(2)
p.ss.Push(7) p.Ss.Push(7)
v := p.Redirect(int(tc.input)) v := p.Redirect(int(tc.input))
require.Equal(t, true, v) require.Equal(t, true, v)
require.Equal(t, tc.expectedDx, p.dx, "Invalid dx value") require.Equal(t, tc.expectedDx, p.dx, "Invalid dx value")