Remove global state from toast

This commit is contained in:
Ganesh Viswanathan 2019-05-08 20:16:02 -05:00
commit b0a8f9bec5
6 changed files with 99 additions and 404 deletions

View file

@ -8,7 +8,7 @@ proc saveNodeData(node: TSNode, nimState: NimState): bool =
let name = $node.tsNodeType() let name = $node.tsNodeType()
if name in gAtoms: if name in gAtoms:
var var
val = node.getNodeVal() val = nimState.getNodeVal(node)
if name == "primitive_type" and node.tsNodeParent.tsNodeType() == "sized_type_specifier": if name == "primitive_type" and node.tsNodeParent.tsNodeType() == "sized_type_specifier":
return true return true
@ -54,7 +54,7 @@ proc saveNodeData(node: TSNode, nimState: NimState): bool =
elif name in gExpressions and name != "escape_sequence": elif name in gExpressions and name != "escape_sequence":
if $node.tsNodeParent.tsNodeType() notin gExpressions: if $node.tsNodeParent.tsNodeType() notin gExpressions:
nimState.data.add((name, node.getNodeVal())) nimState.data.add((name, nimState.getNodeVal(node)))
elif name in ["abstract_pointer_declarator", "enumerator", "field_declaration", "function_declarator"]: elif name in ["abstract_pointer_declarator", "enumerator", "field_declaration", "function_declarator"]:
nimState.data.add((name.replace("abstract_", ""), "")) nimState.data.add((name.replace("abstract_", ""), ""))
@ -107,7 +107,7 @@ proc searchAst(root: TSNode, astTable: AstTable, nimState: NimState) =
for ast in astTable[name]: for ast in astTable[name]:
if searchAstForNode(ast, node, nimState): if searchAstForNode(ast, node, nimState):
ast.tonim(ast, node, nimState) ast.tonim(ast, node, nimState)
if gStateRT.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# " & nimState.data.join("\n# ") & "\n" nimState.debugStr &= "\n# " & nimState.data.join("\n# ") & "\n"
break break
nimState.data = @[] nimState.data = @[]
@ -147,7 +147,7 @@ proc printNimHeader*() =
import nimterop/types import nimterop/types
""" % [$now(), getAppFilename(), commandLineParams().join(" ")] """ % [$now(), getAppFilename(), commandLineParams().join(" ")]
proc printNim*(fullpath: string, root: TSNode, astTable: AstTable) = proc printNim*(gState: State, fullpath: string, root: TSNode, astTable: AstTable) =
var var
nimState = new(NimState) nimState = new(NimState)
fp = fullpath.replace("\\", "/") fp = fullpath.replace("\\", "/")
@ -155,9 +155,10 @@ proc printNim*(fullpath: string, root: TSNode, astTable: AstTable) =
nimState.currentHeader = getCurrentHeader(fullpath) nimState.currentHeader = getCurrentHeader(fullpath)
nimState.impHeader = nimState.currentHeader.replace("header", "imp") nimState.impHeader = nimState.currentHeader.replace("header", "imp")
nimState.sourceFile = fullpath
nimState.constStr &= &"\n {nimState.currentHeader} {{.used.}} = \"{fp}\"" nimState.constStr &= &"\n {nimState.currentHeader} {{.used.}} = \"{fp}\""
nimState.debug = gStateRT.debug nimState.gState = gState
root.searchAst(astTable, nimState) root.searchAst(astTable, nimState)

View file

@ -1,297 +0,0 @@
import macros, os, strformat, strutils
import treesitter/api
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

View file

