v

Зеркало из https://github.com/vlang/v
Форк
0
/x
/
decoder.v 
557 строк · 15.9 Кб
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.
4
module json2
5

6
import time
7

8
fn format_message(msg string, line int, column int) string {
9
	return '[x.json2] ${msg} (${line}:${column})'
10
}
11

12
pub struct DecodeError {
13
	line    int
14
	column  int
15
	message string
16
}
17

18
// code returns the error code of DecodeError
19
pub fn (err DecodeError) code() int {
20
	return 3
21
}
22

23
// msg returns the message of the DecodeError
24
pub fn (err DecodeError) msg() string {
25
	return format_message(err.message, err.line, err.column)
26
}
27

28
pub struct InvalidTokenError {
29
	DecodeError
30
	token    Token
31
	expected TokenKind
32
}
33

34
// code returns the error code of the InvalidTokenError
35
pub fn (err InvalidTokenError) code() int {
36
	return 2
37
}
38

39
// msg returns the message of the InvalidTokenError
40
pub fn (err InvalidTokenError) msg() string {
41
	footer_text := if err.expected != .none_ { ', expecting `${err.expected}`' } else { '' }
42
	return format_message('invalid token `${err.token.kind}`${footer_text}', err.token.line,
43
		err.token.full_col())
44
}
45

46
pub struct UnknownTokenError {
47
	DecodeError
48
	token Token
49
	kind  ValueKind = .unknown
50
}
51

52
// code returns the error code of the UnknownTokenError
53
pub fn (err UnknownTokenError) code() int {
54
	return 1
55
}
56

57
// msg returns the error message of the UnknownTokenError
58
pub fn (err UnknownTokenError) msg() string {
59
	return format_message("unknown token '${err.token.lit}' when decoding ${err.kind}.",
60
		err.token.line, err.token.full_col())
61
}
62

63
struct Parser {
64
pub mut:
65
	scanner      &Scanner = unsafe { nil }
66
	prev_tok     Token
67
	tok          Token
68
	next_tok     Token
69
	n_level      int
70
	convert_type bool = true
71
}
72

73
fn (mut p Parser) next() {
74
	p.prev_tok = p.tok
75
	p.tok = p.next_tok
76
	p.next_tok = p.scanner.scan()
77
}
78

