nifcore-based IC serialization helpers — Stage 1 of porting the IC backend from the old nifstreams/nifcursors NIF stack to nifcore (see doc/ic_nifcore_port.md).
It hosts:
- the process-wide shared Pool/TagPool that stands in for the old global nifstreams.pool,
- writeFileStable, the content-stable file writer mirroring nifcursors.writeFile(..., OnlyIfChanged),
- the first ported writer (writeSemDeps), used as the migration spike.
No nifstreams/nifcursors types cross this module's boundary: callers pass plain Nim values (config, ids, string lists), so it can coexist with the still-old-API ast2nif.nim during the migration.
Types
CookieKind = enum ckParLe, ckParRi, ckSym, ckSymDef, ckIdent, ckStr, ckInt, ckUInt, ckFloat, ckChar, ckDot
- Source Edit
CookieTok = object kind*: CookieKind tag*: string name*: string sym*: uint32 str*: string ival*: int64 uval*: uint64 fval*: float64 cval*: uint32
- Source Edit
IcBuilder = object buf*: TokenBuf
- A thin nifcore TokenBuf builder whose surface is primitive types only (strings/ints/floats). It lets the still-old-API ast2nif.nim drive a nifcore buffer without any nifcore type crossing the module boundary — the bridge that routes IC output onto the nifcore serializer (Stage 2). Source Edit
Procs
proc addCharLit(b: var IcBuilder; c: char) {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc addDotToken(b: var IcBuilder) {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc addFloatLit(b: var IcBuilder; v: float64) {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc addStmtsBody(dest: var IcBuilder; src: var IcBuilder) {....raises: [], tags: [], forbids: [].}
- Append the BODY of a (stmts . . <body> ) builder into dest, dropping the wrapper tag and its two leading dot slots (flags/type) — the nifcore analogue of the old for i in 3 ..< content.len-1: dest.add content[i]. Source Edit
proc addUIntLit(b: var IcBuilder; v: uint64) {.inline, ...raises: [], tags: [], forbids: [].}
- Source Edit
proc collectBifStrLits(path: string): seq[string] {....raises: [IOError], tags: [ReadIOEffect], forbids: [].}
- Read a small (tag "s" "s" …) bif sidecar (semdeps/edges) and return every string literal it holds, in order — the binary analogue of the old nifstreams scan that collected StrLits. Keeps nifcore types out of deps.nim, which only needs the recorded string list. Source Edit
proc createIcBuf(cap = 16): TokenBuf {.inline, ...raises: [], tags: [], forbids: [].}
- A TokenBuf bound to the shared IC pools. Source Edit
proc cursorPool(c: Cursor): Pool {.inline, ...raises: [], tags: [], forbids: [].}
- The literals pool the cursor's buffer was built against. ast2nif.nim imports nifcore with except pool (to keep nifstreams' global pool var the writer uses), so the reader reaches a cursor's pool through here — needed once bif-loaded buffers carry their OWN fresh pool rather than the shared icPool. Source Edit
proc flattenForCookie(b: var IcBuilder): seq[CookieTok] {....raises: [], tags: [], forbids: [].}
- Flatten the nifcore module buffer to the cookie hashers' flat token list. Source Edit
proc lineInfo(b: var IcBuilder; file: string; line, col: int32; comment = "") {. ...raises: [], tags: [], forbids: [].}
- Attach line info (+ optional #comment#) to the head just emitted. No-op when file is empty (matches the old "emit only when info is valid"). Strings are interned in the shared pools; the file/comment ids reproduce the old pool.files/pool.strings entries by string value. Source Edit
proc newIcBuilder(cap = 16): IcBuilder {....raises: [], tags: [], forbids: [].}
- Source Edit
proc storeBifStable(b: var IcBuilder; path: string; dottedSuffix: string) {. ...raises: [IOError, OSError, Exception], tags: [WriteIOEffect, ReadIOEffect, WriteDirEffect, ReadDirEffect], forbids: [].}
- Content-stable bif write — the binary analogue of writeFileStable's onlyIfChanged: only replace path when the encoded bytes differ, so an unchanged sidecar keeps its mtime and nifmake prunes the dependent rebuild cascade. Used for the iface/impl cookies + dep sidecars whose byte-stability gates incremental builds. (bif encoding is deterministic for a given buffer under fresh pools, so equal content ⇒ equal bytes.) Source Edit
proc writeFileStable(b: var TokenBuf; path: string; onlyIfChanged = false) {. ...raises: [Exception, IOError], tags: [RootEffect, ReadIOEffect, WriteIOEffect], forbids: [].}
- Serialize b to canonical module NIF text and write it. Mirrors nifcursors.writeFile: the module suffix is derived from path ("." & extractModuleSuffix), and onlyIfChanged skips the write when the on-disk bytes already match — the content-stability nifmake's incremental rebuild depends on. Source Edit
proc writeSemDeps(config: ConfigRef; thisModule: int32; importPaths: seq[string]) {. ...raises: [OSError, IOError, Exception], tags: [RootEffect, ReadEnvEffect, ReadIOEffect, WriteIOEffect, WriteDirEffect, ReadDirEffect], forbids: [].}
- Stage 1 spike: the nifcore port of ast2nif.writeSemDeps. Serializes the module's resolved direct imports as (semdeps "path" ...). Byte-identical to the old writer (verified), so nim ic build graphs are unaffected. Source Edit
proc writeStable(b: var IcBuilder; path: string; onlyIfChanged = false) {. inline, ...raises: [Exception, IOError], tags: [RootEffect, ReadIOEffect, WriteIOEffect], forbids: [].}
- Source Edit