@ -104,14 +104,14 @@ proc checkIdentifier(name, kind, parent, origName: string) =
if parent.nBl: if parent.nBl:
doAssert name.nBl, &"Blank identifier, originally '{parentStr}{name}' ({kind}), cannot be empty" doAssert name.nBl, &"Blank identifier, originally '{parentStr}{name}' ({kind}), cannot be empty"
proc getIdentifier*(name: string, kind: NimSymKind, parent=""): string = proc getIdentifier*(nimState: NimState, name: string, kind: NimSymKind, parent=""): string =
doAssert name.len != 0, "Blank identifier error" doAssert name.len != 0, "Blank identifier error"
if name notin gStateRT.symOverride or parent.nBl: if name notin nimState.gState.symOverride or parent.nBl:
if gStateRT.onSymbol != nil: if nimState.gState.onSymbol != nil:
var var
sym = Symbol(name: name, parent: parent, kind: kind) sym = Symbol(name: name, parent: parent, kind: kind)
gStateRT.onSymbol(sym) nimState.gState.onSymbol(sym)
result = sym.name result = sym.name
else: else:
@ -124,27 +124,27 @@ proc getIdentifier*(name: string, kind: NimSymKind, parent=""): string =
else: else:
result = "" result = ""
proc getUniqueIdentifier*(existing: TableRef[string, string], prefix = ""): string = proc getUniqueIdentifier*(nimState: NimState, prefix = ""): string =
var var
name = prefix & "_" & gStateRT.sourceFile.extractFilename().multiReplace([(".", ""), ("-", "")]) name = prefix & "_" & nimState.sourceFile.extractFilename().multiReplace([(".", ""), ("-", "")])
nimName = name[0] & name[1 .. ^1].replace("_", "").toLowerAscii nimName = name[0] & name[1 .. ^1].replace("_", "").toLowerAscii
count = 1 count = 1
while (nimName & $count) in existing: while (nimName & $count) in nimState.identifiers:
count += 1 count += 1
return name & $count return name & $count
proc addNewIdentifer*(existing: var TableRef[string, string], name: string): bool = proc addNewIdentifer*(nimState: NimState, name: string): bool =
if name notin gStateRT.symOverride: if name notin nimState.gState.symOverride:
let let
nimName = name[0] & name[1 .. ^1].replace("_", "").toLowerAscii nimName = name[0] & name[1 .. ^1].replace("_", "").toLowerAscii
if existing.hasKey(nimName): if nimState.identifiers.hasKey(nimName):
doAssert name == existing[nimName], &"Identifier '{name}' is a stylistic duplicate of identifier '{existing[nimName]}', use 'cPlugin:onSymbol()' to rename" doAssert name == nimState.identifiers[nimName], &"Identifier '{name}' is a stylistic duplicate of identifier '{nimState.identifiers[nimName]}', use 'cPlugin:onSymbol()' to rename"
result = false result = false
else: else:
existing[nimName] = name nimState.identifiers[nimName] = name
result = true result = true
proc getPtrType*(str: string): string = proc getPtrType*(str: string): string =
@ -166,20 +166,14 @@ proc getLit*(str: string): string =
str.contains(re"^0x[\d]+$"): str.contains(re"^0x[\d]+$"):
return str return str
proc getNodeVal*(node: TSNode): string = proc getNodeVal*(nimState: NimState, node: TSNode): string =
return gStateRT.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip() return nimState.gState.code[node.tsNodeStartByte() .. node.tsNodeEndByte()-1].strip()
proc getNodeValIf*(node: TSNode, esym: string): string = proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
if esym != $node.tsNodeType():
return
return node.getNodeVal()
proc getLineCol*(node: TSNode): tuple[line, col: int] =
result.line = 1 result.line = 1
result.col = 1 result.col = 1
for i in 0 .. node.tsNodeStartByte().int-1: for i in 0 .. node.tsNodeStartByte().int-1:
if gStateRT.code[i] == '\n': if gState.code[i] == '\n':
result.col = 0 result.col = 0
result.line += 1 result.line += 1
result.col += 1 result.col += 1
@ -201,7 +195,7 @@ proc removeStatic(content: string): string =
result.add(body.replace(re"(?m)^(.*\n?)", "//$1")) result.add(body.replace(re"(?m)^(.*\n?)", "//$1"))
) )
proc getPreprocessor*(fullpath: string, mode = "cpp"): string = proc getPreprocessor*(gState: State, fullpath: string, mode = "cpp"): string =
var var
mmode = if mode == "cpp": "c++" else: mode mmode = if mode == "cpp": "c++" else: mode
cmd = &"gcc -E -CC -dD -x{mmode} -w " cmd = &"gcc -E -CC -dD -x{mmode} -w "
@ -210,10 +204,10 @@ proc getPreprocessor*(fullpath: string, mode = "cpp"): string =
start = false start = false
sfile = fullpath.sanitizePath sfile = fullpath.sanitizePath
for inc in gStateRT.includeDirs: for inc in gState.includeDirs:
cmd &= &"-I{inc.quoteShell} " cmd &= &"-I{inc.quoteShell} "
for def in gStateRT.defines: for def in gState.defines:
cmd &= &"-D{def} " cmd &= &"-D{def} "
cmd &= &"{fullpath.quoteShell}" cmd &= &"{fullpath.quoteShell}"
@ -229,13 +223,13 @@ proc getPreprocessor*(fullpath: string, mode = "cpp"): string =
start = true start = true
elif not ("\\" in line) and not ("/" in line) and extractFilename(sfile) in line: elif not ("\\" in line) and not ("/" in line) and extractFilename(sfile) in line:
start = true start = true
elif gStateRT.recurse: elif gState.recurse:
let let
pDir = sfile.expandFilename().parentDir().sanitizePath() pDir = sfile.expandFilename().parentDir().sanitizePath()
if pDir.len == 0 or pDir in saniLine: if pDir.len == 0 or pDir in saniLine:
start = true start = true
else: else:
for inc in gStateRT.includeDirs: for inc in gState.includeDirs:
if inc.absolutePath().sanitizePath in saniLine: if inc.absolutePath().sanitizePath in saniLine:
start = true start = true
break break
@ -350,7 +344,7 @@ proc dll*(path: string): string =
result = dir / (DynlibFormat % name) result = dir / (DynlibFormat % name)
proc loadPlugin*(sourcePath: string) = proc loadPlugin*(gState: State, sourcePath: string) =
doAssert fileExists(sourcePath), "Plugin file does not exist: " & sourcePath doAssert fileExists(sourcePath), "Plugin file does not exist: " & sourcePath
let let
@ -363,5 +357,5 @@ proc loadPlugin*(sourcePath: string) =
let lib = loadLib(pdll) let lib = loadLib(pdll)
doAssert lib != nil, "Plugin $1 compiled to $2 failed to load" % [sourcePath, pdll] doAssert lib != nil, "Plugin $1 compiled to $2 failed to load" % [sourcePath, pdll]
gStateRT.onSymbol = cast[OnSymbol](lib.symAddr("onSymbol")) gState.onSymbol = cast[OnSymbol](lib.symAddr("onSymbol"))
doAssert gStateRT.onSymbol != nil, "onSymbol() load failed from " & pdll doAssert gState.onSymbol != nil, "onSymbol() load failed from " & pdll

