diff options
| author | Ganesh Viswanathan <dev@genotrance.com> | 2019-10-21 21:49:38 -0500 |
|---|---|---|
| committer | Ganesh Viswanathan <dev@genotrance.com> | 2019-10-21 21:49:38 -0500 |
| commit | 3ae716fff6e4b79257a6727eca794850a84f19b8 (patch) | |
| tree | cd5483a5e3beb4400609973c1ce3822cb8a26275 | |
| parent | d3b558b291be1d6dd0885de2ef154b70ed2cfbac (diff) | |
| parent | 5f9a59fcc676170bf465d95971e700ca16959385 (diff) | |
| download | nimterop-3ae716fff6e4b79257a6727eca794850a84f19b8.tar.gz nimterop-3ae716fff6e4b79257a6727eca794850a84f19b8.zip | |
Merge branch 'override'
| -rw-r--r-- | nimterop/ast.nim | 5 | ||||
| -rw-r--r-- | nimterop/cimport.nim | 108 | ||||
| -rw-r--r-- | nimterop/getters.nim | 40 | ||||
| -rw-r--r-- | nimterop/globals.nim | 5 | ||||
| -rw-r--r-- | nimterop/grammar.nim | 70 | ||||
| -rw-r--r-- | nimterop/plugin.nim | 17 | ||||
| -rw-r--r-- | tests/include/test.c | 8 | ||||
| -rw-r--r-- | tests/include/test.h | 25 | ||||
| -rw-r--r-- | tests/tmath.nim | 2 | ||||
| -rw-r--r-- | tests/tnimterop_c.nim | 41 | ||||
| -rw-r--r-- | tests/zlib.nim | 5 |
11 files changed, 276 insertions, 50 deletions
diff --git a/nimterop/ast.nim b/nimterop/ast.nim index c4294dc..1617ea4 100644 --- a/nimterop/ast.nim +++ b/nimterop/ast.nim @@ -1,4 +1,4 @@ -import os, sets, strformat, strutils, tables, times +import macros, os, sets, strformat, strutils, tables, times import regex @@ -187,6 +187,7 @@ proc printNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable if nimState.enumStr.nBl: echo &"{nimState.enumStr}\n" + nimState.constStr = nimState.getOverrideFinal(nskConst) & nimState.constStr if nimState.constStr.nBl: echo &"const{nimState.constStr}\n" @@ -195,9 +196,11 @@ proc printNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable {{.pragma: {nimState.impShort}C, {nimState.impShort}, cdecl{nimState.getDynlib()}.}} """ + nimState.typeStr = nimState.getOverrideFinal(nskType) & nimState.typeStr if nimState.typeStr.nBl: echo &"type{nimState.typeStr}\n" + nimState.procStr = nimState.getOverrideFinal(nskProc) & nimState.procStr if nimState.procStr.nBl: echo &"{nimState.procStr}\n" diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim index cea859a..87d5ba6 100644 --- a/nimterop/cimport.nim +++ b/nimterop/cimport.nim @@ -172,8 +172,8 @@ proc getToast(fullpath: string, recurse: bool = false, dynlib: string = "", macro cOverride*(body): untyped = ## When the wrapper code generated by nimterop is missing certain symbols or not ## accurate, it may be required to hand wrap them. Define them in a - ## `cOverride() <cimport.html#cOverride.m>`_ macro block so that Nimterop no - ## longer defines these symbols. + ## `cOverride() <cimport.html#cOverride.m>`_ macro block so that Nimterop uses + ## these definitions instead. ## ## For example: ## @@ -195,28 +195,70 @@ macro cOverride*(body): untyped = ## proc svGetCallerInfo(fileName: var cstring; lineNumber: var cint) ## ## Using the `cOverride() <cimport.html#cOverride.m>`_ block, nimterop - ## can be instructed to skip over `svGetCallerInfo()`. This works for procs, - ## consts and types. + ## can be instructed to use this definition of `svGetCallerInfo()` instead. + ## This works for procs, consts and types. ## ## `cOverride() <cimport.html#cOverride.m>`_ only affects calls to ## `cImport() <cimport.html#cImport.m%2C%2Cstring%2Cstring%2Cstring>`_ that follow it. - proc recFindIdent(node: NimNode): seq[string] = - if node.kind != nnkIdent: - for child in node: - result.add recFindIdent(child) - if result.len != 0 and node.kind notin [nnkTypeSection, nnkConstSection]: - break - elif $node != "*": - result.add $node + iterator findOverrides(node: NimNode): tuple[name, override: string, kind: NimNodeKind] = + for child in node: + case child.kind + of nnkTypeSection, nnkConstSection: + # Types, const + for inst in child: + let name = + if inst[0].kind == nnkPragmaExpr: + $inst[0][0] + else: + $inst[0] + + yield (name.strip(chars={'*'}), inst.repr, child.kind) + of nnkProcDef: + let + name = $child[0] + + yield (name.strip(chars={'*'}), child.repr, child.kind) + else: + discard - for sym in body: - gStateCT.symOverride.add recFindIdent(sym) + if gStateCT.overrides.len == 0: + gStateCT.overrides = """ +import sets, tables - result = body +proc onSymbolOverride*(sym: var Symbol) {.exportc, dynlib.} = +""" - if gStateCT.debug: - echo "# Overriding " & gStateCT.symOverride.join(" ") + # If cPlugin called before cOverride + if gStateCT.pluginSourcePath.len != 0: + gStateCT.pluginSourcePath = "" + + var + names: seq[string] + for name, override, kind in body.findOverrides(): + let + typ = + case kind + of nnkTypeSection: "nskType" + of nnkConstSection: "nskConst" + of nnkProcDef: "nskProc" + else: "" + + gStateCT.overrides &= &""" + if sym.name == "{name}" and sym.kind == {typ} and "{name}" in cOverrides["{typ}"]: + sym.override = """ & "\"\"\"" & override & "\"\"\"\n" + + gStateCT.overrides &= &" cOverrides[\"{typ}\"].excl \"{name}\"\n" + + gStateCT.overrides = gStateCT.overrides.replace("proc onSymbolOverride", + &"cOverrides[\"{typ}\"].incl \"{name}\"\nproc onSymbolOverride") + + names.add name + + gStateCT.symOverride.add name + + if gStateCT.debug and names.len != 0: + echo "# Overriding " & names.join(" ") proc cSkipSymbol*(skips: seq[string]) {.compileTime.} = ## Similar to `cOverride() <cimport.html#cOverride.m>`_, this macro allows @@ -228,6 +270,22 @@ proc cSkipSymbol*(skips: seq[string]) {.compileTime.} = static: cSkipSymbol @["proc1", "Type2"] gStateCT.symOverride.add skips +proc cPluginHelper(body: string) = + gStateCT.pluginSource = body + + let + data = "import macros, nimterop/plugin\n\n" & body & gStateCT.overrides + hash = data.hash().abs() + path = getProjectCacheDir("cPlugins", forceClean = false) / "nimterop_" & $hash & ".nim" + + if not fileExists(path) or gStateCT.nocache or compileOption("forceBuild"): + mkDir(path.parentDir()) + writeFile(path, data) + + doAssert fileExists(path), "Unable to write plugin file: " & path + + gStateCT.pluginSourcePath = path + macro cPlugin*(body): untyped = ## When `cOverride() <cimport.html#cOverride.m>`_ and ## `cSkipSymbol() <cimport.html#cSkipSymbol%2Cseq[T][string]>`_ @@ -276,18 +334,7 @@ macro cPlugin*(body): untyped = if sym.kind == nskProc and sym.name.contains("SDL_"): sym.name = sym.name.replace("SDL_", "") - let - data = "import macros, nimterop/plugin\n\n" & body.repr - hash = data.hash().abs() - path = getProjectCacheDir("cPlugins", forceClean = false) / "nimterop_" & $hash & ".nim" - - if not fileExists(path) or gStateCT.nocache or compileOption("forceBuild"): - mkDir(path.parentDir()) - writeFile(path, data) - - doAssert fileExists(path), "Unable to write plugin file: " & path - - gStateCT.pluginSourcePath = path + cPluginHelper(body.repr) proc cSearchPath*(path: string): string {.compileTime.}= ## Get full path to file or directory `path` in search path configured @@ -529,6 +576,9 @@ macro cImport*(filename: static string, recurse: static bool = false, dynlib: st let fullpath = findPath(filename) + if gStateCT.overrides.len != 0 and gStateCT.pluginSourcePath.len == 0: + cPluginHelper(gStateCT.pluginSource) + echo "# Importing " & fullpath.sanitizePath let diff --git a/nimterop/getters.nim b/nimterop/getters.nim index a88895d..9970981 100644 --- a/nimterop/getters.nim +++ b/nimterop/getters.nim @@ -138,18 +138,44 @@ proc getUniqueIdentifier*(nimState: NimState, prefix = ""): string = return name & $count -proc addNewIdentifer*(nimState: NimState, name: string): bool = - if name notin nimState.gState.symOverride: +proc addNewIdentifer*(nimState: NimState, name: string, override = false): bool = + if override or name notin nimState.gState.symOverride: let nimName = name[0] & name[1 .. ^1].replace("_", "").toLowerAscii if nimState.identifiers.hasKey(nimName): - doAssert name == nimState.identifiers[nimName], &"Identifier '{name}' is a stylistic duplicate of identifier '{nimState.identifiers[nimName]}', use 'cPlugin:onSymbol()' to rename" + doAssert name == nimState.identifiers[nimName], + &"Identifier '{name}' is a stylistic duplicate of identifier " & + &"'{nimState.identifiers[nimName]}', use 'cPlugin:onSymbol()' to rename" result = false else: nimState.identifiers[nimName] = name result = true +proc getOverride*(nimState: NimState, name: string, kind: NimSymKind): string = + doAssert name.len != 0, "Blank identifier error" + + if nimState.gState.onSymbolOverride != nil: + var + nname = nimState.getIdentifier(name, kind, "Override") + sym = Symbol(name: nname, kind: kind) + if nname.nBl: + nimState.gState.onSymbolOverride(sym) + + if sym.override.len != 0 and nimState.addNewIdentifer(nname, override = true): + result = sym.override + + if kind != nskProc: + result = result.replace(re"(?m)^(.*?)$", " $1") + +proc getOverrideFinal*(nimState: NimState, kind: NimSymKind): string = + let + typ = $kind + + if nimState.gState.onSymbolOverrideFinal != nil: + for i in nimState.gState.onSymbolOverrideFinal(typ): + result &= "\n" & nimState.getOverride(i, kind) + proc getPtrType*(str: string): string = result = case str: of "ptr cchar": @@ -320,6 +346,9 @@ proc getAstChildByName*(ast: ref Ast, name: string): ref Ast = if name in ast.children[i].name.split("|"): return ast.children[i] + if ast.children.len == 1 and ast.children[0].name == ".": + return ast.children[0] + proc getPxName*(node: TSNode, offset: int): string = var np = node @@ -449,7 +478,10 @@ proc loadPlugin*(gState: State, sourcePath: string) = doAssert lib != nil, "Plugin $1 compiled to $2 failed to load" % [sourcePath, pdll] gState.onSymbol = cast[OnSymbol](lib.symAddr("onSymbol")) - doAssert gState.onSymbol != nil, "onSymbol() load failed from " & pdll + + gState.onSymbolOverride = cast[OnSymbol](lib.symAddr("onSymbolOverride")) + + gState.onSymbolOverrideFinal = cast[OnSymbolOverrideFinal](lib.symAddr("onSymbolOverrideFinal")) proc expandSymlinkAbs*(path: string): string = try: diff --git a/nimterop/globals.nim b/nimterop/globals.nim index 8fd8fe9..428d927 100644 --- a/nimterop/globals.nim +++ b/nimterop/globals.nim @@ -57,9 +57,10 @@ type nocache*, nocomments*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool - code*, dynlib*, mode*, nim*, pluginSourcePath*: string + code*, dynlib*, mode*, nim*, overrides*, pluginSource*, pluginSourcePath*: string - onSymbol*: OnSymbol + onSymbol*, onSymbolOverride*: OnSymbol + onSymbolOverrideFinal*: OnSymbolOverrideFinal NimState {.used.} = ref object identifiers*: TableRef[string, string] diff --git a/nimterop/grammar.nim b/nimterop/grammar.nim index 8d98dde..767c8f8 100644 --- a/nimterop/grammar.nim +++ b/nimterop/grammar.nim @@ -20,14 +20,19 @@ proc initGrammar(): Grammar = nimState.debugStr &= "\n# define X Y" let + name = nimState.data[0].val + nname = nimState.getIdentifier(name, nskConst) val = nimState.data[1].val.getLit() - if val.nBl: + if not nname.nBl: let - name = nimState.getIdentifier(nimState.data[0].val, nskConst) - - if name.nBl and nimState.addNewIdentifer(name): - nimState.constStr &= &"{nimState.getComments()}\n {name}* = {val}" + override = nimState.getOverride(name, nskConst) + if override.len != 0: + nimState.constStr &= &"{nimState.getComments()}\n{override}" + else: + nimState.constStr &= &"{nimState.getComments()}\n # Const '{name}' skipped" + elif val.nBl and nimState.addNewIdentifer(nname): + nimState.constStr &= &"{nimState.getComments()}\n {nname}* = {val}" )) let @@ -175,7 +180,12 @@ proc initGrammar(): Grammar = let pragma = nimState.getPragma(pragmas) - if nname notin gTypeMap and typ.nBl and nname.nBl and nimState.addNewIdentifer(nname): + if not nname.nBl: + let + override = nimState.getOverride(name, nskType) + if override.len != 0: + nimState.typeStr &= &"{nimState.getComments()}\n{override}" + elif nname notin gTypeMap and typ.nBl and nimState.addNewIdentifer(nname): if i < nimState.data.len and nimState.data[^1].name == "function_declarator": var fname = nname @@ -266,7 +276,12 @@ proc initGrammar(): Grammar = union = ", union" break - if nname.nBl and nimState.addNewIdentifer(nname): + if not nname.nBl: + let + override = nimState.getOverride(name, nskType) + if override.len != 0: + nimState.typeStr &= &"{nimState.getComments()}\n{override}" + elif nimState.addNewIdentifer(nname): if nimState.data.len == 1: nimState.typeStr &= &"{nimState.getComments()}\n {nname}* {{.bycopy{union}.}} = object" else: @@ -604,7 +619,12 @@ proc initGrammar(): Grammar = if pout.len != 0 and pout[^2 .. ^1] == ", ": pout = pout[0 .. ^3] - if fnname.nBl and nimState.addNewIdentifer(fnname): + if not fnname.nBl: + let + override = nimState.getOverride(fname, nskProc) + if override.len != 0: + nimState.typeStr &= &"{nimState.getComments()}\n{override}" + elif nimState.addNewIdentifer(fnname): let ftyp = nimState.getIdentifier(nimState.data[0].val, nskType, fnname).getType() pragma = nimState.getPragma(nimState.getImportC(fname, fnname), "cdecl") @@ -637,6 +657,38 @@ proc initGrammar(): Grammar = nimState.commentStr &= &"\n # {line.strip(leading=false)}" )) + # // unknown + result.add((&""" + (type_definition|struct_specifier|union_specifier|enum_specifier|declaration + (^.*) + ) + """, + proc (ast: ref Ast, node: TSNode, nimState: NimState) = + for i in nimState.data: + case $node.tsNodeType() + of "declaration": + if i.name == "identifier": + let + override = nimState.getOverride(i.val, nskProc) + + if override.len != 0: + nimState.procStr &= &"{nimState.getComments(true)}\n{override}" + break + else: + nimState.procStr &= &"{nimState.getComments(true)}\n# Declaration '{i.val}' skipped" + + else: + if i.name == "type_identifier": + let + override = nimState.getOverride(i.val, nskType) + + if override.len != 0: + nimState.typeStr &= &"{nimState.getComments()}\n{override}" + else: + nimState.typeStr &= &"{nimState.getComments()}\n # Type '{i.val}' skipped" + + )) + proc initRegex(ast: ref Ast) = if ast.children.len != 0: if not ast.recursive: @@ -653,7 +705,7 @@ proc initRegex(ast: ref Ast) = raise newException(Exception, getCurrentExceptionMsg()) proc parseGrammar*(): AstTable = - let grammars = initGrammar() + const grammars = initGrammar() result = newTable[string, seq[ref Ast]]() for i in 0 .. grammars.len-1: diff --git a/nimterop/plugin.nim b/nimterop/plugin.nim index 646c83c..3769142 100644 --- a/nimterop/plugin.nim +++ b/nimterop/plugin.nim @@ -1,9 +1,22 @@ -import macros +import macros, sets, tables type Symbol* = object name*: string parent*: string kind*: NimSymKind + override*: string - OnSymbol* = proc(sym: var Symbol) {.cdecl.}
\ No newline at end of file + OnSymbol* = proc(sym: var Symbol) {.cdecl.} + OnSymbolOverrideFinal* = proc(typ: string): HashSet[string] {.cdecl.} + +var + cOverrides*: Table[string, HashSet[string]] + +cOverrides = initTable[string, HashSet[string]]() +cOverrides["nskType"] = initSet[string]() +cOverrides["nskConst"] = initSet[string]() +cOverrides["nskProc"] = initSet[string]() + +proc onSymbolOverrideFinal*(typ: string): HashSet[string] {.exportc, dynlib.} = + result = cOverrides[typ] diff --git a/tests/include/test.c b/tests/include/test.c index 18e444f..e9cb2aa 100644 --- a/tests/include/test.c +++ b/tests/include/test.c @@ -75,3 +75,11 @@ void *multiline2(void) { } void multiline3(void) {} + +int weirdfunc(char ***apple) { + return 1; +} + +int weirdfunc2(char **apple) { + return 2; +} diff --git a/tests/include/test.h b/tests/include/test.h index d062277..667f384 100644 --- a/tests/include/test.h +++ b/tests/include/test.h @@ -167,6 +167,31 @@ enum TDEFL_BOGUS_3 = TDEFL_OUT_BUF_SIZE / TDEFL_BOGUS_1 }; +// cOverride +struct foo { int foo[8][1]; }; + +typedef struct tagBITMAPINFOHEADER{ + int biClrImportant; +} BITMAPINFOHEADER, * pBITMAPINFOHEADER; + +#define BIT 123u + +#define BIT2 123u + +#define BIT3 123 + +typedef int ABC; + +typedef int DEF; + +typedef struct { + int **f1; +} GHI; + +struct JKL { + int **f1; +}; + #ifdef __cplusplus } #endif diff --git a/tests/tmath.nim b/tests/tmath.nim index b2f803b..9f3df79 100644 --- a/tests/tmath.nim +++ b/tests/tmath.nim @@ -20,7 +20,7 @@ cPlugin: import strutils proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} = - sym.name = sym.name.strip(chars={'_'}) + sym.name = sym.name.strip(chars={'_'}).replace("__", "_") cImport cSearchPath("math.h") diff --git a/tests/tnimterop_c.nim b/tests/tnimterop_c.nim index a289303..fb1505a 100644 --- a/tests/tnimterop_c.nim +++ b/tests/tnimterop_c.nim @@ -20,6 +20,27 @@ cPlugin: else: sym.name = sym.name.strip(chars={'_'}) +cOverride: + type + BITMAPINFOHEADER* {.bycopy.} = object + biClrImportant*: int + + Random = object + + ABC = pointer + + GHI = object + f2: ptr ptr cint + + JKL = object + f2: ptr ptr cint + + const + BIT* = 1 + + proc weirdfunc(apple: ptr ptr ptr cchar): int {.importc.} + proc weirdfunc2(mango: ptr ptr cchar): int {.importc.} + cImport cSearchPath "test.h" check TEST_INT == 512 @@ -183,3 +204,23 @@ var arr: array[5, cint] check test_array_param(arr) == nil + +# cOverride + +var + ca = weirdfunc + cb: BITMAPINFOHEADER + cc = weirdfunc2 + cd: ABC + ce: DEF + cf: GHI + cg: JKL + +cd = nil +ce = 5 +cf.f2 = nil +cg.f2 = nil + +doAssert BIT == 1 +doAssert ca(nil) == 1 +doAssert cc(nil) == 2 diff --git a/tests/zlib.nim b/tests/zlib.nim index 036b50c..ce26c9a 100644 --- a/tests/zlib.nim +++ b/tests/zlib.nim @@ -48,8 +48,9 @@ cOverride: z_crc_t = culong alloc_func* {.importc.} = proc(opaque: voidpf, items, size: uint) {.cdecl.} Bytef {.importc.} = object - - when defined(posix): + +when defined(posix): + cOverride: type pthread_mutex_s = object pthread_cond_s = object |
