diff --git a/compiler/ast.nim b/compiler/ast.nim index d80589c087d36..1a686b2f6f728 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -268,6 +268,7 @@ type tyVoid # now different from tyEmpty, hurray! tyIterable + tyStub static: # remind us when TTypeKind stops to fit in a single 64-bit word @@ -786,7 +787,7 @@ type sym*: PSym # types have the sym associated with them # it is used for converting types to strings size*: BiggestInt # the size of the type in bytes - # -1 means that the size is unkwown + # -1 means that the size is unknown align*: int16 # the type's alignment requirements paddingAtEnd*: int16 # loc*: TLoc diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim new file mode 100644 index 0000000000000..9bbc80ec345a4 --- /dev/null +++ b/compiler/ast2nif.nim @@ -0,0 +1,886 @@ +# +# +# The Nim Compiler +# (c) Copyright 2025 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## AST to NIF bridge. + +import std / [assertions, tables, sets] +from std / strutils import startsWith +import ast, idents, msgs, options +import lineinfos as astli +import pathutils +import "../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos, + nifindexes, nifreader] +import "../dist/nimony/src/gear2" / modnames + +import icnif / [enum2nif] + +# ---------------- Line info handling ----------------------------------------- + +type + LineInfoWriter = object + fileK: FileIndex # remember the current pair, even faster than the hash table + fileV: FileId + tab: Table[FileIndex, FileId] + revTab: Table[FileId, FileIndex] # reverse mapping for oldLineInfo + man: LineInfoManager + config: ConfigRef + +proc get(w: var LineInfoWriter; key: FileIndex): FileId = + if w.fileK == key: + result = w.fileV + else: + if key in w.tab: + result = w.tab[key] + w.fileK = key + w.fileV = result + else: + result = pool.files.getOrIncl(msgs.toFullPath(w.config, key)) + w.fileK = key + w.fileV = result + w.tab[key] = result + w.revTab[result] = key + +proc nifLineInfo(w: var LineInfoWriter; info: TLineInfo): PackedLineInfo = + if info == unknownLineInfo: + result = NoLineInfo + else: + let fid = get(w, info.fileIndex) + result = pack(w.man, fid, info.line.int32, info.col) + +proc oldLineInfo(w: var LineInfoWriter; info: PackedLineInfo): TLineInfo = + if info == NoLineInfo: + result = unknownLineInfo + else: + var x = unpack(w.man, info) + var fileIdx: FileIndex + if w.fileV == x.file: + fileIdx = w.fileK + elif x.file in w.revTab: + fileIdx = w.revTab[x.file] + else: + # Need to look up FileId -> FileIndex via the file path + let filePath = pool.files[x.file] + fileIdx = msgs.fileInfoIdx(w.config, AbsoluteFile filePath) + w.revTab[x.file] = fileIdx + result = TLineInfo(line: x.line.uint16, col: x.col.int16, fileIndex: fileIdx) + + +# -------------- Module name handling -------------------------------------------- + +proc modname(moduleToNifSuffix: var Table[FileIndex, string]; module: int; conf: ConfigRef): string = + let idx = module.FileIndex + # copied from ../nifgen.nim + result = moduleToNifSuffix.getOrDefault(idx) + if result.len == 0: + let fp = toFullPath(conf, idx) + result = moduleSuffix(fp, cast[seq[string]](conf.searchPaths)) + moduleToNifSuffix[idx] = result + #echo result, " -> ", fp + +proc modname(moduleToNifSuffix: var Table[FileIndex, string]; module: PSym; conf: ConfigRef): string = + assert module.kind == skModule + result = modname(moduleToNifSuffix, module.position, conf) + + + +# ------------- Writer --------------------------------------------------------------- + +#[ + +Strategy: + +We produce NIF from the PNode structure as the single source of truth. NIF nodes can +however, refer to PSym and PType, these get NIF names. If the PSym/PType belongs to +the module that we are currently writing, we emit these fields as an inner NIF +structure via the special tags `sd` and `td`. In fact it is only these tags +that get the NIF `SymbolDef` kinds so that the lazy loading mechanism cannot +be confused. + +We could also emit non-local symbols and types later as the index structure +will tell us the precise offsets anyway. + +]# + +let + sdefTag = registerTag("sd") + tdefTag = registerTag("td") + tuseTag = registerTag("t") + hiddenTypeTag = registerTag("ht") + +type + Writer = object + deps: TokenBuf # include&import deps + infos: LineInfoWriter + currentModule: int32 + writtenSyms: HashSet[ItemId] + writtenTypes: HashSet[ItemId] + decodedFileIndices: HashSet[FileIndex] + moduleToNifSuffix: Table[FileIndex, string] + locals: HashSet[ItemId] # track proc-local symbols + inProc: int + +proc toNifSymName(w: var Writer; sym: PSym): string = + ## Generate NIF name for a symbol: local names are `ident.disamb`, + ## global names are `ident.disamb.moduleSuffix` + result = sym.name.s + result.add '.' + result.addInt sym.disamb + if sym.itemId notin w.locals: + # Global symbol: ident.disamb.moduleSuffix + let module = sym.itemId.module + result.add '.' + result.add modname(w.moduleToNifSuffix, module, w.infos.config) + +type + ParsedSymName* = object + name*: string + module*: string + count*: int + +proc parseSymName*(s: string): ParsedSymName = + var i = s.len - 2 + while i > 0: + if s[i] == '.': + if s[i+1] in {'0'..'9'}: + var count = ord(s[i+1]) - ord('0') + var j = i+2 + while j < s.len and s[j] in {'0'..'9'}: + count = count * 10 + ord(s[j]) - ord('0') + inc j + return ParsedSymName(name: substr(s, 0, i-1), module: "", count: count) + else: + let mend = s.high + var b = i-1 + while b > 0 and s[b] != '.': dec b + var j = b+1 + var count = 0 + while j < s.len and s[j] in {'0'..'9'}: + count = count * 10 + ord(s[j]) - ord('0') + inc j + + return ParsedSymName(name: substr(s, 0, b-1), module: substr(s, i+1, mend), count: count) + dec i + return ParsedSymName(name: s, module: "") + +template buildTree(dest: var TokenBuf; tag: TagId; body: untyped) = + dest.addParLe tag + body + dest.addParRi + +template buildTree(dest: var TokenBuf; tag: string; body: untyped) = + buildTree dest, pool.tags.getOrIncl(tag), body + +proc writeFlags[E](dest: var TokenBuf; flags: set[E]) = + var flagsAsIdent = "" + genFlags(flags, flagsAsIdent) + if flagsAsIdent.len > 0: + dest.addIdent flagsAsIdent + else: + dest.addDotToken + +proc trLineInfo(w: var Writer; info: TLineInfo): PackedLineInfo {.inline.} = + result = nifLineInfo(w.infos, info) + +proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) +proc writeType(w: var Writer; dest: var TokenBuf; typ: PType) +proc writeSym(w: var Writer; dest: var TokenBuf; sym: PSym) + +proc typeToNifSym(w: var Writer; typ: PType): string = + result = "`t." + result.addInt typ.uniqueId.item + result.add '.' + result.add modname(w.moduleToNifSuffix, typ.uniqueId.module, w.infos.config) + +proc writeLoc(w: var Writer; dest: var TokenBuf; loc: TLoc) = + dest.addIdent toNifTag(loc.k) + dest.addIdent toNifTag(loc.storage) + writeFlags(dest, loc.flags) # TLocFlags + dest.addStrLit loc.snippet + +proc writeTypeDef(w: var Writer; dest: var TokenBuf; typ: PType) = + dest.buildTree tdefTag: + dest.addSymDef pool.syms.getOrIncl(w.typeToNifSym(typ)), NoLineInfo + + dest.addIdent toNifTag(typ.kind) + writeFlags(dest, typ.flags) + dest.addIdent toNifTag(typ.callConv) + dest.addIntLit typ.size + dest.addIntLit typ.align + dest.addIntLit typ.paddingAtEnd + dest.addIntLit typ.itemId.item # nonUniqueId + + writeType(w, dest, typ.typeInst) + writeNode(w, dest, typ.n) + writeSym(w, dest, typ.owner) + writeSym(w, dest, typ.sym) + + # Write TLoc structure + writeLoc w, dest, typ.loc + # we store the type's elements here at the end so that + # it is not ambiguous and saves space: + for ch in typ.kids: + writeType(w, dest, ch) + + +proc writeType(w: var Writer; dest: var TokenBuf; typ: PType) = + if typ == nil: + dest.addDotToken() + elif typ.itemId.module == w.currentModule and not w.writtenTypes.containsOrIncl(typ.uniqueId): + writeTypeDef(w, dest, typ) + else: + dest.buildTree tuseTag: + dest.addSymUse pool.syms.getOrIncl(w.typeToNifSym(typ)), NoLineInfo + +proc writeBool(dest: var TokenBuf; b: bool) = + dest.buildTree (if b: "true" else: "false"): + discard + +proc writeLib(w: var Writer; dest: var TokenBuf; lib: PLib) = + if lib == nil: + dest.addDotToken() + else: + dest.buildTree toNifTag(lib.kind): + dest.writeBool lib.generated + dest.writeBool lib.isOverridden + dest.addStrLit lib.name + writeNode w, dest, lib.path + +proc writeSymDef(w: var Writer; dest: var TokenBuf; sym: PSym) = + dest.addParLe sdefTag, trLineInfo(w, sym.info) + dest.addSymDef pool.syms.getOrIncl(w.toNifSymName(sym)), NoLineInfo + if sym.magic == mNone: + dest.addDotToken + else: + dest.addIdent toNifTag(sym.magic) + writeFlags(dest, sym.flags) + writeFlags(dest, sym.options) + dest.addIntLit sym.offset + # field `disamb` made part of the name, so do not store it here + dest.buildTree sym.kind.toNifTag: + case sym.kind + of skLet, skVar, skField, skForVar: + writeSym(w, dest, sym.guard) + dest.addIntLit sym.bitsize + dest.addIntLit sym.alignment + else: + discard + if sym.kind == skModule: + dest.addDotToken() # position will be set by the loader! + else: + dest.addIntLit sym.position + writeType(w, dest, sym.typ) + writeSym(w, dest, sym.owner) + # We do not store `sym.ast` here but instead set it in the deserializer + #writeNode(w, sym.ast) + writeLoc w, dest, sym.loc + writeNode(w, dest, sym.constraint) + writeSym(w, dest, sym.instantiatedFrom) + dest.addParRi + +proc writeSym(w: var Writer; dest: var TokenBuf; sym: PSym) = + if sym == nil: + dest.addDotToken() + elif sym.itemId.module == w.currentModule and not w.writtenSyms.containsOrIncl(sym.itemId): + writeSymDef(w, dest, sym) + else: + # NIF has direct support for symbol references so we don't need to use a tag here, + # unlike what we do for types! + dest.addSymUse pool.syms.getOrIncl(w.toNifSymName(sym)), NoLineInfo + +proc writeSymNode(w: var Writer; dest: var TokenBuf; n: PNode; sym: PSym) = + if sym == nil: + dest.addDotToken() + elif sym.itemId.module == w.currentModule and not w.writtenSyms.containsOrIncl(sym.itemId): + if n.typ != n.sym.typ: + dest.buildTree hiddenTypeTag, trLineInfo(w, n.info): + writeSymDef(w, dest, sym) + else: + writeSymDef(w, dest, sym) + else: + # NIF has direct support for symbol references so we don't need to use a tag here, + # unlike what we do for types! + let info = trLineInfo(w, n.info) + if n.typ != n.sym.typ: + dest.buildTree hiddenTypeTag, info: + dest.addSymUse pool.syms.getOrIncl(w.toNifSymName(sym)), info + else: + dest.addSymUse pool.syms.getOrIncl(w.toNifSymName(sym)), info + +proc writeNodeFlags(dest: var TokenBuf; flags: set[TNodeFlag]) {.inline.} = + writeFlags(dest, flags) + +template withNode(w: var Writer; dest: var TokenBuf; n: PNode; body: untyped) = + dest.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info) + writeNodeFlags(dest, n.flags) + writeType(w, dest, n.typ) + body + dest.addParRi + +proc addLocalSym(w: var Writer; n: PNode) = + ## Add symbol from a node to locals set if it's a symbol node + if n != nil and n.kind == nkSym and n.sym != nil and w.inProc > 0: + w.locals.incl(n.sym.itemId) + +proc addLocalSyms(w: var Writer; n: PNode) = + if n.kind in {nkIdentDefs, nkVarTuple}: + # nkIdentDefs: [ident1, ident2, ..., type, default] + # All children except the last two are identifiers + for i in 0 ..< max(0, n.len - 2): + addLocalSyms(w, n[i]) + elif n.kind == nkSym: + addLocalSym(w, n) + +proc trInclude(w: var Writer; n: PNode) = + w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info) + for child in n: + assert child.kind == nkStrLit + w.deps.addStrLit child.strVal + w.deps.addParRi + +proc trImport(w: var Writer; n: PNode) = + w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info) + for child in n: + assert child.kind == nkSym + let s = child.sym + assert s.kind == skModule + let fp = toFullPath(w.infos.config, s.position.FileIndex) + w.deps.addStrLit fp + w.deps.addParRi + +proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) = + if n == nil: + dest.addDotToken + else: + case n.kind: + of nkEmpty: + let info = trLineInfo(w, n.info) + dest.addParLe pool.tags.getOrIncl(toNifTag(nkEmpty)), info + writeNodeFlags(dest, n.flags) + dest.addParRi + of nkIdent: + # nkIdent uses flags and typ when it is a generic parameter + w.withNode dest, n: + dest.addIdent n.ident.s + of nkSym: + writeSymNode(w, dest, n, n.sym) + of nkCharLit: + w.withNode dest, n: + dest.add charToken(n.intVal.char, NoLineInfo) + of nkIntLit .. nkInt64Lit: + w.withNode dest, n: + dest.addIntLit n.intVal + of nkUIntLit .. nkUInt64Lit: + w.withNode dest, n: + dest.addUIntLit cast[BiggestUInt](n.intVal) + of nkFloatLit .. nkFloat128Lit: + w.withNode dest, n: + dest.add floatToken(pool.floats.getOrIncl(n.floatVal), NoLineInfo) + of nkStrLit .. nkTripleStrLit: + w.withNode dest, n: + dest.addStrLit n.strVal + of nkNilLit: + w.withNode dest, n: + discard + of nkLetSection, nkVarSection, nkConstSection, nkGenericParams: + # Track local variables declared in let/var sections + w.withNode dest, n: + for child in n: + addLocalSyms w, child + # Process the child node + writeNode(w, dest, child) + of nkForStmt, nkTypeDef: + # Track for loop variable (first child is the loop variable) + w.withNode dest, n: + if n.len > 0: + addLocalSyms(w, n[0]) + for i in 0 ..< n.len: + writeNode(w, dest, n[i]) + of nkFormalParams: + # Track parameters (first child is return type, rest are parameters) + w.withNode dest, n: + for i in 0 ..< n.len: + if i > 0: # Skip return type + addLocalSyms(w, n[i]) + writeNode(w, dest, n[i]) + of nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef, nkLambda, nkDo, nkMacroDef: + inc w.inProc + # Entering a proc/function body - parameters are local + var ast = n + if n[namePos].kind == nkSym: + ast = n[namePos].sym.ast + w.withNode dest, ast: + # Process body and other parts + for i in 0 ..< ast.len: + writeNode(w, dest, ast[i]) + dec w.inProc + of nkImportStmt: + # this has been transformed for us, see `importer.nim` to contain a list of module syms: + trImport w, n + of nkIncludeStmt: + trInclude w, n + else: + w.withNode dest, n: + for i in 0 ..< n.len: + writeNode(w, dest, n[i]) + +proc writeToplevelNode(w: var Writer; outer, inner: var TokenBuf; n: PNode) = + case n.kind + of nkStmtList, nkStmtListExpr: + for son in n: writeToplevelNode(w, outer, inner, son) + of nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef, nkLambda, nkDo, nkMacroDef: + # Delegate to `w.topLevel`! + writeNode w, inner, n + of nkConstSection, nkTypeSection, nkTypeDef: + writeNode w, inner, n + else: + writeNode w, outer, n + +proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) = + var w = Writer(infos: LineInfoWriter(config: config), currentModule: thisModule) + var outer = createTokenBuf(300) + var inner = createTokenBuf(300) + + let rootInfo = trLineInfo(w, n.info) + outer.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo + inner.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo + + w.writeToplevelNode outer, inner, n + + outer.addParRi() + inner.addParRi() + + let m = modname(w.moduleToNifSuffix, w.currentModule, w.infos.config) + let d = toGeneratedFile(config, AbsoluteFile(m), ".nif").string + + var dest = createTokenBuf(600) + dest.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo + dest.add w.deps + dest.add outer + dest.add inner + dest.addParRi() + + writeFileAndIndex d, dest + + +# --------------------------- Loader (lazy!) ----------------------------------------------- + +proc nodeKind(n: Cursor): TNodeKind {.inline.} = + assert n.kind == ParLe + parse(TNodeKind, pool.tags[n.tagId]) + +proc expect(n: Cursor; k: set[NifKind]) = + if n.kind notin k: + when defined(debug): + writeStackTrace() + quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n + +proc expect(n: Cursor; k: NifKind) {.inline.} = + expect n, {k} + +proc incExpect(n: var Cursor; k: set[NifKind]) = + inc n + expect n, k + +proc incExpect(n: var Cursor; k: NifKind) {.inline.} = + incExpect n, {k} + +proc skipParRi(n: var Cursor) = + expect n, {ParRi} + inc n + +proc firstSon*(n: Cursor): Cursor {.inline.} = + result = n + inc result + +proc expectTag(n: Cursor; tagId: TagId) = + if n.kind == ParLe and n.tagId == tagId: + discard + else: + when defined(debug): + writeStackTrace() + if n.kind != ParLe: + quit "[NIF decoder] expected: ParLe but got: " & $n.kind & toString n + else: + quit "[NIF decoder] expected: " & pool.tags[tagId] & " but got: " & pool.tags[n.tagId] & toString n + +proc incExpectTag(n: var Cursor; tagId: TagId) = + inc n + expectTag(n, tagId) + +proc loadBool(n: var Cursor): bool = + if n.kind == ParLe: + result = pool.tags[n.tagId] == "true" + inc n + skipParRi n + else: + raiseAssert "(true)/(false) expected" + +type + NifModule = object + stream: nifstreams.Stream + symCounter: int32 + index: NifIndex + + DecodeContext* = object + infos: LineInfoWriter + moduleIds: Table[string, int32] + types: Table[ItemId, (PType, NifIndexEntry)] + syms: Table[ItemId, (PSym, NifIndexEntry)] + mods: seq[NifModule] + cache: IdentCache + moduleToNifSuffix: Table[FileIndex, string] + +proc createDecodeContext*(config: ConfigRef; cache: IdentCache): DecodeContext = + ## Supposed to be a global variable + result = DecodeContext(infos: LineInfoWriter(config: config), cache: cache) + +proc idToIdx(x: int32): int {.inline.} = + assert x <= -2'i32 + result = -(x+2) + +proc cursorFromIndexEntry(c: var DecodeContext; module: int32; entry: NifIndexEntry; + buf: var TokenBuf): Cursor = + let m = idToIdx(module) + let s = addr c.mods[m].stream + s.r.jumpTo entry.offset + var buf = createTokenBuf(30) + nifcursors.parse(s[], buf, entry.info) + result = cursorAt(buf, 0) + +proc moduleId(c: var DecodeContext; suffix: string): int32 = + # We don't know the "real" FileIndex due to our mapping to a short "Module suffix" + # This is not a problem, we use negative `ItemId.module` values here and then + # there is no interference with in-memory-modules. Modulegraphs.nim already uses -1 + # so we start at -2 here. + result = c.moduleIds.getOrDefault(suffix) + if result == 0: + result = -int32(c.moduleIds.len + 2) # negative index! + let modFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".nif")).string + let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".idx.nif")).string + c.moduleIds[suffix] = result + c.mods.add NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile)) + assert c.mods.len-1 == idToIdx(result) + +proc getOffset(c: var DecodeContext; module: int32; nifName: string): NifIndexEntry = + assert module < 0'i32 + let index = idToIdx(module) + let ii = addr c.mods[index].index + result = ii.public.getOrDefault(nifName) + if result.offset == 0: + result = ii.private.getOrDefault(nifName) + if result.offset == 0: + raiseAssert "symbol has no offset: " & nifName + +proc loadNode(c: var DecodeContext; n: var Cursor): PNode + +proc loadTypeStub(c: var DecodeContext; t: SymId): PType = + let name = pool.syms[t] + assert name.startsWith("`t.") + var i = len("`t.") + var itemId = 0'i32 + while i < name.len and name[i] in {'0'..'9'}: + itemId = itemId * 10'i32 + int32(name[i].ord - ord('0')) + inc i + if i < name.len and name[i] == '.': inc i + let suffix = name.substr(i) + let id = ItemId(module: moduleId(c, suffix), item: itemId) + result = c.types.getOrDefault(id)[0] + if result == nil: + let offs = c.getOffset(id.module, name) + result = PType(itemId: id, uniqueId: id, kind: tyStub) + c.types[id] = (result, offs) + +proc loadTypeStub(c: var DecodeContext; n: var Cursor): PType = + if n.kind == DotToken: + result = nil + inc n + elif n.kind == Symbol: + let s = n.symId + result = loadTypeStub(c, s) + inc n + elif n.kind == ParLe and n.tagId == tdefTag: + let s = n.firstSon.symId + skip n + result = loadTypeStub(c, s) + else: + raiseAssert "type expected but got " & $n.kind + +proc loadSymStub(c: var DecodeContext; t: SymId): PSym = + let symAsStr = pool.syms[t] + let sn = parseSymName(symAsStr) + let module = moduleId(c, sn.module) + let val = addr c.mods[idToIdx(module)].symCounter + inc val[] + + let id = ItemId(module: module, item: val[]) + result = c.syms.getOrDefault(id)[0] + if result == nil: + let offs = c.getOffset(module, symAsStr) + result = PSym(itemId: id, kind: skStub, name: c.cache.getIdent(sn.name), disamb: sn.count.int32) + c.syms[id] = (result, offs) + +proc loadSymStub(c: var DecodeContext; n: var Cursor): PSym = + if n.kind == DotToken: + result = nil + inc n + elif n.kind == Symbol: + let s = n.symId + result = loadSymStub(c, s) + inc n + elif n.kind == ParLe and n.tagId == sdefTag: + let s = n.firstSon.symId + skip n + result = loadSymStub(c, s) + else: + raiseAssert "sym expected but got " & $n.kind + +proc isStub*(t: PType): bool {.inline.} = t.kind == tyStub +proc isStub*(s: PSym): bool {.inline.} = s.kind == skStub + +proc loadAtom[T](t: typedesc[set[T]]; n: var Cursor): set[T] = + if n.kind == DotToken: + result = {} + inc n + else: + expect n, Ident + result = parse(T, pool.strings[n.litId]) + inc n + +proc loadAtom[T: enum](t: typedesc[T]; n: var Cursor): T = + if n.kind == DotToken: + result = default(T) + inc n + else: + expect n, Ident + result = parse(T, pool.strings[n.litId]) + inc n + +proc loadAtom(t: typedesc[string]; n: var Cursor): string = + expect n, StringLit + result = pool.strings[n.litId] + inc n + +proc loadAtom[T: int16|int32|int64](t: typedesc[T]; n: var Cursor): T = + expect n, IntLit + result = pool.integers[n.intId].T + inc n + +template loadField(field) = + field = loadAtom(typeof(field), n) + +proc loadLoc(c: var DecodeContext; n: var Cursor; loc: var TLoc) = + loadField loc.k + loadField loc.storage + loadField loc.flags + loadField loc.snippet + +proc loadType*(c: var DecodeContext; t: PType) = + if t.kind != tyStub: return + var buf = createTokenBuf(30) + var n = cursorFromIndexEntry(c, t.itemId.module, c.types[t.itemId][1], buf) + + expect n, ParLe + if n.tagId != tdefTag: + raiseAssert "(td) expected" + inc n + expect n, SymbolDef + # ignore the type's name, we have already used it to create this PType's itemId! + inc n + loadField t.kind + loadField t.flags + loadField t.callConv + loadField t.size + loadField t.align + loadField t.paddingAtEnd + loadField t.itemId.item + + t.typeInst = loadTypeStub(c, n) + t.n = loadNode(c, n) + t.setOwner loadSymStub(c, n) + t.sym = loadSymStub(c, n) + loadLoc c, n, t.loc + + var kids: seq[PType] = @[] + while n.kind != ParRi: + kids.add loadTypeStub(c, n) + + t.setSons kids + + skipParRi n + +proc loadAnnex(c: var DecodeContext; n: var Cursor): PLib = + if n.kind == DotToken: + result = nil + inc n + elif n.kind == ParLe: + result = PLib(kind: parse(TLibKind, pool.tags[n.tagId])) + inc n + result.generated = loadBool(n) + result.isOverridden = loadBool(n) + expect n, StringLit + result.name = pool.strings[n.litId] + inc n + result.path = loadNode(c, n) + skipParRi n + else: + raiseAssert "`lib/annex` information expected" + +proc loadSym*(c: var DecodeContext; s: PSym) = + if s.kind != skStub: return + var buf = createTokenBuf(30) + var n = cursorFromIndexEntry(c, s.itemId.module, c.syms[s.itemId][1], buf) + + expect n, ParLe + if n.tagId != sdefTag: + raiseAssert "(sd) expected" + inc n + expect n, SymbolDef + # ignore the symbol's name, we have already used it to create this PSym instance! + inc n + loadField s.magic + loadField s.flags + loadField s.options + loadField s.offset + + expect n, ParLe + s.kind = parse(TSymKind, pool.tags[n.tagId]) + inc n + + case s.kind + of skLet, skVar, skField, skForVar: + s.guard = loadSymStub(c, n) + loadField s.bitsize + loadField s.alignment + else: + discard + skipParRi n + + if s.kind == skModule: + expect n, DotToken + inc n + else: + loadField s.position + s.typ = loadTypeStub(c, n) + s.setOwner loadSymStub(c, n) + # We do not store `sym.ast` here but instead set it in the deserializer + #writeNode(w, sym.ast) + loadLoc c, n, s.loc + s.constraint = loadNode(c, n) + s.instantiatedFrom = loadSymStub(c, n) + skipParRi n + + +template withNode(c: var DecodeContext; n: var Cursor; result: PNode; kind: TNodeKind; body: untyped) = + let info = c.infos.oldLineInfo(n.info) + let flags = loadAtom(TNodeFlags, n) + result = newNodeI(kind, info) + result.flags = flags + result.typ = c.loadTypeStub n + body + skipParRi n + +proc loadNode(c: var DecodeContext; n: var Cursor): PNode = + result = nil + case n.kind: + of DotToken: + result = nil + inc n + of ParLe: + let kind = n.nodeKind + case kind: + of nkEmpty: + result = newNodeI(nkEmpty, c.infos.oldLineInfo(n.info)) + result.flags = loadAtom(TNodeFlags, n) + skipParRi n + of nkIdent: + let info = c.infos.oldLineInfo(n.info) + let flags = loadAtom(TNodeFlags, n) + let typ = c.loadTypeStub n + expect n, Ident + result = newIdentNode(c.cache.getIdent(pool.strings[n.litId]), info) + inc n + result.flags = flags + result.typ = typ + skipParRi n + of nkSym: + c.withNode n, result, kind: + #result.sym = c.fromNifSymbol n + discard + of nkCharLit: + c.withNode n, result, kind: + expect n, CharLit + result.intVal = n.charLit.int + inc n + of nkIntLit .. nkInt64Lit: + c.withNode n, result, kind: + expect n, IntLit + result.intVal = pool.integers[n.intId] + inc n + of nkUIntLit .. nkUInt64Lit: + c.withNode n, result, kind: + expect n, UIntLit + result.intVal = cast[BiggestInt](pool.uintegers[n.uintId]) + inc n + of nkFloatLit .. nkFloat128Lit: + c.withNode n, result, kind: + if n.kind == FloatLit: + result.floatVal = pool.floats[n.floatId] + inc n + elif n.kind == ParLe: + case pool.tags[n.tagId] + of "inf": + result.floatVal = Inf + of "nan": + result.floatVal = NaN + of "neginf": + result.floatVal = NegInf + else: + raiseAssert "expected float literal but got " & pool.tags[n.tagId] + inc n + skipParRi n + else: + raiseAssert "expected float literal but got " & $n.kind + of nkStrLit .. nkTripleStrLit: + c.withNode n, result, kind: + expect n, StringLit + result.strVal = pool.strings[n.litId] + inc n + of nkNilLit: + c.withNode n, result, kind: + discard + of nkNone: + raiseAssert "Unknown tag " & pool.tags[n.tagId] + else: + c.withNode n, result, kind: + while n.kind != ParRi: + result.addAllowNil c.loadNode n + else: + raiseAssert "Not yet implemented " & $n.kind + + +proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode = + let moduleSuffix = modname(c.moduleToNifSuffix, f.int, c.infos.config) + let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string + + var buf = createTokenBuf(300) + var s = nifstreams.open(modFile) + # XXX We can optimize this here and only load the top level entries! + try: + nifcursors.parse(s, buf, NoLineInfo) + finally: + nifstreams.close(s) + var n = cursorAt(buf, 0) + result = loadNode(c, n) + +when isMainModule: + import std / syncio + let obj = parseSymName("a.123.sys") + echo obj.name, " ", obj.module, " ", obj.count + let objb = parseSymName("abcdef.0121") + echo objb.name, " ", objb.module, " ", objb.count diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index 84478dd07e15e..0e4c73cd17edc 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -112,7 +112,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs, tyUncheckedArray, tyError, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, - tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable: + tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable, tyStub: discard proc specializeReset(p: BProc, a: TLoc) = diff --git a/compiler/commands.nim b/compiler/commands.nim index e206a37300e44..415fe6b352f7b 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -771,6 +771,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.globalOptions.incl optItaniumMangle else: localError(conf, info, "expected nim|cpp but found " & arg) + of "compress": + conf.globalOptions.incl optCompress of "g": # alias for --debugger:native conf.globalOptions.incl optCDebug conf.options.incl optLineDir diff --git a/compiler/expanddefaults.nim b/compiler/expanddefaults.nim index c520d8849f2db..e343317e54140 100644 --- a/compiler/expanddefaults.nim +++ b/compiler/expanddefaults.nim @@ -124,7 +124,7 @@ proc expandDefault(t: PType; info: TLineInfo): PNode = result = newZero(t, info, nkBracket) of tyString: result = newZero(t, info, nkStrLit) - of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc, + of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc, tyStub, tyNil, tyGenericInvocation, tyError, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward: diff --git a/compiler/icnif/enum2nif.nim b/compiler/icnif/enum2nif.nim new file mode 100644 index 0000000000000..1f77393c6aa45 --- /dev/null +++ b/compiler/icnif/enum2nif.nim @@ -0,0 +1,1861 @@ +# Generated by tools/enumgen.nim. DO NOT EDIT! + +import ".." / [ast, options] + +proc toNifTag*(s: TNodeKind): string = + case s + of nkNone: "none" + of nkEmpty: "empty" + of nkIdent: "ident" + of nkSym: "sym" + of nkType: "onlytype" + of nkCharLit: "charlit" + of nkIntLit: "intlit" + of nkInt8Lit: "int8lit" + of nkInt16Lit: "int16lit" + of nkInt32Lit: "int32lit" + of nkInt64Lit: "int64lit" + of nkUIntLit: "uintlit" + of nkUInt8Lit: "uint8lit" + of nkUInt16Lit: "uint16lit" + of nkUInt32Lit: "uint32lit" + of nkUInt64Lit: "uint64lit" + of nkFloatLit: "floatlit" + of nkFloat32Lit: "float32lit" + of nkFloat64Lit: "float64lit" + of nkFloat128Lit: "float128lit" + of nkStrLit: "strlit" + of nkRStrLit: "rstrlit" + of nkTripleStrLit: "triplestrlit" + of nkNilLit: "nil" + of nkComesFrom: "comesfrom" + of nkDotCall: "dotcall" + of nkCommand: "cmd" + of nkCall: "call" + of nkCallStrLit: "callstrlit" + of nkInfix: "infix" + of nkPrefix: "prefix" + of nkPostfix: "postfix" + of nkHiddenCallConv: "hcallconv" + of nkExprEqExpr: "vv" + of nkExprColonExpr: "kv" + of nkIdentDefs: "identdefs" + of nkVarTuple: "vartuple" + of nkPar: "par" + of nkObjConstr: "objconstr" + of nkCurly: "curly" + of nkCurlyExpr: "curlyx" + of nkBracket: "bracket" + of nkBracketExpr: "at" + of nkPragmaExpr: "pragmax" + of nkRange: "range" + of nkDotExpr: "dot" + of nkCheckedFieldExpr: "checkedfieldx" + of nkDerefExpr: "deref" + of nkIfExpr: "ifx" + of nkElifExpr: "elifx" + of nkElseExpr: "elsex" + of nkLambda: "lambda" + of nkDo: "do" + of nkAccQuoted: "accquoted" + of nkTableConstr: "tableconstr" + of nkBind: "bind" + of nkClosedSymChoice: "closedsymchoice" + of nkOpenSymChoice: "opensymchoice" + of nkHiddenStdConv: "hstdconv" + of nkHiddenSubConv: "hsubconv" + of nkConv: "conv" + of nkCast: "cast" + of nkStaticExpr: "staticx" + of nkAddr: "addr" + of nkHiddenAddr: "haddr" + of nkHiddenDeref: "hderef" + of nkObjDownConv: "objdownconv" + of nkObjUpConv: "objupconv" + of nkChckRangeF: "chckrangef" + of nkChckRange64: "chckrange64" + of nkChckRange: "chckrange" + of nkStringToCString: "stringtocstring" + of nkCStringToString: "cstringtostring" + of nkAsgn: "asgn" + of nkFastAsgn: "fastasgn" + of nkGenericParams: "genericparams" + of nkFormalParams: "formalparams" + of nkOfInherit: "ofinherit" + of nkImportAs: "importas" + of nkProcDef: "proc" + of nkMethodDef: "method" + of nkConverterDef: "converter" + of nkMacroDef: "macro" + of nkTemplateDef: "template" + of nkIteratorDef: "iterator" + of nkOfBranch: "of" + of nkElifBranch: "elif" + of nkExceptBranch: "except" + of nkElse: "else" + of nkAsmStmt: "asm" + of nkPragma: "pragma" + of nkPragmaBlock: "pragmablock" + of nkIfStmt: "if" + of nkWhenStmt: "when" + of nkForStmt: "for" + of nkParForStmt: "parfor" + of nkWhileStmt: "while" + of nkCaseStmt: "case" + of nkTypeSection: "type" + of nkVarSection: "var" + of nkLetSection: "let" + of nkConstSection: "const" + of nkConstDef: "const0" + of nkTypeDef: "type0" + of nkYieldStmt: "yield" + of nkDefer: "defer" + of nkTryStmt: "try" + of nkFinally: "finally" + of nkRaiseStmt: "raise" + of nkReturnStmt: "ret" + of nkBreakStmt: "brk" + of nkContinueStmt: "continue" + of nkBlockStmt: "block" + of nkStaticStmt: "static" + of nkDiscardStmt: "discard" + of nkStmtList: "stmts" + of nkImportStmt: "import" + of nkImportExceptStmt: "importexcept" + of nkExportStmt: "export" + of nkExportExceptStmt: "exportexcept" + of nkFromStmt: "from" + of nkIncludeStmt: "include" + of nkBindStmt: "bind0" + of nkMixinStmt: "mixin" + of nkUsingStmt: "using" + of nkCommentStmt: "comment" + of nkStmtListExpr: "expr" + of nkBlockExpr: "blockx" + of nkStmtListType: "stmtlisttype" + of nkBlockType: "blocktype" + of nkWith: "with" + of nkWithout: "without" + of nkTypeOfExpr: "typeofx" + of nkObjectTy: "objectty" + of nkTupleTy: "tuplety" + of nkTupleClassTy: "tupleclassty" + of nkTypeClassTy: "typeclassty" + of nkStaticTy: "staticty" + of nkRecList: "reclist" + of nkRecCase: "reccase" + of nkRecWhen: "recwhen" + of nkRefTy: "refty" + of nkPtrTy: "ptrty" + of nkVarTy: "varty" + of nkConstTy: "constty" + of nkOutTy: "outty" + of nkDistinctTy: "distinctty" + of nkProcTy: "procty" + of nkIteratorTy: "iteratorty" + of nkSinkAsgn: "sinkasgn" + of nkEnumTy: "enumty" + of nkEnumFieldDef: "efld" + of nkArgList: "arglist" + of nkPattern: "pattern" + of nkHiddenTryStmt: "htrystmt" + of nkClosure: "closure" + of nkGotoState: "gotostate" + of nkState: "state" + of nkBreakState: "breakstate" + of nkFuncDef: "func" + of nkTupleConstr: "tupleconstr" + of nkError: "err" + of nkModuleRef: "moduleref" + of nkReplayAction: "replayaction" + of nkNilRodNode: "nilrodnode" + of nkOpenSym: "opensym" + + +proc parse*(t: typedesc[TNodeKind]; s: string): TNodeKind = + case s + of "none": nkNone + of "empty": nkEmpty + of "ident": nkIdent + of "sym": nkSym + of "onlytype": nkType + of "charlit": nkCharLit + of "intlit": nkIntLit + of "int8lit": nkInt8Lit + of "int16lit": nkInt16Lit + of "int32lit": nkInt32Lit + of "int64lit": nkInt64Lit + of "uintlit": nkUIntLit + of "uint8lit": nkUInt8Lit + of "uint16lit": nkUInt16Lit + of "uint32lit": nkUInt32Lit + of "uint64lit": nkUInt64Lit + of "floatlit": nkFloatLit + of "float32lit": nkFloat32Lit + of "float64lit": nkFloat64Lit + of "float128lit": nkFloat128Lit + of "strlit": nkStrLit + of "rstrlit": nkRStrLit + of "triplestrlit": nkTripleStrLit + of "nil": nkNilLit + of "comesfrom": nkComesFrom + of "dotcall": nkDotCall + of "cmd": nkCommand + of "call": nkCall + of "callstrlit": nkCallStrLit + of "infix": nkInfix + of "prefix": nkPrefix + of "postfix": nkPostfix + of "hcallconv": nkHiddenCallConv + of "vv": nkExprEqExpr + of "kv": nkExprColonExpr + of "identdefs": nkIdentDefs + of "vartuple": nkVarTuple + of "par": nkPar + of "objconstr": nkObjConstr + of "curly": nkCurly + of "curlyx": nkCurlyExpr + of "bracket": nkBracket + of "at": nkBracketExpr + of "pragmax": nkPragmaExpr + of "range": nkRange + of "dot": nkDotExpr + of "checkedfieldx": nkCheckedFieldExpr + of "deref": nkDerefExpr + of "ifx": nkIfExpr + of "elifx": nkElifExpr + of "elsex": nkElseExpr + of "lambda": nkLambda + of "do": nkDo + of "accquoted": nkAccQuoted + of "tableconstr": nkTableConstr + of "bind": nkBind + of "closedsymchoice": nkClosedSymChoice + of "opensymchoice": nkOpenSymChoice + of "hstdconv": nkHiddenStdConv + of "hsubconv": nkHiddenSubConv + of "conv": nkConv + of "cast": nkCast + of "staticx": nkStaticExpr + of "addr": nkAddr + of "haddr": nkHiddenAddr + of "hderef": nkHiddenDeref + of "objdownconv": nkObjDownConv + of "objupconv": nkObjUpConv + of "chckrangef": nkChckRangeF + of "chckrange64": nkChckRange64 + of "chckrange": nkChckRange + of "stringtocstring": nkStringToCString + of "cstringtostring": nkCStringToString + of "asgn": nkAsgn + of "fastasgn": nkFastAsgn + of "genericparams": nkGenericParams + of "formalparams": nkFormalParams + of "ofinherit": nkOfInherit + of "importas": nkImportAs + of "proc": nkProcDef + of "method": nkMethodDef + of "converter": nkConverterDef + of "macro": nkMacroDef + of "template": nkTemplateDef + of "iterator": nkIteratorDef + of "of": nkOfBranch + of "elif": nkElifBranch + of "except": nkExceptBranch + of "else": nkElse + of "asm": nkAsmStmt + of "pragma": nkPragma + of "pragmablock": nkPragmaBlock + of "if": nkIfStmt + of "when": nkWhenStmt + of "for": nkForStmt + of "parfor": nkParForStmt + of "while": nkWhileStmt + of "case": nkCaseStmt + of "type": nkTypeSection + of "var": nkVarSection + of "let": nkLetSection + of "const": nkConstSection + of "const0": nkConstDef + of "type0": nkTypeDef + of "yield": nkYieldStmt + of "defer": nkDefer + of "try": nkTryStmt + of "finally": nkFinally + of "raise": nkRaiseStmt + of "ret": nkReturnStmt + of "brk": nkBreakStmt + of "continue": nkContinueStmt + of "block": nkBlockStmt + of "static": nkStaticStmt + of "discard": nkDiscardStmt + of "stmts": nkStmtList + of "import": nkImportStmt + of "importexcept": nkImportExceptStmt + of "export": nkExportStmt + of "exportexcept": nkExportExceptStmt + of "from": nkFromStmt + of "include": nkIncludeStmt + of "bind0": nkBindStmt + of "mixin": nkMixinStmt + of "using": nkUsingStmt + of "comment": nkCommentStmt + of "expr": nkStmtListExpr + of "blockx": nkBlockExpr + of "stmtlisttype": nkStmtListType + of "blocktype": nkBlockType + of "with": nkWith + of "without": nkWithout + of "typeofx": nkTypeOfExpr + of "objectty": nkObjectTy + of "tuplety": nkTupleTy + of "tupleclassty": nkTupleClassTy + of "typeclassty": nkTypeClassTy + of "staticty": nkStaticTy + of "reclist": nkRecList + of "reccase": nkRecCase + of "recwhen": nkRecWhen + of "refty": nkRefTy + of "ptrty": nkPtrTy + of "varty": nkVarTy + of "constty": nkConstTy + of "outty": nkOutTy + of "distinctty": nkDistinctTy + of "procty": nkProcTy + of "iteratorty": nkIteratorTy + of "sinkasgn": nkSinkAsgn + of "enumty": nkEnumTy + of "efld": nkEnumFieldDef + of "arglist": nkArgList + of "pattern": nkPattern + of "htrystmt": nkHiddenTryStmt + of "closure": nkClosure + of "gotostate": nkGotoState + of "state": nkState + of "breakstate": nkBreakState + of "func": nkFuncDef + of "tupleconstr": nkTupleConstr + of "err": nkError + of "moduleref": nkModuleRef + of "replayaction": nkReplayAction + of "nilrodnode": nkNilRodNode + of "opensym": nkOpenSym + else: nkNone + + +proc toNifTag*(s: TSymKind): string = + case s + of skUnknown: "unknown" + of skConditional: "conditional" + of skDynLib: "dynlib" + of skParam: "param" + of skGenericParam: "genericparam" + of skTemp: "temp" + of skModule: "module" + of skType: "type" + of skVar: "var" + of skLet: "let" + of skConst: "const" + of skResult: "result" + of skProc: "proc" + of skFunc: "func" + of skMethod: "method" + of skIterator: "iterator" + of skConverter: "converter" + of skMacro: "macro" + of skTemplate: "template" + of skField: "field" + of skEnumField: "enumfield" + of skForVar: "forvar" + of skLabel: "label" + of skStub: "stub" + of skPackage: "package" + + +proc parse*(t: typedesc[TSymKind]; s: string): TSymKind = + case s + of "unknown": skUnknown + of "conditional": skConditional + of "dynlib": skDynLib + of "param": skParam + of "genericparam": skGenericParam + of "temp": skTemp + of "module": skModule + of "type": skType + of "var": skVar + of "let": skLet + of "const": skConst + of "result": skResult + of "proc": skProc + of "func": skFunc + of "method": skMethod + of "iterator": skIterator + of "converter": skConverter + of "macro": skMacro + of "template": skTemplate + of "field": skField + of "enumfield": skEnumField + of "forvar": skForVar + of "label": skLabel + of "stub": skStub + of "package": skPackage + else: skUnknown + + +proc toNifTag*(s: TTypeKind): string = + case s + of tyNone: "none" + of tyBool: "bool" + of tyChar: "char" + of tyEmpty: "empty" + of tyAlias: "alias" + of tyNil: "nil" + of tyUntyped: "untyped" + of tyTyped: "typed" + of tyTypeDesc: "typedesc" + of tyGenericInvocation: "ginvoke" + of tyGenericBody: "gbody" + of tyGenericInst: "ginst" + of tyGenericParam: "gparam" + of tyDistinct: "distinct" + of tyEnum: "enum" + of tyOrdinal: "ordinal" + of tyArray: "array" + of tyObject: "object" + of tyTuple: "tuple" + of tySet: "set" + of tyRange: "range" + of tyPtr: "ptr" + of tyRef: "ref" + of tyVar: "mut" + of tySequence: "seq" + of tyProc: "proctype" + of tyPointer: "pointer" + of tyOpenArray: "openarray" + of tyString: "string" + of tyCstring: "cstring" + of tyForward: "forward" + of tyInt: "int" + of tyInt8: "int8" + of tyInt16: "int16" + of tyInt32: "int32" + of tyInt64: "int64" + of tyFloat: "float" + of tyFloat32: "float32" + of tyFloat64: "float64" + of tyFloat128: "float128" + of tyUInt: "uint" + of tyUInt8: "uint8" + of tyUInt16: "uint16" + of tyUInt32: "uint32" + of tyUInt64: "uint64" + of tyOwned: "owned" + of tySink: "sink" + of tyLent: "lent" + of tyVarargs: "varargs" + of tyUncheckedArray: "uarray" + of tyError: "error" + of tyBuiltInTypeClass: "bconcept" + of tyUserTypeClass: "uconcept" + of tyUserTypeClassInst: "uconceptinst" + of tyCompositeTypeClass: "cconcept" + of tyInferred: "inferred" + of tyAnd: "and" + of tyOr: "or" + of tyNot: "not" + of tyAnything: "anything" + of tyStatic: "static" + of tyFromExpr: "fromx" + of tyConcept: "concept" + of tyVoid: "void" + of tyIterable: "iterable" + of tyStub: "stub" + + +proc parse*(t: typedesc[TTypeKind]; s: string): TTypeKind = + case s + of "none": tyNone + of "bool": tyBool + of "char": tyChar + of "empty": tyEmpty + of "alias": tyAlias + of "nil": tyNil + of "untyped": tyUntyped + of "typed": tyTyped + of "typedesc": tyTypeDesc + of "ginvoke": tyGenericInvocation + of "gbody": tyGenericBody + of "ginst": tyGenericInst + of "gparam": tyGenericParam + of "distinct": tyDistinct + of "enum": tyEnum + of "ordinal": tyOrdinal + of "array": tyArray + of "object": tyObject + of "tuple": tyTuple + of "set": tySet + of "range": tyRange + of "ptr": tyPtr + of "ref": tyRef + of "mut": tyVar + of "seq": tySequence + of "proctype": tyProc + of "pointer": tyPointer + of "openarray": tyOpenArray + of "string": tyString + of "cstring": tyCstring + of "forward": tyForward + of "int": tyInt + of "int8": tyInt8 + of "int16": tyInt16 + of "int32": tyInt32 + of "int64": tyInt64 + of "float": tyFloat + of "float32": tyFloat32 + of "float64": tyFloat64 + of "float128": tyFloat128 + of "uint": tyUInt + of "uint8": tyUInt8 + of "uint16": tyUInt16 + of "uint32": tyUInt32 + of "uint64": tyUInt64 + of "owned": tyOwned + of "sink": tySink + of "lent": tyLent + of "varargs": tyVarargs + of "uarray": tyUncheckedArray + of "error": tyError + of "bconcept": tyBuiltInTypeClass + of "uconcept": tyUserTypeClass + of "uconceptinst": tyUserTypeClassInst + of "cconcept": tyCompositeTypeClass + of "inferred": tyInferred + of "and": tyAnd + of "or": tyOr + of "not": tyNot + of "anything": tyAnything + of "static": tyStatic + of "fromx": tyFromExpr + of "concept": tyConcept + of "void": tyVoid + of "iterable": tyIterable + of "stub": tyStub + else: tyNone + + +proc toNifTag*(s: TLocKind): string = + case s + of locNone: "none" + of locTemp: "temp" + of locLocalVar: "localvar" + of locGlobalVar: "globalvar" + of locParam: "param" + of locField: "field" + of locExpr: "expr" + of locProc: "proc" + of locData: "data" + of locCall: "call" + of locOther: "other" + + +proc parse*(t: typedesc[TLocKind]; s: string): TLocKind = + case s + of "none": locNone + of "temp": locTemp + of "localvar": locLocalVar + of "globalvar": locGlobalVar + of "param": locParam + of "field": locField + of "expr": locExpr + of "proc": locProc + of "data": locData + of "call": locCall + of "other": locOther + else: locNone + + +proc toNifTag*(s: TCallingConvention): string = + case s + of ccNimCall: "nimcall" + of ccStdCall: "stdcall" + of ccCDecl: "cdecl" + of ccSafeCall: "safecall" + of ccSysCall: "syscall" + of ccInline: "inline" + of ccNoInline: "noinline" + of ccFastCall: "fastcall" + of ccThisCall: "thiscall" + of ccClosure: "closure" + of ccNoConvention: "noconv" + of ccMember: "member" + + +proc parse*(t: typedesc[TCallingConvention]; s: string): TCallingConvention = + case s + of "nimcall": ccNimCall + of "stdcall": ccStdCall + of "cdecl": ccCDecl + of "safecall": ccSafeCall + of "syscall": ccSysCall + of "inline": ccInline + of "noinline": ccNoInline + of "fastcall": ccFastCall + of "thiscall": ccThisCall + of "closure": ccClosure + of "noconv": ccNoConvention + of "member": ccMember + else: ccNimCall + + +proc toNifTag*(s: TMagic): string = + case s + of mNone: "nonem" + of mDefined: "defined" + of mDeclared: "declared" + of mDeclaredInScope: "declaredinscope" + of mCompiles: "compiles" + of mArrGet: "arrget" + of mArrPut: "arrput" + of mAsgn: "asgnm" + of mLow: "low" + of mHigh: "high" + of mSizeOf: "sizeof" + of mAlignOf: "alignof" + of mOffsetOf: "offsetof" + of mTypeTrait: "typetrait" + of mIs: "is" + of mOf: "ofm" + of mAddr: "addrm" + of mType: "typem" + of mTypeOf: "typeof" + of mPlugin: "plugin" + of mEcho: "echo" + of mShallowCopy: "shallowcopy" + of mSlurp: "slurp" + of mStaticExec: "staticexec" + of mStatic: "staticm" + of mParseExprToAst: "parseexprtoast" + of mParseStmtToAst: "parsestmttoast" + of mExpandToAst: "expandtoast" + of mQuoteAst: "quoteast" + of mInc: "inc" + of mDec: "dec" + of mOrd: "ord" + of mNew: "new" + of mNewFinalize: "newfinalize" + of mNewSeq: "newseq" + of mNewSeqOfCap: "newseqofcap" + of mLengthOpenArray: "lenopenarray" + of mLengthStr: "lenstr" + of mLengthArray: "lenarray" + of mLengthSeq: "lenseq" + of mIncl: "incl" + of mExcl: "excl" + of mCard: "card" + of mChr: "chr" + of mGCref: "gcref" + of mGCunref: "gcunref" + of mAddI: "add" + of mSubI: "sub" + of mMulI: "mul" + of mDivI: "div" + of mModI: "mod" + of mSucc: "succ" + of mPred: "pred" + of mAddF64: "addf64" + of mSubF64: "subf64" + of mMulF64: "mulf64" + of mDivF64: "divf64" + of mShrI: "shr" + of mShlI: "shl" + of mAshrI: "ashr" + of mBitandI: "bitand" + of mBitorI: "bitor" + of mBitxorI: "bitxor" + of mMinI: "min" + of mMaxI: "max" + of mAddU: "addu" + of mSubU: "subu" + of mMulU: "mulu" + of mDivU: "divu" + of mModU: "modu" + of mEqI: "eq" + of mLeI: "le" + of mLtI: "lt" + of mEqF64: "eqf64" + of mLeF64: "lef64" + of mLtF64: "ltf64" + of mLeU: "leu" + of mLtU: "ltu" + of mEqEnum: "eqenum" + of mLeEnum: "leenum" + of mLtEnum: "ltenum" + of mEqCh: "eqch" + of mLeCh: "lech" + of mLtCh: "ltch" + of mEqB: "eqb" + of mLeB: "leb" + of mLtB: "ltb" + of mEqRef: "eqref" + of mLePtr: "leptr" + of mLtPtr: "ltptr" + of mXor: "xor" + of mEqCString: "eqcstring" + of mEqProc: "eqproc" + of mUnaryMinusI: "unaryminus" + of mUnaryMinusI64: "unaryminusi64" + of mAbsI: "abs" + of mNot: "not" + of mUnaryPlusI: "unaryplus" + of mBitnotI: "bitnot" + of mUnaryPlusF64: "unaryplusf64" + of mUnaryMinusF64: "unaryminusf64" + of mCharToStr: "chartostr" + of mBoolToStr: "booltostr" + of mCStrToStr: "cstrtostr" + of mStrToStr: "strtostr" + of mEnumToStr: "enumtostr" + of mAnd: "and" + of mOr: "or" + of mImplies: "implies" + of mIff: "iff" + of mExists: "exists" + of mForall: "forall" + of mOld: "old" + of mEqStr: "eqstr" + of mLeStr: "lestr" + of mLtStr: "ltstr" + of mEqSet: "eqset" + of mLeSet: "leset" + of mLtSet: "ltset" + of mMulSet: "mulset" + of mPlusSet: "plusset" + of mMinusSet: "minusset" + of mXorSet: "xorset" + of mConStrStr: "constrstr" + of mSlice: "slice" + of mDotDot: "dotdot" + of mFields: "fields" + of mFieldPairs: "fieldpairs" + of mOmpParFor: "ompparfor" + of mAppendStrCh: "addstrch" + of mAppendStrStr: "addstrstr" + of mAppendSeqElem: "addseqelem" + of mInSet: "contains" + of mRepr: "repr" + of mExit: "exit" + of mSetLengthStr: "setlenstr" + of mSetLengthSeq: "setlenseq" + of mSetLengthSeqUninit: "setlensequninit" + of mIsPartOf: "ispartof" + of mAstToStr: "asttostr" + of mParallel: "parallel" + of mSwap: "swap" + of mIsNil: "isnil" + of mArrToSeq: "arrtoseq" + of mOpenArrayToSeq: "openarraytoseq" + of mNewString: "newstring" + of mNewStringOfCap: "newstringofcap" + of mParseBiggestFloat: "parsebiggestfloat" + of mMove: "move" + of mEnsureMove: "ensuremove" + of mWasMoved: "wasmoved" + of mDup: "dup" + of mDestroy: "destroy" + of mTrace: "trace" + of mDefault: "default" + of mUnown: "unown" + of mFinished: "finished" + of mIsolate: "isolate" + of mAccessEnv: "accessenv" + of mAccessTypeField: "accesstypefield" + of mArray: "array" + of mOpenArray: "openarray" + of mRange: "rangem" + of mSet: "set" + of mSeq: "seq" + of mVarargs: "varargs" + of mRef: "ref" + of mPtr: "ptr" + of mVar: "varm" + of mDistinct: "distinct" + of mVoid: "void" + of mTuple: "tuple" + of mOrdinal: "ordinal" + of mIterableType: "iterabletype" + of mInt: "int" + of mInt8: "int8" + of mInt16: "int16" + of mInt32: "int32" + of mInt64: "int64" + of mUInt: "uint" + of mUInt8: "uint8" + of mUInt16: "uint16" + of mUInt32: "uint32" + of mUInt64: "uint64" + of mFloat: "float" + of mFloat32: "float32" + of mFloat64: "float64" + of mFloat128: "float128" + of mBool: "bool" + of mChar: "char" + of mString: "string" + of mCstring: "cstring" + of mPointer: "pointer" + of mNil: "nilm" + of mExpr: "exprm" + of mStmt: "stmtm" + of mTypeDesc: "typedesc" + of mVoidType: "voidtype" + of mPNimrodNode: "nimnode" + of mSpawn: "spawn" + of mDeepCopy: "deepcopy" + of mIsMainModule: "ismainmodule" + of mCompileDate: "compiledate" + of mCompileTime: "compiletime" + of mProcCall: "proccall" + of mCpuEndian: "cpuendian" + of mHostOS: "hostos" + of mHostCPU: "hostcpu" + of mBuildOS: "buildos" + of mBuildCPU: "buildcpu" + of mAppType: "apptype" + of mCompileOption: "compileoption" + of mCompileOptionArg: "compileoptionarg" + of mNLen: "nlen" + of mNChild: "nchild" + of mNSetChild: "nsetchild" + of mNAdd: "nadd" + of mNAddMultiple: "naddmultiple" + of mNDel: "ndel" + of mNKind: "nkind" + of mNSymKind: "nsymkind" + of mNccValue: "nccvalue" + of mNccInc: "nccinc" + of mNcsAdd: "ncsadd" + of mNcsIncl: "ncsincl" + of mNcsLen: "ncslen" + of mNcsAt: "ncsat" + of mNctPut: "nctput" + of mNctLen: "nctlen" + of mNctGet: "nctget" + of mNctHasNext: "ncthasnext" + of mNctNext: "nctnext" + of mNIntVal: "nintval" + of mNFloatVal: "nfloatval" + of mNSymbol: "nsymbol" + of mNIdent: "nident" + of mNGetType: "ngettype" + of mNStrVal: "nstrval" + of mNSetIntVal: "nsetintval" + of mNSetFloatVal: "nsetfloatval" + of mNSetSymbol: "nsetsymbol" + of mNSetIdent: "nsetident" + of mNSetStrVal: "nsetstrval" + of mNLineInfo: "nlineinfo" + of mNNewNimNode: "nnewnimnode" + of mNCopyNimNode: "ncopynimnode" + of mNCopyNimTree: "ncopynimtree" + of mStrToIdent: "strtoident" + of mNSigHash: "nsighash" + of mNSizeOf: "nsizeof" + of mNBindSym: "nbindsym" + of mNCallSite: "ncallsite" + of mEqIdent: "eqident" + of mEqNimrodNode: "eqnimnode" + of mSameNodeType: "samenodetype" + of mGetImpl: "getimpl" + of mNGenSym: "ngensym" + of mNHint: "nhint" + of mNWarning: "nwarning" + of mNError: "nerror" + of mInstantiationInfo: "instantiationinfo" + of mGetTypeInfo: "gettypeinfo" + of mGetTypeInfoV2: "gettypeinfov2" + of mNimvm: "nimvm" + of mIntDefine: "intdefine" + of mStrDefine: "strdefine" + of mBoolDefine: "booldefine" + of mGenericDefine: "genericdefine" + of mRunnableExamples: "runnableexamples" + of mException: "exception" + of mBuiltinType: "builtintype" + of mSymOwner: "symowner" + of mUncheckedArray: "uncheckedarray" + of mGetImplTransf: "getimpltransf" + of mSymIsInstantiationOf: "symisinstantiationof" + of mNodeId: "nodeid" + of mPrivateAccess: "privateaccess" + of mZeroDefault: "zerodefault" + + +proc parse*(t: typedesc[TMagic]; s: string): TMagic = + case s + of "nonem": mNone + of "defined": mDefined + of "declared": mDeclared + of "declaredinscope": mDeclaredInScope + of "compiles": mCompiles + of "arrget": mArrGet + of "arrput": mArrPut + of "asgnm": mAsgn + of "low": mLow + of "high": mHigh + of "sizeof": mSizeOf + of "alignof": mAlignOf + of "offsetof": mOffsetOf + of "typetrait": mTypeTrait + of "is": mIs + of "ofm": mOf + of "addrm": mAddr + of "typem": mType + of "typeof": mTypeOf + of "plugin": mPlugin + of "echo": mEcho + of "shallowcopy": mShallowCopy + of "slurp": mSlurp + of "staticexec": mStaticExec + of "staticm": mStatic + of "parseexprtoast": mParseExprToAst + of "parsestmttoast": mParseStmtToAst + of "expandtoast": mExpandToAst + of "quoteast": mQuoteAst + of "inc": mInc + of "dec": mDec + of "ord": mOrd + of "new": mNew + of "newfinalize": mNewFinalize + of "newseq": mNewSeq + of "newseqofcap": mNewSeqOfCap + of "lenopenarray": mLengthOpenArray + of "lenstr": mLengthStr + of "lenarray": mLengthArray + of "lenseq": mLengthSeq + of "incl": mIncl + of "excl": mExcl + of "card": mCard + of "chr": mChr + of "gcref": mGCref + of "gcunref": mGCunref + of "add": mAddI + of "sub": mSubI + of "mul": mMulI + of "div": mDivI + of "mod": mModI + of "succ": mSucc + of "pred": mPred + of "addf64": mAddF64 + of "subf64": mSubF64 + of "mulf64": mMulF64 + of "divf64": mDivF64 + of "shr": mShrI + of "shl": mShlI + of "ashr": mAshrI + of "bitand": mBitandI + of "bitor": mBitorI + of "bitxor": mBitxorI + of "min": mMinI + of "max": mMaxI + of "addu": mAddU + of "subu": mSubU + of "mulu": mMulU + of "divu": mDivU + of "modu": mModU + of "eq": mEqI + of "le": mLeI + of "lt": mLtI + of "eqf64": mEqF64 + of "lef64": mLeF64 + of "ltf64": mLtF64 + of "leu": mLeU + of "ltu": mLtU + of "eqenum": mEqEnum + of "leenum": mLeEnum + of "ltenum": mLtEnum + of "eqch": mEqCh + of "lech": mLeCh + of "ltch": mLtCh + of "eqb": mEqB + of "leb": mLeB + of "ltb": mLtB + of "eqref": mEqRef + of "leptr": mLePtr + of "ltptr": mLtPtr + of "xor": mXor + of "eqcstring": mEqCString + of "eqproc": mEqProc + of "unaryminus": mUnaryMinusI + of "unaryminusi64": mUnaryMinusI64 + of "abs": mAbsI + of "not": mNot + of "unaryplus": mUnaryPlusI + of "bitnot": mBitnotI + of "unaryplusf64": mUnaryPlusF64 + of "unaryminusf64": mUnaryMinusF64 + of "chartostr": mCharToStr + of "booltostr": mBoolToStr + of "cstrtostr": mCStrToStr + of "strtostr": mStrToStr + of "enumtostr": mEnumToStr + of "and": mAnd + of "or": mOr + of "implies": mImplies + of "iff": mIff + of "exists": mExists + of "forall": mForall + of "old": mOld + of "eqstr": mEqStr + of "lestr": mLeStr + of "ltstr": mLtStr + of "eqset": mEqSet + of "leset": mLeSet + of "ltset": mLtSet + of "mulset": mMulSet + of "plusset": mPlusSet + of "minusset": mMinusSet + of "xorset": mXorSet + of "constrstr": mConStrStr + of "slice": mSlice + of "dotdot": mDotDot + of "fields": mFields + of "fieldpairs": mFieldPairs + of "ompparfor": mOmpParFor + of "addstrch": mAppendStrCh + of "addstrstr": mAppendStrStr + of "addseqelem": mAppendSeqElem + of "contains": mInSet + of "repr": mRepr + of "exit": mExit + of "setlenstr": mSetLengthStr + of "setlenseq": mSetLengthSeq + of "setlensequninit": mSetLengthSeqUninit + of "ispartof": mIsPartOf + of "asttostr": mAstToStr + of "parallel": mParallel + of "swap": mSwap + of "isnil": mIsNil + of "arrtoseq": mArrToSeq + of "openarraytoseq": mOpenArrayToSeq + of "newstring": mNewString + of "newstringofcap": mNewStringOfCap + of "parsebiggestfloat": mParseBiggestFloat + of "move": mMove + of "ensuremove": mEnsureMove + of "wasmoved": mWasMoved + of "dup": mDup + of "destroy": mDestroy + of "trace": mTrace + of "default": mDefault + of "unown": mUnown + of "finished": mFinished + of "isolate": mIsolate + of "accessenv": mAccessEnv + of "accesstypefield": mAccessTypeField + of "array": mArray + of "openarray": mOpenArray + of "rangem": mRange + of "set": mSet + of "seq": mSeq + of "varargs": mVarargs + of "ref": mRef + of "ptr": mPtr + of "varm": mVar + of "distinct": mDistinct + of "void": mVoid + of "tuple": mTuple + of "ordinal": mOrdinal + of "iterabletype": mIterableType + of "int": mInt + of "int8": mInt8 + of "int16": mInt16 + of "int32": mInt32 + of "int64": mInt64 + of "uint": mUInt + of "uint8": mUInt8 + of "uint16": mUInt16 + of "uint32": mUInt32 + of "uint64": mUInt64 + of "float": mFloat + of "float32": mFloat32 + of "float64": mFloat64 + of "float128": mFloat128 + of "bool": mBool + of "char": mChar + of "string": mString + of "cstring": mCstring + of "pointer": mPointer + of "nilm": mNil + of "exprm": mExpr + of "stmtm": mStmt + of "typedesc": mTypeDesc + of "voidtype": mVoidType + of "nimnode": mPNimrodNode + of "spawn": mSpawn + of "deepcopy": mDeepCopy + of "ismainmodule": mIsMainModule + of "compiledate": mCompileDate + of "compiletime": mCompileTime + of "proccall": mProcCall + of "cpuendian": mCpuEndian + of "hostos": mHostOS + of "hostcpu": mHostCPU + of "buildos": mBuildOS + of "buildcpu": mBuildCPU + of "apptype": mAppType + of "compileoption": mCompileOption + of "compileoptionarg": mCompileOptionArg + of "nlen": mNLen + of "nchild": mNChild + of "nsetchild": mNSetChild + of "nadd": mNAdd + of "naddmultiple": mNAddMultiple + of "ndel": mNDel + of "nkind": mNKind + of "nsymkind": mNSymKind + of "nccvalue": mNccValue + of "nccinc": mNccInc + of "ncsadd": mNcsAdd + of "ncsincl": mNcsIncl + of "ncslen": mNcsLen + of "ncsat": mNcsAt + of "nctput": mNctPut + of "nctlen": mNctLen + of "nctget": mNctGet + of "ncthasnext": mNctHasNext + of "nctnext": mNctNext + of "nintval": mNIntVal + of "nfloatval": mNFloatVal + of "nsymbol": mNSymbol + of "nident": mNIdent + of "ngettype": mNGetType + of "nstrval": mNStrVal + of "nsetintval": mNSetIntVal + of "nsetfloatval": mNSetFloatVal + of "nsetsymbol": mNSetSymbol + of "nsetident": mNSetIdent + of "nsetstrval": mNSetStrVal + of "nlineinfo": mNLineInfo + of "nnewnimnode": mNNewNimNode + of "ncopynimnode": mNCopyNimNode + of "ncopynimtree": mNCopyNimTree + of "strtoident": mStrToIdent + of "nsighash": mNSigHash + of "nsizeof": mNSizeOf + of "nbindsym": mNBindSym + of "ncallsite": mNCallSite + of "eqident": mEqIdent + of "eqnimnode": mEqNimrodNode + of "samenodetype": mSameNodeType + of "getimpl": mGetImpl + of "ngensym": mNGenSym + of "nhint": mNHint + of "nwarning": mNWarning + of "nerror": mNError + of "instantiationinfo": mInstantiationInfo + of "gettypeinfo": mGetTypeInfo + of "gettypeinfov2": mGetTypeInfoV2 + of "nimvm": mNimvm + of "intdefine": mIntDefine + of "strdefine": mStrDefine + of "booldefine": mBoolDefine + of "genericdefine": mGenericDefine + of "runnableexamples": mRunnableExamples + of "exception": mException + of "builtintype": mBuiltinType + of "symowner": mSymOwner + of "uncheckedarray": mUncheckedArray + of "getimpltransf": mGetImplTransf + of "symisinstantiationof": mSymIsInstantiationOf + of "nodeid": mNodeId + of "privateaccess": mPrivateAccess + of "zerodefault": mZeroDefault + else: mNone + + +proc toNifTag*(s: TStorageLoc): string = + case s + of OnUnknown: "unknown" + of OnStatic: "static" + of OnStack: "stack" + of OnHeap: "heap" + + +proc parse*(t: typedesc[TStorageLoc]; s: string): TStorageLoc = + case s + of "unknown": OnUnknown + of "static": OnStatic + of "stack": OnStack + of "heap": OnHeap + else: OnUnknown + + +proc toNifTag*(s: TLibKind): string = + case s + of libHeader: "bheader" + of libDynamic: "bdynamic" + + +proc parse*(t: typedesc[TLibKind]; s: string): TLibKind = + case s + of "bheader": libHeader + of "bdynamic": libDynamic + else: libHeader + + +proc genFlags*(s: set[TSymFlag]; dest: var string) = + for e in s: + case e + of sfUsed: dest.add "u" + of sfExported: dest.add "e" + of sfFromGeneric: dest.add "f" + of sfGlobal: dest.add "g" + of sfForward: dest.add "f0" + of sfWasForwarded: dest.add "w" + of sfImportc: dest.add "i" + of sfExportc: dest.add "e0" + of sfMangleCpp: dest.add "m" + of sfVolatile: dest.add "v" + of sfRegister: dest.add "r" + of sfPure: dest.add "p" + of sfNoSideEffect: dest.add "n" + of sfSideEffect: dest.add "s" + of sfMainModule: dest.add "m0" + of sfSystemModule: dest.add "s0" + of sfNoReturn: dest.add "n0" + of sfAddrTaken: dest.add "a" + of sfCompilerProc: dest.add "c" + of sfEscapes: dest.add "e1" + of sfDiscriminant: dest.add "d" + of sfRequiresInit: dest.add "r0" + of sfDeprecated: dest.add "d0" + of sfExplain: dest.add "e2" + of sfError: dest.add "e3" + of sfShadowed: dest.add "s1" + of sfThread: dest.add "t" + of sfCppNonPod: dest.add "c0" + of sfCompileTime: dest.add "c1" + of sfConstructor: dest.add "c2" + of sfDispatcher: dest.add "d1" + of sfBorrow: dest.add "b" + of sfInfixCall: dest.add "i0" + of sfNamedParamCall: dest.add "n1" + of sfDiscardable: dest.add "d2" + of sfOverridden: dest.add "o" + of sfCallsite: dest.add "c3" + of sfGenSym: dest.add "g0" + of sfNonReloadable: dest.add "n2" + of sfGeneratedOp: dest.add "g1" + of sfTemplateParam: dest.add "t0" + of sfCursor: dest.add "c4" + of sfInjectDestructors: dest.add "i1" + of sfNeverRaises: dest.add "n3" + of sfSystemRaisesDefect: dest.add "s2" + of sfUsedInFinallyOrExcept: dest.add "u0" + of sfSingleUsedTemp: dest.add "s3" + of sfNoalias: dest.add "n4" + of sfEffectsDelayed: dest.add "e4" + of sfGeneratedType: dest.add "g2" + of sfVirtual: dest.add "v0" + of sfByCopy: dest.add "b0" + of sfMember: dest.add "m1" + of sfCodegenDecl: dest.add "c5" + of sfWasGenSym: dest.add "w0" + of sfForceLift: dest.add "l" + of sfDirty: dest.add "d3" + of sfCustomPragma: dest.add "c6" + of sfBase: dest.add "b1" + of sfGoto: dest.add "g3" + of sfAnon: dest.add "a0" + of sfAllUntyped: dest.add "a1" + of sfTemplateRedefinition: dest.add "t1" + + +proc parse*(t: typedesc[TSymFlag]; s: string): set[TSymFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': + if i+1 < s.len and s[i+1] == '0': + result.incl sfAnon + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfAllUntyped + inc i + else: result.incl sfAddrTaken + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl sfByCopy + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfBase + inc i + else: result.incl sfBorrow + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl sfCppNonPod + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfCompileTime + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfConstructor + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfCallsite + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfCursor + inc i + elif i+1 < s.len and s[i+1] == '5': + result.incl sfCodegenDecl + inc i + elif i+1 < s.len and s[i+1] == '6': + result.incl sfCustomPragma + inc i + else: result.incl sfCompilerProc + of 'd': + if i+1 < s.len and s[i+1] == '0': + result.incl sfDeprecated + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfDispatcher + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfDiscardable + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfDirty + inc i + else: result.incl sfDiscriminant + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl sfExportc + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfEscapes + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfExplain + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfError + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfEffectsDelayed + inc i + else: result.incl sfExported + of 'f': + if i+1 < s.len and s[i+1] == '0': + result.incl sfForward + inc i + else: result.incl sfFromGeneric + of 'g': + if i+1 < s.len and s[i+1] == '0': + result.incl sfGenSym + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfGeneratedOp + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfGeneratedType + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfGoto + inc i + else: result.incl sfGlobal + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl sfInfixCall + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfInjectDestructors + inc i + else: result.incl sfImportc + of 'l': result.incl sfForceLift + of 'm': + if i+1 < s.len and s[i+1] == '0': + result.incl sfMainModule + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfMember + inc i + else: result.incl sfMangleCpp + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl sfNoReturn + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfNamedParamCall + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfNonReloadable + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfNeverRaises + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl sfNoalias + inc i + else: result.incl sfNoSideEffect + of 'o': result.incl sfOverridden + of 'p': result.incl sfPure + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl sfRequiresInit + inc i + else: result.incl sfRegister + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl sfSystemModule + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfShadowed + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl sfSystemRaisesDefect + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl sfSingleUsedTemp + inc i + else: result.incl sfSideEffect + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl sfTemplateParam + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl sfTemplateRedefinition + inc i + else: result.incl sfThread + of 'u': + if i+1 < s.len and s[i+1] == '0': + result.incl sfUsedInFinallyOrExcept + inc i + else: result.incl sfUsed + of 'v': + if i+1 < s.len and s[i+1] == '0': + result.incl sfVirtual + inc i + else: result.incl sfVolatile + of 'w': + if i+1 < s.len and s[i+1] == '0': + result.incl sfWasGenSym + inc i + else: result.incl sfWasForwarded + else: discard + inc i + +proc genFlags*(s: set[TNodeFlag]; dest: var string) = + for e in s: + case e + of nfNone: dest.add "n" + of nfBase2: dest.add "b" + of nfBase8: dest.add "b0" + of nfBase16: dest.add "b1" + of nfAllConst: dest.add "a" + of nfTransf: dest.add "t" + of nfNoRewrite: dest.add "r" + of nfSem: dest.add "s" + of nfLL: dest.add "l" + of nfDotField: dest.add "d" + of nfDotSetter: dest.add "d0" + of nfExplicitCall: dest.add "e" + of nfExprCall: dest.add "c" + of nfIsRef: dest.add "i" + of nfIsPtr: dest.add "p" + of nfPreventCg: dest.add "p0" + of nfBlockArg: dest.add "b2" + of nfFromTemplate: dest.add "f" + of nfDefaultParam: dest.add "d1" + of nfDefaultRefsParam: dest.add "d2" + of nfExecuteOnReload: dest.add "o" + of nfLastRead: dest.add "l0" + of nfFirstWrite: dest.add "w" + of nfHasComment: dest.add "h" + of nfSkipFieldChecking: dest.add "s0" + of nfDisabledOpenSym: dest.add "d3" + + +proc parse*(t: typedesc[TNodeFlag]; s: string): set[TNodeFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': result.incl nfAllConst + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl nfBase8 + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl nfBase16 + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl nfBlockArg + inc i + else: result.incl nfBase2 + of 'c': result.incl nfExprCall + of 'd': + if i+1 < s.len and s[i+1] == '0': + result.incl nfDotSetter + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl nfDefaultParam + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl nfDefaultRefsParam + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl nfDisabledOpenSym + inc i + else: result.incl nfDotField + of 'e': result.incl nfExplicitCall + of 'f': result.incl nfFromTemplate + of 'h': result.incl nfHasComment + of 'i': result.incl nfIsRef + of 'l': + if i+1 < s.len and s[i+1] == '0': + result.incl nfLastRead + inc i + else: result.incl nfLL + of 'n': result.incl nfNone + of 'o': result.incl nfExecuteOnReload + of 'p': + if i+1 < s.len and s[i+1] == '0': + result.incl nfPreventCg + inc i + else: result.incl nfIsPtr + of 'r': result.incl nfNoRewrite + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl nfSkipFieldChecking + inc i + else: result.incl nfSem + of 't': result.incl nfTransf + of 'w': result.incl nfFirstWrite + else: discard + inc i + +proc genFlags*(s: set[TTypeFlag]; dest: var string) = + for e in s: + case e + of tfVarargs: dest.add "v" + of tfNoSideEffect: dest.add "n" + of tfFinal: dest.add "f" + of tfInheritable: dest.add "i" + of tfHasOwned: dest.add "h" + of tfEnumHasHoles: dest.add "e" + of tfShallow: dest.add "s" + of tfThread: dest.add "t" + of tfFromGeneric: dest.add "g" + of tfUnresolved: dest.add "u" + of tfResolved: dest.add "r" + of tfRetType: dest.add "r0" + of tfCapturesEnv: dest.add "c" + of tfByCopy: dest.add "b" + of tfByRef: dest.add "b0" + of tfIterator: dest.add "i0" + of tfPartial: dest.add "p" + of tfNotNil: dest.add "n0" + of tfRequiresInit: dest.add "r1" + of tfNeedsFullInit: dest.add "n1" + of tfVarIsPtr: dest.add "v0" + of tfHasMeta: dest.add "m" + of tfHasGCedMem: dest.add "h0" + of tfPacked: dest.add "p0" + of tfHasStatic: dest.add "h1" + of tfGenericTypeParam: dest.add "g0" + of tfImplicitTypeParam: dest.add "i1" + of tfInferrableStatic: dest.add "i2" + of tfConceptMatchedTypeSym: dest.add "c0" + of tfExplicit: dest.add "e0" + of tfWildcard: dest.add "w" + of tfHasAsgn: dest.add "a" + of tfBorrowDot: dest.add "d" + of tfTriggersCompileTime: dest.add "t0" + of tfRefsAnonObj: dest.add "o" + of tfCovariant: dest.add "c1" + of tfWeakCovariant: dest.add "w0" + of tfContravariant: dest.add "c2" + of tfCheckedForDestructor: dest.add "c3" + of tfAcyclic: dest.add "a0" + of tfIncompleteStruct: dest.add "i3" + of tfCompleteStruct: dest.add "c4" + of tfExplicitCallConv: dest.add "e1" + of tfIsConstructor: dest.add "i4" + of tfEffectSystemWorkaround: dest.add "e2" + of tfIsOutParam: dest.add "i5" + of tfSendable: dest.add "s0" + of tfImplicitStatic: dest.add "i6" + + +proc parse*(t: typedesc[TTypeFlag]; s: string): set[TTypeFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': + if i+1 < s.len and s[i+1] == '0': + result.incl tfAcyclic + inc i + else: result.incl tfHasAsgn + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl tfByRef + inc i + else: result.incl tfByCopy + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl tfConceptMatchedTypeSym + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfCovariant + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfContravariant + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl tfCheckedForDestructor + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl tfCompleteStruct + inc i + else: result.incl tfCapturesEnv + of 'd': result.incl tfBorrowDot + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl tfExplicit + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfExplicitCallConv + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfEffectSystemWorkaround + inc i + else: result.incl tfEnumHasHoles + of 'f': result.incl tfFinal + of 'g': + if i+1 < s.len and s[i+1] == '0': + result.incl tfGenericTypeParam + inc i + else: result.incl tfFromGeneric + of 'h': + if i+1 < s.len and s[i+1] == '0': + result.incl tfHasGCedMem + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfHasStatic + inc i + else: result.incl tfHasOwned + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl tfIterator + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfImplicitTypeParam + inc i + elif i+1 < s.len and s[i+1] == '2': + result.incl tfInferrableStatic + inc i + elif i+1 < s.len and s[i+1] == '3': + result.incl tfIncompleteStruct + inc i + elif i+1 < s.len and s[i+1] == '4': + result.incl tfIsConstructor + inc i + elif i+1 < s.len and s[i+1] == '5': + result.incl tfIsOutParam + inc i + elif i+1 < s.len and s[i+1] == '6': + result.incl tfImplicitStatic + inc i + else: result.incl tfInheritable + of 'm': result.incl tfHasMeta + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl tfNotNil + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfNeedsFullInit + inc i + else: result.incl tfNoSideEffect + of 'o': result.incl tfRefsAnonObj + of 'p': + if i+1 < s.len and s[i+1] == '0': + result.incl tfPacked + inc i + else: result.incl tfPartial + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl tfRetType + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl tfRequiresInit + inc i + else: result.incl tfResolved + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl tfSendable + inc i + else: result.incl tfShallow + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl tfTriggersCompileTime + inc i + else: result.incl tfThread + of 'u': result.incl tfUnresolved + of 'v': + if i+1 < s.len and s[i+1] == '0': + result.incl tfVarIsPtr + inc i + else: result.incl tfVarargs + of 'w': + if i+1 < s.len and s[i+1] == '0': + result.incl tfWeakCovariant + inc i + else: result.incl tfWildcard + else: discard + inc i + +proc genFlags*(s: set[TLocFlag]; dest: var string) = + for e in s: + case e + of lfIndirect: dest.add "i" + of lfNoDeepCopy: dest.add "n" + of lfNoDecl: dest.add "d" + of lfDynamicLib: dest.add "l" + of lfExportLib: dest.add "e" + of lfHeader: dest.add "h" + of lfImportCompilerProc: dest.add "c" + of lfSingleUse: dest.add "s" + of lfEnforceDeref: dest.add "e0" + of lfPrepareForMutation: dest.add "p" + + +proc parse*(t: typedesc[TLocFlag]; s: string): set[TLocFlag] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'c': result.incl lfImportCompilerProc + of 'd': result.incl lfNoDecl + of 'e': + if i+1 < s.len and s[i+1] == '0': + result.incl lfEnforceDeref + inc i + else: result.incl lfExportLib + of 'h': result.incl lfHeader + of 'i': result.incl lfIndirect + of 'l': result.incl lfDynamicLib + of 'n': result.incl lfNoDeepCopy + of 'p': result.incl lfPrepareForMutation + of 's': result.incl lfSingleUse + else: discard + inc i + +proc genFlags*(s: set[TOption]; dest: var string) = + for e in s: + case e + of optNone: dest.add "n" + of optObjCheck: dest.add "o" + of optFieldCheck: dest.add "f" + of optRangeCheck: dest.add "r" + of optBoundsCheck: dest.add "b" + of optOverflowCheck: dest.add "c" + of optRefCheck: dest.add "r0" + of optNaNCheck: dest.add "n0" + of optInfCheck: dest.add "i" + of optStaticBoundsCheck: dest.add "s" + of optStyleCheck: dest.add "s0" + of optAssert: dest.add "a" + of optLineDir: dest.add "l" + of optWarns: dest.add "w" + of optHints: dest.add "h" + of optOptimizeSpeed: dest.add "o0" + of optOptimizeSize: dest.add "o1" + of optStackTrace: dest.add "t" + of optStackTraceMsgs: dest.add "m" + of optLineTrace: dest.add "l0" + of optByRef: dest.add "b0" + of optProfiler: dest.add "p" + of optImplicitStatic: dest.add "i0" + of optTrMacros: dest.add "t0" + of optMemTracker: dest.add "m0" + of optSinkInference: dest.add "s1" + of optCursorInference: dest.add "c0" + of optImportHidden: dest.add "i1" + of optQuirky: dest.add "q" + + +proc parse*(t: typedesc[TOption]; s: string): set[TOption] = + result = {} + var i = 0 + while i < s.len: + case s[i] + of 'a': result.incl optAssert + of 'b': + if i+1 < s.len and s[i+1] == '0': + result.incl optByRef + inc i + else: result.incl optBoundsCheck + of 'c': + if i+1 < s.len and s[i+1] == '0': + result.incl optCursorInference + inc i + else: result.incl optOverflowCheck + of 'f': result.incl optFieldCheck + of 'h': result.incl optHints + of 'i': + if i+1 < s.len and s[i+1] == '0': + result.incl optImplicitStatic + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optImportHidden + inc i + else: result.incl optInfCheck + of 'l': + if i+1 < s.len and s[i+1] == '0': + result.incl optLineTrace + inc i + else: result.incl optLineDir + of 'm': + if i+1 < s.len and s[i+1] == '0': + result.incl optMemTracker + inc i + else: result.incl optStackTraceMsgs + of 'n': + if i+1 < s.len and s[i+1] == '0': + result.incl optNaNCheck + inc i + else: result.incl optNone + of 'o': + if i+1 < s.len and s[i+1] == '0': + result.incl optOptimizeSpeed + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optOptimizeSize + inc i + else: result.incl optObjCheck + of 'p': result.incl optProfiler + of 'q': result.incl optQuirky + of 'r': + if i+1 < s.len and s[i+1] == '0': + result.incl optRefCheck + inc i + else: result.incl optRangeCheck + of 's': + if i+1 < s.len and s[i+1] == '0': + result.incl optStyleCheck + inc i + elif i+1 < s.len and s[i+1] == '1': + result.incl optSinkInference + inc i + else: result.incl optStaticBoundsCheck + of 't': + if i+1 < s.len and s[i+1] == '0': + result.incl optTrMacros + inc i + else: result.incl optStackTrace + of 'w': result.incl optWarns + else: discard + inc i + diff --git a/compiler/icnif/icniftags.nim b/compiler/icnif/icniftags.nim new file mode 100644 index 0000000000000..f3c1fe3785f26 --- /dev/null +++ b/compiler/icnif/icniftags.nim @@ -0,0 +1,10 @@ +import "../../dist/nimony/src/lib" / [nifstreams] + +let + symIdTag* = registerTag("symId") + symTag* = registerTag("s") + typeIdTag* = registerTag("typeId") + typeTag* = registerTag("t") + sonsTag* = registerTag("sons") + + modIdTag* = registerTag("modId") diff --git a/compiler/icnif/nifbasics.nim b/compiler/icnif/nifbasics.nim new file mode 100644 index 0000000000000..83f91a2b27bda --- /dev/null +++ b/compiler/icnif/nifbasics.nim @@ -0,0 +1,19 @@ +import std/[assertions, tables] +import ".." / [ast, lineinfos, msgs, options] +import "../../dist/nimony/src/gear2" / modnames + +proc modname(moduleToNifSuffix: var Table[FileIndex, string]; module: PSym; conf: ConfigRef): string = + assert module.kind == skModule + let idx: FileIndex = module.position.FileIndex + # copied from ../nifgen.nim + result = moduleToNifSuffix.getOrDefault(idx) + if result.len == 0: + let fp = toFullPath(conf, idx) + result = moduleSuffix(fp, cast[seq[string]](conf.searchPaths)) + moduleToNifSuffix[idx] = result + #echo result, " -> ", fp + +proc toNifSym*(sym: PSym; moduleToNifSuffix: var Table[FileIndex, string]; conf: ConfigRef): string = + let module = sym.originatingModule + + result = sym.name.s & '.' & $sym.disamb & '.' & modname(moduleToNifSuffix, module, conf) diff --git a/compiler/icnif/nifdecoder.nim b/compiler/icnif/nifdecoder.nim new file mode 100644 index 0000000000000..37f9e888eceef --- /dev/null +++ b/compiler/icnif/nifdecoder.nim @@ -0,0 +1,405 @@ +import std / [assertions, tables] +import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors, lineinfos] +import ".." / [ast, idents, lineinfos, options, modules, modulegraphs, msgs, pathutils] +import enum2nif, icniftags, nifbasics + +type + NifProgram* = ref object + nifSymIdToPSym: Table[SymId, PSym] + moduleToNifSuffix: Table[FileIndex, string] # FileIndex (PSym.position) -> module suffix + + DecodeContext = object + graph: ModuleGraph + symbols: Table[ItemId, PSym] + types: Table[ItemId, PType] + modules: Table[int, FileIndex] # maps module id in NIF to FileIndex of the module + prog: NifProgram + +proc nodeKind(n: Cursor): TNodeKind {.inline.} = + assert n.kind == ParLe + pool.tags[n.tagId].parseNodeKind() + +proc expect(n: Cursor; k: set[NifKind]) = + if n.kind notin k: + when defined(debug): + writeStackTrace() + quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n + +proc expect(n: Cursor; k: NifKind) {.inline.} = + expect n, {k} + +proc incExpect(n: var Cursor; k: set[NifKind]) = + inc n + expect n, k + +proc incExpect(n: var Cursor; k: NifKind) {.inline.} = + incExpect n, {k} + +proc skipParRi(n: var Cursor) = + expect n, {ParRi} + inc n + +proc expectTag(n: Cursor; tagId: TagId) = + if n.kind == ParLe and n.tagId == tagId: + discard + else: + when defined(debug): + writeStackTrace() + if n.kind != ParLe: + quit "[NIF decoder] expected: ParLe but got: " & $n.kind & toString n + else: + quit "[NIF decoder] expected: " & pool.tags[tagId] & " but got: " & pool.tags[n.tagId] & toString n + +proc incExpectTag(n: var Cursor; tagId: TagId) = + inc n + expectTag(n, tagId) + +when false: + proc expectTag(n: Cursor; tag: string) = + let id = pool.tags.getKeyId(tag) + if id == TagId(0): + when defined(debug): + writeStackTrace() + quit "[NIF decoder] expected: " & tag & " but doesn't exist" & toString n + else: + expectTag(n, id) + +proc fromNifLineInfo(c: var DecodeContext; n: Cursor): TLineInfo = + if n.info == NoLineInfo: + unknownLineInfo + else: + let info = pool.man.unpack(n.info) + c.graph.config.newLineInfo(pool.files[info.file].AbsoluteFile, info.line, info.col) + +proc fromNifModuleId(c: var DecodeContext; n: var Cursor): (FileIndex, int32) = + expect n, {ParLe, IntLit} + if n.kind == ParLe: + expectTag n, modIdTag + incExpect n, IntLit + let id = pool.integers[n.intId] + incExpect n, StringLit + let path = pool.strings[n.litId].AbsoluteFile + result = (fileInfoIdx(c.graph.config, path), id.int32) + assert id notin c.modules + c.modules[id] = result[0] + inc n + skipParRi n + elif n.kind == IntLit: + let id = pool.integers[n.intId] + result = (c.modules[id], id.int32) + inc n + +proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym +proc fromNifType(c: var DecodeContext; n: var Cursor): PType +proc fromNif(c: var DecodeContext; n: var Cursor): PNode + +proc fromNifSymDef(c: var DecodeContext; n: var Cursor): PSym = + expectTag n, symIdTag + let info = c.fromNifLineInfo n + inc n + let (itemIdModule, nifModId) = c.fromNifModuleId(n) + expect n, IntLit + let itemId = pool.integers[n.intId].int32 + incExpect n, Ident + let ident = c.graph.cache.getIdent(pool.strings[n.litId]) + incExpect n, {Ident, DotToken} + let magic = if n.kind == Ident: pool.strings[n.litId].parseMagic else: mNone + incExpect n, {Ident, DotToken} + let flags = if n.kind == Ident: pool.strings[n.litId].parseSymFlags else: {} + incExpect n, {Ident, DotToken} + let options = if n.kind == Ident: pool.strings[n.litId].parseOptions else: {} + incExpect n, IntLit + let offset = pool.integers[n.intId].int32 + incExpect n, IntLit + let disamb = pool.integers[n.intId].int32 + incExpect n, ParLe + let kind = parseSymKind(pool.tags[n.tagId]) + inc n + + result = PSym(itemId: ItemId(module: itemIdModule.int32, item: itemId), + kind: kind, + magic: magic, + name: ident, + info: info, + flags: flags, + options: options, + offset: offset, + disamb: disamb) + + # PNode, PSym or PType type fields in PSym can have cycles. + # Add PSym to `c.symbols` before parsing these fields so that + # they can refer this PSym. + let nifItemId = ItemId(module: itemIdModule.int32, item: itemId) + assert nifItemId notin c.symbols + c.symbols[nifItemId] = result + + case kind + of skLet, skVar, skField, skForVar: + result.guard = c.fromNifSymbol n + expect n, IntLit + result.bitsize = pool.integers[n.intId] + incExpect n, IntLit + result.alignment = pool.integers[n.intId] + inc n + else: + discard + skipParRi n + result.position = if kind == skModule: + c.fromNifModuleId(n)[0].int + else: + expect n, IntLit + let p = pool.integers[n.intId] + inc n + p + + result.typ = c.fromNifType n + result.setOwner(c.fromNifSymbol n) + result.ast = c.fromNif n + + expect n, Ident + result.loc.k = pool.strings[n.litId].parseLocKind() + incExpect n, StringLit + result.loc.snippet.add pool.strings[n.litId] + inc n + result.constraint = c.fromNif n + result.instantiatedFrom = c.fromNifSymbol n + skipParRi n + + if sfExported in flags or kind == skModule: + let nifSym = toNifSym(result, c.prog.moduleToNifSuffix, c.graph.config) + let symId = pool.syms.getOrIncl(nifSym) + c.prog.nifSymIdToPSym[symId] = result + +proc fromNifTypeDef(c: var DecodeContext; n: var Cursor): PType = + expectTag n, typeIdTag + inc n + let (itemIdModule, nifModId) = c.fromNifModuleId(n) + expect n, IntLit + let itemId = pool.integers[n.intId].int32 + incExpect n, Ident + let kind = parseTypeKind(pool.strings[n.litId]) + incExpect n, {Ident, DotToken} + let flags = if n.kind == Ident: pool.strings[n.litId].parseTypeFlags else: {} + inc n + + result = PType(itemId: ItemId(module: itemIdModule.int32, item: itemId), + kind: kind, + flags: flags) + let nifItemId = ItemId(module: nifModId, item: itemId) + assert nifItemId notin c.types + c.types[nifItemId] = result + + expect n, {DotToken, ParLe} + if n.kind == DotToken: + inc n + else: + expectTag n, sonsTag + inc n + while n.kind != ParRi: + result.addAllowNil c.fromNifType n + inc n + result.n = c.fromNif n + result.setOwner c.fromNifSymbol n + result.sym = c.fromNifSymbol n + skipParRi n + +proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] = + if n.kind == DotToken: + result = {} + inc n + elif n.kind == Ident: + result = parseNodeFlags(pool.strings[n.litId]) + inc n + else: + assert false, "expected Node flag but got " & $n.kind + +proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym = + if n.kind == DotToken: + result = nil + inc n + elif n.kind == Symbol: + if n.symId notin c.prog.nifSymIdToPSym: + # TODO: Support import statement and remove this branch + #echo pool.syms[n.symId], " is not found" + result = nil + else: + result = c.prog.nifSymIdToPSym[n.symId] + inc n + else: + expect n, ParLe + if n.tagId == symIdTag: + result = c.fromNifSymDef n + elif n.tagId == symTag: + incExpect n, IntLit + let nifModId = c.modules[pool.integers[n.intId].int32] + incExpect n, IntLit + let item = pool.integers[n.intId].int32 + let nifItemId = ItemId(module: nifModId.int32, item: item) + result = c.symbols[nifItemId] + inc n + skipParRi n + else: + assert false, "expected symbol tag but got " & pool.tags[n.tagId] + +proc fromNifType(c: var DecodeContext; n: var Cursor): PType = + if n.kind == DotToken: + result = nil + inc n + else: + expect n, ParLe + if n.tagId == typeIdTag: + result = c.fromNifTypeDef n + elif n.tagId == typeTag: + incExpect n, IntLit + let nifModId = pool.integers[n.intId].int32 + incExpect n, IntLit + let item = pool.integers[n.intId].int32 + let nifItemId = ItemId(module: nifModId, item: item) + result = c.types[nifItemId] + inc n + skipParRi n + else: + assert false, "expected type tag but got " & pool.tags[n.tagId] + +template withNode(c: var DecodeContext; n: var Cursor; result: PNode; kind: TNodeKind; body: untyped) = + let info = c.fromNifLineInfo(n) + incExpect n, {DotToken, Ident} + let flags = fromNifNodeFlags n + result = newNodeI(kind, info) + result.flags = flags + result.typ = c.fromNifType n + body + skipParRi n + +proc fromNif(c: var DecodeContext; n: var Cursor): PNode = + result = nil + case n.kind: + of DotToken: + result = nil + inc n + of ParLe: + let kind = n.nodeKind + case kind: + of nkEmpty: + result = newNodeI(nkEmpty, c.fromNifLineInfo(n)) + incExpect n, {Ident, DotToken} + let flags = fromNifNodeFlags n + result.flags = flags + skipParRi n + of nkIdent: + let info = c.fromNifLineInfo(n) + incExpect n, {DotToken, Ident} + let flags = fromNifNodeFlags n + let typ = c.fromNifType n + expect n, Ident + result = newIdentNode(c.graph.cache.getIdent(pool.strings[n.litId]), info) + inc n + result.flags = flags + result.typ = typ + skipParRi n + of nkSym: + c.withNode n, result, kind: + result.sym = c.fromNifSymbol n + of nkCharLit: + c.withNode n, result, kind: + expect n, CharLit + result.intVal = n.charLit.int + inc n + of nkIntLit .. nkInt64Lit: + c.withNode n, result, kind: + expect n, IntLit + result.intVal = pool.integers[n.intId] + inc n + of nkUIntLit .. nkUInt64Lit: + c.withNode n, result, kind: + expect n, UIntLit + result.intVal = cast[BiggestInt](pool.uintegers[n.uintId]) + inc n + of nkFloatLit .. nkFloat128Lit: + c.withNode n, result, kind: + if n.kind == FloatLit: + result.floatVal = pool.floats[n.floatId] + inc n + elif n.kind == ParLe: + case pool.tags[n.tagId] + of "inf": + result.floatVal = Inf + of "nan": + result.floatVal = NaN + of "neginf": + result.floatVal = NegInf + else: + assert false, "expected float literal but got " & pool.tags[n.tagId] + inc n + skipParRi n + else: + assert false, "expected float literal but got " & $n.kind + of nkStrLit .. nkTripleStrLit: + c.withNode n, result, kind: + expect n, StringLit + result.strVal = pool.strings[n.litId] + inc n + of nkNilLit: + c.withNode n, result, kind: + discard + of nkNone: + assert false, "Unknown tag " & pool.tags[n.tagId] + else: + c.withNode n, result, kind: + while n.kind != ParRi: + result.addAllowNil c.fromNif n + else: + assert false, "Not yet implemented " & $n.kind + +proc loadNif(stream: var Stream; graph: ModuleGraph; prog: NifProgram): PNode = + discard processDirectives(stream.r) + + var buf = fromStream(stream) + var n = beginRead(buf) + var c = DecodeContext(graph: graph, prog: prog) + + var n2 = n + var nested = 0 + while true: + if n2.info != NoLineInfo: + break + elif n2.kind == EofToken: + break + elif n2.kind == ParLe: + inc nested + elif n2.kind == ParRi: + dec nested + if nested == 0: break + inc n2 + assert n2.info != NoLineInfo + let info = pool.man.unpack(n2.info) + let fileIdx = c.graph.config.fileInfoIdx(pool.files[info.file].AbsoluteFile) + var currentModule = graph.newModule(fileIdx) + if currentModule.itemId.module == 0'i32: + currentModule.flags = {sfMainModule, sfSystemModule} + + c.symbols[currentModule.itemId] = currentModule + let nifSym = toNifSym(currentModule, c.prog.moduleToNifSuffix, c.graph.config) + let symId = pool.syms.getOrIncl(nifSym) + c.prog.nifSymIdToPSym[symId] = currentModule + + result = fromNif(c, n) + + endRead(buf) + +proc loadNifFile*(infile: AbsoluteFile; graph: ModuleGraph; prog: NifProgram): PNode = + var stream = nifstreams.open(infile.string) + result = loadNif(stream, graph, prog) + stream.close + +proc loadNifFromBuffer*(strbuf: sink string; graph: ModuleGraph; prog: NifProgram): PNode = + var stream = nifstreams.openFromBuffer(strbuf) + result = loadNif(stream, graph, prog) + +when isMainModule: + import std/cmdline + + if paramCount() > 0: + var graph = newModuleGraph(newIdentCache(), newConfigRef()) + var node = loadNifFile(paramStr(1).toAbsolute(toAbsoluteDir(".")), graph) + debug(node) diff --git a/compiler/icnif/nifencoder.nim b/compiler/icnif/nifencoder.nim new file mode 100644 index 0000000000000..e35ea4ab8abfd --- /dev/null +++ b/compiler/icnif/nifencoder.nim @@ -0,0 +1,218 @@ +import std / [assertions, sets, tables] +import ".." / [ast, idents, lineinfos, msgs, options] +import "../../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos] +import enum2nif, icniftags, nifbasics + +type + EncodeContext = object + conf: ConfigRef + currentModule: PSym + decodedSyms: HashSet[ItemId] + decodedTypes: HashSet[ItemId] + decodedFileIndices: HashSet[FileIndex] + dest: TokenBuf + moduleToNifSuffix: Table[FileIndex, string] # FileIndex (PSym.position) -> module suffix + +proc initEncodeContext(conf: ConfigRef; currentModule: PSym): EncodeContext = + result = EncodeContext(conf: conf, + currentModule: currentModule, + dest: createTokenBuf()) + result.decodedSyms.incl(currentModule.itemId) + +template buildTree(dest: var TokenBuf; tag: TagId; body: untyped) = + dest.addParLe tag + body + dest.addParRi + +template buildTree(dest: var TokenBuf; tag: string; body: untyped) = + buildTree dest, pool.tags.getOrIncl(tag), body + +proc writeFlags[E](dest: var TokenBuf; flags: set[E]) = + var flagsAsIdent = "" + genFlags(flags, flagsAsIdent) + if flagsAsIdent.len > 0: + dest.addIdent flagsAsIdent + else: + dest.addDotToken + +proc toNif(c: var EncodeContext; info: TLineInfo): PackedLineInfo = + if info == unknownLineInfo: + NoLineInfo + else: + let fileId = pool.files.getOrIncl(c.conf.toFullPath(info.fileIndex)) + pack(pool.man, fileId, info.line.int32, info.col) + +proc toNifModuleId(c: var EncodeContext; moduleId: int) = + # `ItemId.module` in PType and PSym (and `PSym.position` when it is skModule) are module's FileIndex + # but it cannot be directly encoded as the uniqueness of it can broke + # if any import/include statements are changed. + if not c.decodedFileIndices.containsOrIncl(moduleId.FileIndex): + c.dest.buildTree modIdTag: + c.dest.addIntLit moduleId + let path = toFullPath(c.conf, moduleId.FileIndex) + c.dest.addStrLit path + else: + c.dest.addIntLit moduleId + +proc toNif(c: var EncodeContext; sym: PSym) +proc toNif(c: var EncodeContext; typ: PType) +proc toNif(c: var EncodeContext; n: PNode) + +proc toNifDef(c: var EncodeContext; sym: PSym) = + c.dest.addParLe symIdTag, c.toNif sym.info + c.toNifModuleId sym.itemId.module + c.dest.addIntLit sym.itemId.item + c.dest.addIdent sym.name.s + if sym.magic == mNone: + c.dest.addDotToken + else: + c.dest.addIdent toNifTag(sym.magic) + c.dest.writeFlags sym.flags + c.dest.writeFlags sym.options + c.dest.addIntLit sym.offset + c.dest.addIntLit sym.disamb + c.dest.buildTree sym.kind.toNifTag: + case sym.kind + of skLet, skVar, skField, skForVar: + c.toNif sym.guard + c.dest.addIntLit sym.bitsize + c.dest.addIntLit sym.alignment + else: + discard + if sym.kind == skModule: + c.toNifModuleId sym.position + else: + c.dest.addIntLit sym.position + c.toNif sym.typ + c.toNif sym.owner + c.toNif sym.ast # drastically increase output NIF size! -- Yeah, no shit Sherlock. + c.dest.addIdent toNifTag(sym.loc.k) + c.dest.addStrLit sym.loc.snippet + c.toNif sym.constraint + c.toNif sym.instantiatedFrom + c.dest.addParRi + +proc toNifDef(c: var EncodeContext; typ: PType) = + c.dest.buildTree typeIdTag: + c.toNifModuleId typ.itemId.module + c.dest.addIntLit typ.itemId.item + c.dest.addIdent toNifTag(typ.kind) + c.dest.writeFlags typ.flags + # following PType or PSym type field can have cycles but this proc should not called recursively + # as c.decodedTypes prevents it. + if typ.len == 0: + c.dest.addDotToken + else: + c.dest.buildTree sonsTag: + for ch in typ.kids: + c.toNif ch + + c.toNif typ.n + c.toNif typ.owner + c.toNif typ.sym + +proc toNif(c: var EncodeContext; sym: PSym) = + if sym == nil: + c.dest.addDotToken() + elif sym.owner != nil and sym.originatingModule != c.currentModule: + let nifSym = toNifSym(sym, c.moduleToNifSuffix, c.conf) + c.dest.addSymUse(pool.syms.getOrIncl(nifSym), NoLineInfo) + else: + if not c.decodedSyms.containsOrIncl(sym.itemId): + c.toNifDef sym + else: + c.dest.buildTree symTag: + c.dest.addIntLit sym.itemId.module + c.dest.addIntLit sym.itemId.item + +proc toNif(c: var EncodeContext; typ: PType) = + if typ == nil: + c.dest.addDotToken() + else: + if not c.decodedTypes.containsOrIncl(typ.itemId): + c.toNifDef typ + else: + c.dest.buildTree typeTag: + c.dest.addIntLit typ.itemId.module + c.dest.addIntLit typ.itemId.item + +proc writeNodeFlags(dest: var TokenBuf; flags: set[TNodeFlag]) {.inline.} = + writeFlags dest, flags + +template withNode(c: var EncodeContext; n: PNode; body: untyped) = + c.dest.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), c.toNif n.info + writeNodeFlags(c.dest, n.flags) + c.toNif n.typ + body + c.dest.addParRi + +proc toNif(c: var EncodeContext; n: PNode) = + if n == nil: + c.dest.addDotToken + else: + case n.kind: + of nkEmpty: + let info = c.toNif n.info + c.dest.addParLe pool.tags.getOrIncl(toNifTag(nkEmpty)), info + c.dest.writeNodeFlags(n.flags) + c.dest.addParRi + of nkIdent: + # nkIdent uses flags and typ when it is a generic parameter + c.withNode n: + c.dest.addIdent n.ident.s + of nkSym: + when false: + echo "nkSym: ", n.sym.name.s + if n.sym.kind == skModule: + echo "position = ", n.sym.position + debug(n.sym) + var o = n.sym.owner + for i in 0 .. 20: + if o == nil: + break + echo "owner ", i, ":" + if o.kind == skModule: + echo "position = ", o.position + debug(o) + o = o.owner + # PNode.typ and PNode.sym.typ are different in `int` nkSym Node in following statement: + # type TestInt = int + c.withNode n: + c.toNif n.sym + of nkCharLit: + c.withNode n: + c.dest.add charToken(n.intVal.char, NoLineInfo) + of nkIntLit .. nkInt64Lit: + c.withNode n: + c.dest.addIntLit n.intVal + of nkUIntLit .. nkUInt64Lit: + c.withNode n: + c.dest.addUIntLit cast[BiggestUInt](n.intVal) + of nkFloatLit .. nkFloat128Lit: + c.withNode n: + c.dest.add floatToken(pool.floats.getOrIncl(n.floatVal), NoLineInfo) + of nkStrLit .. nkTripleStrLit: + c.withNode n: + c.dest.addStrLit n.strVal + of nkNilLit: + c.withNode n: + discard + else: + #assert n.kind in {nkArgList, nkBracket, nkRecList, nkPragma, nkType} or n.len > 0, $n.kind + c.withNode(n): + for i in 0 ..< n.len: + c.toNif n[i] + +proc saveNif(c: var EncodeContext; n: PNode): string = + toNif c, n + + result = "(.nif24)\n" & toString(c.dest) + +proc saveNifFile*(n: PNode; conf: ConfigRef; module: PSym) = + let outfile = module.name.s & ".nif" + var c = initEncodeContext(conf, module) + writeFile outfile, saveNif(c, n) + +proc saveNifToBuffer*(n: PNode; conf: ConfigRef; module: PSym): string = + var c = initEncodeContext(conf, module) + result = saveNif(c, n) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index fd8ef583d00a3..4d63d44acb644 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -219,7 +219,7 @@ proc mapType(typ: PType): TJSTypeKind = else: result = etyNone of tyProc: result = etyProc of tyCstring: result = etyString - of tyConcept, tyIterable: + of tyConcept, tyIterable, tyStub: raiseAssert "unreachable" proc mapType(p: PProc; typ: PType): TJSTypeKind = diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 5d8fbc179dd82..42b96aa1cab9b 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -972,7 +972,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind - of tyNone, tyEmpty, tyVoid: discard + of tyNone, tyEmpty, tyVoid, tyStub: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring, tyPtr, tyUncheckedArray, tyVar, tyLent: defaultOp(c, t, body, x, y) diff --git a/compiler/nifgen.nim b/compiler/nifgen.nim index cf267ef14bc5d..c9d86b50f00bb 100644 --- a/compiler/nifgen.nim +++ b/compiler/nifgen.nim @@ -666,6 +666,7 @@ proc toNifTag(s: TTypeKind): string = of tyConcept: "concept" of tyVoid: "void" of tyIterable: "iterable" + of tyStub: "stub" proc atom(t: PType; c: var TranslationContext) = c.b.withTree toNifTag(t.kind): @@ -924,7 +925,7 @@ proc toNifType(t: PType; parent: PNode; c: var TranslationContext) = atom t, c, "err" of tyCompositeTypeClass: toNifType t.last, parent, c of tyInferred: toNifType t.skipModifier, parent, c - of tyAnything: atom t, c + of tyAnything, tyStub: atom t, c of tyStatic: c.typeHead t: if t.hasElementType: diff --git a/compiler/options.nim b/compiler/options.nim index 7bc7d403c861c..142080cc8f5c4 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -111,6 +111,7 @@ type # please make sure we have under 32 options optShowNonExportedFields # for documentation: show fields that are not exported optJsBigInt64 # use bigints for 64-bit integers in JS optItaniumMangle # mangling follows the Itanium spec + optCompress # turn on AST compression by converting it to NIF TGlobalOptions* = set[TGlobalOption] diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index e617ae8b90b0c..e4becc92f0171 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -1,7 +1,7 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs, lineinfos, reorder, options, semdata, cgendata, modules, pathutils, packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg, - liftdestructors, nifgen + liftdestructors, nifgen, ast2nif import pipelineutils @@ -218,6 +218,9 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator of NonePass: raiseAssert "use setPipeLinePass to set a proper PipelinePass" + if optCompress in graph.config.globalOptions: + writeNifModule(graph.config, module.position.int32, finalNode) + if graph.config.backend notin {backendC, backendCpp, backendObjc}: # We only write rod files here if no C-like backend is active. # The C-like backends have been patched to support the IC mechanism. diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ae4c744ead7b2..1d6312e55c3c6 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2801,7 +2801,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode = if n[bodyPos].kind == nkEmpty: localError(c.config, n.info, errImplOfXexpected % s.name.s) -proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) = +proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult, resolvedIncStmt: PNode) = var f = checkModuleName(c.config, it) if f != InvalidFileIdx: addIncludeFileDep(c, f) @@ -2809,12 +2809,22 @@ proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) = if containsOrIncl(c.includedFiles, f.int): localError(c.config, n.info, errRecursiveDependencyX % toMsgFilename(c.config, f)) else: + if resolvedIncStmt != nil: + resolvedIncStmt.add newStrNode(toFullPath(c.config, f), it.info) includeStmtResult.add semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}) excl(c.includedFiles, f.int) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) - result.add n + var resolvedIncStmt: PNode = nil + if optCompress in c.config.globalOptions: + # New resolve the include filenames to string literals that contain absolute paths, + # nicer for IC: + resolvedIncStmt = newNodeI(nkIncludeStmt, n.info) + result.add resolvedIncStmt + else: + # Legacy: Keep `include` statement as is: + result.add n template checkAs(it: PNode) = if it.kind == nkInfix and it.len == 3: let op = it[0].getPIdent @@ -2832,9 +2842,9 @@ proc evalInclude(c: PContext, n: PNode): PNode = for x in it[lastPos]: checkAs(x) imp[lastPos] = x - incMod(c, n, imp, result) + incMod(c, n, imp, result, resolvedIncStmt) else: - incMod(c, n, it, result) + incMod(c, n, it, result, resolvedIncStmt) proc recursiveSetFlag(n: PNode, flag: TNodeFlag) = if n != nil: diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index 80b532371cb01..0529a6671f6de 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -201,7 +201,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedNode(marker, t.n, kind, c, flags) of tyEmpty: if kind in {skVar, skLet}: result = t - of tyError: + of tyError, tyStub: # for now same as error node; we say it's a valid type as it should # prevent cascading errors: result = nil diff --git a/compiler/types.nim b/compiler/types.nim index bd65c3f33137a..b26a949407de9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -491,7 +491,7 @@ const "BuiltInTypeClass", "UserTypeClass", "UserTypeClassInst", "CompositeTypeClass", "inferred", "and", "or", "not", "any", "static", "TypeFromExpr", "concept", # xxx bugfix - "void", "iterable"] + "void", "iterable", "stub"] const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo, preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects} @@ -1344,6 +1344,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = a.id == b.id and sameFlags(a, b) of tyError: result = b.kind == tyError + of tyStub: + result = false of tyTuple: withoutShallowFlags: cycleCheck() diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 72eec34eadb65..882f030ee764f 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -97,7 +97,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; return atomicType(t.sym) case t.kind - of tyNone: result = atomicType("none", mNone) + of tyNone, tyStub: result = atomicType("none", mNone) of tyBool: result = atomicType("bool", mBool) of tyChar: result = atomicType("char", mChar) of tyNil: result = atomicType("nil", mNil) diff --git a/tests/icnif/tencode_node2node.nim b/tests/icnif/tencode_node2node.nim new file mode 100644 index 0000000000000..b1793ec6c27ec --- /dev/null +++ b/tests/icnif/tencode_node2node.nim @@ -0,0 +1,398 @@ +import std/[assertions, math, tables] +import "../../compiler/icnif" / [nifencoder, nifdecoder] +import "../../compiler" / [idents, ast, astalgo, options, pathutils, modulegraphs, modules, msgs, pipelines, syntaxes, sem, llstream, lineinfos] + +# This test generates PNode by semchecks test code. +# Then it is used to test icnif/nifencoder and nifdecoder. + +const TestCodeDir = currentSourcePath().AbsoluteFile.splitFile().dir / RelativeDir"testcode" + +proc newConfigRefForTest(): ConfigRef = + var conf = newConfigRef() + conf.setDefaultLibpath() + conf.searchPaths.add(conf.libpath) + excl(conf.notes, hintProcessing) + excl(conf.mainPackageNotes, hintProcessing) + result = conf + +proc newModuleGraphForSem(cache: IdentCache; conf: ConfigRef): ModuleGraph = + var graph = newModuleGraph(cache, conf) + graph.setPipeLinePass(SemPass) + # Make PNode from sem pass assigned to graph.systemModule.ast + let oldCmd = graph.config.cmd + graph.config.cmd = cmdIdeTools + graph.compilePipelineSystemModule() + graph.config.cmd = oldCmd + result = graph + +proc getSystemNif(graph: ModuleGraph): seq[string] = + result = newSeqOfCap[string](graph.ifaces.len) + for i, iface in graph.ifaces.mpairs: + if iface.module != nil: + let n = iface.module.ast + assert n != nil + # if nil is not assigned, it generates large NIF + iface.module.ast = nil + result.add saveNifToBuffer(n, graph.config, iface.module) + #writeFile(iface.module.name.s & ".nif", result[^1]) + +proc sem(graph: ModuleGraph; path: AbsoluteFile): (PNode, PSym) = + result = (nil, nil) + + let fileIdx = fileInfoIdx(graph.config, path) + var module = newModule(graph, fileIdx) + registerModule(graph, module) + + var idgen = idGeneratorFromModule(module) + let ctx = preparePContext(graph, module, idgen) + + var stream = llStreamOpen(path, fmRead) + if stream == nil: + rawMessage(graph.config, errCannotOpenFile, path.string) + return (nil, nil) + + var p: Parser = default(Parser) + syntaxes.openParser(p, fileIdx, stream, graph.cache, graph.config) + + checkFirstLineIndentation(p) + block processCode: + if graph.stopCompile(): break processCode + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break processCode + # read everything, no streaming possible + var sl = newNodeI(nkStmtList, n.info) + sl.add n + while true: + var n = parseTopLevelStmt(p) + if n.kind == nkEmpty: break + sl.add n + + result = (semWithPContext(ctx, sl), module) + +type + # Nim's AST has cycles that causes infinite recursive loop in eql procs. + # this is used to prevent that happen. + EqlContext = object + nodeStack: seq[PNode] + checkedSyms: Table[ItemId, PSym] # used to check if each PSym has unique ItemId + # and also prevents inifinite loop + checkedTypes: Table[ItemId, PType]# used like checkedSyms + confX, confY: ConfigRef # used to print the line info when there is a mismatch + # and get path from FileIndex + +# Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support +# `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder. +proc eql(x, y: PNode; c: var EqlContext): bool +proc eql(x, y: PType; c: var EqlContext): bool + +proc eql(x, y: TLoc): bool = + if x.k != y.k: + echo "loc kind mismatch: ", x.k, "/", y.k + result = false + elif x.snippet != y.snippet: + echo "loc snippet mismatch: ", x.snippet, "/", y.snippet + result = false + else: + result = true + +proc eqlFileIndex(x, y: int; c: EqlContext): bool = + let xpath = c.confX.toFullPath(x.FileIndex) + let ypath = c.confY.toFullPath(y.FileIndex) + if xpath != ypath: + echo "file index mismatch: ", xpath, "/", ypath + result = false + else: + result = true + +proc eql(x, y: TLineInfo; c: EqlContext): bool = + # If parent PNode has a valid line info but it's child doesn't have one, + # cannot translate such a tree to NIF. + # Because in NIF, if a child node doesn't have line info, + # nifstream assign the parent's line info to it. + # So cannot have child node without line info if parent has a valid line info. + if x == unknownLineInfo: + result = true + elif x.line != y.line: + echo "line number mismatch: ", x.line, "/", y.line + result = false + elif x.col != y.col: + echo "column number mismatch: ", x.col, "/", y.col + result = false + elif not eqlFileIndex(x.fileIndex.int, y.fileIndex.int, c): + echo "file in line info mismatch" + result = false + else: + result = true + +proc eqlSymPos(x, y: PSym; c: EqlContext): bool = + if x.kind == skModule: + result = eqlFileIndex(x.position, y.position, c) + elif x.position != y.position: + echo "symbol position mismatch: ", x.position, "/", y.position + result = false + else: + result = true + +proc eqlItemId(x, y: ItemId; c: EqlContext): bool = + if x.item != y.item: + echo "itemId.item mismatch: ", x.item, "/", y.item + result = false + elif not eqlFileIndex(x.module, y.module, c): + result = false + else: + result = true + +proc eql(x, y: PSym; c: var EqlContext): bool = + if x == nil and y == nil: + result = true + elif x == nil or y == nil: + echo "symbol is missing" + result = false + elif not eqlItemId(x.itemId, y.itemId, c): + echo "symbol itemId mismatch" + result = false + elif c.checkedSyms.hasKeyOrPut(y.itemId, y): + if c.checkedSyms[y.itemId] == y: + result = true + else: + echo "detected duplicated symbol ItemId:" + debug(x) + debug(c.checkedSyms[y.itemId]) + debug(y) + result = false + elif x.name.s != y.name.s: + echo "symbol name mismatch: ", x.name.s, "/", y.name.s + result = false + elif x.kind != y.kind: + echo "symbol kind mismatch: ", x.kind, "/", y.kind + result = false + elif x.magic != y.magic: + echo "symbol magic mismatch: ", x.magic, "/", y.magic + result = false + elif x.kind != skPackage and not eql(x.info, y.info, c): + # fileIndex of info of skPackage is just a path of first semchecked module in the package + echo "symbol line info mismatch" + result = false + elif x.kind != skModule and x.flags != y.flags: + # TODO: check the flag of skModule + echo "symbol flag mismatch: ", x.flags, "/", y.flags + result = false + elif x.options != y.options: + echo "symbol options mismatch: ", x.options, "/", y.options + result = false + elif not eqlSymPos(x, y, c): + result = false + elif x.offset != y.offset: + echo "symbol offset mismatch: ", x.offset, "/", y.offset + result = false + elif x.disamb != y.disamb: + echo "symbol disamb mismatch: ", x.disamb, "/", y.disamb + result = false + elif not eql(x.loc, y.loc): + echo "symbol.loc mismatch" + result = false + else: + if not eql(x.typ, y.typ, c): + echo "symbol type mismatch:" + result = false + elif not eql(x.owner, y.owner, c): + echo "Symbol owner mismatch:" + debug(x.owner) + debug(y.owner) + result = false + elif not eql(x.ast, y.ast, c): + echo "symbol ast mismatch" + result = false + elif not eql(x.constraint, y.constraint, c): + echo "symbol constraint mismatch" + result = false + elif not eql(x.instantiatedFrom, y.instantiatedFrom, c): + echo "symbol instantiatedFrom mismatch" + result = false + else: + if x.kind in {skLet, skVar, skField, skForVar}: + if not eql(x.guard, y.guard, c): + echo "symbol guard mismatch" + result = false + elif x.bitsize != y.bitsize: + echo "symbol bitsize mismatch: ", x.bitsize, "/", y.bitsize + result = false + elif x.alignment != y.alignment: + echo "symbol alignment mismatch: ", x.alignment, "/", y.alignment + result = false + else: + result = true + else: + result = true + +proc eql(x, y: PType; c: var EqlContext): bool = + if x == nil and y == nil: + result = true + elif x == nil or y == nil: + echo "type is missing" + result = false + elif not eqlItemId(x.itemId, y.itemId, c): + echo "type itemId mismatch" + result = false + elif c.checkedTypes.hasKeyOrPut(y.itemId, y): + result = true + #[ + if c.checkedTypes[y.itemId] == y: + result = true + else: + echo "detected duplicated type ItemId:" + debug(x) + debug(c.checkedTypes[y.itemId]) + debug(y) + result = false + ]# + elif x.kind != y.kind: + echo "type kind mismatch: ", x.kind, "/", y.kind + result = false + elif x.flags != y.flags: + echo "type flag mismatch: ", x.flags, "/", y.flags + result = false + else: + if not eql(x.n, y.n, c): + echo "type.n mismatch" + debug(x.n) + debug(y.n) + result = false + elif not eql(x.owner, y.owner, c): + echo "type owner mismatch: " + debug(x.owner) + debug(y.owner) + result = false + elif not eql(x.sym, y.sym, c): + echo "type sym mismatch:" + debug(x.sym) + debug(y.sym) + result = false + elif x.kidsLen != y.kidsLen: + echo "type kidsLen mismatch" + result = false + else: + result = true + for i in 0 ..< x.kidsLen: + if not eql(x[i], y[i], c): + echo "type kids mismatch: " + debug(x[i]) + debug(y[i]) + result = false + break + +proc eql(x, y: PNode; c: var EqlContext): bool = + if x == nil and y == nil: + result = true + elif x == nil or y == nil: + result = false + elif x.kind != y.kind: + echo "node kind mismatch: ", x.kind, "/", y.kind + result = false + elif x.flags != y.flags: + echo "node flag mismatch: ", x.flags, "/", y.flags, " at ", `$`(c.confX, x.info) + debug(x) + debug(y) + result = false + elif not eql(x.info, y. info, c): + echo "node lineinfo mismatch at ", `$`(c.confX, x.info) + debug(x) + result = false + elif x.safeLen == y.safeLen: + if c.nodeStack.len != 0: + for i in countDown(c.nodeStack.len - 1, 0): + if x == c.nodeStack[i]: + # echo "cycle is detected in PNode" + return true + c.nodeStack.add x + if not eql(x.typ, y.typ, c): + echo "PNode type mismatch at ", `$`(c.confX, x.info), ":" + debug(x) + debug(y) + debug(x.typ) + debug(y.typ) + result = false + else: + case x.kind: + of nkIdent: + # these idents are generated from different IdentCache + result = x.ident.s == y.ident.s + if not result: + echo "PNode identifier mismatch: ", `$`(c.confX, x.info), x.ident.s, "/", y.ident.s + of nkSym: + result = eql(x.sym, y.sym, c) + if not result: + echo "Symbol mismatch:" + debug(x.sym) + if y.sym == nil: + echo "y.sym = nil" + else: + debug(y.sym) + debug(x.sym.typ) + debug(y.sym.typ) + of nkCharLit .. nkUInt64Lit, nkStrLit .. nkTripleStrLit: + result = sameValue(x, y) + of nkFloatLit .. nkFloat128Lit: + # want to know if x and y are identical float value. + # so x == y doesn't work if both x and y are NaN or x == 0 and y == -0. + let xc = classify(x.floatVal) + let yc = classify(y.floatVal) + if xc == yc: + if xc in {fcNormal, fcSubnormal}: + if x.floatVal != y.floatVal: + echo "float literal mismatch: ", x.floatVal, "/", y.floatVal + result = false + else: + result = true + else: + result = true + else: + echo "float literal mismatch: ", xc, "/", yc + result = false + else: + result = true + for i in 0 ..< x.safeLen: + if not eql(x[i], y[i], c): + result = false + break + discard c.nodeStack.pop + else: + echo "node length mismatch" + debug(x) + debug(y) + result = false + +proc testNifEncDec(graph: ModuleGraph; src: string; systemNif: openArray[string]) = + let fullPath = TestCodeDir / RelativeFile(src) + let (n, module) = sem(graph, fullPath) + assert n != nil, "failed to sem " & $fullPath + assert module.owner.kind == skPackage + + #debug(n) + let nif = saveNifToBuffer(n, graph.config, module) + #echo nif + #echo "NIF size of ", src, ": ", nif.len + #writeFile(src & ".nif", nif) + + # Don't reuse the ModuleGraph used for semcheck when load NIF. + var graphForLoad = newModuleGraph(newIdentCache(), newConfigRefForTest()) + var prog = NifProgram() + for sysNif in systemNif: + discard loadNifFromBuffer(sysNif, graphForLoad, prog) + let n2 = loadNifFromBuffer(nif, graphForLoad, prog) + #debug(n2) + var c = EqlContext(confX: graph.config, confY: graphForLoad.config) + assert eql(n, n2, c), "test failed: " & $fullPath + +var conf = newConfigRefForTest() +var cache = newIdentCache() +var graph = newModuleGraphForSem(cache, conf) +let systemNif = getSystemNif(graph) +testNifEncDec(graph, "modtest1.nim", systemNif) +testNifEncDec(graph, "modtestliterals.nim", systemNif) +testNifEncDec(graph, "modtesttypesections.nim", systemNif) +#testNifEncDec(graph, "modtestpragmas.nim", systemNif) +testNifEncDec(graph, "modtestprocs.nim", systemNif) +#testNifEncDec(graph, "modteststatements.nim", systemNif) +#testNifEncDec(graph, "modtestgenerics.nim", systemNif) +#testNifEncDec(graph, "modtestexprs.nim", systemNif) diff --git a/tests/icnif/testcode/modtest1.nim b/tests/icnif/testcode/modtest1.nim new file mode 100644 index 0000000000000..f36fa1afd2393 --- /dev/null +++ b/tests/icnif/testcode/modtest1.nim @@ -0,0 +1,2 @@ +var x* = 123 +var y = x diff --git a/tests/icnif/testcode/modtestexprs.nim b/tests/icnif/testcode/modtestexprs.nim new file mode 100644 index 0000000000000..1ffee629055c8 --- /dev/null +++ b/tests/icnif/testcode/modtestexprs.nim @@ -0,0 +1,79 @@ +type + FooEnum = enum + X, + Y, + Z + +var enumTest = X +enumTest = Y +assert enumTest == Y + +var enumSet = {X, Y} +enumSet.incl Z + +var intArray = [1, 1 + 1, 1 * 2, 0] +intArray[3] = intArray[1] + intArray[0] * intArray[2] +var strArray = ["foo", "ba" & "r", ""] +strArray[2] = $(intArray[2]) +var floatArray = [intArray[0].float, 1.0, 0.0] +floatArray[2] = floatArray[0] + floatArray[1] +var intSeq = @[3, 2] +intSeq.add 1 + +var tup1 = (foo: "Foo", bar: 123) +tup1.foo = "Bar" +tup1.bar = 321 +tup1[0] = "Baz" +assert tup1 is (string, int) +let (tup1foo, tup1bar) = tup1 +let (_, tup1bar2) = tup1 +let (tup1foo2, _) = tup1 + +var testAddr: int +var testPtr = addr testAddr +testPtr[] = 123 + +var testAddr2: array[2, int] +var testPtr2: ptr int +testPtr2 = addr testAddr2[0] +var testPointer: pointer = testPtr2 +testPtr2 = cast[ptr int](testPointer) + +var stmtListExpr = (echo "foo"; "stmtListExpr") +var cond1 = true +var testIfExpr = if cond1: 1 else: -1 +const TestWhenExpr = when sizeof(int) == 8: 1 else: -1 +var cond2: FooEnum = X +var testCaseExpr = case cond2 + of X: + 1 + of Y: + 2 + else: + 3 + +var testBlockExpr = block: + var a = "test" + a + +var testTryExpr = try: + if cond1: + 222 + else: + raise newException(CatchableError, "test") + except CatchableError: + -123 + +var testTryExpr2 = try: + if cond1: + 333 + else: + raise newException(CatchableError, "test") + except CatchableError as e: + echo e.msg + -1234 + finally: + echo "finally" + +proc getNum(a: int): int = a +echo static(getNum(123)) diff --git a/tests/icnif/testcode/modtestgenerics.nim b/tests/icnif/testcode/modtestgenerics.nim new file mode 100644 index 0000000000000..dbf023e88c53f --- /dev/null +++ b/tests/icnif/testcode/modtestgenerics.nim @@ -0,0 +1,43 @@ +type + GenericsType[T] = object + GenericsType2[T] = object + x: T + GenericsType3[T, U] = object + x: T + y: U + GenericsType4[T: int or bool] = distinct int + GenericsType5[N: static[int]; T] = object + x: array[N, T] + GenericsType6[T: SomeNumber] = object + x: T + +var genericsType: GenericsType[int] +var genericsType2: GenericsType2[int] +var genericsType3: GenericsType3[float, string] +var genericsType4: GenericsType4[bool] +var genericsType5: GenericsType5[3, float] +var genericsType6: GenericsType6[int8] + +proc genericsProc[T]() = discard +genericsProc[int]() + +proc genericsProc2[T](x: T) = discard x +genericsProc2(123) + +proc genericsProc3[T, U](x: T; y: U) = discard x +genericsProc3("foo", true) + +proc genericsProc4[T: int or float](x: T): T = x +discard genericsProc4(1.23) + +proc genericsProc5(x: static[int]) = discard x +genericsProc5(123) + +proc genericsProc6[T: SomeNumber](x: T) = discard x +genericsProc6(321) + +proc genericsProc7[T: SomeNumber](x: T): T = x +discard genericsProc7(321) + +proc genericsProc8[N: static[int]; T](x: array[N, T]): T = x[0] +discard genericsProc8([1, 2, 3]) diff --git a/tests/icnif/testcode/modtestliterals.nim b/tests/icnif/testcode/modtestliterals.nim new file mode 100644 index 0000000000000..bb63ceb265951 --- /dev/null +++ b/tests/icnif/testcode/modtestliterals.nim @@ -0,0 +1,36 @@ +var strlit = "test string" +var rstrlit = r"test\t raw" +var triplestrlit = """Triple +string +literal +""" +var charlit = 'a' +var intlit1 = 123456 +var intlit2 = -123456 +var int8litH = 127'i8 +var int8litL = -128'i8 +var int16litH = 32767'i16 +var int16litL = -32768'i16 +var int32litH = 2147483647'i32 +var int32litL = -2147483648'i32 +var int64litH = 9223372036854775807'i64 +var int64litL = -9223372036854775808'i64 + +var uintlitH = 18446744073709551615'u +var uint8litH = 255'u8 +var uint16litH = 65535'u16 +var uint32litH = 4294967295'u32 +var uint64litH = 18446744073709551615'u64 + +var floatlit = 1.25 +var floatlit2 = -1.25 +var float32lit = 1.25'f32 +var float64lit = 1.25'f64 +var floatZero = 0.0 +# Needs newer Nimony to save `-0.0` to NIF correclty +#var floatNegZero = -0.0 +var floatInf = Inf +var floatNaN = NaN +var floatNegInf = NegInf + +var nillit: ptr int = nil diff --git a/tests/icnif/testcode/modtestpragmas.nim b/tests/icnif/testcode/modtestpragmas.nim new file mode 100644 index 0000000000000..a9a64b6f398e2 --- /dev/null +++ b/tests/icnif/testcode/modtestpragmas.nim @@ -0,0 +1,48 @@ +var exportcTest {.exportc.}: int +var importcTest {.importc.}: int +var y* {.importc, header: "test.h".}: int +var EACCES {.importc, nodecl.}: cint +var volatileTest {.volatile.}: int + +const FooBar {.intdefine.}: int = 5 +echo FooBar + +{.passc: "-Wall -Werror".} +{.link: "myfile.o".} + +type + TestImportC {.importc.} = object + x: int + + TestImportC2 {.importc: "TestImportC2Name".} = object + x {.importc.}: int + y {.importc: "yyy".}: int + + TestBitfield = object + flag {.bitsize:1.}: cuint + + TestEnumWithSize* {.size: sizeof(uint32).} = enum + X, + Y, + Z + + sseType = object + sseData {.align(16).}: array[4, float32] + + TestUnionObj {.union.} = object + x: cint + y: cfloat + +const irr = "" +type + IrrlichtDeviceObj {.header: irr, + importcpp: "irr::IrrlichtDevice".} = object + +proc importCProc() {.importc.} +proc importCProc2(x: cint) {.importc: "import_c_proc_2".} +proc headerProc(): cint {.importc, header: "foo.h".} + +proc exportCProc() {.exportc.} + +{.pragma: pragmaPragmaTest, importc, header: "foo.h".} +proc pragmaPragmaTestProc() {.pragmaPragmaTest.} diff --git a/tests/icnif/testcode/modtestprocs.nim b/tests/icnif/testcode/modtestprocs.nim new file mode 100644 index 0000000000000..c872b8edefd69 --- /dev/null +++ b/tests/icnif/testcode/modtestprocs.nim @@ -0,0 +1,48 @@ +proc foo() = discard +foo() + +proc bar(x: int): int = x +discard bar(1) + +proc baz(x, y: int): int = + bar(x) + +proc baz(a: bool; b: string; c: int): float = 0.0 + +proc forwardDecl() +proc forwardDecl() = + foo() + +forwardDecl() + +proc forwardDecl2*(): int +proc forwardDecl2*(): int = bar(1) + +discard forwardDecl2() + +proc forwardDecl3(x, y: int): int +proc forwardDecl3(x, y: int): int = x + +discard forwardDecl3(3, 2) + +func func1(): int = 123 +discard func1() +func func2(x: int): int = x +func func3*(x, y: bool): bool = x + +proc withDefaultValue(x = 1) = discard +withDefaultValue() +withDefaultValue(2) +withDefaultValue(x = 3) + +proc withDefaultValue2(x = "foo"; y = true) = discard +withDefaultValue2() +withDefaultValue2("bar") +withDefaultValue2(x = "baz", y = false) + +proc varParam(x: var int) = x = 10 +var x = 0 +varParam(x) + +proc varRet(x: var int): var int = x +varRet(x) = 100 diff --git a/tests/icnif/testcode/modteststatements.nim b/tests/icnif/testcode/modteststatements.nim new file mode 100644 index 0000000000000..f82c258c02065 --- /dev/null +++ b/tests/icnif/testcode/modteststatements.nim @@ -0,0 +1,44 @@ +var stmtListExpr = (echo "foo"; 111) + +if false: + discard +elif false: + discard +else: + discard + +var caseExpr = true +case caseExpr +of true: + discard +else: + discard + +when sizeof(int) == 2: + echo "running on a 16 bit system!" +elif sizeof(int) == 4: + echo "running on a 32 bit system!" +elif sizeof(int) == 8: + echo "running on a 64 bit system!" +else: + echo "cannot happen!" + +while true: + break + +var x = 2 + +while x != 0: + if x == 2: + x = 0 + continue + else: + break + +block testblock: + while true: + if x > -1: + break testblock + +for i in 0 .. 3: + discard i diff --git a/tests/icnif/testcode/modtesttypesections.nim b/tests/icnif/testcode/modtesttypesections.nim new file mode 100644 index 0000000000000..d858b5af9a05a --- /dev/null +++ b/tests/icnif/testcode/modtesttypesections.nim @@ -0,0 +1,39 @@ +type + TestInt = int + TestEnum = enum + X + Y + TestDistinct = distinct int + + TestObject = object + x*: int + y: int + + TestObject2* = object + x: TestObject + + TestRefInt = ref int + TestPtrInt = ptr int + + TestRefObj = ref object + x: int + + TestPtrObj = ptr object + x: int + + TestEmptyObj = object + +var x: TestInt +var testEnum: TestEnum +var testEnum1 = X +var testDistinct: TestDistinct +var testObject: TestObject +var testObject2*: TestObject2 + +var testRefInt: TestRefInt = nil +var testRefInt2: ref int = nil +var testPtrInt: TestPtrInt = nil +var testPtrInt2: ptr int = nil +var testRefObj: TestRefObj = nil +var testPtrObj: TestPtrObj = nil +var testEmptyObj: TestEmptyObj diff --git a/tools/enumgen.nim b/tools/enumgen.nim new file mode 100644 index 0000000000000..fdcd132f92dad --- /dev/null +++ b/tools/enumgen.nim @@ -0,0 +1,247 @@ +## Generate effective NIF representation for `Enum` + +import ".." / compiler / [ast, options] + +import std / [syncio, assertions, strutils, tables] + +# We need to duplicate this type here as ast.nim's version of it does not work +# as it sets the string values explicitly breaking our logic... +type + TCallingConventionMirror = enum + ccNimCall + ccStdCall + ccCDecl + ccSafeCall + ccSysCall + ccInline + ccNoInline + ccFastCall + ccThisCall + ccClosure + ccNoConvention + ccMember + +const + SpecialCases = [ + ("nkCommand", "cmd"), + ("nkIfStmt", "if"), + ("nkError", "err"), + ("nkType", "onlytype"), + ("nkTypeSection", "type"), + ("tySequence", "seq"), + ("tyVar", "mut"), + ("tyProc", "proctype"), + ("tyUncheckedArray", "uarray"), + ("nkExprEqExpr", "vv"), + ("nkExprColonExpr", "kv"), + ("nkDerefExpr", "deref"), + ("nkReturnStmt", "ret"), + ("nkBreakStmt", "brk"), + ("nkStmtListExpr", "expr"), + ("nkEnumFieldDef", "efld"), + ("nkNilLit", "nil"), + ("ccNoConvention", "noconv"), + ("mExpr", "exprm"), + ("mStmt", "stmtm"), + ("mEqNimrodNode", "eqnimnode"), + ("mPNimrodNode", "nimnode"), + ("mNone", "nonem"), + ("mAsgn", "asgnm"), + ("mOf", "ofm"), + ("mAddr", "addrm"), + ("mType", "typem"), + ("mStatic", "staticm"), + ("mRange", "rangem"), + ("mVar", "varm"), + ("mInSet", "contains"), + ("mNil", "nilm"), + ("tyBuiltInTypeClass", "bconcept"), + ("tyUserTypeClass", "uconcept"), + ("tyUserTypeClassInst", "uconceptinst"), + ("tyCompositeTypeClass", "cconcept"), + ("tyGenericInvocation", "ginvoke"), + ("tyGenericBody", "gbody"), + ("tyGenericInst", "ginst"), + ("tyGenericParam", "gparam"), + ("nkStmtList", "stmts"), + ("nkDotExpr", "dot"), + ("nkBracketExpr", "at") + ] + SuffixesToReplace = [ + ("Section", ""), ("Branch", ""), ("Stmt", ""), ("I", ""), + ("Expr", "x"), ("Def", "") + ] + PrefixesToReplace = [ + ("Length", "len"), + ("SetLength", "setlen"), + ("Append", "add") + ] + AdditionalNodes = [ + "nf", # "node flag" + "tf", # "type flag" + "sf", # "sym flag" + "htype", # annotated with a hidden type + "missing" + ] + +proc genEnum[E](f: var File; enumName: string; known: var OrderedTable[string, bool]; prefixLen = 2) = + var mappingA = initOrderedTable[string, E]() + var cases = "" + for e in low(E)..high(E): + var es = $e + if es.startsWith("nkHidden"): + es = es.replace("nkHidden", "nkh") # prefix will be removed + else: + for (suffix, repl) in items SuffixesToReplace: + if es.len - prefixLen > suffix.len and es.endsWith(suffix): + es.setLen es.len - len(suffix) + es.add repl + break + for (suffix, repl) in items PrefixesToReplace: + if es.len - prefixLen > suffix.len and es.substr(prefixLen).startsWith(suffix): + es = es.substr(0, prefixLen-1) & repl & es.substr(prefixLen+suffix.len) + break + + let s = es.substr(prefixLen) + var done = false + for enu, key in items SpecialCases: + if $e == enu: + assert(not mappingA.hasKey(key)) + if known.hasKey(key): echo "conflict: ", key + known[key] = true + assert key.len > 0 + mappingA[key] = e + cases.add " of " & $e & ": " & escape(key) & "\n" + done = true + break + if not done: + let key = s.toLowerAscii + if not mappingA.hasKey(key): + assert key.len > 0, $e + if known.hasKey(key): echo "conflict: ", key + known[key] = true + mappingA[key] = e + cases.add " of " & $e & ": " & escape(key) & "\n" + done = true + if not done: + var d = 0 + while d < 10: + let key = s.toLowerAscii & $d + if not mappingA.hasKey(key): + assert key.len > 0 + mappingA[key] = e + cases.add " of " & $e & ": " & escape(key) & "\n" + done = true + break + inc d + if not done: + echo "Could not map: " & s + #echo mapping + var code = "" + code.add "proc toNifTag*(s: " & enumName & "): string =\n" + code.add " case s\n" + code.add cases + code.add "\n\n" + let procname = "parse" # & enumName.substr(1) + code.add "proc " & procname & "*(t: typedesc[" & enumName & "]; s: string): " & enumName & " =\n" + code.add " case s\n" + for (k, v) in pairs mappingA: + code.add " of " & escape(k) & ": " & $v & "\n" + code.add " else: " & $low(E) & "\n\n\n" + f.write code + +proc genEnum[E](f: var File; enumName: string; prefixLen = 2) = + var known = initOrderedTable[string, bool]() + genEnum[E](f, enumName, known, prefixLen) + + +proc genFlags[E](f: var File; enumName: string; prefixLen = 2) = + var mappingA = initOrderedTable[string, E]() + var mappingB = initOrderedTable[string, E]() + var cases = "" + for e in low(E)..high(E): + let s = ($e).substr(prefixLen) + var done = false + for c in s: + if c in {'A'..'Z'}: + let key = $c.toLowerAscii + if not mappingA.hasKey(key): + mappingA[key] = e + cases.add " of " & $e & ": dest.add " & escape(key) & "\n" + done = true + break + if not done: + var d = 0 + while d < 10: + let key = $s[0].toLowerAscii & $d + if not mappingB.hasKey(key): + mappingB[key] = e + cases.add " of " & $e & ": dest.add " & escape(key) & "\n" + done = true + break + inc d + if not done: + quit "Could not map: " & s + #echo mapping + var code = "" + code.add "proc genFlags*(s: set[" & enumName & "]; dest: var string) =\n" + code.add " for e in s:\n" + code.add " case e\n" + code.add cases + code.add "\n\n" + code.add "proc parse*(t: typedesc[" & enumName & "]; s: string): set[" & enumName & "] =\n" + code.add " result = {}\n" + code.add " var i = 0\n" + code.add " while i < s.len:\n" + code.add " case s[i]\n" + for c in 'a'..'z': + var letterFound = false + var digitsFound = 0 + for d in '0'..'9': + if mappingB.hasKey($c & $d): + if not letterFound: + letterFound = true + code.add " of '" & c & "':\n" + if digitsFound == 0: + code.add " if" + else: + code.add " elif" + inc digitsFound + code.add " i+1 < s.len and s[i+1] == '" & d & "':\n" + code.add " result.incl " & $mappingB[$c & $d] & "\n" + code.add " inc i\n" + + if mappingA.hasKey($c): + if digitsFound == 0: + code.add " of '" & c & "': " + else: + code.add " else: " + code.add "result.incl " & $mappingA[$c] & "\n" + + code.add " else: discard\n" + code.add " inc i\n\n" + f.write code + +var f = open("compiler/icnif/enum2nif.nim", fmWrite) +f.write "# Generated by tools/enumgen.nim. DO NOT EDIT!\n\n" +f.write "import \"..\" / [ast, options]\n\n" +# use the same mapping for TNodeKind and TMagic so that we can detect conflicts! +var nodeTags = initOrderedTable[string, bool]() +for a in AdditionalNodes: + nodeTags[a] = true + +genEnum[TNodeKind](f, "TNodeKind", nodeTags) +genEnum[TSymKind](f, "TSymKind") +genEnum[TTypeKind](f, "TTypeKind") +genEnum[TLocKind](f, "TLocKind", 3) +genEnum[TCallingConventionMirror](f, "TCallingConvention", 2) +genEnum[TMagic](f, "TMagic", nodeTags, 1) +genEnum[TStorageLoc](f, "TStorageLoc") +genEnum[TLibKind](f, "TLibKind") +genFlags[TSymFlag](f, "TSymFlag") +genFlags[TNodeFlag](f, "TNodeFlag") +genFlags[TTypeFlag](f, "TTypeFlag") +genFlags[TLocFlag](f, "TLocFlag") +genFlags[TOption](f, "TOption", 3) + +f.close()