View file

@ -52,12 +52,12 @@ type
AstTable {.used.} = TableRef[string, seq[ref Ast]] AstTable {.used.} = TableRef[string, seq[ref Ast]]
State = object State = ref object
compile*, defines*, headers*, includeDirs*, searchDirs*, symOverride*: seq[string] compile*, defines*, headers*, includeDirs*, searchDirs*, symOverride*: seq[string]
nocache*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool nocache*, debug*, past*, preprocess*, pnim*, pretty*, recurse*: bool
code*, mode*, pluginSourcePath*, sourceFile*: string code*, mode*, pluginSourcePath*: string
onSymbol*: OnSymbol onSymbol*: OnSymbol
@ -66,15 +66,14 @@ type
constStr*, debugStr*, enumStr*, procStr*, typeStr*, commentStr*: string constStr*, debugStr*, enumStr*, procStr*, typeStr*, commentStr*: string
debug*: bool gState*: State
currentHeader*, impHeader*: string currentHeader*, impHeader*, sourceFile*: string
data*: seq[tuple[name, val: string]] data*: seq[tuple[name, val: string]]
var var
gStateCT {.compiletime, used.}: State gStateCT {.compiletime, used.} = new(State)
gStateRT {.used.}: State
template nBl(s: typed): untyped {.used.} = template nBl(s: typed): untyped {.used.} =
(s.len != 0) (s.len != 0)
@ -87,4 +86,4 @@ type CompileMode = enum
const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant const modeDefault {.used.} = $cpp # TODO: USE this everywhere relevant
when not declared(CIMPORT): when not declared(CIMPORT):
export gAtoms, gExpressions, gEnumVals, Kind, Ast, AstTable, State, NimState, gStateRT, nBl, CompileMode, modeDefault export gAtoms, gExpressions, gEnumVals, Kind, Ast, AstTable, State, NimState, nBl, CompileMode, modeDefault

View file

