Skip to content

Commit d9a26ff

Browse files
authored
Merge pull request #27 from divmadan/fix/parsed_tree
Changes in parse.py
2 parents bd81f51 + 7628b32 commit d9a26ff

File tree

2 files changed

+515
-417
lines changed

2 files changed

+515
-417
lines changed

clang_bind/parse.py

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
from clang_bind.clang_utils import ClangUtils
55

66

7-
class Node:
7+
class ParsedInfo:
8+
"""This is a data holder class containing parsed info, to be used while constructing the tree.
9+
10+
:param cursor: An object of :class:`clang.cindex.Cursor`
11+
:type cursor: class:`clang.cindex.Cursor`
12+
:param verbose: Add additional information about the cursor, defaults to False
13+
:type verbose: bool, optional
14+
"""
15+
816
def __init__(self, cursor, verbose=False):
917
self.cursor = cursor
1018
if verbose:
@@ -19,11 +27,16 @@ def __repr__(self) -> str:
1927

2028

2129
class Parse:
22-
"""
23-
Class to parse a file and generate an AST from it.
30+
"""This is a class which parses a file and generate an abstract syntax tree from it.
31+
32+
:param file: File to parse
33+
:type file: str
34+
:param compiler_arguments: Compiler arguments to use while parsing
35+
:type compiler_arguments: list, optional
2436
"""
2537

26-
def __init__(self, file, compiler_arguments):
38+
def __init__(self, file, compiler_arguments=[]):
39+
self._parsed_info_map = {}
2740
index = clang.Index.create()
2841
"""
2942
- Why parse using the option `PARSE_DETAILED_PROCESSING_RECORD`?
@@ -38,40 +51,124 @@ def __init__(self, file, compiler_arguments):
3851
)
3952
self.filename = source_ast.spelling
4053
self.tree = Tree()
41-
self.root_node = self.tree.create_node(
42-
identifier=Node(source_ast.cursor), tag=repr(Node(source_ast.cursor))
43-
)
54+
parsed_info = ParsedInfo(source_ast.cursor)
55+
self.root_node = self.tree.create_node(tag=repr(parsed_info))
56+
self._parsed_info_map[self.root_node.identifier] = parsed_info
57+
self._construct_tree(self.root_node)
4458

4559
@staticmethod
46-
def is_node_from_file(node, filename):
47-
"""
48-
Check if the node belongs in the file.
60+
def is_cursor_in_file(cursor, filename):
61+
"""Checks if the cursor belongs in the file.
62+
63+
:param cursor: An object of :class:`clang.cindex.Cursor`
64+
:type cursor: class:`clang.cindex.Cursor`
65+
:param filename: Filename to search the cursor
66+
:type filename: str
67+
:return: `True` if cursor in file, else `False`
68+
:rtype: bool
4969
"""
50-
return node.location.file and node.location.file.name == filename
70+
return cursor.location.file and cursor.location.file.name == filename
5171

5272
def _is_valid_child(self, child_cursor):
73+
"""Checks if the child is valid (child should be in the same file as the parent).
74+
75+
:param child_cursor: The child cursor to check, an object of :class:`clang.cindex.Cursor`
76+
:type child_cursor: class:`clang.cindex.Cursor`
77+
:return: `True` if child cursor in file, else `False`
78+
:rtype: bool
5379
"""
54-
Check if the child is valid (child should be in the same file as the parent).
55-
"""
56-
return self.is_node_from_file(child_cursor, self.filename)
80+
return self.is_cursor_in_file(child_cursor, self.filename)
5781

