Skip to content

Commit

Permalink
feat:(ast) Visitor support skip object and array
Browse files Browse the repository at this point in the history
  • Loading branch information
AsterDY committed May 17, 2024
1 parent 1ce4a1e commit 755afe9
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 0 deletions.
4 changes: 4 additions & 0 deletions ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ func (self *Parser) lspace(sp int) int {
return sp
}

func (self *Parser) backward() {
for ; self.p >= 0 && isSpace(self.s[self.p]); self.p-=1 {}
}

func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) {
sp := self.p
ns := len(self.s)
Expand Down
30 changes: 30 additions & 0 deletions ast/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package ast

import (
`encoding/json`
`errors`

`github.com/bytedance/sonic/internal/native/types`
)
Expand Down Expand Up @@ -191,6 +192,19 @@ func (self *traverser) decodeArray() error {

/* allocate array space and parse every element */
if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
if err == VisitOPSkip {
// NOTICE: for user needs to skip entiry object
self.parser.p -= 1
self.parser.backward()
if self.parser.s[self.parser.p] != '[' {
return types.ERR_INVALID_CHAR
}
if _, e := self.parser.skipFast(); e != 0 {
return e
}
println("skip to ", self.parser.p)
return self.visitor.OnArrayEnd()
}
return err
}
for {
Expand Down Expand Up @@ -240,6 +254,18 @@ func (self *traverser) decodeObject() error {

/* allocate object space and decode each pair */
if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
if err == VisitOPSkip {
// NOTICE: for user needs to skip entiry object
self.parser.p -= 1
self.parser.backward()
if self.parser.s[self.parser.p] != '{' {
return types.ERR_INVALID_CHAR
}
if _, e := self.parser.skipFast(); e != 0 {
return e
}
return self.visitor.OnObjectEnd()
}
return err
}
for {
Expand Down Expand Up @@ -313,3 +339,7 @@ func (self *traverser) decodeString(iv int64, ep int) error {
}
return self.visitor.OnString(out)
}

// If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`,
// the transverer will skip entiry object or array
var VisitOPSkip = errors.New("")

Check failure on line 345 in ast/visitor.go

View workflow job for this annotation

GitHub Actions / build (1.20.x)

syntax error: unexpected var after top level declaration
109 changes: 109 additions & 0 deletions ast/visitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,115 @@ func TestVisitor_UserNodeDiff(t *testing.T) {
})
}

type skipVisitor struct {
sp int
Skip int
inSkip bool
CountSkip int
}

func (self *skipVisitor) OnNull() error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnFloat64(v float64, n json.Number) error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnInt64(v int64, n json.Number) error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnBool(v bool) error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnString(v string) error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnObjectBegin(capacity int) error {
println("self.sp", self.sp)
if self.sp == self.Skip {
self.inSkip = true
self.CountSkip++
println("op skip")
self.sp++
return VisitOPSkip
}
self.sp++
return nil
}

func (self *skipVisitor) OnObjectKey(key string) error {
if self.sp == self.Skip+1 && self.inSkip {
panic("unexpected key")
}
return nil
}

func (self *skipVisitor) OnObjectEnd() error {
if self.sp == self.Skip + 1 {
if !self.inSkip {
panic("not in skip")
}
self.inSkip = false
println("finish op skip")
}
self.sp--
return nil
}

func (self *skipVisitor) OnArrayBegin(capacity int) error {
println("arr self.sp", self.sp)
if self.sp == self.Skip {
self.inSkip = true
self.CountSkip++
println("arr op skip")
self.sp++
return VisitOPSkip
}
self.sp++
return nil
}

func (self *skipVisitor) OnArrayEnd() error {
println("arr self.sp", self.sp)
if self.sp == self.Skip + 1 {
if !self.inSkip {
panic("arr not in skip")
}
self.inSkip = false
println("arr finish op skip")
}
self.sp--
return nil
}

func TestVisitor_OpSkip(t *testing.T) {
var suite skipVisitor
suite.Skip = 1
Preorder(`{"a": [ null ] , "b":1, "c": { "1" : 1 } }`, &suite, nil)
if suite.CountSkip != 2 {
t.Fatal(suite.CountSkip)
}
}

func BenchmarkVisitor_UserNode(b *testing.B) {
const str = _TwitterJson
b.Run("AST", func(b *testing.B) {
Expand Down

0 comments on commit 755afe9

Please sign in to comment.