@ -37,7 +37,7 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# define X Y" nimState.debugStr &= "\n# define X Y"
let let
@ -45,9 +45,9 @@ proc initGrammar(): Grammar =
if val.nBl: if val.nBl:
let let
name = nimState.data[0].val.getIdentifier(nskConst) name = nimState.getIdentifier(nimState.data[0].val, nskConst)
if name.nBl and nimState.identifiers.addNewIdentifer(name): if name.nBl and nimState.addNewIdentifer(name):
nimState.constStr &= &"{nimState.getComments()}\n {name}* = {val}" nimState.constStr &= &"{nimState.getComments()}\n {name}* = {val}"
)) ))
@ -109,7 +109,7 @@ proc initGrammar(): Grammar =
""" """
template funcParamCommon(fname, pname, ptyp, pptr, pout, count, i: untyped): untyped = template funcParamCommon(fname, pname, ptyp, pptr, pout, count, i: untyped): untyped =
ptyp = nimState.data[i].val.getIdentifier(nskType, fname) ptyp = nimState.getIdentifier(nimState.data[i].val, nskType, fname)
pptr = "" pptr = ""
while i+1 < nimState.data.len and nimState.data[i+1].name == "pointer_declarator": while i+1 < nimState.data.len and nimState.data[i+1].name == "pointer_declarator":
@ -117,7 +117,7 @@ proc initGrammar(): Grammar =
i += 1 i += 1
if i+1 < nimState.data.len and nimState.data[i+1].name == "identifier": if i+1 < nimState.data.len and nimState.data[i+1].name == "identifier":
pname = nimState.data[i+1].val.getIdentifier(nskParam, fname) pname = nimState.getIdentifier(nimState.data[i+1].val, nskParam, fname)
i += 2 i += 2
else: else:
pname = "a" & $count pname = "a" & $count
@ -150,12 +150,12 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# typedef X Y" nimState.debugStr &= "\n# typedef X Y"
var var
i = 0 i = 0
typ = nimState.data[i].val.getIdentifier(nskType) typ = nimState.getIdentifier(nimState.data[i].val, nskType)
name = "" name = ""
nname = "" nname = ""
tptr = "" tptr = ""
@ -173,13 +173,13 @@ proc initGrammar(): Grammar =
if i < nimState.data.len: if i < nimState.data.len:
name = nimState.data[i].val name = nimState.data[i].val
nname = nimState.data[i].val.getIdentifier(nskType) nname = nimState.getIdentifier(name, nskType)
i += 1 i += 1
let let
pragma = nimState.genPragma(nimState.genImportC(name, nname)) pragma = nimState.genPragma(nimState.genImportC(name, nname))
if typ.nBl and nname.nBl and nimState.identifiers.addNewIdentifer(nname): if typ.nBl and nname.nBl and nimState.addNewIdentifer(nname):
if i < nimState.data.len and nimState.data[^1].name == "function_declarator": if i < nimState.data.len and nimState.data[^1].name == "function_declarator":
var var
fname = nname fname = nname
@ -204,7 +204,7 @@ proc initGrammar(): Grammar =
var var
flen = nimState.data[i].val flen = nimState.data[i].val
if nimState.data[i].name == "identifier": if nimState.data[i].name == "identifier":
flen = flen.getIdentifier(nskConst, nname) flen = nimState.getIdentifier(flen, nskConst, nname)
nimState.typeStr &= &"{nimState.getComments()}\n {nname}*{pragma} = {aptr}array[{flen}, {getPtrType(tptr&typ)}]" nimState.typeStr &= &"{nimState.getComments()}\n {nname}*{pragma} = {aptr}array[{flen}, {getPtrType(tptr&typ)}]"
else: else:
@ -215,12 +215,12 @@ proc initGrammar(): Grammar =
)) ))
proc pDupTypeCommon(nname: string, fend: int, nimState: NimState, isEnum=false) = proc pDupTypeCommon(nname: string, fend: int, nimState: NimState, isEnum=false) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# pDupTypeCommon()" nimState.debugStr &= "\n# pDupTypeCommon()"
var var
dname = nimState.data[^1].val dname = nimState.data[^1].val
ndname = nimState.data[^1].val.getIdentifier(nskType) ndname = nimState.getIdentifier(dname, nskType)
dptr = dptr =
if fend == 2: if fend == 2:
"ptr " "ptr "
@ -229,21 +229,21 @@ proc initGrammar(): Grammar =
if ndname.nBl and ndname != nname: if ndname.nBl and ndname != nname:
if isEnum: if isEnum:
if nimState.identifiers.addNewIdentifer(ndname): if nimState.addNewIdentifer(ndname):
nimState.enumStr &= &"{nimState.getComments()}\ntype {ndname}* = {dptr}{nname}" nimState.enumStr &= &"{nimState.getComments()}\ntype {ndname}* = {dptr}{nname}"
else: else:
if nimState.identifiers.addNewIdentifer(ndname): if nimState.addNewIdentifer(ndname):
let let
pragma = nimState.genPragma(nimState.genImportc(dname, ndname), "bycopy") pragma = nimState.genPragma(nimState.genImportc(dname, ndname), "bycopy")
nimState.typeStr &= nimState.typeStr &=
&"{nimState.getComments()}\n {ndname}*{pragma} = {dptr}{nname}" &"{nimState.getComments()}\n {ndname}*{pragma} = {dptr}{nname}"
proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, nimState: NimState) = proc pStructCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# pStructCommon" nimState.debugStr &= "\n# pStructCommon"
var var
nname = name.getIdentifier(nskType) nname = nimState.getIdentifier(name, nskType)
prefix = "" prefix = ""
union = "" union = ""
@ -269,7 +269,7 @@ proc initGrammar(): Grammar =
union = " {.union.}" union = " {.union.}"
break break
if nname.nBl and nimState.identifiers.addNewIdentifer(nname): if nname.nBl and nimState.addNewIdentifer(nname):
if nimState.data.len == 1: if nimState.data.len == 1:
nimState.typeStr &= &"{nimState.getComments()}\n {nname}* {{.bycopy.}} = object{union}" nimState.typeStr &= &"{nimState.getComments()}\n {nname}* {{.bycopy.}} = object{union}"
else: else:
@ -302,7 +302,7 @@ proc initGrammar(): Grammar =
aptr &= "ptr " aptr &= "ptr "
i += 1 i += 1
fname = nimState.data[i].val.getIdentifier(nskField, nname) fname = nimState.getIdentifier(nimState.data[i].val, nskField, nname)
if i+1 < nimState.data.len-fend and nimState.data[i+1].name in gEnumVals: if i+1 < nimState.data.len-fend and nimState.data[i+1].name in gEnumVals:
let let
@ -390,7 +390,7 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# struct X {}" nimState.debugStr &= "\n# struct X {}"
pStructCommon(ast, node, nimState.data[0].val, 1, 1, nimState) pStructCommon(ast, node, nimState.data[0].val, 1, 1, nimState)
@ -413,7 +413,7 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# typedef struct X {}" nimState.debugStr &= "\n# typedef struct X {}"
var var
@ -434,16 +434,16 @@ proc initGrammar(): Grammar =
)) ))
proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, nimState: NimState) = proc pEnumCommon(ast: ref Ast, node: TSNode, name: string, fstart, fend: int, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# pEnumCommon()" nimState.debugStr &= "\n# pEnumCommon()"
let nname = let nname =
if name.len == 0: if name.len == 0:
getUniqueIdentifier(nimState.identifiers, "Enum") getUniqueIdentifier(nimState, "Enum")
else: else:
name.getIdentifier(nskType) nimState.getIdentifier(name, nskType)
if nname.nBl and nimState.identifiers.addNewIdentifer(nname): if nname.nBl and nimState.addNewIdentifer(nname):
nimState.enumStr &= &"{nimState.getComments()}\ndefineEnum({nname})" nimState.enumStr &= &"{nimState.getComments()}\ndefineEnum({nname})"
var var
@ -455,11 +455,11 @@ proc initGrammar(): Grammar =
continue continue
let let
fname = nimState.data[i].val.getIdentifier(nskEnumField) fname = nimState.getIdentifier(nimState.data[i].val, nskEnumField)
if i+1 < nimState.data.len-fend and if i+1 < nimState.data.len-fend and
nimState.data[i+1].name in gEnumVals: nimState.data[i+1].name in gEnumVals:
if fname.nBl and nimState.identifiers.addNewIdentifer(fname): if fname.nBl and nimState.addNewIdentifer(fname):
nimState.constStr &= &"{nimState.getComments()}\n {fname}* = ({nimState.data[i+1].val.getNimExpression()}).{nname}" nimState.constStr &= &"{nimState.getComments()}\n {fname}* = ({nimState.data[i+1].val.getNimExpression()}).{nname}"
try: try:
count = nimState.data[i+1].val.parseInt() + 1 count = nimState.data[i+1].val.parseInt() + 1
@ -467,7 +467,7 @@ proc initGrammar(): Grammar =
count += 1 count += 1
i += 2 i += 2
else: else:
if fname.nBl and nimState.identifiers.addNewIdentifer(fname): if fname.nBl and nimState.addNewIdentifer(fname):
nimState.constStr &= &"{nimState.getComments()}\n {fname}* = {count}.{nname}" nimState.constStr &= &"{nimState.getComments()}\n {fname}* = {count}.{nname}"
i += 1 i += 1
count += 1 count += 1
@ -489,7 +489,7 @@ proc initGrammar(): Grammar =
) )
""" % gEnumVals.join("|"), """ % gEnumVals.join("|"),
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# enum X {}" nimState.debugStr &= "\n# enum X {}"
var var
@ -517,7 +517,7 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# typedef enum {}" nimState.debugStr &= "\n# typedef enum {}"
var var
@ -550,7 +550,7 @@ proc initGrammar(): Grammar =
) )
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
if nimState.debug: if nimState.gState.debug:
nimState.debugStr &= "\n# typ function" nimState.debugStr &= "\n# typ function"
var var
@ -569,7 +569,7 @@ proc initGrammar(): Grammar =
var var
fname = nimState.data[i].val fname = nimState.data[i].val
fnname = fname.getIdentifier(nskProc) fnname = nimState.getIdentifier(fname, nskProc)
pout, pname, ptyp, pptr = "" pout, pname, ptyp, pptr = ""
count = 1 count = 1
@ -583,9 +583,9 @@ proc initGrammar(): Grammar =
if pout.len != 0 and pout[^2 .. ^1] == ", ": if pout.len != 0 and pout[^2 .. ^1] == ", ":
pout = pout[0 .. ^3] pout = pout[0 .. ^3]
if fnname.nBl and nimState.identifiers.addNewIdentifer(fnname): if fnname.nBl and nimState.addNewIdentifer(fnname):
let let
ftyp = nimState.data[0].val.getIdentifier(nskType, fnname) ftyp = nimState.getIdentifier(nimState.data[0].val, nskType, fnname)
pragma = nimState.genPragma(nimState.genImportC(fname, fnname), "cdecl") pragma = nimState.genPragma(nimState.genImportC(fname, fnname), "cdecl")
if fptr.len != 0 or ftyp != "object": if fptr.len != 0 or ftyp != "object":
@ -601,7 +601,7 @@ proc initGrammar(): Grammar =
""", """,
proc (ast: ref Ast, node: TSNode, nimState: NimState) = proc (ast: ref Ast, node: TSNode, nimState: NimState) =
let let
cmt = $node.getNodeVal() cmt = $nimState.getNodeVal(node)
for line in cmt.splitLines(): for line in cmt.splitLines():
let let

