lambda-graphs 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lambda_graphs/__init__.py +18 -0
- lambda_graphs/__main__.py +7 -0
- lambda_graphs/cli.py +183 -0
- lambda_graphs/codeviews/AST/AST.py +120 -0
- lambda_graphs/codeviews/AST/AST_driver.py +37 -0
- lambda_graphs/codeviews/AST/__init__.py +0 -0
- lambda_graphs/codeviews/CFG/CFG.py +42 -0
- lambda_graphs/codeviews/CFG/CFG_c.py +1182 -0
- lambda_graphs/codeviews/CFG/CFG_cpp.py +5604 -0
- lambda_graphs/codeviews/CFG/CFG_driver.py +45 -0
- lambda_graphs/codeviews/CFG/CFG_java.py +1722 -0
- lambda_graphs/codeviews/CFG/__init__.py +0 -0
- lambda_graphs/codeviews/CST/CST_driver.py +70 -0
- lambda_graphs/codeviews/CST/__init__.py +0 -0
- lambda_graphs/codeviews/DFG/DFG_driver.py +42 -0
- lambda_graphs/codeviews/DFG/__init__.py +0 -0
- lambda_graphs/codeviews/SDFG/SDFG.py +135 -0
- lambda_graphs/codeviews/SDFG/SDFG_c.py +2041 -0
- lambda_graphs/codeviews/SDFG/SDFG_cpp.py +4030 -0
- lambda_graphs/codeviews/SDFG/SDFG_java.py +1618 -0
- lambda_graphs/codeviews/SDFG/__init__.py +0 -0
- lambda_graphs/codeviews/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/combined_driver.py +163 -0
- lambda_graphs/tree_parser/__init__.py +0 -0
- lambda_graphs/tree_parser/c_parser.py +565 -0
- lambda_graphs/tree_parser/cpp_parser.py +424 -0
- lambda_graphs/tree_parser/custom_parser.py +66 -0
- lambda_graphs/tree_parser/java_parser.py +254 -0
- lambda_graphs/tree_parser/parser_driver.py +54 -0
- lambda_graphs/utils/DFG_utils.py +44 -0
- lambda_graphs/utils/__init__.py +0 -0
- lambda_graphs/utils/c_nodes.py +431 -0
- lambda_graphs/utils/cpp_nodes.py +1331 -0
- lambda_graphs/utils/java_nodes.py +756 -0
- lambda_graphs/utils/multi_file_merger.py +444 -0
- lambda_graphs/utils/postprocessor.py +83 -0
- lambda_graphs/utils/preprocessor.py +68 -0
- lambda_graphs/utils/src_parser.py +23 -0
- lambda_graphs-0.1.4.dist-info/METADATA +380 -0
- lambda_graphs-0.1.4.dist-info/RECORD +45 -0
- lambda_graphs-0.1.4.dist-info/WHEEL +5 -0
- lambda_graphs-0.1.4.dist-info/entry_points.txt +2 -0
- lambda_graphs-0.1.4.dist-info/licenses/LICENSE +21 -0
- lambda_graphs-0.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
from ..tree_parser.custom_parser import CustomParser
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CppParser(CustomParser):
|
|
5
|
+
def __init__(self, src_language, src_code):
|
|
6
|
+
super().__init__(src_language, src_code)
|
|
7
|
+
|
|
8
|
+
def check_declaration(self, current_node):
|
|
9
|
+
"""
|
|
10
|
+
Check if the current node is a variable declaration in C++.
|
|
11
|
+
C++ declarations can be:
|
|
12
|
+
- init_declarator (e.g., int x = 5;)
|
|
13
|
+
- Direct child of declaration (e.g., int x;)
|
|
14
|
+
- parameter_declaration (function parameters)
|
|
15
|
+
- pointer_declarator (pointer variables)
|
|
16
|
+
- reference_declarator (reference variables)
|
|
17
|
+
- auto declarations
|
|
18
|
+
- structured bindings
|
|
19
|
+
"""
|
|
20
|
+
parent_types = [
|
|
21
|
+
"init_declarator",
|
|
22
|
+
"parameter_declaration",
|
|
23
|
+
"optional_parameter_declaration",
|
|
24
|
+
"pointer_declarator",
|
|
25
|
+
"reference_declarator",
|
|
26
|
+
"array_declarator",
|
|
27
|
+
]
|
|
28
|
+
current_types = ["identifier"]
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
current_node.parent is not None
|
|
32
|
+
and current_node.parent.type in parent_types
|
|
33
|
+
and current_node.type in current_types
|
|
34
|
+
):
|
|
35
|
+
if current_node.parent.type == "init_declarator":
|
|
36
|
+
declarator = (
|
|
37
|
+
current_node.parent.children[0]
|
|
38
|
+
if current_node.parent.children
|
|
39
|
+
else None
|
|
40
|
+
)
|
|
41
|
+
if declarator:
|
|
42
|
+
if declarator == current_node:
|
|
43
|
+
return True
|
|
44
|
+
if declarator.type in [
|
|
45
|
+
"pointer_declarator",
|
|
46
|
+
"reference_declarator",
|
|
47
|
+
"array_declarator",
|
|
48
|
+
]:
|
|
49
|
+
if (
|
|
50
|
+
self.find_identifier_in_declarator(declarator)
|
|
51
|
+
== current_node
|
|
52
|
+
):
|
|
53
|
+
return True
|
|
54
|
+
elif current_node.parent.type in [
|
|
55
|
+
"pointer_declarator",
|
|
56
|
+
"reference_declarator",
|
|
57
|
+
]:
|
|
58
|
+
if current_node.type == "identifier":
|
|
59
|
+
return True
|
|
60
|
+
elif current_node.parent.type == "array_declarator":
|
|
61
|
+
if (
|
|
62
|
+
current_node.parent.children
|
|
63
|
+
and current_node.parent.children[0] == current_node
|
|
64
|
+
):
|
|
65
|
+
return True
|
|
66
|
+
elif current_node.parent.type in [
|
|
67
|
+
"parameter_declaration",
|
|
68
|
+
"optional_parameter_declaration",
|
|
69
|
+
]:
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
current_node.parent is not None
|
|
74
|
+
and current_node.parent.type == "declaration"
|
|
75
|
+
and current_node.type == "identifier"
|
|
76
|
+
):
|
|
77
|
+
for i, child in enumerate(current_node.parent.children):
|
|
78
|
+
if child == current_node and i > 0:
|
|
79
|
+
prev_sibling = current_node.parent.children[i - 1]
|
|
80
|
+
if prev_sibling.type in [
|
|
81
|
+
"primitive_type",
|
|
82
|
+
"type_identifier",
|
|
83
|
+
"sized_type_specifier",
|
|
84
|
+
"struct_specifier",
|
|
85
|
+
"class_specifier",
|
|
86
|
+
"union_specifier",
|
|
87
|
+
"enum_specifier",
|
|
88
|
+
"storage_class_specifier",
|
|
89
|
+
"type_qualifier",
|
|
90
|
+
"auto",
|
|
91
|
+
"template_type",
|
|
92
|
+
"qualified_identifier",
|
|
93
|
+
]:
|
|
94
|
+
return True
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
if current_node.parent is not None and current_node.parent.type == "declarator":
|
|
98
|
+
if (
|
|
99
|
+
current_node.parent.parent is not None
|
|
100
|
+
and current_node.parent.parent.type
|
|
101
|
+
in ["declaration", "parameter_declaration"]
|
|
102
|
+
):
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
current_node.parent is not None
|
|
107
|
+
and current_node.parent.type == "function_declarator"
|
|
108
|
+
):
|
|
109
|
+
declarator = current_node.parent.child_by_field_name("declarator")
|
|
110
|
+
if declarator == current_node:
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
current_node.parent is not None
|
|
115
|
+
and current_node.parent.type == "field_declaration"
|
|
116
|
+
):
|
|
117
|
+
for i, child in enumerate(current_node.parent.children):
|
|
118
|
+
if child == current_node and i > 0:
|
|
119
|
+
prev_sibling = current_node.parent.children[i - 1]
|
|
120
|
+
if prev_sibling.type in [
|
|
121
|
+
"primitive_type",
|
|
122
|
+
"type_identifier",
|
|
123
|
+
"sized_type_specifier",
|
|
124
|
+
"template_type",
|
|
125
|
+
"qualified_identifier",
|
|
126
|
+
"auto",
|
|
127
|
+
]:
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
def find_identifier_in_declarator(self, node):
|
|
133
|
+
"""Recursively find the identifier within a declarator node."""
|
|
134
|
+
if node.type == "identifier":
|
|
135
|
+
return node
|
|
136
|
+
for child in node.children:
|
|
137
|
+
result = self.find_identifier_in_declarator(child)
|
|
138
|
+
if result is not None:
|
|
139
|
+
return result
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
def get_type(self, node):
|
|
143
|
+
"""
|
|
144
|
+
Given a declarator node, return the variable type of the identifier.
|
|
145
|
+
C++ type specifiers include: primitive_type, type_identifier, template_type, etc.
|
|
146
|
+
|
|
147
|
+
This function traverses up the tree to find the declaration or parameter_declaration node,
|
|
148
|
+
then searches for the type specifier among its children.
|
|
149
|
+
"""
|
|
150
|
+
datatypes = [
|
|
151
|
+
"primitive_type",
|
|
152
|
+
"type_identifier",
|
|
153
|
+
"sized_type_specifier",
|
|
154
|
+
"struct_specifier",
|
|
155
|
+
"class_specifier",
|
|
156
|
+
"union_specifier",
|
|
157
|
+
"enum_specifier",
|
|
158
|
+
"template_type",
|
|
159
|
+
"qualified_identifier",
|
|
160
|
+
"auto",
|
|
161
|
+
"decltype",
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
current = node
|
|
165
|
+
|
|
166
|
+
while current is not None:
|
|
167
|
+
if current.type in [
|
|
168
|
+
"declaration",
|
|
169
|
+
"parameter_declaration",
|
|
170
|
+
"optional_parameter_declaration",
|
|
171
|
+
"field_declaration",
|
|
172
|
+
]:
|
|
173
|
+
for child in current.children:
|
|
174
|
+
if child.type in datatypes:
|
|
175
|
+
return child.text.decode("utf-8")
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
current = current.parent
|
|
179
|
+
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
def scope_check(self, parent_scope, child_scope):
|
|
183
|
+
"""Check if parent_scope is a subset of child_scope."""
|
|
184
|
+
for p in parent_scope:
|
|
185
|
+
if p not in child_scope:
|
|
186
|
+
return False
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
def longest_scope_match(self, name_matches, symbol_table):
|
|
190
|
+
"""Given a list of name matches, return the longest scope match."""
|
|
191
|
+
scope_array = list(map(lambda x: symbol_table["scope_map"][x[0]], name_matches))
|
|
192
|
+
max_val = max(scope_array, key=lambda x: len(x))
|
|
193
|
+
for i in range(len(scope_array)):
|
|
194
|
+
if scope_array[i] == max_val:
|
|
195
|
+
return name_matches[i][0]
|
|
196
|
+
|
|
197
|
+
def create_all_tokens(
|
|
198
|
+
self,
|
|
199
|
+
src_code,
|
|
200
|
+
root_node,
|
|
201
|
+
all_tokens,
|
|
202
|
+
label,
|
|
203
|
+
method_map,
|
|
204
|
+
method_calls,
|
|
205
|
+
start_line,
|
|
206
|
+
declaration,
|
|
207
|
+
declaration_map,
|
|
208
|
+
symbol_table,
|
|
209
|
+
):
|
|
210
|
+
"""
|
|
211
|
+
Create tokens for C++ language.
|
|
212
|
+
Handles C++-specific constructs like classes, namespaces, templates, references, etc.
|
|
213
|
+
"""
|
|
214
|
+
remove_list = [
|
|
215
|
+
"function_definition",
|
|
216
|
+
"call_expression",
|
|
217
|
+
"class_specifier",
|
|
218
|
+
"struct_specifier",
|
|
219
|
+
]
|
|
220
|
+
|
|
221
|
+
block_types = [
|
|
222
|
+
"compound_statement",
|
|
223
|
+
"if_statement",
|
|
224
|
+
"while_statement",
|
|
225
|
+
"for_statement",
|
|
226
|
+
"for_range_loop",
|
|
227
|
+
"do_statement",
|
|
228
|
+
"switch_statement",
|
|
229
|
+
"case_statement",
|
|
230
|
+
"function_definition",
|
|
231
|
+
"class_specifier",
|
|
232
|
+
"struct_specifier",
|
|
233
|
+
"namespace_definition",
|
|
234
|
+
"try_statement",
|
|
235
|
+
"catch_clause",
|
|
236
|
+
"lambda_expression",
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
if root_node.is_named and root_node.type in block_types:
|
|
240
|
+
symbol_table["scope_id"] = symbol_table["scope_id"] + 1
|
|
241
|
+
symbol_table["scope_stack"].append(symbol_table["scope_id"])
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
root_node.is_named
|
|
245
|
+
and (
|
|
246
|
+
len(root_node.children) == 0
|
|
247
|
+
or root_node.type in ["string_literal", "raw_string_literal"]
|
|
248
|
+
)
|
|
249
|
+
and root_node.type != "comment"
|
|
250
|
+
):
|
|
251
|
+
index = self.index[
|
|
252
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
label[index] = root_node.text.decode("UTF-8")
|
|
256
|
+
|
|
257
|
+
start_line[index] = root_node.start_point[0]
|
|
258
|
+
|
|
259
|
+
all_tokens.append(index)
|
|
260
|
+
|
|
261
|
+
symbol_table["scope_map"][index] = symbol_table["scope_stack"].copy()
|
|
262
|
+
|
|
263
|
+
current_node = root_node
|
|
264
|
+
|
|
265
|
+
if (
|
|
266
|
+
current_node.parent is not None
|
|
267
|
+
and current_node.parent.type in remove_list
|
|
268
|
+
):
|
|
269
|
+
method_map.append(index)
|
|
270
|
+
if (
|
|
271
|
+
current_node.next_named_sibling is not None
|
|
272
|
+
and current_node.next_named_sibling.type == "argument_list"
|
|
273
|
+
):
|
|
274
|
+
method_calls.append(index)
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
current_node.parent is not None
|
|
278
|
+
and current_node.parent.type == "call_expression"
|
|
279
|
+
):
|
|
280
|
+
function_node = current_node.parent.child_by_field_name("function")
|
|
281
|
+
if function_node == current_node or (
|
|
282
|
+
function_node
|
|
283
|
+
and self.find_identifier_in_declarator(function_node)
|
|
284
|
+
== current_node
|
|
285
|
+
):
|
|
286
|
+
method_map.append(index)
|
|
287
|
+
method_calls.append(index)
|
|
288
|
+
|
|
289
|
+
if (
|
|
290
|
+
current_node.parent is not None
|
|
291
|
+
and current_node.parent.type == "field_expression"
|
|
292
|
+
):
|
|
293
|
+
field_node = current_node.parent.child_by_field_name("field")
|
|
294
|
+
if field_node is not None:
|
|
295
|
+
field_index = self.index[
|
|
296
|
+
(field_node.start_point, field_node.end_point, field_node.type)
|
|
297
|
+
]
|
|
298
|
+
current_index = self.index[
|
|
299
|
+
(
|
|
300
|
+
current_node.start_point,
|
|
301
|
+
current_node.end_point,
|
|
302
|
+
current_node.type,
|
|
303
|
+
)
|
|
304
|
+
]
|
|
305
|
+
if field_index == current_index:
|
|
306
|
+
method_map.append(current_index)
|
|
307
|
+
|
|
308
|
+
while (
|
|
309
|
+
current_node.parent is not None
|
|
310
|
+
and current_node.parent.type == "field_expression"
|
|
311
|
+
):
|
|
312
|
+
current_node = current_node.parent
|
|
313
|
+
|
|
314
|
+
if (
|
|
315
|
+
current_node.parent is not None
|
|
316
|
+
and current_node.parent.type == "call_expression"
|
|
317
|
+
):
|
|
318
|
+
method_map.append(index)
|
|
319
|
+
method_calls.append(index)
|
|
320
|
+
label[index] = current_node.text.decode("UTF-8")
|
|
321
|
+
|
|
322
|
+
if (
|
|
323
|
+
current_node.parent is not None
|
|
324
|
+
and current_node.parent.type == "qualified_identifier"
|
|
325
|
+
):
|
|
326
|
+
if (
|
|
327
|
+
current_node.parent.children
|
|
328
|
+
and current_node.parent.children[-1] == current_node
|
|
329
|
+
):
|
|
330
|
+
label[index] = current_node.parent.text.decode("UTF-8")
|
|
331
|
+
|
|
332
|
+
if (
|
|
333
|
+
current_node.parent is not None
|
|
334
|
+
and current_node.parent.type == "template_function"
|
|
335
|
+
):
|
|
336
|
+
method_map.append(index)
|
|
337
|
+
if (
|
|
338
|
+
current_node.next_named_sibling is not None
|
|
339
|
+
and current_node.next_named_sibling.type == "template_argument_list"
|
|
340
|
+
):
|
|
341
|
+
method_calls.append(index)
|
|
342
|
+
|
|
343
|
+
if self.check_declaration(current_node):
|
|
344
|
+
variable_name = label[index]
|
|
345
|
+
declaration[index] = variable_name
|
|
346
|
+
|
|
347
|
+
variable_type = self.get_type(current_node.parent)
|
|
348
|
+
if variable_type is not None:
|
|
349
|
+
symbol_table["data_type"][index] = variable_type
|
|
350
|
+
else:
|
|
351
|
+
current_scope = symbol_table["scope_map"][index]
|
|
352
|
+
|
|
353
|
+
if (
|
|
354
|
+
current_node.parent is not None
|
|
355
|
+
and current_node.parent.type == "field_expression"
|
|
356
|
+
):
|
|
357
|
+
field_variable = current_node.parent.children[-1]
|
|
358
|
+
field_variable_name = field_variable.text.decode("utf-8")
|
|
359
|
+
|
|
360
|
+
for ind, var in declaration.items():
|
|
361
|
+
if var == field_variable_name:
|
|
362
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
363
|
+
if self.scope_check(parent_scope, current_scope):
|
|
364
|
+
declaration_map[index] = ind
|
|
365
|
+
break
|
|
366
|
+
elif (
|
|
367
|
+
current_node.parent is not None
|
|
368
|
+
and current_node.parent.type == "qualified_identifier"
|
|
369
|
+
):
|
|
370
|
+
qualified_name = current_node.parent.text.decode("utf-8")
|
|
371
|
+
name_matches = []
|
|
372
|
+
for ind, var in declaration.items():
|
|
373
|
+
if var == qualified_name or var == label[index]:
|
|
374
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
375
|
+
if self.scope_check(parent_scope, current_scope):
|
|
376
|
+
name_matches.append((ind, var))
|
|
377
|
+
|
|
378
|
+
if name_matches:
|
|
379
|
+
closest_index = self.longest_scope_match(
|
|
380
|
+
name_matches, symbol_table
|
|
381
|
+
)
|
|
382
|
+
declaration_map[index] = closest_index
|
|
383
|
+
else:
|
|
384
|
+
name_matches = []
|
|
385
|
+
for ind, var in declaration.items():
|
|
386
|
+
if var == label[index]:
|
|
387
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
388
|
+
if self.scope_check(parent_scope, current_scope):
|
|
389
|
+
name_matches.append((ind, var))
|
|
390
|
+
|
|
391
|
+
if name_matches:
|
|
392
|
+
closest_index = self.longest_scope_match(
|
|
393
|
+
name_matches, symbol_table
|
|
394
|
+
)
|
|
395
|
+
declaration_map[index] = closest_index
|
|
396
|
+
|
|
397
|
+
else:
|
|
398
|
+
for child in root_node.children:
|
|
399
|
+
self.create_all_tokens(
|
|
400
|
+
src_code,
|
|
401
|
+
child,
|
|
402
|
+
all_tokens,
|
|
403
|
+
label,
|
|
404
|
+
method_map,
|
|
405
|
+
method_calls,
|
|
406
|
+
start_line,
|
|
407
|
+
declaration,
|
|
408
|
+
declaration_map,
|
|
409
|
+
symbol_table,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if root_node.is_named and root_node.type in block_types:
|
|
413
|
+
symbol_table["scope_stack"].pop(-1)
|
|
414
|
+
|
|
415
|
+
return (
|
|
416
|
+
all_tokens,
|
|
417
|
+
label,
|
|
418
|
+
method_map,
|
|
419
|
+
method_calls,
|
|
420
|
+
start_line,
|
|
421
|
+
declaration,
|
|
422
|
+
declaration_map,
|
|
423
|
+
symbol_table,
|
|
424
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
3
|
+
from tree_sitter import Parser
|
|
4
|
+
|
|
5
|
+
from lambda_graphs import get_language_map
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_commit_hash(directory):
|
|
9
|
+
try:
|
|
10
|
+
result = subprocess.run(
|
|
11
|
+
["git", "rev-parse", "HEAD"], cwd=directory, capture_output=True, text=True
|
|
12
|
+
)
|
|
13
|
+
if result.returncode == 0:
|
|
14
|
+
commit_hash = result.stdout.strip()
|
|
15
|
+
return commit_hash
|
|
16
|
+
return None
|
|
17
|
+
except FileNotFoundError:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CustomParser:
|
|
22
|
+
"""Custom parser for the src_language"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, src_language, src_code):
|
|
25
|
+
"""Initialize the parser with the language.
|
|
26
|
+
Language options are: c, cpp"""
|
|
27
|
+
|
|
28
|
+
self.src_language = src_language
|
|
29
|
+
self.src_code = src_code
|
|
30
|
+
self.index = {}
|
|
31
|
+
self.language_map = get_language_map()
|
|
32
|
+
self.root_node, self.tree = self.parse()
|
|
33
|
+
self.all_tokens = []
|
|
34
|
+
self.label = {}
|
|
35
|
+
self.method_map = []
|
|
36
|
+
self.method_calls = []
|
|
37
|
+
self.start_line = {}
|
|
38
|
+
self.declaration = {}
|
|
39
|
+
self.declaration_map = {}
|
|
40
|
+
self.symbol_table = {
|
|
41
|
+
"scope_stack": [0],
|
|
42
|
+
"scope_map": {},
|
|
43
|
+
"scope_id": 0,
|
|
44
|
+
"data_type": {},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
def create_AST_id(self, root_node, AST_index, AST_id):
|
|
48
|
+
"""Create an id for each node in the AST. This AST id is maintained and used across all code views so that
|
|
49
|
+
it is possible to easily combine graphs"""
|
|
50
|
+
if root_node.is_named:
|
|
51
|
+
current_node_id = AST_id[0]
|
|
52
|
+
AST_id[0] += 1
|
|
53
|
+
AST_index[(root_node.start_point, root_node.end_point, root_node.type)] = (
|
|
54
|
+
current_node_id
|
|
55
|
+
)
|
|
56
|
+
for child in root_node.children:
|
|
57
|
+
if child.is_named:
|
|
58
|
+
self.create_AST_id(child, AST_index, AST_id)
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
def parse(self):
|
|
62
|
+
parser = Parser(self.language_map[self.src_language])
|
|
63
|
+
tree = parser.parse(bytes(self.src_code, "utf8"))
|
|
64
|
+
self.root_node = tree.root_node
|
|
65
|
+
self.create_AST_id(self.root_node, self.index, [5])
|
|
66
|
+
return self.root_node, tree
|