From 07819dfb4be181468d4f99405b4f9dfc1f8dbc02 Mon Sep 17 00:00:00 2001 From: araq Date: Sat, 13 Dec 2025 15:02:52 +0100 Subject: [PATCH] progress --- compiler/ast2nif.nim | 21 +-- compiler/astdef.nim | 14 ++ compiler/modulegraphs.nim | 4 + compiler/typekeys.nim | 269 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 20 deletions(-) create mode 100644 compiler/typekeys.nim diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index 38120a1554..2eb23d03fa 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -19,32 +19,13 @@ import "../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos, nifindexes, nifreader] import "../dist/nimony/src/gear2" / modnames import "../dist/nimony/src/models" / nifindex_tags - +import typekeys import ic / [enum2nif] # Re-export types needed for hook, converter, and method handling export nifindexes.AttachedOp, nifindexes.HookIndexEntry, nifindexes.HooksPerType export nifindexes.ClassIndexEntry, nifindexes.MethodIndexEntry -# -------------- Module name handling -------------------------------------------- - -proc cachedModuleSuffix*(config: ConfigRef; fileIdx: FileIndex): string = - ## Gets or computes the module suffix for a FileIndex. - ## For NIF modules, the suffix is already stored in the file info. - ## For source files, computes it from the path. - let fullPath = toFullPath(config, fileIdx) - if fileInfoKind(config, fileIdx) == fikNifModule: - result = fullPath # Already a suffix - else: - result = moduleSuffix(fullPath, cast[seq[string]](config.searchPaths)) - -proc modname(module: int; conf: ConfigRef): string = - cachedModuleSuffix(conf, module.FileIndex) - -proc modname(module: PSym; conf: ConfigRef): string = - assert module.kindImpl == skModule - modname(module.positionImpl, conf) - proc toAttachedOp*(op: TTypeAttachedOp): AttachedOp = ## Maps Nim compiler's TTypeAttachedOp to nimony's AttachedOp. diff --git a/compiler/astdef.nim b/compiler/astdef.nim index 2aefc7659f..d0c4586681 100644 --- a/compiler/astdef.nim +++ b/compiler/astdef.nim @@ -990,6 +990,20 @@ proc newStrNode*(strVal: string; info: TLineInfo): PNode = result = newNodeI(nkStrLit, info) result.strVal = strVal +# Hooks, converters, method dispatchers and enum-to-string generated procs need special +# handling for IC, they end up in IC indexes etc. Thus we "log" them in the module graph +# and to pass them around to the NIF writer. This is not very elegant but it works. + +type + LogEntryKind* = enum + HookEntry, ConverterEntry, MethodEntry, EnumToStrEntry + LogEntry* = object + kind*: LogEntryKind + op*: TTypeAttachedOp + typ*: PType + sym*: PSym + + proc forcePartial*(s: PSym) = ## Resets all impl-fields to their default values and sets state to Partial. ## This is useful for creating a stub symbol that can be lazily loaded later. diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index b52ee9f4f0..fdc9da184b 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -79,6 +79,7 @@ type typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId. procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId. attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc. + opsLog*: seq[LogEntry] methodsPerGenericType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual,member and ctor so far). initializersPerType*: Table[ItemId, PNode] # Type ID, AST call to the default ctor (c++ only) @@ -367,6 +368,7 @@ proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym = proc setAttachedOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttachedOp; value: PSym) = ## we also need to record this to the packed module. g.attachedOps[op][t.itemId] = LazySym(sym: value) + g.opsLog.add LogEntry(kind: HookEntry, op: op, typ: t, sym: value) proc setAttachedOp*(g: ModuleGraph; module: int; typeId: ItemId; op: TTypeAttachedOp; value: PSym) = ## Overload that takes ItemId directly, useful for registering hooks from NIF index. @@ -414,6 +416,7 @@ proc getToStringProc*(g: ModuleGraph; t: PType): PSym = proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) = g.enumToStringProcs[t.itemId] = LazySym(sym: value) + g.opsLog.add LogEntry(kind: EnumToStrEntry, typ: t, sym: value) iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) = if g.methodsPerGenericType.contains(t.itemId): @@ -422,6 +425,7 @@ iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) = proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) = g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m)) + g.opsLog.add LogEntry(kind: MethodEntry, typ: t, sym: m) proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool = let op = getAttachedOp(g, t, attachedAsgn) diff --git a/compiler/typekeys.nim b/compiler/typekeys.nim new file mode 100644 index 0000000000..a03f7ffebd --- /dev/null +++ b/compiler/typekeys.nim @@ -0,0 +1,269 @@ +# +# +# The Nim Compiler +# (c) Copyright 2025 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Based on sighashes.nim but works on astdef directly as we need it in ast2nif.nim. +## Also produces more readable names thanks to treemangler. + +import std/assertions + +import "../dist/nimony/src/lib" / [treemangler] +import "../dist/nimony/src/gear2" / modnames + +import astdef, idents, options, lineinfos, msgs +import ic / [enum2nif] + +# -------------- Module name handling -------------------------------------------- + +proc cachedModuleSuffix*(config: ConfigRef; fileIdx: FileIndex): string = + ## Gets or computes the module suffix for a FileIndex. + ## For NIF modules, the suffix is already stored in the file info. + ## For source files, computes it from the path. + let fullPath = toFullPath(config, fileIdx) + if fileInfoKind(config, fileIdx) == fikNifModule: + result = fullPath # Already a suffix + else: + result = moduleSuffix(fullPath, cast[seq[string]](config.searchPaths)) + +proc modname*(module: int; conf: ConfigRef): string = + cachedModuleSuffix(conf, module.FileIndex) + +proc modname*(module: PSym; conf: ConfigRef): string = + assert module.kindImpl == skModule + modname(module.positionImpl, conf) + +# --------------- Type key generation -------------------------------------------- + +type + ConsiderFlag = enum + CoProc + CoType + CoIgnoreRange + CoConsiderOwned + CoDistinct + CoHashTypeInsideNode + +proc typeKey(c: var Mangler, t: PType; flags: set[ConsiderFlag]; conf: ConfigRef) +proc symKey(c: var Mangler, s: PSym; conf: ConfigRef) = + if sfAnon in s.flagsImpl or s.kindImpl == skGenericParam: + c.addIdent("´anon") + else: + var name = s.name.s + name.add '.' + name.addInt s.disamb + + let it = + if s.kindImpl == skModule: + s + elif s.kindImpl in skProcKinds and sfFromGeneric in s.flagsImpl and s.ownerFieldImpl.kindImpl != skModule: + s.ownerFieldImpl.ownerFieldImpl + else: + s.ownerFieldImpl + if it.kindImpl == skModule: + name.add '.' + name.add modname(it, conf) + c.addSymbol(name) + +proc treeKey(c: var Mangler, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) = + if n == nil: + c.addEmpty() + return + + let k = n.kind + case k + of nkEmpty, nkNilLit, nkType: discard + of nkIdent: + c.addIdent(n.ident.s) + of nkSym: + symKey(c, n.sym, conf) + if CoHashTypeInsideNode in flags and n.sym.typImpl != nil: + typeKey(c, n.sym.typImpl, flags, conf) + of nkCharLit..nkUInt64Lit: + let v = n.intVal + c.addIntLit v + of nkFloatLit..nkFloat64Lit: + let v = n.floatVal + c.addFloatLit v + of nkStrLit..nkTripleStrLit: + c.addStrLit n.strVal + else: + withTree c, toNifTag(k): + for i in 0.. 0: + c.typeKey(t.sonsImpl[0], flags, conf) + + c.addIdent toNifTag(t.callConvImpl) + if tfVarargs in t.flagsImpl: c.addIdent "´varargs" + of tyArray: + withTree c, toNifTag(t.kind): + c.typeKey(t.sonsImpl[^1], flags-{CoIgnoreRange}, conf) + c.typeKey(t.sonsImpl[0], flags-{CoIgnoreRange}, conf) + else: + withTree c, toNifTag(t.kind): + for i in 1..