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 /* allocate array space and parse every element */
179 if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil {
180 if err == VisitOPSkip {
181 // NOTICE: for user needs to skip entiry object
182 self.parser.p -= 1
183 if _, e := self.parser.skipFast(); e != 0 {
184 return e
185 }
186 return self.visitor.OnArrayEnd()
187 }
188 return err
189 }
190 191 /* check for EOF */
192 self.parser.p = self.parser.lspace(sp)
193 if self.parser.p >= ns {
194 return types.ERR_EOF
195 }
196 197 /* check for empty array */
198 if self.parser.s[self.parser.p] == ']' {
199 self.parser.p++
200 return self.visitor.OnArrayEnd()
201 }
202 203 for {
204 /* decode the value */
205 if err := self.decodeValue(); err != nil {
206 return err
207 }
208 self.parser.p = self.parser.lspace(self.parser.p)
209 210 /* check for EOF */
211 if self.parser.p >= ns {
212 return types.ERR_EOF
213 }
214 215 /* check for the next character */
216 switch self.parser.s[self.parser.p] {
217 case ',':
218 self.parser.p++
219 case ']':
220 self.parser.p++
221 return self.visitor.OnArrayEnd()
222 default:
223 return types.ERR_INVALID_CHAR
224 }
225 }
226 }
227 228 // NOTE: keep in sync with (*Parser).decodeObject method.
229 func (self *traverser) decodeObject() error {
230 sp := self.parser.p
231 ns := len(self.parser.s)
232 233 /* allocate object space and decode each pair */
234 if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil {
235 if err == VisitOPSkip {
236 // NOTICE: for user needs to skip entiry object
237 self.parser.p -= 1
238 if _, e := self.parser.skipFast(); e != 0 {
239 return e
240 }
241 return self.visitor.OnObjectEnd()
242 }
243 return err
244 }
245 246 /* check for EOF */
247 self.parser.p = self.parser.lspace(sp)
248 if self.parser.p >= ns {
249 return types.ERR_EOF
250 }
251 252 /* check for empty object */
253 if self.parser.s[self.parser.p] == '}' {
254 self.parser.p++
255 return self.visitor.OnObjectEnd()
256 }
257 258 for {
259 var njs types.JsonState
260 var err types.ParsingError
261 262 /* decode the key */
263 if njs = self.parser.decodeValue(); njs.Vt != types.V_STRING {
264 return types.ERR_INVALID_CHAR
265 }
266 267 /* extract the key */
268 idx := self.parser.p - 1
269 key := self.parser.s[njs.Iv:idx]
270 271 /* check for escape sequence */
272 if njs.Ep != -1 {
273 if key, err = unquote(key); err != 0 {
274 return err
275 }
276 }
277 278 if err := self.visitor.OnObjectKey(key); err != nil {
279 return err
280 }
281 282 /* expect a ':' delimiter */
283 if err = self.parser.delim(); err != 0 {
284 return err
285 }
286 287 /* decode the value */
288 if err := self.decodeValue(); err != nil {
289 return err
290 }
291 292 self.parser.p = self.parser.lspace(self.parser.p)
293 294 /* check for EOF */
295 if self.parser.p >= ns {
296 return types.ERR_EOF
297 }
298 299 /* check for the next character */
300 switch self.parser.s[self.parser.p] {
301 case ',':
302 self.parser.p++
303 case '}':
304 self.parser.p++
305 return self.visitor.OnObjectEnd()
306 default:
307 return types.ERR_INVALID_CHAR
308 }
309 }
310 }
311 312 // NOTE: keep in sync with (*Parser).decodeString method.
313 func (self *traverser) decodeString(iv int64, ep int) error {
314 p := self.parser.p - 1
315 s := self.parser.s[iv:p]
316 317 /* fast path: no escape sequence */
318 if ep == -1 {
319 return self.visitor.OnString(s)
320 }
321 322 /* unquote the string */
323 out, err := unquote(s)
324 if err != 0 {
325 return err
326 }
327 return self.visitor.OnString(out)
328 }
329 330 // If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`,
331 // the transverer will skip entiry object or array
332 var VisitOPSkip = errors.New("")
333