mirror of
https://github.com/zap-proto/nim.git
synced 2026-10-30 15:04:34 +00:00
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.
193 lines
6.6 KiB
Nim
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))
|