v
Зеркало из https://github.com/vlang/v
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module json2
5
6import time
7
8fn format_message(msg string, line int, column int) string {
9return '[x.json2] ${msg} (${line}:${column})'
10}
11
12pub struct DecodeError {
13line int
14column int
15message string
16}
17
18// code returns the error code of DecodeError
19pub fn (err DecodeError) code() int {
20return 3
21}
22
23// msg returns the message of the DecodeError
24pub fn (err DecodeError) msg() string {
25return format_message(err.message, err.line, err.column)
26}
27
28pub struct InvalidTokenError {
29DecodeError
30token Token
31expected TokenKind
32}
33
34// code returns the error code of the InvalidTokenError
35pub fn (err InvalidTokenError) code() int {
36return 2
37}
38
39// msg returns the message of the InvalidTokenError
40pub fn (err InvalidTokenError) msg() string {
41footer_text := if err.expected != .none_ { ', expecting `${err.expected}`' } else { '' }
42return format_message('invalid token `${err.token.kind}`${footer_text}', err.token.line,
43err.token.full_col())
44}
45
46pub struct UnknownTokenError {
47DecodeError
48token Token
49kind ValueKind = .unknown
50}
51
52// code returns the error code of the UnknownTokenError
53pub fn (err UnknownTokenError) code() int {
54return 1
55}
56
57// msg returns the error message of the UnknownTokenError
58pub fn (err UnknownTokenError) msg() string {
59return format_message("unknown token '${err.token.lit}' when decoding ${err.kind}.",
60err.token.line, err.token.full_col())
61}
62
63struct Parser {
64pub mut:
65scanner &Scanner = unsafe { nil }
66prev_tok Token
67tok Token
68next_tok Token
69n_level int
70convert_type bool = true
71}
72
73fn (mut p Parser) next() {
74p.prev_tok = p.tok
75p.tok = p.next_tok
76p.next_tok = p.scanner.scan()
77}
78
79fn (mut p Parser) next_with_err() ! {
80p.next()
81if p.tok.kind == .error {
82return DecodeError{
83line: p.tok.line
84column: p.tok.full_col()
85message: p.tok.lit.bytestr()
86}
87}
88}
89
90// TODO: copied from v.util to avoid the entire module and its functions
91// from being imported. remove later once -skip-unused is enabled by default.
92// skip_bom - skip Byte Order Mark (BOM)
93// The UTF-8 BOM is a sequence of Bytes at the start of a text-stream (EF BB BF or \ufeff)
94// that allows the reader to reliably determine if file is being encoded in UTF-8.
95fn skip_bom(file_content string) string {
96mut raw_text := file_content
97// BOM check
98if raw_text.len >= 3 {
99unsafe {
100c_text := raw_text.str
101if c_text[0] == 0xEF && c_text[1] == 0xBB && c_text[2] == 0xBF {
102// skip three BOM bytes
103offset_from_begin := 3
104raw_text = tos(c_text[offset_from_begin], vstrlen(c_text) - offset_from_begin)
105}
106}
107}
108return raw_text
109}
110
111// new_parser - create a instance of Parser{}
112fn new_parser(srce string, convert_type bool) Parser {
113src := skip_bom(srce)
114return Parser{
115scanner: &Scanner{
116text: src.bytes()
117}
118convert_type: convert_type
119}
120}
121
122// Decodes a JSON string into an `Any` type. Returns an option.
123pub fn raw_decode(src string) !Any {
124mut p := new_parser(src, true)
125return p.decode()
126}
127
128// Same with `raw_decode`, but skips the type conversion for certain types when decoding a certain value.
129pub fn fast_raw_decode(src string) !Any {
130mut p := new_parser(src, false)
131return p.decode()
132}
133
134// decode is a generic function that decodes a JSON string into the target type.
135pub fn decode[T](src string) !T {
136res := raw_decode(src)!.as_map()
137return decode_struct[T](T{}, res)
138}
139
140// decode_array is a generic function that decodes a JSON string into the array target type.
141pub fn decode_array[T](src string) ![]T {
142res := raw_decode(src)!.as_map()
143return decode_struct_array(T{}, res)
144}
145
146// decode_struct_array is a generic function that decodes a JSON map into array struct T.
147fn decode_struct_array[T](_ T, res map[string]Any) ![]T {
148$if T is $struct {
149mut arr := []T{}
150for v in res.values() {
151arr << decode_struct[T](T{}, v.as_map())!
152}
153return arr
154} $else {
155return error("The type `${T.name}` can't be decoded.")
156}
157}
158
159// decode_struct is a generic function that decodes a JSON map into the struct T.
160fn decode_struct[T](_ T, res map[string]Any) !T {
161mut typ := T{}
162$if T is $struct {
163$for field in T.fields {
164mut skip_field := false
165mut json_name := field.name
166
167for attr in field.attrs {
168if attr.contains('skip') {
169skip_field = true
170}
171if attr.contains('json: ') {
172json_name = attr.replace('json: ', '')
173if json_name == '-' {
174skip_field = true
175}
176break
177}
178}
179
180if !skip_field {
181$if field.is_enum {
182if v := res[json_name] {
183typ.$(field.name) = v.int()
184} else {
185$if field.is_option {
186typ.$(field.name) = none
187}
188}
189} $else $if field.typ is u8 {
190typ.$(field.name) = res[json_name]!.u64()
191} $else $if field.typ is u16 {
192typ.$(field.name) = res[json_name]!.u64()
193} $else $if field.typ is u32 {
194typ.$(field.name) = res[json_name]!.u64()
195} $else $if field.typ is u64 {
196typ.$(field.name) = res[json_name]!.u64()
197} $else $if field.typ is int {
198typ.$(field.name) = res[json_name]!.int()
199} $else $if field.typ is i8 {
200typ.$(field.name) = res[json_name]!.int()
201} $else $if field.typ is i16 {
202typ.$(field.name) = res[json_name]!.int()
203} $else $if field.typ is i32 {
204typ.$(field.name) = i32(res[field.name]!.i32())
205} $else $if field.typ is i64 {
206typ.$(field.name) = res[json_name]!.i64()
207} $else $if field.typ is ?u8 {
208if json_name in res {
209typ.$(field.name) = ?u8(res[json_name]!.i64())
210}
211} $else $if field.typ is ?i8 {
212if json_name in res {
213typ.$(field.name) = ?i8(res[json_name]!.i64())
214}
215} $else $if field.typ is ?u16 {
216if json_name in res {
217typ.$(field.name) = ?u16(res[json_name]!.i64())
218}
219} $else $if field.typ is ?i16 {
220if json_name in res {
221typ.$(field.name) = ?i16(res[json_name]!.i64())
222}
223} $else $if field.typ is ?u32 {
224if json_name in res {
225typ.$(field.name) = ?u32(res[json_name]!.i64())
226}
227} $else $if field.typ is ?i32 {
228if json_name in res {
229typ.$(field.name) = ?i32(res[json_name]!.i64())
230}
231} $else $if field.typ is ?u64 {
232if json_name in res {
233typ.$(field.name) = ?u64(res[json_name]!.i64())
234}
235} $else $if field.typ is ?i64 {
236if json_name in res {
237typ.$(field.name) = ?i64(res[json_name]!.i64())
238}
239} $else $if field.typ is ?int {
240if json_name in res {
241typ.$(field.name) = ?int(res[json_name]!.i64())
242}
243} $else $if field.typ is f32 {
244typ.$(field.name) = res[json_name]!.f32()
245} $else $if field.typ is ?f32 {
246if json_name in res {
247typ.$(field.name) = res[json_name]!.f32()
248}
249} $else $if field.typ is f64 {
250typ.$(field.name) = res[json_name]!.f64()
251} $else $if field.typ is ?f64 {
252if json_name in res {
253typ.$(field.name) = res[json_name]!.f64()
254}
255} $else $if field.typ is bool {
256typ.$(field.name) = res[json_name]!.bool()
257} $else $if field.typ is ?bool {
258if json_name in res {
259typ.$(field.name) = res[json_name]!.bool()
260}
261} $else $if field.typ is string {
262typ.$(field.name) = res[json_name]!.str()
263} $else $if field.typ is ?string {
264if json_name in res {
265typ.$(field.name) = res[json_name]!.str()
266}
267} $else $if field.typ is time.Time {
268typ.$(field.name) = res[json_name]!.to_time()!
269} $else $if field.typ is ?time.Time {
270if json_name in res {
271typ.$(field.name) = res[json_name]!.to_time()!
272}
273} $else $if field.typ is Any {
274typ.$(field.name) = res[json_name]!
275} $else $if field.typ is ?Any {
276if json_name in res {
277typ.$(field.name) = res[json_name]!
278}
279} $else $if field.is_array {
280arr := res[field.name]! as []Any
281decode_array_item(mut typ.$(field.name), arr)
282} $else $if field.is_struct {
283typ.$(field.name) = decode_struct(typ.$(field.name), res[field.name]!.as_map())!
284} $else $if field.is_alias {
285} $else $if field.is_map {
286typ.$(field.name) = decode_map(typ.$(field.name), res[field.name]!.as_map())!
287} $else {
288return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose")
289}
290}
291}
292} $else $if T is $map {
293for k, v in res {
294// // TODO: make this work to decode types like `map[string]StructType[bool]`
295// $if typeof(typ[k]).idx is string {
296// typ[k] = v.str()
297// } $else $if typeof(typ[k]).idx is $struct {
298
299// }
300match v {
301string {
302typ[k] = v.str()
303}
304else {}
305}
306}
307} $else {
308return error("The type `${T.name}` can't be decoded.")
309}
310return typ
311}
312
313fn decode_array_item[T](mut field T, arr []Any) {
314// vfmt off
315match typeof[T]().idx {
316typeof[[]bool]().idx { field = arr.map(it.bool()) }
317typeof[[]?bool]().idx { field = arr.map(?bool(it.bool())) }
318typeof[[]f32]().idx { field = arr.map(it.f32()) }
319typeof[[]?f32]().idx { field = arr.map(?f32(it.f32())) }
320typeof[[]f64]().idx { field = arr.map(it.f64()) }
321typeof[[]?f64]().idx { field = arr.map(?f64(it.f64())) }
322typeof[[]i8]().idx { field = arr.map(it.i8()) }
323typeof[[]?i8]().idx { field = arr.map(?i8(it.i8())) }
324typeof[[]i16]().idx { field = arr.map(it.i16()) }
325typeof[[]?i16]().idx { field = arr.map(?i16(it.i16())) }
326typeof[[]i32]().idx { field = arr.map(it.i32()) }
327typeof[[]?i32]().idx { field = arr.map(?i32(it.i32())) }
328typeof[[]i64]().idx { field = arr.map(it.i64()) }
329typeof[[]?i64]().idx { field = arr.map(?i64(it.i64())) }
330typeof[[]int]().idx { field = arr.map(it.int()) }
331typeof[[]?int]().idx { field = arr.map(?int(it.int())) }
332typeof[[]string]().idx { field = arr.map(it.str()) }
333typeof[[]?string]().idx { field = arr.map(?string(it.str())) }
334// NOTE: Using `!` on `to_time()` inside the array method causes a builder error - 2024/04/01.
335typeof[[]time.Time]().idx { field = arr.map(it.to_time() or { time.Time{} }) }
336typeof[[]?time.Time]().idx { field = arr.map(?time.Time(it.to_time() or { time.Time{} })) }
337typeof[[]Any]().idx { field = arr.clone() }
338typeof[[]?Any]().idx { field = arr.map(?Any(it)) }
339typeof[[]u8]().idx { field = arr.map(it.u64()) }
340typeof[[]?u8]().idx { field = arr.map(?u8(it.u64())) }
341typeof[[]u16]().idx { field = arr.map(it.u64()) }
342typeof[[]?u16]().idx { field = arr.map(?u16(it.u64())) }
343typeof[[]u32]().idx { field = arr.map(it.u64()) }
344typeof[[]?u32]().idx { field = arr.map(?u32(it.u64())) }
345typeof[[]u64]().idx { field = arr.map(it.u64()) }
346typeof[[]?u64]().idx { field = arr.map(?u64(it.u64())) }
347else {
348$if T is [][]f32 { field << arr.map(it.as_map().values().map(it.f32())) }
349$else $if T is [][]?f32 { field << arr.map(it.as_map().values().map(?f32(it.f32()))) }
350$else $if T is [][]f64 { field << arr.map(it.as_map().values().map(it.f64())) }
351$else $if T is [][]?f64 { field << arr.map(it.as_map().values().map(?f64(it.f64()))) }
352$else $if T is [][]i8 { field << arr.map(it.as_map().values().map(it.i8())) }
353$else $if T is [][]?i8 { field << arr.map(it.as_map().values().map(?i8(it.i8()))) }
354$else $if T is [][]i16 { field << arr.map(it.as_map().values().map(it.i16())) }
355$else $if T is [][]?i16 { field << arr.map(it.as_map().values().map(?i16(it.i16()))) }
356$else $if T is [][]i32 { field << arr.map(it.as_map().values().map(it.i32())) }
357$else $if T is [][]?i32 { field << arr.map(it.as_map().values().map(?i32(it.i32()))) }
358$else $if T is [][]i64 { field << arr.map(it.as_map().values().map(it.i64())) }
359$else $if T is [][]?i64 { field << arr.map(it.as_map().values().map(?i64(it.i64()))) }
360$else $if T is [][]u8 { field << arr.map(it.as_map().values().map(it.u8())) }
361$else $if T is [][]?u8 { field << arr.map(it.as_map().values().map(?u8(it.u8()))) }
362$else $if T is [][]u16 { field << arr.map(it.as_map().values().map(it.u16())) }
363$else $if T is [][]?u16 { field << arr.map(it.as_map().values().map(?u16(it.u16()))) }
364$else $if T is [][]u32 { field << arr.map(it.as_map().values().map(it.u32())) }
365$else $if T is [][]?u32 { field << arr.map(it.as_map().values().map(?u32(it.u32()))) }
366$else $if T is [][]u64 { field << arr.map(it.as_map().values().map(it.u64())) }
367$else $if T is [][]?u64 { field << arr.map(it.as_map().values().map(?u64(it.u64()))) }
368$else $if T is [][]bool { field << arr.map(it.as_map().values().map(it.bool())) }
369$else $if T is [][]?bool { field << arr.map(it.as_map().values().map(?bool(it.bool()))) }
370$else $if T is [][]string { field << arr.map(it.as_map().values().map(it.string())) }
371$else $if T is [][]?string { field << arr.map(it.as_map().values().map(?string(it.string()))) }
372}
373}
374// vfmt on
375}
376
377fn decode_map[K, V](_ map[K]V, res map[string]Any) !map[K]V {
378mut ret := map[K]V{}
379
380for k, v in res {
381$if V is $struct {
382ret[k] = decode_struct(V{}, res[k]!.as_map())!
383} $else $if V is $map {
384ret[k] = decode_map(V{}, res[k]!.as_map())!
385} $else $if V is $sumtype {
386ret[k] = decode_struct(V{}, res[k]!.as_map())!
387} $else $if V is $string {
388ret[k] = v.str()
389} $else $if V is int {
390ret[k] = v.int()
391} $else $if V is i64 {
392ret[k] = v.i64()
393} $else $if V is u64 {
394ret[k] = v.u64()
395} $else $if V is i32 {
396ret[k] = v.i32()
397} $else $if V is u32 {
398ret[k] = v.u32()
399} $else $if V is i16 {
400ret[k] = v.i16()
401} $else $if V is u16 {
402ret[k] = v.u16()
403} $else $if V is i8 {
404ret[k] = v.i8()
405} $else $if V is u8 {
406ret[k] = v.u8()
407} $else $if V is bool {
408ret[k] = v.bool()
409} $else {
410dump(v)
411}
412}
413return ret
414}
415
416// decode - decodes provided JSON
417pub fn (mut p Parser) decode() !Any {
418p.next()
419p.next_with_err()!
420fi := p.decode_value()!
421if p.tok.kind != .eof {
422return InvalidTokenError{
423token: p.tok
424}
425}
426return fi
427}
428
429fn (mut p Parser) decode_value() !Any {
430if p.n_level + 1 == 500 {
431return DecodeError{
432message: 'reached maximum nesting level of 500'
433}
434}
435match p.tok.kind {
436// `[`
437.lsbr {
438return p.decode_array()
439}
440// `{`
441.lcbr {
442return p.decode_object()
443}
444.int_, .float {
445tl := p.tok.lit.bytestr()
446kind := p.tok.kind
447p.next_with_err()!
448if p.convert_type {
449$if !nofloat ? {
450if kind == .float {
451return Any(tl.f64())
452}
453}
454return Any(tl.i64())
455}
456return Any(tl)
457}
458.bool_ {
459lit := p.tok.lit.bytestr()
460p.next_with_err()!
461if p.convert_type {
462return Any(lit.bool())
463}
464return Any(lit)
465}
466.null {
467p.next_with_err()!
468if p.convert_type {
469return Any(null)
470}
471return Any('null')
472}
473.str_ {
474str := p.tok.lit.bytestr()
475p.next_with_err()!
476return Any(str)
477}
478else {
479return InvalidTokenError{
480token: p.tok
481}
482}
483}
484return InvalidTokenError{
485token: p.tok
486}
487}
488
489@[manualfree]
490fn (mut p Parser) decode_array() !Any {
491mut items := []Any{}
492p.next_with_err()!
493p.n_level++
494// `]`
495for p.tok.kind != .rsbr {
496item := p.decode_value()!
497items << item
498if p.tok.kind == .comma {
499p.next_with_err()!
500if p.tok.kind == .rsbr {
501return InvalidTokenError{
502token: p.tok
503}
504}
505} else if p.tok.kind != .rsbr {
506return UnknownTokenError{
507token: p.tok
508kind: .array
509}
510}
511}
512p.next_with_err()!
513p.n_level--
514return Any(items)
515}
516
517fn (mut p Parser) decode_object() !Any {
518mut fields := map[string]Any{}
519p.next_with_err()!
520p.n_level++
521// `}`
522for p.tok.kind != .rcbr {
523// step 1 -> key
524if p.tok.kind != .str_ {
525return InvalidTokenError{
526token: p.tok
527expected: .str_
528}
529}
530
531cur_key := p.tok.lit.bytestr()
532p.next_with_err()!
533// step 2 -> colon separator
534if p.tok.kind != .colon {
535return InvalidTokenError{
536token: p.tok
537expected: .colon
538}
539}
540
541p.next_with_err()!
542// step 3 -> value
543fields[cur_key] = p.decode_value()!
544if p.tok.kind !in [.comma, .rcbr] {
545return InvalidTokenError{
546token: p.tok
547expected: .comma
548}
549} else if p.tok.kind == .comma {
550p.next_with_err()!
551}
552}
553p.next_with_err()!
554// step 4 -> eof (end)
555p.n_level--
556return Any(fields)
557}
558