161 lines
3.6 KiB
Nim
161 lines
3.6 KiB
Nim
import os, strformat, strutils
|
|
|
|
import nimterop/treesitter/[runtime, c, cpp]
|
|
|
|
import nimterop/[ast, globals, getters, grammar]
|
|
|
|
proc printLisp(root: TSNode) =
|
|
var
|
|
node = root
|
|
nextnode: TSNode
|
|
depth = 0
|
|
|
|
while true:
|
|
if not node.tsNodeIsNull():
|
|
if gStateRT.pretty:
|
|
stdout.write spaces(depth)
|
|
let
|
|
(line, col) = node.getLineCol()
|
|
stdout.write &"({$node.tsNodeType()} {line} {col} {node.tsNodeEndByte() - node.tsNodeStartByte()}"
|
|
else:
|
|
return
|
|
|
|
if node.tsNodeNamedChildCount() != 0:
|
|
if gStateRT.pretty:
|
|
echo ""
|
|
nextnode = node.tsNodeNamedChild(0)
|
|
depth += 1
|
|
else:
|
|
if gStateRT.pretty:
|
|
echo ")"
|
|
else:
|
|
stdout.write ")"
|
|
nextnode = node.tsNodeNextNamedSibling()
|
|
|
|
if nextnode.tsNodeIsNull():
|
|
while true:
|
|
node = node.tsNodeParent()
|
|
depth -= 1
|
|
if depth == -1:
|
|
break
|
|
if gStateRT.pretty:
|
|
echo spaces(depth) & ")"
|
|
else:
|
|
stdout.write ")"
|
|
if node == root:
|
|
break
|
|
if not node.tsNodeNextNamedSibling().tsNodeIsNull():
|
|
node = node.tsNodeNextNamedSibling()
|
|
break
|
|
else:
|
|
node = nextnode
|
|
|
|
if node == root:
|
|
break
|
|
|
|
proc process(path: string) =
|
|
if not existsFile(path):
|
|
echo "Invalid path " & path
|
|
return
|
|
|
|
var
|
|
parser = tsParserNew()
|
|
ext = path.splitFile().ext
|
|
|
|
defer:
|
|
parser.tsParserDelete()
|
|
|
|
gStateRT.sourceFile = path
|
|
|
|
if gStateRT.mode.len == 0:
|
|
if ext in [".h", ".c"]:
|
|
gStateRT.mode = "c"
|
|
elif ext in [".hxx", ".hpp", ".hh", ".H", ".h++", ".cpp", ".cxx", ".cc", ".C", ".c++"]:
|
|
gStateRT.mode = "cpp"
|
|
|
|
if gStateRT.preprocess:
|
|
gStateRT.code = getPreprocessor(path)
|
|
else:
|
|
gStateRT.code = readFile(path)
|
|
|
|
if gStateRT.mode == "c":
|
|
if not parser.tsParserSetLanguage(treeSitterC()):
|
|
echo "Failed to load C parser"
|
|
quit()
|
|
elif gStateRT.mode == "cpp":
|
|
if not parser.tsParserSetLanguage(treeSitterCpp()):
|
|
echo "Failed to load C++ parser"
|
|
quit()
|
|
else:
|
|
echo "Invalid parser " & gStateRT.mode
|
|
quit()
|
|
|
|
var
|
|
tree = parser.tsParserParseString(nil, gStateRT.code.cstring, gStateRT.code.len.uint32)
|
|
root = tree.tsTreeRootNode()
|
|
|
|
defer:
|
|
tree.tsTreeDelete()
|
|
|
|
if gStateRT.past:
|
|
printLisp(root)
|
|
elif gStateRT.pnim:
|
|
printNim(path, root)
|
|
elif gStateRT.preprocess:
|
|
echo gStateRT.code
|
|
|
|
proc main(
|
|
mode = modeDefault,
|
|
past = false,
|
|
pnim = false,
|
|
pretty = true,
|
|
preprocess = false,
|
|
pgrammar = false,
|
|
recurse = false,
|
|
debug = false,
|
|
defines: seq[string] = @[],
|
|
includeDirs: seq[string] = @[],
|
|
source: seq[string],
|
|
) =
|
|
|
|
gStateRT = State(
|
|
mode: mode,
|
|
past: past,
|
|
pnim: pnim,
|
|
pretty: pretty,
|
|
preprocess: preprocess,
|
|
recurse: recurse,
|
|
debug: debug,
|
|
defines: defines,
|
|
includeDirs: includeDirs,
|
|
)
|
|
|
|
if pgrammar:
|
|
parseGrammar()
|
|
printGrammar()
|
|
elif source.len != 0:
|
|
process(source[0])
|
|
|
|
when isMainModule:
|
|
import cligen
|
|
dispatch(main, help = {
|
|
"past": "print AST output",
|
|
"mode": "language; see CompileMode", # TODO: auto-generate valid choices
|
|
"pnim": "print Nim output",
|
|
"defines": "definitions to pass to preprocessor",
|
|
"includeDirs": "include directory to pass to preprocessor",
|
|
"preprocess": "run preprocessor on header",
|
|
"pgrammar": "print grammar",
|
|
"recurse": "process #include files",
|
|
"debug": "enable debug output",
|
|
"source" : "C/C++ source/header",
|
|
}, short = {
|
|
"past": 'a',
|
|
"pnim": 'n',
|
|
"defines": 'D',
|
|
"includeDirs": 'I',
|
|
"preprocess": 'p',
|
|
"recurse": 'r',
|
|
"debug": 'd',
|
|
"pgrammar": 'g'
|
|
})
|