Skip to content

Commit

Permalink
[FEATURE] Store wrapped type mappings
Browse files Browse the repository at this point in the history
Partially implement #14 -
allow `type_import.json` to be created when wrapgen script is executed.

- ADDED ::
  - Properly implement anonymous type generation
  - Write and read dependency type import mappings
  • Loading branch information
haxscramper committed Oct 13, 2021
1 parent b434c57 commit 7b0fb9b
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 81 deletions.
3 changes: 3 additions & 0 deletions src/hcparse.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ export
hc_visitors,
hc_impls,
hc_parsefront

import hmisc/core/debug
export debug
75 changes: 49 additions & 26 deletions src/hcparse/hc_codegen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,32 @@ func toNNode*[N](lib: CxxLibImport, asImport: bool): N =


func toNNode*[N](libs: seq[CxxLibImport], asImport: bool): N =
let libs = sortedByIt(libs, it)
if asImport:
result = newNTree[N](nnkImportStmt)
for lib in libs:
result.add lib.getPathNoExt().mapIt(newNIdent[N](it)).foldl(newXCall("/", a, b)):
if libs.len == 0:
result = newEmptyNNode[N]()

else:
result = newNTree[N](nnkExportStmt)
for lib in libs:
result.add newNIdent[N](lib.getFilename())
let libs = sortedByIt(libs, it)
if asImport:
result = newNTree[N](nnkImportStmt)
for lib in libs:
result.add lib.getPathNoExt().mapIt(newNIdent[N](it)).foldl(newXCall("/", a, b)):

else:
result = newNTree[N](nnkExportStmt)
for lib in libs:
result.add newNIdent[N](lib.getFilename())



proc toNNode*[N](
arg: CxxArg, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): NIdentDefs[N]


proc toNNode*[N](
t: CxxTypeUse, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): NType[N] =

case t.kind:
Expand Down Expand Up @@ -94,19 +99,25 @@ proc toNNode*[N](
toNNode[N](t.wrapped, conf, anon)])])

of ctkAnonObject:
let anon = toNNode[N](t.objDef, conf, anon)
result = newNNType[N]("ANON_OBJECT")
var def = t.objDef
def.decl.name = t.objParent & t.objUser
let gen = toNNode[N](def, conf, anon)
anon.add gen
result = newNNType[N](def.nimName)

of ctkAnonEnum:
let anon = toNNode[N](t.enumDef, conf)
result = newNNType[N]("ANON_ENUM")
var def = t.enumDef
def.decl.name = t.enumParent & t.enumUser
let gen = toNNode[N](def, conf)
anon.add gen
result = newNNType[N](def.nimName)

else:
raise newImplementKindError(t)

proc toNNode*[N](
t: CxxTypeDecl, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): NType[N] =

