Remove legacy backend
This commit is contained in:
parent
a8ea96055d
commit
d126e9944f
17 changed files with 33 additions and 1295 deletions
|
|
@ -19,6 +19,8 @@ https://github.com/nimterop/nimterop/compare/v0.5.9...v0.6.0
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
|
|
||||||
|
- The legacy algorithm has been removed as promised. `ast2` is now the default and wrappers no longer need to explicitly specify `-f:ast2` in order to use it.
|
||||||
|
|
||||||
- All shared libraries installed by `getHeader()` will now get copied into the `libdir` parameter specified. If left blank, `libdir` will default to the directory where the executable binary gets created (outdir). While this is not really a breaking change, it is a change in behavior compared to older versions of nimterop. Note that `Std` libraries are not copied over. [#154](i154)
|
- All shared libraries installed by `getHeader()` will now get copied into the `libdir` parameter specified. If left blank, `libdir` will default to the directory where the executable binary gets created (outdir). While this is not really a breaking change, it is a change in behavior compared to older versions of nimterop. Note that `Std` libraries are not copied over. [#154](i154)
|
||||||
|
|
||||||
- `git.nim` has been removed. This module was an artifact from the early days and was renamed to `build.nim` back in v0.2.0.
|
- `git.nim` has been removed. This module was an artifact from the early days and was renamed to `build.nim` back in v0.2.0.
|
||||||
|
|
|
||||||
|
|
@ -177,13 +177,13 @@ Now that this is understood, a user might want any combination of the above in t
|
||||||
- By default, generated wrappers will include the `{.header, importc.}` pragmas for types and procs. This can be disabled with the `--noHeader | -H` flag to `toast` or `flags = "-H"` param to `cImport()` which will remove `{.header}` for both and `{.importc.}` for types only.
|
- By default, generated wrappers will include the `{.header, importc.}` pragmas for types and procs. This can be disabled with the `--noHeader | -H` flag to `toast` or `flags = "-H"` param to `cImport()` which will remove `{.header}` for both and `{.importc.}` for types only.
|
||||||
- By default, generated wrappers will assume that the user will link the library implementation themselves. The `--dynlib | -l` flag to `toast` or `dynlib = "headerLPath"` param to `cImport()` will configure the wrapper to generate `{.dynlib.}` pragmas for procs.
|
- By default, generated wrappers will assume that the user will link the library implementation themselves. The `--dynlib | -l` flag to `toast` or `dynlib = "headerLPath"` param to `cImport()` will configure the wrapper to generate `{.dynlib.}` pragmas for procs.
|
||||||
|
|
||||||
This results in four cases:
|
This results in four supported cases:
|
||||||
1. Default: `{.header, importc.}` for both types and procs
|
1. Default: `{.header, importc.}` for both types and procs
|
||||||
2. With `--noHeader`, types will be pure Nim and procs will be just `{.importc.}`
|
2. With `--noHeader`, types will be pure Nim and procs will be just `{.importc.}`
|
||||||
3. With `--dynlib`, types will still be `{.header, importc.}` but procs will be `{.dynlib, importc.}`
|
3. With `--dynlib`, types will still be `{.header, importc.}` but procs will be `{.dynlib, importc.}`
|
||||||
4. With `--dynlib` and `--noHeader`, types will be pure Nim, procs will be `{.dynlib, importc.}`
|
4. With `--dynlib` and `--noHeader`, types will be pure Nim, procs will be `{.dynlib, importc.}`
|
||||||
|
|
||||||
While `ast2` supports all these modes, the legacy backend does not support the third mixed case and will infer `--noHeader` when `--dynlib` is specified (case 4). Creation of a standalone wrapper (case 4) which does not require the header or library at compile time will require an explicit `--noHeader` and `--dynlib` for `ast2`.
|
Creation of a standalone wrapper (case 4) which does not require the header or library at compile time will require an explicit `--noHeader` and `--dynlib`.
|
||||||
|
|
||||||
More documentation on on these pragmas can be found in the Nim manual:
|
More documentation on on these pragmas can be found in the Nim manual:
|
||||||
- [{.importc.}](https://nim-lang.org/docs/manual.html#foreign-function-interface-importc-pragma)
|
- [{.importc.}](https://nim-lang.org/docs/manual.html#foreign-function-interface-importc-pragma)
|
||||||
|
|
@ -218,7 +218,7 @@ Options:
|
||||||
-d, --debug bool false enable debug output
|
-d, --debug bool false enable debug output
|
||||||
-D=, --defines= strings {} definitions to pass to preprocessor
|
-D=, --defines= strings {} definitions to pass to preprocessor
|
||||||
-l=, --dynlib= string "" {.dynlib.} pragma to import symbols - Nim const string or file path
|
-l=, --dynlib= string "" {.dynlib.} pragma to import symbols - Nim const string or file path
|
||||||
-f=, --feature= Features ast1 flags to enable experimental features
|
-f=, --feature= Features {} flags to enable experimental features
|
||||||
-I=, --includeDirs= strings {} include directory to pass to preprocessor
|
-I=, --includeDirs= strings {} include directory to pass to preprocessor
|
||||||
-m=, --mode= string "" language parser: c or cpp
|
-m=, --mode= string "" language parser: c or cpp
|
||||||
--nim= string "nim" use a particular Nim executable
|
--nim= string "nim" use a particular Nim executable
|
||||||
|
|
@ -226,12 +226,11 @@ Options:
|
||||||
-H, --noHeader bool false skip {.header.} pragma in wrapper
|
-H, --noHeader bool false skip {.header.} pragma in wrapper
|
||||||
-o=, --output= string "" file to output content - default: stdout
|
-o=, --output= string "" file to output content - default: stdout
|
||||||
-a, --past bool false print AST output
|
-a, --past bool false print AST output
|
||||||
-g, --pgrammar bool false print grammar
|
|
||||||
--pluginSourcePath= string "" nim file to build and load as a plugin
|
--pluginSourcePath= string "" nim file to build and load as a plugin
|
||||||
-n, --pnim bool false print Nim output
|
-n, --pnim bool false print Nim output
|
||||||
-E=, --prefix= strings {} strip prefix from identifiers
|
-E=, --prefix= strings {} strip prefix from identifiers
|
||||||
-p, --preprocess bool false run preprocessor on header
|
-p, --preprocess bool false run preprocessor on header
|
||||||
-r, --recurse bool false process #include files, implies --preprocess
|
-r, --recurse bool false process #include files - implies --preprocess
|
||||||
-G=, --replace= strings {} replace X with Y in identifiers, X1=Y1,X2=Y2, @X for regex
|
-G=, --replace= strings {} replace X with Y in identifiers, X1=Y1,X2=Y2, @X for regex
|
||||||
-s, --stub bool false stub out undefined type references as objects
|
-s, --stub bool false stub out undefined type references as objects
|
||||||
-F=, --suffix= strings {} strip suffix from identifiers
|
-F=, --suffix= strings {} strip suffix from identifiers
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "0.5.9"
|
version = "0.6.0"
|
||||||
author = "genotrance"
|
author = "genotrance"
|
||||||
description = "C/C++ interop for Nim"
|
description = "C/C++ interop for Nim"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
@ -55,15 +55,12 @@ task test, "Test":
|
||||||
execTest "tests/tast2.nim", "-d:NOHEADER"
|
execTest "tests/tast2.nim", "-d:NOHEADER"
|
||||||
|
|
||||||
execTest "tests/tnimterop_c.nim"
|
execTest "tests/tnimterop_c.nim"
|
||||||
execTest "tests/tnimterop_c.nim", "-d:FLAGS=\"-f:ast2\""
|
execTest "tests/tnimterop_c.nim", "-d:FLAGS=\"-H\""
|
||||||
execTest "tests/tnimterop_c.nim", "-d:FLAGS=\"-f:ast2 -H\""
|
|
||||||
|
|
||||||
execCmd "nim cpp --hints:off -f -r tests/tnimterop_cpp.nim"
|
execCmd "nim cpp --hints:off -f -r tests/tnimterop_cpp.nim"
|
||||||
execCmd "./nimterop/toast tests/toast.cfg tests/include/toast.h"
|
execCmd "./nimterop/toast tests/toast.cfg tests/include/toast.h"
|
||||||
execCmd "./nimterop/toast tests/toast.cfg -f:ast2 tests/include/toast.h"
|
|
||||||
|
|
||||||
execTest "tests/tpcre.nim"
|
execTest "tests/tpcre.nim"
|
||||||
execTest "tests/tpcre.nim", "-d:FLAGS=\"-f:ast2\""
|
|
||||||
|
|
||||||
when defined(Linux):
|
when defined(Linux):
|
||||||
execTest "tests/rsa.nim"
|
execTest "tests/rsa.nim"
|
||||||
|
|
@ -72,12 +69,10 @@ task test, "Test":
|
||||||
# Platform specific tests
|
# Platform specific tests
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
execTest "tests/tmath.nim"
|
execTest "tests/tmath.nim"
|
||||||
execTest "tests/tmath.nim", "-d:FLAGS=\"-f:ast2\""
|
execTest "tests/tmath.nim", "-d:FLAGS=\"-H\""
|
||||||
execTest "tests/tmath.nim", "-d:FLAGS=\"-f:ast2 -H\""
|
|
||||||
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
|
if defined(OSX) or defined(Windows) or not existsEnv("TRAVIS"):
|
||||||
execTest "tests/tsoloud.nim"
|
execTest "tests/tsoloud.nim"
|
||||||
execTest "tests/tsoloud.nim", "-d:FLAGS=\"-f:ast2\""
|
execTest "tests/tsoloud.nim", "-d:FLAGS=\"-H\""
|
||||||
execTest "tests/tsoloud.nim", "-d:FLAGS=\"-f:ast2 -H\""
|
|
||||||
|
|
||||||
# getHeader tests
|
# getHeader tests
|
||||||
withDir("tests"):
|
withDir("tests"):
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,6 @@ var
|
||||||
gNimExe* = ""
|
gNimExe* = ""
|
||||||
|
|
||||||
# Misc helpers
|
# Misc helpers
|
||||||
proc echoDebug(str: string) =
|
|
||||||
let str = "\n# " & str.strip().replace("\n", "\n# ")
|
|
||||||
when nimvm:
|
|
||||||
if gDebugCT: echo str
|
|
||||||
else:
|
|
||||||
if gDebug: echo str
|
|
||||||
|
|
||||||
proc sanitizePath*(path: string, noQuote = false, sep = $DirSep): string =
|
proc sanitizePath*(path: string, noQuote = false, sep = $DirSep): string =
|
||||||
result = path.multiReplace([("\\\\", sep), ("\\", sep), ("/", sep)])
|
result = path.multiReplace([("\\\\", sep), ("\\", sep), ("/", sep)])
|
||||||
|
|
@ -34,7 +28,7 @@ proc getCurrentNimCompiler*(): string =
|
||||||
else:
|
else:
|
||||||
result = gNimExe
|
result = gNimExe
|
||||||
|
|
||||||
template fixOutDir() {.dirty.} =
|
template fixOutDir() {.dirty, used.} =
|
||||||
let
|
let
|
||||||
outdir = if outdir.isAbsolute(): outdir else: getProjectDir() / outdir
|
outdir = if outdir.isAbsolute(): outdir else: getProjectDir() / outdir
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,6 @@ proc getLocalPath(header, outdir: string): string =
|
||||||
proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string, buildTypes: openArray[BuildType]): string =
|
proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string, buildTypes: openArray[BuildType]): string =
|
||||||
var
|
var
|
||||||
lpath = findFile(lname, outdir, regex = true)
|
lpath = findFile(lname, outdir, regex = true)
|
||||||
makeFlagsProc = &"-j {getNumProcs()} {makeFlags}"
|
|
||||||
makePath = outdir
|
makePath = outdir
|
||||||
|
|
||||||
if lpath.len != 0:
|
if lpath.len != 0:
|
||||||
|
|
@ -200,7 +199,7 @@ proc buildLibrary(lname, outdir, conFlags, cmakeFlags, makeFlags: string, buildT
|
||||||
let libraryExists = findFile(lname, buildStatus.buildPath, regex = true).len > 0
|
let libraryExists = findFile(lname, buildStatus.buildPath, regex = true).len > 0
|
||||||
|
|
||||||
if not libraryExists and fileExists(buildStatus.buildPath / "Makefile"):
|
if not libraryExists and fileExists(buildStatus.buildPath / "Makefile"):
|
||||||
make(buildStatus.buildPath, lname, makeFlagsProc, regex = true)
|
make(buildStatus.buildPath, lname, makeFlags, regex = true)
|
||||||
buildStatus.built = true
|
buildStatus.built = true
|
||||||
|
|
||||||
let error = if buildStatus.error.len > 0: buildStatus.error else: "No build files found in " & outdir
|
let error = if buildStatus.error.len > 0: buildStatus.error else: "No build files found in " & outdir
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,8 @@ proc linkLibs*(names: openArray[string], staticLink = true): string =
|
||||||
for res in resSet:
|
for res in resSet:
|
||||||
result &= " " & res
|
result &= " " & res
|
||||||
|
|
||||||
proc getNumProcs(): string =
|
proc getNumProcs*(): string =
|
||||||
|
## Get number of processors
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
getEnv("NUMBER_OF_PROCESSORS").strip()
|
getEnv("NUMBER_OF_PROCESSORS").strip()
|
||||||
elif defined(linux):
|
elif defined(linux):
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,13 @@ type
|
||||||
buildPath: string
|
buildPath: string
|
||||||
error: string
|
error: string
|
||||||
|
|
||||||
|
proc echoDebug(str: string) =
|
||||||
|
let str = "\n# " & str.strip().replace("\n", "\n# ")
|
||||||
|
when nimvm:
|
||||||
|
if gDebugCT: echo str
|
||||||
|
else:
|
||||||
|
if gDebug: echo str
|
||||||
|
|
||||||
proc configure*(path, check: string, flags = "") =
|
proc configure*(path, check: string, flags = "") =
|
||||||
## Run the GNU `configure` command to generate all Makefiles or other
|
## Run the GNU `configure` command to generate all Makefiles or other
|
||||||
## build scripts in the specified path
|
## build scripts in the specified path
|
||||||
|
|
@ -193,7 +200,7 @@ proc make*(path, check: string, flags = "", regex = false) =
|
||||||
cpFile(cmd, cmd.replace("mingw32-make", "make"))
|
cpFile(cmd, cmd.replace("mingw32-make", "make"))
|
||||||
doAssert cmd.len != 0, "Make not found"
|
doAssert cmd.len != 0, "Make not found"
|
||||||
|
|
||||||
cmd = &"cd {path.sanitizePath} && make"
|
cmd = &"cd {path.sanitizePath} && make -j {getNumProcs()}"
|
||||||
if flags.len != 0:
|
if flags.len != 0:
|
||||||
cmd &= &" {flags}"
|
cmd &= &" {flags}"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import tables
|
||||||
when defined(TOAST):
|
when defined(TOAST):
|
||||||
import sets, sequtils, strutils
|
import sets, sequtils, strutils
|
||||||
|
|
||||||
import regex
|
|
||||||
|
|
||||||
import "."/plugin
|
import "."/plugin
|
||||||
|
|
||||||
import compiler/[ast, idents, modulegraphs, options]
|
import compiler/[ast, idents, modulegraphs, options]
|
||||||
|
|
@ -13,7 +11,7 @@ when defined(TOAST):
|
||||||
|
|
||||||
type
|
type
|
||||||
Feature* = enum
|
Feature* = enum
|
||||||
ast1, ast2
|
ast2
|
||||||
|
|
||||||
State* = ref object
|
State* = ref object
|
||||||
# Command line arguments to toast - some forwarded from cimport.nim
|
# Command line arguments to toast - some forwarded from cimport.nim
|
||||||
|
|
@ -72,12 +70,6 @@ type
|
||||||
# Controls whether or not the current expression
|
# Controls whether or not the current expression
|
||||||
# should validate idents against currently defined idents
|
# should validate idents against currently defined idents
|
||||||
skipIdentValidation*: bool
|
skipIdentValidation*: bool
|
||||||
|
|
||||||
# Legacy AST fields, remove when ast2 becomes default
|
|
||||||
constStr*, enumStr*, procStr*, typeStr*: string
|
|
||||||
commentStr*, debugStr*, skipStr*: string
|
|
||||||
data*: seq[tuple[name, val: string]]
|
|
||||||
nodeBranch*: seq[string]
|
|
||||||
else:
|
else:
|
||||||
# cimport.nim specific
|
# cimport.nim specific
|
||||||
compile*: seq[string] # `cCompile()` list of files already processed
|
compile*: seq[string] # `cCompile()` list of files already processed
|
||||||
|
|
@ -114,23 +106,6 @@ when defined(TOAST):
|
||||||
].concat(toSeq(gExpressions.items))
|
].concat(toSeq(gExpressions.items))
|
||||||
|
|
||||||
type
|
type
|
||||||
Kind* = enum
|
|
||||||
exactlyOne
|
|
||||||
oneOrMore # +
|
|
||||||
zeroOrMore # *
|
|
||||||
zeroOrOne # ?
|
|
||||||
orWithNext # !
|
|
||||||
|
|
||||||
Ast* = object
|
|
||||||
name*: string
|
|
||||||
kind*: Kind
|
|
||||||
recursive*: bool
|
|
||||||
children*: seq[ref Ast]
|
|
||||||
tonim*: proc (ast: ref Ast, node: TSNode, gState: State)
|
|
||||||
regex*: Regex
|
|
||||||
|
|
||||||
AstTable* {.used.} = TableRef[string, seq[ref Ast]]
|
|
||||||
|
|
||||||
Status* = enum
|
Status* = enum
|
||||||
success, unknown, error
|
success, unknown, error
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import "."/treesitter/[api, c, cpp]
|
||||||
|
|
||||||
import "."/[build, globals]
|
import "."/[build, globals]
|
||||||
|
|
||||||
import "."/toastlib/[ast, ast2, getters, grammar, tshelp]
|
import "."/toastlib/[ast2, getters, tshelp]
|
||||||
|
|
||||||
proc process(gState: State, path: string, astTable: AstTable) =
|
proc process(gState: State, path: string) =
|
||||||
doAssert existsFile(path), &"Invalid path {path}"
|
doAssert existsFile(path), &"Invalid path {path}"
|
||||||
|
|
||||||
if gState.mode.Bl:
|
if gState.mode.Bl:
|
||||||
|
|
@ -21,10 +21,7 @@ proc process(gState: State, path: string, astTable: AstTable) =
|
||||||
if gState.past:
|
if gState.past:
|
||||||
gecho gState.printLisp(root)
|
gecho gState.printLisp(root)
|
||||||
elif gState.pnim:
|
elif gState.pnim:
|
||||||
if Feature.ast2 in gState.feature:
|
parseNim(gState, path, root)
|
||||||
ast2.parseNim(gState, path, root)
|
|
||||||
elif Feature.ast1 in gState.feature:
|
|
||||||
ast.parseNim(gState, path, root, astTable)
|
|
||||||
elif gState.preprocess:
|
elif gState.preprocess:
|
||||||
gecho gState.code
|
gecho gState.code
|
||||||
|
|
||||||
|
|
@ -43,7 +40,6 @@ proc main(
|
||||||
noHeader = false,
|
noHeader = false,
|
||||||
output = "",
|
output = "",
|
||||||
past = false,
|
past = false,
|
||||||
pgrammar = false,
|
|
||||||
pluginSourcePath: string = "",
|
pluginSourcePath: string = "",
|
||||||
pnim = false,
|
pnim = false,
|
||||||
prefix: seq[string] = @[],
|
prefix: seq[string] = @[],
|
||||||
|
|
@ -84,10 +80,6 @@ proc main(
|
||||||
build.gDebug = gState.debug
|
build.gDebug = gState.debug
|
||||||
build.gNimExe = gState.nim
|
build.gNimExe = gState.nim
|
||||||
|
|
||||||
# Default `ast` mode
|
|
||||||
if gState.feature.Bl:
|
|
||||||
gState.feature.add Feature.ast1
|
|
||||||
|
|
||||||
# Split some arguments with ,
|
# Split some arguments with ,
|
||||||
gState.symOverride = gState.symOverride.getSplitComma()
|
gState.symOverride = gState.symOverride.getSplitComma()
|
||||||
gState.prefix = gState.prefix.getSplitComma()
|
gState.prefix = gState.prefix.getSplitComma()
|
||||||
|
|
@ -137,31 +129,14 @@ proc main(
|
||||||
if gState.debug:
|
if gState.debug:
|
||||||
echo &"# Writing output to {outputFile}\n"
|
echo &"# Writing output to {outputFile}\n"
|
||||||
|
|
||||||
# Process grammar into AST
|
if source.nBl:
|
||||||
let
|
|
||||||
astTable =
|
|
||||||
if Feature.ast1 in gState.feature:
|
|
||||||
parseGrammar()
|
|
||||||
else:
|
|
||||||
nil
|
|
||||||
|
|
||||||
if pgrammar:
|
|
||||||
if Feature.ast1 in gState.feature:
|
|
||||||
# Print AST of grammar
|
|
||||||
gState.printGrammar(astTable)
|
|
||||||
elif source.nBl:
|
|
||||||
# Print source after preprocess or Nim output
|
# Print source after preprocess or Nim output
|
||||||
if gState.pnim:
|
if gState.pnim:
|
||||||
gState.initNim()
|
gState.initNim()
|
||||||
for src in source:
|
for src in source:
|
||||||
gState.process(src.expandSymlinkAbs(), astTable)
|
gState.process(src.expandSymlinkAbs())
|
||||||
if gState.pnim:
|
if gState.pnim:
|
||||||
if Feature.ast2 in gState.feature:
|
printNim(gState)
|
||||||
ast2.printNim(gState)
|
|
||||||
elif Feature.ast1 in gState.feature:
|
|
||||||
ast.printNim(gState)
|
|
||||||
gecho """{.hint: "The legacy wrapper generation algorithm is deprecated and will be removed in the next release of Nimterop.".}"""
|
|
||||||
gecho """{.hint: "Refer to CHANGES.md for details on migrating to the new backend.".}"""
|
|
||||||
|
|
||||||
# Close outputFile
|
# Close outputFile
|
||||||
if outputFile.len != 0:
|
if outputFile.len != 0:
|
||||||
|
|
@ -249,7 +224,6 @@ when isMainModule:
|
||||||
"noHeader": "skip {.header.} pragma in wrapper",
|
"noHeader": "skip {.header.} pragma in wrapper",
|
||||||
"output": "file to output content - default: stdout",
|
"output": "file to output content - default: stdout",
|
||||||
"past": "print AST output",
|
"past": "print AST output",
|
||||||
"pgrammar": "print grammar",
|
|
||||||
"pluginSourcePath": "nim file to build and load as a plugin",
|
"pluginSourcePath": "nim file to build and load as a plugin",
|
||||||
"pnim": "print Nim output",
|
"pnim": "print Nim output",
|
||||||
"prefix": "strip prefix from identifiers",
|
"prefix": "strip prefix from identifiers",
|
||||||
|
|
@ -273,7 +247,6 @@ when isMainModule:
|
||||||
"noHeader": 'H',
|
"noHeader": 'H',
|
||||||
"output": 'o',
|
"output": 'o',
|
||||||
"past": 'a',
|
"past": 'a',
|
||||||
"pgrammar": 'g',
|
|
||||||
"pnim": 'n',
|
"pnim": 'n',
|
||||||
"prefix": 'E',
|
"prefix": 'E',
|
||||||
"preprocess": 'p',
|
"preprocess": 'p',
|
||||||
|
|
|
||||||
|
|
@ -1,253 +0,0 @@
|
||||||
import hashes, macros, os, sets, strformat, strutils, tables
|
|
||||||
|
|
||||||
import regex
|
|
||||||
|
|
||||||
import ".."/[globals, treesitter/api]
|
|
||||||
import "."/[getters, tshelp]
|
|
||||||
|
|
||||||
proc getHeaderPragma*(gState: State): string =
|
|
||||||
result =
|
|
||||||
if not gState.noHeader and gState.dynlib.Bl:
|
|
||||||
&", header: {gState.currentHeader}"
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
proc getDynlib*(gState: State): string =
|
|
||||||
result =
|
|
||||||
if gState.dynlib.nBl:
|
|
||||||
&", dynlib: {gState.dynlib}"
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
proc getImportC*(gState: State, origName, nimName: string): string =
|
|
||||||
if nimName != origName:
|
|
||||||
result = &"importc: \"{origName}\"{gState.getHeaderPragma()}"
|
|
||||||
else:
|
|
||||||
result = gState.impShort
|
|
||||||
|
|
||||||
proc getPragma*(gState: State, pragmas: varargs[string]): string =
|
|
||||||
result = ""
|
|
||||||
for pragma in pragmas.items():
|
|
||||||
if pragma.nBl:
|
|
||||||
result &= pragma & ", "
|
|
||||||
if result.nBl:
|
|
||||||
result = " {." & result[0 .. ^3] & ".}"
|
|
||||||
|
|
||||||
result = result.replace(gState.impShort & ", cdecl", gState.impShort & "C")
|
|
||||||
|
|
||||||
let
|
|
||||||
dy = gState.getDynlib()
|
|
||||||
|
|
||||||
if ", cdecl" in result and dy.nBl:
|
|
||||||
result = result.replace(".}", dy & ".}")
|
|
||||||
|
|
||||||
proc saveNodeData(node: TSNode, gState: State): bool =
|
|
||||||
let name = $node.tsNodeType()
|
|
||||||
|
|
||||||
# Atoms are nodes whose values are to be saved
|
|
||||||
if name in gAtoms:
|
|
||||||
let
|
|
||||||
pname = node.getPxName(1)
|
|
||||||
ppname = node.getPxName(2)
|
|
||||||
pppname = node.getPxName(3)
|
|
||||||
ppppname = node.getPxName(4)
|
|
||||||
|
|
||||||
var
|
|
||||||
val = gState.getNodeVal(node)
|
|
||||||
|
|
||||||
# Skip since value already obtained from parent atom
|
|
||||||
if name == "primitive_type" and pname == "sized_type_specifier":
|
|
||||||
return true
|
|
||||||
|
|
||||||
# Skip since value already obtained from parent expression
|
|
||||||
if name in ["number_literal", "identifier"] and pname in gExpressions:
|
|
||||||
return true
|
|
||||||
|
|
||||||
# Add reference point in saved data for bitfield_clause
|
|
||||||
if name in ["number_literal"] and pname == "bitfield_clause":
|
|
||||||
gState.data.add(("bitfield_clause", val))
|
|
||||||
return true
|
|
||||||
|
|
||||||
# Process value as a type
|
|
||||||
if name in ["primitive_type", "sized_type_specifier"]:
|
|
||||||
val = val.getType()
|
|
||||||
|
|
||||||
if node.tsNodePrevNamedSibling().tsNodeIsNull():
|
|
||||||
if pname == "pointer_declarator":
|
|
||||||
if ppname notin ["function_declarator", "array_declarator"]:
|
|
||||||
gState.data.add(("pointer_declarator", ""))
|
|
||||||
elif ppname == "array_declarator":
|
|
||||||
gState.data.add(("array_pointer_declarator", ""))
|
|
||||||
|
|
||||||
# Double pointer
|
|
||||||
if ppname == "pointer_declarator":
|
|
||||||
gState.data.add(("pointer_declarator", ""))
|
|
||||||
elif pname in ["function_declarator", "array_declarator"]:
|
|
||||||
if ppname == "pointer_declarator":
|
|
||||||
gState.data.add(("pointer_declarator", ""))
|
|
||||||
if pppname == "pointer_declarator":
|
|
||||||
gState.data.add(("pointer_declarator", ""))
|
|
||||||
|
|
||||||
gState.data.add((name, val))
|
|
||||||
|
|
||||||
if pname == "pointer_declarator" and
|
|
||||||
ppname == "function_declarator":
|
|
||||||
if name == "field_identifier":
|
|
||||||
if pppname == "pointer_declarator":
|
|
||||||
gState.data.insert(("pointer_declarator", ""), gState.data.len-1)
|
|
||||||
if ppppname == "pointer_declarator":
|
|
||||||
gState.data.insert(("pointer_declarator", ""), gState.data.len-1)
|
|
||||||
gState.data.add(("function_declarator", ""))
|
|
||||||
elif name == "identifier":
|
|
||||||
gState.data.add(("pointer_declarator", ""))
|
|
||||||
|
|
||||||
# Save node value for a top-level expression
|
|
||||||
elif name in gExpressions and name != "escape_sequence":
|
|
||||||
if $node.tsNodeParent.tsNodeType() notin gExpressions:
|
|
||||||
gState.data.add((name, gState.getNodeVal(node)))
|
|
||||||
|
|
||||||
elif name in ["abstract_pointer_declarator", "enumerator", "field_declaration", "function_declarator"]:
|
|
||||||
gState.data.add((name.replace("abstract_", ""), ""))
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc searchAstForNode(ast: ref Ast, node: TSNode, gState: State): bool =
|
|
||||||
let
|
|
||||||
childNames = node.getTSNodeNamedChildNames().join()
|
|
||||||
|
|
||||||
if ast.isNil:
|
|
||||||
return
|
|
||||||
|
|
||||||
if gState.debug:
|
|
||||||
gState.nodeBranch.add $node.tsNodeType()
|
|
||||||
gecho "#" & spaces(gState.nodeBranch.len * 2) & gState.nodeBranch[^1]
|
|
||||||
|
|
||||||
if ast.children.nBl:
|
|
||||||
if childNames.contains(ast.regex) or
|
|
||||||
(childNames.Bl and ast.recursive):
|
|
||||||
if node.getTSNodeNamedChildCountSansComments() != 0:
|
|
||||||
var flag = true
|
|
||||||
|
|
||||||
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
|
||||||
if $node.tsNodeNamedChild(i).tsNodeType() != "comment":
|
|
||||||
let
|
|
||||||
nodeChild = node.tsNodeNamedChild(i)
|
|
||||||
astChild =
|
|
||||||
if not ast.recursive:
|
|
||||||
ast.getAstChildByName($nodeChild.tsNodeType())
|
|
||||||
else:
|
|
||||||
ast
|
|
||||||
|
|
||||||
if not searchAstForNode(astChild, nodeChild, gState):
|
|
||||||
flag = false
|
|
||||||
break
|
|
||||||
|
|
||||||
if flag:
|
|
||||||
result = node.saveNodeData(gState)
|
|
||||||
else:
|
|
||||||
result = node.saveNodeData(gState)
|
|
||||||
else:
|
|
||||||
if gState.debug:
|
|
||||||
gecho "#" & spaces(gState.nodeBranch.len * 2) & &" {ast.getRegexForAstChildren()} !=~ {childNames}"
|
|
||||||
elif node.getTSNodeNamedChildCountSansComments() == 0:
|
|
||||||
result = node.saveNodeData(gState)
|
|
||||||
|
|
||||||
if gState.debug:
|
|
||||||
discard gState.nodeBranch.pop()
|
|
||||||
if gState.nodeBranch.Bl:
|
|
||||||
gecho ""
|
|
||||||
|
|
||||||
proc searchAst(root: TSNode, astTable: AstTable, gState: State) =
|
|
||||||
var
|
|
||||||
node = root
|
|
||||||
nextnode: TSNode
|
|
||||||
depth = 0
|
|
||||||
|
|
||||||
while true:
|
|
||||||
if not node.tsNodeIsNull() and depth > -1:
|
|
||||||
let
|
|
||||||
name = $node.tsNodeType()
|
|
||||||
if name in astTable:
|
|
||||||
for ast in astTable[name]:
|
|
||||||
if gState.debug:
|
|
||||||
gecho "\n# " & gState.getNodeVal(node).replace("\n", "\n# ") & "\n"
|
|
||||||
if searchAstForNode(ast, node, gState):
|
|
||||||
ast.tonim(ast, node, gState)
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# " & gState.data.join("\n# ") & "\n"
|
|
||||||
break
|
|
||||||
gState.data = @[]
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
if $node.tsNodeType() notin astTable and node.tsNodeNamedChildCount() != 0:
|
|
||||||
nextnode = node.tsNodeNamedChild(0)
|
|
||||||
depth += 1
|
|
||||||
else:
|
|
||||||
nextnode = node.tsNodeNextNamedSibling()
|
|
||||||
|
|
||||||
if nextnode.tsNodeIsNull():
|
|
||||||
while true:
|
|
||||||
node = node.tsNodeParent()
|
|
||||||
depth -= 1
|
|
||||||
if depth == -1:
|
|
||||||
break
|
|
||||||
if node == root:
|
|
||||||
break
|
|
||||||
if not node.tsNodeNextNamedSibling().tsNodeIsNull():
|
|
||||||
node = node.tsNodeNextNamedSibling()
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
node = nextnode
|
|
||||||
|
|
||||||
if node == root:
|
|
||||||
break
|
|
||||||
|
|
||||||
proc parseNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable) =
|
|
||||||
# Generate Nim from tree-sitter AST root node
|
|
||||||
var
|
|
||||||
fp = fullpath.replace("\\", "/")
|
|
||||||
|
|
||||||
gState.currentHeader = getCurrentHeader(fullpath)
|
|
||||||
gState.impShort = gState.currentHeader.replace("header", "imp")
|
|
||||||
gState.sourceFile = fullpath
|
|
||||||
|
|
||||||
if not gState.noHeader and gState.dynlib.Bl:
|
|
||||||
gState.constStr &= &"\n {gState.currentHeader} {{.used.}} = \"{fp}\""
|
|
||||||
|
|
||||||
root.searchAst(astTable, gState)
|
|
||||||
|
|
||||||
proc printNim*(gState: State) =
|
|
||||||
# Print Nim generated by parseNim()
|
|
||||||
if gState.enumStr.nBl:
|
|
||||||
gecho &"{gState.enumStr}\n"
|
|
||||||
|
|
||||||
gState.constStr = gState.getOverrideFinal(nskConst) & gState.constStr
|
|
||||||
if gState.constStr.nBl:
|
|
||||||
gecho &"const{gState.constStr}\n"
|
|
||||||
|
|
||||||
gecho &"""
|
|
||||||
{{.pragma: {gState.impShort}, importc{gState.getHeaderPragma()}.}}
|
|
||||||
{{.pragma: {gState.impShort}C, {gState.impShort}, cdecl{gState.getDynlib()}.}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
gState.typeStr = gState.getOverrideFinal(nskType) & gState.typeStr
|
|
||||||
if gState.typeStr.nBl:
|
|
||||||
gecho &"type{gState.typeStr}\n"
|
|
||||||
|
|
||||||
gState.procStr = gState.getOverrideFinal(nskProc) & gState.procStr
|
|
||||||
if gState.procStr.nBl:
|
|
||||||
gecho &"{gState.procStr}\n"
|
|
||||||
|
|
||||||
gecho "{.pop.}"
|
|
||||||
|
|
||||||
if gState.debug:
|
|
||||||
if gState.debugStr.nBl:
|
|
||||||
gecho gState.debugStr
|
|
||||||
|
|
||||||
if gState.skipStr.nBl:
|
|
||||||
let
|
|
||||||
hash = gState.skipStr.hash().abs()
|
|
||||||
sname = getTempDir() / &"nimterop_{$hash}.h"
|
|
||||||
gecho &"# Writing skipped definitions to {sname}\n"
|
|
||||||
writeFile(sname, gState.skipStr)
|
|
||||||
|
|
@ -304,131 +304,6 @@ proc getPreprocessor*(gState: State, fullpath: string) =
|
||||||
rdata.add line
|
rdata.add line
|
||||||
gState.code = rdata.join("\n")
|
gState.code = rdata.join("\n")
|
||||||
|
|
||||||
converter toString*(kind: Kind): string =
|
|
||||||
return case kind:
|
|
||||||
of exactlyOne:
|
|
||||||
""
|
|
||||||
of oneOrMore:
|
|
||||||
"+"
|
|
||||||
of zeroOrMore:
|
|
||||||
"*"
|
|
||||||
of zeroOrOne:
|
|
||||||
"?"
|
|
||||||
of orWithNext:
|
|
||||||
"!"
|
|
||||||
|
|
||||||
converter toKind*(kind: string): Kind =
|
|
||||||
return case kind:
|
|
||||||
of "+":
|
|
||||||
oneOrMore
|
|
||||||
of "*":
|
|
||||||
zeroOrMore
|
|
||||||
of "?":
|
|
||||||
zeroOrOne
|
|
||||||
of "!":
|
|
||||||
orWithNext
|
|
||||||
else:
|
|
||||||
exactlyOne
|
|
||||||
|
|
||||||
proc getNameKind*(name: string): tuple[name: string, kind: Kind, recursive: bool] =
|
|
||||||
if name[0] == '^':
|
|
||||||
result.recursive = true
|
|
||||||
result.name = name[1 .. ^1]
|
|
||||||
else:
|
|
||||||
result.name = name
|
|
||||||
result.kind = $name[^1]
|
|
||||||
|
|
||||||
if result.kind != exactlyOne:
|
|
||||||
result.name = result.name[0 .. ^2]
|
|
||||||
|
|
||||||
proc getRegexForAstChildren*(ast: ref Ast): string =
|
|
||||||
result = "^"
|
|
||||||
for i in 0 .. ast.children.len-1:
|
|
||||||
let
|
|
||||||
kind: string = ast.children[i].kind
|
|
||||||
begin = if result[^1] == '|': "" else: "(?:"
|
|
||||||
case kind:
|
|
||||||
of "!":
|
|
||||||
result &= &"{begin}{ast.children[i].name}|"
|
|
||||||
else:
|
|
||||||
result &= &"{begin}{ast.children[i].name}){kind}"
|
|
||||||
result &= "$"
|
|
||||||
|
|
||||||
proc getAstChildByName*(ast: ref Ast, name: string): ref Ast =
|
|
||||||
for i in 0 .. ast.children.len-1:
|
|
||||||
if name in ast.children[i].name.split("|"):
|
|
||||||
return ast.children[i]
|
|
||||||
|
|
||||||
if ast.children.len == 1 and ast.children[0].name == ".":
|
|
||||||
return ast.children[0]
|
|
||||||
|
|
||||||
proc getNimExpression*(gState: State, expr: string, name = ""): string =
|
|
||||||
# Convert C/C++ expression into Nim - cast identifiers to `name` if specified
|
|
||||||
var
|
|
||||||
clean = expr.multiReplace([("\n", " "), ("\r", "")])
|
|
||||||
ident = ""
|
|
||||||
gen = ""
|
|
||||||
hex = false
|
|
||||||
|
|
||||||
for i in 0 .. clean.len:
|
|
||||||
if i != clean.len:
|
|
||||||
if clean[i] in IdentChars:
|
|
||||||
if clean[i] in Digits and ident.Bl:
|
|
||||||
# Identifiers cannot start with digits
|
|
||||||
gen = $clean[i]
|
|
||||||
elif clean[i] in HexDigits and hex == true:
|
|
||||||
# Part of a hex number
|
|
||||||
gen = $clean[i]
|
|
||||||
elif i > 0 and i < clean.len-1 and clean[i] in ['x', 'X'] and
|
|
||||||
clean[i-1] == '0' and clean[i+1] in HexDigits:
|
|
||||||
# Found a hex number
|
|
||||||
gen = $clean[i]
|
|
||||||
hex = true
|
|
||||||
else:
|
|
||||||
# Part of an identifier
|
|
||||||
ident &= clean[i]
|
|
||||||
hex = false
|
|
||||||
else:
|
|
||||||
gen = (block:
|
|
||||||
if (i == 0 or clean[i-1] != '\'') or
|
|
||||||
(i == clean.len - 1 or clean[i+1] != '\''):
|
|
||||||
# If unquoted, convert logical ops to Nim
|
|
||||||
case clean[i]
|
|
||||||
of '^': " xor "
|
|
||||||
of '&': " and "
|
|
||||||
of '|': " or "
|
|
||||||
of '~': " not "
|
|
||||||
else: $clean[i]
|
|
||||||
else:
|
|
||||||
$clean[i]
|
|
||||||
)
|
|
||||||
hex = false
|
|
||||||
|
|
||||||
if i == clean.len or gen.nBl:
|
|
||||||
# Process identifier
|
|
||||||
if ident.nBl:
|
|
||||||
# Issue #178
|
|
||||||
if ident != "_":
|
|
||||||
ident = gState.getIdentifier(ident, nskConst, name)
|
|
||||||
if name.nBl and ident in gState.constIdentifiers:
|
|
||||||
ident = ident & "." & name
|
|
||||||
result &= ident
|
|
||||||
ident = ""
|
|
||||||
result &= gen
|
|
||||||
gen = ""
|
|
||||||
|
|
||||||
# Convert shift ops to Nim
|
|
||||||
result = result.multiReplace([
|
|
||||||
("<<", " shl "), (">>", " shr ")
|
|
||||||
])
|
|
||||||
|
|
||||||
proc getComments*(gState: State, strip = false): string =
|
|
||||||
if not gState.noComments and gState.commentStr.nBl:
|
|
||||||
result = "\n" & gState.commentStr
|
|
||||||
if strip:
|
|
||||||
result = result.replace("\n ", "\n")
|
|
||||||
gState.commentStr = ""
|
|
||||||
|
|
||||||
# Plugin related
|
# Plugin related
|
||||||
|
|
||||||
proc dll*(path: string): string =
|
proc dll*(path: string): string =
|
||||||
|
|
|
||||||
|
|
@ -1,768 +0,0 @@
|
||||||
import macros, strformat, strutils, tables
|
|
||||||
|
|
||||||
import regex
|
|
||||||
|
|
||||||
import ".."/[globals, treesitter/api]
|
|
||||||
import "."/[ast, getters, lisp, tshelp]
|
|
||||||
|
|
||||||
type
|
|
||||||
Grammar = seq[tuple[grammar: string, call: proc(ast: ref Ast, node: TSNode, gState: State) {.nimcall.}]]
|
|
||||||
|
|
||||||
proc getPtrType(str: string): string =
|
|
||||||
result = case str:
|
|
||||||
of "ptr cchar":
|
|
||||||
"cstring"
|
|
||||||
of "ptr ptr cchar":
|
|
||||||
"ptr cstring"
|
|
||||||
of "ptr object":
|
|
||||||
"pointer"
|
|
||||||
of "ptr ptr object":
|
|
||||||
"ptr pointer"
|
|
||||||
of "ptr FILE":
|
|
||||||
"File"
|
|
||||||
else:
|
|
||||||
str
|
|
||||||
|
|
||||||
proc getLit(str: string): string =
|
|
||||||
# Used to convert #define literals into const
|
|
||||||
let
|
|
||||||
str = str.replace(re"/[/*].*?(?:\*/)?$", "").strip()
|
|
||||||
|
|
||||||
if str.contains(re"^[\-]?[\d]*[.]?[\d]+$") or # decimal
|
|
||||||
str.contains(re"^0x[\da-fA-F]+$") or # hexadecimal
|
|
||||||
str.contains(re"^'[[:ascii:]]'$") or # char
|
|
||||||
str.contains(re"""^"[[:ascii:]]+"$"""): # char *
|
|
||||||
return str
|
|
||||||
|
|
||||||
proc initGrammar(): Grammar =
|
|
||||||
# #define X Y
|
|
||||||
result.add(("""
|
|
||||||
(preproc_def
|
|
||||||
(identifier)
|
|
||||||
(preproc_arg)
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# define X Y"
|
|
||||||
|
|
||||||
let
|
|
||||||
name = gState.data[0].val
|
|
||||||
nname = gState.getIdentifier(name, nskConst)
|
|
||||||
val = gState.data[1].val.getLit()
|
|
||||||
|
|
||||||
if not nname.nBl:
|
|
||||||
let
|
|
||||||
override = gState.getOverride(name, nskConst)
|
|
||||||
if override.nBl:
|
|
||||||
gState.constStr &= &"{gState.getComments()}\n{override}"
|
|
||||||
else:
|
|
||||||
gState.constStr &= &"{gState.getComments()}\n # Const '{name}' skipped"
|
|
||||||
if gState.debug:
|
|
||||||
gState.skipStr &= &"\n{gState.getNodeVal(node)}"
|
|
||||||
elif val.nBl and gState.addNewIdentifer(nname):
|
|
||||||
gState.constStr &= &"{gState.getComments()}\n {nname}* = {val}"
|
|
||||||
))
|
|
||||||
|
|
||||||
let
|
|
||||||
typeGrammar = """
|
|
||||||
(type_qualifier?)
|
|
||||||
(primitive_type|type_identifier?)
|
|
||||||
(type_qualifier?)
|
|
||||||
(sized_type_specifier?
|
|
||||||
(primitive_type?)
|
|
||||||
)
|
|
||||||
(struct_specifier|union_specifier|enum_specifier?
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
arrGrammar = &"""
|
|
||||||
(array_declarator!
|
|
||||||
(pointer_declarator!
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
(type_identifier|identifier)
|
|
||||||
(identifier|number_literal)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
paramListGrammar = &"""
|
|
||||||
(parameter_list
|
|
||||||
(parameter_declaration*
|
|
||||||
{typeGrammar}
|
|
||||||
(identifier|type_identifier?)
|
|
||||||
(pointer_declarator?
|
|
||||||
(type_qualifier?)
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_qualifier?)
|
|
||||||
{arrGrammar}
|
|
||||||
(identifier|type_identifier)
|
|
||||||
)
|
|
||||||
{arrGrammar}
|
|
||||||
(identifier|type_identifier)
|
|
||||||
)
|
|
||||||
{arrGrammar}
|
|
||||||
(abstract_pointer_declarator?
|
|
||||||
(abstract_pointer_declarator?)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
funcGrammar = &"""
|
|
||||||
(function_declarator*
|
|
||||||
(identifier|type_identifier!)
|
|
||||||
(pointer_declarator
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
(type_identifier|identifier)
|
|
||||||
)
|
|
||||||
{paramListGrammar}
|
|
||||||
(noexcept|throw_specifier?)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
template funcParamCommon(fname, pname, ptyp, pptr, pout, count, i, flen: untyped): untyped =
|
|
||||||
ptyp = gState.getIdentifier(gState.data[i].val, nskType, fname).getType()
|
|
||||||
|
|
||||||
pptr = ""
|
|
||||||
while i+1 < gState.data.len and gState.data[i+1].name == "pointer_declarator":
|
|
||||||
pptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if i+1 < gState.data.len and gState.data[i+1].name == "identifier":
|
|
||||||
pname = gState.getIdentifier(gState.data[i+1].val, nskParam, fname)
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
pname = "a" & $count
|
|
||||||
count += 1
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if i < gState.data.len and gState.data[i].name in ["identifier", "number_literal"]:
|
|
||||||
flen = gState.data[i].val
|
|
||||||
if gState.data[i].name == "identifier":
|
|
||||||
flen = gState.getIdentifier(flen, nskConst, fname)
|
|
||||||
|
|
||||||
pout &= &"{pname}: array[{flen}, {getPtrType(pptr&ptyp)}], "
|
|
||||||
i += 1
|
|
||||||
elif pptr.nBl or ptyp != "object":
|
|
||||||
pout &= &"{pname}: {getPtrType(pptr&ptyp)}, "
|
|
||||||
|
|
||||||
# typedef int X
|
|
||||||
# typedef X Y
|
|
||||||
# typedef struct X Y
|
|
||||||
# typedef ?* Y
|
|
||||||
result.add((&"""
|
|
||||||
(type_definition
|
|
||||||
{typeGrammar}
|
|
||||||
(type_identifier!)
|
|
||||||
{arrGrammar}
|
|
||||||
(pointer_declarator!
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_identifier!)
|
|
||||||
{arrGrammar}
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
(type_identifier!)
|
|
||||||
{arrGrammar}
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# typedef X Y"
|
|
||||||
|
|
||||||
var
|
|
||||||
i = 0
|
|
||||||
typ = gState.getIdentifier(gState.data[i].val, nskType, "IgnoreSkipSymbol").getType()
|
|
||||||
name = ""
|
|
||||||
nname = ""
|
|
||||||
tptr = ""
|
|
||||||
aptr = ""
|
|
||||||
pragmas: seq[string] = @[]
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
while i < gState.data.len and "pointer" in gState.data[i].name:
|
|
||||||
case gState.data[i].name:
|
|
||||||
of "pointer_declarator":
|
|
||||||
tptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
of "array_pointer_declarator":
|
|
||||||
aptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if i < gState.data.len:
|
|
||||||
name = gState.data[i].val
|
|
||||||
nname = gState.getIdentifier(name, nskType)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if not gState.noHeader and gState.dynlib.Bl:
|
|
||||||
pragmas.add gState.getImportC(name, nname)
|
|
||||||
|
|
||||||
let
|
|
||||||
pragma = gState.getPragma(pragmas)
|
|
||||||
|
|
||||||
if not nname.nBl:
|
|
||||||
let
|
|
||||||
override = gState.getOverride(name, nskType)
|
|
||||||
if override.nBl:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n{override}"
|
|
||||||
elif nname notin gTypeMap and typ.nBl and gState.addNewIdentifer(nname):
|
|
||||||
if i < gState.data.len and gState.data[^1].name == "function_declarator":
|
|
||||||
var
|
|
||||||
fname = nname
|
|
||||||
pout, pname, ptyp, pptr = ""
|
|
||||||
count = 1
|
|
||||||
flen = ""
|
|
||||||
|
|
||||||
while i < gState.data.len:
|
|
||||||
if gState.data[i].name == "function_declarator":
|
|
||||||
break
|
|
||||||
|
|
||||||
funcParamCommon(fname, pname, ptyp, pptr, pout, count, i, flen)
|
|
||||||
|
|
||||||
if pout.nBl and pout[^2 .. ^1] == ", ":
|
|
||||||
pout = pout[0 .. ^3]
|
|
||||||
|
|
||||||
if tptr.nBl or typ != "object":
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = proc({pout}): {getPtrType(tptr&typ)} {{.cdecl.}}"
|
|
||||||
else:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = proc({pout}) {{.cdecl.}}"
|
|
||||||
else:
|
|
||||||
if i < gState.data.len and gState.data[i].name in ["identifier", "number_literal"]:
|
|
||||||
var
|
|
||||||
flen = gState.data[i].val
|
|
||||||
if gState.data[i].name == "identifier":
|
|
||||||
flen = gState.getIdentifier(flen, nskConst, nname)
|
|
||||||
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = {aptr}array[{flen}, {getPtrType(tptr&typ)}]"
|
|
||||||
else:
|
|
||||||
if nname == typ:
|
|
||||||
pragmas.add "incompleteStruct"
|
|
||||||
let
|
|
||||||
pragma = gState.getPragma(pragmas)
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = object"
|
|
||||||
else:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = {getPtrType(tptr&typ)}"
|
|
||||||
))
|
|
||||||
|
|
||||||
proc pDupTypeCommon(nname: string, fend: int, gState: State, isEnum=false) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# pDupTypeCommon()"
|
|
||||||
|
|
||||||
var
|
|
||||||
dname = gState.data[^1].val
|
|
||||||
ndname = gState.getIdentifier(dname, nskType)
|
|
||||||
dptr =
|
|
||||||
if fend == 2:
|
|
||||||
"ptr "
|
|
||||||
else:
|
|
||||||
""
|
|
||||||
|
|
||||||
if ndname.nBl and ndname != nname:
|
|
||||||
if isEnum:
|
|
||||||
if gState.addNewIdentifer(ndname):
|
|
||||||
gState.enumStr &= &"{gState.getComments(true)}\ntype {ndname}* = {dptr}{nname}"
|
|
||||||
else:
|
|
||||||
if gState.addNewIdentifer(ndname):
|
|
||||||
let
|
|
||||||
pragma = gState.getPragma(gState.getImportc(dname, ndname), "bycopy")
|
|
||||||
gState.typeStr &=
|
|
||||||
&"{gState.getComments()}\n {ndname}*{pragma} = {dptr}{nname}"
|
|
||||||
|
|
||||||
proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# pStructCommon"
|
|
||||||
|
|
||||||
var
|
|
||||||
nname = gState.getIdentifier(name, nskType)
|
|
||||||
prefix = ""
|
|
||||||
union = ""
|
|
||||||
|
|
||||||
case $node.tsNodeType():
|
|
||||||
of "struct_specifier":
|
|
||||||
prefix = "struct "
|
|
||||||
of "union_specifier":
|
|
||||||
prefix = "union "
|
|
||||||
union = ", union"
|
|
||||||
of "type_definition":
|
|
||||||
if node.getTSNodeNamedChildCountSansComments() != 0:
|
|
||||||
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
|
||||||
let
|
|
||||||
nchild = $node.tsNodeNamedChild(i).tsNodeType()
|
|
||||||
if nchild != "comment":
|
|
||||||
case nchild:
|
|
||||||
of "struct_specifier":
|
|
||||||
if fstart == 1:
|
|
||||||
prefix = "struct "
|
|
||||||
of "union_specifier":
|
|
||||||
if fstart == 1:
|
|
||||||
prefix = "union "
|
|
||||||
union = ", union"
|
|
||||||
break
|
|
||||||
|
|
||||||
if not nname.nBl:
|
|
||||||
let
|
|
||||||
override = gState.getOverride(name, nskType)
|
|
||||||
if override.nBl:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n{override}"
|
|
||||||
elif gState.addNewIdentifer(nname):
|
|
||||||
if gState.data.len == 1:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}* {{.bycopy{union}.}} = object"
|
|
||||||
else:
|
|
||||||
var
|
|
||||||
pragmas: seq[string] = @[]
|
|
||||||
if not gState.noHeader and gState.dynlib.Bl:
|
|
||||||
pragmas.add gState.getImportC(prefix & name, nname)
|
|
||||||
pragmas.add "bycopy"
|
|
||||||
if union.nBl:
|
|
||||||
pragmas.add "union"
|
|
||||||
|
|
||||||
let
|
|
||||||
pragma = gState.getPragma(pragmas)
|
|
||||||
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {nname}*{pragma} = object"
|
|
||||||
|
|
||||||
var
|
|
||||||
i = fstart
|
|
||||||
ftyp, fname: string
|
|
||||||
fptr = ""
|
|
||||||
aptr = ""
|
|
||||||
flen = ""
|
|
||||||
while i < gState.data.len-fend:
|
|
||||||
fptr = ""
|
|
||||||
aptr = ""
|
|
||||||
if gState.data[i].name == "field_declaration":
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if gState.data[i].name notin ["field_identifier", "pointer_declarator", "array_pointer_declarator"]:
|
|
||||||
ftyp = gState.getIdentifier(gState.data[i].val, nskType, nname).getType()
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
while i < gState.data.len-fend and "pointer" in gState.data[i].name:
|
|
||||||
case gState.data[i].name:
|
|
||||||
of "pointer_declarator":
|
|
||||||
fptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
of "array_pointer_declarator":
|
|
||||||
aptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
fname = gState.getIdentifier(gState.data[i].val, nskField, nname)
|
|
||||||
|
|
||||||
if i+1 < gState.data.len-fend and gState.data[i+1].name in gEnumVals:
|
|
||||||
# Struct field is an array where size is an expression
|
|
||||||
var
|
|
||||||
flen = gState.getNimExpression(gState.data[i+1].val)
|
|
||||||
if "/" in flen:
|
|
||||||
flen = &"({flen}).int"
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}*: {aptr}array[{flen}, {getPtrType(fptr&ftyp)}]"
|
|
||||||
i += 2
|
|
||||||
elif i+1 < gState.data.len-fend and gState.data[i+1].name == "bitfield_clause":
|
|
||||||
let
|
|
||||||
size = gState.data[i+1].val
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}* {{.bitsize: {size}.}} : {getPtrType(fptr&ftyp)} "
|
|
||||||
i += 2
|
|
||||||
elif i+1 < gState.data.len-fend and gState.data[i+1].name == "function_declarator":
|
|
||||||
var
|
|
||||||
pout, pname, ptyp, pptr = ""
|
|
||||||
count = 1
|
|
||||||
|
|
||||||
i += 2
|
|
||||||
while i < gState.data.len-fend:
|
|
||||||
if gState.data[i].name == "function_declarator":
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
if gState.data[i].name == "field_declaration":
|
|
||||||
break
|
|
||||||
|
|
||||||
funcParamCommon(fname, pname, ptyp, pptr, pout, count, i, flen)
|
|
||||||
|
|
||||||
if pout.nBl and pout[^2 .. ^1] == ", ":
|
|
||||||
pout = pout[0 .. ^3]
|
|
||||||
if fptr.nBl or ftyp != "object":
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}*: proc({pout}): {getPtrType(fptr&ftyp)} {{.cdecl.}}"
|
|
||||||
else:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}*: proc({pout}) {{.cdecl.}}"
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
if ftyp == "object":
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}*: pointer"
|
|
||||||
else:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n {fname}*: {getPtrType(fptr&ftyp)}"
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
if node.tsNodeType() == "type_definition" and
|
|
||||||
gState.data[^1].name == "type_identifier" and gState.data[^1].val.nBl:
|
|
||||||
pDupTypeCommon(nname, fend, gState, false)
|
|
||||||
|
|
||||||
let
|
|
||||||
fieldGrammar = &"""
|
|
||||||
(field_identifier!)
|
|
||||||
(bitfield_clause!
|
|
||||||
(number_literal)
|
|
||||||
)
|
|
||||||
(array_declarator!
|
|
||||||
(field_identifier!)
|
|
||||||
(pointer_declarator
|
|
||||||
(pointer_declarator!
|
|
||||||
(field_identifier)
|
|
||||||
)
|
|
||||||
(field_identifier)
|
|
||||||
)
|
|
||||||
(^$1+)
|
|
||||||
)
|
|
||||||
(function_declarator+
|
|
||||||
(pointer_declarator
|
|
||||||
(pointer_declarator!
|
|
||||||
(field_identifier)
|
|
||||||
)
|
|
||||||
(field_identifier)
|
|
||||||
)
|
|
||||||
{paramListGrammar}
|
|
||||||
)
|
|
||||||
""" % gEnumVals.join("|")
|
|
||||||
|
|
||||||
fieldListGrammar = &"""
|
|
||||||
(field_declaration_list?
|
|
||||||
(field_declaration+
|
|
||||||
{typeGrammar}
|
|
||||||
(pointer_declarator!
|
|
||||||
(pointer_declarator!
|
|
||||||
{fieldGrammar}
|
|
||||||
)
|
|
||||||
{fieldGrammar}
|
|
||||||
)
|
|
||||||
{fieldGrammar}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# struct X {}
|
|
||||||
result.add((&"""
|
|
||||||
(struct_specifier|union_specifier
|
|
||||||
(type_identifier)
|
|
||||||
{fieldListGrammar}
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# struct X {}"
|
|
||||||
|
|
||||||
pStructCommon(ast, node, gState.data[0].val, 1, 1, gState)
|
|
||||||
))
|
|
||||||
|
|
||||||
# typedef struct X {}
|
|
||||||
result.add((&"""
|
|
||||||
(type_definition
|
|
||||||
(struct_specifier|union_specifier
|
|
||||||
(type_identifier?)
|
|
||||||
{fieldListGrammar}
|
|
||||||
)
|
|
||||||
(type_identifier!)
|
|
||||||
(pointer_declarator
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# typedef struct X {}"
|
|
||||||
|
|
||||||
var
|
|
||||||
fstart = 0
|
|
||||||
fend = 1
|
|
||||||
|
|
||||||
if gState.data[^2].name == "pointer_declarator":
|
|
||||||
fend = 2
|
|
||||||
|
|
||||||
if gState.data.len > 1 and
|
|
||||||
gState.data[0].name == "type_identifier" and
|
|
||||||
gState.data[1].name notin ["field_identifier", "pointer_declarator"]:
|
|
||||||
|
|
||||||
fstart = 1
|
|
||||||
pStructCommon(ast, node, gState.data[0].val, fstart, fend, gState)
|
|
||||||
else:
|
|
||||||
pStructCommon(ast, node, gState.data[^1].val, fstart, fend, gState)
|
|
||||||
))
|
|
||||||
|
|
||||||
proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# pEnumCommon()"
|
|
||||||
|
|
||||||
let nname =
|
|
||||||
if name.Bl:
|
|
||||||
getUniqueIdentifier(gState, "Enum")
|
|
||||||
else:
|
|
||||||
gState.getIdentifier(name, nskType)
|
|
||||||
|
|
||||||
if nname.nBl and gState.addNewIdentifer(nname):
|
|
||||||
gState.enumStr &= &"{gState.getComments(true)}\ndefineEnum({nname})"
|
|
||||||
|
|
||||||
var
|
|
||||||
i = fstart
|
|
||||||
count = 0
|
|
||||||
while i < gState.data.len-fend:
|
|
||||||
if gState.data[i].name == "enumerator":
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
let
|
|
||||||
fname = gState.getIdentifier(gState.data[i].val, nskEnumField)
|
|
||||||
|
|
||||||
if i+1 < gState.data.len-fend and
|
|
||||||
gState.data[i+1].name in gEnumVals:
|
|
||||||
if fname.nBl and gState.addNewIdentifer(fname):
|
|
||||||
gState.constStr &= &"{gState.getComments()}\n {fname}* = ({gState.getNimExpression(gState.data[i+1].val)}).{nname}"
|
|
||||||
try:
|
|
||||||
count = gState.data[i+1].val.parseInt() + 1
|
|
||||||
except:
|
|
||||||
count += 1
|
|
||||||
i += 2
|
|
||||||
else:
|
|
||||||
if fname.nBl and gState.addNewIdentifer(fname):
|
|
||||||
gState.constStr &= &"{gState.getComments()}\n {fname}* = {count}.{nname}"
|
|
||||||
i += 1
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
if node.tsNodeType() == "type_definition" and
|
|
||||||
gState.data[^1].name == "type_identifier" and gState.data[^1].val.nBl:
|
|
||||||
pDupTypeCommon(nname, fend, gState, true)
|
|
||||||
|
|
||||||
# enum X {}
|
|
||||||
result.add(("""
|
|
||||||
(enum_specifier
|
|
||||||
(type_identifier?)
|
|
||||||
(enumerator_list
|
|
||||||
(enumerator+
|
|
||||||
(identifier?)
|
|
||||||
(^$1+)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
""" % gEnumVals.join("|"),
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# enum X {}"
|
|
||||||
|
|
||||||
var
|
|
||||||
name = ""
|
|
||||||
offset = 0
|
|
||||||
|
|
||||||
if gState.data[0].name == "type_identifier":
|
|
||||||
name = gState.data[0].val
|
|
||||||
offset = 1
|
|
||||||
|
|
||||||
pEnumCommon(ast, node, name, offset, 0, gState)
|
|
||||||
))
|
|
||||||
|
|
||||||
# typedef enum {} X
|
|
||||||
result.add((&"""
|
|
||||||
(type_definition
|
|
||||||
{result[^1].grammar}
|
|
||||||
(type_identifier!)
|
|
||||||
(pointer_declarator
|
|
||||||
(pointer_declarator!
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
(type_identifier)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# typedef enum {}"
|
|
||||||
|
|
||||||
var
|
|
||||||
fstart = 0
|
|
||||||
fend = 1
|
|
||||||
|
|
||||||
if gState.data[^2].name == "pointer_declarator":
|
|
||||||
fend = 2
|
|
||||||
|
|
||||||
if gState.data[0].name == "type_identifier":
|
|
||||||
fstart = 1
|
|
||||||
|
|
||||||
pEnumCommon(ast, node, gState.data[0].val, fstart, fend, gState)
|
|
||||||
else:
|
|
||||||
pEnumCommon(ast, node, gState.data[^1].val, fstart, fend, gState)
|
|
||||||
))
|
|
||||||
|
|
||||||
# typ function(typ param1, ...)
|
|
||||||
result.add((&"""
|
|
||||||
(declaration
|
|
||||||
(storage_class_specifier?)
|
|
||||||
{typeGrammar}
|
|
||||||
(pointer_declarator!
|
|
||||||
(pointer_declarator!
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
{funcGrammar}
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
if gState.debug:
|
|
||||||
gState.debugStr &= "\n# typ function"
|
|
||||||
|
|
||||||
var
|
|
||||||
fptr = ""
|
|
||||||
i = 1
|
|
||||||
|
|
||||||
while i < gState.data.len:
|
|
||||||
if gState.data[i].name == "function_declarator":
|
|
||||||
i += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
fptr = ""
|
|
||||||
while i < gState.data.len and gState.data[i].name == "pointer_declarator":
|
|
||||||
fptr &= "ptr "
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
var
|
|
||||||
fname = gState.data[i].val
|
|
||||||
fnname = gState.getIdentifier(fname, nskProc)
|
|
||||||
pout, pname, ptyp, pptr = ""
|
|
||||||
count = 1
|
|
||||||
flen = ""
|
|
||||||
fVar = false
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
if i < gState.data.len and gState.data[i].name == "pointer_declarator":
|
|
||||||
fVar = true
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
while i < gState.data.len:
|
|
||||||
if gState.data[i].name == "function_declarator":
|
|
||||||
break
|
|
||||||
|
|
||||||
funcParamCommon(fnname, pname, ptyp, pptr, pout, count, i, flen)
|
|
||||||
|
|
||||||
if pout.nBl and pout[^2 .. ^1] == ", ":
|
|
||||||
pout = pout[0 .. ^3]
|
|
||||||
|
|
||||||
if not fnname.nBl:
|
|
||||||
let
|
|
||||||
override = gState.getOverride(fname, nskProc)
|
|
||||||
if override.nBl:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n{override}"
|
|
||||||
elif gState.addNewIdentifer(fnname):
|
|
||||||
let
|
|
||||||
ftyp = gState.getIdentifier(gState.data[0].val, nskType, fnname).getType()
|
|
||||||
pragma = gState.getPragma(gState.getImportC(fname, fnname), "cdecl")
|
|
||||||
|
|
||||||
if fptr.nBl or ftyp != "object":
|
|
||||||
if fVar:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\nvar {fnname}*: proc ({pout}): {getPtrType(fptr&ftyp)}{{.cdecl.}}"
|
|
||||||
else:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\nproc {fnname}*({pout}): {getPtrType(fptr&ftyp)}{pragma}"
|
|
||||||
else:
|
|
||||||
if fVar:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\nvar {fnname}*: proc ({pout}){{.cdecl.}}"
|
|
||||||
else:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\nproc {fnname}*({pout}){pragma}"
|
|
||||||
))
|
|
||||||
|
|
||||||
# // comment
|
|
||||||
result.add((&"""
|
|
||||||
(comment
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
let
|
|
||||||
cmt = $gState.getNodeVal(node)
|
|
||||||
|
|
||||||
for line in cmt.splitLines():
|
|
||||||
let
|
|
||||||
line = line.multiReplace([("//", ""), ("/*", ""), ("*/", "")])
|
|
||||||
|
|
||||||
gState.commentStr &= &"\n # {line.strip(leading=false)}"
|
|
||||||
))
|
|
||||||
|
|
||||||
# // unknown
|
|
||||||
result.add((&"""
|
|
||||||
(type_definition|struct_specifier|union_specifier|enum_specifier|declaration
|
|
||||||
(^.*)
|
|
||||||
)
|
|
||||||
""",
|
|
||||||
proc (ast: ref Ast, node: TSNode, gState: State) =
|
|
||||||
var
|
|
||||||
done = false
|
|
||||||
for i in gState.data:
|
|
||||||
case $node.tsNodeType()
|
|
||||||
of "declaration":
|
|
||||||
if i.name == "identifier":
|
|
||||||
let
|
|
||||||
override = gState.getOverride(i.val, nskProc)
|
|
||||||
|
|
||||||
if override.nBl:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\n{override}"
|
|
||||||
done = true
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
gState.procStr &= &"{gState.getComments(true)}\n# Declaration '{i.val}' skipped"
|
|
||||||
|
|
||||||
else:
|
|
||||||
if i.name == "type_identifier":
|
|
||||||
let
|
|
||||||
override = gState.getOverride(i.val, nskType)
|
|
||||||
|
|
||||||
if override.nBl:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n{override}"
|
|
||||||
done = true
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
gState.typeStr &= &"{gState.getComments()}\n # Type '{i.val}' skipped"
|
|
||||||
|
|
||||||
if gState.debug and not done:
|
|
||||||
gState.skipStr &= &"\n{gState.getNodeVal(node)}"
|
|
||||||
))
|
|
||||||
|
|
||||||
proc initRegex(ast: ref Ast) =
|
|
||||||
if ast.children.nBl:
|
|
||||||
if not ast.recursive:
|
|
||||||
for child in ast.children:
|
|
||||||
child.initRegex()
|
|
||||||
|
|
||||||
var
|
|
||||||
reg: string
|
|
||||||
try:
|
|
||||||
reg = ast.getRegexForAstChildren()
|
|
||||||
ast.regex = reg.re()
|
|
||||||
except:
|
|
||||||
echo reg
|
|
||||||
raise newException(Exception, getCurrentExceptionMsg())
|
|
||||||
|
|
||||||
proc parseGrammar*(): AstTable =
|
|
||||||
const grammars = initGrammar()
|
|
||||||
|
|
||||||
result = newTable[string, seq[ref Ast]]()
|
|
||||||
for i in 0 .. grammars.len-1:
|
|
||||||
var
|
|
||||||
ast = grammars[i].grammar.parseLisp()
|
|
||||||
|
|
||||||
ast.tonim = grammars[i].call
|
|
||||||
ast.initRegex()
|
|
||||||
for n in ast.name.split("|"):
|
|
||||||
if n notin result:
|
|
||||||
result[n] = @[ast]
|
|
||||||
else:
|
|
||||||
result[n].add(ast)
|
|
||||||
|
|
||||||
proc printGrammar*(gState: State, astTable: AstTable) =
|
|
||||||
for name in astTable.keys():
|
|
||||||
for ast in astTable[name]:
|
|
||||||
gecho ast.printAst()
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
import ".."/globals
|
|
||||||
import "."/getters
|
|
||||||
|
|
||||||
var
|
|
||||||
gTokens: seq[string]
|
|
||||||
idx = 0
|
|
||||||
|
|
||||||
proc tokenize(tree: string) =
|
|
||||||
var collect = ""
|
|
||||||
|
|
||||||
gTokens = @[]
|
|
||||||
idx = 0
|
|
||||||
for i in tree:
|
|
||||||
case i:
|
|
||||||
of ' ', '\n', '\r', '(', ')':
|
|
||||||
if collect.nBl:
|
|
||||||
gTokens.add(collect)
|
|
||||||
collect = ""
|
|
||||||
if i in ['(', ')']:
|
|
||||||
gTokens.add($i)
|
|
||||||
else:
|
|
||||||
collect &= $i
|
|
||||||
|
|
||||||
proc readFromTokens(): ref Ast =
|
|
||||||
if idx == gTokens.len:
|
|
||||||
doAssert false, "Bad AST " & $(idx: idx)
|
|
||||||
|
|
||||||
if gTokens[idx] == "(":
|
|
||||||
if gTokens.len - idx < 2:
|
|
||||||
doAssert false, "Corrupt AST " & $(gTokensLen: gTokens.len, idx: idx)
|
|
||||||
result = new(Ast)
|
|
||||||
(result.name, result.kind, result.recursive) = gTokens[idx+1].getNameKind()
|
|
||||||
result.children = @[]
|
|
||||||
if result.recursive:
|
|
||||||
result.children.add(result)
|
|
||||||
idx += 2
|
|
||||||
while gTokens[idx] != ")":
|
|
||||||
var res = readFromTokens()
|
|
||||||
if not res.isNil:
|
|
||||||
result.children.add(res)
|
|
||||||
elif gTokens[idx] == ")":
|
|
||||||
doAssert false, "Poor AST " & $(idx: idx)
|
|
||||||
|
|
||||||
idx += 1
|
|
||||||
|
|
||||||
proc printAst*(node: ref Ast, offset=""): string =
|
|
||||||
result = offset & "(" & (if node.recursive: "^" else: "") & node.name & node.kind.toString()
|
|
||||||
|
|
||||||
if node.children.nBl and not node.recursive:
|
|
||||||
result &= "\n"
|
|
||||||
for child in node.children:
|
|
||||||
result &= printAst(child, offset & " ")
|
|
||||||
result &= offset & ")\n"
|
|
||||||
else:
|
|
||||||
result &= ")\n"
|
|
||||||
|
|
||||||
proc parseLisp*(tree: string): ref Ast =
|
|
||||||
tokenize(tree)
|
|
||||||
|
|
||||||
return readFromTokens()
|
|
||||||
|
|
@ -2,7 +2,6 @@ import sets, strformat, strutils
|
||||||
|
|
||||||
import ".."/treesitter/[api, c, cpp]
|
import ".."/treesitter/[api, c, cpp]
|
||||||
import ".."/globals
|
import ".."/globals
|
||||||
import "."/getters
|
|
||||||
|
|
||||||
template withCodeAst*(code: string, mode: string, body: untyped): untyped =
|
template withCodeAst*(code: string, mode: string, body: untyped): untyped =
|
||||||
## A simple template to inject the TSNode into a body of code
|
## A simple template to inject the TSNode into a body of code
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ proc testCall(cmd, output: string, exitCode: int, delete = true) =
|
||||||
doAssert outp.contains(output), outp
|
doAssert outp.contains(output), outp
|
||||||
|
|
||||||
var
|
var
|
||||||
cmd = "nim c -f --hints:off -d:FLAGS=\"-f:ast2\" -d:checkAbi"
|
cmd = "nim c -f --hints:off -d:checkAbi"
|
||||||
lrcmd = " -r lzma.nim"
|
lrcmd = " -r lzma.nim"
|
||||||
zrcmd = " -r zlib.nim"
|
zrcmd = " -r zlib.nim"
|
||||||
sshcmd = " -r libssh2.nim"
|
sshcmd = " -r libssh2.nim"
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ cOverride:
|
||||||
SOCKET = object
|
SOCKET = object
|
||||||
|
|
||||||
when not libssh2Static:
|
when not libssh2Static:
|
||||||
cImport(libssh2Path, recurse = true, dynlib = "libssh2LPath", flags = "-f:ast2 -c -E_ -F_")
|
cImport(libssh2Path, recurse = true, dynlib = "libssh2LPath", flags = "-c -E_ -F_")
|
||||||
|
|
||||||
when not defined(Windows) and not isDefined(libssh2JBB):
|
when not defined(Windows) and not isDefined(libssh2JBB):
|
||||||
proc zlibVersion(): cstring {.importc, dynlib: libssh2LPath.}
|
proc zlibVersion(): cstring {.importc, dynlib: libssh2LPath.}
|
||||||
else:
|
else:
|
||||||
cImport(libssh2Path, recurse = true, flags = "-f:ast2 -c -E_ -F_")
|
cImport(libssh2Path, recurse = true, flags = "-c -E_ -F_")
|
||||||
|
|
||||||
when not defined(Windows) and not isDefined(libssh2JBB):
|
when not defined(Windows) and not isDefined(libssh2JBB):
|
||||||
proc zlibVersion(): cstring {.importc.}
|
proc zlibVersion(): cstring {.importc.}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ cOverride:
|
||||||
cImport(@[
|
cImport(@[
|
||||||
basePath / "rsa.h",
|
basePath / "rsa.h",
|
||||||
basePath / "err.h",
|
basePath / "err.h",
|
||||||
], recurse = true, flags = "-f:ast2 -s -c " & FLAGS)
|
], recurse = true, flags = "-s -c " & FLAGS)
|
||||||
|
|
||||||
{.passL: cryptoLPath.}
|
{.passL: cryptoLPath.}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue