aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Viswanathan <dev@genotrance.com>2019-01-27 11:37:33 -0600
committergenotrance <dev@genotrance.com>2019-01-27 22:05:54 -0600
commitf7a77b7ab9c7cae36014e1991245e0d4c1da7099 (patch)
tree1a0f1d8f2669d7b6f83e5b375b758c88593fa4d2
parenta8b08e1867c6ad130a86d7848b45a5698fdd7699 (diff)
downloadnimterop-f7a77b7ab9c7cae36014e1991245e0d4c1da7099.tar.gz
nimterop-f7a77b7ab9c7cae36014e1991245e0d4c1da7099.zip
Improve onSymbol API
-rw-r--r--nimterop/cimport.nim25
-rw-r--r--nimterop/getters.nim10
-rw-r--r--nimterop/globals.nim14
-rw-r--r--nimterop/grammar.nim32
-rw-r--r--tests/tmath.nim4
-rw-r--r--tests/tnimterop_c.nim4
6 files changed, 58 insertions, 31 deletions
diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim
index bd330b4..0a4a138 100644
--- a/nimterop/cimport.nim
+++ b/nimterop/cimport.nim
@@ -174,18 +174,33 @@ macro cSkipSymbol*(skips: varargs[string]): untyped =
macro cPlugin*(body): untyped =
## When `cOverride() <cimport.html#cOverride.m,>`_ and `cSkipSymbol() <cimport.html#cSkipSymbol.m%2Cvarargs[string]>`_
- ## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used to customize the generated Nim output.
- ## The following callbacks are available at this time.
+ ## are not adequate, the `cPlugin() <cimport.html#cPlugin.m,>`_ macro can be used
+ ## to customize the generated Nim output. The following callbacks are available at
+ ## this time.
##
+ ## .. code-block:: nim
+ ##
+ ## proc onSymbol(sym: var Symbol): Result {.exportc, dynlib.}
+ ##
+ ## `onSymbol()` can be used to handle symbol name modifications required due to invalid
+ ## characters like `_` or to rename duplicate types. It can also be used to remove prefixes
+ ## and suffixes. The symbol name and type is provided to the callback and the name can be
+ ## modified. Symbol types can be any of the following:
+ ## - `nskConst` for constants
+ ## - `nskType` for type identifiers, including primitive
+ ## - `nskParam` for param names
+ ## - `nskField` for struct field names
+ ## - `nskEnumField` for enum (field) names, though they are in the global namespace as `nskConst`
+ ## - `nskProc` - for proc names
runnableExamples:
cPlugin:
import strutils
- proc onSymbol*(sym: string): string {.exportc, dynlib.} =
- return sym.strip(chars={'_'})
+ proc onSymbol*(sym: var Symbol): Result {.exportc, dynlib.} =
+ sym.name = sym.name.strip(chars={'_'})
let
- data = body.repr
+ data = "import nimterop/cimport\n\n" & body.repr
hash = data.hash()
phash = if hash<0: -hash else: hash
path = getTempDir() / "nimterop_" & $phash & ".nim"
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index 30a0001..e2cfbe9 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -90,11 +90,17 @@ proc getType*(str: string): string =
template checkUnderscores(str, errmsg: string): untyped =
doAssert str[0] != '_' and str[^1] != '_', errmsg
-proc getIdentifier*(str: string): string =
+proc getIdentifier*(str: string, kind: NimSymKind): string =
doAssert str.len != 0, "Blank identifier error"
if gStateRT.onSymbol != nil:
- result = gStateRT.onSymbol(str)
+ var
+ sym = Symbol(name: str, kind: kind)
+ res = gStateRT.onSymbol(sym)
+
+ doAssert res.error == 0, res.message
+
+ result = sym.name
checkUnderscores(result, &"Identifier '{str}' still contains leading/trailing underscores '_' after 'cPlugin:onSymbol()': result '{result}'")
else:
result = str
diff --git a/nimterop/globals.nim b/nimterop/globals.nim
index 22b2794..dac31e5 100644
--- a/nimterop/globals.nim
+++ b/nimterop/globals.nim
@@ -45,9 +45,13 @@ type
tonim*: proc (ast: ref Ast, node: TSNode)
regex*: Regex
- Symbol = object
- name: string
- kind: NimSymKind
+ Symbol* = object
+ name*: string
+ kind*: NimSymKind
+
+ Result* = object
+ error*: int
+ message*: string
State = object
compile*, defines*, headers*, includeDirs*, searchDirs*, symOverride*: seq[string]
@@ -63,7 +67,7 @@ type
when not declared(CIMPORT):
grammar*: seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode) {.nimcall.}]]
- onSymbol*: proc(sym: string): string {.cdecl.}
+ onSymbol*: proc(sym: var Symbol): Result {.cdecl.}
var
gStateCT {.compiletime, used.}: State
gStateRT {.used.}: State
@@ -79,4 +83,4 @@ type CompileMode = enum
const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant
when not declared(CIMPORT):
- export gAtoms, gExpressions, gEnumVals, Kind, Ast, Symbol, State, gStateRT, nBl, CompileMode, modeDefault \ No newline at end of file
+ export gAtoms, gExpressions, gEnumVals, Kind, Ast, State, gStateRT, nBl, CompileMode, modeDefault \ No newline at end of file
diff --git a/nimterop/grammar.nim b/nimterop/grammar.nim
index 5a7ca66..259a9d4 100644
--- a/nimterop/grammar.nim
+++ b/nimterop/grammar.nim
@@ -1,4 +1,4 @@
-import sets, strformat, strutils, tables
+import macros, sets, strformat, strutils, tables
import regex
@@ -14,7 +14,7 @@ proc initGrammar() =
""",
proc (ast: ref Ast, node: TSNode) =
let
- name = gStateRT.data[0].val.getIdentifier()
+ name = gStateRT.data[0].val.getIdentifier(nskConst)
val = gStateRT.data[1].val.getLit()
if val.nBl and gStateRT.consts.addNewIdentifer(name):
@@ -67,7 +67,7 @@ proc initGrammar() =
"""
template funcParamCommon(pname, ptyp, pptr, pout, count, i: untyped): untyped =
- ptyp = gStateRT.data[i].val.getIdentifier()
+ ptyp = gStateRT.data[i].val.getIdentifier(nskType)
if i+1 < gStateRT.data.len and gStateRT.data[i+1].name == "pointer_declarator":
pptr = "ptr "
i += 1
@@ -75,7 +75,7 @@ proc initGrammar() =
pptr = ""
if i+1 < gStateRT.data.len and gStateRT.data[i+1].name == "identifier":
- pname = gStateRT.data[i+1].val.getIdentifier()
+ pname = gStateRT.data[i+1].val.getIdentifier(nskParam)
i += 2
else:
pname = "a" & $count
@@ -104,7 +104,7 @@ proc initGrammar() =
proc (ast: ref Ast, node: TSNode) =
var
i = 0
- typ = gStateRT.data[i].val.getIdentifier()
+ typ = gStateRT.data[i].val.getIdentifier(nskType)
name = ""
tptr = ""
aptr = ""
@@ -120,7 +120,7 @@ proc initGrammar() =
i += 1
if i < gStateRT.data.len:
- name = gStateRT.data[i].val.getIdentifier()
+ name = gStateRT.data[i].val.getIdentifier(nskType)
i += 1
if gStateRT.types.addNewIdentifer(name):
@@ -144,8 +144,10 @@ proc initGrammar() =
gStateRT.typeStr &= &" {name}* = proc({pout}) {{.nimcall.}}\n"
else:
if i < gStateRT.data.len and gStateRT.data[i].name in ["identifier", "number_literal"]:
- let
- flen = gStateRT.data[i].val.getIdentifier()
+ var
+ flen = gStateRT.data[i].val
+ if gStateRT.data[i].name == "identifier":
+ flen = flen.getIdentifier(nskConst)
gStateRT.typeStr &= &" {name}* = {aptr}array[{flen}, {getPtrType(tptr&typ)}]\n"
else:
if name == typ:
@@ -157,7 +159,7 @@ proc initGrammar() =
proc pDupTypeCommon(nname: string, fend: int, isEnum=false) =
var
dname = gStateRT.data[^1].val
- ndname = gStateRT.data[^1].val.getIdentifier()
+ ndname = gStateRT.data[^1].val.getIdentifier(nskType)
dptr =
if fend == 2:
"ptr "
@@ -175,7 +177,7 @@ proc initGrammar() =
proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) =
var
- nname = name.getIdentifier()
+ nname = name.getIdentifier(nskType)
prefix = ""
union = ""
@@ -231,7 +233,7 @@ proc initGrammar() =
aptr = "ptr "
i += 1
- fname = gStateRT.data[i].val.getIdentifier()
+ fname = gStateRT.data[i].val.getIdentifier(nskField)
if i+1 < gStateRT.data.len-fend and gStateRT.data[i+1].name in gEnumVals:
let
flen = gStateRT.data[i+1].val.getNimExpression()
@@ -348,7 +350,7 @@ proc initGrammar() =
if name.len == 0:
getUniqueIdentifier(gStateRT.enums, "Enum")
else:
- name.getIdentifier()
+ name.getIdentifier(nskType)
if gStateRT.enums.addNewIdentifer(nname):
gStateRT.enumStr &= &"\ntype {nname}* = distinct int"
@@ -363,7 +365,7 @@ proc initGrammar() =
continue
let
- fname = gStateRT.data[i].val.getIdentifier()
+ fname = gStateRT.data[i].val.getIdentifier(nskEnumField)
if i+1 < gStateRT.data.len-fend and
gStateRT.data[i+1].name in gEnumVals:
@@ -447,7 +449,7 @@ proc initGrammar() =
""",
proc (ast: ref Ast, node: TSNode) =
var
- ftyp = gStateRT.data[0].val.getIdentifier()
+ ftyp = gStateRT.data[0].val.getIdentifier(nskType)
fptr = ""
i = 1
@@ -464,7 +466,7 @@ proc initGrammar() =
var
fname = gStateRT.data[i].val
- fnname = fname.getIdentifier()
+ fnname = fname.getIdentifier(nskProc)
pout, pname, ptyp, pptr = ""
count = 1
diff --git a/tests/tmath.nim b/tests/tmath.nim
index 5e98968..a561251 100644
--- a/tests/tmath.nim
+++ b/tests/tmath.nim
@@ -14,8 +14,8 @@ cAddStdDir()
cPlugin:
import strutils
- proc onSymbol*(sym: string): string {.exportc, dynlib.} =
- return sym.strip(chars={'_'})
+ proc onSymbol*(sym: var Symbol): Result {.exportc, dynlib.} =
+ sym.name = sym.name.strip(chars={'_'})
cImport cSearchPath("math.h")
diff --git a/tests/tnimterop_c.nim b/tests/tnimterop_c.nim
index 095fe20..c9b4667 100644
--- a/tests/tnimterop_c.nim
+++ b/tests/tnimterop_c.nim
@@ -12,8 +12,8 @@ cCompile cSearchPath("test.c")
cPlugin:
import strutils
- proc onSymbol*(sym: string): string {.exportc, dynlib.} =
- return sym.strip(chars={'_'})
+ proc onSymbol*(sym: var Symbol): Result {.exportc, dynlib.} =
+ sym.name = sym.name.strip(chars={'_'})
cImport cSearchPath "test.h"