ast2 nested struct support

This commit is contained in:
Ganesh Viswanathan 2020-04-14 19:40:46 -05:00
commit 92fe90f834
4 changed files with 82 additions and 27 deletions

View file

@ -29,7 +29,7 @@ task bt, "build toast":
execCmd("nim c --hints:off -d:danger nimterop/toast.nim") execCmd("nim c --hints:off -d:danger nimterop/toast.nim")
task btd, "build toast": task btd, "build toast":
execCmd("nim c -g --hints:off nimterop/toast.nim") execCmd("nim c -g nimterop/toast.nim")
task docs, "Generate docs": task docs, "Generate docs":
buildDocs(@["nimterop/all.nim"], "build/htmldocs") buildDocs(@["nimterop/all.nim"], "build/htmldocs")

View file

@ -495,10 +495,12 @@ proc newArrayTree(nimState: NimState, node: TSNode, typ, size: PNode = nil): PNo
proc getTypeArray(nimState: NimState, node, tnode: TSNode, name: string): PNode proc getTypeArray(nimState: NimState, node, tnode: TSNode, name: string): PNode
proc getTypeProc(nimState: NimState, name: string, node, rnode: TSNode): PNode proc getTypeProc(nimState: NimState, name: string, node, rnode: TSNode): PNode
iterator newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: SomeInteger, exported = false): PNode = iterator newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: SomeInteger, ftname = "", exported = false): PNode =
# Create nkIdentDefs tree for specified proc parameter or object field # Create nkIdentDefs tree for specified proc parameter or object field
# #
# For proc, param should not be exported # For proc, param should not be `exported`
#
# If `ftname` is set, use it as the type name
# #
# pname: [ptr ..] typ # pname: [ptr ..] typ
# #
@ -531,7 +533,15 @@ iterator newIdentDefs(nimState: NimState, name: string, node: TSNode, offset: So
start = getStartAtom(node) start = getStartAtom(node)
# node[start] - param type # node[start] - param type
(tname, _, tinfo) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name) (tname0, _, tinfo) = nimState.getNameInfo(node[start].getAtom(), nskType, parent = name)
# Override type name
tname =
if ftname.nBl:
ftname
else:
tname0
tident = nimState.getIdent(tname, tinfo, exported = false) tident = nimState.getIdent(tname, tinfo, exported = false)
if start == node.len - 1: if start == node.len - 1:
@ -676,6 +686,7 @@ proc newProcTy(nimState: NimState, name: string, node: TSNode, rtyp: PNode): PNo
result.add nimState.newFormalParams(name, node, rtyp) result.add nimState.newFormalParams(name, node, rtyp)
result.add nimState.newPragma(node, nimState.gState.convention) result.add nimState.newPragma(node, nimState.gState.convention)
proc processNode(nimState: NimState, node: TSNode): bool
proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode = proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode =
# Create nkRecList tree for specified object # Create nkRecList tree for specified object
if not node.isNil: if not node.isNil:
@ -691,8 +702,34 @@ proc newRecListTree(nimState: NimState, name: string, node: TSNode): PNode =
for i in 0 ..< node.len: for i in 0 ..< node.len:
if node[i].getName() == "field_declaration": if node[i].getName() == "field_declaration":
# Check for nested structs / unions / enums
let
fdecl = node[i].anyChildInTree("field_declaration_list")
edecl = node[i].anyChildInTree("enumerator_list")
# `tname` is name of nested struct / union / enum just
# added, passed on as type name for field in `newIdentDefs()`
(processed, tname) =
if not fdecl.isNil:
# Nested struct / union
(
nimState.processNode(fdecl.tsNodeParent()),
nimState.typeSection[^1].getIdentName()
)
elif not edecl.isNil:
# Nested enum
(
nimState.processNode(edecl.tsNodeParent()),
$nimState.enumSection[^1][0][1]
)
else:
(true, "")
if not processed:
return nil
# Add nkIdentDefs for each field # Add nkIdentDefs for each field
for field in nimState.newIdentDefs(name, node[i], i, exported = true): for field in nimState.newIdentDefs(name, node[i], i, ftname = tname, exported = true):
if not field.isNil: if not field.isNil:
result.add field result.add field
@ -722,6 +759,16 @@ proc addTypeObject(nimState: NimState, node: TSNode, typeDef: PNode = nil, fname
pragmas pragmas
fname =
if not node.firstChildInTree("field_declaration_list").isNil and
node.tsNodeParent().getName() == "field_declaration":
# If nested struct / union without a name
nimState.getUniqueIdentifier(
if union: "Union" else: "Type"
)
else:
fname
typeDefExisting = not typeDef.isNil typeDefExisting = not typeDef.isNil
typeDef = typeDef =
@ -784,7 +831,11 @@ proc addTypeObject(nimState: NimState, node: TSNode, typeDef: PNode = nil, fname
if not fdlist.isNil and fdlist.len > 0: if not fdlist.isNil and fdlist.len > 0:
# Add fields to object if present # Add fields to object if present
obj.add nimState.newRecListTree(name, fdlist) let
fields = nimState.newRecListTree(name, fdlist)
if fields.isNil:
return
obj.add fields
else: else:
obj.add newNode(nkEmpty) obj.add newNode(nkEmpty)
@ -828,7 +879,11 @@ proc addTypeObject(nimState: NimState, node: TSNode, typeDef: PNode = nil, fname
def[2].kind == nkObjectTy and def[2].len == 3 and def[2].kind == nkObjectTy and def[2].len == 3 and
def[2][2].kind == nkEmpty: def[2][2].kind == nkEmpty:
# Add fields to existing object # Add fields to existing object
def[2][2] = nimState.newRecListTree(name, fdlist) let
fields = nimState.newRecListTree(name, fdlist)
if fields.isNil:
return
def[2][2] = fields
# Change incompleteStruct to bycopy pragma # Change incompleteStruct to bycopy pragma
if def[0].kind == nkPragmaExpr and def[0].len == 2 and if def[0].kind == nkPragmaExpr and def[0].len == 2 and
@ -1180,7 +1235,7 @@ proc addType(nimState: NimState, node: TSNode, union = false) =
let let
fdecl = node[1].anyChildInTree("function_declarator") fdecl = node[1].anyChildInTree("function_declarator")
adecl = node[1].anyChildInTree("array_declarator") adecl = node[1].anyChildInTree("array_declarator")
if fdlist.isNil(): if fdlist.isNil:
if adecl.isNil and fdecl.isNil: if adecl.isNil and fdecl.isNil:
# typedef X Y; # typedef X Y;
# typedef X *Y; # typedef X *Y;
@ -1605,18 +1660,18 @@ proc searchTree(nimState: NimState, root: TSNode) =
processed = false processed = false
while true: while true:
if not node.isNil() and depth > -1: if not node.isNil and depth > -1:
processed = nimState.processNode(node) processed = nimState.processNode(node)
else: else:
break break
if not processed and node.len() != 0: if not processed and node.len != 0:
nextnode = node[0] nextnode = node[0]
depth += 1 depth += 1
else: else:
nextnode = node.tsNodeNextNamedSibling() nextnode = node.tsNodeNextNamedSibling()
if nextnode.isNil(): if nextnode.isNil:
while true: while true:
node = node.tsNodeParent() node = node.tsNodeParent()
depth -= 1 depth -= 1
@ -1624,7 +1679,7 @@ proc searchTree(nimState: NimState, root: TSNode) =
break break
if node == root: if node == root:
break break
if not node.tsNodeNextNamedSibling().isNil(): if not node.tsNodeNextNamedSibling().isNil:
node = node.tsNodeNextNamedSibling() node = node.tsNodeNextNamedSibling()
break break
else: else:

View file

@ -214,7 +214,7 @@ proc len*(node: TSNode): int =
result = node.tsNodeNamedChildCount().int result = node.tsNodeNamedChildCount().int
proc `[]`*(node: TSNode, i: SomeInteger): TSNode = proc `[]`*(node: TSNode, i: SomeInteger): TSNode =
if i < node.len(): if i < node.len:
result = node.tsNodeNamedChild(i.uint32) result = node.tsNodeNamedChild(i.uint32)
proc getName*(node: TSNode): string {.inline.} = proc getName*(node: TSNode): string {.inline.} =
@ -233,10 +233,10 @@ proc getAtom*(node: TSNode): TSNode =
# Get child node which is topmost atom # Get child node which is topmost atom
if node.getName() in gAtoms: if node.getName() in gAtoms:
return node return node
elif node.len() != 0: elif node.len != 0:
if node[0].getName() == "type_qualifier": if node[0].getName() == "type_qualifier":
# Skip const, volatile # Skip const, volatile
if node.len() > 1: if node.len > 1:
return node[1].getAtom() return node[1].getAtom()
else: else:
return return
@ -262,10 +262,10 @@ proc getXCount*(node: TSNode, ntype: string, reverse = false): int =
if reverse: if reverse:
cnode = cnode.tsNodeParent() cnode = cnode.tsNodeParent()
else: else:
if cnode.len() != 0: if cnode.len != 0:
if cnode[0].getName() == "type_qualifier": if cnode[0].getName() == "type_qualifier":
# Skip const, volatile # Skip const, volatile
if cnode.len() > 1: if cnode.len > 1:
cnode = cnode[1] cnode = cnode[1]
else: else:
break break
@ -285,7 +285,7 @@ proc getDeclarator*(node: TSNode): TSNode =
# Return if child is a function or array declarator # Return if child is a function or array declarator
if node.getName() in ["function_declarator", "array_declarator"]: if node.getName() in ["function_declarator", "array_declarator"]:
return node return node
elif node.len() != 0: elif node.len != 0:
return node[0].getDeclarator() return node[0].getDeclarator()
proc firstChildInTree*(node: TSNode, ntype: string): TSNode = proc firstChildInTree*(node: TSNode, ntype: string): TSNode =
@ -307,7 +307,7 @@ proc anyChildInTree*(node: TSNode, ntype: string): TSNode =
for i in 0 ..< cnode.len: for i in 0 ..< cnode.len:
let let
ccnode = cnode[i].anyChildInTree(ntype) ccnode = cnode[i].anyChildInTree(ntype)
if not ccnode.isNil(): if not ccnode.isNil:
return ccnode return ccnode
if cnode != node: if cnode != node:
cnode = cnode.tsNodeNextNamedSibling() cnode = cnode.tsNodeNextNamedSibling()
@ -326,7 +326,7 @@ proc mostNestedChildInTree*(node: TSNode): TSNode =
proc inChildren*(node: TSNode, ntype: string): bool = proc inChildren*(node: TSNode, ntype: string): bool =
# Search for node type in immediate children # Search for node type in immediate children
result = false result = false
for i in 0 ..< node.len(): for i in 0 ..< node.len:
if (node[i]).getName() == ntype: if (node[i]).getName() == ntype:
result = true result = true
break break
@ -342,7 +342,7 @@ proc getLineCol*(gState: State, node: TSNode): tuple[line, col: int] =
result.col += 1 result.col += 1
proc getTSNodeNamedChildCountSansComments*(node: TSNode): int = proc getTSNodeNamedChildCountSansComments*(node: TSNode): int =
for i in 0 ..< node.len(): for i in 0 ..< node.len:
if node.getName() != "comment": if node.getName() != "comment":
result += 1 result += 1
@ -352,11 +352,11 @@ proc getPxName*(node: TSNode, offset: int): string =
np = node np = node
count = 0 count = 0
while not np.isNil() and count < offset: while not np.isNil and count < offset:
np = np.tsNodeParent() np = np.tsNodeParent()
count += 1 count += 1
if count == offset and not np.isNil(): if count == offset and not np.isNil:
return np.getName() return np.getName()
proc printLisp*(gState: State, root: TSNode): string = proc printLisp*(gState: State, root: TSNode): string =
@ -366,7 +366,7 @@ proc printLisp*(gState: State, root: TSNode): string =
depth = 0 depth = 0
while true: while true:
if not node.isNil() and depth > -1: if not node.isNil and depth > -1:
result &= spaces(depth) result &= spaces(depth)
let let
(line, col) = gState.getLineCol(node) (line, col) = gState.getLineCol(node)
@ -386,7 +386,7 @@ proc printLisp*(gState: State, root: TSNode): string =
result &= ")\n" result &= ")\n"
nextnode = node.tsNodeNextNamedSibling() nextnode = node.tsNodeNextNamedSibling()
if nextnode.isNil(): if nextnode.isNil:
while true: while true:
node = node.tsNodeParent() node = node.tsNodeParent()
depth -= 1 depth -= 1
@ -395,7 +395,7 @@ proc printLisp*(gState: State, root: TSNode): string =
result &= spaces(depth) & ")\n" result &= spaces(depth) & ")\n"
if node == root: if node == root:
break break
if not node.tsNodeNextNamedSibling().isNil(): if not node.tsNodeNextNamedSibling().isNil:
node = node.tsNodeNextNamedSibling() node = node.tsNodeNextNamedSibling()
break break
else: else:

View file

@ -35,7 +35,7 @@ proc readFromTokens(): ref Ast =
idx += 2 idx += 2
while gTokens[idx] != ")": while gTokens[idx] != ")":
var res = readFromTokens() var res = readFromTokens()
if not res.isNil(): if not res.isNil:
result.children.add(res) result.children.add(res)
elif gTokens[idx] == ")": elif gTokens[idx] == ")":
doAssert false, "Poor AST " & $(idx: idx) doAssert false, "Poor AST " & $(idx: idx)