5882
def _construct_tree(self, node):
83+
"""Recursively generates tree by traversing the AST of the node.
84+
85+
:param node: An object of :class:`treelib.Node`
86+
:type node: class:`treelib.Node`
5987
"""
60-
Recursively generates tree by traversing the AST of the node.
61-
"""
62-
cursor = node.identifier.cursor
88+
cursor = self.get_parsed_info_from_node_id(node.identifier).cursor
6389
for child_cursor in cursor.get_children():
6490
if self._is_valid_child(child_cursor):
91+
parsed_info = ParsedInfo(child_cursor)
6592
child_node = self.tree.create_node(
66-
identifier=Node(child_cursor),
6793
parent=node,
68-
tag=repr(Node(child_cursor)),
94+
tag=repr(parsed_info),
6995
)
96+
self._parsed_info_map[child_node.identifier] = parsed_info
7097
self._construct_tree(child_node)
7198

7299
def get_tree(self):
100+
"""Returns the constructed AST.
101+
102+
:return: Constructed AST
103+
:rtype: class:`treelib.Tree`
73104
"""
74-
Returns the constructed tree.
75-
"""
76-
self._construct_tree(self.root_node)
77105
return self.tree
106+
107+
def get_node_id_from_parsed_info(self, parsed_info):
108+
"""Returns node identifier by performing a value based search of `_parsed_info_map`.
109+
110+
:param parsed_info: An object of :class:`clang_bind.parse.ParsedInfo`
111+
, the value to get the corresponding key from `_parsed_info_map`
112+
:type parsed_info`: class:`clang_bind.parse.ParsedInfo`
113+
:return node_id: Node identifier corresponding to `parsed_info`
114+
:rtype: `treelib.Tree.identifier`
115+
"""
116+
for node_id, parsed_info_ in self._parsed_info_map.items():
117+
if parsed_info_ == parsed_info:
118+
return node_id
119+
120+
def get_children_nodes_from_parent_parsed_info(self, parent_parsed_info):
121+
"""Returns a list of children nodes from parent parsed infos.
122+
123+
:param parent_parsed_info: The parent object of :class:`clang_bind.parse.ParsedInfo`
124+
:type parent_parsed_info: class:`clang_bind.parse.ParsedInfo`
125+
:return: Children nodes of :class:`treelib.Node`
126+
:rtype: list
127+
"""
128+
return self.tree.children(self.get_node_id_from_parsed_info(parent_parsed_info))
129+
130+
def get_parsed_infos_from_node_ids(self, node_ids):
131+
"""Returns a list of parsed infos from a list of node identifiers
132+
, by getting the values from `_parsed_info_map`
133+
134+
:param node_ids: Node identifiers of :class:`treelib.Node`
135+
:type node_ids: list
136+
:return: Parsed infos of :class:`clang_bind.parse.ParsedInfo`
137+
:rtype: list
138+
"""
139+
return list(map(lambda node_id: self._parsed_info_map.get(node_id), node_ids))
140+
141+
def get_parsed_info_from_node_id(self, node_id):
142+
"""Returns parsed info from node identifier, by getting the value from `_parsed_info_map`
143+
144+
:param node_id: Node identifier
145+
:type node_id: class:`treelib.Node`
146+
:return: Parsed info corresponding to `node_id`
147+
:rtype: class:`clang_bind.parse.ParsedInfo`
148+
"""
149+
return self.get_parsed_infos_from_node_ids([node_id])[0]
150+
151+
@staticmethod
152+
def get_node_ids_from_nodes(nodes):
153+
"""Returns a list of node identifiers from a list of nodes.
154+
155+
:param nodes: A list of objects of :class:`treelib.Node`
156+
:type nodes: class:`treelib.Node`
157+
:return: A list of node identifiers of `treelib.Tree.identifier`
158+
:rtype: list
159+
"""
160+
return list(map(lambda node: node.identifier, nodes))
161+
162+
def get_children_parsed_infos_from_parent_parsed_info(self, parent_parsed_info):
163+
"""Returns children parsed infos from parent parsed infos.
164+
165+
:param parent_parsed_info: The parent object of :class:`clang_bind.parse.ParsedInfo`
166+
:type parent_parsed_info: class:`clang_bind.parse.ParsedInfo`
167+
:return: Children parsed infos of :class:`clang_bind.parse.ParsedInfo`
168+
:rtype: list
169+
"""
170+
return self.get_parsed_infos_from_node_ids(
171+
self.get_node_ids_from_nodes(
172+
self.get_children_nodes_from_parent_parsed_info(parent_parsed_info)
173+
)
174+
)

0 commit comments

Comments
 (0)