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,431 @@
|
|
|
1
|
+
statement_types = {
|
|
2
|
+
"node_list_type": [
|
|
3
|
+
"declaration",
|
|
4
|
+
"expression_statement",
|
|
5
|
+
"labeled_statement",
|
|
6
|
+
"if_statement",
|
|
7
|
+
"while_statement",
|
|
8
|
+
"for_statement",
|
|
9
|
+
"do_statement",
|
|
10
|
+
"break_statement",
|
|
11
|
+
"continue_statement",
|
|
12
|
+
"return_statement",
|
|
13
|
+
"switch_statement",
|
|
14
|
+
"function_definition",
|
|
15
|
+
"case_statement",
|
|
16
|
+
"goto_statement",
|
|
17
|
+
"compound_statement",
|
|
18
|
+
"preproc_include",
|
|
19
|
+
"preproc_def",
|
|
20
|
+
"preproc_function_def",
|
|
21
|
+
"preproc_call",
|
|
22
|
+
"preproc_if",
|
|
23
|
+
"preproc_ifdef",
|
|
24
|
+
"preproc_elif",
|
|
25
|
+
"preproc_else",
|
|
26
|
+
],
|
|
27
|
+
"non_control_statement": [
|
|
28
|
+
"declaration",
|
|
29
|
+
"expression_statement",
|
|
30
|
+
"preproc_include",
|
|
31
|
+
"preproc_def",
|
|
32
|
+
"preproc_function_def",
|
|
33
|
+
"preproc_call",
|
|
34
|
+
],
|
|
35
|
+
"control_statement": [
|
|
36
|
+
"if_statement",
|
|
37
|
+
"while_statement",
|
|
38
|
+
"for_statement",
|
|
39
|
+
"do_statement",
|
|
40
|
+
"break_statement",
|
|
41
|
+
"continue_statement",
|
|
42
|
+
"return_statement",
|
|
43
|
+
"switch_statement",
|
|
44
|
+
"goto_statement",
|
|
45
|
+
"case_statement",
|
|
46
|
+
"preproc_if",
|
|
47
|
+
"preproc_ifdef",
|
|
48
|
+
"preproc_elif",
|
|
49
|
+
"preproc_else",
|
|
50
|
+
],
|
|
51
|
+
"loop_control_statement": [
|
|
52
|
+
"while_statement",
|
|
53
|
+
"for_statement",
|
|
54
|
+
"do_statement",
|
|
55
|
+
],
|
|
56
|
+
"not_implemented": [],
|
|
57
|
+
"inner_node_type": [
|
|
58
|
+
"declaration",
|
|
59
|
+
"expression_statement",
|
|
60
|
+
],
|
|
61
|
+
"outer_node_type": ["for_statement"],
|
|
62
|
+
"statement_holders": [
|
|
63
|
+
"compound_statement",
|
|
64
|
+
"translation_unit",
|
|
65
|
+
"case_statement",
|
|
66
|
+
"function_definition",
|
|
67
|
+
],
|
|
68
|
+
"definition_types": [
|
|
69
|
+
"function_definition",
|
|
70
|
+
"declaration",
|
|
71
|
+
"struct_specifier",
|
|
72
|
+
"union_specifier",
|
|
73
|
+
"enum_specifier",
|
|
74
|
+
],
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function_return_types = [
|
|
78
|
+
"primitive_type",
|
|
79
|
+
"type_identifier",
|
|
80
|
+
"sized_type_specifier",
|
|
81
|
+
"struct_specifier",
|
|
82
|
+
"union_specifier",
|
|
83
|
+
"enum_specifier",
|
|
84
|
+
"pointer_declarator",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def extract_parameter_type(param_node):
|
|
89
|
+
"""
|
|
90
|
+
Extract the full type of a parameter declaration, including qualifiers and pointers.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
- const uint32_t *in_arr -> 'uint32_t*'
|
|
94
|
+
- size_t n -> 'size_t'
|
|
95
|
+
- char **argv -> 'char**'
|
|
96
|
+
- const int * const ptr -> 'int*'
|
|
97
|
+
- int arr[] -> 'int*' (array parameters decay to pointers)
|
|
98
|
+
- int arr[][10] -> 'int*' (multi-dimensional arrays decay to pointers)
|
|
99
|
+
|
|
100
|
+
Returns: string representing the parameter type
|
|
101
|
+
"""
|
|
102
|
+
if param_node.type != "parameter_declaration":
|
|
103
|
+
return "unknown"
|
|
104
|
+
|
|
105
|
+
base_type = None
|
|
106
|
+
pointer_count = 0
|
|
107
|
+
|
|
108
|
+
for child in param_node.children:
|
|
109
|
+
if child.type == "type_qualifier":
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
if child.type in [
|
|
113
|
+
"primitive_type",
|
|
114
|
+
"type_identifier",
|
|
115
|
+
"sized_type_specifier",
|
|
116
|
+
"struct_specifier",
|
|
117
|
+
"union_specifier",
|
|
118
|
+
"enum_specifier",
|
|
119
|
+
]:
|
|
120
|
+
base_type = child.text.decode("utf-8")
|
|
121
|
+
|
|
122
|
+
elif child.type == "pointer_declarator":
|
|
123
|
+
pointer_text = child.text.decode("utf-8")
|
|
124
|
+
pointer_count = pointer_text.count("*")
|
|
125
|
+
|
|
126
|
+
elif child.type == "array_declarator":
|
|
127
|
+
|
|
128
|
+
def count_array_dimensions(node):
|
|
129
|
+
count = 0
|
|
130
|
+
if node.type == "array_declarator":
|
|
131
|
+
count = 1
|
|
132
|
+
for subchild in node.children:
|
|
133
|
+
if subchild.type == "array_declarator":
|
|
134
|
+
count += count_array_dimensions(subchild)
|
|
135
|
+
return count
|
|
136
|
+
|
|
137
|
+
pointer_count = count_array_dimensions(child)
|
|
138
|
+
|
|
139
|
+
if base_type:
|
|
140
|
+
return base_type + ("*" * pointer_count)
|
|
141
|
+
|
|
142
|
+
return "unknown"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_child_of_type(node, type_list):
|
|
146
|
+
out = list(filter(lambda x: x.type in type_list, node.children))
|
|
147
|
+
if len(out) > 0:
|
|
148
|
+
return out[0]
|
|
149
|
+
else:
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def return_switch_child(node):
|
|
154
|
+
bfs_queue = []
|
|
155
|
+
for child in node.children:
|
|
156
|
+
bfs_queue.append(child)
|
|
157
|
+
while bfs_queue != []:
|
|
158
|
+
top = bfs_queue.pop(0)
|
|
159
|
+
if top.type == "switch_statement":
|
|
160
|
+
return top
|
|
161
|
+
for child in top.children:
|
|
162
|
+
bfs_queue.append(child)
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_function_signature(node):
|
|
167
|
+
"""
|
|
168
|
+
Extract function signature from function definition or declaration.
|
|
169
|
+
|
|
170
|
+
For variadic functions (e.g., int foo(int x, ...)), the signature includes
|
|
171
|
+
'...' as the last element to indicate variable arguments.
|
|
172
|
+
|
|
173
|
+
Handles complex types including pointers, const qualifiers, etc.
|
|
174
|
+
Examples:
|
|
175
|
+
- int foo(const uint32_t *arr, size_t n) -> ('uint32_t*', 'size_t')
|
|
176
|
+
- char* bar(char **argv, int argc) -> ('char**', 'int')
|
|
177
|
+
|
|
178
|
+
Returns: tuple of parameter types, e.g., ('int', 'char*') or ('int', '...')
|
|
179
|
+
"""
|
|
180
|
+
signature = []
|
|
181
|
+
for child in node.children:
|
|
182
|
+
if child.type == "function_declarator":
|
|
183
|
+
param_list = child.child_by_field_name("parameters")
|
|
184
|
+
if param_list:
|
|
185
|
+
for param in param_list.children:
|
|
186
|
+
if param.type == "parameter_declaration":
|
|
187
|
+
param_type = extract_parameter_type(param)
|
|
188
|
+
signature.append(param_type)
|
|
189
|
+
elif param.type == "variadic_parameter":
|
|
190
|
+
signature.append("...")
|
|
191
|
+
return tuple(signature)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def get_function_name(node):
|
|
195
|
+
"""Extract function name from function_definition"""
|
|
196
|
+
for child in node.children:
|
|
197
|
+
if child.type == "function_declarator":
|
|
198
|
+
for dchild in child.children:
|
|
199
|
+
if dchild.type == "identifier":
|
|
200
|
+
return dchild.text.decode("utf-8")
|
|
201
|
+
elif dchild.type == "pointer_declarator":
|
|
202
|
+
for pchild in dchild.children:
|
|
203
|
+
if pchild.type == "identifier":
|
|
204
|
+
return pchild.text.decode("utf-8")
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def is_function_declaration(node):
|
|
209
|
+
"""
|
|
210
|
+
Check if a declaration node is a function declaration (forward declaration/prototype).
|
|
211
|
+
|
|
212
|
+
Function declarations have the form: int foo(int x);
|
|
213
|
+
They contain a function_declarator child but no compound_statement (function body).
|
|
214
|
+
|
|
215
|
+
Returns True if the node is a function declaration, False otherwise.
|
|
216
|
+
"""
|
|
217
|
+
if node.type != "declaration":
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
for child in node.children:
|
|
221
|
+
if child.type == "function_declarator":
|
|
222
|
+
return True
|
|
223
|
+
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def get_nodes(root_node=None, node_list={}, graph_node_list=[], index={}, records={}):
|
|
228
|
+
"""
|
|
229
|
+
Returns statement level nodes recursively from the C AST.
|
|
230
|
+
Extracts nodes that will become CFG nodes and populates records dictionary.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
if (
|
|
234
|
+
root_node.type == "parenthesized_expression"
|
|
235
|
+
and root_node.parent is not None
|
|
236
|
+
and root_node.parent.type == "do_statement"
|
|
237
|
+
):
|
|
238
|
+
label = "while" + root_node.text.decode("UTF-8")
|
|
239
|
+
type_label = "while"
|
|
240
|
+
node_list[(root_node.start_point, root_node.end_point, root_node.type)] = (
|
|
241
|
+
root_node
|
|
242
|
+
)
|
|
243
|
+
graph_node_list.append(
|
|
244
|
+
(
|
|
245
|
+
index[(root_node.start_point, root_node.end_point, root_node.type)],
|
|
246
|
+
root_node.start_point[0],
|
|
247
|
+
label,
|
|
248
|
+
type_label,
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
elif root_node.type in statement_types["node_list_type"]:
|
|
253
|
+
if (
|
|
254
|
+
root_node.type in statement_types["inner_node_type"]
|
|
255
|
+
and root_node.parent is not None
|
|
256
|
+
and root_node.parent.type in statement_types["outer_node_type"]
|
|
257
|
+
):
|
|
258
|
+
if root_node.parent.type == "for_statement":
|
|
259
|
+
body = root_node.parent.child_by_field_name("body")
|
|
260
|
+
if body != root_node:
|
|
261
|
+
pass
|
|
262
|
+
else:
|
|
263
|
+
node_list[
|
|
264
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
265
|
+
] = root_node
|
|
266
|
+
label = root_node.text.decode("UTF-8")
|
|
267
|
+
type_label = root_node.type
|
|
268
|
+
graph_node_list.append(
|
|
269
|
+
(
|
|
270
|
+
index[
|
|
271
|
+
(
|
|
272
|
+
root_node.start_point,
|
|
273
|
+
root_node.end_point,
|
|
274
|
+
root_node.type,
|
|
275
|
+
)
|
|
276
|
+
],
|
|
277
|
+
root_node.start_point[0],
|
|
278
|
+
label,
|
|
279
|
+
type_label,
|
|
280
|
+
)
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
elif (
|
|
284
|
+
root_node.type in statement_types["inner_node_type"]
|
|
285
|
+
and return_switch_child(root_node) is not None
|
|
286
|
+
):
|
|
287
|
+
switch_child = return_switch_child(root_node)
|
|
288
|
+
child_index = index[
|
|
289
|
+
(switch_child.start_point, switch_child.end_point, switch_child.type)
|
|
290
|
+
]
|
|
291
|
+
current_index = index[
|
|
292
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
293
|
+
]
|
|
294
|
+
records["switch_child_map"][current_index] = child_index
|
|
295
|
+
|
|
296
|
+
else:
|
|
297
|
+
node_list[(root_node.start_point, root_node.end_point, root_node.type)] = (
|
|
298
|
+
root_node
|
|
299
|
+
)
|
|
300
|
+
label = root_node.text.decode("UTF-8")
|
|
301
|
+
type_label = root_node.type
|
|
302
|
+
|
|
303
|
+
if root_node.type == "function_definition":
|
|
304
|
+
label = ""
|
|
305
|
+
for child in root_node.children:
|
|
306
|
+
if child.type != "compound_statement":
|
|
307
|
+
label = label + " " + child.text.decode("utf-8")
|
|
308
|
+
|
|
309
|
+
func_name = get_function_name(root_node)
|
|
310
|
+
func_index = index[
|
|
311
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
312
|
+
]
|
|
313
|
+
type_label = "function_definition"
|
|
314
|
+
|
|
315
|
+
if func_name:
|
|
316
|
+
signature = get_function_signature(root_node)
|
|
317
|
+
records["function_list"][(func_name, signature)] = func_index
|
|
318
|
+
|
|
319
|
+
if func_name == "main":
|
|
320
|
+
records["main_function"] = func_index
|
|
321
|
+
|
|
322
|
+
return_type = None
|
|
323
|
+
for child in root_node.children:
|
|
324
|
+
if child.type in function_return_types:
|
|
325
|
+
return_type = child.text.decode("utf-8")
|
|
326
|
+
break
|
|
327
|
+
records["return_type"][(func_name, signature)] = return_type
|
|
328
|
+
|
|
329
|
+
graph_node_list.append(
|
|
330
|
+
(func_index, root_node.start_point[0], label, type_label)
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
elif root_node.type == "if_statement":
|
|
334
|
+
condition = root_node.child_by_field_name("condition")
|
|
335
|
+
if condition:
|
|
336
|
+
label = "if" + condition.text.decode("UTF-8")
|
|
337
|
+
else:
|
|
338
|
+
label = "if(...)"
|
|
339
|
+
type_label = "if"
|
|
340
|
+
|
|
341
|
+
elif root_node.type == "for_statement":
|
|
342
|
+
init = root_node.child_by_field_name("initializer")
|
|
343
|
+
init_str = init.text.decode("UTF-8") + ";" if init else ""
|
|
344
|
+
|
|
345
|
+
condition = root_node.child_by_field_name("condition")
|
|
346
|
+
cond_str = condition.text.decode("UTF-8") if condition else ""
|
|
347
|
+
|
|
348
|
+
update = root_node.child_by_field_name("update")
|
|
349
|
+
update_str = update.text.decode("UTF-8") if update else ""
|
|
350
|
+
|
|
351
|
+
label = "for(" + init_str + " " + cond_str + "; " + update_str + ")"
|
|
352
|
+
type_label = "for"
|
|
353
|
+
|
|
354
|
+
elif root_node.type == "while_statement":
|
|
355
|
+
condition = root_node.child_by_field_name("condition")
|
|
356
|
+
if condition:
|
|
357
|
+
label = "while" + condition.text.decode("UTF-8")
|
|
358
|
+
else:
|
|
359
|
+
label = "while(...)"
|
|
360
|
+
type_label = "while"
|
|
361
|
+
|
|
362
|
+
elif root_node.type == "do_statement":
|
|
363
|
+
label = "do"
|
|
364
|
+
type_label = "do"
|
|
365
|
+
|
|
366
|
+
elif root_node.type == "switch_statement":
|
|
367
|
+
condition = root_node.child_by_field_name("condition")
|
|
368
|
+
if condition:
|
|
369
|
+
label = "switch" + condition.text.decode("UTF-8")
|
|
370
|
+
else:
|
|
371
|
+
label = "switch(...)"
|
|
372
|
+
type_label = "switch"
|
|
373
|
+
|
|
374
|
+
elif root_node.type == "case_statement":
|
|
375
|
+
value_node = root_node.child_by_field_name("value")
|
|
376
|
+
if value_node:
|
|
377
|
+
label = "case " + value_node.text.decode("UTF-8") + ":"
|
|
378
|
+
else:
|
|
379
|
+
if root_node.children and root_node.children[0].type == "default":
|
|
380
|
+
label = "default:"
|
|
381
|
+
else:
|
|
382
|
+
label = "case:"
|
|
383
|
+
type_label = "case"
|
|
384
|
+
|
|
385
|
+
elif root_node.type == "labeled_statement":
|
|
386
|
+
label_node = root_node.child_by_field_name("label")
|
|
387
|
+
if label_node:
|
|
388
|
+
label_name = label_node.text.decode("UTF-8")
|
|
389
|
+
label = label_name + ":"
|
|
390
|
+
current_index = index[
|
|
391
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
392
|
+
]
|
|
393
|
+
records["label_statement_map"][label_name] = (
|
|
394
|
+
root_node.start_point,
|
|
395
|
+
root_node.end_point,
|
|
396
|
+
root_node.type,
|
|
397
|
+
)
|
|
398
|
+
type_label = "label"
|
|
399
|
+
|
|
400
|
+
elif root_node.type == "return_statement":
|
|
401
|
+
label = root_node.text.decode("UTF-8")
|
|
402
|
+
type_label = "return"
|
|
403
|
+
|
|
404
|
+
elif root_node.type == "break_statement":
|
|
405
|
+
label = "break;"
|
|
406
|
+
type_label = "break"
|
|
407
|
+
|
|
408
|
+
elif root_node.type == "continue_statement":
|
|
409
|
+
label = "continue;"
|
|
410
|
+
type_label = "continue"
|
|
411
|
+
|
|
412
|
+
elif root_node.type == "goto_statement":
|
|
413
|
+
label_node = root_node.child_by_field_name("label")
|
|
414
|
+
if label_node:
|
|
415
|
+
label = "goto " + label_node.text.decode("UTF-8") + ";"
|
|
416
|
+
else:
|
|
417
|
+
label = "goto;"
|
|
418
|
+
type_label = "goto"
|
|
419
|
+
|
|
420
|
+
if root_node.type not in ["function_definition"]:
|
|
421
|
+
node_index = index[
|
|
422
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
423
|
+
]
|
|
424
|
+
graph_node_list.append(
|
|
425
|
+
(node_index, root_node.start_point[0], label, type_label)
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
for child in root_node.children:
|
|
429
|
+
get_nodes(child, node_list, graph_node_list, index, records)
|
|
430
|
+
|
|
431
|
+
return node_list, graph_node_list, records
|