View file

@ -4,7 +4,7 @@ import "."/treesitter/[api, c, cpp]
import "."/[ast, globals, getters, grammar] import "."/[ast, globals, getters, grammar]
proc printLisp(root: TSNode) = proc printLisp(gState: State, root: TSNode) =
var var
node = root node = root
nextnode: TSNode nextnode: TSNode
@ -12,21 +12,21 @@ proc printLisp(root: TSNode) =
while true: while true:
if not node.tsNodeIsNull() and depth > -1: if not node.tsNodeIsNull() and depth > -1:
if gStateRT.pretty: if gState.pretty:
stdout.write spaces(depth) stdout.write spaces(depth)
let let
(line, col) = node.getLineCol() (line, col) = gState.getLineCol(node)
stdout.write &"({$node.tsNodeType()} {line} {col} {node.tsNodeEndByte() - node.tsNodeStartByte()}" stdout.write &"({$node.tsNodeType()} {line} {col} {node.tsNodeEndByte() - node.tsNodeStartByte()}"
else: else:
break break
if node.tsNodeNamedChildCount() != 0: if node.tsNodeNamedChildCount() != 0:
if gStateRT.pretty: if gState.pretty:
echo "" echo ""
nextnode = node.tsNodeNamedChild(0) nextnode = node.tsNodeNamedChild(0)
depth += 1 depth += 1
else: else:
if gStateRT.pretty: if gState.pretty:
echo ")" echo ")"
else: else:
stdout.write ")" stdout.write ")"
@ -38,7 +38,7 @@ proc printLisp(root: TSNode) =
depth -= 1 depth -= 1
if depth == -1: if depth == -1:
break break
if gStateRT.pretty: if gState.pretty:
echo spaces(depth) & ")" echo spaces(depth) & ")"
else: else:
stdout.write ")" stdout.write ")"
@ -53,7 +53,7 @@ proc printLisp(root: TSNode) =
if node == root: if node == root:
break break
proc process(path: string, astTable: AstTable) = proc process(gState: State, path: string, astTable: AstTable) =
doAssert existsFile(path), "Invalid path " & path doAssert existsFile(path), "Invalid path " & path
var var
@ -63,41 +63,39 @@ proc process(path: string, astTable: AstTable) =
defer: defer:
parser.tsParserDelete() parser.tsParserDelete()
gStateRT.sourceFile = path if gState.mode.len == 0:
if gStateRT.mode.len == 0:
if ext in [".h", ".c"]: if ext in [".h", ".c"]:
gStateRT.mode = "c" gState.mode = "c"
elif ext in [".hxx", ".hpp", ".hh", ".H", ".h++", ".cpp", ".cxx", ".cc", ".C", ".c++"]: elif ext in [".hxx", ".hpp", ".hh", ".H", ".h++", ".cpp", ".cxx", ".cc", ".C", ".c++"]:
gStateRT.mode = "cpp" gState.mode = "cpp"
if gStateRT.preprocess: if gState.preprocess:
gStateRT.code = getPreprocessor(path) gState.code = gState.getPreprocessor(path)
else: else:
gStateRT.code = readFile(path) gState.code = readFile(path)
doAssert gStateRT.code.len != 0, "Empty file or preprocessor error" doAssert gState.code.len != 0, "Empty file or preprocessor error"
if gStateRT.mode == "c": if gState.mode == "c":
doAssert parser.tsParserSetLanguage(treeSitterC()), "Failed to load C parser" doAssert parser.tsParserSetLanguage(treeSitterC()), "Failed to load C parser"
elif gStateRT.mode == "cpp": elif gState.mode == "cpp":
doAssert parser.tsParserSetLanguage(treeSitterCpp()), "Failed to load C++ parser" doAssert parser.tsParserSetLanguage(treeSitterCpp()), "Failed to load C++ parser"
else: else:
doAssert false, "Invalid parser " & gStateRT.mode doAssert false, "Invalid parser " & gState.mode
var var
tree = parser.tsParserParseString(nil, gStateRT.code.cstring, gStateRT.code.len.uint32) tree = parser.tsParserParseString(nil, gState.code.cstring, gState.code.len.uint32)
root = tree.tsTreeRootNode() root = tree.tsTreeRootNode()
defer: defer:
tree.tsTreeDelete() tree.tsTreeDelete()
if gStateRT.past: if gState.past:
printLisp(root) gState.printLisp(root)
elif gStateRT.pnim: elif gState.pnim:
printNim(path, root, astTable) gState.printNim(path, root, astTable)
elif gStateRT.preprocess: elif gState.preprocess:
echo gStateRT.code echo gState.code
proc main( proc main(
mode = modeDefault, mode = modeDefault,
@ -115,7 +113,7 @@ proc main(
source: seq[string], source: seq[string],
) = ) =
gStateRT = State( var gState = State(
mode: mode, mode: mode,
past: past, past: past,
pnim: pnim, pnim: pnim,
@ -129,20 +127,20 @@ proc main(
pluginSourcePath: pluginSourcePath pluginSourcePath: pluginSourcePath
) )
gStateRT.symOverride = gStateRT.symOverride.getSplitComma() gState.symOverride = gState.symOverride.getSplitComma()
if pluginSourcePath.nBl: if pluginSourcePath.nBl:
loadPlugin(pluginSourcePath) gState.loadPlugin(pluginSourcePath)
let let
astTable = parseGrammar() astTable = parseGrammar()
if pgrammar: if pgrammar:
astTable.printGrammar() astTable.printGrammar()
elif source.len != 0: elif source.len != 0:
if gStateRT.pnim: if gState.pnim:
printNimHeader() printNimHeader()
for src in source: for src in source:
process(src, astTable) gState.process(src, astTable)
when isMainModule: when isMainModule:
import cligen import cligen