Skip to content

Commit

Permalink
starlarkjson: sort dict keys (google#316)
Browse files Browse the repository at this point in the history
This is for consistency with the java.starlark.net implementation
and proposed spec.

This is a (minor) incompatible behavior change.
  • Loading branch information
adonovan authored Nov 13, 2020
1 parent 501b6c7 commit e292e66
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 16 deletions.
1 change: 1 addition & 0 deletions starlark/testdata/json.star
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ assert.eq(json.encode([1, 2, 3]), "[1,2,3]")
assert.eq(json.encode((1, 2, 3)), "[1,2,3]")
assert.eq(json.encode(range(3)), "[0,1,2]") # a built-in iterable
assert.eq(json.encode(dict(x = 1, y = "two")), '{"x":1,"y":"two"}')
assert.eq(json.encode(dict(y = "two", x = 1)), '{"x":1,"y":"two"}') # key, not insertion, order
assert.eq(json.encode(struct(x = 1, y = "two")), '{"x":1,"y":"two"}') # a user-defined HasAttrs
assert.eq(json.encode("\x80"), '"\\ufffd"') # invalid UTF-8 -> replacement char

Expand Down
30 changes: 14 additions & 16 deletions starlarkjson/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,24 @@ func encode(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, k
case starlark.IterableMapping:
// e.g. dict (must have string keys)
buf.WriteByte('{')
iter := x.Iterate()
defer iter.Done()
var k starlark.Value
for i := 0; iter.Next(&k); i++ {
items := x.Items()
for _, item := range items {
if _, ok := item[0].(starlark.String); !ok {
return fmt.Errorf("%s has %s key, want string", x.Type(), item[0].Type())
}
}
sort.Slice(items, func(i, j int) bool {
return items[i][0].(starlark.String) < items[j][0].(starlark.String)
})
for i, item := range items {
if i > 0 {
buf.WriteByte(',')
}
s, ok := starlark.AsString(k)
if !ok {
return fmt.Errorf("%s has %s key, want string", x.Type(), k.Type())
}
v, found, err := x.Get(k)
if err != nil || !found {
log.Fatalf("internal error: mapping %s has %s among keys but value lookup fails", x.Type(), k)
}

quote(s)
k, _ := starlark.AsString(item[0])
quote(k)
buf.WriteByte(':')
if err := emit(v); err != nil {
return fmt.Errorf("in %s key %s: %v", x.Type(), k, err)
if err := emit(item[1]); err != nil {
return fmt.Errorf("in %s key %s: %v", x.Type(), item[0], err)
}
}
buf.WriteByte('}')
Expand Down

0 comments on commit e292e66

Please sign in to comment.