1- import macros, strutils
1+ import macros, strutils, tables, unicode
22
33type JsonError = object of ValueError
44
@@ -7,9 +7,9 @@ const whiteSpace = {' ', '\n', '\t', '\r'}
77proc parseJson [T](s: string , i: var int , v: var seq [T])
88proc parseJson [T:enum ](s: string , i: var int , v: var T)
99proc parseJson [T:object | ref object ](s: string , i: var int , v: var T)
10+ proc parseJson [T](s: string , i: var int , v: var Table [string , T])
1011
11-
12- template error (msg: string ) =
12+ template error (msg: string , i: int ) =
1313 # # Short cut to raise an exception.
1414 raise newException (JsonError , msg)
1515
@@ -28,11 +28,11 @@ proc eat(s: string, i: var int, c: char) =
2828 # # Will raise an exception if `c` is not found.
2929 eatSpace (s, i)
3030 if i >= s.len:
31- error (" Expected " & c & " but end reached." )
31+ error (" Expected " & c & " but end reached." , i )
3232 if s[i] == c:
3333 inc i
3434 else :
35- error (" Expected " & c & " at offset " & $ i & " . " )
35+ error (" Expected " & c & " at offset. " , i )
3636
3737proc parseSymbol (s: string , i: var int ): string =
3838 # # Will read a symbol and return it.
@@ -56,7 +56,7 @@ proc parseJson(s: string, i: var int, v: var bool) =
5656 of " false" :
5757 v = false
5858 else :
59- error (" Boolean true or false expected at offset " & $ i & " . " )
59+ error (" Boolean true or false expected. " , i )
6060
6161proc parseJson (s: string , i: var int , v: var SomeInteger ) =
6262 # # Will parse int8, uint8, int16, uint16, int32, uint32, int64, uint64 or
@@ -69,15 +69,40 @@ proc parseJson(s: string, i: var int, v: var SomeFloat) =
6969
7070proc parseJson (s: string , i: var int , v: var string ) =
7171 # # Parse string.
72+ # echo "S:", s[i .. min(i + 80, s.len-1)]
73+ eatSpace (s, i)
74+ if s[i] == 'n' :
75+ let what = parseSymbol (s, i)
76+ if what == " null" :
77+ return
78+ else :
79+ error (" Expected \" or null at offset." , i)
7280 eat (s, i, '"' )
7381 var j = i
7482 while i < s.len:
75- case s[i]
83+ let c = s[i]
84+ case c
7685 of '"' :
77- v = s[j ..< i]
7886 break
87+ of '\\ ' :
88+ inc i
89+ let c = s[i]
90+ case c
91+ of '"' , '\\ ' , '/' : v.add (c)
92+ of 'b' : v.add '\b '
93+ of 'f' : v.add '\f '
94+ of 'n' : v.add '\n '
95+ of 'r' : v.add '\r '
96+ of 't' : v.add '\t '
97+ of 'u' :
98+ inc i
99+ let u = parseHexInt (s[i ..< i + 4 ])
100+ i += 3
101+ v.add (Rune (u).toUTF8 ())
102+ else :
103+ v.add (c)
79104 else :
80- discard
105+ v. add (c)
81106 inc i
82107 eat (s, i, '"' )
83108
@@ -100,8 +125,10 @@ proc parseJson[T](s: string, i: var int, v: var seq[T]) =
100125
101126proc skipValue (s: string , i: var int ) =
102127 # # Used to skip values of extra fields.
128+ # echo "Skip:", s[i .. min(i + 80, s.len-1)]
103129 eatSpace (s, i)
104130 if s[i] == '{' :
131+ # echo "skip obj"
105132 eat (s, i, '{' )
106133 while i < s.len:
107134 eatSpace (s, i)
@@ -115,6 +142,7 @@ proc skipValue(s: string, i: var int) =
115142 inc i
116143 eat (s, i, '}' )
117144 elif s[i] == '[' :
145+ # echo "skip arr"
118146 eat (s, i, '[' )
119147 while i < s.len:
120148 eatSpace (s, i)
@@ -126,13 +154,11 @@ proc skipValue(s: string, i: var int) =
126154 inc i
127155 eat (s, i, ']' )
128156 elif s[i] == '"' :
129- eat (s, i, '"' )
130- while i < s.len:
131- inc i
132- if s[i] == '"' :
133- break
134- eat (s, i, '"' )
157+ # echo "skip str"
158+ var str: string
159+ parseJson (s, i, str)
135160 else :
161+ # echo "skip sym"
136162 discard parseSymbol (s, i)
137163
138164proc camelCase (s: string ): string =
@@ -189,8 +215,8 @@ proc parseJson[T:enum](s: string, i: var int, v: var T) =
189215 var strV: string
190216 if s[i] == '"' :
191217 parseJson (s, i, strV)
192- when compiles (enumHook [T] (strV)):
193- v = enumHook [T] (strV)
218+ when compiles (enumHook (strV, v )):
219+ enumHook (strV, v )
194220 else :
195221 v = parseEnum [T](strV)
196222 else :
@@ -199,6 +225,13 @@ proc parseJson[T:enum](s: string, i: var int, v: var T) =
199225
200226proc parseJson [T:object | ref object ](s: string , i: var int , v: var T) =
201227 # # Parse an object.
228+ eatSpace (s, i)
229+ if s[i] == 'n' :
230+ let what = parseSymbol (s, i)
231+ if what == " null" :
232+ return
233+ else :
234+ error (" Expected {} or null at offset." , i)
202235 eat (s, i, '{' )
203236 when compiles (newHook (v)):
204237 newHook (v)
@@ -219,6 +252,25 @@ proc parseJson[T:object|ref object](s: string, i: var int, v: var T) =
219252 break
220253 eat (s, i, '}' )
221254
255+ proc parseJson [T](s: string , i: var int , v: var Table [string , T]) =
256+ # # Parse an object.
257+ eat (s, i, '{' )
258+ while i < s.len:
259+ eatSpace (s, i)
260+ if s[i] == '}' :
261+ break
262+ var key: string
263+ parseJson (s, i, key)
264+ eat (s, i, ':' )
265+ var element: T
266+ parseJson (s, i, element)
267+ v[key] = element
268+ if s[i] == ',' :
269+ inc i
270+ else :
271+ break
272+ eat (s, i, '}' )
273+
222274proc fromJson * [T](s: string ): T =
223275 # # Takes json and outputs the object it represents.
224276 # # * Create little intermediate values.
0 commit comments