aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Viswanathan <dev@genotrance.com>2018-12-03 14:58:27 -0600
committerGanesh Viswanathan <dev@genotrance.com>2018-12-03 14:58:27 -0600
commit33956c36ee837603ed94f94b528a3bbb6bd51890 (patch)
tree3e6849e177eb97a2abbe6a94596648fd3ff01c1e
parent9c206fea4f93fe2dcc9b5332d08d86f6dc5adb03 (diff)
downloadnimterop-33956c36ee837603ed94f94b528a3bbb6bd51890.tar.gz
nimterop-33956c36ee837603ed94f94b528a3bbb6bd51890.zip
Switch to simpler grammar engine
-rw-r--r--nimterop/ast.nim300
-rw-r--r--nimterop/astold.nim297
-rw-r--r--nimterop/getters.nim61
-rw-r--r--nimterop/globals.nim19
-rw-r--r--nimterop/grammar.nim244
-rw-r--r--nimterop/lisp.nim35
6 files changed, 690 insertions, 266 deletions
diff --git a/nimterop/ast.nim b/nimterop/ast.nim
index 069ecba..cce07c3 100644
--- a/nimterop/ast.nim
+++ b/nimterop/ast.nim
@@ -1,265 +1,83 @@
-import macros, os, strformat, strutils
+import strformat, strutils, tables
-import treesitter/runtime
-
-import getters, globals
-
-#
-# Preprocessor
-#
-
-proc pPreprocDef(node: TSNode) =
- if node.tsNodeNamedChildCount() == 2:
- let
- name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
- val = getNodeValIf(node.tsNodeNamedChild(1), "preproc_arg")
-
- if name.nBl and val.nBl and name notin gStateRT.consts:
- gStateRT.consts.add(name)
- if val.getLit().nBl:
- # #define NAME VALUE
- gStateRT.constStr &= &" {name.getIdentifier()}* = {val} # pPreprocDef()\n"
-
-#
-# Types
-#
-
-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.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.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:
- return
- elif ptyp.nBl:
- ptyp = ptyp.getType()
- if ptyp != "object" and ptrname:
- ptyp = &"ptr {ptyp}"
- result = &"{offset}{name.getIdentifier()}: {ptyp}"
- elif ttyp.nBl:
- if ptrname:
- ttyp = &"ptr {ttyp}"
- result = &"{offset}{name.getIdentifier()}: {ttyp}"
- 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}"
-
-proc pStructSpecifier(node: TSNode, name = "") =
- var stmt: string
- 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:
- gStateRT.types.add(name)
- if name != typ:
- # typedef struct X Y
- gStateRT.typeStr &= &" {name.getIdentifier()}* = {typ} #1 pStructSpecifier()\n"
- else:
- # typedef struct X X
- gStateRT.typeStr &= &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #2 pStructSpecifier()\n"
-
- of "field_declaration_list":
- # typedef struct { fields } X
- stmt = &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #3 pStructSpecifier()\n"
-
- if node.tsNodeNamedChild(0).tsNodeNamedChildCount() != 0:
- for i in 0 .. node.tsNodeNamedChild(0).tsNodeNamedChildCount()-1:
- if $node.tsNodeNamedChild(0).tsNodeNamedChild(i).tsNodeType() == "comment":
- continue
- let ts = typeScan(node.tsNodeNamedChild(0).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
- if ts.len == 0:
- return
- stmt &= ts & "\n"
-
- gStateRT.types.add(name)
- gStateRT.typeStr &= stmt
- else:
- discard
-
- 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: {gStateRT.currentHeader}, bycopy.}} = object #4 pStructSpecifier()\n"
+import regex
- if node.tsNodeNamedChild(1).tsNodeNamedChildCount() != 0:
- for i in 0 .. node.tsNodeNamedChild(1).tsNodeNamedChildCount()-1:
- if $node.tsNodeNamedChild(1).tsNodeNamedChild(i).tsNodeType() == "comment":
- continue
- let ts = typeScan(node.tsNodeNamedChild(1).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
- if ts.len == 0:
- return
- stmt &= ts & "\n"
-
- gStateRT.types.add(name)
- gStateRT.typeStr &= stmt
-
-proc pEnumSpecifier(node: TSNode, name = "") =
- var
- ename: string
- elid: uint32
- stmt: string
-
- 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 node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "enumerator_list":
- if name.len == 0:
- ename = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
- else:
- ename = name
- elid = 1
- if ename.nBl:
- # enum X { fields }
- stmt = &" {ename}* = enum #2 pEnumSpecifier()\n"
- else:
- return
- else:
- return
+import treesitter/runtime
- if node.tsNodeNamedChild(elid).tsNodeNamedChildCount() != 0:
- for i in 0 .. node.tsNodeNamedChild(elid).tsNodeNamedChildCount()-1:
- let field = node.tsNodeNamedChild(elid).tsNodeNamedChild(i)
- if $field.tsNodeType() == "comment":
- continue
- 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
+import "."/[getters, globals, grammar]
- if ename notin gStateRT.types:
- gStateRT.types.add(name)
- gStateRT.typeStr &= stmt
+const gAtoms = @[
+ "field_identifier",
+ "identifier",
+ "number_literal",
+ "preproc_arg",
+ "primitive_type",
+ "type_identifier"
+]
-proc pTypeDefinition(node: TSNode) =
- if node.tsNodeNamedChildCount() == 2:
+proc saveNodeData(node: TSNode): bool =
+ let name = $node.tsNodeType()
+ if name in gAtoms:
var
- name = getNodeValIf(node.tsNodeNamedChild(1), "type_identifier")
- ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
- ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
- ptrname = false
+ val = node.getNodeVal()
- 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 == "primitive_type":
+ val = val.getType()
- if name.nBl and name notin gStateRT.types:
- if ptyp.nBl:
- # typedef int X
- gStateRT.types.add(name)
- ptyp = ptyp.getType()
- if ptyp != "object" and ptrname:
- ptyp = &"ptr {ptyp}"
- gStateRT.typeStr &= &" {name.getIdentifier()}* = {ptyp} #1 pTypeDefinition()\n"
- elif ttyp.nBl:
- # typedef X Y
- gStateRT.types.add(name)
- if ptrname:
- ttyp = &"ptr {ttyp}"
- gStateRT.typeStr &= &" {name.getIdentifier()}* = {ttyp} #2 pTypeDefinition()\n"
- else:
- case $node.tsNodeNamedChild(0).tsNodeType():
- of "struct_specifier":
- pStructSpecifier(node.tsNodeNamedChild(0), name)
- of "enum_specifier":
- pEnumSpecifier(node.tsNodeNamedChild(0), name)
- else:
- discard
+ if node.tsNodeParent().tsNodeType() == "pointer_declarator":
+ if gStateRT.data[^1].val != "object":
+ gStateRT.data[^1].val = "ptr " & gStateRT.data[^1].val
-proc pFunctionDeclarator(node: TSNode, typ: string) =
- if node.tsNodeNamedChildCount() == 2:
- let
- name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
-
- 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()}*("
-
- 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 &= ") "
+ gStateRT.data.add((name, val))
- stmt &= &"{{.importc: \"{name}\", header: {gStateRT.currentHeader}.}}\n"
+ return true
- gStateRT.procs.add(name)
- gStateRT.procStr &= stmt
+proc searchAstForNode(ast: ref Ast, node: TSNode): bool =
+ let
+ childNames = node.getTSNodeNamedChildNames().join()
-proc pDeclaration*(node: TSNode) =
- if node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "function_declarator":
+ if ast.children.len != 0:
let
- ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
- ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
-
- if ptyp.nBl:
- pFunctionDeclarator(node.tsNodeNamedChild(1), ptyp.getType())
- elif ttyp.nBl:
- 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.tsNodeNamedChild(1), styp)
+ rstr = ast.getRegexForAstChildren()
+
+ if childNames.contains(rstr.toPattern):
+ if node.getTSNodeNamedChildCountSansComments() != 0:
+ var flag = true
+ for i in 0 .. node.tsNodeNamedChildCount()-1:
+ if node.tsNodeType() != "comment":
+ let
+ nodeChild = node.tsNodeNamedChild(i)
+ astChild = ast.getAstChildByName($nodeChild.tsNodeType())
+ if not searchAstForNode(astChild, nodeChild):
+ flag = false
+ break
+
+ if flag:
+ return node.saveNodeData()
+ else:
+ return node.saveNodeData()
+ elif node.getTSNodeNamedChildCountSansComments() == 0:
+ return node.saveNodeData()
-proc genNimAst(root: TSNode) =
+proc searchAst(root: TSNode) =
var
node = root
nextnode: TSNode
while true:
if not node.tsNodeIsNull():
- case $node.tsNodeType():
- of "ERROR":
- let (line, col) = getLineCol(node)
- let file = gStateRT.sourceFile
- echo &"# [toast] Potentially invalid syntax at {file}:{line}:{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:
- # TODO: log
- discard
+ let
+ name = $node.tsNodeType()
+ if name in gStateRT.ast:
+ for ast in gStateRT.ast[name]:
+ if searchAstForNode(ast, node):
+ ast.tonim()
+ break
+ gStateRT.data = @[]
else:
return
- if node.tsNodeNamedChildCount() != 0:
+ if $node.tsNodeType() notin gStateRT.ast and node.tsNodeNamedChildCount() != 0:
nextnode = node.tsNodeNamedChild(0)
else:
nextnode = node.tsNodeNextNamedSibling()
@@ -279,13 +97,15 @@ proc genNimAst(root: TSNode) =
break
proc printNim*(fullpath: string, root: TSNode) =
+ parseGrammar()
+
echo "{.experimental: \"codeReordering\".}"
var fp = fullpath.replace("\\", "/")
gStateRT.currentHeader = getCurrentHeader(fullpath)
gStateRT.constStr &= &" {gStateRT.currentHeader} = \"{fp}\"\n"
- genNimAst(root)
+ root.searchAst()
if gStateRT.constStr.nBl:
echo "const\n" & gStateRT.constStr
diff --git a/nimterop/astold.nim b/nimterop/astold.nim
new file mode 100644
index 0000000..069ecba
--- /dev/null
+++ b/nimterop/astold.nim
@@ -0,0 +1,297 @@
+import macros, os, strformat, strutils
+
+import treesitter/runtime
+
+import getters, globals
+
+#
+# Preprocessor
+#
+
+proc pPreprocDef(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2:
+ let
+ name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
+ val = getNodeValIf(node.tsNodeNamedChild(1), "preproc_arg")
+
+ if name.nBl and val.nBl and name notin gStateRT.consts:
+ gStateRT.consts.add(name)
+ if val.getLit().nBl:
+ # #define NAME VALUE
+ gStateRT.constStr &= &" {name.getIdentifier()}* = {val} # pPreprocDef()\n"
+
+#
+# Types
+#
+
+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.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.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:
+ return
+ elif ptyp.nBl:
+ ptyp = ptyp.getType()
+ if ptyp != "object" and ptrname:
+ ptyp = &"ptr {ptyp}"
+ result = &"{offset}{name.getIdentifier()}: {ptyp}"
+ elif ttyp.nBl:
+ if ptrname:
+ ttyp = &"ptr {ttyp}"
+ result = &"{offset}{name.getIdentifier()}: {ttyp}"
+ 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}"
+
+proc pStructSpecifier(node: TSNode, name = "") =
+ var stmt: string
+ 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:
+ gStateRT.types.add(name)
+ if name != typ:
+ # typedef struct X Y
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {typ} #1 pStructSpecifier()\n"
+ else:
+ # typedef struct X X
+ gStateRT.typeStr &= &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #2 pStructSpecifier()\n"
+
+ of "field_declaration_list":
+ # typedef struct { fields } X
+ stmt = &" {name.getIdentifier()}* {{.importc: \"{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object #3 pStructSpecifier()\n"
+
+ if node.tsNodeNamedChild(0).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(0).tsNodeNamedChildCount()-1:
+ if $node.tsNodeNamedChild(0).tsNodeNamedChild(i).tsNodeType() == "comment":
+ continue
+ let ts = typeScan(node.tsNodeNamedChild(0).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
+ if ts.len == 0:
+ return
+ stmt &= ts & "\n"
+
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
+ else:
+ discard
+
+ 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: {gStateRT.currentHeader}, bycopy.}} = object #4 pStructSpecifier()\n"
+
+ if node.tsNodeNamedChild(1).tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChild(1).tsNodeNamedChildCount()-1:
+ if $node.tsNodeNamedChild(1).tsNodeNamedChild(i).tsNodeType() == "comment":
+ continue
+ let ts = typeScan(node.tsNodeNamedChild(1).tsNodeNamedChild(i), "field_declaration", "field_identifier", " ")
+ if ts.len == 0:
+ return
+ stmt &= ts & "\n"
+
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
+
+proc pEnumSpecifier(node: TSNode, name = "") =
+ var
+ ename: string
+ elid: uint32
+ stmt: string
+
+ 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 node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "enumerator_list":
+ if name.len == 0:
+ ename = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
+ else:
+ ename = name
+ elid = 1
+ if ename.nBl:
+ # enum X { fields }
+ stmt = &" {ename}* = enum #2 pEnumSpecifier()\n"
+ else:
+ return
+ 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 $field.tsNodeType() == "comment":
+ continue
+ 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 gStateRT.types:
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= stmt
+
+proc pTypeDefinition(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2:
+ var
+ 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.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 gStateRT.types:
+ if ptyp.nBl:
+ # typedef int X
+ gStateRT.types.add(name)
+ ptyp = ptyp.getType()
+ if ptyp != "object" and ptrname:
+ ptyp = &"ptr {ptyp}"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {ptyp} #1 pTypeDefinition()\n"
+ elif ttyp.nBl:
+ # typedef X Y
+ gStateRT.types.add(name)
+ if ptrname:
+ ttyp = &"ptr {ttyp}"
+ gStateRT.typeStr &= &" {name.getIdentifier()}* = {ttyp} #2 pTypeDefinition()\n"
+ else:
+ 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: TSNode, typ: string) =
+ if node.tsNodeNamedChildCount() == 2:
+ let
+ name = getNodeValIf(node.tsNodeNamedChild(0), "identifier")
+
+ 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()}*("
+
+ 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: {gStateRT.currentHeader}.}}\n"
+
+ gStateRT.procs.add(name)
+ gStateRT.procStr &= stmt
+
+proc pDeclaration*(node: TSNode) =
+ if node.tsNodeNamedChildCount() == 2 and $node.tsNodeNamedChild(1).tsNodeType() == "function_declarator":
+ let
+ ptyp = getNodeValIf(node.tsNodeNamedChild(0), "primitive_type")
+ ttyp = getNodeValIf(node.tsNodeNamedChild(0), "type_identifier")
+
+ if ptyp.nBl:
+ pFunctionDeclarator(node.tsNodeNamedChild(1), ptyp.getType())
+ elif ttyp.nBl:
+ 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.tsNodeNamedChild(1), styp)
+
+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)
+ let file = gStateRT.sourceFile
+ echo &"# [toast] Potentially invalid syntax at {file}:{line}:{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:
+ # TODO: log
+ discard
+ else:
+ return
+
+ if node.tsNodeNamedChildCount() != 0:
+ nextnode = node.tsNodeNamedChild(0)
+ else:
+ 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
+
+ if gStateRT.procStr.nBl:
+ echo gStateRT.procStr
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index daf01ef..ff8a361 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -21,11 +21,14 @@ proc getLit*(str: string): string =
str.contains(re"^0x[\d]+$"):
return str
+proc getNodeVal*(node: TSNode): string =
+ return gStateRT.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
+
proc getNodeValIf*(node: TSNode, esym: string): string =
if esym != $node.tsNodeType():
return
- return gStateRT.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
+ return node.getNodeVal()
proc getLineCol*(node: TSNode): tuple[line, col: int] =
result.line = 1
@@ -81,3 +84,59 @@ proc getPreprocessor*(fullpath: string, mode = "cpp"): string =
.replace(re"\(\(__format__[\s]*\(__[gnu_]*printf__, [\d]+, [\d]+\)\)\);", ";")
)
return rdata.join("\n")
+
+converter toString*(kind: Kind): string =
+ return case kind:
+ of exactlyOne:
+ ""
+ of oneOrMore:
+ "+"
+ of zeroOrMore:
+ "*"
+ of zeroOrOne:
+ "?"
+
+converter toKind*(kind: string): Kind =
+ return case kind:
+ of "+":
+ oneOrMore
+ of "*":
+ zeroOrMore
+ of "?":
+ zeroOrOne
+ else:
+ exactlyOne
+
+proc getNameKind*(name: string): tuple[name: string, kind: Kind] =
+ result.name = name
+ result.kind = $name[^1]
+
+ if result.kind != exactlyOne:
+ result.name = name[0 .. ^2]
+
+proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
+ if node.tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChildCount()-1:
+ if $node.tsNodeType() != "comment":
+ result += 1
+
+proc getTSNodeNamedChildNames*(node: TSNode): seq[string] =
+ if node.tsNodeNamedChildCount() != 0:
+ for i in 0 .. node.tsNodeNamedChildCount()-1:
+ let
+ name = $node.tsNodeNamedChild(i).tsNodeType()
+
+ if name != "comment":
+ result.add(name)
+
+proc getRegexForAstChildren*(ast: ref Ast): string =
+ result = "^"
+ for i in 0 .. ast.children.len-1:
+ let kind: string = ast.children[i].kind
+ result &= &"(?:{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]
diff --git a/nimterop/globals.nim b/nimterop/globals.nim
index f1ba151..39969bc 100644
--- a/nimterop/globals.nim
+++ b/nimterop/globals.nim
@@ -1,4 +1,18 @@
+import tables
+
type
+ Kind* = enum
+ exactlyOne
+ oneOrMore # +
+ zeroOrMore # *
+ zeroOrOne # ?
+
+ Ast* = object
+ name*: string
+ kind*: Kind
+ children*: seq[ref Ast]
+ tonim*: proc () {.closure, locks: 0.}
+
State* = object
compile*, defines*, headers*, includeDirs*, searchDirs*: seq[string]
@@ -9,6 +23,10 @@ type
code*, constStr*, currentHeader*, mode*, procStr*, typeStr*: string
sourceFile*: string # eg, C or C++ source or header file
+ ast*: Table[string, seq[ref Ast]]
+ data*: seq[tuple[name, val: string]]
+ grammar*: seq[tuple[grammar: string, call: proc() {.locks: 0.}]]
+
var
gStateCT* {.compiletime.}: State
gStateRT*: State
@@ -16,7 +34,6 @@ var
template nBl*(s: typed): untyped =
(s.len != 0)
-
type CompileMode* = enum
c,
cpp,
diff --git a/nimterop/grammar.nim b/nimterop/grammar.nim
new file mode 100644
index 0000000..4e819d9
--- /dev/null
+++ b/nimterop/grammar.nim
@@ -0,0 +1,244 @@
+import strformat, tables
+
+import "."/[getters, globals, lisp]
+
+proc initGrammar() =
+ # #define X Y
+ gStateRT.grammar.add(("""
+ (preproc_def
+ (identifier)
+ (preproc_arg)
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ let
+ name = gStateRT.data[0].val.getIdentifier()
+ val = gStateRT.data[1].val
+
+ if name notin gStateRT.consts:
+ gStateRT.consts.add(name)
+ gStateRT.constStr &= &" {name}* = {val}\n"
+ ))
+
+ # typedef int X
+ # typedef X Y
+ # typedef struct X Y
+ # typedef ?* Y
+ gStateRT.grammar.add(("""
+ (type_definition
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (type_identifier?)
+ (pointer_declarator?
+ (type_identifier)
+ )
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ var
+ name = gStateRT.data[1].val.getIdentifier()
+ typ = gStateRT.data[0].val
+
+ if name notin gStateRT.types:
+ gStateRT.types.add(name)
+ gStateRT.typeStr &= &" {name}* = {typ}\n"
+ ))
+
+ proc pStructCommon(name: string, fstart, fend: int, prefix="") =
+ let
+ nname = name.getIdentifier()
+ if nname notin gStateRT.types:
+ gStateRT.types.add(nname)
+ gStateRT.typeStr &= &" {nname}* {{.importc: \"{prefix}{name}\", header: {gStateRT.currentHeader}, bycopy.}} = object\n"
+
+ for i in fstart .. gStateRT.data.len-fend:
+ let
+ ftyp = gStateRT.data[i].val
+ fname = gStateRT.data[i+1].val.getIdentifier()
+ gStateRT.typeStr &= &" {fname}*: {ftyp}\n"
+
+ # struct X {}
+ gStateRT.grammar.add(("""
+ (struct_specifier
+ (type_identifier)
+ (field_declaration_list
+ (field_declaration+
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (field_identifier?)
+ (pointer_declarator?
+ (field_identifier)
+ )
+ )
+ )
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ pStructCommon(gStateRT.data[0].val, 1, 2, "struct ")
+ ))
+
+ # typedef struct X {}
+ gStateRT.grammar.add(("""
+ (type_definition
+ (struct_specifier
+ (field_declaration_list
+ (field_declaration+
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (field_identifier?)
+ (pointer_declarator?
+ (field_identifier)
+ )
+ )
+ )
+ )
+ (type_identifier)
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ pStructCommon(gStateRT.data[^1].val, 0, 3)
+ ))
+
+ proc pEnumCommon(name: string, fstart, fend: int, prefix="") =
+ let
+ nname = name.getIdentifier()
+ if nname notin gStateRT.types:
+ gStateRT.types.add(nname)
+ gStateRT.typeStr &= &" {nname}* = enum\n"
+
+ var
+ i = fstart
+ while i < gStateRT.data.len-fend:
+ let
+ fname = gStateRT.data[i].val.getIdentifier()
+
+ if i+1 < gStateRT.data.len-fend and gStateRT.data[i+1].name == "number_literal":
+ gStateRT.typeStr &= &" {fname} = {gStateRT.data[i+1].val}\n"
+ i += 2
+ else:
+ gStateRT.typeStr &= &" {fname}\n"
+ i += 1
+
+ # enum X {}
+ gStateRT.grammar.add(("""
+ (enum_specifier
+ (type_identifier)
+ (enumerator_list
+ (enumerator+
+ (identifier)
+ (number_literal?)
+ )
+ )
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ pEnumCommon(gStateRT.data[0].val, 1, 0)
+ ))
+
+ # typedef enum {} X
+ gStateRT.grammar.add(("""
+ (type_definition
+ (enum_specifier
+ (enumerator_list
+ (enumerator+
+ (identifier)
+ (number_literal?)
+ )
+ )
+ )
+ (type_identifier)
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ pEnumCommon(gStateRT.data[^1].val, 0, 1)
+ ))
+
+ # typ function(typ param1, ...)
+ gStateRT.grammar.add(("""
+ (declaration
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (function_declarator?
+ (identifier)
+ (parameter_list
+ (parameter_declaration*
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (enum_specifier?
+ (type_identifier)
+ )
+ (identifier)
+ )
+ )
+ )
+ (pointer_declarator?
+ (function_declarator?
+ (identifier)
+ (parameter_list
+ (parameter_declaration*
+ (primitive_type|type_identifier?)
+ (struct_specifier?
+ (type_identifier)
+ )
+ (enum_specifier?
+ (type_identifier)
+ )
+ (identifier)
+ )
+ )
+ )
+ )
+ )
+ """,
+ proc () {.closure, locks: 0.} =
+ let
+ ftyp = gStateRT.data[0].val
+ fname = gStateRT.data[1].val
+ fnname = fname.getIdentifier()
+
+ if fnname notin gStateRT.procs:
+ var
+ pout = ""
+ i = 2
+ if gStateRT.data.len > 2:
+ while i < gStateRT.data.len-1:
+ let
+ ptyp = gStateRT.data[i].val
+ pname = gStateRT.data[i+1].val.getIdentifier()
+ pout &= &"{pname}: {ptyp},"
+ i += 2
+ if pout.len != 0 and pout[^1] == ',':
+ pout = pout[0 .. ^2]
+
+ gStateRT.procStr &= &"proc {fnname}({pout}): {ftyp} {{.importc: \"{fname}\", header: {gStateRT.currentHeader}.}}\n"
+
+ ))
+
+proc parseGrammar*() =
+ initGrammar()
+
+ gStateRT.ast = initTable[string, seq[ref Ast]]()
+ for i in 0 .. gStateRT.grammar.len-1:
+ var
+ ast = gStateRT.grammar[i].grammar.parseLisp()
+
+ ast.tonim = gStateRT.grammar[i].call
+ if ast.name notin gStateRT.ast:
+ gStateRT.ast[ast.name] = @[ast]
+ else:
+ gStateRT.ast[ast.name].add(ast)
+
+proc printGrammar*() =
+ for name in gStateRT.ast.keys():
+ for ast in gStateRT.ast[name]:
+ echo ast.printAst()
diff --git a/nimterop/lisp.nim b/nimterop/lisp.nim
index 8fa73e0..3d3c34e 100644
--- a/nimterop/lisp.nim
+++ b/nimterop/lisp.nim
@@ -1,22 +1,18 @@
import strutils
import strformat
-import globals
+import "."/[getters, globals]
var
- gTokens {.compiletime.}: seq[string]
- idx {.compiletime.} = 0
+ gTokens: seq[string]
+ idx = 0
-proc tokenize(fullpath: string) =
+proc tokenize(tree: string) =
var collect = ""
gTokens = @[]
idx = 0
- # TODO: consider calling API directly
- const cmd = &"toast --past --pretty:false --source:{fullpath.quoteShell}"
- var (output, exitCode) = gorgeEx cmd
- doAssert exitCode == 0, $exitCode
- for i in output:
+ for i in tree:
case i:
of ' ', '\n', '\r', '(', ')':
if collect.nBl:
@@ -27,10 +23,6 @@ proc tokenize(fullpath: string) =
else:
collect &= $i
- if gTokens.len == 0:
- echo "toast binary not installed - nimble install nimterop to force build"
- quit(1)
-
proc readFromTokens(): ref Ast =
if idx == gTokens.len:
echo "Bad AST"
@@ -42,18 +34,12 @@ proc readFromTokens(): ref Ast =
quit(1)
if gTokens[idx+1] != "comment":
result = new(Ast)
- try:
- result.sym = parseEnum[Sym](gTokens[idx+1])
- except:
- result.sym = IGNORED
- result.start = gTokens[idx+2].parseInt()
- result.stop = gTokens[idx+3].parseInt()
+ (result.name, result.kind) = gTokens[idx+1].getNameKind()
result.children = @[]
- idx += 4
+ idx += 2
while gTokens[idx] != ")":
var res = readFromTokens()
if not res.isNil():
- res.parent = result
result.children.add(res)
elif gTokens[idx] == ")":
echo "Poor AST"
@@ -62,7 +48,8 @@ proc readFromTokens(): ref Ast =
idx += 1
proc printAst*(node: ref Ast, offset=""): string =
- result = offset & "(" & $node.sym & " " & $node.start & " " & $node.stop
+ result = offset & "(" & node.name & node.kind.toString()
+
if node.children.len != 0:
result &= "\n"
for child in node.children:
@@ -71,7 +58,7 @@ proc printAst*(node: ref Ast, offset=""): string =
else:
result &= ")\n"
-proc parseLisp*(fullpath: string): ref Ast =
- tokenize(fullpath)
+proc parseLisp*(tree: string): ref Ast =
+ tokenize(tree)
return readFromTokens()