Improve onSymbol API

This commit is contained in:
Ganesh Viswanathan 2019-01-27 11:37:33 -06:00 • committed by genotrance
commit f7a77b7ab9
6 changed files with 58 additions and 31 deletions

View file

@ -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"

View file

@ -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

View file

@ -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
export gAtoms, gExpressions, gEnumVals, Kind, Ast, State, gStateRT, nBl, CompileMode, modeDefault

View file

@ -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

View file

@ -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")

View file

@ -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"