...

Source file src/github.com/bytedance/sonic/ast/visitor.go

Documentation: github.com/bytedance/sonic/ast

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

View as plain text