1416 lines
40 KiB
Nim
1416 lines
40 KiB
Nim
import macros, os, sequtils, sets, strformat, strutils, tables, times
|
|
|
|
import regex
|
|
|
|
import compiler/[ast, idents, modulegraphs, options, parser, renderer]
|
|
|
|
import "."/treesitter/api
|
|
|
|
import "."/[globals, getters]
|
|
|
|
proc getPtrType*(str: string): string =
|
|
result = case str:
|
|
of "cchar":
|
|
"cstring"
|
|
of "object":
|
|
"pointer"
|
|
else:
|
|
str
|
|
|
|
proc parseString(nimState: NimState, str: string): PNode =
|
|
# Parse a string into Nim AST
|
|
result = parseString(str, nimState.identCache, nimState.config)
|
|
|
|
proc getLit*(nimState: NimState, str: string): PNode =
|
|
# Used to convert #define literals into const and expressions
|
|
# in array sizes
|
|
let
|
|
str = str.replace(re"/[/*].*?(?:\*/)?$", "").strip()
|
|
|
|
if str.contains(re"^[\-]?[\d]+$"): # decimal
|
|
result = newIntNode(nkIntLit, parseInt(str))
|
|
|
|
elif str.contains(re"^[\-]?[\d]*[.]?[\d]+$"): # float
|
|
result = newFloatNode(nkFloatLit, parseFloat(str))
|
|
|
|
# # TODO - hex becomes int on render
|
|
# elif str.contains(re"^0x[\da-fA-F]+$"): # hexadecimal
|
|
# result = newIntNode(nkIntLit, parseHexInt(str))
|
|
|
|
elif str.contains(re"^'[[:ascii:]]'$"): # char
|
|
result = newNode(nkCharLit)
|
|
result.intVal = str[1].int64
|
|
|
|
elif str.contains(re"""^"[[:ascii:]]+"$"""): # char *
|
|
result = newStrNode(nkStrLit, str[1 .. ^2])
|
|
|
|
else:
|
|
result = nimState.parseString(nimState.getNimExpression(str))
|
|
if result.isNil:
|
|
result = newNode(nkNilLit)
|
|
|
|
proc getOverrideOrSkip(nimState: NimState, node: TSNode, origname: string, kind: NimSymKind): PNode =
|
|
# Check if symbol `origname` of `kind` and `origname` has any cOverride defined
|
|
# and use that if present
|
|
#
|
|
# If not, symbol needs to be skipped - only get here if `name` is blank
|
|
let
|
|
# Get cleaned name for symbol, set parent so that cOverride is ignored
|
|
name = nimState.getIdentifier(origname, kind, parent = "override")
|
|
|
|
override = nimState.getOverride(origname, kind)
|
|
|
|
var
|
|
skind = getKeyword(kind) & " "
|
|
if override.nBl:
|
|
if kind == nskProc:
|
|
skind = ""
|
|
result = nimState.parseString(skind & override.replace(origname, name))[0][0]
|
|
else:
|
|
necho &"\n# $1'{origname}' skipped" % skind
|
|
if nimState.gState.debug:
|
|
nimState.skipStr &= &"\n{nimState.getNodeVal(node)}"
|
|
|
|
proc addOverrideFinal(nimState: NimState, kind: NimSymKind) =
|
|
# Add all unused cOverride symbols for `kind` to AST
|
|
var
|
|
syms = nimState.getOverrideFinal(kind)
|
|
skind = getKeyword(kind) & "\n"
|
|
if kind == nskProc:
|
|
skind = ""
|
|
|
|
if syms.nBl:
|
|
var
|
|
nsyms = nimState.parseString(skind & syms)
|
|
if not nsyms.isNil:
|
|
let
|
|
list =
|
|
if kind == nskProc:
|
|
nsyms.sons
|
|
else:
|
|
nsyms[0].sons
|
|
case kind
|
|
of nskConst:
|
|
nimState.constSection.sons.insert(list, 0)
|
|
of nskType:
|
|
nimState.typeSection.sons.insert(list, 0)
|
|
of nskProc:
|
|
nimState.procSection.sons.insert(list, 0)
|
|
else:
|
|
discard
|
|
|
|
proc addAllOverrideFinal(nimState: NimState) =
|
|
# Add all unused cOverride symbols to AST
|
|
for kind in [nskConst, nskType, nskProc]:
|
|
nimState.addOverrideFinal(kind)
|
|
|
|
proc newConstDef(nimState: NimState, node: TSNode, fname = "", fval = ""): PNode =
|
|
# Create an nkConstDef PNode
|
|
#
|
|
# If `fname` or `fval` are set, use them as name and val
|
|
let
|
|
origname =
|
|
if fname.nBl:
|
|
fname
|
|
else:
|
|
# node[0] = identifier = const name
|
|
nimState.getNodeVal(node.getAtom())
|
|
|
|
name = nimState.getIdentifier(origname, nskConst)
|
|
info = nimState.getLineInfo(node)
|
|
ident = nimState.getIdent(name, info)
|
|
|
|
# node[1] = preproc_arg = value
|
|
val =
|
|
if fval.nBl:
|
|
fval
|
|
else:
|
|
nimState.getNodeVal(node[1])
|
|
valident =
|
|
nimState.getLit(val)
|
|
|
|
if name.Bl:
|
|
# Name skipped or overridden since blank
|
|
result = nimState.getOverrideOrSkip(node, origname, nskConst)
|
|
elif valident.kind != nkNilLit:
|
|
if nimState.addNewIdentifer(name):
|
|
# const X* = Y
|
|
#
|
|
# nkConstDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkXLit(Y)
|
|
# )
|
|
result = newNode(nkConstDef)
|
|
result.add ident
|
|
result.add newNode(nkEmpty)
|
|
result.add valident
|
|
else:
|
|
necho &"# const '{origname}' is duplicate, skipped"
|
|
else:
|
|
necho &"# const '{origname}' has invalid value '{val}'"
|
|
|
|
proc addConst(nimState: NimState, node: TSNode) =
|
|
# Add a const to the AST
|
|
#
|
|
# #define X Y
|
|
#
|
|
# (preproc_def
|
|
# (identifier)
|
|
# (preproc_arg)
|
|
# )
|
|
decho("addConst()")
|
|
nimState.printDebug(node)
|
|
|
|
if node[0].getName() == "identifier" and
|
|
node[1].getName() == "preproc_arg":
|
|
let
|
|
constDef = nimState.newConstDef(node)
|
|
|
|
if not constDef.isNil:
|
|
# nkConstSection.add
|
|
nimState.constSection.add constDef
|
|
nimState.constIdentifiers.incl constDef.getIdentName()
|
|
|
|
nimState.printDebug(constDef)
|
|
|
|
proc addPragma(nimState: NimState, node: TSNode, pragma: PNode, name: string, value: PNode = nil) =
|
|
# Add pragma to an existing nkPragma tree
|
|
let
|
|
pinfo = nimState.getLineInfo(node.getAtom())
|
|
pident = nimState.getIdent(name, pinfo, exported = false)
|
|
|
|
if value.isNil:
|
|
pragma.add pident
|
|
else:
|
|
let
|
|
colExpr = newNode(nkExprColonExpr)
|
|
colExpr.add pident
|
|
colExpr.add value
|
|
pragma.add colExpr
|
|
|
|
proc addPragma(nimState: NimState, node: TSNode, pragma: PNode, pragmas: seq[string]) =
|
|
# Add sequence of pragmas to an existing nkPragma tree
|
|
for name in pragmas:
|
|
nimState.addPragma(node, pragma, name)
|
|
|
|
proc addPragma(nimState: NimState, node: TSNode, pragma: PNode, pragmas: OrderedTable[string, PNode]) =
|
|
# Add a table of name:value pragmas to an existing nkPragma tree
|
|
for name, value in pragmas.pairs:
|
|
nimState.addPragma(node, pragma, name, value)
|
|
|
|
proc newPragma(nimState: NimState, node: TSNode, name: string, value: PNode = nil): PNode =
|
|
# Create nkPragma tree for name:value
|
|
#
|
|
# {.name1, name2: value2.}
|
|
#
|
|
# nkPragma(
|
|
# nkIdent(name1),
|
|
# nkExprColonExpr(
|
|
# nkIdent(name2),
|
|
# nkStrLit(value2)
|
|
# )
|
|
# )
|
|
result = newNode(nkPragma)
|
|
nimState.addPragma(node, result, name, value)
|
|
|
|
proc newPragma(nimState: NimState, node: TSNode, pragmas: seq[string] | OrderedTable[string, PNode]): PNode =
|
|
# Create nkPragma tree for multiple name:value
|
|
result = newNode(nkPragma)
|
|
nimState.addPragma(node, result, pragmas)
|
|
|
|
proc newPragmaExpr(nimState: NimState, node: TSNode, ident: PNode, name: string, value: PNode = nil): PNode =
|
|
# Create nkPragmaExpr tree for name:value
|
|
#
|
|
# nkPragmaExpr(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkPragma(
|
|
# nkIdent(name1),
|
|
# nkExprColonExpr(
|
|
# nkIdent(name2),
|
|
# nkStrLit(value2)
|
|
# )
|
|
# )
|
|
# )
|
|
result = newNode(nkPragmaExpr)
|
|
result.add ident
|
|
result.add nimState.newPragma(node, name, value)
|
|
|
|
proc newPragmaExpr(nimState: NimState, node: TSNode, ident: PNode, pragmas: seq[string] | OrderedTable[string, PNode]): PNode =
|
|
# Create nkPragmaExpr tree for multiple name:value
|
|
result = newNode(nkPragmaExpr)
|
|
result.add ident
|
|
result.add nimState.newPragma(node, pragmas)
|
|
|
|
proc newTypeIdent(nimState: NimState, node: TSNode, kind = nskType, fname = "", pragmas: seq[string] = @[], istype = false): PNode =
|
|
# Create nkTypeDef PNode with first ident if `nskType` else just create an nkPostfix node for `nskProc`
|
|
#
|
|
# If `fname`, use it instead of node.getAtom() for name
|
|
# If `pragmas`, add as nkPragmaExpr but only if `nskType` since procs add pragmas elsewhere
|
|
# If `istype` is set, this is a typedef, else struct/union so add {.importc: "struct/union X".} when includeHeader
|
|
let
|
|
(tname, torigname, info) = nimState.getNameInfo(node.getAtom(), kind)
|
|
|
|
origname =
|
|
if fname.nBl:
|
|
fname
|
|
else:
|
|
torigname
|
|
|
|
# Process name if forced, getNameInfo() already runs getIdentifier()
|
|
name =
|
|
if fname.nBl:
|
|
nimState.getIdentifier(fname, kind)
|
|
else:
|
|
tname
|
|
|
|
ident = nimState.getIdent(name, info)
|
|
|
|
if name.Bl:
|
|
# Name skipped or overridden since blank
|
|
result = nimState.getOverrideOrSkip(node, origname, kind)
|
|
elif nimState.addNewIdentifer(name):
|
|
if kind == nskType:
|
|
# type name* =
|
|
#
|
|
# nkTypeDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent(name)
|
|
# ),
|
|
# nkEmpty()
|
|
# )
|
|
var
|
|
pragmas =
|
|
if nimState.includeHeader:
|
|
# Need to add header and importc
|
|
if istype and name == origname:
|
|
# Need to add impShort since neither struct/union nor name change
|
|
pragmas & nimState.impShort
|
|
else:
|
|
# Add header shortcut, additional pragmas added later
|
|
pragmas & (nimState.impShort & "H")
|
|
else:
|
|
pragmas
|
|
|
|
prident =
|
|
if pragmas.nBl:
|
|
nimState.newPragmaExpr(node, ident, pragmas)
|
|
else:
|
|
ident
|
|
|
|
if nimState.includeHeader:
|
|
if not istype or name != origname:
|
|
# Add importc pragma since either struct/union or name changed
|
|
let
|
|
uors =
|
|
if not istype:
|
|
if "union" in pragmas:
|
|
"union "
|
|
else:
|
|
"struct "
|
|
else:
|
|
""
|
|
nimState.addPragma(node, prident[1], "importc", newStrNode(nkStrLit, &"{uors}{origname}"))
|
|
|
|
result = newNode(nkTypeDef)
|
|
result.add prident
|
|
result.add newNode(nkEmpty)
|
|
elif kind == nskProc:
|
|
# name*
|
|
#
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent(name)
|
|
# )
|
|
result = ident
|
|
|
|
nimState.identifierNodes[name] = result
|
|
else:
|
|
necho &"# $1 '{origname}' is duplicate, skipped" % getKeyword(kind)
|
|
|
|
proc newPtrTree(nimState: NimState, count: int, typ: PNode): PNode =
|
|
# Create nkPtrTy tree depending on count
|
|
#
|
|
# Reduce by 1 if Nim type available for ptr X - e.g. ptr cchar = cstring
|
|
result = typ
|
|
var
|
|
count = count
|
|
if typ.kind == nkIdent:
|
|
let
|
|
tname = typ.ident.s
|
|
ptname = getPtrType(tname)
|
|
if tname != ptname:
|
|
# If Nim type available, use that ident
|
|
result = nimState.getIdent(ptname, typ.info, exported = false)
|
|
# One ptr reduced
|
|
count -= 1
|
|
if count > 0:
|
|
# Nested nkPtrTy(typ) depending on count
|
|
#
|
|
# [ptr ...] typ
|
|
#
|
|
# nkPtrTy(
|
|
# nkPtrTy(
|
|
# typ
|
|
# )
|
|
# )
|
|
var
|
|
nresult = newNode(nkPtrTy)
|
|
parent = nresult
|
|
child: PNode
|
|
for i in 1 ..< count:
|
|
child = newNode(nkPtrTy)
|
|
parent.add child
|
|
parent = child
|
|
parent.add result
|
|
result = nresult
|
|
|
|
proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode): PNode =
|
|
# Create nkBracketExpr tree depending on input
|
|
let
|
|
info = nimState.getLineInfo(node.getAtom())
|
|
ident = nimState.getIdent("array", info, exported = false)
|
|
|
|
# array[size, typ]
|
|
#
|
|
# nkBracketExpr(
|
|
# nkIdent("array"),
|
|
# size,
|
|
# typ
|
|
# )
|
|
result = newNode(nkBracketExpr)
|
|
result.add ident
|
|
result.add size
|
|
result.add typ
|
|
|
|
proc getTypeArray(nimState: NimState, node: TSNode, name: string): PNode
|
|
proc getTypeProc(nimState: NimState, name: string, node: TSNode): PNode
|
|
|
|
proc newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: SomeInteger, exported = false): PNode =
|
|
# Create nkIdentDefs tree for specified proc parameter or object field
|
|
#
|
|
# For proc, param should not be exported
|
|
#
|
|
# pname: [ptr ..] typ
|
|
#
|
|
# nkIdentDefs(
|
|
# nkIdent(pname),
|
|
# typ,
|
|
# nkEmpty()
|
|
# )
|
|
#
|
|
# For object, field should be exported
|
|
#
|
|
# pname*: [ptr ..] typ
|
|
#
|
|
# nkIdentDefs(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent(pname)
|
|
# ),
|
|
# typ,
|
|
# nkEmpty()
|
|
# )
|
|
result = newNode(nkIdentDefs)
|
|
|
|
let
|
|
start = getStartAtom(node)
|
|
|
|
# node[start] - param type
|
|
(tname, _, tinfo) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name)
|
|
tident = nimState.getIdent(tname, tinfo, exported = false)
|
|
|
|
if start == node.len - 1:
|
|
# Only for proc with no named param - create a param name based on offset
|
|
#
|
|
# int func(char, int);
|
|
if tname != "object":
|
|
let
|
|
pname = "a" & $(offset+1)
|
|
pident = nimState.getIdent(pname, tinfo, exported)
|
|
result.add pident
|
|
result.add tident
|
|
result.add newNode(nkEmpty)
|
|
else:
|
|
# int func(void)
|
|
result = nil
|
|
else:
|
|
let
|
|
fdecl = node[start+1].anyChildInTree("function_declarator")
|
|
adecl = node[start+1].anyChildInTree("array_declarator")
|
|
abst = node[start+1].getName() == "abstract_pointer_declarator"
|
|
if fdecl.isNil and adecl.isNil:
|
|
if abst:
|
|
# Only for proc with no named param with pointer type
|
|
# Create a param name based on offset
|
|
#
|
|
# int func(char *, int **);
|
|
let
|
|
pname = "a" & $(offset+1)
|
|
pident = nimState.getIdent(pname, tinfo, exported)
|
|
acount = node[start+1].getXCount("abstract_pointer_declarator")
|
|
result.add pident
|
|
result.add nimState.newPtrTree(acount, tident)
|
|
result.add newNode(nkEmpty)
|
|
else:
|
|
# Named param, simple type
|
|
let
|
|
(pname, _, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
|
pident = nimState.getIdent(pname, pinfo, exported)
|
|
|
|
count = node[start+1].getPtrCount()
|
|
result.add pident
|
|
if count > 0:
|
|
result.add nimState.newPtrTree(count, tident)
|
|
else:
|
|
result.add tident
|
|
result.add newNode(nkEmpty)
|
|
elif not fdecl.isNil:
|
|
# Named param, function pointer
|
|
let
|
|
(pname, _, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
|
pident = nimState.getIdent(pname, pinfo, exported)
|
|
result.add pident
|
|
result.add nimState.getTypeProc(name, node)
|
|
result.add newNode(nkEmpty)
|
|
elif not adecl.isNil:
|
|
# Named param, array type
|
|
let
|
|
(pname, _, pinfo) = nimState.getNameInfo(node[start+1].getAtom(), nskField, parent = name)
|
|
pident = nimState.getIdent(pname, pinfo, exported)
|
|
result.add pident
|
|
result.add nimState.getTypeArray(node, name)
|
|
result.add newNode(nkEmpty)
|
|
else:
|
|
result = nil
|
|
|
|
proc newFormalParams(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNode =
|
|
# Create nkFormalParams tree for specified params and return type
|
|
#
|
|
# proc(pname: ptyp ..): rtyp
|
|
#
|
|
# nkFormalParams(
|
|
# rtyp,
|
|
# nkIdentDefs( # multiple depending on params
|
|
# ..
|
|
# )
|
|
# )
|
|
result = newNode(nkFormalParams)
|
|
|
|
# Add return type
|
|
result.add rtyp
|
|
|
|
if not node.isNil:
|
|
for i in 0 ..< node.len:
|
|
# Add nkIdentDefs for each param
|
|
let
|
|
param = nimState.newIdentDefs(name, node[i], i, exported = false)
|
|
if not param.isNil:
|
|
result.add param
|
|
|
|
proc newProcTy(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNode =
|
|
# Create nkProcTy tree for specified proc type
|
|
|
|
# proc(pname: ptyp ..): rtyp
|
|
#
|
|
# nkProcTy(
|
|
# nkFormalParams(
|
|
# rtyp,
|
|
# nkIdentDefs( # multiple depending on params
|
|
# ..
|
|
# )
|
|
# ),
|
|
# nkEmpty()
|
|
# )
|
|
result = newNode(nkProcTy)
|
|
result.add nimState.newFormalParams(name, node, rtyp)
|
|
result.add newNode(nkEmpty)
|
|
|
|
proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode =
|
|
# Create nkRecList tree for specified object
|
|
if not node.isNil:
|
|
# fname*: ftyp
|
|
# ..
|
|
#
|
|
# nkRecList(
|
|
# nkIdentDefs( # multiple depending on fields
|
|
# ..
|
|
# )
|
|
# )
|
|
result = newNode(nkRecList)
|
|
|
|
for i in 0 ..< node.len:
|
|
# Add nkIdentDefs for each field
|
|
let
|
|
field = nimState.newIdentDefs(name, node[i], i, exported = true)
|
|
if not field.isNil:
|
|
result.add field
|
|
|
|
proc addTypeObject(nimState: NimState, node: TSNode, typeDef: PNode = nil, fname = "", istype = false, union = false) =
|
|
# Add a type of object
|
|
#
|
|
# If `typeDef` is set, use it instead of creating new PNode
|
|
# If `fname` is set, use it as the name when creating new PNode
|
|
# If `istype` is set, this is a typedef, else struct/union
|
|
decho("addTypeObject()")
|
|
let
|
|
# Object has fields or not
|
|
fdlist = node.anyChildInTree("field_declaration_list")
|
|
|
|
pragmas = block:
|
|
var pragmas =
|
|
if union:
|
|
@["union"]
|
|
else:
|
|
@[]
|
|
if not fdlist.isNil and fdlist.len > 0:
|
|
# Object with fields should be bycopy
|
|
pragmas.add "bycopy"
|
|
else:
|
|
# Incomplete, might get forward declared
|
|
pragmas.add "incompleteStruct"
|
|
|
|
pragmas
|
|
|
|
typeDefExisting = not typeDef.isNil
|
|
|
|
typeDef =
|
|
if typeDef.isNil:
|
|
nimState.newTypeIdent(node, fname = fname, pragmas = pragmas, istype = istype)
|
|
else:
|
|
typeDef
|
|
|
|
if not typeDef.isNil:
|
|
# type X* = object
|
|
#
|
|
# nkTypeDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkObjectTy(
|
|
# nkEmpty(),
|
|
# nkEmpty(),
|
|
# nkEmpty()
|
|
# )
|
|
# )
|
|
let
|
|
name = typeDef.getIdentName()
|
|
obj = newNode(nkObjectTy)
|
|
obj.add newNode(nkEmpty)
|
|
obj.add newNode(nkEmpty)
|
|
|
|
if not fdlist.isNil and fdlist.len > 0:
|
|
# Add fields to object if present
|
|
obj.add nimState.newRecListTree(name, fdlist)
|
|
else:
|
|
obj.add newNode(nkEmpty)
|
|
|
|
typeDef.add obj
|
|
|
|
# If typeDef was passed in, need to add pragmas if any
|
|
if pragmas.nBl and typeDefExisting:
|
|
if typeDef[0].kind != nkPragmaExpr:
|
|
let
|
|
npexpr = nimState.newPragmaExpr(node, typedef[0], pragmas)
|
|
typedef[0] = npexpr
|
|
else:
|
|
# includeHeader already added impShort in newTypeIdent()
|
|
nimState.addPragma(node, typeDef[0][1], pragmas)
|
|
|
|
# nkTypeSection.add
|
|
nimState.typeSection.add typeDef
|
|
|
|
nimState.printDebug(typeDef)
|
|
else:
|
|
# Forward declaration case
|
|
let
|
|
fdlist = node.anyChildInTree("field_declaration_list")
|
|
if not fdlist.isNil and fdlist.len > 0:
|
|
# Current node has fields
|
|
let
|
|
name = nimState.getNodeVal(node.getAtom())
|
|
|
|
if nimState.identifierNodes.hasKey(name):
|
|
let
|
|
def = nimState.identifierNodes[name]
|
|
# Duplicate nkTypeDef for `name` with empty fields
|
|
if def.kind == nkTypeDef and def.len == 3 and
|
|
def[2].kind == nkObjectTy and def[2].len == 3 and
|
|
def[2][2].kind == nkEmpty:
|
|
# Add fields to existing object
|
|
def[2][2] = nimState.newRecListTree(name, fdlist)
|
|
|
|
# Change incompleteStruct to bycopy pragma
|
|
if def[0].kind == nkPragmaExpr and def[0].len == 2 and
|
|
def[0][1].kind == nkPragma and def[0][1].len > 0:
|
|
for i in 0 ..< def[0][1].len:
|
|
if $def[0][1][i] == "incompleteStruct":
|
|
def[0][1][i] = nimState.getIdent(
|
|
"bycopy", nimState.getLineInfo(node.getAtom()),
|
|
exported = false
|
|
)
|
|
|
|
nimState.printDebug(def)
|
|
|
|
proc addTypeTyped(nimState: NimState, node: TSNode, ftname = "", offset = 0) =
|
|
# Add a type of a specified type
|
|
#
|
|
# If `ftname` is set, use it as the type name
|
|
# If `offset` is set, skip `offset` names, since created already
|
|
decho("addTypeTyped()")
|
|
let
|
|
start = getStartAtom(node)
|
|
for i in start+1+offset ..< node.len:
|
|
# Add a type of a specific type
|
|
let
|
|
# node[i] = identifer = name
|
|
typeDef = nimState.newTypeIdent(node[i], istype = true)
|
|
|
|
if not typeDef.isNil:
|
|
let
|
|
name = typeDef.getIdentName()
|
|
|
|
# node[start] = identifier = type name
|
|
(tname0, _, tinfo) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name)
|
|
|
|
# Override type name
|
|
tname =
|
|
if ftname.nBl:
|
|
ftname
|
|
else:
|
|
tname0
|
|
|
|
ident = nimState.getIdent(tname, tinfo, exported = false)
|
|
|
|
# node[i] could have nested pointers
|
|
count = node[i].getPtrCount()
|
|
|
|
# Skip typedef X X;
|
|
if name != tname:
|
|
if count > 0:
|
|
# If pointers
|
|
typeDef.add nimState.newPtrTree(count, ident)
|
|
else:
|
|
typeDef.add ident
|
|
|
|
# type X* = [ptr ..] Y
|
|
#
|
|
# nkTypeDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkPtrTy( # optional, nested
|
|
# nkIdent("Y")
|
|
# )
|
|
# )
|
|
|
|
# nkTypeSection.add
|
|
nimState.typeSection.add typeDef
|
|
|
|
nimState.printDebug(typeDef)
|
|
else:
|
|
nimState.addTypeObject(node, typeDef = typeDef, istype = true)
|
|
|
|
proc getTypeArray(nimState: NimState, node: TSNode, name: string): PNode =
|
|
# Create array type tree
|
|
let
|
|
start = getStartAtom(node)
|
|
|
|
# node[start] = identifier = type name
|
|
(tname, _, info) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name)
|
|
ident = nimState.getIdent(tname, info, exported = false)
|
|
|
|
# Top-most array declarator
|
|
adecl = node[start+1].firstChildInTree("array_declarator")
|
|
|
|
# node[start+1] could have nested arrays
|
|
acount = adecl.getArrayCount()
|
|
innermost = adecl.mostNestedChildInTree()
|
|
|
|
# node[start+1] could have nested pointers - type
|
|
tcount = node[start+1].getPtrCount()
|
|
|
|
# Name could be nested pointer to array
|
|
#
|
|
# (..
|
|
# (array_declarator
|
|
# (parenthesized_declarator
|
|
# (pointer_declarator ..
|
|
# (pointer_declarator <- search upwards from atom
|
|
# (type_identifier) <- atom
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
ncount = innermost[0].getAtom().tsNodeParent().getPtrCount(reverse = true)
|
|
|
|
result = ident
|
|
var
|
|
cnode = adecl
|
|
|
|
if tcount > 0:
|
|
# If pointers
|
|
result = nimState.newPtrTree(tcount, result)
|
|
|
|
for i in 0 ..< acount:
|
|
let
|
|
size = nimState.getLit(nimState.getNodeVal(cnode[1]))
|
|
if size.kind != nkNilLit:
|
|
result = nimState.newArrayTree(cnode, result, size)
|
|
cnode = cnode[0]
|
|
|
|
if ncount > 0:
|
|
result = nimState.newPtrTree(ncount, result)
|
|
|
|
proc addTypeArray(nimState: NimState, node: TSNode) =
|
|
# Add a type of array type
|
|
decho("addTypeArray()")
|
|
let
|
|
# node[1] = identifer = name
|
|
typeDef = nimState.newTypeIdent(node[1], istype = true)
|
|
|
|
if not typeDef.isNil:
|
|
let
|
|
name = typeDef.getIdentName()
|
|
typ = nimState.getTypeArray(node, name)
|
|
|
|
typeDef.add typ
|
|
|
|
# type X* = [ptr] array[x, [ptr] Y]
|
|
#
|
|
# nkTypeDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkPtrTy( # optional, nested
|
|
# nkBracketExpr(
|
|
# nkIdent("array")
|
|
# nkXLit(x),
|
|
# nkPtrTy( # optional, nested
|
|
# nkIdent("Y")
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
|
|
# nkTypeSection.add
|
|
nimState.typeSection.add typeDef
|
|
|
|
nimState.printDebug(typeDef)
|
|
|
|
proc getTypeProc(nimState: NimState, name: string, node: TSNode): PNode =
|
|
# Create proc type tree
|
|
let
|
|
# node[0] = identifier = return type name
|
|
(rname, _, rinfo) = nimState.getNameInfo(node[0].getAtom(), nskType, parent = name)
|
|
|
|
# Parameter list
|
|
plist = node[1].anyChildInTree("parameter_list")
|
|
|
|
# node[1] could have nested pointers
|
|
tcount = node[1].getPtrCount()
|
|
|
|
# Name could be nested pointer to function
|
|
#
|
|
# (..
|
|
# (function_declarator
|
|
# (parenthesized_declarator
|
|
# (pointer_declarator ..
|
|
# (pointer_declarator <- search upwards from atom
|
|
# (type_identifier) <- atom
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
ncount = node[1].getAtom().tsNodeParent().getPtrCount(reverse = true)
|
|
|
|
# Return type
|
|
var
|
|
retType =
|
|
if rname == "object" and tcount == 0:
|
|
# void (*func)(..)
|
|
newNode(nkEmpty)
|
|
else:
|
|
nimState.getIdent(rname, rinfo, exported = false)
|
|
if tcount > 0:
|
|
retType = nimState.newPtrTree(tcount, retType)
|
|
|
|
# Proc with return type and params
|
|
result = nimState.newProcTy(name, plist, retType)
|
|
if ncount > 1:
|
|
result = nimState.newPtrTree(ncount-1, result)
|
|
|
|
proc addTypeProc(nimState: NimState, node: TSNode) =
|
|
# Add a type of proc type
|
|
decho("addTypeProc()")
|
|
let
|
|
# node[1] = identifier = name
|
|
typeDef = nimState.newTypeIdent(node[1], istype = true)
|
|
|
|
if not typeDef.isNil:
|
|
let
|
|
name = typeDef.getIdentName()
|
|
|
|
procTy = nimState.getTypeProc(name, node)
|
|
|
|
typeDef.add procTy
|
|
|
|
# type X* = proc(a1: Y, a2: Z): P
|
|
#
|
|
# nkTypeDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkPtrTy( # optional, nested
|
|
# nkProcTy(
|
|
# nkFormalParams(
|
|
# nkPtrTy( # optional, nested
|
|
# nkIdent(retType)
|
|
# ),
|
|
# nkIdentDefs(
|
|
# nkIdent(param),
|
|
# nkPtrTy(
|
|
# nkIdent(ptype)
|
|
# ),
|
|
# nkEmpty()
|
|
# ),
|
|
# ...
|
|
# ),
|
|
# nkEmpty()
|
|
# )
|
|
# )
|
|
# )
|
|
|
|
# nkTypeSection.add
|
|
nimState.typeSection.add typeDef
|
|
|
|
nimState.printDebug(typeDef)
|
|
|
|
proc addType(nimState: NimState, node: TSNode, union = false) =
|
|
decho("addType()")
|
|
nimState.printDebug(node)
|
|
|
|
if node.getName() in ["struct_specifier", "union_specifier"]:
|
|
# struct X;
|
|
#
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
#
|
|
# struct X {};
|
|
#
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# (field_declaration_list = "{}")
|
|
# )
|
|
#
|
|
# struct X { char *a1; };
|
|
#
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# (field_declaration_list
|
|
# (field_declaration
|
|
# (type_identifier|primitive_type|)
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
#
|
|
# (field_identifier)
|
|
# )
|
|
# (field_declaration ...)
|
|
# )
|
|
decho("addType(): case 1")
|
|
nimState.addTypeObject(node, union = union)
|
|
elif node.getName() == "type_definition":
|
|
if node.len >= 2:
|
|
let
|
|
fdlist = node[0].anyChildInTree("field_declaration_list")
|
|
if (fdlist.isNil or (not fdlist.isNil and fdlist.Bl)) and
|
|
nimState.getNodeVal(node[1]) == "":
|
|
# typedef struct X;
|
|
#
|
|
# (type_definition
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
# (type_definition = "")
|
|
# )
|
|
#
|
|
# typedef struct X {};
|
|
#
|
|
# (type_definition
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# (field_declaration_list = "{}")
|
|
# )
|
|
# (type_definition = "")
|
|
# )
|
|
decho("addType(): case 2")
|
|
nimState.addTypeObject(node[0], union = union)
|
|
else:
|
|
let
|
|
fdecl = node[1].anyChildInTree("function_declarator")
|
|
adecl = node[1].anyChildInTree("array_declarator")
|
|
if fdlist.isNil():
|
|
if adecl.isNil and fdecl.isNil:
|
|
# typedef X Y;
|
|
# typedef X *Y;
|
|
# typedef struct X Y;
|
|
# typedef struct X *Y;
|
|
#
|
|
# (type_definition
|
|
# (type_qualifier?)
|
|
# (type_identifier|primitive_type|)
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
#
|
|
# (pointer_declarator - optional, nested
|
|
# (type_identifier)
|
|
# )
|
|
# )
|
|
decho("addType(): case 3")
|
|
nimState.addTypeTyped(node)
|
|
elif not fdecl.isNil:
|
|
# typedef X (*Y)(a1, a2, a3);
|
|
# typedef X *(*Y)(a1, a2, a3);
|
|
# typedef struct X (*Y)(a1, a2, a3);
|
|
# typedef struct X *(*Y)(a1, a2, a3);
|
|
#
|
|
# (type_definition
|
|
# (type_qualifier?)
|
|
# (type_identifier|primitive_type|)
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
#
|
|
# (pointer_declarator - optional, nested
|
|
# (function_declarator
|
|
# (parenthesized_declarator
|
|
# (pointer_declarator
|
|
# (type_identifer)
|
|
# )
|
|
# )
|
|
# (parameter_list
|
|
# (parameter_declaration
|
|
# (struct_specifier|type_identifier|primitive_type|array_declarator|function_declarator)
|
|
# (identifier - optional)
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
# )
|
|
decho("addType(): case 4")
|
|
nimState.addTypeProc(node)
|
|
elif not adecl.isNil:
|
|
# typedef struct X Y[a][..];
|
|
# typedef struct X *Y[a][..];
|
|
# typedef struct X *(*Y)[a][..];
|
|
#
|
|
# (type_definition
|
|
# (type_qualifier?)
|
|
# (type_identifier|primitive_type|)
|
|
# (struct_specifier
|
|
# (type_identifier)
|
|
# )
|
|
#
|
|
# (pointer_declarator - optional, nested
|
|
# (array_declarator - nested
|
|
# (pointer_declarator - optional, nested
|
|
# (type_identifier)
|
|
# )
|
|
# (number_literal)
|
|
# )
|
|
# )
|
|
# )
|
|
decho("addType(): case 5")
|
|
nimState.addTypeArray(node)
|
|
else:
|
|
if node.firstChildInTree("field_declaration_list").isNil:
|
|
# typedef struct X { .. } Y, *Z;
|
|
#
|
|
# (type_definition
|
|
# (struct_specifier
|
|
# (type_identifier) - named struct <====
|
|
# (field_declaration_list
|
|
# (field_declaration - optional, multiple
|
|
# (type_identifier|primitive_type|)
|
|
# (function_declarator|array_declarator
|
|
# ..
|
|
# )
|
|
#
|
|
# (field_identifier)
|
|
# )
|
|
# )
|
|
# )
|
|
#
|
|
# (type_identifier)
|
|
# (pointer_declarator - optional, nested
|
|
# (type_identifier)
|
|
# )
|
|
# )
|
|
|
|
# First add struct as object
|
|
decho("addType(): case 6")
|
|
nimState.addTypeObject(node[0], istype = true, union = union)
|
|
|
|
if node.len > 1 and nimState.getNodeVal(node[1]) != "":
|
|
# Add any additional names
|
|
nimState.addTypeTyped(node)
|
|
else:
|
|
# Same as above except unnamed struct
|
|
#
|
|
# typedef struct { .. } Y, *Z;
|
|
|
|
# Get any name that isn't a pointer
|
|
decho("addType(): case 7")
|
|
let
|
|
name = block:
|
|
var
|
|
name = ""
|
|
for i in 1 ..< node.len:
|
|
if node[i].getName() == "type_identifier":
|
|
name = nimState.getNodeVal(node[i].getAtom())
|
|
|
|
name
|
|
|
|
# Now add struct as object with specified name
|
|
nimState.addTypeObject(node[0], fname = name, istype = true, union = union)
|
|
|
|
if name.nBl:
|
|
# Add any additional names
|
|
nimState.addTypeTyped(node, ftname = name, offset = 1)
|
|
|
|
proc addEnum(nimState: NimState, node: TSNode) =
|
|
decho("addEnum()")
|
|
nimState.printDebug(node)
|
|
|
|
let
|
|
enumlist = node.anyChildInTree("enumerator_list")
|
|
if not enumlist.isNil:
|
|
var
|
|
name, origname = ""
|
|
offset = 0
|
|
prev = ""
|
|
|
|
if node.getAtom().getName() == "type_identifier":
|
|
# [typedef] enum X {} Y;
|
|
# Use X as name
|
|
origname = nimState.getNodeVal(node.getAtom())
|
|
elif node.getName() == "type_definition" and node.len > 1:
|
|
# typedef enum {} Y;
|
|
# Use Y as name
|
|
origname = nimState.getNodeVal(node[1].getAtom())
|
|
offset = 1
|
|
|
|
if origname.nBl:
|
|
name = nimState.getIdentifier(origname, nskType)
|
|
else:
|
|
# enum {};
|
|
# Nameless so create a name
|
|
name = nimState.getUniqueIdentifier("Enum")
|
|
|
|
if name.Bl:
|
|
# Name skipped or overridden since blank
|
|
let
|
|
eoverride = nimState.getOverrideOrSkip(node, origname, nskType)
|
|
if not eoverride.isNil:
|
|
nimState.typeSection.add eoverride
|
|
elif nimState.addNewIdentifer(name):
|
|
# Add enum definition and helpers
|
|
nimState.enumSection.add nimState.parseString(&"defineEnum({name})")
|
|
|
|
# Create const for fields
|
|
var
|
|
fnames: HashSet[string]
|
|
for i in 0 .. enumlist.len - 1:
|
|
let
|
|
en = enumlist[i]
|
|
if en.getName() == "comment":
|
|
continue
|
|
let
|
|
fname = nimState.getIdentifier(nimState.getNodeVal(en.getAtom()), nskEnumField)
|
|
if fname.nBl:
|
|
var
|
|
fval = ""
|
|
if prev.Bl:
|
|
# Starting default value
|
|
fval = &"(0).{name}"
|
|
else:
|
|
# One greater than previous
|
|
fval = &"({prev} + 1).{name}"
|
|
|
|
if en.len > 1 and en[1].getName() in gEnumVals:
|
|
# Explicit value
|
|
fval = "(" & nimState.getNimExpression(nimState.getNodeVal(en[1]), name) & ")." & name
|
|
|
|
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
|
|
nimState.constSection.add nimState.parseString(&"const {fname}* = {fval}")[0][0]
|
|
|
|
fnames.incl fname
|
|
|
|
prev = fname
|
|
|
|
# Add fields to list of consts after processing enum so that we don't cast
|
|
# enum field to itself
|
|
nimState.constIdentifiers.incl fnames
|
|
|
|
# Add other names
|
|
if node.getName() == "type_definition" and node.len > 1:
|
|
nimState.addTypeTyped(node, ftname = name, offset = offset)
|
|
|
|
proc addProc(nimState: NimState, node: TSNode) =
|
|
# Add a proc
|
|
decho("addProc()")
|
|
nimState.printDebug(node)
|
|
|
|
let
|
|
start = getStartAtom(node)
|
|
|
|
for i in start+1 ..< node.len:
|
|
let
|
|
# node[i] = identifier = name
|
|
ident = nimState.newTypeIdent(node[i], kind = nskProc)
|
|
|
|
if not ident.isNil:
|
|
let
|
|
# Only need the ident tree, not nkTypeDef parent
|
|
name = ident.getIdentName()
|
|
|
|
# node[i] could have nested pointers
|
|
tcount = node[i].getPtrCount()
|
|
|
|
# node[start] = identifier = return type name
|
|
(rname, _, rinfo) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name)
|
|
|
|
# Parameter list
|
|
plist = node[i].anyChildInTree("parameter_list")
|
|
|
|
procDef = newNode(nkProcDef)
|
|
|
|
# proc X(a1: Y, a2: Z): P {.pragma.}
|
|
#
|
|
# nkProcDef(
|
|
# nkPostfix(
|
|
# nkIdent("*"),
|
|
# nkIdent("X")
|
|
# ),
|
|
# nkEmpty(),
|
|
# nkEmpty(),
|
|
# nkFormalParams(
|
|
# nkPtrTy( # optional, nested
|
|
# nkIdent(retType)
|
|
# ),
|
|
# nkIdentDefs(
|
|
# nkIdent(param),
|
|
# nkPtrTy(
|
|
# nkIdent(ptype)
|
|
# ),
|
|
# nkEmpty()
|
|
# ),
|
|
# ...
|
|
# ),
|
|
# nkPragma(...),
|
|
# nkEmpty(),
|
|
# nkEmpty()
|
|
# )
|
|
|
|
procDef.add ident
|
|
procDef.add newNode(nkEmpty)
|
|
procDef.add newNode(nkEmpty)
|
|
|
|
# Return type
|
|
var
|
|
retType =
|
|
if rname == "object" and tcount == 0:
|
|
# void func(..)
|
|
newNode(nkEmpty)
|
|
else:
|
|
nimState.getIdent(rname, rinfo, exported = false)
|
|
if tcount > 0:
|
|
retType = nimState.newPtrTree(tcount, retType)
|
|
|
|
# Proc with return type and params
|
|
procDef.add nimState.newFormalParams(name, plist, retType)
|
|
procDef.add newNode(nkEmpty) # Pragmas
|
|
procDef.add newNode(nkEmpty)
|
|
procDef.add newNode(nkEmpty)
|
|
|
|
# nkProcSection.add
|
|
nimState.procSection.add procDef
|
|
|
|
nimState.printDebug(procDef)
|
|
|
|
proc processNode(nimState: NimState, node: TSNode): bool =
|
|
result = true
|
|
|
|
case node.getName()
|
|
of "preproc_def":
|
|
nimState.addConst(node)
|
|
of "type_definition":
|
|
if node.len > 0 and node[0].getName() == "enum_specifier":
|
|
nimState.addEnum(node)
|
|
elif node.len > 0 and node[0].getName() == "union_specifier":
|
|
nimState.addType(node, union = true)
|
|
else:
|
|
nimState.addType(node)
|
|
of "struct_specifier":
|
|
nimState.addType(node)
|
|
of "union_specifier":
|
|
nimState.addType(node, union = true)
|
|
of "enum_specifier":
|
|
nimState.addEnum(node)
|
|
of "declaration":
|
|
nimState.addProc(node)
|
|
else:
|
|
# Unknown
|
|
result = false
|
|
|
|
proc searchTree(nimState: NimState, root: TSNode) =
|
|
# Search AST generated by tree-sitter for recognized elements
|
|
var
|
|
node = root
|
|
nextnode: TSNode
|
|
depth = 0
|
|
processed = false
|
|
|
|
while true:
|
|
if not node.isNil() and depth > -1:
|
|
processed = nimState.processNode(node)
|
|
else:
|
|
break
|
|
|
|
if not processed and node.len() != 0:
|
|
nextnode = node[0]
|
|
depth += 1
|
|
else:
|
|
nextnode = node.tsNodeNextNamedSibling()
|
|
|
|
if nextnode.isNil():
|
|
while true:
|
|
node = node.tsNodeParent()
|
|
depth -= 1
|
|
if depth == -1:
|
|
break
|
|
if node == root:
|
|
break
|
|
if not node.tsNodeNextNamedSibling().isNil():
|
|
node = node.tsNodeNextNamedSibling()
|
|
break
|
|
else:
|
|
node = nextnode
|
|
|
|
if node == root:
|
|
break
|
|
|
|
proc setupPragmas(nimState: NimState, root: TSNode, fullpath: string) =
|
|
# Create shortcut pragmas to reduce clutter
|
|
var
|
|
hdrPragma: PNode
|
|
impPragma = newNode(nkPragma)
|
|
impCPragma = newNode(nkPragma)
|
|
|
|
# {.importc.}
|
|
nimState.addPragma(root, impPragma, "pragma", nimState.getIdent(nimState.impShort))
|
|
nimState.addPragma(root, impPragma, "importc")
|
|
|
|
if nimState.includeHeader():
|
|
nimState.constSection.add nimState.newConstDef(
|
|
root, fname = nimState.currentHeader, fval = '"' & fullpath & '"')
|
|
|
|
# {.header: "xxx".}
|
|
hdrPragma = nimState.newPragma(root, "pragma", nimState.getIdent(nimState.impShort & "H"))
|
|
nimState.addPragma(root, hdrPragma, "header", nimState.getIdent(nimState.currentHeader))
|
|
|
|
nimState.addPragma(root, impPragma, nimState.impShort & "H")
|
|
|
|
# {.importc.} + {.cdecl.} for procs
|
|
nimState.addPragma(root, impCPragma, "pragma", nimState.getIdent(nimState.impShort & "C"))
|
|
nimState.addPragma(root, impCPragma, nimState.impShort)
|
|
nimState.addPragma(root, impCPragma, "cdecl")
|
|
|
|
if nimState.gState.dynlib.nBl:
|
|
# {.dynlib.} for DLLs
|
|
nimState.addPragma(root, impCPragma, "dynlib", nimState.getIdent(nimState.gState.dynlib))
|
|
|
|
# Add all pragma shortcuts to output
|
|
if not hdrPragma.isNil:
|
|
nimState.pragmaSection.add hdrPragma
|
|
nimState.pragmaSection.add impPragma
|
|
nimState.pragmaSection.add impCPragma
|
|
|
|
proc printNimHeader*(gState: State) =
|
|
# Top level output with context info
|
|
gecho """# Generated at $1
|
|
# Command line:
|
|
# $2 $3
|
|
|
|
{.hint[ConvFromXtoItselfNotNeeded]: off.}
|
|
|
|
import nimterop/types
|
|
""" % [$now(), getAppFilename(), commandLineParams().join(" ")]
|
|
|
|
proc printNim*(gState: State, fullpath: string, root: TSNode) =
|
|
# Generate Nim from tree-sitter AST root node
|
|
let
|
|
nimState = new(NimState)
|
|
fp = fullpath.replace("\\", "/")
|
|
|
|
# Track identifiers already rendered and corresponding PNodes
|
|
nimState.identifiers = newTable[string, string]()
|
|
nimState.identifierNodes = newTable[string, PNode]()
|
|
|
|
# toast objects
|
|
nimState.gState = gState
|
|
nimState.currentHeader = getCurrentHeader(fullpath)
|
|
nimState.impShort = nimState.currentHeader.replace("header", "imp")
|
|
nimState.sourceFile = fullpath
|
|
|
|
# Nim compiler objects
|
|
nimState.identCache = newIdentCache()
|
|
nimState.config = newConfigRef()
|
|
nimstate.graph = newModuleGraph(nimState.identCache, nimState.config)
|
|
|
|
# Initialize all section PNodes
|
|
nimState.pragmaSection = newNode(nkStmtList)
|
|
nimState.constSection = newNode(nkConstSection)
|
|
nimState.enumSection = newNode(nkStmtList)
|
|
nimState.procSection = newNode(nkStmtList)
|
|
nimState.typeSection = newNode(nkTypeSection)
|
|
|
|
# Setup pragmas
|
|
nimState.setupPragmas(root, fp)
|
|
|
|
# Search root node and render Nim
|
|
nimState.searchTree(root)
|
|
|
|
# Add any unused cOverride symbols to output
|
|
nimState.addAllOverrideFinal()
|
|
|
|
# Create output to Nim using Nim compiler renderer
|
|
var
|
|
tree = newNode(nkStmtList)
|
|
tree.add nimState.enumSection
|
|
tree.add nimState.constSection
|
|
tree.add nimState.pragmaSection
|
|
tree.add nimState.typeSection
|
|
tree.add nimState.procSection
|
|
|
|
gecho tree.renderTree()
|