aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmd/headless_interpreter/main.go3
-rw-r--r--pkg/interpreter/interpreter.go28
-rw-r--r--pkg/pointer/exec.go39
-rw-r--r--pkg/pointer/pointer.go13
-rw-r--r--pkg/pointer/pointer_test.go21
5 files changed, 78 insertions, 26 deletions
diff --git a/cmd/headless_interpreter/main.go b/cmd/headless_interpreter/main.go
index 73b71dc..9bed538 100644
--- a/cmd/headless_interpreter/main.go
+++ b/cmd/headless_interpreter/main.go
@@ -38,5 +38,6 @@ func main() {
os.Exit(3)
}
- interpreter.NewInterpreter(f, pointer.NewPointer()).Run()
+ v := interpreter.NewInterpreter(f, pointer.NewPointer()).Run()
+ os.Exit(v)
}
diff --git a/pkg/interpreter/interpreter.go b/pkg/interpreter/interpreter.go
index b64e90a..76917b7 100644
--- a/pkg/interpreter/interpreter.go
+++ b/pkg/interpreter/interpreter.go
@@ -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
}
diff --git a/pkg/pointer/exec.go b/pkg/pointer/exec.go
new file mode 100644
index 0000000..9d55136
--- /dev/null
+++ b/pkg/pointer/exec.go
@@ -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
+}
diff --git a/pkg/pointer/pointer.go b/pkg/pointer/pointer.go
index 4d847bf..902fe69 100644
--- a/pkg/pointer/pointer.go
+++ b/pkg/pointer/pointer.go
@@ -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
diff --git a/pkg/pointer/pointer_test.go b/pkg/pointer/pointer_test.go
index 4885d6b..aa007fe 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, 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")