aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Viswanathan <dev@genotrance.com>2018-11-28 11:08:45 -0600
committerGanesh Viswanathan <dev@genotrance.com>2018-11-28 11:08:45 -0600
commit7344042029bf6319219c11b318372f55904c6491 (patch)
treeca559801ed238a6b88981a1108e0892d0f856868
parentd7ca43f49fb544d1d1299a445ad519874ec63f3a (diff)
downloadnimterop-7344042029bf6319219c11b318372f55904c6491.tar.gz
nimterop-7344042029bf6319219c11b318372f55904c6491.zip
Move AST to Nim processing into toast
-rw-r--r--nimterop/ast.nim312
-rw-r--r--nimterop/cimport.nim72
-rw-r--r--nimterop/getters.nim29
-rw-r--r--nimterop/globals.nim44
-rw-r--r--toast.nim78
5 files changed, 264 insertions, 271 deletions
diff --git a/nimterop/ast.nim b/nimterop/ast.nim
index cc1cd61..4cee1db 100644
--- a/nimterop/ast.nim
+++ b/nimterop/ast.nim
@@ -1,53 +1,41 @@
-import macros, os, strformat
+import macros, os, strformat, strutils
-import regex
+import treesitter/runtime
import getters, globals
-proc addReorder*(): NimNode =
- result = newNimNode(nnkStmtList)
- if not gReorder:
- gReorder = true
- result.add parseStmt(
- "{.experimental: \"codeReordering\".}"
- )
-
-proc addHeader*(fullpath: string) =
- gCurrentHeader = ("header" & fullpath.splitFile().name.replace(re"[-.]+", ""))
- gConstStr &= &" {gCurrentHeader} = \"{fullpath}\" # addHeader()\n"
-
#
# Preprocessor
#
-proc pPreprocDef(node: ref Ast) =
- if node.children.len == 2:
+proc pPreprocDef(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2:
let
- name = getNodeValIf(node.children[0], identifier)
- val = getNodeValIf(node.children[1], preproc_arg)
+ name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
+ val = getNodeValIf(node.tsNodeNamedChild(1), "preproc_arg")
- if name.nBl and val.nBl and name notin gConsts:
- gConsts.add(name)
+ if name.nBl and val.nBl and name notin gStateRT.consts:
+ gStateRT.consts.add(name)
if val.getLit().nBl:
# #define NAME VALUE
- gConstStr &= &" {name.getIdentifier()}* = {val} # pPreprocDef()\n"
+ gStateRT.constStr &= &" {name.getIdentifier()}* = {val} # pPreprocDef()\n"
#
# Types
#
-proc typeScan(node: ref Ast, sym, id: Sym, offset: string): string =
- if node.sym != sym or node.children.len != 2:
+proc typeScan(node: TSNode, sym, id: string, offset: string): string =
+ if node.tsNodeIsNull() or $node.tsNodeType() != sym or node.tsNodeNamedChildCount() != 2:
return
var
- name = getNodeValIf(node.children[1], id)
- ptyp = getNodeValIf(node.children[0], primitive_type)
- ttyp = getNodeValIf(node.children[0], type_identifier)
+ name = getNodeValIf(node.tsNodeNamedChild(1), id)
+ ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
+ ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
ptrname = false
- if name.len == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len == 1:
- name = getNodeValIf(node.children[1].children[0], id)
+ if name.len == 0 and $node.tsNodeNamedChild(1).tsNodeType() == "pointer_declarator" and node.tsNodeNamedChild(1).tsNodeNamedChildCount() == 1:
+ name = getNodeValIf(node.tsNodeNamedChild(1).tsNodeNamedChild(0), id)
ptrname = true
if name.len == 0:
@@ -61,194 +49,238 @@ proc typeScan(node: ref Ast, sym, id: Sym, offset: string): string =
if ptrname:
ttyp = &"ptr {ttyp}"
result = &"{offset}{name.getIdentifier()}: {ttyp}"
- elif node.children[0].sym in [struct_specifier, enum_specifier] and node.children[0].children.len == 1:
- var styp = getNodeValIf(node.children[0].children[0], type_identifier)
+ elif $node.tsNodeNamedChild(0).tsNodeType() in ["struct_specifier", "enum_specifier"] and node.tsNodeNamedChild(0).tsNodeNamedChildCount() == 1:
+ var styp = getNodeValIf(node.tsNodeNamedChild(0).tsNodeNamedChild(0), "type_identifier")
if styp.nBl:
if ptrname:
styp = &"ptr {styp}"
result = &"{offset}{name.getIdentifier()}: {styp}"
- else:
- return
-proc pStructSpecifier(node: ref Ast, name = "") =
+proc pStructSpecifier(node: TSNode, name = "") =
var stmt: string
- if node.children.len == 1 and name notin gTypes:
- case node.children[0].sym:
- of type_identifier:
- let typ = getNodeValIf(node.children[0], type_identifier)
+ if node.tsNodeNamedChildCount() == 1 and name notin gStateRT.types:
+ case $node.tsNodeNamedChild(0).tsNodeType():
+ of "type_identifier":
+ let typ = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
if typ.nBl:
- gTypes.add(name)
+ gStateRT.types.add(name)
if name != typ:
# typedef struct X Y
- gTypeStr &= &" {name.getIdentifier()}* = {typ} #1 pStructSpecifier()\n"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {typ} #1 pStructSpecifier()\n"
else:
# typedef struct X X
- gTypeStr &= &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #2 pStructSpecifier()\n"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #2 pStructSpecifier()\n"
- of field_declaration_list:
+ of "field_declaration_list":
# typedef struct { fields } X
- stmt = &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gCurrentHeader}, bycopy.}} = object #3 pStructSpecifier()\n"
+ stmt = &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #3 pStructSpecifier()\n"
- for field in node.children[0].children:
- let ts = typeScan(field, field_declaration, field_identifier, " ")
- if ts.len == 0:
- return
- stmt &= ts & "\n"
+ if node.tsNodeNamedChild(0).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(0).tsNodeNamedChildCount()-1:
+ let ts = typeScan(node.tsNodeNamedChild(0).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
+ if ts.len == 0:
+ return
+ stmt &= ts & "\n"
- gTypes.add(name)
- gTypeStr &= stmt
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
else:
discard
- elif name.len == 0 and node.children.len == 2 and node.children[1].sym == field_declaration_list:
- let ename = getNodeValIf(node.children[0], type_identifier)
- if ename.nBl and ename notin gTypes:
+ elif name.len == 0 and node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "field_declaration_list":
+ let ename = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
+ if ename.nBl and ename notin gStateRT.types:
# struct X { fields }
- stmt &= &" {ename}* {{.importc: \"struct {ename}\", header: {gCurrentHeader}, bycopy.}} = object #4 pStructSpecifier()\n"
+ stmt &= &" {ename}* {{.importc: \"struct {ename}\", header: {gStateRT.currentHeader}, bycopy.}} = object #4 pStructSpecifier()\n"
- for field in node.children[1].children:
- let ts = typeScan(field, field_declaration, field_identifier, " ")
- if ts.len == 0:
- return
- stmt &= ts & "\n"
+ if node.tsNodeNamedChild(1).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(1).tsNodeNamedChildCount()-1:
+ let ts = typeScan(node.tsNodeNamedChild(1).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
+ if ts.len == 0:
+ return
+ stmt &= ts & "\n"
- gTypes.add(name)
- gTypeStr &= stmt
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
-proc pEnumSpecifier(node: ref Ast, name = "") =
+proc pEnumSpecifier(node: TSNode, name = "") =
var
ename: string
- elid: int
+ elid: uint32
stmt: string
- if node.children.len == 1 and node.children[0].sym == enumerator_list:
+ if node.tsNodeNamedChildCount() == 1 and $node.tsNodeNamedChild(0).tsNodeType() == "enumerator_list":
# typedef enum { fields } X
ename = name
elid = 0
stmt = &" {name.getIdentifier()}* = enum #1 pEnumSpecifier()\n"
- elif name.len == 0 and node.children.len == 2 and node.children[1].sym == enumerator_list:
- ename = getNodeValIf(node.children[0], type_identifier)
+ elif name.len == 0 and node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "enumerator_list":
+ ename = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
elid = 1
if ename.nBl:
# enum X { fields }
stmt = &" {ename}* = enum #2 pEnumSpecifier()\n"
else:
return
+ else:
+ return
- for field in node.children[elid].children:
- if field.sym == enumerator:
- let fname = getNodeValIf(field.children[0], identifier)
- if field.children.len == 1:
- stmt &= &" {fname}\n"
- elif field.children.len == 2 and field.children[1].sym == number_literal:
- let num = getNodeValIf(field.children[1], number_literal)
- stmt &= &" {fname} = {num}\n"
- else:
- return
+ if node.tsNodeNamedChild(elid).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(elid).tsNodeNamedChildCount()-1:
+ let field = node.tsNodeNamedChild(elid).tsNodeNamedChild(i)
+ if not field.tsNodeIsNull() and $field.tsNodeType() == "enumerator":
+ let fname = getNodeValIf(field.tsNodeNamedChild(0), "identifier")
+ if field.tsNodeNamedChildCount() == 1:
+ stmt &= &" {fname}\n"
+ elif field.tsNodeNamedChildCount() == 2 and $field.tsNodeNamedChild(1).tsNodeType() == "number_literal":
+ let num = getNodeValIf(field.tsNodeNamedChild(1), "number_literal")
+ stmt &= &" {fname} = {num}\n"
+ else:
+ return
- if ename notin gTypes:
- gTypes.add(name)
- gTypeStr &= stmt
+ if ename notin gStateRT.types:
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
-proc pTypeDefinition(node: ref Ast) =
- if node.children.len == 2:
+proc pTypeDefinition(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2:
var
- name = getNodeValIf(node.children[1], type_identifier)
- ptyp = getNodeValIf(node.children[0], primitive_type)
- ttyp = getNodeValIf(node.children[0], type_identifier)
+ name = getNodeValIf(node.tsNodeNamedChild(1), "type_identifier")
+ ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
+ ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
ptrname = false
- if name.len == 0 and node.children[1].sym == pointer_declarator and node.children[1].children.len == 1:
- name = getNodeValIf(node.children[1].children[0], type_identifier)
+ if name.len == 0 and $node.tsNodeNamedChild(1).tsNodeType() == "pointer_declarator" and node.tsNodeNamedChild(1).tsNodeNamedChildCount() == 1:
+ name = getNodeValIf(node.tsNodeNamedChild(1).tsNodeNamedChild(0), "type_identifier")
ptrname = true
- if name.nBl and name notin gTypes:
+ if name.nBl and name notin gStateRT.types:
if ptyp.nBl:
# typedef int X
- gTypes.add(name)
+ gStateRT.types.add(name)
ptyp = ptyp.getType()
if ptyp != "object" and ptrname:
ptyp = &"ptr {ptyp}"
- gTypeStr &= &" {name.getIdentifier()}* = {ptyp} #1 pTypeDefinition()\n"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {ptyp} #1 pTypeDefinition()\n"
elif ttyp.nBl:
# typedef X Y
- gTypes.add(name)
+ gStateRT.types.add(name)
if ptrname:
ttyp = &"ptr {ttyp}"
- gTypeStr &= &" {name.getIdentifier()}* = {ttyp} #2 pTypeDefinition()\n"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {ttyp} #2 pTypeDefinition()\n"
else:
- case node.children[0].sym:
- of struct_specifier:
- pStructSpecifier(node.children[0], name)
- of enum_specifier:
- pEnumSpecifier(node.children[0], name)
+ case $node.tsNodeNamedChild(0).tsNodeType():
+ of "struct_specifier":
+ pStructSpecifier(node.tsNodeNamedChild(0), name)
+ of "enum_specifier":
+ pEnumSpecifier(node.tsNodeNamedChild(0), name)
else:
discard
-proc pFunctionDeclarator(node: ref Ast, typ: string) =
- if node.children.len == 2:
+proc pFunctionDeclarator(node: TSNode, typ: string) =
+ if node.tsNodeNamedChildCount() == 2:
let
- name = getNodeValIf(node.children[0], identifier)
+ name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
- if name.nBl and name notin gProcs and node.children[1].sym == parameter_list:
+ if name.nBl and name notin gStateRT.procs and $node.tsNodeNamedChild(1).tsNodeType() == "parameter_list":
# typ function(typ param1, ...)
var stmt = &"# pFunctionDeclarator()\nproc {name.getIdentifier()}*("
- for i in 0 .. node.children[1].children.len-1:
- let ts = typeScan(node.children[1].children[i], parameter_declaration, identifier, "")
- if ts.len == 0:
- return
- stmt &= ts
- if i != node.children[1].children.len-1:
- stmt &= ", "
+ if node.tsNodeNamedChild(1).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(1).tsNodeNamedChildCount()-1:
+ let ts = typeScan(node.tsNodeNamedChild(1).tsNodeNamedChild(i), "parameter_declaration", "identifier", "")
+ if ts.len == 0:
+ return
+ stmt &= ts
+ if i != node.tsNodeNamedChild(1).tsNodeNamedChildCount()-1:
+ stmt &= ", "
if typ != "void":
stmt &= &"): {typ.getType()} "
else:
stmt &= ") "
- stmt &= &"{{.importc: \"{name}\", header: {gCurrentHeader}.}}\n"
+ stmt &= &"{{.importc: \"{name}\", header: {gStateRT.currentHeader}.}}\n"
- gProcs.add(name)
- gProcStr &= stmt
+ gStateRT.procs.add(name)
+ gStateRT.procStr &= stmt
-proc pDeclaration*(node: ref Ast) =
- if node.children.len == 2 and node.children[1].sym == function_declarator:
+proc pDeclaration*(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "function_declarator":
let
- ptyp = getNodeValIf(node.children[0], primitive_type)
- ttyp = getNodeValIf(node.children[0], type_identifier)
+ ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
+ ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
if ptyp.nBl:
- pFunctionDeclarator(node.children[1], ptyp.getType())
+ pFunctionDeclarator(node.tsNodeNamedChild(1), ptyp.getType())
elif ttyp.nBl:
- pFunctionDeclarator(node.children[1], ttyp)
- elif node.children[0].sym == struct_specifier and node.children[0].children.len == 1:
- let styp = getNodeValIf(node.children[0].children[0], type_identifier)
+ pFunctionDeclarator(node.tsNodeNamedChild(1), ttyp)
+ elif $node.tsNodeNamedChild(0).tsNodeType() == "struct_specifier" and node.tsNodeNamedChild(0).tsNodeNamedChildCount() == 1:
+ let styp = getNodeValIf(node.tsNodeNamedChild(0).tsNodeNamedChild(0), "type_identifier")
if styp.nBl:
- pFunctionDeclarator(node.children[1], styp)
+ pFunctionDeclarator(node.tsNodeNamedChild(1), styp)
-proc genNimAst*(node: ref Ast) =
- if node.isNil:
- return
+proc genNimAst(root: TSNode) =
+ var
+ node = root
+ nextnode: TSNode
+
+ while true:
+ if not node.tsNodeIsNull():
+ case $node.tsNodeType():
+ of "ERROR":
+ let (line, col) = getLineCol(node)
+ echo &"Potentially invalid syntax at line {line} column {col}"
+ of "preproc_def":
+ pPreprocDef(node)
+ of "type_definition":
+ pTypeDefinition(node)
+ of "declaration":
+ pDeclaration(node)
+ of "struct_specifier":
+ if $node.tsNodeParent().tsNodeType() notin ["type_definition", "declaration"]:
+ pStructSpecifier(node)
+ of "enum_specifier":
+ if $node.tsNodeParent.tsNodeType() notin ["type_definition", "declaration"]:
+ pEnumSpecifier(node)
+ else:
+ discard
+ else:
+ return
- case node.sym:
- of ERROR:
- let (line, col) = getLineCol(node)
- echo &"Potentially invalid syntax at line {line} column {col}"
- of preproc_def:
- pPreprocDef(node)
- of type_definition:
- pTypeDefinition(node)
- of declaration:
- pDeclaration(node)
- of struct_specifier:
- if node.parent.sym notin [type_definition, declaration]:
- pStructSpecifier(node)
- of enum_specifier:
- if node.parent.sym notin [type_definition, declaration]:
- pEnumSpecifier(node)
+ if node.tsNodeNamedChildCount() != 0:
+ nextnode = node.tsNodeNamedChild(0)
else:
- discard
+ nextnode = node.tsNodeNextNamedSibling()
+
+ if nextnode.tsNodeIsNull():
+ while true:
+ node = node.tsNodeParent()
+ if node == root:
+ break
+ if not node.tsNodeNextNamedSibling().tsNodeIsNull():
+ node = node.tsNodeNextNamedSibling()
+ break
+ else:
+ node = nextnode
+
+ if node == root:
+ break
+
+proc printNim*(fullpath: string, root: TSNode) =
+ echo "{.experimental: \"codeReordering\".}"
+
+ var fp = fullpath.replace("\\", "/")
+ gStateRT.currentHeader = getCurrentHeader(fullpath)
+ gStateRT.constStr &= &" {gStateRT.currentHeader} = \"{fp}\"\n"
+
+ genNimAst(root)
+
+ if gStateRT.constStr.nBl:
+ echo "const\n" & gStateRT.constStr
+
+ if gStateRT.typeStr.nBl:
+ echo "type\n" & gStateRT.typeStr
- for child in node.children:
- genNimAst(child)
+ if gStateRT.procStr.nBl:
+ echo gStateRT.procStr
diff --git a/nimterop/cimport.nim b/nimterop/cimport.nim
index 0317787..fc0d057 100644
--- a/nimterop/cimport.nim
+++ b/nimterop/cimport.nim
@@ -1,6 +1,6 @@
import macros, os, strformat, strutils
-import ast, getters, globals, lisp
+import getters, globals
proc interpPath(dir: string): string=
# TODO: more robust: needs a DirSep after "$projpath"
@@ -24,19 +24,31 @@ proc findPath(path: string, fail = true): string =
else:
return ""
+proc getToast(fullpath: string): string =
+ var
+ cmd = "toast -n -p "
+
+ for i in gStateCT.defines:
+ cmd &= &"-D\"{i}\" "
+
+ for i in gStateCT.includeDirs:
+ cmd &= &"-I\"{i}\" "
+
+ result = staticExec(cmd & fullpath)
+
proc cSearchPath*(path: string): string {.compileTime.}=
result = findPath(path, fail = false)
if result.len == 0:
var found = false
- for inc in gSearchDirs:
+ for inc in gStateCT.searchDirs:
result = (inc & "/" & path).replace("\\", "/")
if fileExists(result) or dirExists(result):
found = true
break
- doAssert found, "File or directory not found: " & path & " gSearchDirs: " & $gSearchDirs
+ doAssert found, "File or directory not found: " & path & " gStateCT.searchDirs: " & $gStateCT.searchDirs
macro cDebug*(): untyped =
- gDebug = true
+ gStateCT.debug = true
macro cDefine*(name: static string, val: static string = ""): untyped =
result = newNimNode(nnkStmtList)
@@ -45,21 +57,21 @@ macro cDefine*(name: static string, val: static string = ""): untyped =
if val.nBl:
str &= &"=\"{val}\""
- if str notin gDefines:
- gDefines.add(str)
+ if str notin gStateCT.defines:
+ gStateCT.defines.add(str)
str = "-D" & str
result.add(quote do:
{.passC: `str`.}
)
- if gDebug:
+ if gStateCT.debug:
echo result.repr
macro cAddSearchDir*(dir: static string): untyped =
var dir = interpPath(dir)
- if dir notin gSearchDirs:
- gSearchDirs.add(dir)
+ if dir notin gStateCT.searchDirs:
+ gStateCT.searchDirs.add(dir)
macro cIncludeDir*(dir: static string): untyped =
var dir = interpPath(dir)
@@ -69,14 +81,14 @@ macro cIncludeDir*(dir: static string): untyped =
fullpath = findPath(dir)
str = &"-I\"{fullpath}\""
- if fullpath notin gIncludeDirs:
- gIncludeDirs.add(fullpath)
+ if fullpath notin gStateCT.includeDirs:
+ gStateCT.includeDirs.add(fullpath)
result.add(quote do:
{.passC: `str`.}
)
- if gDebug:
+ if gStateCT.debug:
echo result.repr
macro cAddStdDir*(mode = "c"): untyped =
@@ -109,11 +121,11 @@ macro cCompile*(path: static string): untyped =
var
ufn = fn
uniq = 1
- while ufn in gCompile:
+ while ufn in gStateCT.compile:
ufn = fn & $uniq
uniq += 1
- gCompile.add(ufn)
+ gStateCT.compile.add(ufn)
if fn == ufn:
return "{.compile: \"$#\".}" % file.replace("\\", "/")
else:
@@ -138,44 +150,18 @@ macro cCompile*(path: static string): untyped =
result.add stmt.parseStmt()
- if gDebug:
+ if gStateCT.debug:
echo result.repr
macro cImport*(filename: static string): untyped =
result = newNimNode(nnkStmtList)
- result.add addReorder()
let
fullpath = findPath(filename)
- root = parseLisp(fullpath)
echo "Importing " & fullpath
- gCode = staticRead(fullpath)
- gConstStr = ""
- gTypeStr = ""
-
- addHeader(fullpath)
- genNimAst(root)
-
- if gConstStr.nBl:
- if gDebug:
- echo "const\n" & gConstStr
- result.add parseStmt(
- "const\n" & gConstStr
- )
-
- if gTypeStr.nBl:
- if gDebug:
- echo "type\n" & gTypeStr
- result.add parseStmt(
- "type\n" & gTypeStr
- )
-
- if gProcStr.nBl:
- if gDebug:
- echo gProcStr
- result.add gProcStr.parseStmt()
+ result.add parseStmt(getToast(fullpath))
- if gDebug:
+ if gStateCT.debug:
echo result.repr
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index c9ac3b9..a402610 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -2,6 +2,8 @@ import macros, ospaths, strformat, strutils
import regex
+import treesitter/runtime
+
import git, globals
proc sanitizePath*(path: string): string =
@@ -19,21 +21,24 @@ proc getLit*(str: string): string =
str.contains(re"^0x[\d]+$"):
return str
-proc getNodeValIf*(node: ref Ast, esym: Sym): string =
- if esym != node.sym:
+proc getNodeValIf*(node: TSNode, esym: string): string =
+ if esym != $node.tsNodeType():
return
- return gCode[node.start .. node.stop-1].strip()
+ return gStateRT.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
-proc getLineCol*(node: ref Ast): tuple[line, col: int] =
+proc getLineCol*(node: TSNode): tuple[line, col: int] =
result.line = 1
result.col = 1
- for i in 0 .. node.start-1:
- if gCode[i] == '\n':
+ for i in 0 .. node.tsNodeStartByte()-1:
+ if gStateRT.code[i] == '\n':
result.col = 0
result.line += 1
result.col += 1
+proc getCurrentHeader*(fullpath: string): string =
+ ("header" & fullpath.splitFile().name.replace(re"[-.]+", ""))
+
proc getGccPaths*(mode = "c"): string =
var
nul = when defined(Windows): "nul" else: "/dev/null"
@@ -45,23 +50,15 @@ proc getPreprocessor*(fullpath: string, mode = "cpp"): string =
var
mmode = if mode == "cpp": "c++" else: mode
cmd = &"gcc -E -dD -x{mmode} "
- gdef, gdir: seq[string]
rdata: seq[string] = @[]
start = false
sfile = fullpath.sanitizePath
- when nimvm:
- gdef = gDefines
- gdir = gIncludeDirs
- else:
- gdef = gDefinesRT
- gdir = gIncludeDirsRT
-
- for inc in gdir:
+ for inc in gStateRT.includeDirs:
cmd &= &"-I\"{inc}\" "
- for def in gdef:
+ for def in gStateRT.defines:
cmd &= &"-D{def} "
cmd &= &"\"{fullpath}\""
diff --git a/nimterop/globals.nim b/nimterop/globals.nim
index 8797af8..98e4249 100644
--- a/nimterop/globals.nim
+++ b/nimterop/globals.nim
@@ -1,42 +1,16 @@
-import macros
-
type
- Sym* = enum
- ERROR, IGNORED,
- enumerator, enumerator_list, enum_specifier,
- declaration,
- field_declaration, field_declaration_list, field_identifier, function_declarator,
- identifier,
- number_literal,
- parameter_declaration, parameter_list, pointer_declarator, preproc_arg, preproc_def, primitive_type,
- struct_specifier,
- type_definition, type_identifier
+ State* = object
+ compile*, defines*, headers*, includeDirs*, searchDirs*: seq[string]
- Ast* = object
- sym*: Sym
- start*, stop*: int
- parent*: ref Ast
- children*: seq[ref Ast]
+ debug*, past*, preprocess*, pnim*, pretty*: bool
-var
- gDefines* {.compiletime.}: seq[string]
- gDefinesRT*: seq[string]
- gCompile* {.compiletime.}: seq[string]
- gConsts* {.compiletime.}: seq[string]
- gHeaders* {.compiletime.}: seq[string]
- gIncludeDirs* {.compiletime.}: seq[string]
- gIncludeDirsRT*: seq[string]
- gProcs* {.compiletime.}: seq[string]
- gSearchDirs* {.compiletime.}: seq[string]
- gTypes* {.compiletime.}: seq[string]
+ consts*, procs*, types*: seq[string]
- gCode* {.compiletime.}: string
- gConstStr* {.compiletime.}: string
- gCurrentHeader* {.compiletime.}: string
- gDebug* {.compiletime.}: bool
- gReorder* {.compiletime.}: bool
- gProcStr* {.compiletime.}: string
- gTypeStr* {.compiletime.}: string
+ code*, constStr*, currentHeader*, mode*, procStr*, typeStr*: string
+
+var
+ gStateCT* {.compiletime.}: State
+ gStateRT*: State
template nBl*(s: untyped): untyped =
(s.len != 0) \ No newline at end of file
diff --git a/toast.nim b/toast.nim
index 409b293..4877c50 100644
--- a/toast.nim
+++ b/toast.nim
@@ -2,18 +2,20 @@ import os, strutils
import treesitter/[runtime, c, cpp]
-import nimterop/[globals, getters]
+import nimterop/[ast, globals, getters]
const HELP = """
> toast header.h
-a print AST output
--c C mode - CPP is default
-m print minimized AST output - non-pretty (implies -a)
+-n print Nim output
+
+-c C mode - CPP is default
-p run preprocessor on header
-D definitions to pass to preprocessor
-I include directory to pass to preprocessor"""
-proc printLisp(root: TSNode, data: var string, pretty = true) =
+proc printLisp(root: TSNode) =
var
node = root
nextnode: TSNode
@@ -21,19 +23,19 @@ proc printLisp(root: TSNode, data: var string, pretty = true) =
while true:
if not node.tsNodeIsNull():
- if pretty:
+ if gStateRT.pretty:
stdout.write spaces(depth)
stdout.write "(" & $node.tsNodeType() & " " & $node.tsNodeStartByte() & " " & $node.tsNodeEndByte()
else:
return
if node.tsNodeNamedChildCount() != 0:
- if pretty:
+ if gStateRT.pretty:
echo ""
nextnode = node.tsNodeNamedChild(0)
depth += 1
else:
- if pretty:
+ if gStateRT.pretty:
echo ")"
else:
stdout.write ")"
@@ -45,7 +47,7 @@ proc printLisp(root: TSNode, data: var string, pretty = true) =
depth -= 1
if depth == -1:
break
- if pretty:
+ if gStateRT.pretty:
echo spaces(depth) & ")"
else:
stdout.write ")"
@@ -60,7 +62,7 @@ proc printLisp(root: TSNode, data: var string, pretty = true) =
if node == root:
break
-proc process(path: string, mode="cpp", past, pretty, preprocess: bool) =
+proc process(path: string) =
if not existsFile(path):
echo "Invalid path " & path
return
@@ -68,54 +70,54 @@ proc process(path: string, mode="cpp", past, pretty, preprocess: bool) =
var
parser = tsParserNew()
ext = path.splitFile().ext
- pmode = ""
- data = ""
defer:
parser.tsParserDelete()
- if mode.len != 0:
- pmode = mode
+ if gStateRT.mode.len != 0:
+ gStateRT.mode = "cpp"
elif ext in [".h", ".c"]:
- pmode = "c"
+ gStateRT.mode = "c"
elif ext in [".hxx", ".hpp", ".hh", ".H", ".h++", ".cpp", ".cxx", ".cc", ".C", ".c++"]:
- pmode = "cpp"
+ gStateRT.mode = "cpp"
- if preprocess:
- data = getPreprocessor(path)
+ if gStateRT.preprocess:
+ gStateRT.code = getPreprocessor(path)
else:
- data = readFile(path)
+ gStateRT.code = readFile(path)
- if pmode == "c":
+ if gStateRT.mode == "c":
if not parser.tsParserSetLanguage(treeSitterC()):
echo "Failed to load C parser"
quit()
- elif pmode == "cpp":
+ elif gStateRT.mode == "cpp":
if not parser.tsParserSetLanguage(treeSitterCpp()):
echo "Failed to load C++ parser"
quit()
else:
- echo "Invalid parser " & mode
+ echo "Invalid parser " & gStateRT.mode
quit()
var
- tree = parser.tsParserParseString(nil, data.cstring, data.len.uint32)
+ tree = parser.tsParserParseString(nil, gStateRT.code.cstring, gStateRT.code.len.uint32)
root = tree.tsTreeRootNode()
defer:
tree.tsTreeDelete()
- if past:
- printLisp(root, data, pretty)
+ if gStateRT.past:
+ printLisp(root)
+ elif gStateRT.pnim:
+ printNim(path, root)
proc parseCli() =
- var
- mode = "cpp"
- params = commandLineParams()
+ var params = commandLineParams()
- past = false
- pretty = true
- preprocess = false
+ gStateRT.mode = "cpp"
+ gStateRT.past = false
+ gStateRT.pnim = false
+ gStateRT.pretty = true
+ gStateRT.preprocess = false
for param in params:
let flag = if param.len() <= 2: param else: param[0..<2]
@@ -124,19 +126,21 @@ proc parseCli() =
echo HELP
quit()
elif flag == "-a":
- past = true
+ gStateRT.past = true
elif flag == "-c":
- mode = "c"
+ gStateRT.mode = "c"
elif flag == "-m":
- past = true
- pretty = false
+ gStateRT.past = true
+ gStateRT.pretty = false
+ elif flag == "-n":
+ gStateRT.pnim = true
elif flag == "-p":
- preprocess = true
+ gStateRT.preprocess = true
elif flag == "-D":
- gDefinesRT.add(param[2..^1])
+ gStateRT.defines.add(param[2..^1].strip(chars={'"'}))
elif flag == "-I":
- gIncludeDirsRT.add(param[2..^1])
+ gStateRT.includeDirs.add(param[2..^1].strip(chars={'"'}))
else:
- process(param, mode, past, pretty, preprocess)
+ process(param)
parseCli()