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("")