genpacket_enet.nim 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import macros, macro_dsl, estreams
  2. from strutils import format
  3. template newLenName() =
  4. let lenName {.inject.} = ^("len" & $lenNames)
  5. inc(lenNames)
  6. template defPacketImports*() {.dirty.} =
  7. import macros, macro_dsl, estreams
  8. from strutils import format
  9. macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
  10. result = newNimNode(nnkStmtList)
  11. let
  12. typeName = quoted2ident(typeNameN)
  13. packetID = ^"p"
  14. streamID = ^"s"
  15. var
  16. constructorParams = newNimNode(nnkFormalParams).und(typeName)
  17. constructor = newNimNode(nnkProcDef).und(
  18. postfix(^("new" & $typeName.ident), "*"),
  19. emptyNode(),
  20. emptyNode(),
  21. constructorParams,
  22. emptyNode(),
  23. emptyNode())
  24. pack = newNimNode(nnkProcDef).und(
  25. postfix(^"pack", "*"),
  26. emptyNode(),
  27. emptyNode(),
  28. newNimNode(nnkFormalParams).und(
  29. emptyNode(), # : void
  30. newNimNode(nnkIdentDefs).und(
  31. streamID, # s: PBuffer
  32. ^"PBuffer",
  33. newNimNode(nnkNilLit)),
  34. newNimNode(nnkIdentDefs).und(
  35. packetID, # p: var typeName
  36. newNimNode(nnkVarTy).und(typeName),
  37. emptyNode())),
  38. emptyNode(),
  39. emptyNode())
  40. read = newNimNode(nnkProcDef).und(
  41. newIdentNode("read" & $typeName.ident).postfix("*"),
  42. emptyNode(),
  43. emptyNode(),
  44. newNimNode(nnkFormalParams).und(
  45. typeName, #result type
  46. newNimNode(nnkIdentDefs).und(
  47. streamID, # s: PBuffer = nil
  48. ^"PBuffer",
  49. newNimNode(nnkNilLit))),
  50. emptyNode(),
  51. emptyNode())
  52. constructorBody = newNimNode(nnkStmtList)
  53. packBody = newNimNode(nnkStmtList)
  54. readBody = newNimNode(nnkStmtList)
  55. lenNames = 0
  56. for i in 0.. typeFields.len - 1:
  57. let
  58. name = typeFields[i][0]
  59. dotName = packetID.dot(name)
  60. resName = newIdentNode("result").dot(name)
  61. case typeFields[i][1].kind
  62. of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
  63. case $typeFields[i][1][0].ident
  64. of "seq":
  65. ## let lenX = readInt16(s)
  66. newLenName()
  67. let
  68. item = ^"item" ## item name in our iterators
  69. seqType = typeFields[i][1][1] ## type of seq
  70. readName = newIdentNode("read" & $seqType.ident)
  71. readBody.add(newNimNode(nnkLetSection).und(
  72. newNimNode(nnkIdentDefs).und(
  73. lenName,
  74. newNimNode(nnkEmpty),
  75. newCall("readInt16", streamID))))
  76. readBody.add( ## result.name = @[]
  77. resName := ("@".prefix(newNimNode(nnkBracket))),
  78. newNimNode(nnkForStmt).und( ## for item in 1..len:
  79. item,
  80. infix(1.lit, "..", lenName),
  81. newNimNode(nnkStmtList).und(
  82. newCall( ## add(result.name, unpack[seqType](stream))
  83. "add", resName, newNimNode(nnkCall).und(readName, streamID)
  84. ) ) ) )
  85. packbody.add(
  86. newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
  87. lenName, ## var lenName = int16(len(p.name))
  88. newIdentNode("int16"),
  89. newCall("int16", newCall("len", dotName)))),
  90. newCall("writeBE", streamID, lenName),
  91. newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream)
  92. item,
  93. infix(0.lit, "..", infix(lenName, "-", 1.lit)),
  94. newNimNode(nnkStmtList).und(
  95. newCall("echo", item, ": ".lit),
  96. newCall("pack", streamID, dotName[item]))))
  97. #set the default value to @[] (new sequence)
  98. typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
  99. else:
  100. error("Unknown type: " & treeRepr(typeFields[i]))
  101. of nnkIdent: ##normal type
  102. case $typeFields[i][1].ident
  103. of "string": # length encoded string
  104. packBody.add(newCall("write", streamID, dotName))
  105. readBody.add(resName := newCall("readStr", streamID))
  106. of "int8", "int16", "int32", "float32", "float64", "char", "bool":
  107. packBody.add(newCall(
  108. "writeBE", streamID, dotName))
  109. readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
  110. else: ## hopefully the type you specified was another defpacket() type
  111. packBody.add(newCall("pack", streamID, dotName))
  112. readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
  113. else:
  114. error("I dont know what to do with: " & treerepr(typeFields[i]))
  115. var
  116. toStringFunc = newNimNode(nnkProcDef).und(
  117. newNimNode(nnkPostfix).und(
  118. ^"*",
  119. newNimNode(nnkAccQuoted).und(^"$")),
  120. emptyNode(),
  121. emptyNode(),
  122. newNimNode(nnkFormalParams).und(
  123. ^"string",
  124. newNimNode(nnkIdentDefs).und(
  125. packetID, # p: typeName
  126. typeName,
  127. emptyNode())),
  128. emptyNode(),
  129. emptyNode(),
  130. newNimNode(nnkStmtList).und(# [6]
  131. newNimNode(nnkAsgn).und(
  132. ^"result", ## result =
  133. newNimNode(nnkCall).und(# [6][0][1]
  134. ^"format", ## format
  135. emptyNode())))) ## "[TypeName $1 $2]"
  136. formatStr = "[" & $typeName.ident
  137. const emptyFields = {nnkEmpty, nnkNilLit}
  138. var objFields = newNimNode(nnkRecList)
  139. for i in 0 ..< len(typeFields):
  140. let fname = typeFields[i][0]
  141. constructorParams.add(newNimNode(nnkIdentDefs).und(
  142. fname,
  143. typeFields[i][1],
  144. typeFields[i][2]))
  145. constructorBody.add((^"result").dot(fname) := fname)
  146. #export the name
  147. typeFields[i][0] = fname.postfix("*")
  148. if not(typeFields[i][2].kind in emptyFields):
  149. ## empty the type default for the type def
  150. typeFields[i][2] = newNimNode(nnkEmpty)
  151. objFields.add(typeFields[i])
  152. toStringFunc[6][0][1].add(
  153. prefix("$", packetID.dot(fname)))
  154. formatStr.add " $"
  155. formatStr.add($(i + 1))
  156. formatStr.add ']'
  157. toStringFunc[6][0][1][1] = formatStr.lit()
  158. result.add(
  159. newNimNode(nnkTypeSection).und(
  160. newNimNode(nnkTypeDef).und(
  161. typeName.postfix("*"),
  162. newNimNode(nnkEmpty),
  163. newNimNode(nnkObjectTy).und(
  164. newNimNode(nnkEmpty), #not sure what this is
  165. newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
  166. objFields))))
  167. result.add(constructor.und(constructorBody))
  168. result.add(pack.und(packBody))
  169. result.add(read.und(readBody))
  170. result.add(toStringFunc)
  171. when defined(GenPacketShowOutput):
  172. echo(repr(result))
  173. proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
  174. result = newNimNode(nnkProcDef).und(
  175. name,
  176. emptyNode(),
  177. emptyNode(),
  178. newNimNode(nnkFormalParams).und(resultType),
  179. emptyNode(),
  180. emptyNode(),
  181. newNimNode(nnkStmtList))
  182. result[3].add(params)
  183. proc body*(procNode: NimNode): NimNode {.compileTime.} =
  184. assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
  185. result = procNode[6]
  186. proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
  187. result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
  188. proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
  189. result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
  190. proc varTy*(a: NimNode): NimNode {.compileTime.} =
  191. result = newNimNode(nnkVarTy).und(a)
  192. macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped =
  193. var
  194. packetID = ^"p"
  195. streamID = ^"s"
  196. result = newNimNode(nnkStmtList).und(
  197. newProc(
  198. (^("read" & $typeName.ident)).postfix("*"),
  199. [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
  200. typeName),
  201. newProc(
  202. (^"pack").postfix("*"),
  203. [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)),
  204. iddefs("p", varTy(typeName)) ],
  205. emptyNode()))
  206. var
  207. readBody = result[0][6]
  208. packBody = result[1][6]
  209. resName = ^"result"
  210. case underlyingType.kind
  211. of nnkBracketExpr:
  212. case $underlyingType[0].ident
  213. of "array":
  214. for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int:
  215. readBody.add(
  216. newCall("read", ^"s", resName[lit(i)]))
  217. packBody.add(
  218. newCall("writeBE", ^"s", packetID[lit(i)]))
  219. else:
  220. echo "Unknown type: ", repr(underlyingtype)
  221. else:
  222. echo "unknown type:", repr(underlyingtype)
  223. echo(repr(result))
  224. template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} =
  225. proc `read typeName`*(buffer: PBuffer): typeName =
  226. #discard readData(s, addr result, sizeof(result))
  227. var res: underlyingType
  228. buffer.read(res)
  229. result = typeName(res)
  230. proc `pack`*(buffer: PBuffer; ord: var typeName) =
  231. #writeData(s, addr p, sizeof(p))
  232. buffer.write(underlyingType(ord))
  233. when false:
  234. type
  235. SomeEnum = enum
  236. A = 0'i8,
  237. B, C
  238. forwardPacket(SomeEnum, int8)
  239. defPacket(Foo, tuple[x: array[0..4, int8]])
  240. var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
  241. var s2 = newStringStream("")
  242. f.pack(s2)
  243. assert s2.data == "\4\3\2\1\0"
  244. var s = newStringStream()
  245. s.flushImpl = proc(s: PStream) =
  246. var z = PStringStream(s)
  247. z.setPosition(0)
  248. z.data.setLen(0)
  249. s.setPosition(0)
  250. s.data.setLen(0)
  251. var o = B
  252. o.pack(s)
  253. o = A
  254. o.pack(s)
  255. o = C
  256. o.pack(s)
  257. assert s.data == "\1\0\2"
  258. s.flush
  259. defPacket(Y, tuple[z: int8])
  260. proc `$`(z: Y): string = result = "Y(" & $z.z & ")"
  261. defPacket(TestPkt, tuple[x: seq[Y]])
  262. var test = newTestPkt()
  263. test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
  264. for itm in test.x:
  265. echo(itm)
  266. test.pack(s)
  267. echo(repr(s.data))