66
77# # Nimony index generator.
88
9- import std / [os, assertions]
9+ import std / [os, assertions, sets, tables ]
1010include " .." / lib / nifprelude
1111import " .." / lib / [nifindexes, symparser]
12- import decls, nimony_model, programs
12+ import decls, nimony_model, programs, vtables_frontend, semos
13+ import " .." / models / nifindex_tags
1314
1415proc getAttachedOp (symId: SymId , attackedOp: var AttachedOp ): bool =
1516 var name = pool.syms[symId]
@@ -26,6 +27,54 @@ proc getAttachedOp(symId: SymId, attackedOp: var AttachedOp): bool =
2627
2728 return true
2829
30+ proc indexMethod (classIndexMap: var seq [ClassIndexEntry ]; symId: SymId ; routine: Routine ) =
31+ var param = routine.params
32+ if param.substructureKind == ParamsU :
33+ inc param
34+ if param.substructureKind == ParamU :
35+ var typ = param.takeLocal (SkipFinalParRi ).typ
36+ # should use `getClass` proc in `nimony/typeprops.nim`,
37+ # but current `tryLoadSym` doesn't work with Nim v2 NIF.
38+ # let root = typ.getClass()
39+ if typ.typeKind == RefT :
40+ inc typ
41+ if typ.kind == Symbol :
42+ let root = typ.symId
43+ var methodName = pool.syms[symId]
44+ extractBasename methodName
45+ let signature = pool.strings.getOrIncl (methodKey (methodName, param))
46+ if routine.typevars.typeKind != InvokeT :
47+ # don't register instances
48+ for i in 0 ..< classIndexMap.len:
49+ if classIndexMap[i].cls == root:
50+ classIndexMap[i].methods.add MethodIndexEntry (fn:symId, signature: signature)
51+ continue
52+ classIndexMap.add ClassIndexEntry (cls: root, methods: @ [MethodIndexEntry (fn: symId, signature: signature)])
53+
54+ proc buildIndexExports (exports: Table [string , HashSet [SymId ]]; infile: string ): TokenBuf =
55+ result = default (TokenBuf )
56+ let (dir, _, ext) = splitModulePath infile
57+ if exports.len != 0 :
58+ result = createTokenBuf (32 )
59+ for suffix, syms in exports:
60+ # open NIF file to get the path of source file of the module from the line info.
61+ let modPath = dir / (suffix & ext)
62+ var stream = nifstreams.open (modPath)
63+ discard processDirectives (stream.r)
64+ discard stream.next # first stmts node doesn't have line info.
65+ let t = stream.next
66+ let fileId = pool.man.getFileId (t.info)
67+ assert fileId.isValid
68+ stream.close
69+ let path = pool.files[fileId].toAbsolutePath
70+ result .addParLe (TagId (FromexportIdx ))
71+ result .addStrLit path
72+ for s in syms:
73+ var isGlobal = false
74+ let ident = extractBasename (pool.syms[s], isGlobal)
75+ result .addIdent (ident)
76+ result .addParRi ()
77+
2978proc indexFromNif * (infile: string ) =
3079 # # Extract index from `infile` Nif file and write it to `*.idx.nif` file.
3180 # #
@@ -40,35 +89,63 @@ proc indexFromNif*(infile: string) =
4089 var hookIndexLog = default array [AttachedOp , seq [HookIndexEntry ]]
4190 var converterIndexMap = default seq [(SymId , SymId )]
4291 var classIndexMap = default seq [ClassIndexEntry ]
92+ var exports = default Table [string , HashSet [SymId ]] # Module suffix -> symbols to export in the module
4393
4494 assert n.stmtKind == StmtsS
4595 inc n
4696 while n.kind != ParRi :
4797 if n.kind == ParLe :
4898 case n.stmtKind:
4999 of ProcS , FuncS , ConverterS , MethodS :
100+ let kind = n.stmtKind
50101 let routine = takeRoutine (n, SkipFinalParRi )
51102 let symId = routine.name.symId
52- var op = default AttachedOp
53- if getAttachedOp (symId, op):
54- var param = routine.params
55- assert param.substructureKind == ParamsU
56- inc param
57- assert param.substructureKind == ParamU
58- let typ = takeLocal (param, SkipExclBody ).typ.skipModifier
59- # this assertion fails when got generics proc as generics parameters are not supported yet.
60- if typ.kind == Symbol :
61- let obj = typ.symId
62- let isGeneric = routine.typevars.substructureKind == TypevarsU
63- hookIndexLog[op].add HookIndexEntry (typ: obj, hook: symId, isGeneric: isGeneric)
103+ if kind == ConverterS :
104+ if routine.exported.kind != DotToken and
105+ routine.typevars.typeKind != InvokeT :
106+ # don't register instances and not exported ones
107+ let root = routine.retType.skipModifier.symId
108+ converterIndexMap.add ((root, symId))
109+ elif kind == MethodS :
110+ indexMethod (classIndexMap, symId, routine)
111+ else :
112+ var op = default AttachedOp
113+ if getAttachedOp (symId, op):
114+ var param = routine.params
115+ assert param.substructureKind == ParamsU
116+ inc param
117+ assert param.substructureKind == ParamU
118+ let typ = takeLocal (param, SkipExclBody ).typ.skipModifier
119+ # this doesn't work with generics proc as generics parameters are not supported yet.
120+ if typ.kind == Symbol :
121+ let obj = typ.symId
122+ let isGeneric = routine.typevars.substructureKind == TypevarsU
123+ hookIndexLog[op].add HookIndexEntry (typ: obj, hook: symId, isGeneric: isGeneric)
124+ of ExportS :
125+ inc n
126+ # .nif files generated by `nim nif foo.nim` has `(exports symbol1, symbol2, ...)`, but doesn't have other kinds of export node.
127+ # export statement like `export modname` becomes `(exports symbols1, symbols2, ...)` where symbols1, symbols2, ... are exported symbols in the module.
128+ # So they are indexed only with `FromexportIdx`.
129+ while n.kind != ParRi :
130+ assert n.kind == Symbol
131+ let sym = n.symId
132+ let name = pool.syms[sym]
133+ let suffix = extractModule (name)
134+ assert suffix != " "
135+ exports.mgetOrPut (suffix).incl sym
136+ inc n
137+ inc n
64138 else :
65139 skip n
66140 else :
67141 skip n
68142
69143 endRead buf
70144
145+ var exportBuf = buildIndexExports (exports, infile)
146+
71147 createIndex infile, root, true ,
72148 IndexSections (hooks: move hookIndexLog,
73149 converters: move converterIndexMap,
74- classes: move classIndexMap)
150+ classes: move classIndexMap,
151+ exportBuf: exportBuf)
0 commit comments