newNType[N](
Expand All @@ -115,7 +126,7 @@ proc toNNode*[N](

proc toNNode*[N](
arg: CxxArg, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): NIdentDefs[N] =

newNIdentDefs[N](
Expand All @@ -130,7 +141,7 @@ proc toNimComment*(com: seq[CxxComment]): string =

proc toNNode*[N](
field: CxxField, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): ObjectField[N] =

result = ObjectField[N](
Expand Down Expand Up @@ -197,7 +208,7 @@ proc toNNode*[N](header: CxxBind, conf: CodegenConf, name: string): seq[N] =

proc toNNode*[N](
def: CxxAlias, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): tuple[alias: AliasDecl[N], extra: seq[NimDecl[N]]] =

result.alias = newAliasDecl(
Expand Down Expand Up @@ -226,7 +237,7 @@ proc toNNode*[N](
proc toNNode*[N](
def: CxxProc,
conf: CodegenConf,
anon: var seq[NimTypeDecl[N]],
anon: var seq[NimDecl[N]],
onConstructor: CxxTypeKind = ctkIdent
): ProcDecl[N] =

Expand Down Expand Up @@ -259,12 +270,14 @@ proc toNNode*[N](

proc toNNode*[N](
obj: CxxObject, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): seq[NimDecl[N]] =

var res = newObjectDecl[N](obj.nimName)
res.docComment = obj.docComment.toNimComment()
res.addPragma("bycopy")
if obj.kind == cokUnion:
res.addPragma("union")
# res.addPragma("inheritable")
# res.addPragma("byref")

Expand Down Expand Up @@ -313,7 +326,7 @@ proc toNNode*[N](en: CxxEnum, conf: CodegenConf): EnumDecl[N] =

proc toNNode*[N](
entry: CxxEntry, conf: CodegenConf,
anon: var seq[NimTypeDecl[N]]
anon: var seq[NimDecl[N]]
): seq[NimDecl[N]] =

case entry.kind:
Expand Down Expand Up @@ -350,9 +363,12 @@ proc toNNode*[N](
raise newImplementKindError(entry)

proc toNNode*[N](entries: seq[CxxEntry], conf: CodegenConf): seq[NimDecl[N]] =
var types: seq[NimTypeDecl[N]]
var other: seq[NimDecl[N]]
var visited: HashSet[CxxNamePair]
var
types: seq[NimTypeDecl[N]]
other: seq[NimDecl[N]]
anon: seq[NimDecl[N]]
visited: HashSet[CxxNamePair]

for item in entries:
if item of cekEmpty:
discard
Expand All @@ -361,13 +377,20 @@ proc toNNode*[N](entries: seq[CxxEntry], conf: CodegenConf): seq[NimDecl[N]] =
if item of cekForward:
visited.incl item.name

for conv in toNNode[N](item, conf, types):
if conv of {nekObjectDecl, nekAliasDecl, nekEnumDecl}:
for conv in toNNode[N](item, conf, anon):
if conv of nekTypeKinds:
types.add toNimTypeDecl(conv)

else:
other.add conv

for conv in anon:
if conv of nekTypeKinds:
types.add toNimTypeDecl(conv)

else:
other.add conv

result.add toNimDecl(sortedByIt(types, it.getName()))
result.add other

Expand Down
10 changes: 4 additions & 6 deletions src/hcparse/hc_grouping.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ type
inProcs: UsedSet
inTypes: UsedSet

func mgetOrDefault*[K, V](table: var Table[K, V], key: K): var V =
if key notin table:
table[key] = default(V)

return table[key]

proc registerUse*(ctype: CxxTypeUse, used: var UsedSet) =
## Register type and all it's inner used types (proctype arguments,
## generic parameters etc) in the used set.
Expand All @@ -52,6 +46,10 @@ proc registerUse*(ctype: CxxTypeUse, used: var UsedSet) =
if decl.isSome():
used.cursors.mgetOrDefault(decl.get()).incl use

elif use.hasExternalImport():
let lib = use.getExternalImport()
used.libs.mgetOrDefault(lib).incl use


proc registerUsedTypes*(genProc: CxxProc, used: var UsedSet) =
## Register return type and all argument's types in used set
Expand Down
75 changes: 62 additions & 13 deletions src/hcparse/hc_parsefront.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import
std/[sequtils, strformat, bitops, strutils, tables]

import
pkg/[jsony]

import
./cxtypes,
./hc_types,
Expand Down Expand Up @@ -202,7 +205,7 @@ proc wrapViaTs*(
): CxxFile =
assertRef conf.typeStore
let relative = file.string.dropPrefix(libRoot.string)
let lib = cxxLibImport(conf.libName, relative.split("/"))
let lib = cxxLibImport(conf.libName, relative.split("/").filterIt(it.len > 0))
wrapViaTs(file.readFile(), conf, lib, some file).cxxFile(lib)

proc wrapViaTsWave*(
Expand Down Expand Up @@ -281,20 +284,49 @@ proc expandViaWave*(
if not exists(resFile) or force:
resFile.writeFile(expandViaWave(file, cache, conf))


const importMapFile* = "type_import.json"

proc getImportMap*(files: seq[CxxFile]): CxxTypeImportMap =
for file in files:
for entry in file.entries:
if entry of {cekObject, cekAlias, cekEnum}:
result[CxxNameString(entry.cxxName.scopes.join("::"))] = file.savePath

func `$`*(s: CxxNameString): string = s.string

proc readImportMap*(store: var CxxTypeStore, file: AbsFile) =
assertExists(file)
let j = readFile(file)
let map = j.fromJson(Table[string, CxxLibImport])
for key, val in map:
store.importDecls[cxxName(key.split("::"))] = val

proc readImportMap*(store: var CxxTypeStore, dirs: seq[AbsDir]) =
for dir in dirs:
for file in walkDir(dir, AbsFile, exts = @["json"]):
if file.name() == "type_import":
readImportMap(store, file)
break



proc initCSharedLibFixConf*(
lib: string,
packageName: string,
isIcpp: bool,
libRoot: AbsDir,
expandMap: CxxExpandMap,
configFiles: seq[string] = @["lib" & lib & "_config"],
base: CxxFixConf = baseFixConf,
base: CxxFixConf = baseFixConf,
libIncludePrefix: string = lib,
nameStyle: IdentStyle = idsSnake
nameStyle: IdentStyle = idsSnake,
depDirs: seq[AbsDir] = @[]
): CxxFixConf =

var fixConf = base
fixConf.isIcpp = isIcpp
fixConf.libName = lib
fixConf.libName = packageName

fixConf.onGetBind():
case entry.kind:
Expand All @@ -315,6 +347,8 @@ proc initCSharedLibFixConf*(
cache.fixContextedName(name, fixConf.libNameStyle)

fixConf.typeStore = newTypeStore()
fixConf.typeStore.readImportMap(depDirs)

return fixConf

proc wrapViaTs*(
Expand All @@ -331,28 +365,43 @@ proc wrapViaTs*(
err.msg.add "\nException raised while processing file " & file.string
raise err

type
GenFiles = object
genNim*: seq[AbsFile]
genTypeMap*: Option[AbsFile]

proc writeFiles*(
outDir: AbsDir,
files: seq[CxxFile],
codegenConf: CodegenConf
): seq[AbsFile] =
codegenConf: CodegenConf,
extraTypes: seq[(CxxName, CxxLibImport)] = @[]
): GenFiles =

let mapFile = outDir /. importMapFile
result.genTypeMap = some mapFile
var map = getImportMap(files)
for (ctype, cimport) in extraTypes:
map[CxxNameString(ctype.scopes.join("::"))] = cimport

writeFile(mapFile, toJson(map))

let group = regroupFiles(files)

for fix in group:
let res = outDir / fix.getFile().withExt("nim")
res.writeFile(toNNode[PNode](fix, codegenConf).toPString())
result.add res
result.genNim.add res


proc wrapCSharedLibViaTsWave*(
inDir, tmpDir, outDir: AbsDir,
libName: string,
libName, packageName: string,
ignoreIn: seq[string] = @[],
persistentOut: seq[string] = @[
"hcparse_generate", "lib" & libName & "_config"],
): seq[AbsFile] =
depDirs: seq[AbsDir] = @[],
extraTypes: seq[(CxxName, CxxLibImport)] = @[]
): GenFiles =
var expandMap = expandViaWave(
listFiles(inDir, ignoreNames = ignoreIn),
tmpDir, baseCParseConf
Expand All @@ -362,15 +411,15 @@ proc wrapCSharedLibViaTsWave*(

let
fixConf = initCSharedLibFixConf(
libName, false, inDir, expandMap)
libName, packageName, false, inDir, expandMap, depDirs = depDirs)

resultWrapped = tmpDir.wrapViaTs(fixConf)
resultGrouped = writeFiles(outDir, resultWrapped, cCodegenConf)
resultGrouped = writeFiles(outDir, resultWrapped, cCodegenConf, extraTypes = extraTypes)

return resultGrouped

proc validateGenerated*(files: seq[AbsFile]) =
for file in items(files):
proc validateGenerated*(files: GenFiles) =
for file in items(files.genNim):
try:
execShell shellCmd(nim, check, errormax = 3, $file)

Expand Down
Loading

0 comments on commit 7b0fb9b

Please sign in to comment.