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 language: c
env: env:
- BRANCH=0.19.0
- BRANCH=0.19.2 - BRANCH=0.19.2
- BRANCH=devel - BRANCH=devel
cache: cache:
directories: directories:
- "$HOME/.choosenim/toolchains/nim-0.19.0"
- "$HOME/.choosenim/toolchains/nim-0.19.2" - "$HOME/.choosenim/toolchains/nim-0.19.2"
install: install:

View file

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

View file

@ -1,4 +1,4 @@
import macros, os, strformat, strutils import hashes, macros, os, ospaths, strformat, strutils
const CIMPORT {.used.} = 1 const CIMPORT {.used.} = 1
@ -102,6 +102,9 @@ proc getToast(fullpath: string, recurse: bool = false): string =
if gStateCT.symOverride.len != 0: if gStateCT.symOverride.len != 0:
cmd.add &"--symOverride={gStateCT.symOverride.join(\",\")} " cmd.add &"--symOverride={gStateCT.symOverride.join(\",\")} "
if gStateCT.pluginFile.nBl and gStateCT.pluginFile.fileExists():
cmd.add &"--pluginFile={gStateCT.pluginFile.quoteShell} "
cmd.add &"{fullpath.quoteShell}" cmd.add &"{fullpath.quoteShell}"
echo cmd echo cmd
(result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath)) (result, ret) = gorgeEx(cmd, cache=getCacheValue(fullpath))
@ -170,6 +173,16 @@ macro cSkipSymbol*(skips: varargs[string]): untyped =
for skip in skips: for skip in skips:
gStateCT.symOverride.add skip.strVal 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.}= proc cSearchPath*(path: string): string {.compileTime.}=
## Get full path to file or directory ``path`` in search path configured ## Get full path to file or directory ``path`` in search path configured
## using `cAddSearchDir() <cimport.html#cAddSearchDir.m,>`_ and ## 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 import regex
@ -88,7 +88,14 @@ proc getType*(str: string): string =
result = gTypeMap[result] result = gTypeMap[result]
proc getIdentifier*(str: string): string = 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: if result in gReserved:
result = &"`{result}`" result = &"`{result}`"
@ -306,4 +313,27 @@ proc getNimExpression*(expr: string): string =
proc getSplitComma*(joined: seq[string]): seq[string] = proc getSplitComma*(joined: seq[string]): seq[string] =
for i in joined: 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 nocache*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool
consts*, enums*, procs*, types*: HashSet[string] consts*, enums*, procs*, types*: HashSet[string]
constStr*, debugStr*, enumStr*, procStr*, typeStr*: string
code*, constStr*, currentHeader*, debugStr*, enumStr*, mode*, procStr*, typeStr*: string code*, currentHeader*, mode*, pluginFile*, sourceFile*: string
sourceFile*: string # eg, C or C++ source or header file
ast*: Table[string, seq[ref Ast]] ast*: Table[string, seq[ref Ast]]
data*: seq[tuple[name, val: string]] data*: seq[tuple[name, val: string]]
when not declared(CIMPORT): when not declared(CIMPORT):
grammar*: seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode) {.nimcall.}]] grammar*: seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode) {.nimcall.}]]
onSymbol*: proc(sym: string): string {.cdecl.}
var var
gStateCT {.compiletime, used.}: State gStateCT {.compiletime, used.}: State
gStateRT {.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) = proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int) =
var let nname =
nname = name.getIdentifier() if name.len == 0:
getUniqueIdentifier(gStateRT.enums, "Enum")
if nname.len == 0: else:
nname = getUniqueIdentifier(gStateRT.enums, "Enum") name.getIdentifier()
if gStateRT.enums.addNewIdentifer(nname): if gStateRT.enums.addNewIdentifer(nname):
gStateRT.enumStr &= &"\ntype {nname}* = distinct int" gStateRT.enumStr &= &"\ntype {nname}* = distinct int"
@ -358,13 +358,13 @@ proc initGrammar() =
i = fstart i = fstart
count = 0 count = 0
while i < gStateRT.data.len-fend: while i < gStateRT.data.len-fend:
let
fname = gStateRT.data[i].val.getIdentifier()
if gStateRT.data[i].name == "enumerator": if gStateRT.data[i].name == "enumerator":
i += 1 i += 1
continue continue
let
fname = gStateRT.data[i].val.getIdentifier()
if i+1 < gStateRT.data.len-fend and if i+1 < gStateRT.data.len-fend and
gStateRT.data[i+1].name in gEnumVals: gStateRT.data[i+1].name in gEnumVals:
if gStateRT.consts.addNewIdentifer(fname): if gStateRT.consts.addNewIdentifer(fname):

View file

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

View file

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