github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/ast/visitor.go (about)

     1  /*
     2   * Copyright 2021 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package ast
    18  
    19  import (
    20      `encoding/json`
    21      `errors`
    22  
    23      `github.com/bytedance/sonic/internal/native/types`
    24  )
    25  
    26  // Visitor handles the callbacks during preorder traversal of a JSON AST.
    27  //
    28  // According to the JSON RFC8259, a JSON AST can be defined by
    29  // the following rules without separator / whitespace tokens.
    30  //
    31  //  JSON-AST  = value
    32  //  value     = false / null / true / object / array / number / string
    33  //  object    = begin-object [ member *( member ) ] end-object
    34  //  member    = string value
    35  //  array     = begin-array [ value *( value ) ] end-array
    36  //
    37  type Visitor interface {
    38  
    39      // OnNull handles a JSON null value.
    40      OnNull() error
    41  
    42      // OnBool handles a JSON true / false value.
    43      OnBool(v bool) error
    44  
    45      // OnString handles a JSON string value.
    46      OnString(v string) error
    47  
    48      // OnInt64 handles a JSON number value with int64 type.
    49      OnInt64(v int64, n json.Number) error
    50  
    51      // OnFloat64 handles a JSON number value with float64 type.
    52      OnFloat64(v float64, n json.Number) error
    53  
    54      // OnObjectBegin handles the beginning of a JSON object value with a
    55      // suggested capacity that can be used to make your custom object container.
    56      //
    57      // After this point the visitor will receive a sequence of callbacks like
    58      // [string, value, string, value, ......, ObjectEnd].
    59      //
    60      // Note:
    61      // 1. This is a recursive definition which means the value can
    62      // also be a JSON object / array described by a sequence of callbacks.
    63      // 2. The suggested capacity will be 0 if current object is empty.
    64      // 3. Currently sonic use a fixed capacity for non-empty object (keep in
    65      // sync with ast.Node) which might not be very suitable. This may be
    66      // improved in future version.
    67      OnObjectBegin(capacity int) error
    68  
    69      // OnObjectKey handles a JSON object key string in member.
    70      OnObjectKey(key string) error
    71  
    72      // OnObjectEnd handles the ending of a JSON object value.
    73      OnObjectEnd() error
    74  
    75      // OnArrayBegin handles the beginning of a JSON array value with a
    76      // suggested capacity that can be used to make your custom array container.
    77      //
    78      // After this point the visitor will receive a sequence of callbacks like
    79      // [value, value, value, ......, ArrayEnd].
    80      //
    81      // Note:
    82      // 1. This is a recursive definition which means the value can
    83      // also be a JSON object / array described by a sequence of callbacks.
    84      // 2. The suggested capacity will be 0 if current array is empty.
    85      // 3. Currently sonic use a fixed capacity for non-empty array (keep in
    86      // sync with ast.Node) which might not be very suitable. This may be
    87      // improved in future version.
    88      OnArrayBegin(capacity int) error
    89  
    90      // OnArrayEnd handles the ending of a JSON array value.
    91      OnArrayEnd() error
    92  }
    93  
    94  // VisitorOptions contains all Visitor's options. The default value is an
    95  // empty VisitorOptions{}.
    96  type VisitorOptions struct {
    97      // OnlyNumber indicates parser to directly return number value without
    98      // conversion, then the first argument of OnInt64 / OnFloat64 will always
    99      // be zero.
   100      OnlyNumber bool
   101  }
   102  
   103  var defaultVisitorOptions = &VisitorOptions{}
   104  
   105  // Preorder decodes the whole JSON string and callbacks each AST node to visitor
   106  // during preorder traversal. Any visitor method with an error returned will
   107  // break the traversal and the given error will be directly returned. The opts
   108  // argument can be reused after every call.
   109  func Preorder(str string, visitor Visitor, opts *VisitorOptions) error {
   110      if opts == nil {
   111          opts = defaultVisitorOptions
   112      }
   113      // process VisitorOptions first to guarantee that all options will be
   114      // constant during decoding and make options more readable.
   115      var (
   116          optDecodeNumber = !opts.OnlyNumber
   117      )
   118  
   119      tv := &traverser{
   120          parser: Parser{
   121              s:         str,
   122              noLazy:    true,
   123              skipValue: false,
   124          },
   125          visitor: visitor,
   126      }
   127  
   128      if optDecodeNumber {
   129          tv.parser.decodeNumber(true)
   130      }
   131  
   132      err := tv.decodeValue()
   133  
   134      if optDecodeNumber {
   135          tv.parser.decodeNumber(false)
   136      }
   137      return err
   138  }
   139  
   140  type traverser struct {
   141      parser  Parser
   142      visitor Visitor
   143  }
   144  
   145  // NOTE: keep in sync with (*Parser).Parse method.
   146  func (self *traverser) decodeValue() error {
   147      switch val := self.parser.decodeValue(); val.Vt {
   148      case types.V_EOF:
   149          return types.ERR_EOF
   150      case types.V_NULL:
   151          return self.visitor.OnNull()
   152      case types.V_TRUE:
   153          return self.visitor.OnBool(true)
   154      case types.V_FALSE:
   155          return self.visitor.OnBool(false)
   156      case types.V_STRING:
   157          return self.decodeString(val.Iv, val.Ep)
   158      case types.V_DOUBLE:
   159          return self.visitor.OnFloat64(val.Dv,
   160              json.Number(self.parser.s[val.Ep:self.parser.p]))
   161      case types.V_INTEGER:
   162          return self.visitor.OnInt64(val.Iv,
   163              json.Number(self.parser.s[val.Ep:self.parser.p]))
   164      case types.V_ARRAY:
   165          return self.decodeArray()
   166      case types.V_OBJECT:
   167          return self.decodeObject()
   168      default:
   169          return types.ParsingError(-val.Vt)
   170      }
   171  }
   172  
   173  // NOTE: keep in sync with (*Parser).decodeArray method.
   174  func (self *traverser) decodeArray() error {
   175      sp := self.parser.p
   176      ns := len(self.parser.s)
   177  
   178      /* check for EOF */
   179      self.parser.p = self.parser.lspace(sp)
   180      if self.parser.p >= ns {
   181          return types.ERR_EOF
   182      }
   183  
   184      /* check for empty array */
   185      if self.parser.s[self.parser.p] == ']' {
   186          self.parser.p++
   187          if err := self.visitor.OnArrayBegin(0); err != nil {
   188              return err
   189          }
   190          return self.visitor.OnArrayEnd()
   191      }
   192  
   193      /* allocate array space and parse every element */
   194      if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
   195          if err == VisitOPSkip {
   196              // NOTICE: for user needs to skip entiry object
   197              self.parser.p -= 1
   198              self.parser.backward()
   199              if self.parser.s[self.parser.p] != '[' {
   200                  return types.ERR_INVALID_CHAR
   201              }
   202              if _, e := self.parser.skipFast(); e != 0 {
   203                  return e
   204              }
   205              println("skip to ", self.parser.p)
   206              return self.visitor.OnArrayEnd()
   207          }
   208          return err
   209      }
   210      for {
   211          /* decode the value */
   212          if err := self.decodeValue(); err != nil {
   213              return err
   214          }
   215          self.parser.p = self.parser.lspace(self.parser.p)
   216  
   217          /* check for EOF */
   218          if self.parser.p >= ns {
   219              return types.ERR_EOF
   220          }
   221  
   222          /* check for the next character */
   223          switch self.parser.s[self.parser.p] {
   224          case ',':
   225              self.parser.p++
   226          case ']':
   227              self.parser.p++
   228              return self.visitor.OnArrayEnd()
   229          default:
   230              return types.ERR_INVALID_CHAR
   231          }
   232      }
   233  }
   234  
   235  // NOTE: keep in sync with (*Parser).decodeObject method.
   236  func (self *traverser) decodeObject() error {
   237      sp := self.parser.p
   238      ns := len(self.parser.s)
   239  
   240      /* check for EOF */
   241      self.parser.p = self.parser.lspace(sp)
   242      if self.parser.p >= ns {
   243          return types.ERR_EOF
   244      }
   245  
   246      /* check for empty object */
   247      if self.parser.s[self.parser.p] == '}' {
   248          self.parser.p++
   249          if err := self.visitor.OnObjectBegin(0); err != nil {
   250              return err
   251          }
   252          return self.visitor.OnObjectEnd()
   253      }
   254  
   255      /* allocate object space and decode each pair */
   256      if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
   257          if err == VisitOPSkip {
   258              // NOTICE: for user needs to skip entiry object
   259              self.parser.p -= 1
   260              self.parser.backward()
   261              if self.parser.s[self.parser.p] != '{' {
   262                  return types.ERR_INVALID_CHAR
   263              }
   264              if _, e := self.parser.skipFast(); e != 0 {
   265                  return e
   266              }
   267              return self.visitor.OnObjectEnd()
   268          }
   269          return err
   270      }
   271      for {
   272          var njs types.JsonState
   273          var err types.ParsingError
   274  
   275          /* decode the key */
   276          if njs = self.parser.decodeValue(); njs.Vt != types.V_STRING {
   277              return types.ERR_INVALID_CHAR
   278          }
   279  
   280          /* extract the key */
   281          idx := self.parser.p - 1
   282          key := self.parser.s[njs.Iv:idx]
   283  
   284          /* check for escape sequence */
   285          if njs.Ep != -1 {
   286              if key, err = unquote(key); err != 0 {
   287                  return err
   288              }
   289          }
   290  
   291          if err := self.visitor.OnObjectKey(key); err != nil {
   292              return err
   293          }
   294  
   295          /* expect a ':' delimiter */
   296          if err = self.parser.delim(); err != 0 {
   297              return err
   298          }
   299  
   300          /* decode the value */
   301          if err := self.decodeValue(); err != nil {
   302              return err
   303          }
   304  
   305          self.parser.p = self.parser.lspace(self.parser.p)
   306  
   307          /* check for EOF */
   308          if self.parser.p >= ns {
   309              return types.ERR_EOF
   310          }
   311  
   312          /* check for the next character */
   313          switch self.parser.s[self.parser.p] {
   314          case ',':
   315              self.parser.p++
   316          case '}':
   317              self.parser.p++
   318              return self.visitor.OnObjectEnd()
   319          default:
   320              return types.ERR_INVALID_CHAR
   321          }
   322      }
   323  }
   324  
   325  // NOTE: keep in sync with (*Parser).decodeString method.
   326  func (self *traverser) decodeString(iv int64, ep int) error {
   327      p := self.parser.p - 1
   328      s := self.parser.s[iv:p]
   329  
   330      /* fast path: no escape sequence */
   331      if ep == -1 {
   332          return self.visitor.OnString(s)
   333      }
   334  
   335      /* unquote the string */
   336      out, err := unquote(s)
   337      if err != 0 {
   338          return err
   339      }
   340      return self.visitor.OnString(out)
   341  }
   342  
   343  // If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`, 
   344  // the transverer will skip entiry object or array
   345  var VisitOPSkip = errors.New("")