diff --git a/dev/ast/error.go b/dev/ast/error.go index 4b4d4752a..c0b3564f2 100644 --- a/dev/ast/error.go +++ b/dev/ast/error.go @@ -11,6 +11,8 @@ var ( // ErrNotExist means both key and value doesn't exist ErrNotExist error = newError(errors.New("not exist")) + emptyNode = newError(errors.New("not exist")) + // ErrUnsupportType means API on the node is unsupported ErrUnsupportType error = newError(errors.New("not exist")) ) diff --git a/dev/ast/native.go b/dev/ast/native.go index 7ead4140d..2e537541c 100644 --- a/dev/ast/native.go +++ b/dev/ast/native.go @@ -15,45 +15,85 @@ type Node struct { } -// func (n *node) SetAt(i int32, val unsafe.Pointer) { -// x := len(n.mut) -// n.tape[i] = token(_K_MUT|x) -// n.mut = append(n.mut, val) -// } - - -// func (n *Node) objAt(i int) (Pair, error) { -// key, err := strForToken(n.Kids[i * 2], n.JSON) -// if err != nil { -// return Pair{}, err -// } - -// node := n.Kids[i * 2 + 1] -// val := node.Raw(n.JSON) -// return Pair{key, newRawNodeUnsafe(val, node.Flag.IsEsc())}, nil -// } - -// func (n *Node) arrAt(i int) Node { -// node := n.Kids[i * 2 + 1] -// val := node.Raw(n.JSON) -// return newRawNodeUnsafe(val, node.Flag.IsEsc()) -// } - - -// func strForToken(t types.Token, json string) (string, error) { -// raw := t.Raw(json) -// if !t.Flag.IsEsc(){ -// // remove the quotes -// return raw[1: len(raw) - 1], nil -// } +func (n *Node) arrSet(i int, typ types.Type, val unsafe.Pointer) error { + t := n.arrAt(i) + if t == nil { + return ErrNotExist + } + l := len(n.mut) + *t = types.Token{ + Kind: typ, + Flag: _F_MUT, + Off: uint32(l), + } + n.mut = append(n.mut, val) + n.Flag |= _F_MUT + return nil +} + +func (n *Node) objSet(key string, typ types.Type, val unsafe.Pointer) error { + t, err := n.objAt(key) + if err != nil { + return err + } + l := len(n.mut) + *t = types.Token{ + Kind: typ, + Flag: _F_MUT, + Off: uint32(l), + } + n.mut = append(n.mut, val) + n.Flag |= _F_MUT + return nil +} + +func (n *Node) objAt(key string) (*types.Token, error) { + for i := 0; i= len(n.Kids) { + return nil + } + return &n.Kids[i] +} + +func strForToken(t types.Token, json string) (string, error) { + raw := t.Raw(json) + if !t.Flag.IsEsc(){ + // remove the quotes + return raw[1: len(raw) - 1], nil + } -// s, err := unquote(raw) -// if err != 0 { -// return "", makeSyntaxError(json, int(t.Off), err.Message()) -// } else { -// return s, nil -// } -// } + s, err := unquote(raw) + if err != 0 { + return "", makeSyntaxError(json, int(t.Off), err.Message()) + } else { + return s, nil + } +} func makeSyntaxError(json string, p int, msg string) decoder.SyntaxError { return decoder.SyntaxError{ @@ -63,8 +103,6 @@ func makeSyntaxError(json string, p int, msg string) decoder.SyntaxError { } } - - // TODO: use flags to make, if is primitives func parseLazy(json string, path *[]interface{}) (Node, error) { // TODO: got real PC of biz caller @@ -130,11 +168,9 @@ func parseLazy(json string, path *[]interface{}) (Node, error) { // Note: not validate the input json, only used internal func newRawNodeUnsafe(json string, hasEsc bool) Node { - ret := Node{ - Node: types.NewNode(json, hasEsc), + n := types.NewNode(json, hasEsc) + if !n.Kind.IsComplex() { + return Node{n, nil} } - // if (ret.Kind == types.T_ARRAY || ret.Kind == types.T_OBJECT) && isRaw { - // ret.Flag |= _F_RAW - // } - return ret + return NewRaw(json) } diff --git a/dev/ast/node.go b/dev/ast/node.go index bd5bb1786..b3abe7e6b 100644 --- a/dev/ast/node.go +++ b/dev/ast/node.go @@ -76,14 +76,11 @@ var ( // NewRaw creates a node of raw json. // If the input json is invalid, NewRaw returns a error Node. func NewRaw(json string) Node { - p := NewParser(json) - start, err := p.skip() - if err != nil { - return newError(err) - } - - // TODO: FIXME, should has escaped flags - return newRawNodeUnsafe(json[start: p.pos], true) + n, e := NewParser(json).Parse() + if e != nil { + return newError(e) + } + return n } // NewAny creates a node of type V_ANY if any's type isn't Node or *Node @@ -151,7 +148,57 @@ func NewBytes(src []byte) Node { return NewString(out) } +func (self *Node) should(t types.Type) error { + if err := self.Error(); err != "" { + return self + } + if self.Kind != t { + return ErrUnsupportType + } + return nil +} + +func (n *Node) get(key string) (Node) { + t, err := n.objAt(key) + if err != nil { + return newError(err) + } + return n.sub(*t) +} + +func (n *Node) index(key int) (Node) { + t := n.arrAt(key) + if t == nil { + return emptyNode + } + return n.sub(*t) +} + + +func (self *Node) GetByPath(path ...interface{}) Node { + if l := len(path); l == 0 { + return *self + } else if l == 1 { + switch p := path[0].(type) { + case int: + return self.index(p) + case string: + return self.get(p) + default: + panic("path must be either int or string") + } + } else { + n, err := NewParser(self.JSON).getByPath(path...) + if err != nil { + return newError(err) + } + return n + } +} + /***************** Cast APIs ***********************/ + + /***************** Set APIs ***********************/ \ No newline at end of file diff --git a/dev/ast/node_test.go b/dev/ast/node_test.go index 27cd8556b..320735a8a 100644 --- a/dev/ast/node_test.go +++ b/dev/ast/node_test.go @@ -25,6 +25,9 @@ func getSample(width int, depth int) string { } func TestNodeParse(t *testing.T) { + n1, err := NewParser(`[1,"1",true]`).Parse() + require.NoError(t, err) + spew.Dump(n1.Kids) src := getSample(100, 0) n, err := NewParser(src).Parse() require.NoError(t, err) diff --git a/internal/native/types/types.go b/internal/native/types/types.go index b46699b5b..11dd39658 100644 --- a/internal/native/types/types.go +++ b/internal/native/types/types.go @@ -188,6 +188,9 @@ type Token struct { Len uint32 } +func (t Type) IsComplex() bool { + return t == T_ARRAY || t == T_OBJECT +} type Node struct { Kind Type