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