json.nim 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements a simple high performance `JSON`:idx:
  10. ## parser. JSON (JavaScript Object Notation) is a lightweight
  11. ## data-interchange format that is easy for humans to read and write
  12. ## (unlike XML). It is easy for machines to parse and generate.
  13. ## JSON is based on a subset of the JavaScript Programming Language,
  14. ## Standard ECMA-262 3rd Edition - December 1999.
  15. ##
  16. ## Overview
  17. ## ========
  18. ##
  19. ## Parsing JSON
  20. ## ------------
  21. ##
  22. ## JSON often arrives into your program (via an API or a file) as a ``string``.
  23. ## The first step is to change it from its serialized form into a nested object
  24. ## structure called a ``JsonNode``.
  25. ##
  26. ## The ``parseJson`` procedure takes a string containing JSON and returns a
  27. ## ``JsonNode`` object. This is an object variant and it is either a
  28. ## ``JObject``, ``JArray``, ``JString``, ``JInt``, ``JFloat``, ``JBool`` or
  29. ## ``JNull``. You check the kind of this object variant by using the ``kind``
  30. ## accessor.
  31. ##
  32. ## For a ``JsonNode`` who's kind is ``JObject``, you can access its fields using
  33. ## the ``[]`` operator. The following example shows how to do this:
  34. ##
  35. ## .. code-block:: Nim
  36. ## import json
  37. ##
  38. ## let jsonNode = parseJson("""{"key": 3.14}""")
  39. ##
  40. ## doAssert jsonNode.kind == JObject
  41. ## doAssert jsonNode["key"].kind == JFloat
  42. ##
  43. ## Reading values
  44. ## --------------
  45. ##
  46. ## Once you have a ``JsonNode``, retrieving the values can then be achieved
  47. ## by using one of the helper procedures, which include:
  48. ##
  49. ## * ``getInt``
  50. ## * ``getFloat``
  51. ## * ``getStr``
  52. ## * ``getBool``
  53. ##
  54. ## To retrieve the value of ``"key"`` you can do the following:
  55. ##
  56. ## .. code-block:: Nim
  57. ## import json
  58. ##
  59. ## let jsonNode = parseJson("""{"key": 3.14}""")
  60. ##
  61. ## doAssert jsonNode["key"].getFloat() == 3.14
  62. ##
  63. ## **Important:** The ``[]`` operator will raise an exception when the
  64. ## specified field does not exist.
  65. ##
  66. ## Handling optional keys
  67. ## ----------------------
  68. ##
  69. ## By using the ``{}`` operator instead of ``[]``, it will return ``nil``
  70. ## when the field is not found. The ``get``-family of procedures will return a
  71. ## type's default value when called on ``nil``.
  72. ##
  73. ## .. code-block:: Nim
  74. ## import json
  75. ##
  76. ## let jsonNode = parseJson("{}")
  77. ##
  78. ## doAssert jsonNode{"nope"}.getInt() == 0
  79. ## doAssert jsonNode{"nope"}.getFloat() == 0
  80. ## doAssert jsonNode{"nope"}.getStr() == ""
  81. ## doAssert jsonNode{"nope"}.getBool() == false
  82. ##
  83. ## Using default values
  84. ## --------------------
  85. ##
  86. ## The ``get``-family helpers also accept an additional parameter which allow
  87. ## you to fallback to a default value should the key's values be ``null``:
  88. ##
  89. ## .. code-block:: Nim
  90. ## import json
  91. ##
  92. ## let jsonNode = parseJson("""{"key": 3.14, "key2": null}""")
  93. ##
  94. ## doAssert jsonNode["key"].getFloat(6.28) == 3.14
  95. ## doAssert jsonNode["key2"].getFloat(3.14) == 3.14
  96. ## doAssert jsonNode{"nope"}.getFloat(3.14) == 3.14 # note the {}
  97. ##
  98. ## Unmarshalling
  99. ## -------------
  100. ##
  101. ## In addition to reading dynamic data, Nim can also unmarshal JSON directly
  102. ## into a type with the ``to`` macro.
  103. ##
  104. ## .. code-block:: Nim
  105. ## import json
  106. ##
  107. ## type
  108. ## User = object
  109. ## name: string
  110. ## age: int
  111. ##
  112. ## let userJson = parseJson("""{ "name": "Nim", "age": 12 }""")
  113. ## let user = to(userJson, User)
  114. ##
  115. ## Creating JSON
  116. ## =============
  117. ##
  118. ## This module can also be used to comfortably create JSON using the ``%*``
  119. ## operator:
  120. ##
  121. ## .. code-block:: nim
  122. ## import json
  123. ##
  124. ## var hisName = "John"
  125. ## let herAge = 31
  126. ## var j = %*
  127. ## [
  128. ## { "name": hisName, "age": 30 },
  129. ## { "name": "Susan", "age": herAge }
  130. ## ]
  131. ##
  132. ## var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]}
  133. ## j2["details"] = %* {"age":35, "pi":3.1415}
  134. ## echo j2
  135. runnableExamples:
  136. ## Note: for JObject, key ordering is preserved, unlike in some languages,
  137. ## this is convenient for some use cases. Example:
  138. type Foo = object
  139. a1, a2, a0, a3, a4: int
  140. doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}"""
  141. import
  142. hashes, tables, strutils, lexbase, streams, macros, parsejson,
  143. options
  144. export
  145. tables.`$`
  146. export
  147. parsejson.JsonEventKind, parsejson.JsonError, JsonParser, JsonKindError,
  148. open, close, str, getInt, getFloat, kind, getColumn, getLine, getFilename,
  149. errorMsg, errorMsgExpected, next, JsonParsingError, raiseParseErr
  150. type
  151. JsonNodeKind* = enum ## possible JSON node types
  152. JNull,
  153. JBool,
  154. JInt,
  155. JFloat,
  156. JString,
  157. JObject,
  158. JArray
  159. JsonNode* = ref JsonNodeObj ## JSON node
  160. JsonNodeObj* {.acyclic.} = object
  161. case kind*: JsonNodeKind
  162. of JString:
  163. str*: string
  164. of JInt:
  165. num*: BiggestInt
  166. of JFloat:
  167. fnum*: float
  168. of JBool:
  169. bval*: bool
  170. of JNull:
  171. nil
  172. of JObject:
  173. fields*: OrderedTable[string, JsonNode]
  174. of JArray:
  175. elems*: seq[JsonNode]
  176. proc newJString*(s: string): JsonNode =
  177. ## Creates a new `JString JsonNode`.
  178. result = JsonNode(kind: JString, str: s)
  179. proc newJStringMove(s: string): JsonNode =
  180. result = JsonNode(kind: JString)
  181. shallowCopy(result.str, s)
  182. proc newJInt*(n: BiggestInt): JsonNode =
  183. ## Creates a new `JInt JsonNode`.
  184. result = JsonNode(kind: JInt, num: n)
  185. proc newJFloat*(n: float): JsonNode =
  186. ## Creates a new `JFloat JsonNode`.
  187. result = JsonNode(kind: JFloat, fnum: n)
  188. proc newJBool*(b: bool): JsonNode =
  189. ## Creates a new `JBool JsonNode`.
  190. result = JsonNode(kind: JBool, bval: b)
  191. proc newJNull*(): JsonNode =
  192. ## Creates a new `JNull JsonNode`.
  193. result = JsonNode(kind: JNull)
  194. proc newJObject*(): JsonNode =
  195. ## Creates a new `JObject JsonNode`
  196. result = JsonNode(kind: JObject, fields: initOrderedTable[string, JsonNode](4))
  197. proc newJArray*(): JsonNode =
  198. ## Creates a new `JArray JsonNode`
  199. result = JsonNode(kind: JArray, elems: @[])
  200. proc getStr*(n: JsonNode, default: string = ""): string =
  201. ## Retrieves the string value of a `JString JsonNode`.
  202. ##
  203. ## Returns ``default`` if ``n`` is not a ``JString``, or if ``n`` is nil.
  204. if n.isNil or n.kind != JString: return default
  205. else: return n.str
  206. proc getInt*(n: JsonNode, default: int = 0): int =
  207. ## Retrieves the int value of a `JInt JsonNode`.
  208. ##
  209. ## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
  210. if n.isNil or n.kind != JInt: return default
  211. else: return int(n.num)
  212. proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
  213. ## Retrieves the BiggestInt value of a `JInt JsonNode`.
  214. ##
  215. ## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
  216. if n.isNil or n.kind != JInt: return default
  217. else: return n.num
  218. proc getFloat*(n: JsonNode, default: float = 0.0): float =
  219. ## Retrieves the float value of a `JFloat JsonNode`.
  220. ##
  221. ## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil.
  222. if n.isNil: return default
  223. case n.kind
  224. of JFloat: return n.fnum
  225. of JInt: return float(n.num)
  226. else: return default
  227. proc getBool*(n: JsonNode, default: bool = false): bool =
  228. ## Retrieves the bool value of a `JBool JsonNode`.
  229. ##
  230. ## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
  231. if n.isNil or n.kind != JBool: return default
  232. else: return n.bval
  233. proc getFields*(n: JsonNode,
  234. default = initOrderedTable[string, JsonNode](4)):
  235. OrderedTable[string, JsonNode] =
  236. ## Retrieves the key, value pairs of a `JObject JsonNode`.
  237. ##
  238. ## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
  239. if n.isNil or n.kind != JObject: return default
  240. else: return n.fields
  241. proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
  242. ## Retrieves the array of a `JArray JsonNode`.
  243. ##
  244. ## Returns ``default`` if ``n`` is not a ``JArray``, or if ``n`` is nil.
  245. if n.isNil or n.kind != JArray: return default
  246. else: return n.elems
  247. proc add*(father, child: JsonNode) =
  248. ## Adds `child` to a JArray node `father`.
  249. assert father.kind == JArray
  250. father.elems.add(child)
  251. proc add*(obj: JsonNode, key: string, val: JsonNode) =
  252. ## Sets a field from a `JObject`.
  253. assert obj.kind == JObject
  254. obj.fields[key] = val
  255. proc `%`*(s: string): JsonNode =
  256. ## Generic constructor for JSON data. Creates a new `JString JsonNode`.
  257. result = JsonNode(kind: JString, str: s)
  258. proc `%`*(n: uint): JsonNode =
  259. ## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
  260. result = JsonNode(kind: JInt, num: BiggestInt(n))
  261. proc `%`*(n: int): JsonNode =
  262. ## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
  263. result = JsonNode(kind: JInt, num: n)
  264. proc `%`*(n: BiggestUInt): JsonNode =
  265. ## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
  266. result = JsonNode(kind: JInt, num: BiggestInt(n))
  267. proc `%`*(n: BiggestInt): JsonNode =
  268. ## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
  269. result = JsonNode(kind: JInt, num: n)
  270. proc `%`*(n: float): JsonNode =
  271. ## Generic constructor for JSON data. Creates a new `JFloat JsonNode`.
  272. result = JsonNode(kind: JFloat, fnum: n)
  273. proc `%`*(b: bool): JsonNode =
  274. ## Generic constructor for JSON data. Creates a new `JBool JsonNode`.
  275. result = JsonNode(kind: JBool, bval: b)
  276. proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
  277. ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
  278. if keyVals.len == 0: return newJArray()
  279. result = newJObject()
  280. for key, val in items(keyVals): result.fields[key] = val
  281. template `%`*(j: JsonNode): JsonNode = j
  282. proc `%`*[T](elements: openArray[T]): JsonNode =
  283. ## Generic constructor for JSON data. Creates a new `JArray JsonNode`
  284. result = newJArray()
  285. for elem in elements: result.add(%elem)
  286. proc `%`*[T](table: Table[string, T]|OrderedTable[string, T]): JsonNode =
  287. ## Generic constructor for JSON data. Creates a new ``JObject JsonNode``.
  288. result = newJObject()
  289. for k, v in table: result[k] = %v
  290. proc `%`*[T](opt: Option[T]): JsonNode =
  291. ## Generic constructor for JSON data. Creates a new ``JNull JsonNode``
  292. ## if ``opt`` is empty, otherwise it delegates to the underlying value.
  293. if opt.isSome: %opt.get else: newJNull()
  294. when false:
  295. # For 'consistency' we could do this, but that only pushes people further
  296. # into that evil comfort zone where they can use Nim without understanding it
  297. # causing problems later on.
  298. proc `%`*(elements: set[bool]): JsonNode =
  299. ## Generic constructor for JSON data. Creates a new `JObject JsonNode`.
  300. ## This can only be used with the empty set ``{}`` and is supported
  301. ## to prevent the gotcha ``%*{}`` which used to produce an empty
  302. ## JSON array.
  303. result = newJObject()
  304. assert false notin elements, "usage error: only empty sets allowed"
  305. assert true notin elements, "usage error: only empty sets allowed"
  306. proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
  307. ## Sets a field from a `JObject`.
  308. assert(obj.kind == JObject)
  309. obj.fields[key] = val
  310. proc `%`*[T: object](o: T): JsonNode =
  311. ## Construct JsonNode from tuples and objects.
  312. result = newJObject()
  313. for k, v in o.fieldPairs: result[k] = %v
  314. proc `%`*(o: ref object): JsonNode =
  315. ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
  316. if o.isNil:
  317. result = newJNull()
  318. else:
  319. result = %(o[])
  320. proc `%`*(o: enum): JsonNode =
  321. ## Construct a JsonNode that represents the specified enum value as a
  322. ## string. Creates a new ``JString JsonNode``.
  323. result = %($o)
  324. proc toJson(x: NimNode): NimNode {.compileTime.} =
  325. case x.kind
  326. of nnkBracket: # array
  327. if x.len == 0: return newCall(bindSym"newJArray")
  328. result = newNimNode(nnkBracket)
  329. for i in 0 ..< x.len:
  330. result.add(toJson(x[i]))
  331. result = newCall(bindSym("%", brOpen), result)
  332. of nnkTableConstr: # object
  333. if x.len == 0: return newCall(bindSym"newJObject")
  334. result = newNimNode(nnkTableConstr)
  335. for i in 0 ..< x.len:
  336. x[i].expectKind nnkExprColonExpr
  337. result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1]))
  338. result = newCall(bindSym("%", brOpen), result)
  339. of nnkCurly: # empty object
  340. x.expectLen(0)
  341. result = newCall(bindSym"newJObject")
  342. of nnkNilLit:
  343. result = newCall(bindSym"newJNull")
  344. of nnkPar:
  345. if x.len == 1: result = toJson(x[0])
  346. else: result = newCall(bindSym("%", brOpen), x)
  347. else:
  348. result = newCall(bindSym("%", brOpen), x)
  349. macro `%*`*(x: untyped): untyped =
  350. ## Convert an expression to a JsonNode directly, without having to specify
  351. ## `%` for every element.
  352. result = toJson(x)
  353. proc `==`*(a, b: JsonNode): bool =
  354. ## Check two nodes for equality
  355. if a.isNil:
  356. if b.isNil: return true
  357. return false
  358. elif b.isNil or a.kind != b.kind:
  359. return false
  360. else:
  361. case a.kind
  362. of JString:
  363. result = a.str == b.str
  364. of JInt:
  365. result = a.num == b.num
  366. of JFloat:
  367. result = a.fnum == b.fnum
  368. of JBool:
  369. result = a.bval == b.bval
  370. of JNull:
  371. result = true
  372. of JArray:
  373. result = a.elems == b.elems
  374. of JObject:
  375. # we cannot use OrderedTable's equality here as
  376. # the order does not matter for equality here.
  377. if a.fields.len != b.fields.len: return false
  378. for key, val in a.fields:
  379. if not b.fields.hasKey(key): return false
  380. if b.fields[key] != val: return false
  381. result = true
  382. proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
  383. proc hash*(n: JsonNode): Hash =
  384. ## Compute the hash for a JSON node
  385. case n.kind
  386. of JArray:
  387. result = hash(n.elems)
  388. of JObject:
  389. result = hash(n.fields)
  390. of JInt:
  391. result = hash(n.num)
  392. of JFloat:
  393. result = hash(n.fnum)
  394. of JBool:
  395. result = hash(n.bval.int)
  396. of JString:
  397. result = hash(n.str)
  398. of JNull:
  399. result = Hash(0)
  400. proc hash*(n: OrderedTable[string, JsonNode]): Hash =
  401. for key, val in n:
  402. result = result xor (hash(key) !& hash(val))
  403. result = !$result
  404. proc len*(n: JsonNode): int =
  405. ## If `n` is a `JArray`, it returns the number of elements.
  406. ## If `n` is a `JObject`, it returns the number of pairs.
  407. ## Else it returns 0.
  408. case n.kind
  409. of JArray: result = n.elems.len
  410. of JObject: result = n.fields.len
  411. else: discard
  412. proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
  413. ## Gets a field from a `JObject`, which must not be nil.
  414. ## If the value at `name` does not exist, raises KeyError.
  415. assert(not isNil(node))
  416. assert(node.kind == JObject)
  417. when defined(nimJsonGet):
  418. if not node.fields.hasKey(name): return nil
  419. result = node.fields[name]
  420. proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
  421. ## Gets the node at `index` in an Array. Result is undefined if `index`
  422. ## is out of bounds, but as long as array bound checks are enabled it will
  423. ## result in an exception.
  424. assert(not isNil(node))
  425. assert(node.kind == JArray)
  426. return node.elems[index]
  427. proc hasKey*(node: JsonNode, key: string): bool =
  428. ## Checks if `key` exists in `node`.
  429. assert(node.kind == JObject)
  430. result = node.fields.hasKey(key)
  431. proc contains*(node: JsonNode, key: string): bool =
  432. ## Checks if `key` exists in `node`.
  433. assert(node.kind == JObject)
  434. node.fields.hasKey(key)
  435. proc contains*(node: JsonNode, val: JsonNode): bool =
  436. ## Checks if `val` exists in array `node`.
  437. assert(node.kind == JArray)
  438. find(node.elems, val) >= 0
  439. proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
  440. ## Traverses the node and gets the given value. If any of the
  441. ## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the
  442. ## intermediate data structures is not an object.
  443. ##
  444. ## This proc can be used to create tree structures on the
  445. ## fly (sometimes called `autovivification`:idx:):
  446. ##
  447. ## .. code-block:: nim
  448. ## myjson{"parent", "child", "grandchild"} = newJInt(1)
  449. ##
  450. result = node
  451. for key in keys:
  452. if isNil(result) or result.kind != JObject:
  453. return nil
  454. result = result.fields.getOrDefault(key)
  455. proc `{}`*(node: JsonNode, index: varargs[int]): JsonNode =
  456. ## Traverses the node and gets the given value. If any of the
  457. ## indexes do not exist, returns ``nil``. Also returns ``nil`` if one of the
  458. ## intermediate data structures is not an array.
  459. result = node
  460. for i in index:
  461. if isNil(result) or result.kind != JArray or i >= node.len:
  462. return nil
  463. result = result.elems[i]
  464. proc getOrDefault*(node: JsonNode, key: string): JsonNode =
  465. ## Gets a field from a `node`. If `node` is nil or not an object or
  466. ## value at `key` does not exist, returns nil
  467. if not isNil(node) and node.kind == JObject:
  468. result = node.fields.getOrDefault(key)
  469. template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode,
  470. key: string): JsonNode = node.getOrDefault(key)
  471. proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
  472. ## Traverses the node and tries to set the value at the given location
  473. ## to ``value``. If any of the keys are missing, they are added.
  474. var node = node
  475. for i in 0..(keys.len-2):
  476. if not node.hasKey(keys[i]):
  477. node[keys[i]] = newJObject()
  478. node = node[keys[i]]
  479. node[keys[keys.len-1]] = value
  480. proc delete*(obj: JsonNode, key: string) =
  481. ## Deletes ``obj[key]``.
  482. assert(obj.kind == JObject)
  483. if not obj.fields.hasKey(key):
  484. raise newException(KeyError, "key not in object")
  485. obj.fields.del(key)
  486. proc copy*(p: JsonNode): JsonNode =
  487. ## Performs a deep copy of `a`.
  488. case p.kind
  489. of JString:
  490. result = newJString(p.str)
  491. of JInt:
  492. result = newJInt(p.num)
  493. of JFloat:
  494. result = newJFloat(p.fnum)
  495. of JBool:
  496. result = newJBool(p.bval)
  497. of JNull:
  498. result = newJNull()
  499. of JObject:
  500. result = newJObject()
  501. for key, val in pairs(p.fields):
  502. result.fields[key] = copy(val)
  503. of JArray:
  504. result = newJArray()
  505. for i in items(p.elems):
  506. result.elems.add(copy(i))
  507. # ------------- pretty printing ----------------------------------------------
  508. proc indent(s: var string, i: int) =
  509. s.add(spaces(i))
  510. proc newIndent(curr, indent: int, ml: bool): int =
  511. if ml: return curr + indent
  512. else: return indent
  513. proc nl(s: var string, ml: bool) =
  514. s.add(if ml: "\n" else: " ")
  515. proc escapeJsonUnquoted*(s: string; result: var string) =
  516. ## Converts a string `s` to its JSON representation without quotes.
  517. ## Appends to ``result``.
  518. for c in s:
  519. case c
  520. of '\L': result.add("\\n")
  521. of '\b': result.add("\\b")
  522. of '\f': result.add("\\f")
  523. of '\t': result.add("\\t")
  524. of '\v': result.add("\\v")
  525. of '\r': result.add("\\r")
  526. of '"': result.add("\\\"")
  527. of '\0'..'\7': result.add("\\u000" & $ord(c))
  528. of '\14'..'\31': result.add("\\u00" & toHex(ord(c), 2))
  529. of '\\': result.add("\\\\")
  530. else: result.add(c)
  531. proc escapeJsonUnquoted*(s: string): string =
  532. ## Converts a string `s` to its JSON representation without quotes.
  533. result = newStringOfCap(s.len + s.len shr 3)
  534. escapeJsonUnquoted(s, result)
  535. proc escapeJson*(s: string; result: var string) =
  536. ## Converts a string `s` to its JSON representation with quotes.
  537. ## Appends to ``result``.
  538. result.add("\"")
  539. escapeJsonUnquoted(s, result)
  540. result.add("\"")
  541. proc escapeJson*(s: string): string =
  542. ## Converts a string `s` to its JSON representation with quotes.
  543. result = newStringOfCap(s.len + s.len shr 3)
  544. escapeJson(s, result)
  545. proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
  546. lstArr = false, currIndent = 0) =
  547. case node.kind
  548. of JObject:
  549. if lstArr: result.indent(currIndent) # Indentation
  550. if node.fields.len > 0:
  551. result.add("{")
  552. result.nl(ml) # New line
  553. var i = 0
  554. for key, val in pairs(node.fields):
  555. if i > 0:
  556. result.add(",")
  557. result.nl(ml) # New Line
  558. inc i
  559. # Need to indent more than {
  560. result.indent(newIndent(currIndent, indent, ml))
  561. escapeJson(key, result)
  562. result.add(": ")
  563. toPretty(result, val, indent, ml, false,
  564. newIndent(currIndent, indent, ml))
  565. result.nl(ml)
  566. result.indent(currIndent) # indent the same as {
  567. result.add("}")
  568. else:
  569. result.add("{}")
  570. of JString:
  571. if lstArr: result.indent(currIndent)
  572. escapeJson(node.str, result)
  573. of JInt:
  574. if lstArr: result.indent(currIndent)
  575. when defined(js): result.add($node.num)
  576. else: result.addInt(node.num)
  577. of JFloat:
  578. if lstArr: result.indent(currIndent)
  579. # Fixme: implement new system.add ops for the JS target
  580. when defined(js): result.add($node.fnum)
  581. else: result.addFloat(node.fnum)
  582. of JBool:
  583. if lstArr: result.indent(currIndent)
  584. result.add(if node.bval: "true" else: "false")
  585. of JArray:
  586. if lstArr: result.indent(currIndent)
  587. if len(node.elems) != 0:
  588. result.add("[")
  589. result.nl(ml)
  590. for i in 0..len(node.elems)-1:
  591. if i > 0:
  592. result.add(",")
  593. result.nl(ml) # New Line
  594. toPretty(result, node.elems[i], indent, ml,
  595. true, newIndent(currIndent, indent, ml))
  596. result.nl(ml)
  597. result.indent(currIndent)
  598. result.add("]")
  599. else: result.add("[]")
  600. of JNull:
  601. if lstArr: result.indent(currIndent)
  602. result.add("null")
  603. proc pretty*(node: JsonNode, indent = 2): string =
  604. ## Returns a JSON Representation of `node`, with indentation and
  605. ## on multiple lines.
  606. ##
  607. ## Similar to prettyprint in Python.
  608. runnableExamples:
  609. let j = %* {"name": "Isaac", "books": ["Robot Dreams"],
  610. "details": {"age": 35, "pi": 3.1415}}
  611. doAssert pretty(j) == """
  612. {
  613. "name": "Isaac",
  614. "books": [
  615. "Robot Dreams"
  616. ],
  617. "details": {
  618. "age": 35,
  619. "pi": 3.1415
  620. }
  621. }"""
  622. result = ""
  623. toPretty(result, node, indent)
  624. proc toUgly*(result: var string, node: JsonNode) =
  625. ## Converts `node` to its JSON Representation, without
  626. ## regard for human readability. Meant to improve ``$`` string
  627. ## conversion performance.
  628. ##
  629. ## JSON representation is stored in the passed `result`
  630. ##
  631. ## This provides higher efficiency than the ``pretty`` procedure as it
  632. ## does **not** attempt to format the resulting JSON to make it human readable.
  633. var comma = false
  634. case node.kind:
  635. of JArray:
  636. result.add "["
  637. for child in node.elems:
  638. if comma: result.add ","
  639. else: comma = true
  640. result.toUgly child
  641. result.add "]"
  642. of JObject:
  643. result.add "{"
  644. for key, value in pairs(node.fields):
  645. if comma: result.add ","
  646. else: comma = true
  647. key.escapeJson(result)
  648. result.add ":"
  649. result.toUgly value
  650. result.add "}"
  651. of JString:
  652. node.str.escapeJson(result)
  653. of JInt:
  654. when defined(js): result.add($node.num)
  655. else: result.addInt(node.num)
  656. of JFloat:
  657. when defined(js): result.add($node.fnum)
  658. else: result.addFloat(node.fnum)
  659. of JBool:
  660. result.add(if node.bval: "true" else: "false")
  661. of JNull:
  662. result.add "null"
  663. proc `$`*(node: JsonNode): string =
  664. ## Converts `node` to its JSON Representation on one line.
  665. result = newStringOfCap(node.len shl 1)
  666. toUgly(result, node)
  667. iterator items*(node: JsonNode): JsonNode =
  668. ## Iterator for the items of `node`. `node` has to be a JArray.
  669. assert node.kind == JArray
  670. for i in items(node.elems):
  671. yield i
  672. iterator mitems*(node: var JsonNode): var JsonNode =
  673. ## Iterator for the items of `node`. `node` has to be a JArray. Items can be
  674. ## modified.
  675. assert node.kind == JArray
  676. for i in mitems(node.elems):
  677. yield i
  678. iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
  679. ## Iterator for the child elements of `node`. `node` has to be a JObject.
  680. assert node.kind == JObject
  681. for key, val in pairs(node.fields):
  682. yield (key, val)
  683. iterator keys*(node: JsonNode): string =
  684. ## Iterator for the keys in `node`. `node` has to be a JObject.
  685. assert node.kind == JObject
  686. for key in node.fields.keys:
  687. yield key
  688. iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
  689. ## Iterator for the child elements of `node`. `node` has to be a JObject.
  690. ## Values can be modified
  691. assert node.kind == JObject
  692. for key, val in mpairs(node.fields):
  693. yield (key, val)
  694. proc parseJson(p: var JsonParser): JsonNode =
  695. ## Parses JSON from a JSON Parser `p`.
  696. case p.tok
  697. of tkString:
  698. # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
  699. result = newJStringMove(p.a)
  700. p.a = ""
  701. discard getTok(p)
  702. of tkInt:
  703. result = newJInt(parseBiggestInt(p.a))
  704. discard getTok(p)
  705. of tkFloat:
  706. result = newJFloat(parseFloat(p.a))
  707. discard getTok(p)
  708. of tkTrue:
  709. result = newJBool(true)
  710. discard getTok(p)
  711. of tkFalse:
  712. result = newJBool(false)
  713. discard getTok(p)
  714. of tkNull:
  715. result = newJNull()
  716. discard getTok(p)
  717. of tkCurlyLe:
  718. result = newJObject()
  719. discard getTok(p)
  720. while p.tok != tkCurlyRi:
  721. if p.tok != tkString:
  722. raiseParseErr(p, "string literal as key")
  723. var key = p.a
  724. discard getTok(p)
  725. eat(p, tkColon)
  726. var val = parseJson(p)
  727. result[key] = val
  728. if p.tok != tkComma: break
  729. discard getTok(p)
  730. eat(p, tkCurlyRi)
  731. of tkBracketLe:
  732. result = newJArray()
  733. discard getTok(p)
  734. while p.tok != tkBracketRi:
  735. result.add(parseJson(p))
  736. if p.tok != tkComma: break
  737. discard getTok(p)
  738. eat(p, tkBracketRi)
  739. of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof:
  740. raiseParseErr(p, "{")
  741. iterator parseJsonFragments*(s: Stream, filename: string = ""): JsonNode =
  742. ## Parses from a stream `s` into `JsonNodes`. `filename` is only needed
  743. ## for nice error messages.
  744. ## The JSON fragments are separated by whitespace. This can be substantially
  745. ## faster than the comparable loop
  746. ## ``for x in splitWhitespace(s): yield parseJson(x)``.
  747. ## This closes the stream `s` after it's done.
  748. var p: JsonParser
  749. p.open(s, filename)
  750. try:
  751. discard getTok(p) # read first token
  752. while p.tok != tkEof:
  753. yield p.parseJson()
  754. finally:
  755. p.close()
  756. proc parseJson*(s: Stream, filename: string = ""): JsonNode =
  757. ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed
  758. ## for nice error messages.
  759. ## If `s` contains extra data, it will raise `JsonParsingError`.
  760. ## This closes the stream `s` after it's done.
  761. var p: JsonParser
  762. p.open(s, filename)
  763. try:
  764. discard getTok(p) # read first token
  765. result = p.parseJson()
  766. eat(p, tkEof) # check if there is no extra data
  767. finally:
  768. p.close()
  769. when defined(js):
  770. from math import `mod`
  771. type
  772. JSObject = object
  773. proc parseNativeJson(x: cstring): JSObject {.importc: "JSON.parse".}
  774. proc getVarType(x: JSObject): JsonNodeKind =
  775. result = JNull
  776. proc getProtoName(y: JSObject): cstring
  777. {.importc: "Object.prototype.toString.call".}
  778. case $getProtoName(x) # TODO: Implicit returns fail here.
  779. of "[object Array]": return JArray
  780. of "[object Object]": return JObject
  781. of "[object Number]":
  782. if cast[float](x) mod 1.0 == 0:
  783. return JInt
  784. else:
  785. return JFloat
  786. of "[object Boolean]": return JBool
  787. of "[object Null]": return JNull
  788. of "[object String]": return JString
  789. else: assert false
  790. proc len(x: JSObject): int =
  791. assert x.getVarType == JArray
  792. asm """
  793. `result` = `x`.length;
  794. """
  795. proc `[]`(x: JSObject, y: string): JSObject =
  796. assert x.getVarType == JObject
  797. asm """
  798. `result` = `x`[`y`];
  799. """
  800. proc `[]`(x: JSObject, y: int): JSObject =
  801. assert x.getVarType == JArray
  802. asm """
  803. `result` = `x`[`y`];
  804. """
  805. proc convertObject(x: JSObject): JsonNode =
  806. case getVarType(x)
  807. of JArray:
  808. result = newJArray()
  809. for i in 0 ..< x.len:
  810. result.add(x[i].convertObject())
  811. of JObject:
  812. result = newJObject()
  813. asm """for (var property in `x`) {
  814. if (`x`.hasOwnProperty(property)) {
  815. """
  816. var nimProperty: cstring
  817. var nimValue: JSObject
  818. asm "`nimProperty` = property; `nimValue` = `x`[property];"
  819. result[$nimProperty] = nimValue.convertObject()
  820. asm "}}"
  821. of JInt:
  822. result = newJInt(cast[int](x))
  823. of JFloat:
  824. result = newJFloat(cast[float](x))
  825. of JString:
  826. result = newJString($cast[cstring](x))
  827. of JBool:
  828. result = newJBool(cast[bool](x))
  829. of JNull:
  830. result = newJNull()
  831. proc parseJson*(buffer: string): JsonNode =
  832. when nimvm:
  833. return parseJson(newStringStream(buffer), "input")
  834. else:
  835. return parseNativeJson(buffer).convertObject()
  836. else:
  837. proc parseJson*(buffer: string): JsonNode =
  838. ## Parses JSON from `buffer`.
  839. ## If `buffer` contains extra data, it will raise `JsonParsingError`.
  840. result = parseJson(newStringStream(buffer), "input")
  841. proc parseFile*(filename: string): JsonNode =
  842. ## Parses `file` into a `JsonNode`.
  843. ## If `file` contains extra data, it will raise `JsonParsingError`.
  844. var stream = newFileStream(filename, fmRead)
  845. if stream == nil:
  846. raise newException(IOError, "cannot read from file: " & filename)
  847. result = parseJson(stream, filename)
  848. # -- Json deserialiser. --
  849. template verifyJsonKind(node: JsonNode, kinds: set[JsonNodeKind],
  850. ast: string) =
  851. if node == nil:
  852. raise newException(KeyError, "key not found: " & ast)
  853. elif node.kind notin kinds:
  854. let msg = "Incorrect JSON kind. Wanted '$1' in '$2' but got '$3'." % [
  855. $kinds,
  856. ast,
  857. $node.kind
  858. ]
  859. raise newException(JsonKindError, msg)
  860. when defined(nimFixedForwardGeneric):
  861. macro isRefSkipDistinct(arg: typed): untyped =
  862. var impl = getTypeImpl(arg)
  863. if impl.kind == nnkBracketExpr and impl[0].eqIdent("typeDesc"):
  864. impl = getTypeImpl(impl[1])
  865. while impl.kind == nnkDistinctTy:
  866. impl = getTypeImpl(impl[0])
  867. result = newLit(impl.kind == nnkRefTy)
  868. # The following forward declarations don't work in older versions of Nim
  869. # forward declare all initFromJson
  870. proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string)
  871. proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string)
  872. proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string)
  873. proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string)
  874. proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string)
  875. proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string)
  876. proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string)
  877. proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string)
  878. proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string)
  879. proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string)
  880. proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string)
  881. proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string)
  882. proc initFromJson[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string)
  883. proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string)
  884. # initFromJson definitions
  885. proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string) =
  886. verifyJsonKind(jsonNode, {JString, JNull}, jsonPath)
  887. # since strings don't have a nil state anymore, this mapping of
  888. # JNull to the default string is questionable. `none(string)` and
  889. # `some("")` have the same potentional json value `JNull`.
  890. if jsonNode.kind == JNull:
  891. dst = ""
  892. else:
  893. dst = jsonNode.str
  894. proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string) =
  895. verifyJsonKind(jsonNode, {JBool}, jsonPath)
  896. dst = jsonNode.bval
  897. proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) =
  898. dst = jsonNode.copy
  899. proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) =
  900. verifyJsonKind(jsonNode, {JInt}, jsonPath)
  901. dst = T(jsonNode.num)
  902. proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
  903. verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath)
  904. if jsonNode.kind == JFloat:
  905. dst = T(jsonNode.fnum)
  906. else:
  907. dst = T(jsonNode.num)
  908. proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
  909. verifyJsonKind(jsonNode, {JString}, jsonPath)
  910. dst = parseEnum[T](jsonNode.getStr)
  911. proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string) =
  912. verifyJsonKind(jsonNode, {JArray}, jsonPath)
  913. dst.setLen jsonNode.len
  914. let orignalJsonPathLen = jsonPath.len
  915. for i in 0 ..< jsonNode.len:
  916. jsonPath.add '['
  917. jsonPath.addInt i
  918. jsonPath.add ']'
  919. initFromJson(dst[i], jsonNode[i], jsonPath)
  920. jsonPath.setLen orignalJsonPathLen
  921. proc initFromJson[S,T](dst: var array[S,T]; jsonNode: JsonNode; jsonPath: var string) =
  922. verifyJsonKind(jsonNode, {JArray}, jsonPath)
  923. let originalJsonPathLen = jsonPath.len
  924. for i in 0 ..< jsonNode.len:
  925. jsonPath.add '['
  926. jsonPath.addInt i
  927. jsonPath.add ']'
  928. initFromJson(dst[i], jsonNode[i], jsonPath)
  929. jsonPath.setLen originalJsonPathLen
  930. proc initFromJson[T](dst: var Table[string,T];jsonNode: JsonNode; jsonPath: var string) =
  931. dst = initTable[string, T]()
  932. verifyJsonKind(jsonNode, {JObject}, jsonPath)
  933. let originalJsonPathLen = jsonPath.len
  934. for key in keys(jsonNode.fields):
  935. jsonPath.add '.'
  936. jsonPath.add key
  937. initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath)
  938. jsonPath.setLen originalJsonPathLen
  939. proc initFromJson[T](dst: var OrderedTable[string,T];jsonNode: JsonNode; jsonPath: var string) =
  940. dst = initOrderedTable[string,T]()
  941. verifyJsonKind(jsonNode, {JObject}, jsonPath)
  942. let originalJsonPathLen = jsonPath.len
  943. for key in keys(jsonNode.fields):
  944. jsonPath.add '.'
  945. jsonPath.add key
  946. initFromJson(mgetOrPut(dst, key, default(T)), jsonNode[key], jsonPath)
  947. jsonPath.setLen originalJsonPathLen
  948. proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string) =
  949. verifyJsonKind(jsonNode, {JObject, JNull}, jsonPath)
  950. if jsonNode.kind == JNull:
  951. dst = nil
  952. else:
  953. dst = new(T)
  954. initFromJson(dst[], jsonNode, jsonPath)
  955. proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string) =
  956. if jsonNode != nil and jsonNode.kind != JNull:
  957. dst = some(default(T))
  958. initFromJson(dst.get, jsonNode, jsonPath)
  959. macro assignDistinctImpl[T : distinct](dst: var T;jsonNode: JsonNode; jsonPath: var string) =
  960. let typInst = getTypeInst(dst)
  961. let typImpl = getTypeImpl(dst)
  962. let baseTyp = typImpl[0]
  963. result = quote do:
  964. when nimvm:
  965. # workaround #12282
  966. var tmp: `baseTyp`
  967. initFromJson( tmp, `jsonNode`, `jsonPath`)
  968. `dst` = `typInst`(tmp)
  969. else:
  970. initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`)
  971. proc initFromJson[T : distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
  972. assignDistinctImpl(dst, jsonNode, jsonPath)
  973. proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode): void =
  974. if typeExpr.kind == nnkTupleConstr:
  975. error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode)
  976. proc foldObjectBody(dst, typeNode, tmpSym, jsonNode, jsonPath, originalJsonPathLen: NimNode): void {.compileTime.} =
  977. case typeNode.kind
  978. of nnkEmpty:
  979. discard
  980. of nnkRecList, nnkTupleTy:
  981. for it in typeNode:
  982. foldObjectBody(dst, it, tmpSym, jsonNode, jsonPath, originalJsonPathLen)
  983. of nnkIdentDefs:
  984. typeNode.expectLen 3
  985. let fieldSym = typeNode[0]
  986. let fieldNameLit = newLit(fieldSym.strVal)
  987. let fieldPathLit = newLit("." & fieldSym.strVal)
  988. let fieldType = typeNode[1]
  989. # Detecting incompatiple tuple types in `assignObjectImpl` only
  990. # would be much cleaner, but the ast for tuple types does not
  991. # contain usable type information.
  992. detectIncompatibleType(fieldType, fieldSym)
  993. dst.add quote do:
  994. jsonPath.add `fieldPathLit`
  995. when nimvm:
  996. when isRefSkipDistinct(`tmpSym`.`fieldSym`):
  997. # workaround #12489
  998. var tmp: `fieldType`
  999. initFromJson(tmp, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`)
  1000. `tmpSym`.`fieldSym` = tmp
  1001. else:
  1002. initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`)
  1003. else:
  1004. initFromJson(`tmpSym`.`fieldSym`, getOrDefault(`jsonNode`,`fieldNameLit`), `jsonPath`)
  1005. jsonPath.setLen `originalJsonPathLen`
  1006. of nnkRecCase:
  1007. let kindSym = typeNode[0][0]
  1008. let kindNameLit = newLit(kindSym.strVal)
  1009. let kindPathLit = newLit("." & kindSym.strVal)
  1010. let kindType = typeNode[0][1]
  1011. let kindOffsetLit = newLit(uint(getOffset(kindSym)))
  1012. dst.add quote do:
  1013. var kindTmp: `kindType`
  1014. jsonPath.add `kindPathLit`
  1015. initFromJson(kindTmp, `jsonNode`[`kindNameLit`], `jsonPath`)
  1016. jsonPath.setLen `originalJsonPathLen`
  1017. when defined js:
  1018. `tmpSym`.`kindSym` = kindTmp
  1019. else:
  1020. when nimvm:
  1021. `tmpSym`.`kindSym` = kindTmp
  1022. else:
  1023. # fuck it, assign kind field anyway
  1024. ((cast[ptr `kindType`](cast[uint](`tmpSym`.addr) + `kindOffsetLit`))[]) = kindTmp
  1025. dst.add nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym))
  1026. for i in 1 ..< typeNode.len:
  1027. foldObjectBody(dst, typeNode[i], tmpSym, jsonNode, jsonPath, originalJsonPathLen)
  1028. of nnkOfBranch, nnkElse:
  1029. let ofBranch = newNimNode(typeNode.kind)
  1030. for i in 0 ..< typeNode.len-1:
  1031. ofBranch.add copyNimTree(typeNode[i])
  1032. let dstInner = newNimNode(nnkStmtListExpr)
  1033. foldObjectBody(dstInner, typeNode[^1], tmpSym, jsonNode, jsonPath, originalJsonPathLen)
  1034. # resOuter now contains the inner stmtList
  1035. ofBranch.add dstInner
  1036. dst[^1].expectKind nnkCaseStmt
  1037. dst[^1].add ofBranch
  1038. of nnkObjectTy:
  1039. typeNode[0].expectKind nnkEmpty
  1040. typeNode[1].expectKind {nnkEmpty, nnkOfInherit}
  1041. if typeNode[1].kind == nnkOfInherit:
  1042. let base = typeNode[1][0]
  1043. var impl = getTypeImpl(base)
  1044. while impl.kind in {nnkRefTy, nnkPtrTy}:
  1045. impl = getTypeImpl(impl[0])
  1046. foldObjectBody(dst, impl, tmpSym, jsonNode, jsonPath, originalJsonPathLen)
  1047. let body = typeNode[2]
  1048. foldObjectBody(dst, body, tmpSym, jsonNode, jsonPath, originalJsonPathLen)
  1049. else:
  1050. error("unhandled kind: " & $typeNode.kind, typeNode)
  1051. macro assignObjectImpl[T](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
  1052. let typeSym = getTypeInst(dst)
  1053. let originalJsonPathLen = genSym(nskLet, "originalJsonPathLen")
  1054. result = newStmtList()
  1055. result.add quote do:
  1056. let `originalJsonPathLen` = len(`jsonPath`)
  1057. if typeSym.kind in {nnkTupleTy, nnkTupleConstr}:
  1058. # both, `dst` and `typeSym` don't have good lineinfo. But nothing
  1059. # else is available here.
  1060. detectIncompatibleType(typeSym, dst)
  1061. foldObjectBody(result, typeSym, dst, jsonNode, jsonPath, originalJsonPathLen)
  1062. else:
  1063. foldObjectBody(result, typeSym.getTypeImpl, dst, jsonNode, jsonPath, originalJsonPathLen)
  1064. proc initFromJson[T : object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
  1065. assignObjectImpl(dst, jsonNode, jsonPath)
  1066. proc to*[T](node: JsonNode, t: typedesc[T]): T =
  1067. ## `Unmarshals`:idx: the specified node into the object type specified.
  1068. ##
  1069. ## Known limitations:
  1070. ##
  1071. ## * Heterogeneous arrays are not supported.
  1072. ## * Sets in object variants are not supported.
  1073. ## * Not nil annotations are not supported.
  1074. ##
  1075. ## Example:
  1076. ##
  1077. ## .. code-block:: Nim
  1078. ## let jsonNode = parseJson("""
  1079. ## {
  1080. ## "person": {
  1081. ## "name": "Nimmer",
  1082. ## "age": 21
  1083. ## },
  1084. ## "list": [1, 2, 3, 4]
  1085. ## }
  1086. ## """)
  1087. ##
  1088. ## type
  1089. ## Person = object
  1090. ## name: string
  1091. ## age: int
  1092. ##
  1093. ## Data = object
  1094. ## person: Person
  1095. ## list: seq[int]
  1096. ##
  1097. ## var data = to(jsonNode, Data)
  1098. ## doAssert data.person.name == "Nimmer"
  1099. ## doAssert data.person.age == 21
  1100. ## doAssert data.list == @[1, 2, 3, 4]
  1101. var jsonPath = ""
  1102. initFromJson(result, node, jsonPath)
  1103. when false:
  1104. import os
  1105. var s = newFileStream(paramStr(1), fmRead)
  1106. if s == nil: quit("cannot open the file" & paramStr(1))
  1107. var x: JsonParser
  1108. open(x, s, paramStr(1))
  1109. while true:
  1110. next(x)
  1111. case x.kind
  1112. of jsonError:
  1113. Echo(x.errorMsg())
  1114. break
  1115. of jsonEof: break
  1116. of jsonString, jsonInt, jsonFloat: echo(x.str)
  1117. of jsonTrue: echo("!TRUE")
  1118. of jsonFalse: echo("!FALSE")
  1119. of jsonNull: echo("!NULL")
  1120. of jsonObjectStart: echo("{")
  1121. of jsonObjectEnd: echo("}")
  1122. of jsonArrayStart: echo("[")
  1123. of jsonArrayEnd: echo("]")
  1124. close(x)
  1125. # { "json": 5 }
  1126. # To get that we shall use, obj["json"]
  1127. when isMainModule:
  1128. # Note: Macro tests are in tests/stdlib/tjsonmacro.nim
  1129. let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
  1130. # nil passthrough
  1131. doAssert(testJson{"doesnt_exist"}{"anything"}.isNil)
  1132. testJson{["e", "f"]} = %true
  1133. doAssert(testJson["e"]["f"].bval)
  1134. # make sure UTF-16 decoding works.
  1135. doAssert(testJson["c"].str == "🎃")
  1136. doAssert(testJson["d"].str == "æ")
  1137. # make sure no memory leek when parsing invalid string
  1138. let startMemory = getOccupiedMem()
  1139. for i in 0 .. 10000:
  1140. try:
  1141. discard parseJson"""{ invalid"""
  1142. except:
  1143. discard
  1144. # memory diff should less than 4M
  1145. doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
  1146. # test `$`
  1147. let stringified = $testJson
  1148. let parsedAgain = parseJson(stringified)
  1149. doAssert(parsedAgain["b"].str == "asd")
  1150. parsedAgain["abc"] = %5
  1151. doAssert parsedAgain["abc"].num == 5
  1152. # Bounds checking
  1153. when compileOption("boundChecks"):
  1154. try:
  1155. let a = testJson["a"][9]
  1156. doAssert(false, "IndexError not thrown")
  1157. except IndexError:
  1158. discard
  1159. try:
  1160. let a = testJson["a"][-1]
  1161. doAssert(false, "IndexError not thrown")
  1162. except IndexError:
  1163. discard
  1164. try:
  1165. doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
  1166. except:
  1167. doAssert(false, "IndexError thrown for valid index")
  1168. doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
  1169. doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
  1170. doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
  1171. doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
  1172. doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
  1173. doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
  1174. # Generator:
  1175. var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
  1176. doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
  1177. var j2 = %*
  1178. [
  1179. {
  1180. "name": "John",
  1181. "age": 30
  1182. },
  1183. {
  1184. "name": "Susan",
  1185. "age": 31
  1186. }
  1187. ]
  1188. doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
  1189. var name = "John"
  1190. let herAge = 30
  1191. const hisAge = 31
  1192. var j3 = %*
  1193. [ {"name": "John"
  1194. , "age": herAge
  1195. }
  1196. , {"name": "Susan"
  1197. , "age": hisAge
  1198. }
  1199. ]
  1200. doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
  1201. var j4 = %*{"test": nil}
  1202. doAssert j4 == %{"test": newJNull()}
  1203. let seqOfNodes = @[%1, %2]
  1204. let jSeqOfNodes = %seqOfNodes
  1205. doAssert(jSeqOfNodes[1].num == 2)
  1206. type MyObj = object
  1207. a, b: int
  1208. s: string
  1209. f32: float32
  1210. f64: float64
  1211. next: ref MyObj
  1212. var m: MyObj
  1213. m.s = "hi"
  1214. m.a = 5
  1215. let jMyObj = %m
  1216. doAssert(jMyObj["a"].num == 5)
  1217. doAssert(jMyObj["s"].str == "hi")
  1218. # Test loading of file.
  1219. when not defined(js):
  1220. var parsed = parseFile("tests/testdata/jsontest.json")
  1221. try:
  1222. discard parsed["key2"][12123]
  1223. doAssert(false)
  1224. except IndexError: doAssert(true)
  1225. var parsed2 = parseFile("tests/testdata/jsontest2.json")
  1226. doAssert(parsed2{"repository", "description"}.str ==
  1227. "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
  1228. doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
  1229. doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
  1230. doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
  1231. doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887
  1232. # Test with extra data
  1233. when not defined(js):
  1234. try:
  1235. discard parseJson("123 456")
  1236. doAssert(false)
  1237. except JsonParsingError:
  1238. doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
  1239. try:
  1240. discard parseFile("tests/testdata/jsonwithextradata.json")
  1241. doAssert(false)
  1242. except JsonParsingError:
  1243. doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
  1244. # bug #6438
  1245. doAssert($ %*[] == "[]")
  1246. doAssert($ %*{} == "{}")
  1247. doAssert(not compiles(%{"error": "No messages"}))
  1248. # bug #9111
  1249. block:
  1250. type
  1251. Bar = string
  1252. Foo = object
  1253. a: int
  1254. b: Bar
  1255. let
  1256. js = """{"a": 123, "b": "abc"}""".parseJson
  1257. foo = js.to Foo
  1258. doAssert(foo.b == "abc")
  1259. # Generate constructors for range[T] types
  1260. block:
  1261. type
  1262. Q1 = range[0'u8 .. 50'u8]
  1263. Q2 = range[0'u16 .. 50'u16]
  1264. Q3 = range[0'u32 .. 50'u32]
  1265. Q4 = range[0'i8 .. 50'i8]
  1266. Q5 = range[0'i16 .. 50'i16]
  1267. Q6 = range[0'i32 .. 50'i32]
  1268. Q7 = range[0'f32 .. 50'f32]
  1269. Q8 = range[0'f64 .. 50'f64]
  1270. Q9 = range[0 .. 50]
  1271. X = object
  1272. m1: Q1
  1273. m2: Q2
  1274. m3: Q3
  1275. m4: Q4
  1276. m5: Q5
  1277. m6: Q6
  1278. m7: Q7
  1279. m8: Q8
  1280. m9: Q9
  1281. let obj = X(
  1282. m1: Q1(42),
  1283. m2: Q2(42),
  1284. m3: Q3(42),
  1285. m4: Q4(42),
  1286. m5: Q5(42),
  1287. m6: Q6(42),
  1288. m7: Q7(42),
  1289. m8: Q8(42),
  1290. m9: Q9(42)
  1291. )
  1292. doAssert(obj == to(%obj, type(obj)))
  1293. when not defined(js):
  1294. const fragments = """[1,2,3] {"hi":3} 12 [] """
  1295. var res = ""
  1296. for x in parseJsonFragments(newStringStream(fragments)):
  1297. res.add($x)
  1298. res.add " "
  1299. doAssert res == fragments
  1300. # test isRefSkipDistinct
  1301. type
  1302. MyRef = ref object
  1303. MyObject = object
  1304. MyDistinct = distinct MyRef
  1305. MyOtherDistinct = distinct MyRef
  1306. var x0: ref int
  1307. var x1: MyRef
  1308. var x2: MyObject
  1309. var x3: MyDistinct
  1310. var x4: MyOtherDistinct
  1311. doAssert isRefSkipDistinct(x0)
  1312. doAssert isRefSkipDistinct(x1)
  1313. doAssert not isRefSkipDistinct(x2)
  1314. doAssert isRefSkipDistinct(x3)
  1315. doAssert isRefSkipDistinct(x4)
  1316. doAssert isRefSkipDistinct(ref int)
  1317. doAssert isRefSkipDistinct(MyRef)
  1318. doAssert not isRefSkipDistinct(MyObject)
  1319. doAssert isRefSkipDistinct(MyDistinct)
  1320. doAssert isRefSkipDistinct(MyOtherDistinct)