Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/build
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down
8 changes: 6 additions & 2 deletions .github/run-tests.sh
Original file line number Diff line number Diff line change
@@ -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
Expand Down
34 changes: 34 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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++
}

}
30 changes: 28 additions & 2 deletions object/object_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++
}
Expand Down