Plugin support

This commit is contained in:
Ganesh Viswanathan 2019-01-24 22:44:16 -06:00 committed by genotrance
commit d8c75a43f7
8 changed files with 72 additions and 19 deletions

View file

@ -5,13 +5,11 @@ os:
language: c
env:
- BRANCH=0.19.0
- BRANCH=0.19.2
- BRANCH=devel
cache:
directories:
- "$HOME/.choosenim/toolchains/nim-0.19.0"
- "$HOME/.choosenim/toolchains/nim-0.19.2"
install:

View file

@ -9,7 +9,6 @@ matrix:
environment:
matrix:
- NIM_VERSION: 0.19.0
- NIM_VERSION: 0.19.2
for:

View file

@ -1,4 +1,4 @@
import macros, os, strformat, strutils
import hashes, macros, os, ospaths, strformat, strutils
const CIMPORT {.used.} = 1
@ -102,6 +102,9 @@ proc getToast(fullpath: string, recurse: bool = false): string =
if gStateCT.symOverride.len != 0:
cmd.add &"--symOverride={gStateCT.symOverride.join(\",\")} "
if gStateCT.pluginFile.nBl and gStateCT.pluginFile.fileExists():
cmd.add &"--pluginFile={gStateCT.pluginFile.quoteShell} "
cmd.add &"{fullpath.quoteShell}"
echo cmd
(result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath))
@ -170,6 +173,16 @@ macro cSkipSymbol*(skips: varargs[string]): untyped =
for skip in skips:
gStateCT.symOverride.add skip.strVal
macro cPlugin*(body): untyped =
let
data = body.repr
path = getTempDir() / "nimterop" & ($data.hash() & ".nim")
if not fileExists(path):
writeFile(path, data)
gStateCT.pluginFile = path
proc cSearchPath*(path: string): string {.compileTime.}=
## Get full path to file or directory ``path`` in search path configured
## using `cAddSearchDir() <cimport.html#cAddSearchDir.m,>`_ and

View file

@ -1,4 +1,4 @@
import macros, os, sequtils, sets, strformat, strutils, tables
import dynlib, macros, os, sequtils, sets, strformat, strutils, tables
import regex
@ -88,7 +88,14 @@ proc getType*(str: string): string =
result = gTypeMap[result]
proc getIdentifier*(str: string): string =
result = str.strip(chars={'_'}).replace(re"_+", "_")
doAssert str.len != 0, "Blank identifier error"
if gStateRT.onSymbol != nil:
result = gStateRT.onSymbol(str)
else:
result = str
doAssert result[0] != '_' and result[^1] != '_', &"Identifier '{result}' with leading/trailing underscore '_' not supported: use cPlugin() to handle"
if result in gReserved:
result = &"`{result}`"
@ -306,4 +313,27 @@ proc getNimExpression*(expr: string): string =
proc getSplitComma*(joined: seq[string]): seq[string] =
for i in joined:
result = result.concat(i.split(","))
result = result.concat(i.split(","))
proc dll*(path: string): string =
let
(dir, name, ext) = path.splitFile()
when defined(Windows):
result = dir/name.addFileExt("dll")
when defined(Linux):
result = dir/"lib" & name.addFileExt("so")
when defined(OSX):
result = dir/"lib" & name.addFileExt("dynlib")
proc loadPlugin*(fullpath: string) =
doAssert fileExists(fullpath), "Plugin file does not exist: " & fullpath
if not fileExists(fullpath.dll):
discard execAction("nim c --app:lib " & fullpath)
doAssert fileExists(fullpath.dll), "No plugin binary generated for " & fullpath
let lib = loadLib(fullpath.dll)
doAssert lib != nil, "Plugin load failed"
gStateRT.onSymbol = cast[proc(sym: string): string {.cdecl.}](lib.symAddr("onSymbol"))
doAssert gStateRT.onSymbol != nil, "onSymbol() load failed"

View file

@ -51,15 +51,15 @@ type
nocache*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool
consts*, enums*, procs*, types*: HashSet[string]
code*, constStr*, currentHeader*, debugStr*, enumStr*, mode*, procStr*, typeStr*: string
sourceFile*: string # eg, C or C++ source or header file
constStr*, debugStr*, enumStr*, procStr*, typeStr*: string
code*, currentHeader*, mode*, pluginFile*, sourceFile*: string
ast*: Table[string, seq[ref Ast]]
data*: seq[tuple[name, val: string]]
when not declared(CIMPORT):
grammar*: seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode) {.nimcall.}]]
onSymbol*: proc(sym: string): string {.cdecl.}
var
gStateCT {.compiletime, used.}: State
gStateRT {.used.}: State

View file

@ -344,11 +344,11 @@ proc initGrammar() =
))
proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) =
var
nname = name.getIdentifier()
if nname.len == 0:
nname = getUniqueIdentifier(gStateRT.enums, "Enum")
let nname =
if name.len == 0:
getUniqueIdentifier(gStateRT.enums, "Enum")
else:
name.getIdentifier()
if gStateRT.enums.addNewIdentifer(nname):
gStateRT.enumStr &= &"\ntype {nname}* = distinct int"
@ -358,13 +358,13 @@ proc initGrammar() =
i = fstart
count = 0
while i < gStateRT.data.len-fend:
let
fname = gStateRT.data[i].val.getIdentifier()
if gStateRT.data[i].name == "enumerator":
i += 1
continue
let
fname = gStateRT.data[i].val.getIdentifier()
if i+1 < gStateRT.data.len-fend and
gStateRT.data[i+1].name in gEnumVals:
if gStateRT.consts.addNewIdentifer(fname):

View file

@ -8,6 +8,13 @@ cDefine("FORCE")
cIncludeDir "$projpath/include"
cAddSearchDir "$projpath/include"
cCompile cSearchPath("test.c")
cPlugin:
import strutils
proc onSymbol*(sym: string): string {.exportc, dynlib.} =
return sym.strip(chars={'_'})
cImport cSearchPath "test.h"
check TEST_INT == 512

View file

@ -113,6 +113,7 @@ proc main(
defines: seq[string] = @[],
includeDirs: seq[string] = @[],
symOverride: seq[string] = @[],
pluginFile: string = "",
source: seq[string],
) =
@ -126,11 +127,15 @@ proc main(
debug: debug,
defines: defines,
includeDirs: includeDirs,
symOverride: symOverride
symOverride: symOverride,
pluginFile: pluginFile
)
gStateRT.symOverride = gStateRT.symOverride.getSplitComma()
if pluginFile.nBl:
loadPlugin(pluginFile)
if pgrammar:
parseGrammar()
printGrammar()
@ -146,6 +151,7 @@ when isMainModule:
"defines": "definitions to pass to preprocessor",
"includeDirs": "include directory to pass to preprocessor",
"symOverride": "skip generating specified symbols",
"pluginFile": "Nim file to build and load as a plugin",
"preprocess": "run preprocessor on header",
"pgrammar": "print grammar",
"recurse": "process #include files",