Files
nim/zap/gensupport.nim
zeekay 68037f9ca4 Rebrand Cap'n Proto Nim port to ZAP
Rename the capnp/ module set to zap/ and the capnpc compiler to zapc;
rename all .capnp schemas and fixtures to .zap; update every import,
include guard (isInZap), generated-code emission, exception type
(ZapFormatError), and the macro-generated zapUnpackStructImpl/
zapPackStructImpl identifiers to the ZAP brand. Zero capnp/Cap'n Proto
references remain in source or build files; upstream MIT attribution
(Sandstorm, Michał Zieliński) is preserved.

Raise the nimble nim floor from the fictional 0.12.0 to the locked,
verified 0.15.2 (matches nimenv.cfg/build.sh; code carries fixes through
Nim 0.18). Rewrite TODO.md as honest, source-anchored known-limitations
(two-word intersegment pointers, nested/named-union codegen, RPC
interface inheritance) instead of a bare wishlist.
2026-06-19 23:42:02 -07:00

193 lines
6.6 KiB
Nim

# included from zap/gensupport.nim
import macros, strutils, zap, collections, typetraits
export typetraits.name
type PointerFlag* {.pure.} = enum
none, text
template kindMatches(obj, v): typed =
assert obj != nil
when v is bool:
v
else:
obj.kind == v
template zapUnpackScalarMember*(name, fieldOffset, fieldDefault, condition) =
if kindMatches(result, condition):
if fieldOffset + sizeof(name) > dataLength:
name = fieldDefault
else:
name = self.unpackScalar(offset + fieldOffset, type(name), fieldDefault)
template zapUnpackBoolMember*(name, fieldOffset, fieldDefault, condition) =
if kindMatches(result, condition):
if fieldOffset div 8 >= dataLength:
name = fieldDefault
else:
name = self.unpackBool(offset, fieldOffset, defaultValue=fieldDefault)
template zapPackScalarMember*(name, fieldOffset, fieldDefault, condition) =
if kindMatches(value, condition):
packScalar(scalarBuffer, fieldOffset, name, fieldDefault)
template zapPackBoolMember*(name, fieldOffset, fieldDefault, condition) =
if kindMatches(value, condition):
packBool(scalarBuffer, fieldOffset, name, fieldDefault)
template zapUnpackPointerMember*(name, pointerIndex, flag, condition) =
if kindMatches(result, condition):
name = defaultVal(type(name))
if pointerIndex < pointerCount:
let realOffset = offset + pointerIndex * 8 + dataLength
if realOffset + 8 <= buffer(self).len:
when flag == PointerFlag.text:
name = unpackText(self, realOffset, type(name))
else:
name = unpackPointer(self, realOffset, type(name))
template zapPreparePack*() =
trimWords(scalarBuffer, minDataSize * 8)
if bufferM != nil:
bufferM.insertAt(dataOffset, scalarBuffer)
var pointers {.inject.}: seq[bool] = @[]
template zapPreparePackPointer*(name, offset, condition) =
if kindMatches(value, condition):
if not isNil(name) and pointers.len <= offset:
pointers.setLen offset + 1
template zapPreparePackFinish*() =
let pointerOffset {.inject.} = dataOffset + scalarBuffer.len
if bufferM != nil:
bufferM.insertAt(pointerOffset, newZeroString(pointers.len * 8))
template zapPackPointer*(name, offset, flag, condition): untyped =
if bufferM != nil and kindMatches(value, condition) and not isNil(name):
when flag == PointerFlag.text:
packText(p, pointerOffset + offset * 8, name)
else:
packPointer(p, pointerOffset + offset * 8, name)
template zapPackFinish*(): untyped =
assert((scalarBuffer.len mod 8) == 0, "")
return (tuple[dataSize: int, pointerCount: int])((scalarBuffer.len div 8, pointers.len))
template zapGetPointerField*(name, pointerIndex, condition) =
if pointerIndex == index and kindMatches(self, condition):
return name.toAnyPointer
proc newComplexDotExpr(a: NimNode, b: NimNode): NimNode {.compileTime.} =
var b = b
var a = a
while b.kind == nnkDotExpr:
a = newDotExpr(a, b[0])
b = b[1]
return newDotExpr(a, b)
proc makeUnpacker(typename: NimNode, scalars: NimNode, pointers: NimNode, bools: NimNode): NimNode {.compiletime.} =
# zapUnpackStructImpl is generic to delay instantation
result = parseStmt("""proc zapUnpackStructImpl*[T: XXX](self: Unpacker, offset: int, dataLength: int, pointerCount: int, typ: typedesc[T]): T =
new(result)""")
result[0][2][0][1] = typeName # replace XXX
#result.treeRepr.echo
var body = result[0][^1]
let resultId = newIdentNode($"result")
for p in scalars:
let name = p[0]
let offset = p[1]
let default = p[2]
let condition = p[3]
body.add(newCall(!"zapUnpackScalarMember", newComplexDotExpr(resultId, name), offset, default, condition))
for p in bools:
let name = p[0]
let offset = p[1]
let default = p[2]
let condition = p[3]
body.add(newCall(!"zapUnpackBoolMember", newComplexDotExpr(resultId, name), offset, default, condition))
for p in pointers:
let name = p[0]
let offset = p[1]
let flag = p[2]
let condition = p[3]
body.add(newCall(!"zapUnpackPointerMember", newComplexDotExpr(resultId, name), offset, flag, condition))
proc makePacker(typename: NimNode, scalars: NimNode, pointers: NimNode, bools: NimNode): NimNode {.compiletime.} =
# bufferM should be named buffer, but compiler manages to confuse it with buffer proc in unpack
result = parseStmt("""proc zapPackStructImpl*[T: XXX](p: Packer, bufferM: var string, value: T, dataOffset: int, minDataSize=0): tuple[dataSize: int, pointerCount: int] =
var scalarBuffer = newZeroString(max(@[int(0)]))""")
result[0][2][0][1] = typeName # replace XXX
let body = result[0][6]
let sizesList = body[0][0][2][1][1][1]
let valueId = newIdentNode($"value")
for p in scalars:
let name = p[0]
let offset = p[1]
sizesList.add(newCall(newIdentNode($"+"), newCall(newIdentNode($"zapSizeof"), newComplexDotExpr(valueId, name)), offset))
for p in bools:
let offset = p[1]
sizesList.add(newCall(!"int", newLit((offset.intVal + 8) div 8)))
for p in scalars:
let name = p[0]
let offset = p[1]
let default = p[2]
let condition = p[3]
body.add(newCall(!"zapPackScalarMember", newComplexDotExpr(valueId, name), offset, default, condition))
for p in bools:
let name = p[0]
let offset = p[1]
let default = p[2]
let condition = p[3]
body.add(newCall(!"zapPackBoolMember", newComplexDotExpr(valueId, name), offset, default, condition))
body.add(newCall(!"zapPreparePack"))
for p in pointers:
let name = p[0]
let offset = p[1]
let condition = p[3]
body.add(newCall(!"zapPreparePackPointer", newComplexDotExpr(valueId, name), offset, condition))
body.add(newCall(!"zapPreparePackFinish"))
for p in pointers:
let name = p[0]
let offset = p[1]
let flag = p[2]
let condition = p[3]
body.add(newCall(!"zapPackPointer", newComplexDotExpr(valueId, name), offset, flag, condition))
body.add(parseStmt("zapPackFinish()"))
proc makeGetPointerField(typename: NimNode, pointers: NimNode): NimNode {.compiletime.} =
result = parseStmt("""proc getPointerField*[T: XXX](self: T, index: int): AnyPointer =
discard""")
result[0][2][0][1] = typeName # replace XXX
let body = result[0][6]
for p in pointers:
let name = p[0]
let offset = p[1]
let condition = p[3]
body.add(newCall(!"zapGetPointerField", newComplexDotExpr(newIdentNode("self"), name), offset, condition))
macro makeStructCoders*(typeName, scalars, pointers, bitfields): untyped =
newNimNode(nnkStmtList)
.add(makeGetPointerField(typeName, pointers))
.add(makeUnpacker(typeName, scalars, pointers, bitfields))
.add(makePacker(typeName, scalars, pointers, bitfields))