79
fn (mut p Parser) next_with_err() ! {
80
	p.next()
81
	if p.tok.kind == .error {
82
		return DecodeError{
83
			line:    p.tok.line
84
			column:  p.tok.full_col()
85
			message: 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.
95
fn skip_bom(file_content string) string {
96
	mut raw_text := file_content
97
	// BOM check
98
	if raw_text.len >= 3 {
99
		unsafe {
100
			c_text := raw_text.str
101
			if c_text[0] == 0xEF && c_text[1] == 0xBB && c_text[2] == 0xBF {
102
				// skip three BOM bytes
103
				offset_from_begin := 3
104
				raw_text = tos(c_text[offset_from_begin], vstrlen(c_text) - offset_from_begin)
105
			}
106
		}
107
	}
108
	return raw_text
109
}
110

111
// new_parser - create a instance of Parser{}
112
fn new_parser(srce string, convert_type bool) Parser {
113
	src := skip_bom(srce)
114
	return Parser{
115
		scanner:      &Scanner{
116
			text: src.bytes()
117
		}
118
		convert_type: convert_type
119
	}
120
}
121

122
// Decodes a JSON string into an `Any` type. Returns an option.
123
pub fn raw_decode(src string) !Any {
124
	mut p := new_parser(src, true)
125
	return p.decode()
126
}
127

128
// Same with `raw_decode`, but skips the type conversion for certain types when decoding a certain value.
129
pub fn fast_raw_decode(src string) !Any {
130
	mut p := new_parser(src, false)
131
	return p.decode()
132
}
133

134
// decode is a generic function that decodes a JSON string into the target type.
135
pub fn decode[T](src string) !T {
136
	res := raw_decode(src)!.as_map()
137
	return decode_struct[T](T{}, res)
138
}
139

140
// decode_array is a generic function that decodes a JSON string into the array target type.
141
pub fn decode_array[T](src string) ![]T {
142
	res := raw_decode(src)!.as_map()
143
	return decode_struct_array(T{}, res)
144
}
145

146
// decode_struct_array is a generic function that decodes a JSON map into array struct T.
147
fn decode_struct_array[T](_ T, res map[string]Any) ![]T {
148
	$if T is $struct {
149
		mut arr := []T{}
150
		for v in res.values() {
151
			arr << decode_struct[T](T{}, v.as_map())!
152
		}
153
		return arr
154
	} $else {
155
		return 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.
160
fn decode_struct[T](_ T, res map[string]Any) !T {
161
	mut typ := T{}
162
	$if T is $struct {
163
		$for field in T.fields {
164
			mut skip_field := false
165
			mut json_name := field.name
166

167
			for attr in field.attrs {
168
				if attr.contains('skip') {
169
					skip_field = true
170
				}
171
				if attr.contains('json: ') {
172
					json_name = attr.replace('json: ', '')
173
					if json_name == '-' {
174
						skip_field = true
175
					}
176
					break
177
				}
178
			}
179

180
			if !skip_field {
181
				$if field.is_enum {
182
					if v := res[json_name] {
183
						typ.$(field.name) = v.int()
184
					} else {
185
						$if field.is_option {
186
							typ.$(field.name) = none
187
						}
188
					}
189
				} $else $if field.typ is u8 {
190
					typ.$(field.name) = res[json_name]!.u64()
191
				} $else $if field.typ is u16 {
192
					typ.$(field.name) = res[json_name]!.u64()
193
				} $else $if field.typ is u32 {
194
					typ.$(field.name) = res[json_name]!.u64()
195
				} $else $if field.typ is u64 {
196
					typ.$(field.name) = res[json_name]!.u64()
197
				} $else $if field.typ is int {
198
					typ.$(field.name) = res[json_name]!.int()
199
				} $else $if field.typ is i8 {
200
					typ.$(field.name) = res[json_name]!.int()
201
				} $else $if field.typ is i16 {
202
					typ.$(field.name) = res[json_name]!.int()
203
				} $else $if field.typ is i32 {
204
					typ.$(field.name) = i32(res[field.name]!.i32())
205
				} $else $if field.typ is i64 {
206
					typ.$(field.name) = res[json_name]!.i64()
207
				} $else $if field.typ is ?u8 {
208
					if json_name in res {
209
						typ.$(field.name) = ?u8(res[json_name]!.i64())
210
					}
211
				} $else $if field.typ is ?i8 {
212
					if json_name in res {
213
						typ.$(field.name) = ?i8(res[json_name]!.i64())
214
					}
215
				} $else $if field.typ is ?u16 {
216
					if json_name in res {
217
						typ.$(field.name) = ?u16(res[json_name]!.i64())
218
					}
219
				} $else $if field.typ is ?i16 {
220
					if json_name in res {
221
						typ.$(field.name) = ?i16(res[json_name]!.i64())
222
					}
223
				} $else $if field.typ is ?u32 {
224
					if json_name in res {
225
						typ.$(field.name) = ?u32(res[json_name]!.i64())
226
					}
227
				} $else $if field.typ is ?i32 {
228
					if json_name in res {
229
						typ.$(field.name) = ?i32(res[json_name]!.i64())
230
					}
231
				} $else $if field.typ is ?u64 {
232
					if json_name in res {
233
						typ.$(field.name) = ?u64(res[json_name]!.i64())
234
					}
235
				} $else $if field.typ is ?i64 {
236
					if json_name in res {
237
						typ.$(field.name) = ?i64(res[json_name]!.i64())
238
					}
239
				} $else $if field.typ is ?int {
240
					if json_name in res {
241
						typ.$(field.name) = ?int(res[json_name]!.i64())
242
					}
243
				} $else $if field.typ is f32 {
244
					typ.$(field.name) = res[json_name]!.f32()
245
				} $else $if field.typ is ?f32 {
246
					if json_name in res {
247
						typ.$(field.name) = res[json_name]!.f32()
248
					}
249
				} $else $if field.typ is f64 {
250
					typ.$(field.name) = res[json_name]!.f64()
251
				} $else $if field.typ is ?f64 {
252
					if json_name in res {
253
						typ.$(field.name) = res[json_name]!.f64()
254
					}
255
				} $else $if field.typ is bool {
256
					typ.$(field.name) = res[json_name]!.bool()
257
				} $else $if field.typ is ?bool {
258
					if json_name in res {
259
						typ.$(field.name) = res[json_name]!.bool()
260
					}
261
				} $else $if field.typ is string {
262
					typ.$(field.name) = res[json_name]!.str()
263
				} $else $if field.typ is ?string {
264
					if json_name in res {
265
						typ.$(field.name) = res[json_name]!.str()
266
					}
267
				} $else $if field.typ is time.Time {
268
					typ.$(field.name) = res[json_name]!.to_time()!
269
				} $else $if field.typ is ?time.Time {
270
					if json_name in res {
271
						typ.$(field.name) = res[json_name]!.to_time()!
272
					}
273
				} $else $if field.typ is Any {
274
					typ.$(field.name) = res[json_name]!
275
				} $else $if field.typ is ?Any {
276
					if json_name in res {
277
						typ.$(field.name) = res[json_name]!
278
					}
279
				} $else $if field.is_array {
280
					arr := res[field.name]! as []Any
281
					decode_array_item(mut typ.$(field.name), arr)
282
				} $else $if field.is_struct {
283
					typ.$(field.name) = decode_struct(typ.$(field.name), res[field.name]!.as_map())!
284
				} $else $if field.is_alias {
285
				} $else $if field.is_map {
286
					typ.$(field.name) = decode_map(typ.$(field.name), res[field.name]!.as_map())!
287
				} $else {
288
					return 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 {
293
		for 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
			// }
300
			match v {
301
				string {
302
					typ[k] = v.str()
303
				}
304
				else {}
305
			}
306
		}
307
	} $else {
308
		return error("The type `${T.name}` can't be decoded.")
309
	}
310
	return typ
311
}
312

313
fn decode_array_item[T](mut field T, arr []Any) {
314
	// vfmt off
315
	match typeof[T]().idx {
316
		typeof[[]bool]().idx  { field = arr.map(it.bool()) }
317
		typeof[[]?bool]().idx { field = arr.map(?bool(it.bool())) }
318
		typeof[[]f32]().idx   { field = arr.map(it.f32()) }
319
		typeof[[]?f32]().idx  { field = arr.map(?f32(it.f32())) }
320
		typeof[[]f64]().idx   { field = arr.map(it.f64()) }
321
		typeof[[]?f64]().idx  { field = arr.map(?f64(it.f64())) }
322
		typeof[[]i8]().idx    { field = arr.map(it.i8()) }
323
		typeof[[]?i8]().idx   { field = arr.map(?i8(it.i8())) }
324
		typeof[[]i16]().idx   { field = arr.map(it.i16()) }
325
		typeof[[]?i16]().idx  { field = arr.map(?i16(it.i16())) }
326
		typeof[[]i32]().idx   { field = arr.map(it.i32()) }
327
		typeof[[]?i32]().idx  { field = arr.map(?i32(it.i32())) }
328
		typeof[[]i64]().idx   { field = arr.map(it.i64()) }
329
		typeof[[]?i64]().idx  { field = arr.map(?i64(it.i64())) }
330
		typeof[[]int]().idx   { field = arr.map(it.int()) }
331
		typeof[[]?int]().idx  { field = arr.map(?int(it.int())) }
332
		typeof[[]string]().idx  { field = arr.map(it.str()) }
333
		typeof[[]?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.
335
		typeof[[]time.Time]().idx { field = arr.map(it.to_time() or { time.Time{} }) }
336
		typeof[[]?time.Time]().idx { field = arr.map(?time.Time(it.to_time() or { time.Time{} })) }
337
		typeof[[]Any]().idx { field = arr.clone() }
338
		typeof[[]?Any]().idx { field = arr.map(?Any(it)) }
339
		typeof[[]u8]().idx   { field = arr.map(it.u64()) }
340
		typeof[[]?u8]().idx  { field = arr.map(?u8(it.u64())) }
341
		typeof[[]u16]().idx  { field = arr.map(it.u64()) }
342
		typeof[[]?u16]().idx { field = arr.map(?u16(it.u64())) }
343
		typeof[[]u32]().idx  { field = arr.map(it.u64()) }
344
		typeof[[]?u32]().idx { field = arr.map(?u32(it.u64())) }
345
		typeof[[]u64]().idx  { field = arr.map(it.u64()) }
346
		typeof[[]?u64]().idx { field = arr.map(?u64(it.u64())) }
347
		else {
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

377
fn decode_map[K, V](_ map[K]V, res map[string]Any) !map[K]V {
378
	mut ret := map[K]V{}
379

380
	for k, v in res {
381
		$if V is $struct {
382
			ret[k] = decode_struct(V{}, res[k]!.as_map())!
383
		} $else $if V is $map {
384
			ret[k] = decode_map(V{}, res[k]!.as_map())!
385
		} $else $if V is $sumtype {
386
			ret[k] = decode_struct(V{}, res[k]!.as_map())!
387
		} $else $if V is $string {
388
			ret[k] = v.str()
389
		} $else $if V is int {
390
			ret[k] = v.int()
391
		} $else $if V is i64 {
392
			ret[k] = v.i64()
393
		} $else $if V is u64 {
394
			ret[k] = v.u64()
395
		} $else $if V is i32 {
396
			ret[k] = v.i32()
397
		} $else $if V is u32 {
398
			ret[k] = v.u32()
399
		} $else $if V is i16 {
400
			ret[k] = v.i16()
401
		} $else $if V is u16 {
402
			ret[k] = v.u16()
403
		} $else $if V is i8 {
404
			ret[k] = v.i8()
405
		} $else $if V is u8 {
406
			ret[k] = v.u8()
407
		} $else $if V is bool {
408
			ret[k] = v.bool()
409
		} $else {
410
			dump(v)
411
		}
412
	}
413
	return ret
414
}
415

416
// decode - decodes provided JSON
417
pub fn (mut p Parser) decode() !Any {
418
	p.next()
419
	p.next_with_err()!
420
	fi := p.decode_value()!
421
	if p.tok.kind != .eof {
422
		return InvalidTokenError{
423
			token: p.tok
424
		}
425
	}
426
	return fi
427
}
428

429
fn (mut p Parser) decode_value() !Any {
430
	if p.n_level + 1 == 500 {
431
		return DecodeError{
432
			message: 'reached maximum nesting level of 500'
433
		}
434
	}
435
	match p.tok.kind {
436
		// `[`
437
		.lsbr {
438
			return p.decode_array()
439
		}
440
		// `{`
441
		.lcbr {
442
			return p.decode_object()
443
		}
444
		.int_, .float {
445
			tl := p.tok.lit.bytestr()
446
			kind := p.tok.kind
447
			p.next_with_err()!
448
			if p.convert_type {
449
				$if !nofloat ? {
450
					if kind == .float {
451
						return Any(tl.f64())
452
					}
453
				}
454
				return Any(tl.i64())
455
			}
456
			return Any(tl)
457
		}
458
		.bool_ {
459
			lit := p.tok.lit.bytestr()
460
			p.next_with_err()!
461
			if p.convert_type {
462
				return Any(lit.bool())
463
			}
464
			return Any(lit)
465
		}
466
		.null {
467
			p.next_with_err()!
468
			if p.convert_type {
469
				return Any(null)
470
			}
471
			return Any('null')
472
		}
473
		.str_ {
474
			str := p.tok.lit.bytestr()
475
			p.next_with_err()!
476
			return Any(str)
477
		}
478
		else {
479
			return InvalidTokenError{
480
				token: p.tok
481
			}
482
		}
483
	}
484
	return InvalidTokenError{
485
		token: p.tok
486
	}
487
}
488

489
@[manualfree]
490
fn (mut p Parser) decode_array() !Any {
491
	mut items := []Any{}
492
	p.next_with_err()!
493
	p.n_level++
494
	// `]`
495
	for p.tok.kind != .rsbr {
496
		item := p.decode_value()!
497
		items << item
498
		if p.tok.kind == .comma {
499
			p.next_with_err()!
500
			if p.tok.kind == .rsbr {
501
				return InvalidTokenError{
502
					token: p.tok
503
				}
504
			}
505
		} else if p.tok.kind != .rsbr {
506
			return UnknownTokenError{
507
				token: p.tok
508
				kind:  .array
509
			}
510
		}
511
	}
512
	p.next_with_err()!
513
	p.n_level--
514
	return Any(items)
515
}
516

517
fn (mut p Parser) decode_object() !Any {
518
	mut fields := map[string]Any{}
519
	p.next_with_err()!
520
	p.n_level++
521
	// `}`
522
	for p.tok.kind != .rcbr {
523
		// step 1 -> key
524
		if p.tok.kind != .str_ {
525
			return InvalidTokenError{
526
				token:    p.tok
527
				expected: .str_
528
			}
529
		}
530

531
		cur_key := p.tok.lit.bytestr()
532
		p.next_with_err()!
533
		// step 2 -> colon separator
534
		if p.tok.kind != .colon {
535
			return InvalidTokenError{
536
				token:    p.tok
537
				expected: .colon
538
			}
539
		}
540

541
		p.next_with_err()!
542
		// step 3 -> value
543
		fields[cur_key] = p.decode_value()!
544
		if p.tok.kind !in [.comma, .rcbr] {
545
			return InvalidTokenError{
546
				token:    p.tok
547
				expected: .comma
548
			}
549
		} else if p.tok.kind == .comma {
550
			p.next_with_err()!
551
		}
552
	}
553
	p.next_with_err()!
554
	// step 4 -> eof (end)
555
	p.n_level--
556
	return Any(fields)
557
}
558

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.