123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- import macros, macro_dsl, estreams
- from strutils import format
- template newLenName() =
- let lenName {.inject.} = ^("len" & $lenNames)
- inc(lenNames)
- template defPacketImports*() {.dirty.} =
- import macros, macro_dsl, estreams
- from strutils import format
- macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
- result = newNimNode(nnkStmtList)
- let
- typeName = quoted2ident(typeNameN)
- packetID = ^"p"
- streamID = ^"s"
- var
- constructorParams = newNimNode(nnkFormalParams).und(typeName)
- constructor = newNimNode(nnkProcDef).und(
- postfix(^("new" & $typeName.ident), "*"),
- emptyNode(),
- emptyNode(),
- constructorParams,
- emptyNode(),
- emptyNode())
- pack = newNimNode(nnkProcDef).und(
- postfix(^"pack", "*"),
- emptyNode(),
- emptyNode(),
- newNimNode(nnkFormalParams).und(
- emptyNode(), # : void
- newNimNode(nnkIdentDefs).und(
- streamID, # s: PBuffer
- ^"PBuffer",
- newNimNode(nnkNilLit)),
- newNimNode(nnkIdentDefs).und(
- packetID, # p: var typeName
- newNimNode(nnkVarTy).und(typeName),
- emptyNode())),
- emptyNode(),
- emptyNode())
- read = newNimNode(nnkProcDef).und(
- newIdentNode("read" & $typeName.ident).postfix("*"),
- emptyNode(),
- emptyNode(),
- newNimNode(nnkFormalParams).und(
- typeName, #result type
- newNimNode(nnkIdentDefs).und(
- streamID, # s: PBuffer = nil
- ^"PBuffer",
- newNimNode(nnkNilLit))),
- emptyNode(),
- emptyNode())
- constructorBody = newNimNode(nnkStmtList)
- packBody = newNimNode(nnkStmtList)
- readBody = newNimNode(nnkStmtList)
- lenNames = 0
- for i in 0.. typeFields.len - 1:
- let
- name = typeFields[i][0]
- dotName = packetID.dot(name)
- resName = newIdentNode("result").dot(name)
- case typeFields[i][1].kind
- of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
- case $typeFields[i][1][0].ident
- of "seq":
- ## let lenX = readInt16(s)
- newLenName()
- let
- item = ^"item" ## item name in our iterators
- seqType = typeFields[i][1][1] ## type of seq
- readName = newIdentNode("read" & $seqType.ident)
- readBody.add(newNimNode(nnkLetSection).und(
- newNimNode(nnkIdentDefs).und(
- lenName,
- newNimNode(nnkEmpty),
- newCall("readInt16", streamID))))
- readBody.add( ## result.name = @[]
- resName := ("@".prefix(newNimNode(nnkBracket))),
- newNimNode(nnkForStmt).und( ## for item in 1..len:
- item,
- infix(1.lit, "..", lenName),
- newNimNode(nnkStmtList).und(
- newCall( ## add(result.name, unpack[seqType](stream))
- "add", resName, newNimNode(nnkCall).und(readName, streamID)
- ) ) ) )
- packbody.add(
- newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
- lenName, ## var lenName = int16(len(p.name))
- newIdentNode("int16"),
- newCall("int16", newCall("len", dotName)))),
- newCall("writeBE", streamID, lenName),
- newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream)
- item,
- infix(0.lit, "..", infix(lenName, "-", 1.lit)),
- newNimNode(nnkStmtList).und(
- newCall("echo", item, ": ".lit),
- newCall("pack", streamID, dotName[item]))))
- #set the default value to @[] (new sequence)
- typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
- else:
- error("Unknown type: " & treeRepr(typeFields[i]))
- of nnkIdent: ##normal type
- case $typeFields[i][1].ident
- of "string": # length encoded string
- packBody.add(newCall("write", streamID, dotName))
- readBody.add(resName := newCall("readStr", streamID))
- of "int8", "int16", "int32", "float32", "float64", "char", "bool":
- packBody.add(newCall(
- "writeBE", streamID, dotName))
- readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
- else: ## hopefully the type you specified was another defpacket() type
- packBody.add(newCall("pack", streamID, dotName))
- readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
- else:
- error("I dont know what to do with: " & treerepr(typeFields[i]))
- var
- toStringFunc = newNimNode(nnkProcDef).und(
- newNimNode(nnkPostfix).und(
- ^"*",
- newNimNode(nnkAccQuoted).und(^"$")),
- emptyNode(),
- emptyNode(),
- newNimNode(nnkFormalParams).und(
- ^"string",
- newNimNode(nnkIdentDefs).und(
- packetID, # p: typeName
- typeName,
- emptyNode())),
- emptyNode(),
- emptyNode(),
- newNimNode(nnkStmtList).und(# [6]
- newNimNode(nnkAsgn).und(
- ^"result", ## result =
- newNimNode(nnkCall).und(# [6][0][1]
- ^"format", ## format
- emptyNode())))) ## "[TypeName $1 $2]"
- formatStr = "[" & $typeName.ident
- const emptyFields = {nnkEmpty, nnkNilLit}
- var objFields = newNimNode(nnkRecList)
- for i in 0 ..< len(typeFields):
- let fname = typeFields[i][0]
- constructorParams.add(newNimNode(nnkIdentDefs).und(
- fname,
- typeFields[i][1],
- typeFields[i][2]))
- constructorBody.add((^"result").dot(fname) := fname)
- #export the name
- typeFields[i][0] = fname.postfix("*")
- if not(typeFields[i][2].kind in emptyFields):
- ## empty the type default for the type def
- typeFields[i][2] = newNimNode(nnkEmpty)
- objFields.add(typeFields[i])
- toStringFunc[6][0][1].add(
- prefix("$", packetID.dot(fname)))
- formatStr.add " $"
- formatStr.add($(i + 1))
- formatStr.add ']'
- toStringFunc[6][0][1][1] = formatStr.lit()
- result.add(
- newNimNode(nnkTypeSection).und(
- newNimNode(nnkTypeDef).und(
- typeName.postfix("*"),
- newNimNode(nnkEmpty),
- newNimNode(nnkObjectTy).und(
- newNimNode(nnkEmpty), #not sure what this is
- newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
- objFields))))
- result.add(constructor.und(constructorBody))
- result.add(pack.und(packBody))
- result.add(read.und(readBody))
- result.add(toStringFunc)
- when defined(GenPacketShowOutput):
- echo(repr(result))
- proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
- result = newNimNode(nnkProcDef).und(
- name,
- emptyNode(),
- emptyNode(),
- newNimNode(nnkFormalParams).und(resultType),
- emptyNode(),
- emptyNode(),
- newNimNode(nnkStmtList))
- result[3].add(params)
- proc body*(procNode: NimNode): NimNode {.compileTime.} =
- assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
- result = procNode[6]
- proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
- result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
- proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
- result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
- proc varTy*(a: NimNode): NimNode {.compileTime.} =
- result = newNimNode(nnkVarTy).und(a)
- macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped =
- var
- packetID = ^"p"
- streamID = ^"s"
- result = newNimNode(nnkStmtList).und(
- newProc(
- (^("read" & $typeName.ident)).postfix("*"),
- [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
- typeName),
- newProc(
- (^"pack").postfix("*"),
- [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)),
- iddefs("p", varTy(typeName)) ],
- emptyNode()))
- var
- readBody = result[0][6]
- packBody = result[1][6]
- resName = ^"result"
- case underlyingType.kind
- of nnkBracketExpr:
- case $underlyingType[0].ident
- of "array":
- for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int:
- readBody.add(
- newCall("read", ^"s", resName[lit(i)]))
- packBody.add(
- newCall("writeBE", ^"s", packetID[lit(i)]))
- else:
- echo "Unknown type: ", repr(underlyingtype)
- else:
- echo "unknown type:", repr(underlyingtype)
- echo(repr(result))
- template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} =
- proc `read typeName`*(buffer: PBuffer): typeName =
- #discard readData(s, addr result, sizeof(result))
- var res: underlyingType
- buffer.read(res)
- result = typeName(res)
- proc `pack`*(buffer: PBuffer; ord: var typeName) =
- #writeData(s, addr p, sizeof(p))
- buffer.write(underlyingType(ord))
- when false:
- type
- SomeEnum = enum
- A = 0'i8,
- B, C
- forwardPacket(SomeEnum, int8)
- defPacket(Foo, tuple[x: array[0..4, int8]])
- var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
- var s2 = newStringStream("")
- f.pack(s2)
- assert s2.data == "\4\3\2\1\0"
- var s = newStringStream()
- s.flushImpl = proc(s: PStream) =
- var z = PStringStream(s)
- z.setPosition(0)
- z.data.setLen(0)
- s.setPosition(0)
- s.data.setLen(0)
- var o = B
- o.pack(s)
- o = A
- o.pack(s)
- o = C
- o.pack(s)
- assert s.data == "\1\0\2"
- s.flush
- defPacket(Y, tuple[z: int8])
- proc `$`(z: Y): string = result = "Y(" & $z.z & ")"
- defPacket(TestPkt, tuple[x: seq[Y]])
- var test = newTestPkt()
- test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
- for itm in test.x:
- echo(itm)
- test.pack(s)
- echo(repr(s.data))
|