vmmarshal.nim 9.6 KB

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