From 52cb20bb62b26f3df87e9618a68f718e74d50ae0 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sat, 11 Nov 2023 19:43:37 +0200 Subject: [PATCH 1/4] Correct the iteration of key/values of hashes This commit adds a test-case which checks that the iteration over hash keys returns the correct results. It seems that the value varies over runs - so repeating the test ten times is likely sufficient to trigger the issue. Once this bug is fixed this will close #90. --- evaluator/evaluator_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 62afd12..454e4b0 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -55,6 +55,11 @@ func testEval(input string) object.Object { p := parser.New(l) program := p.ParseProgram() env := object.NewEnvironment() + + ctx, cancel := context.WithTimeout(context.Background(), 5000*time.Millisecond) + defer cancel() + SetContext(ctx) + return Eval(program, env) } @@ -654,3 +659,32 @@ for ( true ) { } } + +// Test90 tests hash-key iteration, which was reported in #90 +func Test90(t *testing.T) { + input := ` +a = { 1: "one", 2: "two", 3: "three" } +total = 0 +foreach key in a { + total += key +} +return total; +` + count := 0 + + for count < 10 { + + evaluated := testEval(input) + result, ok := evaluated.(*object.Integer) + if !ok { + t.Fatalf("Eval did't return number. got=%T(%+v)", + evaluated, evaluated) + } + if result.Value != 6 { + t.Fatalf("key iteration %d resulted in %d != 6", count, result) + } + + count++ + } + +} From 41db835cc12e97492c13ee42b5f868db6531b3b7 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sat, 11 Nov 2023 19:55:48 +0200 Subject: [PATCH 2/4] Sort the key/value pairs. --- object/object_hash.go | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/object/object_hash.go b/object/object_hash.go index c05cc18..fbfca82 100644 --- a/object/object_hash.go +++ b/object/object_hash.go @@ -102,10 +102,36 @@ func (h *Hash) Next() (Object, Object, bool) { if h.offset < len(h.Pairs) { idx := 0 - for _, pair := range h.Pairs { + // + // Bug: #90 + // + // Using "range" to iterate over a map will + // return the values in a random order. + // + // We need to sort the keys, that will give us + // a standard order. + // + // x -> sorted keys + // y -> key/val map, for simplicity + // + x := []Object{} + y := make(map[Object]Object) + // x is now the keys + for _, ent := range h.Pairs { + x = append(x, ent.Key) + y[ent.Key] = ent.Value + } + + // sort the keys + sort.Slice(x, func(i, j int) bool { + return x[i].Inspect() < x[j].Inspect() + }) + + // Now range over the keys + for _, key := range x { if h.offset == idx { h.offset++ - return pair.Key, pair.Value, true + return key, y[key], true } idx++ } From ea9cffd11329db439c77989560028ff7c33294f8 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sat, 11 Nov 2023 20:05:14 +0200 Subject: [PATCH 3/4] Install the tools correctly for linting --- .github/run-tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/run-tests.sh b/.github/run-tests.sh index 676774e..ce0764a 100755 --- a/.github/run-tests.sh +++ b/.github/run-tests.sh @@ -1,8 +1,8 @@ #!/bin/sh # Install the lint-tool, and the shadow-tool -go get -u golang.org/x/lint/golint -go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow +go install golang.org/x/lint/golint@latest +go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest # At this point failures cause aborts set -e From 777534120e604c6e90cbbd347805fe83f60e4d07 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Sat, 11 Nov 2023 20:16:48 +0200 Subject: [PATCH 4/4] Disable VCS stuff. --- .github/build | 4 ++++ .github/run-tests.sh | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/build b/.github/build index ea779ca..ecdc823 100755 --- a/.github/build +++ b/.github/build @@ -3,6 +3,10 @@ # The basename of our binary BASE="monkey" + +# I don't even .. +go env -w GOFLAGS="-buildvcs=false" + # # We build on multiple platforms/archs # diff --git a/.github/run-tests.sh b/.github/run-tests.sh index ce0764a..80d1be1 100755 --- a/.github/run-tests.sh +++ b/.github/run-tests.sh @@ -1,5 +1,9 @@ #!/bin/sh + +# I don't even .. +go env -w GOFLAGS="-buildvcs=false" + # Install the lint-tool, and the shadow-tool go install golang.org/x/lint/golint@latest go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest