diff --git a/README.md b/README.md index 6d15cb0..88d4525 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,23 @@ root, err := sonic.Get(input, "key1", 1, "key2") sub := root.Get("key3").Index(2).Int64() // == 3 ``` +#### Set/Unset +Modify the json content by Set()/Unset() +```go +import "github.com/bytedance/sonic" + +// Set +exist, err := root.Set("key4", NewBool(true)) // exist == false +alias1 := root.Get("key4") +println(alias1.Valid()) // true +alias2 := root.Index(1) +println(alias1 == alias2) // true + +// Unset +exist, err := root.UnsetByIndex(1) // exist == true +println(root.Get("key4").Check()) // "value not exist" +``` + #### Serialize To encode `ast.Node` as json, use `MarshalJson()` or `json.Marshal()` (MUST pass the node's pointer) ```go diff --git a/ast/encode.go b/ast/encode.go index 21c548f..38eae51 100644 --- a/ast/encode.go +++ b/ast/encode.go @@ -17,7 +17,6 @@ package ast import ( - `errors` `sync` ) @@ -69,7 +68,8 @@ func (self *Node) encode(buf *[]byte) error { return self.encodeRaw(buf) } switch self.Type() { - case V_NONE : return errors.New("value not exist") + case V_NONE : return ErrNotExist + case V_ERROR : return self.Check() case V_NULL : return self.encodeNull(buf) case V_TRUE : return self.encodeTrue(buf) case V_FALSE : return self.encodeFalse(buf) @@ -77,13 +77,15 @@ func (self *Node) encode(buf *[]byte) error { case V_OBJECT: return self.encodeObject(buf) case V_STRING: return self.encodeString(buf) case V_NUMBER: return self.encodeNumber(buf) - default : errors.New("unsupported type") + default : return ErrUnsupportType } - return nil } func (self *Node) encodeRaw(buf *[]byte) error { - raw := self.Raw() + raw, err := self.Raw() + if err != nil { + return err + } *buf = append(*buf, raw...) return nil } @@ -119,7 +121,9 @@ func (self *Node) encodeString(buf *[]byte) error { func (self *Node) encodeArray(buf *[]byte) error { if self.isLazy() { - self.skipAllIndex() + if err := self.skipAllIndex(); err != nil { + return err + } } nb := self.len() @@ -157,7 +161,9 @@ func (self *Pair) encode(buf *[]byte) error { func (self *Node) encodeObject(buf *[]byte) error { if self.isLazy() { - self.skipAllKey() + if err := self.skipAllKey(); err != nil { + return err + } } nb := self.len() diff --git a/ast/iterator.go b/ast/iterator.go index d3b5e61..d47a062 100644 --- a/ast/iterator.go +++ b/ast/iterator.go @@ -35,7 +35,7 @@ func (self *Iterator) Len() int { } func (self *Iterator) HasNext() bool { - return self.i < self.p.len() + return self.i < self.p.len() && self.p.Valid() } type ListIterator struct { diff --git a/ast/iterator_test.go b/ast/iterator_test.go index 1cf23fa..ece4c07 100644 --- a/ast/iterator_test.go +++ b/ast/iterator_test.go @@ -47,14 +47,15 @@ func TestRawIterator(t *testing.T) { if err != nil { t.Fatal(err) } - ai := root.Values() + ai, _ := root.Values() i := int64(0) for ai.HasNext() { v := &Node{} if !ai.Next(v) { t.Fatalf("no next") - } - if i < int64(loop) && v.Int64() != i { + } + x, _ := v.Int64() + if i < int64(loop) && x != i { t.Fatalf("exp:%v, got:%v", i, v) } if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) { @@ -67,15 +68,17 @@ func TestRawIterator(t *testing.T) { if err != nil { t.Fatal(err) } - mi := root.Properties() + mi, _ := root.Properties() i = int64(0) for mi.HasNext() { v := &Pair{} if !mi.Next(v) { t.Fatalf("no next") - } - if i < int64(loop) &&( v.Value.Int64() != i ||v.Key != fmt.Sprintf("k%d", i)) { - t.Fatalf("exp:%v, got:%v", i, v.Value.Interface()) + } + x, _ := v.Value.Int64() + if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { + vv, _ := v.Value.Interface() + t.Fatalf("exp:%v, got:%v", i, vv) } if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { t.Fatal(i) @@ -92,14 +95,15 @@ func TestIterator(t *testing.T) { if err != 0 { t.Fatal(err) } - ai := root.Get("array").Values() + ai, _ := root.Get("array").Values() i := int64(0) for ai.HasNext() { v := &Node{} if !ai.Next(v) { t.Fatalf("no next") } - if i < int64(loop) && v.Int64() != i { + x, _ := v.Int64() + if i < int64(loop) && x != i { t.Fatalf("exp:%v, got:%v", i, v) } if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) { @@ -112,15 +116,17 @@ func TestIterator(t *testing.T) { if err != 0 { t.Fatal(err) } - mi := root.Get("object").Properties() + mi, _ := root.Get("object").Properties() i = int64(0) for mi.HasNext() { v := &Pair{} if !mi.Next(v) { t.Fatalf("no next") } - if i < int64(loop) &&( v.Value.Int64() != i ||v.Key != fmt.Sprintf("k%d", i)) { - t.Fatalf("exp:%v, got:%v", i, v.Value.Interface()) + x, _ := v.Value.Int64() + if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { + vv, _ := v.Value.Interface() + t.Fatalf("exp:%v, got:%v", i, vv) } if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { t.Fatal(i) @@ -135,7 +141,7 @@ func BenchmarkArrays(b *testing.B) { if err != nil { b.Fatal(err) } - a := root.Array() + a, _ := root.Array() for _,v := range a { _ = v } @@ -148,7 +154,7 @@ func BenchmarkListIterator(b *testing.B) { if err != nil { b.Fatal(err) } - it := root.Values() + it, _ := root.Values() for it.HasNext() { v := &Node{} if !it.Next(v) { @@ -164,7 +170,7 @@ func BenchmarkMap(b *testing.B) { if err != nil { b.Fatal(err) } - m := root.Map() + m, _ := root.Map() for k,v := range m { _ = v _ = k @@ -178,7 +184,7 @@ func BenchmarkObjectIterator(b *testing.B) { if err != nil { b.Fatal(err) } - it := root.Properties() + it, _ := root.Properties() for it.HasNext() { v := &Pair{} if !it.Next(v) { diff --git a/ast/node.go b/ast/node.go index 23d9c17..02ff3fb 100644 --- a/ast/node.go +++ b/ast/node.go @@ -20,6 +20,7 @@ import ( `encoding/json` `unsafe` + `github.com/bytedance/sonic/decoder` `github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/unquote` @@ -47,6 +48,7 @@ const ( const ( V_NONE = 0 + V_ERROR = 1 V_NULL = 2 V_TRUE = 3 V_FALSE = 4 @@ -67,6 +69,7 @@ type Node struct { // Type returns json type represented by the node // It will be one of belows: // V_NONE = 0 +// V_ERROR = 1 // V_NULL = 2 // V_TRUE = 3 // V_FALSE = 4 @@ -87,6 +90,39 @@ func (self *Node) Exists() bool { return self != nil && self.t != _V_NONE } +// Valid returns true when the node has any type of V_NULL ~ V_STRING, or V_NUMBER +func (self *Node) Valid() bool { + if self == nil { + return false + } + it := self.Type() + return it >= V_NULL && it <= V_STRING || it == V_NUMBER +} + +// Check check if the node itself is valid, and return: +// - ErrNotFound If the node does not exist +// - Its underlying error If the node is V_ERROR +func (self *Node) Check() error { + if self == nil || self.t == V_NONE { + return ErrNotExist + } else if self.t != V_ERROR { + return nil + } else { + return self + } +} + +// Error returns error message if the node is invalid +func (self Node) Error() string { + if self.t == V_NONE { + return "unsupported type" + } else if self.t != V_ERROR { + return "" + } else { + return *(*string)(self.p) + } +} + // IsRaw returns true if node's underlying value is raw json func (self Node) IsRaw() bool { return self.t&_V_RAW != 0 @@ -100,74 +136,94 @@ func (self Node) isLazy() bool { // Raw returns underlying json string of an raw node, // which usually created by Search() api -func (self Node) Raw() string { +func (self *Node) Raw() (string, error) { if !self.IsRaw() { - panic("value cannot be represented as raw json") + return "", ErrUnsupportType } - return addr2str(self.p, self.v) + return addr2str(self.p, self.v), nil } -func (self *Node) checkRaw() { - if !self.IsRaw() { - return +func (self *Node) checkRaw() error { + if self.IsRaw() { + *self = self.parseRaw() } - *self = self.parseRaw() + if err := self.Check(); err != nil { + return err + } + return nil } -// Bool returns bool value represented by this node +// Bool_E returns bool value represented by this node // -// If node type is not types.V_TRUE or types.V_FALSE, or V_RAW (must be a bool json value) -// it will panic -func (self *Node) Bool() bool { - self.checkRaw() +// If node type is not types.V_TRUE or types.V_FALSE, or V_RAW (must be a bool json value), +// it will return error +func (self *Node) Bool() (bool, error) { + if err := self.checkRaw(); err != nil { + return false, err + } switch self.t { - case types.V_TRUE : return true - case types.V_FALSE : return false - default : panic("value cannot be represented as a boolean") + case types.V_TRUE : return true , nil + case types.V_FALSE : return false, nil + default : return false, ErrUnsupportType } } // Int64 as above. -func (self *Node) Int64() int64 { - self.checkRaw() +func (self *Node) Int64() (int64, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } switch self.t { case _V_NUMBER : return numberToInt64(self) - case types.V_TRUE : return 1 - case types.V_FALSE : return 0 - default : panic("value cannot be represented as an integer") + case types.V_TRUE : return 1, nil + case types.V_FALSE : return 0, nil + default : return 0, ErrUnsupportType } } // Number as above. -func (self *Node) Number() json.Number { - self.checkRaw() +func (self *Node) Number() (json.Number, error) { + if err := self.checkRaw(); err != nil { + return json.Number(""), err + } switch self.t { - case _V_NUMBER : return toNumber(self) - default : panic("value cannot be represented as a json.Number") + case _V_NUMBER : return toNumber(self) , nil + case types.V_TRUE : return json.Number("1"), nil + case types.V_FALSE : return json.Number("0"), nil + default : return json.Number(""), ErrUnsupportType } } -// String as above. -func (self *Node) String() string { - self.checkRaw() +// String returns raw string value if node type is V_STRING. +// Or return the string representation of other types: +// V_NULL => "null", +// V_TRUE => "true", +// V_FALSE => "false", +// V_NUMBER => "[0-9\.]*" +func (self *Node) String() (string, error) { + if err := self.checkRaw(); err != nil { + return "", err + } switch self.t { - case _V_NUMBER : return toNumber(self).String() - case types.V_NULL : return "null" - case types.V_TRUE : return "true" - case types.V_FALSE : return "false" - case types.V_STRING : return addr2str(self.p, self.v) - default : panic("value cannot be represented as a simple string") + case _V_NUMBER : return toNumber(self).String(), nil + case types.V_NULL : return "null" , nil + case types.V_TRUE : return "true" , nil + case types.V_FALSE : return "false", nil + case types.V_STRING : return addr2str(self.p, self.v), nil + default : return "" , ErrUnsupportType } } // Float64 as above. -func (self *Node) Float64() float64 { - self.checkRaw() +func (self *Node) Float64() (float64, error) { + if err := self.checkRaw(); err != nil { + return 0.0, err + } switch self.t { case _V_NUMBER : return numberToFloat64(self) - case types.V_TRUE : return 1.0 - case types.V_FALSE : return 0.0 - default : panic("value cannot be represented as an integer") + case types.V_TRUE : return 1.0, nil + case types.V_FALSE : return 0.0, nil + default : return 0.0, ErrUnsupportType } } @@ -175,14 +231,16 @@ func (self *Node) Float64() float64 { // Len returns children count of a array|object|string node // For partially loaded node, it also works but only counts the parsed children -func (self *Node) Len() int { - self.checkRaw() +func (self *Node) Len() (int, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { - return int(self.v & _LEN_MASK) + return int(self.v & _LEN_MASK), nil } else if self.t == types.V_STRING { - return int(self.v) + return int(self.v), nil } else { - panic("value does not have a length") + return 0, ErrUnsupportType } } @@ -191,12 +249,14 @@ func (self Node) len() int { } // Cap returns malloc capacity of a array|object node for children -func (self *Node) Cap() int { - self.checkRaw() +func (self *Node) Cap() (int, error) { + if err := self.checkRaw(); err != nil { + return 0, err + } if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { - return int(self.v >> _CAP_BITS) + return int(self.v >> _CAP_BITS), nil } else { - panic("value does not have a capacity") + return 0, ErrUnsupportType } } @@ -206,13 +266,14 @@ func (self Node) cap() int { // Set sets the node of given key under object parent // If the key doesn't exist, it will be append to the last -func (self *Node) Set(key string, node Node) { +func (self *Node) Set(key string, node Node) (bool, error) { p := self.Get(key) + if !p.Exists() { l := self.len() c := self.cap() if l == c { - // TODO: maybe change append_extra_size in future + // TODO: maybe change append size in future c += _DEFAULT_NODE_CAP mem := unsafe_NewArray(_PAIR_TYPE, c) memmove(mem, self.p, _PAIR_SIZE * uintptr(l)) @@ -222,37 +283,47 @@ func (self *Node) Set(key string, node Node) { v.Key = key v.Value = node self.setCapAndLen(c, l+1) - } else { - *p = node - } + return false, nil + + } else if err := p.Check(); err != nil { + return false, err + } + + *p = node + return true, nil } // Unset remove the node of given key under object parent -func (self *Node) Unset(key string) (exist bool) { +func (self *Node) Unset(key string) (bool, error) { self.must(types.V_OBJECT, "an object") - n, i := self.skipKey(key) - if !n.Exists() { - return false + p, i := self.skipKey(key) + if !p.Exists() { + return false, nil + } else if err := p.Check(); err != nil { + return false, err } self.removePair(i) - return true + return true, nil } // SetByIndex sets the node of given index // // The index must within parent array's children -func (self *Node) SetByIndex(index int, node Node) { +func (self *Node) SetByIndex(index int, node Node) (bool, error) { p := self.Index(index) if !p.Exists() { - panic("index to nil value") - } else { - *p = node + return false, ErrNotExist + } else if err := p.Check(); err != nil { + return false, err } + + *p = node + return true, nil } // UnsetByIndex remove the node of given index -func (self *Node) UnsetByIndex(index int) (exist bool) { +func (self *Node) UnsetByIndex(index int) (bool, error) { var p *Node it := self.itype() if it == types.V_ARRAY { @@ -260,28 +331,34 @@ func (self *Node) UnsetByIndex(index int) (exist bool) { }else if it == types.V_OBJECT { pr := self.skipIndexPair(index) if pr == nil { - return false + return false, ErrNotExist } p = &pr.Value }else{ - panic("value must be object or array type") + return false, ErrUnsupportType } if !p.Exists() { - return false + return false, ErrNotExist } + if it == types.V_ARRAY { self.removeNode(index) }else if it == types.V_OBJECT { self.removePair(index) } - return true + return true, nil } // Add appends the given node under array node -func (self *Node) Add(node Node) { - self.must(types.V_ARRAY, "an array") - self.skipAllIndex() +func (self *Node) Add(node Node) error { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return err + } + if err := self.skipAllIndex(); err != nil { + return err + } + l := self.len() c := self.cap() if l == c { @@ -291,25 +368,30 @@ func (self *Node) Add(node Node) { memmove(mem, self.p, _NODE_SIZE * uintptr(l)) self.p = mem } + v := self.nodeAt(l) *v = node self.setCapAndLen(c, l+1) + return nil } // GetByPath load given path on demands, // which only ensure nodes before this path got parsed func (self *Node) GetByPath(path ...interface{}) *Node { + if !self.Valid() { + return self + } var s = self for _, p := range path { switch p.(type) { case int: s = s.Index(p.(int)) - if !s.Exists() { + if !s.Valid() { return s } case string: s = s.Get(p.(string)) - if !s.Exists() { + if !s.Valid() { return s } default: @@ -321,7 +403,9 @@ func (self *Node) GetByPath(path ...interface{}) *Node { // Get loads given key of an object node on demands func (self *Node) Get(key string) *Node { - self.must(types.V_OBJECT, "an object") + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return unwrapError(err) + } n, _ := self.skipKey(key) return n } @@ -329,163 +413,228 @@ func (self *Node) Get(key string) *Node { // Index loads given index of an node on demands, // node type can be either V_OBJECT or V_ARRAY func (self *Node) Index(idx int) *Node { - self.checkRaw() + if err := self.checkRaw(); err != nil { + return unwrapError(err) + } + it := self.itype() - if it == types.V_ARRAY { return self.skipIndex(idx) }else if it == types.V_OBJECT { pr := self.skipIndexPair(idx) if pr == nil { - return &Node{} + return nodeNotExist } return &pr.Value }else{ - panic("node must be object or array type") + return nodeUnsupportType } } // Values returns iterator for array's children traversal -func (self *Node) Values() ListIterator { - self.must(types.V_ARRAY, "an array") - self.skipAllIndex() - return ListIterator{Iterator{p: self}} +func (self *Node) Values() (ListIterator, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return ListIterator{}, err + } + if err := self.skipAllIndex(); err != nil { + return ListIterator{}, err + } + return ListIterator{Iterator{p: self}}, nil } // Properties returns iterator for object's children traversal -func (self *Node) Properties() ObjectIterator { - self.must(types.V_OBJECT, "an object") - self.skipAllKey() - return ObjectIterator{Iterator{p: self}} +func (self *Node) Properties() (ObjectIterator, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return ObjectIterator{}, err + } + if err := self.skipAllKey(); err != nil { + return ObjectIterator{}, err + } + return ObjectIterator{Iterator{p: self}}, nil } /** Generic Value Converters **/ // Map loads all keys of an object node -func (self *Node) Map() map[string]interface{} { - self.must(types.V_OBJECT, "an object") - self.loadAllKey() +func (self *Node) Map() (map[string]interface{}, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.loadAllKey(); err != nil { + return nil, err + } return self.toGenericObject() } // MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number -func (self *Node) MapUseNumber() map[string]interface{} { - self.must(types.V_OBJECT, "an object") - self.loadAllKey() +func (self *Node) MapUseNumber() (map[string]interface{}, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.loadAllKey(); err != nil { + return nil, err + } return self.toGenericObjectUseNumber() } // MapUseNode scans both parsed and non-parsed chidren nodes, // and map them by their keys -func (self *Node) MapUseNode() map[string]Node { - self.must(types.V_OBJECT, "an object") - self.skipAllKey() +func (self *Node) MapUseNode() (map[string]Node, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.skipAllKey(); err != nil { + return nil, err + } return self.toGenericObjectUseNode() } // MapUnsafe exports the underlying pointer to its children map // WARN: don't use it unless you know what you are doing -func (self *Node) UnsafeMap() []Pair { - self.must(types.V_OBJECT, "an object") - self.skipAllKey() +func (self *Node) UnsafeMap() ([]Pair, error) { + if err := self.should(types.V_OBJECT, "an object"); err != nil { + return nil, err + } + if err := self.skipAllKey(); err != nil { + return nil, err + } s := ptr2slice(self.p, int(self.len()), self.cap()) - return *(*[]Pair)(s) + return *(*[]Pair)(s), nil } // Array loads all indexes of an array node -func (self *Node) Array() []interface{} { - self.must(types.V_ARRAY, "an array") - self.loadAllIndex() +func (self *Node) Array() ([]interface{}, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } return self.toGenericArray() } // ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number -func (self *Node) ArrayUseNumber() []interface{} { - self.must(types.V_ARRAY, "an array") - self.loadAllIndex() +func (self *Node) ArrayUseNumber() ([]interface{}, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } return self.toGenericArrayUseNumber() } // ArrayUseNode copys both parsed and non-parsed chidren nodes, // and indexes them by original order -func (self *Node) ArrayUseNode() []Node { - self.must(types.V_ARRAY, "an array") - self.skipAllIndex() +func (self *Node) ArrayUseNode() ([]Node, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } return self.toGenericArrayUseNode() } // ArrayUnsafe exports the underlying pointer to its children array // WARN: don't use it unless you know what you are doing -func (self *Node) UnsafeArray() []Node { - self.must(types.V_ARRAY, "an array") - self.skipAllIndex() - s := ptr2slice(self.p, self.len(), self.Cap()) - return *(*[]Node)(s) +func (self *Node) UnsafeArray() ([]Node, error) { + if err := self.should(types.V_ARRAY, "an array"); err != nil { + return nil, err + } + if err := self.loadAllIndex(); err != nil { + return nil, err + } + s := ptr2slice(self.p, self.len(), self.cap()) + return *(*[]Node)(s), nil } // Interface loads all children under all pathes from this node, -// and converts itself as generic go type -// all numberic nodes are casted to float64 -func (self *Node) Interface() interface{} { - self.checkRaw() +// and converts itself as generic type. +// WARN: all numberic nodes are casted to float64 +func (self *Node) Interface() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } switch self.t { - case types.V_EOF : panic("invalid value") - case types.V_NULL : return nil - case types.V_TRUE : return true - case types.V_FALSE : return false + case V_ERROR : return nil, self.Check() + case types.V_NULL : return nil, nil + case types.V_TRUE : return true, nil + case types.V_FALSE : return false, nil case types.V_ARRAY : return self.toGenericArray() case types.V_OBJECT : return self.toGenericObject() - case types.V_STRING : return addr2str(self.p, self.v) - case _V_NUMBER : return numberToFloat64(self) + case types.V_STRING : return addr2str(self.p, self.v), nil + case _V_NUMBER : + v, err := numberToFloat64(self) + if err != nil { + return nil, err + } + return v, nil case _V_ARRAY_LAZY : - self.loadAllIndex() + if err := self.loadAllIndex(); err != nil { + return nil, err + } return self.toGenericArray() case _V_OBJECT_LAZY : - self.loadAllKey() + if err := self.loadAllKey(); err != nil { + return nil, err + } return self.toGenericObject() - default : panic("not gonna happen") + default : return nil, ErrUnsupportType } } // InterfaceUseNumber works same with Interface() // except numberic nodes are casted to json.Number -func (self *Node) InterfaceUseNumber() interface{} { - self.checkRaw() +func (self *Node) InterfaceUseNumber() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } switch self.t { - case types.V_EOF : panic("invalid value") - case types.V_NULL : return nil - case types.V_TRUE : return true - case types.V_FALSE : return false + case V_ERROR : return nil, self.Check() + case types.V_NULL : return nil, nil + case types.V_TRUE : return true, nil + case types.V_FALSE : return false, nil case types.V_ARRAY : return self.toGenericArrayUseNumber() case types.V_OBJECT : return self.toGenericObjectUseNumber() - case types.V_STRING : return addr2str(self.p, self.v) - case _V_NUMBER : return toNumber(self) + case types.V_STRING : return addr2str(self.p, self.v), nil + case _V_NUMBER : return toNumber(self), nil case _V_ARRAY_LAZY : - self.loadAllIndex() + if err := self.loadAllIndex(); err != nil { + return nil, err + } return self.toGenericArrayUseNumber() case _V_OBJECT_LAZY : - self.loadAllKey() + if err := self.loadAllKey(); err != nil { + return nil, err + } return self.toGenericObjectUseNumber() - default : panic("not gonna happen") + default : return nil, ErrUnsupportType } } // InterfaceUseNode clone itself as a new node, // or its children as map[string]Node (or []Node) -func (self *Node) InterfaceUseNode() interface{} { - self.checkRaw() +func (self *Node) InterfaceUseNode() (interface{}, error) { + if err := self.checkRaw(); err != nil { + return nil, err + } switch self.t { case types.V_ARRAY : return self.toGenericArrayUseNode() case types.V_OBJECT : return self.toGenericObjectUseNode() - case _V_ARRAY_LAZY: - self.skipAllIndex() + case _V_ARRAY_LAZY : + if err := self.skipAllIndex(); err != nil { + return nil, err + } return self.toGenericArrayUseNode() - case _V_OBJECT_LAZY: - self.skipAllKey() + case _V_OBJECT_LAZY : + if err := self.loadAllKey(); err != nil { + return nil, err + } return self.toGenericObjectUseNode() - default : return *self + default : return *self, nil } } @@ -513,16 +662,25 @@ func (self *Pair) unsafe_next() *Pair { } func (self *Node) must(t types.ValueType, s string) { - self.checkRaw() - if self.itype() != t { + if err := self.checkRaw(); err != nil { + panic(err) + } + if err := self.Check(); err != nil { + panic(err) + } + if self.itype() != t { panic("value cannot be represented as " + s) } } -func (self *Node) bound(i int) { - if i < 0 || i >= self.Len() { - panic("list index out of range") +func (self *Node) should(t types.ValueType, s string) error { + if err := self.checkRaw(); err != nil { + return err } + if self.itype() != t { + return ErrUnsupportType + } + return nil } func (self *Node) nodeAt(i int) *Node { @@ -587,9 +745,9 @@ func (self *Node) getParserAndObjectStack() (*Parser, *parseObjectStack) { return &stack.parser, stack } -func (self *Node) skipAllIndex() { +func (self *Node) skipAllIndex() error { if !self.isLazy() { - return + return nil } var err types.ParsingError parser, stack := self.getParserAndArrayStack() @@ -597,13 +755,14 @@ func (self *Node) skipAllIndex() { parser.noLazy = true *self, err = parser.decodeArray(stack.v) if err != 0 { - panic(parser.ExportError(err)) + return parser.ExportError(err) } + return nil } -func (self *Node) skipAllKey() { +func (self *Node) skipAllKey() error { if !self.isLazy() { - return + return nil } var err types.ParsingError parser, stack := self.getParserAndObjectStack() @@ -611,8 +770,9 @@ func (self *Node) skipAllKey() { parser.noLazy = true *self, err = parser.decodeObject(stack.v) if err != 0 { - panic(parser.ExportError(err)) + return parser.ExportError(err) } + return nil } func (self *Node) skipNextNode() *Node { @@ -627,7 +787,7 @@ func (self *Node) skipNextNode() *Node { /* check for EOF */ if parser.p = parser.lspace(sp); parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF)) + return newSyntaxError(parser.syntaxError(types.ERR_EOF)) } /* check for empty array */ @@ -640,11 +800,11 @@ func (self *Node) skipNextNode() *Node { var val Node /* skip the value */ if start, err := parser.skip(); err != 0 { - panic(parser.ExportError(err)) + return newSyntaxError(parser.syntaxError(err)) }else{ t := switchRawType(parser.s[start]) if t == _V_NONE { - panic(parser.ExportError(types.ERR_INVALID_CHAR)) + return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) } val = newRawNode(parser.s[start:parser.p], t) } @@ -655,7 +815,7 @@ func (self *Node) skipNextNode() *Node { /* check for EOF */ if parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF)) + return newSyntaxError(parser.syntaxError(types.ERR_EOF)) } /* check for the next character */ @@ -669,7 +829,7 @@ func (self *Node) skipNextNode() *Node { self.setArray(ret) return &ret[len(ret)-1] default: - panic(parser.ExportError(types.ERR_INVALID_CHAR)) + return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) } } @@ -685,7 +845,7 @@ func (self *Node) skipNextPair() (*Pair) { /* check for EOF */ if parser.p = parser.lspace(sp); parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF)) + return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_EOF))} } /* check for empty object */ @@ -702,7 +862,7 @@ func (self *Node) skipNextPair() (*Pair) { /* decode the key */ if njs = parser.decodeValue(); njs.Vt != types.V_STRING { - panic(parser.ExportError(types.ERR_INVALID_CHAR)) + return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} } /* extract the key */ @@ -712,22 +872,22 @@ func (self *Node) skipNextPair() (*Pair) { /* check for escape sequence */ if njs.Ep != -1 { if key, err = unquote.String(key); err != 0 { - panic(parser.ExportError(err)) + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} } } /* expect a ':' delimiter */ if err = parser.delim(); err != 0 { - panic(parser.ExportError(err)) + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} } /* skip the value */ if start, err := parser.skip(); err != 0 { - panic(parser.ExportError(err)) + return &Pair{key, *newSyntaxError(parser.syntaxError(err))} }else{ t := switchRawType(parser.s[start]) if t == _V_NONE { - panic(parser.ExportError(types.ERR_INVALID_CHAR)) + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} } val = newRawNode(parser.s[start:parser.p], t) } @@ -738,7 +898,7 @@ func (self *Node) skipNextPair() (*Pair) { /* check for EOF */ if parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF)) + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_EOF))} } /* check for the next character */ @@ -752,7 +912,7 @@ func (self *Node) skipNextPair() (*Pair) { self.setObject(ret) return &ret[len(ret)-1] default: - panic(parser.ExportError(types.ERR_INVALID_CHAR)) + return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} } } @@ -768,12 +928,14 @@ func (self *Node) skipKey(key string) (*Node, int) { // lazy load var i = self.len() for last := self.skipNextPair(); last != nil; last = self.skipNextPair() { + if last.Value.Check() != nil { + return &last.Value, -1 + } if last.Key == key { return &last.Value, i } i++ } - return &Node{}, -1 } @@ -789,6 +951,9 @@ func (self *Node) skipIndex(index int) *Node { // lazy load for last := self.skipNextNode(); last != nil; last = self.skipNextNode(){ + if last.Check() != nil { + return last + } if self.len() > index { return last } @@ -808,6 +973,9 @@ func (self *Node) skipIndexPair(index int) *Pair { // lazy load for last := self.skipNextPair(); last != nil; last = self.skipNextPair(){ + if last.Value.Check() != nil { + return last + } if self.len() > index { return last } @@ -816,30 +984,32 @@ func (self *Node) skipIndexPair(index int) *Pair { return nil } -func (self *Node) loadAllIndex() { +func (self *Node) loadAllIndex() error { if !self.isLazy() { - return + return nil } var err types.ParsingError parser, stack := self.getParserAndArrayStack() parser.noLazy = true *self, err = parser.decodeArray(stack.v) if err != 0 { - panic(parser.ExportError(err)) + return parser.ExportError(err) } + return nil } -func (self *Node) loadAllKey() { +func (self *Node) loadAllKey() error { if !self.isLazy() { - return + return nil } var err types.ParsingError parser, stack := self.getParserAndObjectStack() parser.noLazy = true *self, err = parser.decodeObject(stack.v) if err != 0 { - panic(parser.ExportError(err)) + return parser.ExportError(err) } + return nil } func (self *Node) removeNode(i int) { @@ -878,116 +1048,166 @@ func (self *Node) removePair(i int) { self.setCapAndLen(self.cap(), nb) } -func (self *Node) toGenericArray() []interface{} { +func (self *Node) toGenericArray() ([]interface{}, error) { nb := self.len() ret := make([]interface{}, nb) if nb == 0 { - return ret + return ret, nil } /* convert each item */ var p = (*Node)(self.p) - ret[0] = p.Interface() + x, err := p.Interface() + if err != nil { + return nil, err + } + ret[0] = x + for i := 1; i < nb; i++ { p = p.unsafe_next() - ret[i] = p.Interface() + x, err := p.Interface() + if err != nil { + return nil, err + } + ret[i] = x } /* all done */ - return ret + return ret, nil } -func (self *Node) toGenericArrayUseNumber() []interface{} { +func (self *Node) toGenericArrayUseNumber() ([]interface{}, error) { nb := self.len() ret := make([]interface{}, nb) if nb == 0 { - return ret + return ret, nil } /* convert each item */ var p = (*Node)(self.p) - ret[0] = p.InterfaceUseNumber() + x, err := p.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[0] = x + for i := 1; i < nb; i++ { p = p.unsafe_next() - ret[i] = p.InterfaceUseNumber() + x, err := p.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[i] = x } /* all done */ - return ret + return ret, nil } -func (self *Node) toGenericArrayUseNode() []Node { +func (self *Node) toGenericArrayUseNode() ([]Node, error) { var nb = self.len() var out = make([]Node, nb) if nb == 0 { - return out + return out, nil } var p = (*Node)(self.p) out[0] = *p + if err := p.Check(); err != nil { + return nil, err + } + for i := 1; i < nb; i++ { p = p.unsafe_next() + if err := p.Check(); err != nil { + return nil, err + } out[i] = *p } - return out + return out, nil } -func (self *Node) toGenericObject() map[string]interface{} { +func (self *Node) toGenericObject() (map[string]interface{}, error) { nb := self.len() ret := make(map[string]interface{}, nb) if nb == 0 { - return ret + return ret, nil } /* convert each item */ var p = (*Pair)(self.p) - ret[p.Key] = p.Value.Interface() + x, err := p.Value.Interface() + if err != nil { + return nil, err + } + ret[p.Key] = x + for i := 1; i < nb; i++ { p = p.unsafe_next() - ret[p.Key] = p.Value.Interface() + x, err := p.Value.Interface() + if err != nil { + return nil, err + } + ret[p.Key] = x } /* all done */ - return ret + return ret, nil } -func (self *Node) toGenericObjectUseNumber() map[string]interface{} { +func (self *Node) toGenericObjectUseNumber() (map[string]interface{}, error) { nb := self.len() ret := make(map[string]interface{}, nb) if nb == 0 { - return ret + return ret, nil } /* convert each item */ var p = (*Pair)(self.p) - ret[p.Key] = p.Value.InterfaceUseNumber() + x, err := p.Value.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[p.Key] = x + for i := 1; i < nb; i++ { p = p.unsafe_next() - ret[p.Key] = p.Value.InterfaceUseNumber() + x, err := p.Value.InterfaceUseNumber() + if err != nil { + return nil, err + } + ret[p.Key] = x } /* all done */ - return ret + return ret, nil } -func (self *Node) toGenericObjectUseNode() map[string]Node { +func (self *Node) toGenericObjectUseNode() (map[string]Node, error) { var nb = self.len() var out = make(map[string]Node, nb) if nb == 0 { - return out + return out, nil } var p = (*Pair)(self.p) out[p.Key] = p.Value + if err := p.Value.Check(); err != nil { + return nil, err + } + for i := 1; i < nb; i++ { p = p.unsafe_next() + if err := p.Value.Check(); err != nil { + return nil, err + } out[p.Key] = p.Value } /* all done */ - return out + return out, nil } /**------------------------------------ Factory Methods ------------------------------------**/ @@ -1039,20 +1259,20 @@ func toNumber(node *Node) json.Number { return json.Number(addr2str(node.p, node.v)) } -func numberToFloat64(node *Node) float64 { +func numberToFloat64(node *Node) (float64, error) { ret,err := toNumber(node).Float64() if err != nil { - panic(err) + return 0, err } - return ret + return ret, nil } -func numberToInt64(node *Node) int64 { +func numberToInt64(node *Node) (int64, error) { ret,err := toNumber(node).Int64() if err != nil { - panic(err) + return 0, err } - return ret + return ret, nil } func newBytes(v []byte) Node { @@ -1167,11 +1387,28 @@ func (self *Node) parseRaw() Node { parser := NewParser(raw) n, e := parser.Parse() if e != 0 { - panic(parser.ExportError(e)) + return *newSyntaxError(parser.syntaxError(e)) } return n } +func newError(err types.ParsingError, msg string) *Node { + return &Node{ + t: V_ERROR, + v: int64(err), + p: unsafe.Pointer(&msg), + } +} + +func newSyntaxError(err *decoder.SyntaxError) *Node { + msg := err.Description() + return &Node{ + t: V_ERROR, + v: int64(err.Code), + p: unsafe.Pointer(&msg), + } +} + var typeJumpTable = [256]types.ValueType{ '"' : types.V_STRING, '-' : _V_NUMBER, @@ -1194,4 +1431,19 @@ var typeJumpTable = [256]types.ValueType{ func switchRawType(c byte) types.ValueType { return typeJumpTable[c] +} + +func unwrapError(err error) *Node { + if se, ok := err.(*Node); ok { + return se + }else if sse, ok := err.(Node); ok { + return &sse + }else{ + msg := err.Error() + return &Node{ + t: V_ERROR, + v: 0, + p: unsafe.Pointer(&msg), + } + } } \ No newline at end of file diff --git a/ast/node_test.go b/ast/node_test.go index 6fefc13..574f593 100644 --- a/ast/node_test.go +++ b/ast/node_test.go @@ -18,6 +18,8 @@ package ast import ( `encoding/json` + `fmt` + `reflect` `strconv` `testing` @@ -28,13 +30,134 @@ import ( var parallelism = 4 +func TestTypeCast(t *testing.T) { + type tcase struct { + method string + node Node + exp interface{} + err error + } + lazyArray, _ := NewParser("[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]").Parse() + lazyObject, _ := NewParser(`{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16}`).Parse() + var cases = []tcase{ + {"Raw", Node{}, "", ErrUnsupportType}, + {"Raw", newRawNode("[ ]", types.V_ARRAY), "[ ]", nil}, + {"Bool", Node{}, false, ErrNotExist}, + {"Bool", newRawNode("true", types.V_TRUE), true, nil}, + {"Bool", newRawNode("false", types.V_FALSE), false, nil}, + {"Int64", Node{}, int64(0), ErrNotExist}, + {"Int64", newRawNode("0", _V_NUMBER), int64(0), nil}, + {"Float64", Node{}, float64(0), ErrNotExist}, + {"Float64", newRawNode("0.0", _V_NUMBER), float64(0.0), nil}, + {"Number", Node{}, json.Number(""), ErrNotExist}, + {"Number", newRawNode("0.0", _V_NUMBER), json.Number("0.0"), nil}, + {"Number", newRawNode("true", types.V_TRUE), json.Number("1"), nil}, + {"Number", newRawNode("false", types.V_FALSE), json.Number("0"), nil}, + {"String", Node{}, "", ErrNotExist}, + {"String", newRawNode(`""`, types.V_STRING), ``, nil}, + {"String", newRawNode(`0.0`, _V_NUMBER), "0.0", nil}, + {"String", newRawNode(`null`, types.V_NULL), "null", nil}, + {"String", newRawNode(`true`, types.V_TRUE), "true", nil}, + {"String", newRawNode(`false`, types.V_FALSE), "false", nil}, + {"Len", NewNull(), 0, ErrUnsupportType}, + {"Len", newRawNode(`"1"`, types.V_STRING), 1, nil}, + {"Len", newRawNode(`[1]`, types.V_ARRAY), 0, nil}, + {"Len", NewArray([]Node{NewNull()}), 1, nil}, + {"Len", lazyArray, 0, nil}, + {"Len", newRawNode(`{"a":1}`, types.V_OBJECT), 0, nil}, + {"Len", lazyObject, 0, nil}, + {"Cap", NewNull(), 0, ErrUnsupportType}, + {"Cap", newRawNode(`[1]`, types.V_ARRAY), _DEFAULT_NODE_CAP, nil}, + {"Cap", NewObject([]Pair{{"",NewNull()}}), 1, nil}, + {"Cap", newRawNode(`{"a":1}`, types.V_OBJECT), _DEFAULT_NODE_CAP, nil}, + } + lazyArray.skipAllIndex() + lazyObject.skipAllKey() + cases = append(cases, + tcase{"Len", lazyObject, 17, nil}, + tcase{"Len", lazyObject, 17, nil}, + tcase{"Cap", lazyObject, _DEFAULT_NODE_CAP*2, nil}, + tcase{"Cap", lazyObject, _DEFAULT_NODE_CAP*2, nil}, + ) + + for i, c := range cases { + fmt.Println(c) + rt := reflect.ValueOf(&c.node) + m := rt.MethodByName(c.method) + rets := m.Call([]reflect.Value{}) + if len(rets) != 2 { + t.Fatal(i, rets) + } + if rets[0].Interface() != c.exp { + t.Fatal(i, rets[0].Interface()) + } + if rets[1].Interface() != c.err { + t.Fatal(i, rets[1].Interface()) + } + } +} + +func TestCheckError(t *testing.T) { + s, err := NewParser(`{"a":{}, "b":talse, "c":{}}`).Parse() + if err != 0 { + t.Fatal(err) + } + root := s.GetByPath() + // fmt.Println(root.Check()) + a := root.Get("a") + if a.Check() != nil { + t.Fatal(a.Check()) + } + c := root.Get("c") + if c.Check() == nil { + t.Fatal() + } + fmt.Println(c.Check()) + + _, e := a.Properties() + if e != nil { + t.Fatal(e) + } + exist, e := a.Set("d", newRawNode("x", types.V_OBJECT)) + if exist || e != nil { + t.Fatal(err) + } + if a.len() != 1 { + t.Fail() + } + d := a.Get("d").Get("") + if d.Check() == nil { + t.Fatal(d) + } + exist, e = a.Set("e", newRawNode("[}", types.V_ARRAY)) + if e != nil { + t.Fatal(e) + } + if a.len() != 2 { + t.Fail() + } + d = a.Index(1).Index(0) + if d.Check() == nil { + t.Fatal(d) + } + + + it, e := root.Interface() + if e == nil { + t.Fatal(it) + } + fmt.Println(e) +} + func TestIndex(t *testing.T) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) } status := root.GetByPath("statuses", 0) - if status.Index(4).String() != status.Get("id_str").String() { + x, _ := status.Index(4).String() + y, _ := status.Get("id_str").String() + if x != y { t.Fail() } } @@ -48,25 +171,26 @@ func TestUnset(t *testing.T) { if !entities.Exists() { t.Fatal() } - exist := entities.Unset("urls") - if !exist { + exist, err := entities.Unset("urls") + if !exist || err != nil { t.Fatal() } e := entities.Get("urls") if e.Exists() { t.Fatal() } - if entities.Len() != 2 { + if entities.len() != 2 { t.Fatal() } entities.Set("urls", NewString("a")) e = entities.Get("urls") - if !e.Exists() || e.String() != "a" { + x, _ := e.String() + if !e.Exists() || x != "a" { t.Fatal() } - exist = entities.UnsetByIndex(entities.Len()-1) - if !exist { + exist, err = entities.UnsetByIndex(entities.len()-1) + if !exist || err != nil { t.Fatal() } e = entities.Get("urls") @@ -76,11 +200,12 @@ func TestUnset(t *testing.T) { hashtags := entities.Get("hashtags").Index(0) hashtags.Set("text2", newRawNode(`{}`, types.V_OBJECT)) - exist = hashtags.Unset("indices") - if !exist || hashtags.Len() != 2 { + exist, err = hashtags.Unset("indices") + if !exist || err != nil || hashtags.len() != 2 { t.Fatal() } - if hashtags.Get("text").String() != "freebandnames" { + y, _ := hashtags.Get("text").String() + if y != "freebandnames" { t.Fatal() } if hashtags.Get("text2").Type() != V_OBJECT { @@ -91,14 +216,16 @@ func TestUnset(t *testing.T) { ums.Add(NewNull()) ums.Add(NewBool(true)) ums.Add(NewBool(false)) - if ums.Len() != 3 { + if ums.len() != 3 { t.Fatal() } - exist = ums.UnsetByIndex(1) - if !exist { + exist, err = ums.UnsetByIndex(1) + if !exist || err != nil { t.Fatal() } - if ums.Index(0).Interface() != nil || ums.Index(1).Interface() != false { + v1, _ := ums.Index(0).Interface() + v2, _ := ums.Index(1).Interface() + if v1 != nil || v2 != false { t.Fatal() } @@ -111,14 +238,15 @@ func TestUnsafeNode(t *testing.T) { if err != nil { t.Fatal(err) } - a := root.UnsafeArray() + a, _ := root.UnsafeArray() if len(a) != loop { t.Fatalf("exp:%v, got:%v", loop, len(a)) } for i := int64(0); i= 0; i-- { + for i := root.GetByPath("statuses", 3).cap(); i >= 0; i-- { root.GetByPath("statuses", 3).Set("id_str"+strconv.Itoa(i), app) } - val = root.GetByPath("statuses", 3, "id_str0").Int64() + val, _ = root.GetByPath("statuses", 3, "id_str0").Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } @@ -416,7 +572,7 @@ func TestNodeSet(t *testing.T) { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses", 3).Set("id_str2", nroot) - val2 := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String() + val2, _ := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } @@ -432,7 +588,8 @@ func TestNodeSetByIndex(t *testing.T) { st.SetByIndex(0, app) st = root.GetByPath("statuses") val := st.Index(0) - if val.Int64() != 111 { + x, _ := val.Int64() + if x != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } @@ -441,7 +598,7 @@ func TestNodeSetByIndex(t *testing.T) { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses").SetByIndex(0, nroot) - val2 := root.GetByPath("statuses", 0, "a", 4, "b").String() + val2, _ := root.GetByPath("statuses", 0, "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } @@ -454,14 +611,14 @@ func TestNodeAdd(t *testing.T) { } app, _ := NewParser("111").Parse() - for i := root.GetByPath("statuses").Cap(); i >= 0; i-- { + for i := root.GetByPath("statuses").cap(); i >= 0; i-- { root.GetByPath("statuses").Add(app) } - val := root.GetByPath("statuses", 4).Int64() + val, _ := root.GetByPath("statuses", 4).Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } - val = root.GetByPath("statuses", root.GetByPath("statuses").Len()-1).Int64() + val, _ = root.GetByPath("statuses", root.GetByPath("statuses").len()-1).Int64() if val != 111 { t.Fatalf("exp: %+v, got: %+v", 111, val) } @@ -471,7 +628,7 @@ func TestNodeAdd(t *testing.T) { t.Fatalf("decode failed: %v", derr.Error()) } root.GetByPath("statuses").Add(nroot) - val2 := root.GetByPath("statuses", root.GetByPath("statuses").Len()-1, "a", 4, "b").String() + val2, _ := root.GetByPath("statuses", root.GetByPath("statuses").len()-1, "a", 4, "b").String() if val2 != "c" { t.Fatalf("exp:%+v, got:%+v", "c", val2) } @@ -497,13 +654,13 @@ func BenchmarkNodeGetByPath(b *testing.B) { if derr != 0 { b.Fatalf("decode failed: %v", derr.Error()) } - _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() + _, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() b.SetParallelism(parallelism) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { - _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() + _, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String() } }) } @@ -553,7 +710,7 @@ func BenchmarkMapGet(b *testing.B) { node.Set("test3", NewNumber("3")) node.Set("test4", NewNumber("4")) node.Set("test5", NewNumber("5")) - m := node.Map() + m, _ := node.Map() b.ResetTimer() for i := 0; i < b.N; i++ { _ = m["text"] @@ -578,7 +735,7 @@ func BenchmarkMapSet(b *testing.B) { if derr != 0 { b.Fatalf("decode failed: %v", derr.Error()) } - node := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0).Map() + node, _ := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0).Map() b.SetParallelism(parallelism) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -611,7 +768,7 @@ func BenchmarkSliceAdd(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { root, _ := NewParser(data).Parse() - node := root.Get("statuses").Array() + node, _ := root.Get("statuses").Array() node = append(node, map[string]interface{}{"test": 1}) } } diff --git a/ast/parser.go b/ast/parser.go index 5511524..b01715a 100644 --- a/ast/parser.go +++ b/ast/parser.go @@ -19,7 +19,7 @@ package ast import ( `fmt` `sync` - `unsafe` + `unsafe` `github.com/bytedance/sonic/decoder` `github.com/bytedance/sonic/internal/native` @@ -30,7 +30,18 @@ import ( const _DEFAULT_NODE_CAP int = 16 -const _ERR_NOT_FOUND types.ParsingError = 33 +const ( + _ERR_NOT_FOUND types.ParsingError = 33 + _ERR_UNSUPPORT_TYPE types.ParsingError = 34 +) + +var ( + nodeNotExist = newError(_ERR_NOT_FOUND, "value not exists") + nodeUnsupportType = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") + + ErrNotExist error = nodeNotExist + ErrUnsupportType error = nodeUnsupportType +) type Parser struct { p int @@ -330,20 +341,24 @@ func (self *Parser) skip() (int, types.ParsingError) { /** Parser Factory **/ // Loads parse all json into interface{} -func Loads(src string) (int, interface{}, types.ParsingError) { +func Loads(src string) (int, interface{}, error) { ps := &Parser{s: src} np, err := ps.Parse() /* check for errors */ if err != 0 { - return 0, nil, err + return 0, nil, ps.ExportError(err) } else { - return ps.Pos(), np.Interface(), 0 + x, err := np.Interface() + if err != nil { + return 0, nil, err + } + return ps.Pos(), x, nil } } // LoadsUseNumber parse all json into interface{}, with numeric nodes casted to json.Number -func LoadsUseNumber(src string) (int, interface{}, types.ParsingError) { +func LoadsUseNumber(src string) (int, interface{}, error) { ps := &Parser{s: src} np, err := ps.Parse() @@ -351,7 +366,11 @@ func LoadsUseNumber(src string) (int, interface{}, types.ParsingError) { if err != 0 { return 0, nil, err } else { - return ps.Pos(), np.InterfaceUseNumber(), 0 + x, err := np.InterfaceUseNumber() + if err != nil { + return 0, nil, err + } + return ps.Pos(), x, nil } } @@ -362,11 +381,19 @@ func NewParser(src string) *Parser { // ExportError converts types.ParsingError to std Error func (self *Parser) ExportError(err types.ParsingError) error { if err == _ERR_NOT_FOUND { - return fmt.Errorf("node not exists") + return ErrNotExist } return fmt.Errorf("%q", decoder.SyntaxError{ - Pos: self.p, - Src: self.s, + Pos : self.p, + Src : self.s, Code: err, }.Description()) +} + +func (self *Parser) syntaxError(err types.ParsingError) *decoder.SyntaxError { + return &decoder.SyntaxError{ + Pos : self.p, + Src : self.s, + Code: err, + } } \ No newline at end of file diff --git a/ast/parser_test.go b/ast/parser_test.go index a94b121..d0d81f7 100644 --- a/ast/parser_test.go +++ b/ast/parser_test.go @@ -28,13 +28,14 @@ import ( func runDecoderTest(t *testing.T, src string, expect interface{}) { vv, err := NewParser(src).Parse() if err != 0 { panic(err) } - assert.Equal(t, expect, vv.Interface()) + x, _ := vv.Interface() + assert.Equal(t, expect, x) } func runDecoderTestUseNumber(t *testing.T, src string, expect interface{}) { vv, err := NewParser(src).Parse() if err != 0 { panic(err) } - vvv := vv.InterfaceUseNumber() + vvv, _ := vv.InterfaceUseNumber() switch vvv.(type) { case json.Number: assert.Equal(t, expect, n2f64(vvv.(json.Number))) @@ -156,12 +157,12 @@ func TestParser_Basic(t *testing.T) { func TestLoads(t *testing.T) { _,i,e := Loads(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`) - if e != 0 { + if e != nil { t.Fatal(e) } assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": 2.4, "f": 1.2e15, "g": float64(1)}, i) _,i,e = LoadsUseNumber(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`) - if e != 0 { + if e != nil { t.Fatal(e) } assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": json.Number("2.4"), "f": json.Number("1.2e15"), "g": json.Number("1")}, i) @@ -284,7 +285,7 @@ func BenchmarkGetOne_Sonic(b *testing.B) { b.SetBytes(int64(len(_TwitterJson))) for i := 0; i < b.N; i++ { ast, _ := NewParser(_TwitterJson).Parse() - node := ast.Get("statuses").Index(2).Get("id").Int64() + node, _ := ast.Get("statuses").Index(2).Get("id").Int64() if node != 249289491129438208 { b.Fail() } diff --git a/ast/search_test.go b/ast/search_test.go index 3d5d950..5ae76ef 100644 --- a/ast/search_test.go +++ b/ast/search_test.go @@ -60,27 +60,32 @@ func TestSearcher_GetByPath(t *testing.T) { s := NewSearcher(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `) node, e := s.GetByPath("test", 0) - if e != nil || node.Bool() != true { + a, _ := node.Bool() + if e != nil || a != true { t.Fatalf("node: %v, err: %v", node, e) } node, e = s.GetByPath("test", 1) - if e != nil || node.Float64() != 0.1 { + b, _ := node.Float64() + if e != nil || b != 0.1 { t.Fatalf("node: %v, err: %v", node, e) } node, e = s.GetByPath("test", 2) - if e != nil || node.String() != "abc" { + c, _ := node.String() + if e != nil || c != "abc" { t.Fatalf("node: %v, err: %v", node, e) } node, e = s.GetByPath("test", 3) - if e != nil || node.Array()[0] != "h" { + arr, _ := node.Array() + if e != nil || arr[0] != "h" { t.Fatalf("node: %v, err: %v", node, e) } node, e = s.GetByPath("test", 4, "a") - if e != nil || node.String() != "bc" { + d, _ := node.String() + if e != nil || d != "bc" { t.Fatalf("node: %v, err: %v", node, e) } } @@ -123,9 +128,9 @@ func TestLoadIndex(t *testing.T) { if err != nil { t.Fatal(err) } - a := node.Index(3).Float64() + a, _ := node.Index(3).Float64() assert.Equal(t, -1.2e-10, a) - m := node.Array() + m, _ := node.Array() assert.Equal(t, m, []interface{}{ float64(0), float64(1), @@ -185,7 +190,8 @@ func BenchmarkSearchOne_Sonic(b *testing.B) { if err != nil { b.Fatal(err) } - if node.Int64() != 249279667666817024 { + x, _ := node.Int64() + if x != 249279667666817024 { b.Fatal(node.Interface()) } } @@ -230,7 +236,8 @@ func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) { if err != nil { b.Fatal(err) } - if node.Int64() != 249279667666817024 { + x, _ := node.Int64() + if x != 249279667666817024 { b.Fatal(node.Interface()) } } diff --git a/search_test.go b/search_test.go index be295b4..6b498c7 100644 --- a/search_test.go +++ b/search_test.go @@ -48,27 +48,32 @@ func TestExampleSearch(t *testing.T) { data := []byte(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `) node, e := Get(data, "test", 0) - if e != nil || node.Bool() != true { + x, _ := node.Bool() + if e != nil || x != true { t.Fatalf("node: %v, err: %v", node, e) } node, e = Get(data, "test", 1) - if e != nil || node.Float64() != 0.1 { + a, _ := node.Float64() + if e != nil || a != 0.1 { t.Fatalf("node: %v, err: %v", node, e) } node, e = Get(data, "test", 2) - if e != nil || node.String() != "abc" { + b, _ := node.String() + if e != nil || b != "abc" { t.Fatalf("node: %v, err: %v", node, e) } node, e = Get(data, "test", 3) - if e != nil || node.Array()[0] != "h" { + arr, _ := node.Array() + if e != nil || arr[0] != "h" { t.Fatalf("node: %v, err: %v", node, e) } node, e = Get(data, "test", 4, "a") - if e != nil || node.String() != "bc" { + c, _ := node.String() + if e != nil || c != "bc" { t.Fatalf("node: %v, err: %v", node, e) } } @@ -148,8 +153,9 @@ func TestRandomValidStrings(t *testing.T) { if err != nil { t.Fatal("search data failed:",err) } - if token.Interface().(string) != su { - t.Fatalf("string mismatch, exp: %v, got: %v", su, token.Interface()) + x, _ := token.Interface() + if x.(string) != su { + t.Fatalf("string mismatch, exp: %v, got: %v", su, x) } } } @@ -166,8 +172,9 @@ func TestEmoji(t *testing.T) { t.Fatal(err) } s, _ := v["utf8"].(string) - if value.String() != s { - t.Fatalf("expected '%v', got '%v'", s, value.String()) + x, _ := value.String() + if x != s { + t.Fatalf("expected '%v', got '%v'", s, x) } } @@ -176,8 +183,10 @@ func testEscapePath(t *testing.T, json, expect string, path ...interface{}) { if e != nil { t.Fatal(e) } - if n.String() != expect { - t.Fatalf("expected '%v', got '%v'", expect, n.Interface()) + x, _ := n.String() + if x != expect { + x, _ := n.Interface() + t.Fatalf("expected '%v', got '%v'", expect, x) } } @@ -213,19 +222,23 @@ func TestParseAny(t *testing.T) { if n == nil { panic("n is nil") } - assertCond(n.Float64() == 100) + x, _ := n.Float64() + assertCond(x == 100) n, e = Parse("true") assertCond(e == nil) if n == nil { panic("n is nil") } - assertCond(n.Bool()) + + a, _ := n.Bool() + assertCond(a) n, e = Parse("false") assertCond(e == nil) if n == nil { panic("n is nil") } - assertCond(n.Bool() == false) + b, _ := n.Bool() + assertCond(b == false) n, e = Parse("yikes") assertCond(e != nil) } @@ -263,7 +276,9 @@ func TestTime(t *testing.T) { if e != nil { t.Fatal(e) } - for _, v := range n.Array() { + + arr, _ := n.Array() + for _, v := range arr { s := v.(string) num = append(num, s) } @@ -303,7 +318,7 @@ func TestUnmarshalMap(t *testing.T) { if err != nil || n == nil { t.Fatal(err) } - m1 := n.Map() + m1, _ := n.Map() var m2 map[string]interface{} if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil { t.Fatal(err) @@ -337,7 +352,8 @@ func GetMany(src2 string, path ...string) (ret []string) { ret = append(ret, "") continue } - ret = append(ret, fmt.Sprintf("%v", n.Interface())) + x, _ := n.Interface() + ret = append(ret, fmt.Sprintf("%v", x)) } return } @@ -361,7 +377,7 @@ func get(str string, path string) *ast.Node { func TestSingleArrayValue(t *testing.T) { var data = []byte(`{"key": "value","key2":[1,2,3,4,"A"]}`) - array := get(string(data), "key2").Array() + array, _ := get(string(data), "key2").Array() if len(array) != 5 { t.Fatalf("got '%v', expected '%v'", len(array), 5) } @@ -392,6 +408,7 @@ var manyJSON = ` { func TestManyBasic(t *testing.T) { testMany := func(shouldFallback bool, expect string, paths ...string) { + println() rs := GetMany( manyJSON, paths..., @@ -413,7 +430,8 @@ func TestManyBasic(t *testing.T) { testMany(true, `[]`, strings.Repeat("a.", 40)+"hello") res := get(manyJSON, strings.Repeat("a.", 48)+"a") assertCond(res != nil) - testMany(true, "["+fmt.Sprint(res.Interface())+"]", strings.Repeat("a.", 48)+"a") + x, _ := res.Interface() + testMany(true, "["+fmt.Sprint(x)+"]", strings.Repeat("a.", 48)+"a") // these should fallback testMany(true, `[Cat Nancy]`, "name_first", "name.first") testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello") @@ -432,7 +450,8 @@ func testManyAny(t *testing.T, json string, paths, expected []string) { which = "Get" result = nil for j := 0; j < len(expected); j++ { - result = append(result, fmt.Sprintf("%v", get(json, paths[j]).Interface())) + x, _ := get(json, paths[j]).Interface() + result = append(result, fmt.Sprintf("%v", x)) } } else if i == 1 { which = "GetMany" @@ -546,7 +565,7 @@ func TestGetMany2(t *testing.T) { } func TestNullArray(t *testing.T) { - n := get(`{"data":null}`, "data").Interface() + n, _ := get(`{"data":null}`, "data").Interface() if n != nil { t.Fatalf("expected '%v', got '%v'", nil, n) } @@ -558,7 +577,8 @@ func TestNullArray(t *testing.T) { if reflect.DeepEqual(n, &ast.Node{}) { t.Fatalf("expected '%v', got '%v'", nil, n) } - n = len(get(`{"data":[null]}`, "data").Array()) + arr, _ := get(`{"data":[null]}`, "data").Array() + n = len(arr) if n != 1 { t.Fatalf("expected '%v', got '%v'", 1, n) } @@ -613,7 +633,11 @@ func TestGetNotExist(t *testing.T) { t.Fatal() } v2 := ret.GetByPath("m1", "m2") - if !v2.Exists() || !v2.IsRaw() || v2.Int64() != 3 { + if !v2.Exists() || !v2.IsRaw() { t.Fatal(ret.Type()) } + x, _ := v2.Int64() + if x != 3 { + t.Fatal(x) + } } \ No newline at end of file