summaryrefslogtreecommitdiffstats
path: root/libgo/go/json
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-10-26 23:57:58 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-10-26 23:57:58 +0000
commitfa5d125b5cfa5c935e46d27a2cbcd71ae37687ac (patch)
tree19d182df05ead7ff8ba7ee00a7d57555e1383fdf /libgo/go/json
parente3d46e67996cf20ca3a75fccbb5a0007bfa3f992 (diff)
downloadppe42-gcc-fa5d125b5cfa5c935e46d27a2cbcd71ae37687ac.tar.gz
ppe42-gcc-fa5d125b5cfa5c935e46d27a2cbcd71ae37687ac.zip
Update Go library to last weekly.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@180552 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/json')
-rw-r--r--libgo/go/json/decode.go71
-rw-r--r--libgo/go/json/decode_test.go6
-rw-r--r--libgo/go/json/encode.go25
-rw-r--r--libgo/go/json/encode_test.go2
-rw-r--r--libgo/go/json/indent.go1
-rw-r--r--libgo/go/json/scanner_test.go35
-rw-r--r--libgo/go/json/stream_test.go25
7 files changed, 119 insertions, 46 deletions
diff --git a/libgo/go/json/decode.go b/libgo/go/json/decode.go
index b7129f9846a..31b15a400df 100644
--- a/libgo/go/json/decode.go
+++ b/libgo/go/json/decode.go
@@ -22,17 +22,20 @@ import (
// Unmarshal parses the JSON-encoded data and stores the result
// in the value pointed to by v.
//
-// Unmarshal traverses the value v recursively.
-// If an encountered value implements the Unmarshaler interface,
-// Unmarshal calls its UnmarshalJSON method with a well-formed
-// JSON encoding.
-//
-// Otherwise, Unmarshal uses the inverse of the encodings that
+// Unmarshal uses the inverse of the encodings that
// Marshal uses, allocating maps, slices, and pointers as necessary,
// with the following additional rules:
//
-// To unmarshal a JSON value into a nil interface value, the
-// type stored in the interface value is one of:
+// To unmarshal JSON into a pointer, Unmarshal first handles the case of
+// the JSON being the JSON literal null. In that case, Unmarshal sets
+// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
+// the value pointed at by the pointer. If the pointer is nil, Unmarshal
+// allocates a new value for it to point to.
+//
+// To unmarshal JSON into an interface value, Unmarshal unmarshals
+// the JSON into the concrete value contained in the interface value.
+// If the interface value is nil, that is, has no concrete value stored in it,
+// Unmarshal stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
@@ -250,8 +253,8 @@ func (d *decodeState) value(v reflect.Value) {
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
-// if wantptr is true, indirect stops at the last pointer.
-func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
+func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
@@ -277,7 +280,7 @@ func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, refl
break
}
- if pv.Elem().Kind() != reflect.Ptr && wantptr && pv.CanSet() && !isUnmarshaler {
+ if pv.Elem().Kind() != reflect.Ptr && decodingNull && pv.CanSet() {
return nil, pv
}
if pv.IsNil() {
@@ -391,11 +394,6 @@ func (d *decodeState) array(v reflect.Value) {
}
}
-// matchName returns true if key should be written to a field named name.
-func matchName(key, name string) bool {
- return strings.ToLower(key) == strings.ToLower(name)
-}
-
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte of the object ('{') has been read already.
func (d *decodeState) object(v reflect.Value) {
@@ -485,24 +483,31 @@ func (d *decodeState) object(v reflect.Value) {
var f reflect.StructField
var ok bool
st := sv.Type()
- // First try for field with that tag.
- if isValidTag(key) {
- for i := 0; i < sv.NumField(); i++ {
- f = st.Field(i)
- tagName, _ := parseTag(f.Tag.Get("json"))
- if tagName == key {
- ok = true
- break
- }
+ for i := 0; i < sv.NumField(); i++ {
+ sf := st.Field(i)
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ // Pretend this field doesn't exist.
+ continue
+ }
+ // First, tag match
+ tagName, _ := parseTag(tag)
+ if tagName == key {
+ f = sf
+ ok = true
+ break // no better match possible
+ }
+ // Second, exact field name match
+ if sf.Name == key {
+ f = sf
+ ok = true
+ }
+ // Third, case-insensitive field name match,
+ // but only if a better match hasn't already been seen
+ if !ok && strings.EqualFold(sf.Name, key) {
+ f = sf
+ ok = true
}
- }
- if !ok {
- // Second, exact match.
- f, ok = st.FieldByName(key)
- }
- if !ok {
- // Third, case-insensitive match.
- f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
}
// Extract value; name must be exported.
diff --git a/libgo/go/json/decode_test.go b/libgo/go/json/decode_test.go
index 5f6c3f5b8d0..2c7cbc4a290 100644
--- a/libgo/go/json/decode_test.go
+++ b/libgo/go/json/decode_test.go
@@ -15,6 +15,7 @@ import (
type T struct {
X string
Y int
+ Z int `json:"-"`
}
type tx struct {
@@ -42,7 +43,7 @@ var (
um0, um1 unmarshaler // target2 of unmarshaling
ump = &um1
umtrue = unmarshaler{true}
- umslice = []unmarshaler{unmarshaler{true}}
+ umslice = []unmarshaler{{true}}
umslicep = new([]unmarshaler)
umstruct = ustruct{unmarshaler{true}}
)
@@ -68,6 +69,9 @@ var unmarshalTests = []unmarshalTest{
{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
{`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+ // Z has a "-" tag.
+ {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
+
// syntax errors
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
diff --git a/libgo/go/json/encode.go b/libgo/go/json/encode.go
index 16be5e2af16..46abe4360ed 100644
--- a/libgo/go/json/encode.go
+++ b/libgo/go/json/encode.go
@@ -24,8 +24,11 @@ import (
// Marshal returns the JSON encoding of v.
//
// Marshal traverses the value v recursively.
-// If an encountered value implements the Marshaler interface,
-// Marshal calls its MarshalJSON method to produce JSON.
+// If an encountered value implements the Marshaler interface
+// and is not a nil pointer, Marshal calls its MarshalJSON method
+// to produce JSON. The nil pointer exception is not strictly necessary
+// but mimics a similar, necessary exception in the behavior of
+// UnmarshalJSON.
//
// Otherwise, Marshal uses the following type-dependent default encodings:
//
@@ -40,18 +43,23 @@ import (
// []byte encodes as a base64-encoded string.
//
// Struct values encode as JSON objects. Each exported struct field
-// becomes a member of the object unless the field is empty and its tag
-// specifies the "omitempty" option. The empty values are false, 0, any
+// becomes a member of the object unless
+// - the field's tag is "-", or
+// - the field is empty and its tag specifies the "omitempty" option.
+// The empty values are false, 0, any
// nil pointer or interface value, and any array, slice, map, or string of
// length zero. The object's default key string is the struct field name
// but can be specified in the struct field's tag value. The "json" key in
// struct field's tag value is the key name, followed by an optional comma
// and options. Examples:
//
-// // Specifies that Field appears in JSON as key "myName"
+// // Field is ignored by this package.
+// Field int `json:"-"`
+//
+// // Field appears in JSON as key "myName".
// Field int `json:"myName"`
//
-// // Specifies that Field appears in JSON as key "myName" and
+// // Field appears in JSON as key "myName" and
// // the field is omitted from the object if its value is empty,
// // as defined above.
// Field int `json:"myName,omitempty"`
@@ -240,7 +248,7 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
return
}
- if j, ok := v.Interface().(Marshaler); ok {
+ if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
b, err := j.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
@@ -298,6 +306,9 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
}
tag, omitEmpty, quoted := f.Name, false, false
if tv := f.Tag.Get("json"); tv != "" {
+ if tv == "-" {
+ continue
+ }
name, opts := parseTag(tv)
if isValidTag(name) {
tag = name
diff --git a/libgo/go/json/encode_test.go b/libgo/go/json/encode_test.go
index 012e9f143b4..f85bb6216a2 100644
--- a/libgo/go/json/encode_test.go
+++ b/libgo/go/json/encode_test.go
@@ -13,6 +13,7 @@ import (
type Optionals struct {
Sr string `json:"sr"`
So string `json:"so,omitempty"`
+ Sw string `json:"-"`
Ir int `json:"omitempty"` // actually named omitempty, not an option
Io int `json:"io,omitempty"`
@@ -33,6 +34,7 @@ var optionalsExpected = `{
func TestOmitEmpty(t *testing.T) {
var o Optionals
+ o.Sw = "something"
o.Mr = map[string]interface{}{}
o.Mo = map[string]interface{}{}
diff --git a/libgo/go/json/indent.go b/libgo/go/json/indent.go
index 000da42f6fb..2a753037308 100644
--- a/libgo/go/json/indent.go
+++ b/libgo/go/json/indent.go
@@ -59,6 +59,7 @@ func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
needIndent := false
depth := 0
for _, c := range src {
+ scan.bytes++
v := scan.step(&scan, int(c))
if v == scanSkipSpace {
continue
diff --git a/libgo/go/json/scanner_test.go b/libgo/go/json/scanner_test.go
index 023e7c81ee4..4d73eac8aaa 100644
--- a/libgo/go/json/scanner_test.go
+++ b/libgo/go/json/scanner_test.go
@@ -7,7 +7,9 @@ package json
import (
"bytes"
"math"
+ "os"
"rand"
+ "reflect"
"testing"
)
@@ -136,6 +138,29 @@ func TestIndentBig(t *testing.T) {
}
}
+type indentErrorTest struct {
+ in string
+ err os.Error
+}
+
+var indentErrorTests = []indentErrorTest{
+ {`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
+ {`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
+}
+
+func TestIdentErrors(t *testing.T) {
+ for i, tt := range indentErrorTests {
+ slice := make([]uint8, 0)
+ buf := bytes.NewBuffer(slice)
+ if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: Indent: %#v", i, err)
+ continue
+ }
+ }
+ }
+}
+
func TestNextValueBig(t *testing.T) {
initBig()
var scan scanner
@@ -150,7 +175,7 @@ func TestNextValueBig(t *testing.T) {
t.Errorf("invalid rest: %d", len(rest))
}
- item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
+ item, rest, err = nextValue(append(jsonBig, "HELLO WORLD"...), &scan)
if err != nil {
t.Fatalf("nextValue extra: %s", err)
}
@@ -235,10 +260,10 @@ func genValue(n int) interface{} {
}
func genString(stddev float64) string {
- n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
+ n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
c := make([]int, n)
for i := range c {
- f := math.Fabs(rand.NormFloat64()*64 + 32)
+ f := math.Abs(rand.NormFloat64()*64 + 32)
if f > 0x10ffff {
f = 0x10ffff
}
@@ -248,7 +273,7 @@ func genString(stddev float64) string {
}
func genArray(n int) []interface{} {
- f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
@@ -263,7 +288,7 @@ func genArray(n int) []interface{} {
}
func genMap(n int) map[string]interface{} {
- f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
diff --git a/libgo/go/json/stream_test.go b/libgo/go/json/stream_test.go
index 6ddaed9fe8f..ce5a7e6d656 100644
--- a/libgo/go/json/stream_test.go
+++ b/libgo/go/json/stream_test.go
@@ -120,3 +120,28 @@ func TestRawMessage(t *testing.T) {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
+
+func TestNullRawMessage(t *testing.T) {
+ // TODO(rsc): Should not need the * in *RawMessage
+ var data struct {
+ X float64
+ Id *RawMessage
+ Y float32
+ }
+ data.Id = new(RawMessage)
+ const msg = `{"X":0.1,"Id":null,"Y":0.2}`
+ err := Unmarshal([]byte(msg), &data)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if data.Id != nil {
+ t.Fatalf("Raw mismatch: have non-nil, want nil")
+ }
+ b, err := Marshal(&data)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if string(b) != msg {
+ t.Fatalf("Marshal: have %#q want %#q", b, msg)
+ }
+}
OpenPOWER on IntegriCloud