Plugin support
This commit is contained in:
parent
c3e442474b
commit
fb997526de
8 changed files with 72 additions and 19 deletions
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue