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 676774e..80d1be1 100755 --- a/.github/run-tests.sh +++ b/.github/run-tests.sh @@ -1,8 +1,12 @@ #!/bin/sh + +# I don't even .. +go env -w GOFLAGS="-buildvcs=false" + # 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 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++ + } + +} 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++ }