11import macros, strutils, tables, unicode
22
3- type JsonError = object of ValueError
3+ type JsonError * = object of ValueError
44
55const whiteSpace = {' ' , '\n ' , '\t ' , '\r ' }
66
7+ when defined (release):
8+ {.push checks : off .}
9+
710proc parseHook * [T](s: string , i: var int , v: var seq [T])
811proc parseHook * [T: enum ](s: string , i: var int , v: var T)
912proc 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) =
6164 else :
6265 # Its faster to do char by char scan:
6366 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' :
6568 i += 4
6669 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' :
6871 i += 5
6972 v = false
7073 else :
@@ -76,10 +79,14 @@ proc parseHook*(s: string, i: var int, v: var SomeUnsignedInt) =
7679 v = type (v)(parseInt (parseSymbol (s, i)))
7780 else :
7881 eatSpace (s, i)
79- var v2: uint64 = 0
82+ var
83+ v2: uint64 = 0
84+ startI = i
8085 while i < s.len and s[i] in {'0' .. '9' }:
8186 v2 = v2 * 10 + (s[i].ord - '0' .ord).uint64
8287 inc i
88+ if startI == i:
89+ error (" Number expected." , i)
8390 v = type (v)(v2)
8491
8592proc parseHook * (s: string , i: var int , v: var SomeSignedInt ) =
@@ -88,15 +95,18 @@ proc parseHook*(s: string, i: var int, v: var SomeSignedInt) =
8895 v = type (v)(parseInt (parseSymbol (s, i)))
8996 else :
9097 eatSpace (s, i)
91- if s[i] == '-' :
98+ if i < s.len and s[i] == '-' :
9299 var v2: uint64
93100 inc i
94101 parseHook (s, i, v2)
95102 v = - type (v)(v2)
96103 else :
97104 var v2: uint64
98105 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)
100110
101111proc parseHook * (s: string , i: var int , v: var SomeFloat ) =
102112 # # Will parse float32 and float64.
@@ -141,13 +151,13 @@ proc parseHook*[T](s: string, i: var int, v: var seq[T]) =
141151 eatChar (s, i, '[' )
142152 while i < s.len:
143153 eatSpace (s, i)
144- if s[i] == ']' :
154+ if i < s.len and s[i] == ']' :
145155 break
146156 var element: T
147157 parseHook (s, i, element)
148158 v.add (element)
149159 eatSpace (s, i)
150- if s[i] == ',' :
160+ if i < s.len and s[i] == ',' :
151161 inc i
152162 else :
153163 break
@@ -161,7 +171,7 @@ proc parseHook*[T: tuple](s: string, i: var int, v: var T) =
161171 eatSpace (s, i)
162172 parseHook (s, i, value)
163173 eatSpace (s, i)
164- if s[i] == ',' :
174+ if i < s.len and s[i] == ',' :
165175 inc i
166176 eatChar (s, i, ']' )
167177
@@ -173,38 +183,38 @@ proc parseHook*[T: array](s: string, i: var int, v: var T) =
173183 eatSpace (s, i)
174184 parseHook (s, i, value)
175185 eatSpace (s, i)
176- if s[i] == ',' :
186+ if i < s.len and s[i] == ',' :
177187 inc i
178188 eatChar (s, i, ']' )
179189
180190proc skipValue (s: string , i: var int ) =
181191 # # Used to skip values of extra fields.
182192 eatSpace (s, i)
183- if s[i] == '{' :
193+ if i < s.len and s[i] == '{' :
184194 eatChar (s, i, '{' )
185195 while i < s.len:
186196 eatSpace (s, i)
187- if s[i] == '}' :
197+ if i < s.len and s[i] == '}' :
188198 break
189199 skipValue (s, i)
190200 eatChar (s, i, ':' )
191201 skipValue (s, i)
192202 eatSpace (s, i)
193- if s[i] == ',' :
203+ if i < s.len and s[i] == ',' :
194204 inc i
195205 eatChar (s, i, '}' )
196- elif s[i] == '[' :
206+ elif i < s.len and s[i] == '[' :
197207 eatChar (s, i, '[' )
198208 while i < s.len:
199209 eatSpace (s, i)
200- if s[i] == ']' :
210+ if i < s.len and s[i] == ']' :
201211 break
202212 skipValue (s, i)
203213 eatSpace (s, i)
204- if s[i] == ',' :
214+ if i < s.len and s[i] == ',' :
205215 inc i
206216 eatChar (s, i, ']' )
207- elif s[i] == '"' :
217+ elif i < s.len and s[i] == '"' :
208218 var str: string
209219 parseHook (s, i, str)
210220 else :
@@ -264,25 +274,25 @@ macro fieldsMacro(v: typed, key: string) =
264274proc parseHook * [T: enum ](s: string , i: var int , v: var T) =
265275 eatSpace (s, i)
266276 var strV: string
267- if s[i] == '"' :
277+ if i < s.len and s[i] == '"' :
268278 parseHook (s, i, strV)
269279 when compiles (enumHook (strV, v)):
270280 enumHook (strV, v)
271281 else :
272- v = parseEnum [T](strV)
282+ try :
283+ v = parseEnum [T](strV)
284+ except :
285+ error (" Can't parse enum." , i)
273286 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)
276292
277293proc parseHook * [T: object | ref object ](s: string , i: var int , v: var T) =
278294 # # Parse an object.
279295 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)
286296 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' :
287297 i += 4
288298 return
@@ -293,7 +303,7 @@ proc parseHook*[T: object|ref object](s: string, i: var int, v: var T) =
293303 new (v)
294304 while i < s.len:
295305 eatSpace (s, i)
296- if s[i] == '}' :
306+ if i < s.len and s[i] == '}' :
297307 break
298308 var key: string
299309 parseHook (s, i, key)
@@ -302,7 +312,7 @@ proc parseHook*[T: object|ref object](s: string, i: var int, v: var T) =
302312 renameHook (v, key)
303313 fieldsMacro (v, key)
304314 eatSpace (s, i)
305- if s[i] == ',' :
315+ if i < s.len and s[i] == ',' :
306316 inc i
307317 else :
308318 break
@@ -315,35 +325,44 @@ proc parseHook*[T](s: string, i: var int, v: var Table[string, T]) =
315325 eatChar (s, i, '{' )
316326 while i < s.len:
317327 eatSpace (s, i)
318- if s[i] == '}' :
328+ if i < s.len and s[i] == '}' :
319329 break
320330 var key: string
321331 parseHook (s, i, key)
322332 eatChar (s, i, ':' )
323333 var element: T
324334 parseHook (s, i, element)
325335 v[key] = element
326- if s[i] == ',' :
336+ if i < s.len and s[i] == ',' :
327337 inc i
328338 else :
329339 break
330340 eatChar (s, i, '}' )
331341
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 =
333352 # # Takes json and outputs the object it represents.
334353 # # * Extra json fields are ignored.
335354 # # * Missing json fields keep their default values.
336355 # # * `proc newHook(foo: var ...)` Can be used to populate default values.
337-
338356 var i = 0
339- parseHook (s, i, result )
357+ s. parseHook (i, result )
340358
341359proc dumpHook * (s: var string , v: bool )
342360proc dumpHook * (s: var string , v: uint | uint8 | uint16 | uint32 | uint64 )
343361proc dumpHook * (s: var string , v: int | int8 | int16 | int32 | int64 )
344362proc dumpHook * (s: var string , v: string )
345363proc dumpHook * (s: var string , v: char )
346364proc dumpHook * (s: var string , v: tuple )
365+ proc dumpHook * (s: var string , v: enum )
347366proc dumpHook * [N, T](s: var string , v: array [N, T])
348367proc dumpHook * [T](s: var string , v: seq [T])
349368proc dumpHook * (s: var string , v: object )
@@ -355,9 +374,6 @@ proc dumpHook*(s: var string, v: bool) =
355374 else :
356375 s.add " false"
357376
358- when defined (release):
359- {.push checks : off .}
360-
361377const lookup = block :
362378 # # Generate 00, 01, 02 ... 99 pairs.
363379 var s = " "
@@ -408,9 +424,6 @@ proc dumpHook*(s: var string, v: int|int8|int16|int32|int64) =
408424 else :
409425 dumpHook (s, v.uint64 )
410426
411- when defined (release):
412- {.pop .}
413-
414427proc dumpHook * (s: var string , v: SomeFloat ) =
415428 s.add $ v
416429
@@ -478,6 +491,9 @@ proc dumpHook*(s: var string, v: tuple) =
478491 inc i
479492 s.add ']'
480493
494+ proc dumpHook * (s: var string , v: enum ) =
495+ s.dumpHook ($ v)
496+
481497proc dumpHook * [N, T](s: var string , v: array [N, T]) =
482498 s.add '['
483499 var i = 0
@@ -541,3 +557,7 @@ template toStaticJson*(v: untyped): static[string] =
541557# ## This will turn v into json at compile time and return the json string.
542558# const s = v.toJsonDynamic()
543559# s
560+
561+
562+ when defined (release):
563+ {.pop .}
0 commit comments