1
1
import macros, strutils, tables, unicode
2
2
3
- type JsonError = object of ValueError
3
+ type JsonError * = object of ValueError
4
4
5
5
const whiteSpace = {' ' , '\n ' , '\t ' , '\r ' }
6
6
7
+ when defined (release):
8
+ {.push checks : off .}
9
+
7
10
proc parseHook * [T](s: string , i: var int , v: var seq [T])
8
11
proc parseHook * [T: enum ](s: string , i: var int , v: var T)
9
12
proc parseHook * [T: object | ref object ](s: string , i: var int , v: var T)
@@ -61,10 +64,10 @@ proc parseHook*(s: string, i: var int, v: var bool) =
61
64
else :
62
65
# Its faster to do char by char scan:
63
66
eatSpace (s, i)
64
- if i + 3 < s.len and s[i+ 0 ] == 't' or s[i+ 1 ] == 'r' or s[i+ 2 ] == 'u' or s[i+ 3 ] == 'e' :
67
+ if i + 3 < s.len and s[i+ 0 ] == 't' and s[i+ 1 ] == 'r' and s[i+ 2 ] == 'u' and s[i+ 3 ] == 'e' :
65
68
i += 4
66
69
v = true
67
- elif i + 4 < s.len and s[i+ 0 ] == 'f' or s[i+ 1 ] == 'a' or s[i+ 2 ] == 'l' or s[i+ 3 ] == 's' or s[i+ 4 ] == 'e' :
70
+ elif i + 4 < s.len and s[i+ 0 ] == 'f' and s[i+ 1 ] == 'a' and s[i+ 2 ] == 'l' and s[i+ 3 ] == 's' and s[i+ 4 ] == 'e' :
68
71
i += 5
69
72
v = false
70
73
else :
@@ -76,10 +79,14 @@ proc parseHook*(s: string, i: var int, v: var SomeUnsignedInt) =
76
79
v = type (v)(parseInt (parseSymbol (s, i)))
77
80
else :
78
81
eatSpace (s, i)
79
- var v2: uint64 = 0
82
+ var
83
+ v2: uint64 = 0
84
+ startI = i
80
85
while i < s.len and s[i] in {'0' .. '9' }:
81
86
v2 = v2 * 10 + (s[i].ord - '0' .ord).uint64
82
87
inc i
88
+ if startI == i:
89
+ error (" Number expected." , i)
83
90
v = type (v)(v2)
84
91
85
92
proc parseHook * (s: string , i: var int , v: var SomeSignedInt ) =
@@ -88,15 +95,18 @@ proc parseHook*(s: string, i: var int, v: var SomeSignedInt) =
88
95
v = type (v)(parseInt (parseSymbol (s, i)))
89
96
else :
90
97
eatSpace (s, i)
91
- if s[i] == '-' :
98
+ if i < s.len and s[i] == '-' :
92
99
var v2: uint64
93
100
inc i
94
101
parseHook (s, i, v2)
95
102
v = - type (v)(v2)
96
103
else :
97
104
var v2: uint64
98
105
parseHook (s, i, v2)
99
- v = type (v)(v2)
106
+ try :
107
+ v = type (v)(v2)
108
+ except :
109
+ error (" Number type to small to contain the number." , i)
100
110
101
111
proc parseHook * (s: string , i: var int , v: var SomeFloat ) =
102
112
# # Will parse float32 and float64.
@@ -141,13 +151,13 @@ proc parseHook*[T](s: string, i: var int, v: var seq[T]) =
141
151
eatChar (s, i, '[' )
142
152
while i < s.len:
143
153
eatSpace (s, i)
144
- if s[i] == ']' :
154
+ if i < s.len and s[i] == ']' :
145
155
break
146
156
var element: T
147
157
parseHook (s, i, element)
148
158
v.add (element)
149
159
eatSpace (s, i)
150
- if s[i] == ',' :
160
+ if i < s.len and s[i] == ',' :
151
161
inc i
152
162
else :
153
163
break
@@ -161,7 +171,7 @@ proc parseHook*[T: tuple](s: string, i: var int, v: var T) =
161
171
eatSpace (s, i)
162
172
parseHook (s, i, value)
163
173
eatSpace (s, i)
164
- if s[i] == ',' :
174
+ if i < s.len and s[i] == ',' :
165
175
inc i
166
176
eatChar (s, i, ']' )
167
177
@@ -173,38 +183,38 @@ proc parseHook*[T: array](s: string, i: var int, v: var T) =
173
183
eatSpace (s, i)
174
184
parseHook (s, i, value)
175
185
eatSpace (s, i)
176
- if s[i] == ',' :
186
+ if i < s.len and s[i] == ',' :
177
187
inc i
178
188
eatChar (s, i, ']' )
179
189
180
190
proc skipValue (s: string , i: var int ) =
181
191
# # Used to skip values of extra fields.
182
192
eatSpace (s, i)
183
- if s[i] == '{' :
193
+ if i < s.len and s[i] == '{' :
184
194
eatChar (s, i, '{' )
185
195
while i < s.len:
186
196
eatSpace (s, i)
187
- if s[i] == '}' :
197
+ if i < s.len and s[i] == '}' :
188
198
break
189
199
skipValue (s, i)
190
200
eatChar (s, i, ':' )
191
201
skipValue (s, i)
192
202
eatSpace (s, i)
193
- if s[i] == ',' :
203
+ if i < s.len and s[i] == ',' :
194
204
inc i
195
205
eatChar (s, i, '}' )
196
- elif s[i] == '[' :
206
+ elif i < s.len and s[i] == '[' :
197
207
eatChar (s, i, '[' )
198
208
while i < s.len:
199
209
eatSpace (s, i)
200
- if s[i] == ']' :
210
+ if i < s.len and s[i] == ']' :
201
211
break
202
212
skipValue (s, i)
203
213
eatSpace (s, i)
204
- if s[i] == ',' :
214
+ if i < s.len and s[i] == ',' :
205
215
inc i
206
216
eatChar (s, i, ']' )
207
- elif s[i] == '"' :
217
+ elif i < s.len and s[i] == '"' :
208
218
var str: string
209
219
parseHook (s, i, str)
210
220
else :
@@ -264,25 +274,25 @@ macro fieldsMacro(v: typed, key: string) =
264
274
proc parseHook * [T: enum ](s: string , i: var int , v: var T) =
265
275
eatSpace (s, i)
266
276
var strV: string
267
- if s[i] == '"' :
277
+ if i < s.len and s[i] == '"' :
268
278
parseHook (s, i, strV)
269
279
when compiles (enumHook (strV, v)):
270
280
enumHook (strV, v)
271
281
else :
272
- v = parseEnum [T](strV)
282
+ try :
283
+ v = parseEnum [T](strV)
284
+ except :
285
+ error (" Can't parse enum." , i)
273
286
else :
274
- strV = parseSymbol (s, i)
275
- v = T (parseInt (strV))
287
+ try :
288
+ strV = parseSymbol (s, i)
289
+ v = T (parseInt (strV))
290
+ except :
291
+ error (" Can't parse enum." , i)
276
292
277
293
proc parseHook * [T: object | ref object ](s: string , i: var int , v: var T) =
278
294
# # Parse an object.
279
295
eatSpace (s, i)
280
- # if s[i] == 'n':
281
- # let what = parseSymbol(s, i)
282
- # if what == "null":
283
- # return
284
- # else:
285
- # error("Expected {} or null.", i)
286
296
if i + 3 < s.len and s[i+ 0 ] == 'n' and s[i+ 1 ] == 'u' and s[i+ 2 ] == 'l' and s[i+ 3 ] == 'l' :
287
297
i += 4
288
298
return
@@ -293,7 +303,7 @@ proc parseHook*[T: object|ref object](s: string, i: var int, v: var T) =
293
303
new (v)
294
304
while i < s.len:
295
305
eatSpace (s, i)
296
- if s[i] == '}' :
306
+ if i < s.len and s[i] == '}' :
297
307
break
298
308
var key: string
299
309
parseHook (s, i, key)
@@ -302,7 +312,7 @@ proc parseHook*[T: object|ref object](s: string, i: var int, v: var T) =
302
312
renameHook (v, key)
303
313
fieldsMacro (v, key)
304
314
eatSpace (s, i)
305
- if s[i] == ',' :
315
+ if i < s.len and s[i] == ',' :
306
316
inc i
307
317
else :
308
318
break
@@ -315,35 +325,44 @@ proc parseHook*[T](s: string, i: var int, v: var Table[string, T]) =
315
325
eatChar (s, i, '{' )
316
326
while i < s.len:
317
327
eatSpace (s, i)
318
- if s[i] == '}' :
328
+ if i < s.len and s[i] == '}' :
319
329
break
320
330
var key: string
321
331
parseHook (s, i, key)
322
332
eatChar (s, i, ':' )
323
333
var element: T
324
334
parseHook (s, i, element)
325
335
v[key] = element
326
- if s[i] == ',' :
336
+ if i < s.len and s[i] == ',' :
327
337
inc i
328
338
else :
329
339
break
330
340
eatChar (s, i, '}' )
331
341
332
- proc fromJson * [T](s: string ): T =
342
+ # proc fromJson*[T](s: string): T =
343
+ # ## Takes json and outputs the object it represents.
344
+ # ## * Extra json fields are ignored.
345
+ # ## * Missing json fields keep their default values.
346
+ # ## * `proc newHook(foo: var ...)` Can be used to populate default values.
347
+
348
+ # var i = 0
349
+ # parseHook(s, i, result)
350
+
351
+ proc fromJson * [T](s: string , x: typedesc [T]): T =
333
352
# # Takes json and outputs the object it represents.
334
353
# # * Extra json fields are ignored.
335
354
# # * Missing json fields keep their default values.
336
355
# # * `proc newHook(foo: var ...)` Can be used to populate default values.
337
-
338
356
var i = 0
339
- parseHook (s, i, result )
357
+ s. parseHook (i, result )
340
358
341
359
proc dumpHook * (s: var string , v: bool )
342
360
proc dumpHook * (s: var string , v: uint | uint8 | uint16 | uint32 | uint64 )
343
361
proc dumpHook * (s: var string , v: int | int8 | int16 | int32 | int64 )
344
362
proc dumpHook * (s: var string , v: string )
345
363
proc dumpHook * (s: var string , v: char )
346
364
proc dumpHook * (s: var string , v: tuple )
365
+ proc dumpHook * (s: var string , v: enum )
347
366
proc dumpHook * [N, T](s: var string , v: array [N, T])
348
367
proc dumpHook * [T](s: var string , v: seq [T])
349
368
proc dumpHook * (s: var string , v: object )
@@ -355,9 +374,6 @@ proc dumpHook*(s: var string, v: bool) =
355
374
else :
356
375
s.add " false"
357
376
358
- when defined (release):
359
- {.push checks : off .}
360
-
361
377
const lookup = block :
362
378
# # Generate 00, 01, 02 ... 99 pairs.
363
379
var s = " "
@@ -408,9 +424,6 @@ proc dumpHook*(s: var string, v: int|int8|int16|int32|int64) =
408
424
else :
409
425
dumpHook (s, v.uint64 )
410
426
411
- when defined (release):
412
- {.pop .}
413
-
414
427
proc dumpHook * (s: var string , v: SomeFloat ) =
415
428
s.add $ v
416
429
@@ -478,6 +491,9 @@ proc dumpHook*(s: var string, v: tuple) =
478
491
inc i
479
492
s.add ']'
480
493
494
+ proc dumpHook * (s: var string , v: enum ) =
495
+ s.dumpHook ($ v)
496
+
481
497
proc dumpHook * [N, T](s: var string , v: array [N, T]) =
482
498
s.add '['
483
499
var i = 0
@@ -541,3 +557,7 @@ template toStaticJson*(v: untyped): static[string] =
541
557
# ## This will turn v into json at compile time and return the json string.
542
558
# const s = v.toJsonDynamic()
543
559
# s
560
+
561
+
562
+ when defined (release):
563
+ {.pop .}
0 commit comments