Compare commits
19 commits
master
...
ast2_comme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae5a3f7e7a | ||
|
|
6895132749 | ||
|
|
42fbaf4c4f | ||
|
|
83a63881f1 | ||
|
|
14e42a0a22 | ||
|
|
e24ced7826 | ||
|
|
2bd8b297a9 | ||
|
|
2faebddcaa | ||
|
|
63367a16a5 | ||
|
|
418e5db825 | ||
|
|
c083b443e4 | ||
|
|
522178913e | ||
|
|
df3e73e965 | ||
|
|
c78dfd087c | ||
|
|
8ecac1f09c | ||
|
|
6a8d05dae2 | ||
|
|
f2975fde55 | ||
|
|
4ea1f0f340 | ||
|
|
dac496e6c2 |
7 changed files with 214 additions and 40 deletions
|
|
@ -83,7 +83,7 @@ for:
|
||||||
- /home/appveyor/binaries
|
- /home/appveyor/binaries
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- nimble --verbose install -y
|
- nimble --verbose develop -y
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- nimble --verbose test
|
- nimble --verbose test
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,21 @@ installDirs = @["nimterop"]
|
||||||
requires "nim >= 0.20.2", "regex >= 0.14.1", "cligen >= 0.9.45"
|
requires "nim >= 0.20.2", "regex >= 0.14.1", "cligen >= 0.9.45"
|
||||||
|
|
||||||
import nimterop/docs
|
import nimterop/docs
|
||||||
|
import os
|
||||||
|
|
||||||
proc execCmd(cmd: string) =
|
proc execCmd(cmd: string) =
|
||||||
exec "tests/timeit " & cmd
|
exec "tests/timeit " & cmd
|
||||||
|
|
||||||
proc execTest(test: string, flags = "") =
|
proc execTest(test: string, flags = "", runDocs = true) =
|
||||||
execCmd "nim c --hints:off -f " & flags & " -r " & test
|
execCmd "nim c --hints:off -f " & flags & " -r " & test
|
||||||
execCmd "nim cpp --hints:off " & flags & " -r " & test
|
execCmd "nim cpp --hints:off " & flags & " -r " & test
|
||||||
|
|
||||||
|
if runDocs:
|
||||||
|
let docPath = "build/html_" & test.extractFileName.changeFileExt("") & "_docs"
|
||||||
|
rmDir docPath
|
||||||
|
mkDir docPath
|
||||||
|
buildDocs(@[test], docPath, nimArgs = flags)
|
||||||
|
|
||||||
task buildToast, "build toast":
|
task buildToast, "build toast":
|
||||||
execCmd("nim c --hints:off nimterop/toast.nim")
|
execCmd("nim c --hints:off nimterop/toast.nim")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -691,6 +691,7 @@ proc newRecListTree(gState: State, name: string, node: TSNode): PNode =
|
||||||
let
|
let
|
||||||
fdecl = node[i].anyChildInTree("field_declaration_list")
|
fdecl = node[i].anyChildInTree("field_declaration_list")
|
||||||
edecl = node[i].anyChildInTree("enumerator_list")
|
edecl = node[i].anyChildInTree("enumerator_list")
|
||||||
|
commentNodes = gState.getCommentNodes(node[i])
|
||||||
|
|
||||||
# `tname` is name of nested struct / union / enum just
|
# `tname` is name of nested struct / union / enum just
|
||||||
# added, passed on as type name for field in `newIdentDefs()`
|
# added, passed on as type name for field in `newIdentDefs()`
|
||||||
|
|
@ -716,6 +717,7 @@ proc newRecListTree(gState: State, name: string, node: TSNode): PNode =
|
||||||
# Add nkIdentDefs for each field
|
# Add nkIdentDefs for each field
|
||||||
for field in gState.newIdentDefs(name, node[i], i, ftname = tname, exported = true):
|
for field in gState.newIdentDefs(name, node[i], i, ftname = tname, exported = true):
|
||||||
if not field.isNil:
|
if not field.isNil:
|
||||||
|
field.comment = gState.getCommentsStr(commentNodes)
|
||||||
result.add field
|
result.add field
|
||||||
|
|
||||||
proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = "", istype = false, union = false) =
|
proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = "", istype = false, union = false) =
|
||||||
|
|
@ -725,6 +727,8 @@ proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = ""
|
||||||
# If `fname` is set, use it as the name when creating new PNode
|
# If `fname` is set, use it as the name when creating new PNode
|
||||||
# If `istype` is set, this is a typedef, else struct/union
|
# If `istype` is set, this is a typedef, else struct/union
|
||||||
decho("addTypeObject()")
|
decho("addTypeObject()")
|
||||||
|
let commentNodes = gState.getCommentNodes(node.tsNodeParent())
|
||||||
|
|
||||||
let
|
let
|
||||||
# Object has fields or not
|
# Object has fields or not
|
||||||
fdlist = node.anyChildInTree("field_declaration_list")
|
fdlist = node.anyChildInTree("field_declaration_list")
|
||||||
|
|
@ -837,6 +841,7 @@ proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = ""
|
||||||
gState.addPragma(node, typeDef[0][1], pragmas)
|
gState.addPragma(node, typeDef[0][1], pragmas)
|
||||||
|
|
||||||
# nkTypeSection.add
|
# nkTypeSection.add
|
||||||
|
typeDef.comment = gState.getCommentsStr(commentNodes)
|
||||||
gState.typeSection.add typeDef
|
gState.typeSection.add typeDef
|
||||||
|
|
||||||
gState.printDebug(typeDef)
|
gState.printDebug(typeDef)
|
||||||
|
|
@ -848,6 +853,7 @@ proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = ""
|
||||||
# Current node has fields
|
# Current node has fields
|
||||||
let
|
let
|
||||||
origname = gState.getNodeVal(node.getAtom())
|
origname = gState.getNodeVal(node.getAtom())
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
|
|
||||||
# Fix issue #185
|
# Fix issue #185
|
||||||
name =
|
name =
|
||||||
|
|
@ -859,6 +865,8 @@ proc addTypeObject(gState: State, node: TSNode, typeDef: PNode = nil, fname = ""
|
||||||
if name.nBl and gState.identifierNodes.hasKey(name):
|
if name.nBl and gState.identifierNodes.hasKey(name):
|
||||||
let
|
let
|
||||||
def = gState.identifierNodes[name]
|
def = gState.identifierNodes[name]
|
||||||
|
def.comment = gState.getCommentsStr(commentNodes)
|
||||||
|
|
||||||
# Duplicate nkTypeDef for `name` with empty fields
|
# Duplicate nkTypeDef for `name` with empty fields
|
||||||
if def.kind == nkTypeDef and def.len == 3 and
|
if def.kind == nkTypeDef and def.len == 3 and
|
||||||
def[2].kind == nkObjectTy and def[2].len == 3 and
|
def[2].kind == nkObjectTy and def[2].len == 3 and
|
||||||
|
|
@ -890,6 +898,7 @@ proc addTypeTyped(gState: State, node: TSNode, ftname = "", offset = 0) =
|
||||||
decho("addTypeTyped()")
|
decho("addTypeTyped()")
|
||||||
let
|
let
|
||||||
start = getStartAtom(node)
|
start = getStartAtom(node)
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
for i in start+1+offset ..< node.len:
|
for i in start+1+offset ..< node.len:
|
||||||
# Add a type of a specific type
|
# Add a type of a specific type
|
||||||
let
|
let
|
||||||
|
|
@ -897,6 +906,7 @@ proc addTypeTyped(gState: State, node: TSNode, ftname = "", offset = 0) =
|
||||||
typeDef = gState.newXIdent(node[i], istype = true)
|
typeDef = gState.newXIdent(node[i], istype = true)
|
||||||
|
|
||||||
if not typeDef.isNil:
|
if not typeDef.isNil:
|
||||||
|
typeDef.comment = gState.getCommentsStr(commentNodes)
|
||||||
let
|
let
|
||||||
name = typeDef.getIdentName()
|
name = typeDef.getIdentName()
|
||||||
|
|
||||||
|
|
@ -1007,6 +1017,7 @@ proc addTypeArray(gState: State, node: TSNode) =
|
||||||
# node[start] = identifier = type name
|
# node[start] = identifier = type name
|
||||||
(tname, _, info) = gState.getNameInfo(node[start].getAtom(), nskType, parent = "addTypeArray")
|
(tname, _, info) = gState.getNameInfo(node[start].getAtom(), nskType, parent = "addTypeArray")
|
||||||
tident = gState.getIdent(tname, info, exported = false)
|
tident = gState.getIdent(tname, info, exported = false)
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
|
|
||||||
# Could have multiple types, comma separated
|
# Could have multiple types, comma separated
|
||||||
for i in start+1 ..< node.len:
|
for i in start+1 ..< node.len:
|
||||||
|
|
@ -1040,6 +1051,7 @@ proc addTypeArray(gState: State, node: TSNode) =
|
||||||
# )
|
# )
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
typeDef.comment = gState.getCommentsStr(commentNodes)
|
||||||
# nkTypeSection.add
|
# nkTypeSection.add
|
||||||
gState.typeSection.add typeDef
|
gState.typeSection.add typeDef
|
||||||
|
|
||||||
|
|
@ -1386,21 +1398,33 @@ proc addEnum(gState: State, node: TSNode) =
|
||||||
gState.typeSection.add eoverride
|
gState.typeSection.add eoverride
|
||||||
elif gState.addNewIdentifer(name):
|
elif gState.addNewIdentifer(name):
|
||||||
# Add enum definition and helpers
|
# Add enum definition and helpers
|
||||||
gState.enumSection.add gState.parseString(&"defineEnum({name})")
|
let defineNode = gState.parseString(&"defineEnum({name})")
|
||||||
|
# nkStmtList(
|
||||||
|
# nkCall(
|
||||||
|
# nkIdent("defineEnum"),
|
||||||
|
# nkIdent(name) <- set the comment here
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
defineNode[0][1].comment = gState.getCommentsStr(gState.getCommentNodes(node))
|
||||||
|
gState.enumSection.add defineNode
|
||||||
|
|
||||||
# Create const for fields
|
# Create const for fields
|
||||||
var
|
var
|
||||||
fnames: HashSet[string]
|
fnames: HashSet[string]
|
||||||
# Hold all of field information so that we can add all of them
|
# Hold all of field information so that we can add all of them
|
||||||
# after the const identifiers has been updated
|
# after the const identifiers has been updated
|
||||||
fieldDeclarations: seq[tuple[fname: string, fval: string, cexpr: Option[TSNode]]]
|
fieldDeclarations: seq[tuple[fname: string, fval: string, cexpr: Option[TSNode], comment: seq[TSNode]]]
|
||||||
for i in 0 .. enumlist.len - 1:
|
for i in 0 .. enumlist.len - 1:
|
||||||
let
|
let
|
||||||
en = enumlist[i]
|
en = enumlist[i]
|
||||||
if en.getName() == "comment":
|
if en.getName() == "comment":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
let
|
let
|
||||||
fname = gState.getIdentifier(gState.getNodeVal(en.getAtom()), nskEnumField)
|
atom = en.getAtom()
|
||||||
|
commentNodes = gState.getCommentNodes(en)
|
||||||
|
fname = gState.getIdentifier(gState.getNodeVal(atom), nskEnumField)
|
||||||
|
|
||||||
if fname.nBl and gState.addNewIdentifer(fname):
|
if fname.nBl and gState.addNewIdentifer(fname):
|
||||||
var
|
var
|
||||||
fval = ""
|
fval = ""
|
||||||
|
|
@ -1412,9 +1436,9 @@ proc addEnum(gState: State, node: TSNode) =
|
||||||
fval = &"({prev} + 1).{name}"
|
fval = &"({prev} + 1).{name}"
|
||||||
|
|
||||||
if en.len > 1 and en[1].getName() in gEnumVals:
|
if en.len > 1 and en[1].getName() in gEnumVals:
|
||||||
fieldDeclarations.add((fname, "", some(en[1])))
|
fieldDeclarations.add((fname, "", some(en[1]), commentNodes))
|
||||||
else:
|
else:
|
||||||
fieldDeclarations.add((fname, fval, none(TSNode)))
|
fieldDeclarations.add((fname, fval, none(TSNode), commentNodes))
|
||||||
|
|
||||||
fnames.incl fname
|
fnames.incl fname
|
||||||
prev = fname
|
prev = fname
|
||||||
|
|
@ -1424,18 +1448,20 @@ proc addEnum(gState: State, node: TSNode) =
|
||||||
gState.constIdentifiers.incl fnames
|
gState.constIdentifiers.incl fnames
|
||||||
|
|
||||||
# parseCExpression requires all const identifiers to be present for the enum
|
# parseCExpression requires all const identifiers to be present for the enum
|
||||||
for (fname, fval, cexprNode) in fieldDeclarations:
|
for (fname, fval, cexprNode, commentNodes) in fieldDeclarations:
|
||||||
var fval = fval
|
var fval = fval
|
||||||
if cexprNode.isSome:
|
if cexprNode.isSome:
|
||||||
fval = "(" & $gState.parseCExpression(gState.getNodeVal(cexprNode.get()), name) & ")." & name
|
fval = "(" & $gState.parseCExpression(gState.getNodeVal(cexprNode.get()), name) & ")." & name
|
||||||
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
|
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
|
||||||
gState.constSection.add gState.parseString(&"const {fname}* = {fval}")[0][0]
|
let constNode = gState.parseString(&"const {fname}* = {fval}")[0][0]
|
||||||
|
constNode.comment = gState.getCommentsStr(commentNodes)
|
||||||
|
gState.constSection.add constNode
|
||||||
|
|
||||||
# Add other names
|
# Add other names
|
||||||
if node.getName() == "type_definition" and node.len > 1:
|
if node.getName() == "type_definition" and node.len > 1:
|
||||||
gState.addTypeTyped(node, ftname = name, offset = offset)
|
gState.addTypeTyped(node, ftname = name, offset = offset)
|
||||||
|
|
||||||
proc addProcVar(gState: State, node, rnode: TSNode) =
|
proc addProcVar(gState: State, node, rnode: TSNode, commentNodes: seq[TSNode]) =
|
||||||
# Add a proc variable
|
# Add a proc variable
|
||||||
decho("addProcVar()")
|
decho("addProcVar()")
|
||||||
let
|
let
|
||||||
|
|
@ -1488,12 +1514,13 @@ proc addProcVar(gState: State, node, rnode: TSNode) =
|
||||||
# nkEmpty()
|
# nkEmpty()
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
identDefs.comment = gState.getCommentsStr(commentNodes)
|
||||||
# nkVarSection.add
|
# nkVarSection.add
|
||||||
gState.varSection.add identDefs
|
gState.varSection.add identDefs
|
||||||
|
|
||||||
gState.printDebug(identDefs)
|
gState.printDebug(identDefs)
|
||||||
|
|
||||||
proc addProc(gState: State, node, rnode: TSNode) =
|
proc addProc(gState: State, node, rnode: TSNode, commentNodes: seq[TSNode]) =
|
||||||
# Add a proc
|
# Add a proc
|
||||||
#
|
#
|
||||||
# `node` is the `nth` child of (declaration)
|
# `node` is the `nth` child of (declaration)
|
||||||
|
|
@ -1599,6 +1626,8 @@ proc addProc(gState: State, node, rnode: TSNode) =
|
||||||
procDef.add newNode(nkEmpty)
|
procDef.add newNode(nkEmpty)
|
||||||
procDef.add newNode(nkEmpty)
|
procDef.add newNode(nkEmpty)
|
||||||
|
|
||||||
|
procDef.comment = gState.getCommentsStr(commentNodes)
|
||||||
|
|
||||||
# nkProcSection.add
|
# nkProcSection.add
|
||||||
gState.procSection.add procDef
|
gState.procSection.add procDef
|
||||||
|
|
||||||
|
|
@ -1612,15 +1641,33 @@ proc addDecl(gState: State, node: TSNode) =
|
||||||
let
|
let
|
||||||
start = getStartAtom(node)
|
start = getStartAtom(node)
|
||||||
|
|
||||||
|
var
|
||||||
|
firstDecl = true
|
||||||
|
commentNodes: seq[TSNode]
|
||||||
|
|
||||||
for i in start+1 ..< node.len:
|
for i in start+1 ..< node.len:
|
||||||
if not node[i].firstChildInTree("function_declarator").isNil:
|
if not node[i].firstChildInTree("function_declarator").isNil:
|
||||||
# Proc declaration - var or actual proc
|
# Proc declaration - var or actual proc
|
||||||
if node[i].getAtom().getPxName(1) == "pointer_declarator":
|
if node[i].getAtom().getPxName(1) == "pointer_declarator":
|
||||||
# proc var
|
# proc var
|
||||||
gState.addProcVar(node[i], node[start])
|
if firstDecl:
|
||||||
|
# If it's the first declaration, use the whole node
|
||||||
|
# to get the comment above/below
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
|
firstDecl = false
|
||||||
|
else:
|
||||||
|
commentNodes = gState.getCommentNodes(node[i])
|
||||||
|
gState.addProcVar(node[i], node[start], commentNodes)
|
||||||
else:
|
else:
|
||||||
# proc
|
# proc
|
||||||
gState.addProc(node[i], node[start])
|
if firstDecl:
|
||||||
|
# If it's the first declaration, use the whole node
|
||||||
|
# to get the comment above/below
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
|
firstDecl = false
|
||||||
|
else:
|
||||||
|
commentNodes = gState.getCommentNodes(node[i])
|
||||||
|
gState.addProc(node[i], node[start], commentNodes)
|
||||||
else:
|
else:
|
||||||
# Regular var
|
# Regular var
|
||||||
discard
|
discard
|
||||||
|
|
@ -1632,11 +1679,14 @@ proc addDef(gState: State, node: TSNode) =
|
||||||
# and will fail at link time
|
# and will fail at link time
|
||||||
decho("addDef()")
|
decho("addDef()")
|
||||||
gState.printDebug(node)
|
gState.printDebug(node)
|
||||||
|
|
||||||
let
|
let
|
||||||
start = getStartAtom(node)
|
start = getStartAtom(node)
|
||||||
|
commentNodes = gState.getCommentNodes(node)
|
||||||
|
|
||||||
if node[start+1].getName() == "function_declarator":
|
if node[start+1].getName() == "function_declarator":
|
||||||
if gState.isIncludeHeader():
|
if gState.isIncludeHeader():
|
||||||
gState.addProc(node[start+1], node[start])
|
gState.addProc(node[start+1], node[start], commentNodes)
|
||||||
else:
|
else:
|
||||||
gecho &"\n# proc '$1' skipped - static inline procs require 'includeHeader'" %
|
gecho &"\n# proc '$1' skipped - static inline procs require 'includeHeader'" %
|
||||||
gState.getNodeVal(node[start+1].getAtom())
|
gState.getNodeVal(node[start+1].getAtom())
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ proc cAddSearchDir*(dir: string) {.compileTime.} =
|
||||||
## Add directory `dir` to the search path used in calls to
|
## Add directory `dir` to the search path used in calls to
|
||||||
## `cSearchPath() <cimport.html#cSearchPath,string>`_.
|
## `cSearchPath() <cimport.html#cSearchPath,string>`_.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
import paths, os
|
import nimterop/paths, os
|
||||||
static:
|
static:
|
||||||
cAddSearchDir testsIncludeDir()
|
cAddSearchDir testsIncludeDir()
|
||||||
doAssert cSearchPath("test.h").existsFile
|
doAssert cSearchPath("test.h").existsFile
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ proc execAction(cmd: string): string =
|
||||||
doAssert ret == 0, "Command failed: " & $ret & "\ncmd: " & ccmd & "\nresult:\n" & result
|
doAssert ret == 0, "Command failed: " & $ret & "\ncmd: " & ccmd & "\nresult:\n" & result
|
||||||
|
|
||||||
proc buildDocs*(files: openArray[string], path: string, baseDir = getProjectPath() & $DirSep,
|
proc buildDocs*(files: openArray[string], path: string, baseDir = getProjectPath() & $DirSep,
|
||||||
defines: openArray[string] = @[]) =
|
defines: openArray[string] = @[], nimArgs = "") =
|
||||||
## Generate docs for all specified nim `files` to the specified `path`
|
## Generate docs for all specified nim `files` to the specified `path`
|
||||||
##
|
##
|
||||||
## `baseDir` is the project path by default and `files` and `path` are relative
|
## `baseDir` is the project path by default and `files` and `path` are relative
|
||||||
|
|
@ -45,6 +45,8 @@ proc buildDocs*(files: openArray[string], path: string, baseDir = getProjectPath
|
||||||
## `defines` is a list of `-d:xxx` define flags (the `xxx` part) that should be passed
|
## `defines` is a list of `-d:xxx` define flags (the `xxx` part) that should be passed
|
||||||
## to `nim doc` so that `getHeader()` is invoked correctly.
|
## to `nim doc` so that `getHeader()` is invoked correctly.
|
||||||
##
|
##
|
||||||
|
## `nimArgs` is a string representing extra arguments to send to the `nim doc` call.
|
||||||
|
##
|
||||||
## Use the `--publish` flag with nimble to publish docs contained in
|
## Use the `--publish` flag with nimble to publish docs contained in
|
||||||
## `path` to Github in the `gh-pages` branch. This requires the ghp-import
|
## `path` to Github in the `gh-pages` branch. This requires the ghp-import
|
||||||
## package for Python: `pip install ghp-import`
|
## package for Python: `pip install ghp-import`
|
||||||
|
|
@ -70,7 +72,7 @@ proc buildDocs*(files: openArray[string], path: string, baseDir = getProjectPath
|
||||||
defStr
|
defStr
|
||||||
nim = getCurrentCompilerExe()
|
nim = getCurrentCompilerExe()
|
||||||
for file in files:
|
for file in files:
|
||||||
echo execAction(&"{nim} doc {defStr} -o:{path} --project --index:on {baseDir & file}")
|
echo execAction(&"{nim} doc {defStr} {nimArgs} -o:{path} --project --index:on {baseDir & file}")
|
||||||
|
|
||||||
echo execAction(&"{nim} buildIndex -o:{path}/theindex.html {path}")
|
echo execAction(&"{nim} buildIndex -o:{path}/theindex.html {path}")
|
||||||
when declared(getNimRootDir):
|
when declared(getNimRootDir):
|
||||||
|
|
|
||||||
|
|
@ -387,6 +387,16 @@ proc getLineCol*(code: var string, node: TSNode): tuple[line, col: int] =
|
||||||
proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
||||||
getLineCol(gState.code, node)
|
getLineCol(gState.code, node)
|
||||||
|
|
||||||
|
proc getEndLineCol*(code: var string, node: TSNode): tuple[line, col: int] =
|
||||||
|
# Get line number and column info for node
|
||||||
|
let
|
||||||
|
point = node.tsNodeEndPoint()
|
||||||
|
result.line = point.row.int + 1
|
||||||
|
result.col = point.column.int + 1
|
||||||
|
|
||||||
|
proc getEndLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
|
||||||
|
getEndLineCol(gState.code, node)
|
||||||
|
|
||||||
proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
|
proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
|
||||||
for i in 0 ..< node.len:
|
for i in 0 ..< node.len:
|
||||||
if node.getName() != "comment":
|
if node.getName() != "comment":
|
||||||
|
|
@ -571,30 +581,30 @@ proc getPreprocessor*(gState: State, fullpath: string): string =
|
||||||
|
|
||||||
# Include content only from file
|
# Include content only from file
|
||||||
for line in execAction(cmd).output.splitLines():
|
for line in execAction(cmd).output.splitLines():
|
||||||
if line.strip() != "":
|
# We want to keep blank lines here for comment processing
|
||||||
if line.len > 1 and line[0 .. 1] == "# ":
|
if line.len > 1 and line[0 .. 1] == "# ":
|
||||||
start = false
|
start = false
|
||||||
|
let
|
||||||
|
saniLine = line.sanitizePath(noQuote = true)
|
||||||
|
if sfile in saniLine:
|
||||||
|
start = true
|
||||||
|
elif not ("\\" in line) and not ("/" in line) and extractFilename(sfile) in line:
|
||||||
|
start = true
|
||||||
|
elif gState.recurse:
|
||||||
let
|
let
|
||||||
saniLine = line.sanitizePath(noQuote = true)
|
pDir = sfile.expandFilename().parentDir().sanitizePath(noQuote = true)
|
||||||
if sfile in saniLine:
|
if pDir.Bl or pDir in saniLine:
|
||||||
start = true
|
start = true
|
||||||
elif not ("\\" in line) and not ("/" in line) and extractFilename(sfile) in line:
|
else:
|
||||||
start = true
|
for inc in gState.includeDirs:
|
||||||
elif gState.recurse:
|
if inc.absolutePath().sanitizePath(noQuote = true) in saniLine:
|
||||||
let
|
start = true
|
||||||
pDir = sfile.expandFilename().parentDir().sanitizePath(noQuote = true)
|
break
|
||||||
if pDir.Bl or pDir in saniLine:
|
else:
|
||||||
start = true
|
if start:
|
||||||
else:
|
if "#undef" in line:
|
||||||
for inc in gState.includeDirs:
|
continue
|
||||||
if inc.absolutePath().sanitizePath(noQuote = true) in saniLine:
|
rdata.add line
|
||||||
start = true
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if start:
|
|
||||||
if "#undef" in line:
|
|
||||||
continue
|
|
||||||
rdata.add line
|
|
||||||
return rdata.join("\n")
|
return rdata.join("\n")
|
||||||
|
|
||||||
converter toString*(kind: Kind): string =
|
converter toString*(kind: Kind): string =
|
||||||
|
|
@ -634,6 +644,109 @@ proc getNameKind*(name: string): tuple[name: string, kind: Kind, recursive: bool
|
||||||
if result.kind != exactlyOne:
|
if result.kind != exactlyOne:
|
||||||
result.name = result.name[0 .. ^2]
|
result.name = result.name[0 .. ^2]
|
||||||
|
|
||||||
|
proc getCommentsStr*(gState: State, commentNodes: seq[TSNode]): string =
|
||||||
|
## Generate a comment from a set of comment nodes. Comment is guaranteed
|
||||||
|
## to be able to be rendered using nim doc
|
||||||
|
if commentNodes.len > 0:
|
||||||
|
result = "::"
|
||||||
|
for commentNode in commentNodes:
|
||||||
|
result &= "\n " & gState.getNodeVal(commentNode).strip()
|
||||||
|
|
||||||
|
result = result.replace(re" *(//|/\*\*|\*\*/|/\*|\*/|\*)", "")
|
||||||
|
result = result.multiReplace([("\n", "\n "), ("`", "")]).strip()
|
||||||
|
|
||||||
|
proc getCommentNodes*(gState: State, node: TSNode, maxSearch=1): seq[TSNode] =
|
||||||
|
## Get a set of comment nodes in order of priority. Will search up to ``maxSearch``
|
||||||
|
## nodes before and after the current node
|
||||||
|
##
|
||||||
|
## Priority is (closest line number) > comment before > comment after.
|
||||||
|
## This priority might need to be changed based on the project, but
|
||||||
|
## for now it is good enough
|
||||||
|
|
||||||
|
# Skip this if we don't want comments
|
||||||
|
if gState.nocomments:
|
||||||
|
return
|
||||||
|
|
||||||
|
let (line, _) = gState.getLineCol(node)
|
||||||
|
|
||||||
|
# Keep track of both directions from a node
|
||||||
|
var
|
||||||
|
prevSibling = node.tsNodePrevNamedSibling()
|
||||||
|
nextSibling = node.tsNodeNextNamedSibling()
|
||||||
|
nilNode: TSNode
|
||||||
|
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
prevSiblingDistance, nextSiblingDistance: int = int.high
|
||||||
|
lowestDistance: int
|
||||||
|
commentsFound = false
|
||||||
|
|
||||||
|
while not commentsFound and i < maxSearch:
|
||||||
|
# Distance from the current node will tell us approximately if the
|
||||||
|
# comment belongs to the node. The closer it is in terms of line
|
||||||
|
# numbers, the more we can be sure it's the comment we want
|
||||||
|
if not prevSibling.isNil:
|
||||||
|
if prevSibling.getName() == "comment":
|
||||||
|
prevSiblingDistance = abs(gState.getEndLineCol(prevSibling)[0] - line)
|
||||||
|
else:
|
||||||
|
prevSiblingDistance = int.high
|
||||||
|
if not nextSibling.isNil:
|
||||||
|
if nextSibling.getName() == "comment":
|
||||||
|
nextSiblingDistance = abs(gState.getLineCol(nextSibling)[0] - line)
|
||||||
|
else:
|
||||||
|
nextSiblingDistance = int.high
|
||||||
|
|
||||||
|
lowestDistance = min(prevSiblingDistance, nextSiblingDistance)
|
||||||
|
|
||||||
|
if prevSiblingDistance > maxSearch:
|
||||||
|
# If the line is out of range, skip searching
|
||||||
|
prevSibling = nilNode # Can't do `= nil`
|
||||||
|
|
||||||
|
if nextSiblingDistance > maxSearch:
|
||||||
|
# If the line is out of range, skip searching
|
||||||
|
nextSibling = nilNode
|
||||||
|
|
||||||
|
# Search above the current line for comments. When one is found
|
||||||
|
# keep going to retrieve successive comments for cases with multiple
|
||||||
|
# `//` style comments
|
||||||
|
while (
|
||||||
|
not prevSibling.isNil and
|
||||||
|
prevSibling.getName() == "comment" and
|
||||||
|
prevSiblingDistance == lowestDistance
|
||||||
|
):
|
||||||
|
# Put the previous nodes in reverse order so the comments
|
||||||
|
# make logical sense
|
||||||
|
result.insert(prevSibling, 0)
|
||||||
|
prevSibling = prevSibling.tsNodePrevNamedSibling()
|
||||||
|
commentsFound = true
|
||||||
|
|
||||||
|
# If we've already found comments above the current line, quit
|
||||||
|
if commentsFound:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Search below or at the current line for comments. When one is found
|
||||||
|
# keep going to retrieve successive comments for cases with multiple
|
||||||
|
# `//` style comments
|
||||||
|
while (
|
||||||
|
not nextSibling.isNil and
|
||||||
|
nextSibling.getName() == "comment" and
|
||||||
|
nextSiblingDistance == lowestDistance
|
||||||
|
):
|
||||||
|
result.add(nextSibling)
|
||||||
|
nextSibling = nextSibling.tsNodeNextNamedSibling()
|
||||||
|
commentsFound = true
|
||||||
|
|
||||||
|
if commentsFound:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Go to next sibling pair
|
||||||
|
if not prevSibling.isNil:
|
||||||
|
prevSibling = prevSibling.tsNodePrevNamedSibling()
|
||||||
|
if not nextSibling.isNil:
|
||||||
|
nextSibling = nextSibling.tsNodeNextNamedSibling()
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
proc getTSNodeNamedChildNames*(node: TSNode): seq[string] =
|
proc getTSNodeNamedChildNames*(node: TSNode): seq[string] =
|
||||||
if node.tsNodeNamedChildCount() != 0:
|
if node.tsNodeNamedChildCount() != 0:
|
||||||
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
for i in 0 .. node.tsNodeNamedChildCount()-1:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import std/unittest
|
import std/unittest
|
||||||
|
import os
|
||||||
|
import macros
|
||||||
import nimterop/cimport
|
import nimterop/cimport
|
||||||
import nimterop/paths
|
import nimterop/paths
|
||||||
|
|
||||||
|
|
@ -10,7 +12,7 @@ cDefine("FORCE")
|
||||||
cIncludeDir testsIncludeDir()
|
cIncludeDir testsIncludeDir()
|
||||||
cCompile cSearchPath("test.c")
|
cCompile cSearchPath("test.c")
|
||||||
|
|
||||||
cPluginPath("tests/tnimterop_c_plugin.nim")
|
cPluginPath(getProjectPath() / "tnimterop_c_plugin.nim")
|
||||||
|
|
||||||
cOverride:
|
cOverride:
|
||||||
type
|
type
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue