From da7e7dae2b690308fb7ff3aba34145233c740bce Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Fri, 24 Sep 2021 01:26:49 +0200 Subject: Made the interpreter pass most of the mycology test suite --- .gitmodules | 6 ++ cmd/headless_interpreter/main.go | 5 +- go.mod | 2 - go.sum | 4 - mycology | 1 + pkg/field/utils.go | 4 + pkg/field/utils_test.go | 6 ++ pkg/pointer/exec.go | 161 +++++++++++++++++++++++++++++++++++++-- pkg/pointer/intput-output.go | 9 --- pkg/pointer/pointer.go | 2 + pkg/pointer/stack-stack.go | 37 ++++++--- pkg/pointer/stack.go | 3 + spec | 1 + 13 files changed, 206 insertions(+), 35 deletions(-) create mode 100644 .gitmodules create mode 160000 mycology create mode 160000 spec diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..efdb3a1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "spec"] + path = spec + url = https://github.com/catseye/Funge-98 +[submodule "mycology"] + path = mycology + url = https://github.com/Deewiant/Mycology diff --git a/cmd/headless_interpreter/main.go b/cmd/headless_interpreter/main.go index 9bed538..8bf97c4 100644 --- a/cmd/headless_interpreter/main.go +++ b/cmd/headless_interpreter/main.go @@ -37,7 +37,8 @@ func main() { fmt.Printf("Failed to load file %s : %+v", *filename, err) os.Exit(3) } - - v := interpreter.NewInterpreter(f, pointer.NewPointer()).Run() + p := pointer.NewPointer() + p.Argv = []string{*filename} + v := interpreter.NewInterpreter(f, p).Run() os.Exit(v) } diff --git a/go.mod b/go.mod index 4dea3d5..718a815 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,6 @@ require github.com/stretchr/testify v1.7.0 require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index edc2e45..c221f64 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= -github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/mycology b/mycology new file mode 160000 index 0000000..3787e42 --- /dev/null +++ b/mycology @@ -0,0 +1 @@ +Subproject commit 3787e42c3d4f0b735a09129a205e3e4df848558c diff --git a/pkg/field/utils.go b/pkg/field/utils.go index 4c4774c..1bd2b2b 100644 --- a/pkg/field/utils.go +++ b/pkg/field/utils.go @@ -96,3 +96,7 @@ func (f *Field) Set(x, y, v int) { } } } + +func (f Field) Dump() (int, int, int, int) { + return f.x, f.y, f.lx, f.ly +} diff --git a/pkg/field/utils_test.go b/pkg/field/utils_test.go index 9c1f7c7..837f9fb 100644 --- a/pkg/field/utils_test.go +++ b/pkg/field/utils_test.go @@ -329,3 +329,9 @@ func TestGetAndSetOnEmptyLines(t *testing.T) { field.Set(0, -1, 'c') require.Equal(t, &f, field) } + +func TestDump(t *testing.T) { + // nothing to test really + f := Field{} + f.Dump() +} diff --git a/pkg/pointer/exec.go b/pkg/pointer/exec.go index f7fcf8f..448e1e1 100644 --- a/pkg/pointer/exec.go +++ b/pkg/pointer/exec.go @@ -2,6 +2,9 @@ package pointer import ( "log" + "os" + "time" + "unsafe" "git.adyxax.org/adyxax/gofunge/pkg/field" ) @@ -41,12 +44,21 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { switch c { case '@': return true, nil + case 'z': case '#': p.Step(*f) case 'j': n := p.ss.head.Pop() - for j := 0; j < n; j++ { - p.Step(*f) + if n > 0 { + for j := 0; j < n; j++ { + p.Step(*f) + } + } else { + p.Reverse() + for j := 0; j < -n; j++ { + p.Step(*f) + } + p.Reverse() } case 'q': v := p.ss.head.Pop() @@ -54,13 +66,27 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { case 'k': n := p.ss.head.Pop() c = p.StepAndGet(*f) + steps := 1 for jumpingMode := false; jumpingMode || c == ' ' || c == ';'; c = p.StepAndGet(*f) { + steps += 1 if c == ';' { jumpingMode = !jumpingMode } } - for j := 0; j < n; j++ { - p.eval(c, f) + if n > 0 { + // we need to reverse that step + p.Reverse() + for i := 0; i < steps; i++ { + p.Step(*f) + } + p.Reverse() + if c != ' ' && c != ';' { + if n > 0 { + for i := 0; i < n; i++ { + p.eval(c, f) + } + } + } } case '!': v := p.ss.head.Pop() @@ -140,9 +166,13 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { case '{': p.ss.Begin(p) case '}': - p.ss.End(p) + if p.ss.End(p) { + p.Reverse() + } case 'u': - p.ss.Under() + if p.ss.Under() { + p.Reverse() + } case 'g': y, x := p.ss.head.Pop(), p.ss.head.Pop() p.ss.head.Push(f.Get(x+p.sox, y+p.soy)) @@ -157,6 +187,123 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { p.ss.head.Push(p.DecimalInput()) case '~': p.ss.head.Push(p.CharacterInput()) + case 'y': + n := p.ss.head.Pop() + if n > 22+p.ss.height { + n = n - 20 + if p.ss.head.height <= n { + p.ss.head.Push(0) + } else { + p.ss.head.Push(p.ss.head.data[p.ss.head.height-n]) + } + return + } + 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 + } + if n <= 0 { + for _, e := range os.Environ() { + p.ss.head.Push(0) + for i := len(e) - 1; i >= 0; i-- { + p.ss.head.Push(int(e[i])) + } + } + } + if n <= 0 { + p.ss.head.Push(0) + p.ss.head.Push(0) + for i := len(p.Argv) - 1; i >= 0; i-- { + p.ss.head.Push(0) + for j := len(p.Argv[i]) - 1; j >= 0; j-- { + p.ss.head.Push(int(p.Argv[i][j])) + } + } + } + if (n > 22 && n <= 22+p.ss.height) || n <= 0 { + for i := 0; i < len(heights); i++ { + p.ss.head.Push(heights[i]) + } + } + if n == 22 || n <= 0 { + p.ss.head.Push(p.ss.height) + } + if n == 21 || n <= 0 { + p.ss.head.Push((now.Hour() * 256 * 256) + (now.Minute() * 256) + now.Second()) + } + if n == 20 || n <= 0 { + p.ss.head.Push(((now.Year() - 1900) * 256 * 256) + (int(now.Month()) * 256) + now.Day()) + } + if n == 19 || n <= 0 { + p.ss.head.Push(lx + x) + } + if n == 18 || n <= 0 { + p.ss.head.Push(ly + y) + } + if n == 17 || n <= 0 { + p.ss.head.Push(x) + } + if n == 16 || n <= 0 { + p.ss.head.Push(y) + } + if n == 15 || n <= 0 { + p.ss.head.Push(p.sox) + } + if n == 14 || n <= 0 { + p.ss.head.Push(p.soy) + } + if n == 13 || n <= 0 { + p.ss.head.Push(p.dx) + } + if n == 12 || n <= 0 { + p.ss.head.Push(p.dy) + } + if n == 11 || n <= 0 { + p.ss.head.Push(p.x) + } + if n == 10 || n <= 0 { + p.ss.head.Push(p.y) + } + if n == 9 || n <= 0 { + p.ss.head.Push(0) + } + if n == 8 || n <= 0 { + p.ss.head.Push(*((*int)(unsafe.Pointer(p)))) + } + if n == 7 || n <= 0 { + p.ss.head.Push(2) + } + if n == 6 || n <= 0 { + p.ss.head.Push('/') + } + if n == 5 || n <= 0 { + p.ss.head.Push(0) // TODO update when implementing = + } + if n == 4 || n <= 0 { + p.ss.head.Push(1) + } + if n == 3 || n <= 0 { + p.ss.head.Push(1048576) + } + if n == 2 || n <= 0 { + p.ss.head.Push(uintSize / 8) + } + if n == 1 || n <= 0 { + p.ss.head.Push(0b00000) // TODO update when implementing t, i, o and = + } + case 'i': + log.Fatalf("Non implemented instruction code %d : %c", c, c) + case 'o': + log.Fatalf("Non implemented instruction code %d : %c", c, c) + case '=': + log.Fatalf("Non implemented instruction code %d : %c", c, c) + case 't': + log.Fatalf("Non implemented instruction code %d : %c", c, c) default: handled = false } @@ -168,7 +315,7 @@ func (p *Pointer) eval(c int, f *field.Field) (done bool, returnValue *int) { case c >= 'a' && c <= 'f': p.ss.head.Push(c - 'a' + 10) default: - log.Fatalf("Non implemented instruction code %d : %c", c, c) + p.Redirect('r') } } return diff --git a/pkg/pointer/intput-output.go b/pkg/pointer/intput-output.go index cc7533e..ac58d44 100644 --- a/pkg/pointer/intput-output.go +++ b/pkg/pointer/intput-output.go @@ -4,8 +4,6 @@ import ( "fmt" "log" "os" - - "github.com/pkg/term" ) var defaultInputLastChar *int = nil @@ -16,13 +14,6 @@ func DefaultCharacterInput() int { defaultInputLastChar = nil return c } - t, err := term.Open("/dev/stdin") - if err != nil { - log.Fatalf("Could not open stdin: %+v", err) - } - defer t.Close() - defer t.Restore() - term.RawMode(t) b := make([]byte, 1) i, err := os.Stdin.Read(b) if err != nil { diff --git a/pkg/pointer/pointer.go b/pkg/pointer/pointer.go index 2eea79d..d9a6b3d 100644 --- a/pkg/pointer/pointer.go +++ b/pkg/pointer/pointer.go @@ -31,6 +31,8 @@ type Pointer struct { DecimalInput InputFunction CharacterOutput OutputFunction DecimalOutput OutputFunction + // command line arguments + Argv []string } func NewPointer() *Pointer { diff --git a/pkg/pointer/stack-stack.go b/pkg/pointer/stack-stack.go index 2f57b05..404542c 100644 --- a/pkg/pointer/stack-stack.go +++ b/pkg/pointer/stack-stack.go @@ -21,18 +21,27 @@ func (ss *StackStack) Begin(p *Pointer) { np = -np } toss := &Stack{ - size: np, - height: np, - data: make([]int, np), - next: soss, + size: np, + data: make([]int, np), + next: soss, } ss.head = toss - max := n - soss.height - if max < 0 { - max = 0 - } - for i := n - 1; i >= max; i-- { - toss.data[i] = soss.data[soss.height-n+i] + 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 + } else if n < 0 { + for i := 0; i < np; i++ { + soss.Push(0) + } } x, y := p.GetStorageOffset() soss.Push(x) @@ -50,6 +59,12 @@ func (ss *StackStack) End(p *Pointer) (reflect bool) { 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)...) @@ -58,7 +73,7 @@ func (ss *StackStack) End(p *Pointer) (reflect bool) { for i := n; i > 0; i-- { soss.data[soss.height-i] = ss.head.data[ss.head.height-i] } - } else { + } else if n < 0 { soss.height += n if soss.height < 0 { soss.height = 0 diff --git a/pkg/pointer/stack.go b/pkg/pointer/stack.go index 1832dbb..ba51c7c 100644 --- a/pkg/pointer/stack.go +++ b/pkg/pointer/stack.go @@ -23,6 +23,9 @@ func (s *Stack) Clear() { func (s *Stack) Duplicate() { if s.height > 0 { s.Push(s.data[s.height-1]) + } else { + s.Push(0) + s.Push(0) } } diff --git a/spec b/spec new file mode 160000 index 0000000..7b4330d --- /dev/null +++ b/spec @@ -0,0 +1 @@ +Subproject commit 7b4330df1a624c464f01c80090b60621ce5a330e -- cgit v1.2.3