vmmarshal.nim 9.3 KB

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