vmmarshal.nim 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements marshaling for the VM.
  10. import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
  11. proc ptrToInt(x: PNode): int {.inline.} =
  12. result = cast[int](x) # don't skip alignment
  13. proc getField(n: PNode; position: int): PSym =
  14. case n.kind
  15. of nkRecList:
  16. for i in countup(0, sonsLen(n) - 1):
  17. result = getField(n.sons[i], position)
  18. if result != nil: return
  19. of nkRecCase:
  20. result = getField(n.sons[0], position)
  21. if result != nil: return
  22. for i in countup(1, sonsLen(n) - 1):
  23. case n.sons[i].kind
  24. of nkOfBranch, nkElse:
  25. result = getField(lastSon(n.sons[i]), position)
  26. if result != nil: return
  27. else: internalError(n.info, "getField(record case branch)")
  28. of nkSym:
  29. if n.sym.position == position: result = n.sym
  30. else: discard
  31. proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
  32. proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
  33. internalAssert x.kind == nkObjConstr
  34. let start = 1
  35. for i in countup(start, sonsLen(x) - 1):
  36. if i > start: s.add(", ")
  37. var it = x.sons[i]
  38. if it.kind == nkExprColonExpr:
  39. internalAssert it.sons[0].kind == nkSym
  40. let field = it.sons[0].sym
  41. s.add(escapeJson(field.name.s))
  42. s.add(": ")
  43. storeAny(s, field.typ, it.sons[1], stored)
  44. elif typ.n != nil:
  45. let field = getField(typ.n, i)
  46. s.add(escapeJson(field.name.s))
  47. s.add(": ")
  48. storeAny(s, field.typ, it, stored)
  49. proc skipColon*(n: PNode): PNode =
  50. result = n
  51. if n.kind == nkExprColonExpr:
  52. result = n.sons[1]
  53. proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
  54. case t.kind
  55. of tyNone: assert false
  56. of tyBool: s.add($(a.intVal != 0))
  57. of tyChar:
  58. let ch = char(a.intVal)
  59. if ch < '\128':
  60. s.add(escapeJson($ch))
  61. else:
  62. s.add($int(ch))
  63. of tyArray, tySequence:
  64. if t.kind == tySequence and a.kind == nkNilLit: s.add("null")
  65. else:
  66. s.add("[")
  67. for i in 0 .. a.len-1:
  68. if i > 0: s.add(", ")
  69. storeAny(s, t.elemType, a[i], stored)
  70. s.add("]")
  71. of tyTuple:
  72. s.add("{")
  73. for i in 0.. <t.len:
  74. if i > 0: s.add(", ")
  75. s.add("\"Field" & $i)
  76. s.add("\": ")
  77. storeAny(s, t.sons[i], a[i].skipColon, stored)
  78. s.add("}")
  79. of tyObject:
  80. s.add("{")
  81. storeObj(s, t, a, stored)
  82. s.add("}")
  83. of tySet:
  84. s.add("[")
  85. for i in 0.. <a.len:
  86. if i > 0: s.add(", ")
  87. if a[i].kind == nkRange:
  88. var x = copyNode(a[i][0])
  89. storeAny(s, t.lastSon, x, stored)
  90. while x.intVal+1 <= a[i][1].intVal:
  91. s.add(", ")
  92. storeAny(s, t.lastSon, x, stored)
  93. inc x.intVal
  94. else:
  95. storeAny(s, t.lastSon, a[i], stored)
  96. s.add("]")
  97. of tyRange, tyGenericInst, tyAlias: storeAny(s, t.lastSon, a, stored)
  98. of tyEnum:
  99. # we need a slow linear search because of enums with holes:
  100. for e in items(t.n):
  101. if e.sym.position == a.intVal:
  102. s.add e.sym.name.s.escapeJson
  103. break
  104. of tyPtr, tyRef:
  105. var x = a
  106. if isNil(x) or x.kind == nkNilLit: s.add("null")
  107. elif stored.containsOrIncl(x.ptrToInt):
  108. # already stored, so we simply write out the pointer as an int:
  109. s.add($x.ptrToInt)
  110. else:
  111. # else as a [value, key] pair:
  112. # (reversed order for convenient x[0] access!)
  113. s.add("[")
  114. s.add($x.ptrToInt)
  115. s.add(", ")
  116. storeAny(s, t.lastSon, a, stored)
  117. s.add("]")
  118. of tyString, tyCString:
  119. if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
  120. else: s.add(escapeJson(a.strVal))
  121. of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
  122. of tyFloat..tyFloat128: s.add($a.floatVal)
  123. else:
  124. internalError a.info, "cannot marshal at compile-time " & t.typeToString
  125. proc storeAny*(s: var string; t: PType; a: PNode) =
  126. var stored = initIntSet()
  127. storeAny(s, t, a, stored)
  128. proc loadAny(p: var JsonParser, t: PType,
  129. tab: var Table[BiggestInt, PNode]): PNode =
  130. case t.kind
  131. of tyNone: assert false
  132. of tyBool:
  133. case p.kind
  134. of jsonFalse: result = newIntNode(nkIntLit, 0)
  135. of jsonTrue: result = newIntNode(nkIntLit, 1)
  136. else: raiseParseErr(p, "'true' or 'false' expected for a bool")
  137. next(p)
  138. of tyChar:
  139. if p.kind == jsonString:
  140. var x = p.str
  141. if x.len == 1:
  142. result = newIntNode(nkIntLit, ord(x[0]))
  143. next(p)
  144. return
  145. elif p.kind == jsonInt:
  146. result = newIntNode(nkIntLit, getInt(p))
  147. next(p)
  148. return
  149. raiseParseErr(p, "string of length 1 expected for a char")
  150. of tyEnum:
  151. if p.kind == jsonString:
  152. for e in items(t.n):
  153. if e.sym.name.s == p.str:
  154. result = newIntNode(nkIntLit, e.sym.position)
  155. next(p)
  156. return
  157. raiseParseErr(p, "string expected for an enum")
  158. of tyArray:
  159. if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
  160. next(p)
  161. result = newNode(nkBracket)
  162. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  163. result.add loadAny(p, t.elemType, tab)
  164. if p.kind == jsonArrayEnd: next(p)
  165. else: raiseParseErr(p, "']' end of array expected")
  166. of tySequence:
  167. case p.kind
  168. of jsonNull:
  169. result = newNode(nkNilLit)
  170. next(p)
  171. of jsonArrayStart:
  172. next(p)
  173. result = newNode(nkBracket)
  174. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  175. result.add loadAny(p, t.elemType, tab)
  176. if p.kind == jsonArrayEnd: next(p)
  177. else: raiseParseErr(p, "")
  178. else:
  179. raiseParseErr(p, "'[' expected for a seq")
  180. of tyTuple:
  181. if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
  182. next(p)
  183. result = newNode(nkPar)
  184. var i = 0
  185. while p.kind != jsonObjectEnd and p.kind != jsonEof:
  186. if p.kind != jsonString:
  187. raiseParseErr(p, "string expected for a field name")
  188. next(p)
  189. if i >= t.len:
  190. raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
  191. result.add loadAny(p, t.sons[i], tab)
  192. inc i
  193. if p.kind == jsonObjectEnd: next(p)
  194. else: raiseParseErr(p, "'}' end of object expected")
  195. of tyObject:
  196. if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
  197. next(p)
  198. result = newNode(nkObjConstr)
  199. result.sons = @[newNode(nkEmpty)]
  200. while p.kind != jsonObjectEnd and p.kind != jsonEof:
  201. if p.kind != jsonString:
  202. raiseParseErr(p, "string expected for a field name")
  203. let ident = getIdent(p.str)
  204. let field = lookupInRecord(t.n, ident)
  205. if field.isNil:
  206. raiseParseErr(p, "unknown field for object of type " & typeToString(t))
  207. next(p)
  208. let pos = field.position + 1
  209. if pos >= result.sons.len:
  210. setLen(result.sons, pos + 1)
  211. let fieldNode = newNode(nkExprColonExpr)
  212. fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo())))
  213. fieldNode.addSon(loadAny(p, field.typ, tab))
  214. result.sons[pos] = fieldNode
  215. if p.kind == jsonObjectEnd: next(p)
  216. else: raiseParseErr(p, "'}' end of object expected")
  217. of tySet:
  218. if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
  219. next(p)
  220. result = newNode(nkCurly)
  221. while p.kind != jsonArrayEnd and p.kind != jsonEof:
  222. result.add loadAny(p, t.lastSon, tab)
  223. next(p)
  224. if p.kind == jsonArrayEnd: next(p)
  225. else: raiseParseErr(p, "']' end of array expected")
  226. of tyPtr, tyRef:
  227. case p.kind
  228. of jsonNull:
  229. result = newNode(nkNilLit)
  230. next(p)
  231. of jsonInt:
  232. result = tab.getOrDefault(p.getInt)
  233. if result.isNil:
  234. raiseParseErr(p, "cannot load object with address " & $p.getInt)
  235. next(p)
  236. of jsonArrayStart:
  237. next(p)
  238. if p.kind == jsonInt:
  239. let idx = p.getInt
  240. next(p)
  241. result = loadAny(p, t.lastSon, tab)
  242. tab[idx] = result
  243. else: raiseParseErr(p, "index for ref type expected")
  244. if p.kind == jsonArrayEnd: next(p)
  245. else: raiseParseErr(p, "']' end of ref-address pair expected")
  246. else: raiseParseErr(p, "int for pointer type expected")
  247. of tyString, tyCString:
  248. case p.kind
  249. of jsonNull:
  250. result = newNode(nkNilLit)
  251. next(p)
  252. of jsonString:
  253. result = newStrNode(nkStrLit, p.str)
  254. next(p)
  255. else: raiseParseErr(p, "string expected")
  256. of tyInt..tyInt64, tyUInt..tyUInt64:
  257. if p.kind == jsonInt:
  258. result = newIntNode(nkIntLit, getInt(p))
  259. next(p)
  260. return
  261. raiseParseErr(p, "int expected")
  262. of tyFloat..tyFloat128:
  263. if p.kind == jsonFloat:
  264. result = newFloatNode(nkFloatLit, getFloat(p))
  265. next(p)
  266. return
  267. raiseParseErr(p, "float expected")
  268. of tyRange, tyGenericInst, tyAlias: result = loadAny(p, t.lastSon, tab)
  269. else:
  270. internalError "cannot marshal at compile-time " & t.typeToString
  271. proc loadAny*(s: string; t: PType): PNode =
  272. var tab = initTable[BiggestInt, PNode]()
  273. var p: JsonParser
  274. open(p, newStringStream(s), "unknown file")
  275. next(p)
  276. result = loadAny(p, t, tab)
  277. close(p)