diff --git a/ast/node.go b/ast/node.go index 060fffd..01aba5d 100644 --- a/ast/node.go +++ b/ast/node.go @@ -514,10 +514,9 @@ func (self *Node) loadAllIndex() { parser, stack := self.getParserAndArrayStack() old := parser.noLazy parser.noLazy = true - start := parser.p *self, err = parser.decodeArray(stack.v) if err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.noLazy = old } @@ -532,10 +531,9 @@ func (self *Node) skipAllIndex() { parser.skipValue = true oldl := parser.noLazy parser.noLazy = true - start := parser.p *self, err = parser.decodeArray(stack.v) if err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.skipValue = olds parser.noLazy = oldl @@ -549,10 +547,9 @@ func (self *Node) loadAllKey() { parser, stack := self.getParserAndObjectStack() old := parser.noLazy parser.noLazy = true - start := parser.p *self, err = parser.decodeObject(stack.v) if err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.noLazy = old } @@ -567,10 +564,9 @@ func (self *Node) skipAllKey() { parser.skipValue = true oldl := parser.noLazy parser.noLazy = true - start := parser.p *self, err = parser.decodeObject(stack.v) if err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.skipValue = olds parser.noLazy = oldl @@ -604,11 +600,10 @@ func (self *Node) loadNextNode() *Node { parser := &stack.parser sp := parser.p ns := len(parser.s) - start := sp /* check for EOF */ if parser.p = parser.lspace(sp); parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF, start)) + panic(parser.ExportError(types.ERR_EOF)) } /* check for empty array */ @@ -624,9 +619,8 @@ func (self *Node) loadNextNode() *Node { /* decode the value */ old := parser.noLazy parser.noLazy = true - start = parser.p if val, err = parser.Parse(); err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.noLazy = old @@ -636,7 +630,7 @@ func (self *Node) loadNextNode() *Node { /* check for EOF */ if parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF, start)) + panic(parser.ExportError(types.ERR_EOF)) } /* check for the next character */ @@ -650,7 +644,7 @@ func (self *Node) loadNextNode() *Node { self.setArray(ret) return &ret[len(ret)-1] default: - panic(parser.ExportError(types.ERR_INVALID_CHAR, start)) + panic(parser.ExportError(types.ERR_INVALID_CHAR)) } } @@ -682,11 +676,10 @@ func (self *Node) loadNextPair() (*Pair) { parser := &stack.parser sp := parser.p ns := len(parser.s) - start := sp /* check for EOF */ if parser.p = parser.lspace(sp); parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF, start)) + panic(parser.ExportError(types.ERR_EOF)) } /* check for empty object */ @@ -702,9 +695,8 @@ func (self *Node) loadNextPair() (*Pair) { var err types.ParsingError /* decode the key */ - start = parser.p if njs = parser.decodeValue(); njs.Vt != types.V_STRING { - panic(parser.ExportError(types.ERR_INVALID_CHAR, start)) + panic(parser.ExportError(types.ERR_INVALID_CHAR)) } /* extract the key */ @@ -714,22 +706,20 @@ func (self *Node) loadNextPair() (*Pair) { /* check for escape sequence */ if njs.Ep != -1 { if key, err = unquote.String(key); err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } } /* expect a ':' delimiter */ - start = parser.p if err = parser.delim(); err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } /* decode the value */ old := parser.noLazy parser.noLazy = true - start = parser.p if val, err = parser.Parse(); err != 0 { - panic(parser.ExportError(err, start)) + panic(parser.ExportError(err)) } parser.noLazy = old @@ -739,7 +729,7 @@ func (self *Node) loadNextPair() (*Pair) { /* check for EOF */ if parser.p >= ns { - panic(parser.ExportError(types.ERR_EOF, start)) + panic(parser.ExportError(types.ERR_EOF)) } /* check for the next character */ @@ -753,7 +743,7 @@ func (self *Node) loadNextPair() (*Pair) { self.setObject(ret) return &ret[len(ret)-1] default: - panic(parser.ExportError(types.ERR_INVALID_CHAR, start)) + panic(parser.ExportError(types.ERR_INVALID_CHAR)) } } @@ -1015,7 +1005,7 @@ func (self *Node) parseRaw() Node { parser := NewParser(raw) n, e := parser.Parse() if e != 0 { - panic(parser.ExportError(e, 0)) + panic(parser.ExportError(e)) } return n } diff --git a/ast/parser.go b/ast/parser.go index f35c2bc..e9a5164 100644 --- a/ast/parser.go +++ b/ast/parser.go @@ -17,14 +17,15 @@ package ast import ( - `fmt` + `fmt` `sync` `unsafe` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/bytedance/sonic/unquote` + `github.com/bytedance/sonic/decoder` + `github.com/bytedance/sonic/internal/native` + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` + `github.com/bytedance/sonic/unquote` ) const _DEFAULT_NODE_CAP int = 16 @@ -359,20 +360,27 @@ func NewParser(src string) *Parser { } // ExportError converts types.ParsingError to std Error -func (self *Parser) ExportError(err types.ParsingError, start int) error { +func (self *Parser) ExportError(err types.ParsingError) error { if err == _ERR_NOT_FOUND { return fmt.Errorf("node not exists") } - return fmt.Errorf("%v at %d, near '%s'", err, self.p, self.printNear(start)) + return fmt.Errorf("%q", decoder.SyntaxError{ + Pos: self.p, + Src: self.s, + Code: err, + }.Description()) } -func (self *Parser) printNear(start int) string { - if start < 0 { - start = 0 - } - end := self.p + 10 - if end > len(self.s) { - end = len(self.s) - } - return self.s[start:end] -} \ No newline at end of file +// func (self *Parser) printNear(start int) string { +// end := self.p + 10 +// if end > len(self.s) { +// end = len(self.s) +// } +// if start > end { +// start = end - 1 +// } +// if start < 0 { +// start = 0 +// } +// return self.s[start:end] +// } \ No newline at end of file diff --git a/ast/search.go b/ast/search.go index b01c549..f7d372f 100644 --- a/ast/search.go +++ b/ast/search.go @@ -43,32 +43,30 @@ func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { for _, p := range path { switch p.(type) { case int: - start := self.parser.p if err = self.parser.searchIndex(p.(int)); err != 0 { - return Node{}, self.parser.ExportError(err, start) + return Node{}, self.parser.ExportError(err) } case string: - start := self.parser.p if err = self.parser.searchKey(p.(string)); err != 0 { - return Node{}, self.parser.ExportError(err, start) + return Node{}, self.parser.ExportError(err) } default: panic("path must be either int or string") } } - var start int + var start = self.parser.p if start, err = self.parser.skip(); err != 0 { - return Node{}, self.parser.ExportError(err, start) + return Node{}, self.parser.ExportError(err) } ns := len(self.parser.s) - if self.parser.p > ns || start >= ns { + if self.parser.p > ns || start >= ns || start>=self.parser.p { return Node{}, fmt.Errorf("skip %d char out of json boundary", start) } t := switchRawType(self.parser.s[start]) if t == _V_NONE { - return Node{}, self.parser.ExportError(err, start) + return Node{}, self.parser.ExportError(err) } return newRawNode(self.parser.s[start:self.parser.p], t), nil diff --git a/ast/search_test.go b/ast/search_test.go index 5ff669a..3d5d950 100644 --- a/ast/search_test.go +++ b/ast/search_test.go @@ -24,6 +24,38 @@ import ( `github.com/tidwall/gjson` ) +func TestExportError(t *testing.T) { + data := `{"a":]` + p := NewSearcher(data) + _, err := p.GetByPath("a") + if err == nil { + t.Fatal() + } + if err.Error() != `"Syntax error at index 6: invalid char\n\n\t{\"a\":]\n\t......^\n"` { + t.Fatal(err) + } + + data = `:"b"]` + p = NewSearcher(data) + _, err = p.GetByPath("a") + if err == nil { + t.Fatal() + } + if err.Error() != `"Syntax error at index 0: invalid char\n\n\t:\"b\"]\n\t^....\n"` { + t.Fatal(err) + } + + data = `{:"b"]` + p = NewSearcher(data) + _, err = p.GetByPath("a") + if err == nil { + t.Fatal() + } + if err.Error() != `"Syntax error at index 1: invalid char\n\n\t{:\"b\"]\n\t.^....\n"` { + t.Fatal(err) + } +} + func TestSearcher_GetByPath(t *testing.T) { s := NewSearcher(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `) diff --git a/decoder/generic_test.go b/decoder/generic_test.go index 19dbab0..551d3a4 100644 --- a/decoder/generic_test.go +++ b/decoder/generic_test.go @@ -21,7 +21,6 @@ import ( `reflect` `testing` - `github.com/bytedance/sonic/ast` `github.com/bytedance/sonic/internal/native/types` `github.com/davecgh/go-spew/spew` `github.com/stretchr/testify/assert` @@ -55,15 +54,6 @@ func TestGeneric_DecodeInterface(t *testing.T) { fmt.Printf("type: %s\n", reflect.TypeOf(v)) } -func BenchmarkGeneric_DecodeAST(b *testing.B) { - _, _, _ = ast.Loads(TwitterJson) - b.SetBytes(int64(len(TwitterJson))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _, _ = ast.Loads(TwitterJson) - } -} - func BenchmarkGeneric_DecodeGeneric(b *testing.B) { t := newStack() _, _, _ = decodeValue(t, TwitterJson, 0, 0) @@ -75,17 +65,6 @@ func BenchmarkGeneric_DecodeGeneric(b *testing.B) { freeStack(t) } -func BenchmarkGeneric_Parallel_DecodeAST(b *testing.B) { - _, _, _ = ast.Loads(TwitterJson) - b.SetBytes(int64(len(TwitterJson))) - b.ResetTimer() - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - _, _, _ = ast.Loads(TwitterJson) - } - }) -} - func BenchmarkGeneric_Parallel_DecodeGeneric(b *testing.B) { _, _, _ = decodeGeneric(TwitterJson, 0, 0) b.SetBytes(int64(len(TwitterJson)))