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.
Files changed (45) hide show
  1. lambda_graphs/__init__.py +18 -0
  2. lambda_graphs/__main__.py +7 -0
  3. lambda_graphs/cli.py +183 -0
  4. lambda_graphs/codeviews/AST/AST.py +120 -0
  5. lambda_graphs/codeviews/AST/AST_driver.py +37 -0
  6. lambda_graphs/codeviews/AST/__init__.py +0 -0
  7. lambda_graphs/codeviews/CFG/CFG.py +42 -0
  8. lambda_graphs/codeviews/CFG/CFG_c.py +1182 -0
  9. lambda_graphs/codeviews/CFG/CFG_cpp.py +5604 -0
  10. lambda_graphs/codeviews/CFG/CFG_driver.py +45 -0
  11. lambda_graphs/codeviews/CFG/CFG_java.py +1722 -0
  12. lambda_graphs/codeviews/CFG/__init__.py +0 -0
  13. lambda_graphs/codeviews/CST/CST_driver.py +70 -0
  14. lambda_graphs/codeviews/CST/__init__.py +0 -0
  15. lambda_graphs/codeviews/DFG/DFG_driver.py +42 -0
  16. lambda_graphs/codeviews/DFG/__init__.py +0 -0
  17. lambda_graphs/codeviews/SDFG/SDFG.py +135 -0
  18. lambda_graphs/codeviews/SDFG/SDFG_c.py +2041 -0
  19. lambda_graphs/codeviews/SDFG/SDFG_cpp.py +4030 -0
  20. lambda_graphs/codeviews/SDFG/SDFG_java.py +1618 -0
  21. lambda_graphs/codeviews/SDFG/__init__.py +0 -0
  22. lambda_graphs/codeviews/__init__.py +0 -0
  23. lambda_graphs/codeviews/combined_graph/__init__.py +0 -0
  24. lambda_graphs/codeviews/combined_graph/combined_driver.py +163 -0
  25. lambda_graphs/tree_parser/__init__.py +0 -0
  26. lambda_graphs/tree_parser/c_parser.py +565 -0
  27. lambda_graphs/tree_parser/cpp_parser.py +424 -0
  28. lambda_graphs/tree_parser/custom_parser.py +66 -0
  29. lambda_graphs/tree_parser/java_parser.py +254 -0
  30. lambda_graphs/tree_parser/parser_driver.py +54 -0
  31. lambda_graphs/utils/DFG_utils.py +44 -0
  32. lambda_graphs/utils/__init__.py +0 -0
  33. lambda_graphs/utils/c_nodes.py +431 -0
  34. lambda_graphs/utils/cpp_nodes.py +1331 -0
  35. lambda_graphs/utils/java_nodes.py +756 -0
  36. lambda_graphs/utils/multi_file_merger.py +444 -0
  37. lambda_graphs/utils/postprocessor.py +83 -0
  38. lambda_graphs/utils/preprocessor.py +68 -0
  39. lambda_graphs/utils/src_parser.py +23 -0
  40. lambda_graphs-0.1.4.dist-info/METADATA +380 -0
  41. lambda_graphs-0.1.4.dist-info/RECORD +45 -0
  42. lambda_graphs-0.1.4.dist-info/WHEEL +5 -0
  43. lambda_graphs-0.1.4.dist-info/entry_points.txt +2 -0
  44. lambda_graphs-0.1.4.dist-info/licenses/LICENSE +21 -0
  45. lambda_graphs-0.1.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1331 @@
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
+ "for_range_loop",
10
+ "do_statement",
11
+ "break_statement",
12
+ "continue_statement",
13
+ "return_statement",
14
+ "goto_statement",
15
+ "switch_statement",
16
+ "case_statement",
17
+ "throw_statement",
18
+ "try_statement",
19
+ "function_definition",
20
+ "class_specifier",
21
+ "struct_specifier",
22
+ "using_declaration",
23
+ "alias_declaration",
24
+ "template_declaration",
25
+ "field_declaration",
26
+ "access_specifier",
27
+ "constructor_or_destructor_definition",
28
+ "operator_cast",
29
+ "lambda_expression",
30
+ "enum_specifier",
31
+ "union_specifier",
32
+ "type_definition",
33
+ "friend_declaration",
34
+ "catch_clause",
35
+ "attributed_statement",
36
+ "static_assert_declaration",
37
+ "namespace_alias_definition",
38
+ "preproc_include",
39
+ "preproc_def",
40
+ "preproc_ifdef",
41
+ "preproc_if",
42
+ "preproc_elif",
43
+ "preproc_else",
44
+ ],
45
+ "non_control_statement": [
46
+ "declaration",
47
+ "expression_statement",
48
+ "field_declaration",
49
+ "using_declaration",
50
+ "alias_declaration",
51
+ "access_specifier",
52
+ "enum_specifier",
53
+ "union_specifier",
54
+ "type_definition",
55
+ "friend_declaration",
56
+ "static_assert_declaration",
57
+ "namespace_alias_definition",
58
+ "attributed_statement",
59
+ ],
60
+ "control_statement": [
61
+ "if_statement",
62
+ "while_statement",
63
+ "for_statement",
64
+ "for_range_loop",
65
+ "do_statement",
66
+ "break_statement",
67
+ "continue_statement",
68
+ "return_statement",
69
+ "goto_statement",
70
+ "switch_statement",
71
+ "try_statement",
72
+ "throw_statement",
73
+ ],
74
+ "loop_control_statement": [
75
+ "while_statement",
76
+ "for_statement",
77
+ "for_range_loop",
78
+ ],
79
+ "not_implemented": [],
80
+ "inner_node_type": [
81
+ "declaration",
82
+ "expression_statement",
83
+ ],
84
+ "outer_node_type": ["for_statement", "for_range_loop"],
85
+ "statement_holders": [
86
+ "compound_statement",
87
+ "case_statement",
88
+ "function_definition",
89
+ "class_specifier",
90
+ "struct_specifier",
91
+ "namespace_definition",
92
+ "translation_unit",
93
+ ],
94
+ "definition_types": [
95
+ "function_definition",
96
+ "class_specifier",
97
+ "struct_specifier",
98
+ "field_declaration",
99
+ "namespace_definition",
100
+ "template_declaration",
101
+ "enum_specifier",
102
+ "union_specifier",
103
+ "type_definition",
104
+ ],
105
+ }
106
+
107
+ method_return_types = [
108
+ "primitive_type",
109
+ "type_identifier",
110
+ "template_type",
111
+ "qualified_identifier",
112
+ "sized_type_specifier",
113
+ "auto",
114
+ "decltype",
115
+ ]
116
+
117
+
118
+ def get_child_of_type(node, type_list):
119
+ """Get first child of node matching any type in type_list"""
120
+ out = list(filter(lambda x: x.type in type_list, node.children))
121
+ if len(out) > 0:
122
+ return out[0]
123
+ else:
124
+ return None
125
+
126
+
127
+ def return_switch_child(node):
128
+ bfs_queue = []
129
+ for child in node.children:
130
+ bfs_queue.append(child)
131
+ while bfs_queue != []:
132
+ top = bfs_queue.pop(0)
133
+ if top.type == "switch_statement":
134
+ return top
135
+ if top.type in statement_types["node_list_type"]:
136
+ return None
137
+ for child in top.children:
138
+ bfs_queue.append(child)
139
+ return None
140
+
141
+
142
+ def return_switch_parent(node, non_control_statement):
143
+ while node.parent is not None and (
144
+ node.parent.type != "class_specifier"
145
+ and node.parent.type != "compound_statement"
146
+ ):
147
+ if node.parent.type == "compound_statement" and node.type == "switch_statement":
148
+ return node
149
+ if node.parent.type in non_control_statement:
150
+ return node.parent
151
+ node = node.parent
152
+ return None
153
+
154
+
155
+ def return_switch_parent_statement(node, non_control_statement):
156
+ while node.parent is not None and (
157
+ node.parent.type != "class_specifier"
158
+ and node.parent.type != "compound_statement"
159
+ ):
160
+ if node.parent.type in non_control_statement:
161
+ return node.parent
162
+ node = node.parent
163
+ return None
164
+
165
+
166
+ def has_inner_definition(node):
167
+ if node.type in ["struct_specifier", "class_specifier", "union_specifier"]:
168
+ has_body = any(
169
+ child.type == "field_declaration_list" for child in node.named_children
170
+ )
171
+ if has_body:
172
+ return True
173
+ for child in node.children:
174
+ if has_inner_definition(child):
175
+ return True
176
+ return False
177
+
178
+ if node.type in statement_types["definition_types"]:
179
+ return True
180
+
181
+ for child in node.children:
182
+ if has_inner_definition(child):
183
+ return True
184
+ return False
185
+
186
+
187
+ def is_function_declaration(node):
188
+ if node.type != "declaration":
189
+ return False
190
+
191
+ has_function_declarator = False
192
+ has_body = False
193
+
194
+ for child in node.children:
195
+ if child.type == "function_declarator":
196
+ has_function_declarator = True
197
+ if child.type == "compound_statement":
198
+ has_body = True
199
+
200
+ return has_function_declarator and not has_body
201
+
202
+
203
+ def find_function_definition(node):
204
+ while node.parent is not None:
205
+ if node.parent.type == "function_definition":
206
+ return node.parent
207
+ node = node.parent
208
+ return None
209
+
210
+
211
+ def is_virtual_function(node):
212
+ if node.type not in ["function_definition", "field_declaration"]:
213
+ return False
214
+
215
+ for child in node.children:
216
+ if child.type == "virtual":
217
+ return True
218
+ return False
219
+
220
+
221
+ def is_pure_virtual_function(node):
222
+ if not is_virtual_function(node):
223
+ return False
224
+
225
+ has_equals = False
226
+ for child in node.children:
227
+ if child.type == "=" or child.text == b"=":
228
+ has_equals = True
229
+ if has_equals and child.type == "number_literal" and child.text == b"0":
230
+ return True
231
+ return False
232
+
233
+
234
+ def has_field_initializer_list(node):
235
+ if node.type != "function_definition":
236
+ return False
237
+
238
+ for child in node.children:
239
+ if child.type == "field_initializer_list":
240
+ return True
241
+ return False
242
+
243
+
244
+ def is_deleted_or_defaulted(node):
245
+ if node.type not in ["function_definition", "field_declaration"]:
246
+ return None
247
+
248
+ for child in node.children:
249
+ if child.type == "default_method_clause":
250
+ return "default"
251
+ if child.type == "delete_method_clause":
252
+ return "delete"
253
+ return None
254
+
255
+
256
+ def is_operator_overload(node):
257
+ if node.type != "function_definition":
258
+ return False
259
+
260
+ declarator = node.child_by_field_name("declarator")
261
+ if declarator:
262
+ for child in declarator.children:
263
+ if child.type == "operator_name":
264
+ return True
265
+ return False
266
+
267
+
268
+ def is_constexpr_function(node):
269
+ if node.type not in ["function_definition", "field_declaration"]:
270
+ return False
271
+
272
+ for child in node.children:
273
+ if child.type == "constexpr":
274
+ return True
275
+ return False
276
+
277
+
278
+ def is_inline_function(node):
279
+ if node.type not in ["function_definition", "field_declaration"]:
280
+ return False
281
+
282
+ for child in node.children:
283
+ if child.type == "inline":
284
+ return True
285
+ return False
286
+
287
+
288
+ def has_noexcept_specifier(node):
289
+ if node.type not in ["function_definition", "field_declaration"]:
290
+ return False
291
+
292
+ for child in node.children:
293
+ if child.type == "noexcept":
294
+ return True
295
+ return False
296
+
297
+
298
+ def get_attributes(node):
299
+ attributes = []
300
+ for child in node.children:
301
+ if child.type == "attribute_specifier":
302
+ for attr_child in child.children:
303
+ if attr_child.type == "attribute":
304
+ for identifier in attr_child.children:
305
+ if identifier.type == "identifier":
306
+ attributes.append(identifier.text.decode("utf-8"))
307
+ return attributes
308
+
309
+
310
+ def has_auto_type(node):
311
+ if node.type not in ["declaration", "parameter_declaration"]:
312
+ return False
313
+
314
+ for child in node.children:
315
+ if child.type == "auto":
316
+ return True
317
+ if child.type in ["init_declarator", "parameter_declarator"]:
318
+ for subchild in child.children:
319
+ if subchild.type == "auto":
320
+ return True
321
+ return False
322
+
323
+
324
+ def is_rvalue_reference(node):
325
+ if node.type not in ["declaration", "parameter_declaration", "field_declaration"]:
326
+ return False
327
+
328
+ for child in node.children:
329
+ if child.type == "rvalue_reference_declarator":
330
+ return True
331
+ if hasattr(child, "children"):
332
+ for subchild in child.children:
333
+ if subchild.type == "rvalue_reference_declarator":
334
+ return True
335
+ return False
336
+
337
+
338
+ def is_template_specialization(node):
339
+ if node.type != "template_declaration":
340
+ return False
341
+
342
+ for child in node.children:
343
+ if child.type == "template_parameter_list":
344
+ named_children = [c for c in child.children if c.is_named]
345
+ if len(named_children) == 0:
346
+ return True
347
+ return False
348
+
349
+
350
+ def get_signature(node):
351
+ signature = []
352
+ parameter_list = node.child_by_field_name("parameters")
353
+ if parameter_list is None:
354
+ return tuple(signature)
355
+
356
+ def count_array_dimensions(array_node):
357
+ count = 0
358
+ if array_node.type == "array_declarator":
359
+ count = 1
360
+ for subchild in array_node.children:
361
+ if subchild.type == "array_declarator":
362
+ count += count_array_dimensions(subchild)
363
+ return count
364
+
365
+ for param in parameter_list.children:
366
+ if param.type in ["parameter_declaration", "optional_parameter_declaration"]:
367
+ base_type = None
368
+ for child in param.children:
369
+ if child.type in [
370
+ "primitive_type",
371
+ "type_identifier",
372
+ "template_type",
373
+ "qualified_identifier",
374
+ "sized_type_specifier",
375
+ ]:
376
+ base_type = child.text.decode("utf-8")
377
+ break
378
+
379
+ if base_type:
380
+ declarator = param.child_by_field_name("declarator")
381
+ if declarator:
382
+ if declarator.type == "reference_declarator":
383
+ declarator_text = declarator.text.decode("utf-8")
384
+ if declarator_text.startswith("&&"):
385
+ signature.append(base_type + "&&")
386
+ else:
387
+ signature.append(base_type + "&")
388
+ elif declarator.type == "pointer_declarator":
389
+ signature.append(base_type + "*")
390
+ elif declarator.type == "array_declarator":
391
+ pointer_count = count_array_dimensions(declarator)
392
+ signature.append(base_type + "*" * pointer_count)
393
+ else:
394
+ signature.append(base_type)
395
+ else:
396
+ signature.append(base_type)
397
+ elif param.type == "...":
398
+ signature.append("...")
399
+
400
+ return tuple(signature)
401
+
402
+
403
+ def get_lambda_body(node):
404
+ bfs_queue = []
405
+ bfs_queue.append(node)
406
+ while bfs_queue != []:
407
+ top = bfs_queue.pop(0)
408
+ if top.type == "lambda_expression":
409
+ return top
410
+ for child in top.children:
411
+ bfs_queue.append(child)
412
+ return None
413
+
414
+
415
+ def get_all_lambda_body(node):
416
+ bfs_queue = []
417
+ output = []
418
+ bfs_queue.append(node)
419
+ while bfs_queue != []:
420
+ top = bfs_queue.pop(0)
421
+ if top.type == "lambda_expression":
422
+ output.append(top)
423
+ for child in top.children:
424
+ if (
425
+ child.type == "lambda_expression"
426
+ or child.type not in statement_types["node_list_type"]
427
+ ):
428
+ bfs_queue.append(child)
429
+ return output
430
+
431
+
432
+ def check_lambda(node):
433
+ if get_lambda_body(node) is None:
434
+ return False
435
+ else:
436
+ initial_node = node
437
+ lambda_node = get_lambda_body(node)
438
+ parent_node = lambda_node.parent
439
+ while parent_node is not None:
440
+ if parent_node.type in statement_types["node_list_type"]:
441
+ if parent_node == initial_node:
442
+ return True
443
+ else:
444
+ return False
445
+ parent_node = parent_node.parent
446
+
447
+
448
+ def get_class_name(node, index):
449
+ """Returns the class name or namespace when a function definition or method is passed to it.
450
+
451
+ For namespaces, builds the fully qualified name (e.g., "Outer::Inner").
452
+ Returns tuple: (index, [name]) where name can be class, struct, or namespace.
453
+ """
454
+ type_identifiers = ["type_identifier", "template_type", "qualified_identifier"]
455
+
456
+ namespace_parts = []
457
+ temp_node = node
458
+ while temp_node is not None:
459
+ if temp_node.type == "namespace_definition":
460
+ namespace_name_node = temp_node.child_by_field_name("name")
461
+ if namespace_name_node:
462
+ namespace_name = namespace_name_node.text.decode("UTF-8")
463
+ namespace_parts.insert(0, namespace_name)
464
+ else:
465
+ pass
466
+ temp_node = temp_node.parent
467
+
468
+ if namespace_parts:
469
+ qualified_namespace = "::".join(namespace_parts)
470
+ temp_node = node
471
+ while temp_node is not None:
472
+ if temp_node.type == "namespace_definition":
473
+ namespace_index = index.get(
474
+ (temp_node.start_point, temp_node.end_point, temp_node.type)
475
+ )
476
+ if namespace_index is not None:
477
+ return namespace_index, [qualified_namespace]
478
+ temp_node = temp_node.parent
479
+
480
+ while node is not None:
481
+ if (
482
+ node.type == "field_declaration_list"
483
+ and node.parent.type == "class_specifier"
484
+ ):
485
+ node = node.parent
486
+ class_index = index[(node.start_point, node.end_point, node.type)]
487
+ class_name_node = get_child_of_type(node, ["type_identifier"])
488
+ if class_name_node:
489
+ class_name = [class_name_node.text.decode("UTF-8")]
490
+ else:
491
+ class_name = ["anonymous_class"]
492
+
493
+ base_list = node.child_by_field_name("base_class_clause")
494
+ if base_list is not None:
495
+ for child in base_list.children:
496
+ if child.type in type_identifiers:
497
+ class_name.append(child.text.decode("UTF-8"))
498
+
499
+ return class_index, class_name
500
+
501
+ elif (
502
+ node.type == "field_declaration_list"
503
+ and node.parent.type == "struct_specifier"
504
+ ):
505
+ node = node.parent
506
+ class_index = index[(node.start_point, node.end_point, node.type)]
507
+ class_name_node = get_child_of_type(node, ["type_identifier"])
508
+ if class_name_node:
509
+ class_name = [class_name_node.text.decode("UTF-8")]
510
+ else:
511
+ class_name = ["anonymous_struct"]
512
+
513
+ return class_index, class_name
514
+
515
+ node = node.parent
516
+ return None
517
+
518
+
519
+ def evaluate_preprocessor_condition(condition_text, macro_definitions):
520
+ """
521
+ Evaluate a preprocessor condition based on defined macros.
522
+ Returns True if the condition is satisfied, False otherwise, None if cannot evaluate.
523
+
524
+ Supports:
525
+ - #ifdef MACRO
526
+ - #ifndef MACRO
527
+ - #if MACRO == VALUE
528
+ - #if defined(MACRO)
529
+ - Simple comparisons and logic
530
+ """
531
+ import re
532
+
533
+ if not any(
534
+ op in condition_text for op in ["==", "!=", ">", "<", "&&", "||", "defined"]
535
+ ):
536
+ identifier = condition_text.strip()
537
+ return identifier in macro_definitions
538
+
539
+ defined_pattern = r"defined\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)"
540
+ condition_text = re.sub(
541
+ defined_pattern,
542
+ lambda m: "1" if m.group(1) in macro_definitions else "0",
543
+ condition_text,
544
+ )
545
+
546
+ for macro, value in macro_definitions.items():
547
+ condition_text = re.sub(r"\b" + macro + r"\b", str(value), condition_text)
548
+
549
+ try:
550
+ if re.match(r"^[\d\s+\-*/<>=!&|()]+$", condition_text):
551
+ result = eval(condition_text)
552
+ return bool(result)
553
+ except:
554
+ pass
555
+
556
+ return None
557
+
558
+
559
+ def get_nodes(
560
+ root_node=None,
561
+ node_list={},
562
+ graph_node_list=[],
563
+ index={},
564
+ records={},
565
+ macro_definitions=None,
566
+ ):
567
+ """
568
+ Returns statement level nodes recursively from the concrete syntax tree passed to it.
569
+ Uses records to maintain required supplementary information.
570
+ node_list maintains an intermediate representation and graph_node_list returns the final list.
571
+
572
+ Args:
573
+ macro_definitions: Dictionary of defined macros {name: value} for preprocessor evaluation
574
+ """
575
+ import os
576
+
577
+ if macro_definitions is None:
578
+ macro_definitions = {}
579
+
580
+ if root_node.type == "catch_clause":
581
+ node_list[(root_node.start_point, root_node.end_point, root_node.type)] = (
582
+ root_node
583
+ )
584
+ catch_parameter = list(
585
+ filter(lambda child: child.type == "parameter_list", root_node.children)
586
+ )
587
+ if catch_parameter:
588
+ param_text = catch_parameter[0].text.decode("UTF-8")
589
+ if param_text.startswith("(") and param_text.endswith(")"):
590
+ param_text = param_text[1:-1]
591
+
592
+ if param_text.strip() == "...":
593
+ label = "catch (...)"
594
+ else:
595
+ label = "catch (" + param_text + ")"
596
+ else:
597
+ label = "catch (...)"
598
+ type_label = "catch"
599
+ graph_node_list.append(
600
+ (
601
+ index[(root_node.start_point, root_node.end_point, root_node.type)],
602
+ root_node.start_point[0],
603
+ label,
604
+ type_label,
605
+ )
606
+ )
607
+
608
+ elif (
609
+ root_node.type == "parenthesized_expression"
610
+ and root_node.parent is not None
611
+ and root_node.parent.type == "do_statement"
612
+ ):
613
+ label = "while" + root_node.text.decode("UTF-8")
614
+ type_label = "while"
615
+ node_list[(root_node.start_point, root_node.end_point, root_node.type)] = (
616
+ root_node
617
+ )
618
+ graph_node_list.append(
619
+ (
620
+ index[(root_node.start_point, root_node.end_point, root_node.type)],
621
+ root_node.start_point[0],
622
+ label,
623
+ type_label,
624
+ )
625
+ )
626
+
627
+ elif root_node.type in [
628
+ "preproc_include",
629
+ "preproc_def",
630
+ "preproc_function_def",
631
+ "preproc_call",
632
+ "preproc_if",
633
+ "preproc_ifdef",
634
+ "preproc_elif",
635
+ "preproc_else",
636
+ ]:
637
+
638
+ if root_node.type == "preproc_def":
639
+ text = root_node.text.decode("UTF-8")
640
+ parts = text.split(None, 2)
641
+ if len(parts) >= 2:
642
+ macro_name = parts[1]
643
+ macro_value = parts[2].strip() if len(parts) > 2 else "1"
644
+ macro_definitions[macro_name] = macro_value
645
+ if os.environ.get("DEBUG_PREPROC"):
646
+ print(f"[DEFINE] {macro_name} = {macro_value}")
647
+
648
+ elif root_node.type in statement_types["node_list_type"]:
649
+ if root_node.type == "field_declaration":
650
+ pass
651
+
652
+ elif root_node.type in ["struct_specifier", "class_specifier"]:
653
+ parent = root_node.parent
654
+ should_skip = False
655
+
656
+ if parent and parent.type in ["translation_unit", "declaration_list"]:
657
+ if parent.type == "declaration_list":
658
+ grandparent = parent.parent if parent else None
659
+ if grandparent and grandparent.type in [
660
+ "namespace_definition",
661
+ "translation_unit",
662
+ ]:
663
+ should_skip = True
664
+ else:
665
+ should_skip = True
666
+
667
+ elif parent and parent.type == "field_declaration_list":
668
+ should_skip = True
669
+
670
+ if should_skip:
671
+ pass
672
+ elif is_function_declaration(root_node):
673
+ pass
674
+ elif root_node.type == "template_declaration":
675
+ pass
676
+ elif root_node.type == "access_specifier":
677
+ pass
678
+ elif root_node.parent and root_node.parent.type == "attributed_statement":
679
+ pass
680
+ elif root_node.type == "lambda_expression":
681
+ parent = root_node.parent
682
+ while parent and parent.type not in statement_types["node_list_type"]:
683
+ parent = parent.parent
684
+
685
+ if parent and parent.type != "lambda_expression":
686
+ node_list[
687
+ (root_node.start_point, root_node.end_point, root_node.type)
688
+ ] = root_node
689
+ else:
690
+ node_list[
691
+ (root_node.start_point, root_node.end_point, root_node.type)
692
+ ] = root_node
693
+ label = root_node.text.decode("UTF-8")
694
+ type_label = "expression_statement"
695
+ try:
696
+ if "{" in label:
697
+ label = label.split("{")[0] + label.split("}")[-1]
698
+ else:
699
+ label = root_node.text.decode("utf-8")
700
+ except:
701
+ pass
702
+ graph_node_list.append(
703
+ (
704
+ index[
705
+ (root_node.start_point, root_node.end_point, root_node.type)
706
+ ],
707
+ root_node.start_point[0],
708
+ label,
709
+ type_label,
710
+ )
711
+ )
712
+ elif (
713
+ root_node.type in statement_types["inner_node_type"]
714
+ and root_node.parent is not None
715
+ and root_node.parent.type in statement_types["outer_node_type"]
716
+ and root_node.parent.child_by_field_name("body") != root_node
717
+ ):
718
+ pass
719
+ elif (
720
+ root_node.type in statement_types["inner_node_type"]
721
+ and return_switch_child(root_node) is not None
722
+ ):
723
+ switch_child = return_switch_child(root_node)
724
+ child_index = index[
725
+ (switch_child.start_point, switch_child.end_point, switch_child.type)
726
+ ]
727
+ current_index = index[
728
+ (root_node.start_point, root_node.end_point, root_node.type)
729
+ ]
730
+ records["switch_child_map"][current_index] = child_index
731
+ else:
732
+ node_list[(root_node.start_point, root_node.end_point, root_node.type)] = (
733
+ root_node
734
+ )
735
+ label = root_node.text.decode("UTF-8")
736
+ type_label = "expression_statement"
737
+
738
+ if (
739
+ check_lambda(root_node)
740
+ and root_node.type not in statement_types["definition_types"]
741
+ ):
742
+ raw_label = root_node.text.decode("utf-8")
743
+ label = ""
744
+ for lambda_expression in get_all_lambda_body(root_node):
745
+ split_label = raw_label.split(
746
+ lambda_expression.text.decode("utf-8"), 2
747
+ )
748
+ raw_label = split_label[0]
749
+ if len(split_label) > 1:
750
+ label = split_label[1] + label
751
+ lambda_node = (
752
+ lambda_expression.start_point,
753
+ lambda_expression.end_point,
754
+ lambda_expression.type,
755
+ )
756
+ records["lambda_map"][lambda_node] = root_node
757
+ label = raw_label + label
758
+
759
+ if root_node.type == "function_definition":
760
+ label = ""
761
+ declarator = root_node.child_by_field_name("declarator")
762
+
763
+ is_virtual = is_virtual_function(root_node)
764
+ is_pure_virtual = is_pure_virtual_function(root_node)
765
+ is_operator = is_operator_overload(root_node)
766
+ deleted_or_defaulted = is_deleted_or_defaulted(root_node)
767
+ has_initializers = has_field_initializer_list(root_node)
768
+
769
+ is_constexpr = is_constexpr_function(root_node)
770
+ is_inline = is_inline_function(root_node)
771
+ has_noexcept = has_noexcept_specifier(root_node)
772
+ attributes = get_attributes(root_node)
773
+
774
+ if declarator:
775
+ for child in root_node.children:
776
+ if child.type not in [
777
+ "compound_statement",
778
+ "function_body",
779
+ "field_initializer_list",
780
+ ]:
781
+ label = label + " " + child.text.decode("utf-8")
782
+
783
+ function_name_node = None
784
+ if declarator:
785
+ if declarator.type == "function_declarator":
786
+ operator_name_node = None
787
+ for child in declarator.children:
788
+ if child.type == "operator_name":
789
+ operator_name_node = child
790
+ break
791
+
792
+ if operator_name_node:
793
+ function_name_node = operator_name_node
794
+ else:
795
+ function_name_node = declarator.child_by_field_name(
796
+ "declarator"
797
+ )
798
+ elif (
799
+ declarator.type == "pointer_declarator"
800
+ or declarator.type == "reference_declarator"
801
+ ):
802
+ nested = declarator
803
+ while nested and nested.type in [
804
+ "pointer_declarator",
805
+ "reference_declarator",
806
+ ]:
807
+ found_nested = None
808
+ for child in nested.children:
809
+ if child.type in [
810
+ "function_declarator",
811
+ "pointer_declarator",
812
+ "reference_declarator",
813
+ ]:
814
+ found_nested = child
815
+ break
816
+ nested = found_nested
817
+
818
+ if nested and nested.type == "function_declarator":
819
+ operator_name_node = None
820
+ for child in nested.children:
821
+ if child.type == "operator_name":
822
+ operator_name_node = child
823
+ break
824
+
825
+ if operator_name_node:
826
+ function_name_node = operator_name_node
827
+ else:
828
+ function_name_node = nested.child_by_field_name(
829
+ "declarator"
830
+ )
831
+
832
+ if function_name_node:
833
+ function_name = function_name_node.text.decode("UTF-8")
834
+ else:
835
+ function_name = "unknown"
836
+
837
+ function_index = index[
838
+ (root_node.start_point, root_node.end_point, root_node.type)
839
+ ]
840
+ type_label = root_node.type
841
+
842
+ try:
843
+ sig_node = declarator
844
+ if declarator and declarator.type in [
845
+ "pointer_declarator",
846
+ "reference_declarator",
847
+ ]:
848
+ nested = declarator
849
+ while nested and nested.type in [
850
+ "pointer_declarator",
851
+ "reference_declarator",
852
+ ]:
853
+ found_nested = None
854
+ for child in nested.children:
855
+ if child.type == "function_declarator":
856
+ sig_node = child
857
+ break
858
+ elif child.type in [
859
+ "pointer_declarator",
860
+ "reference_declarator",
861
+ ]:
862
+ found_nested = child
863
+ break
864
+ if sig_node and sig_node.type == "function_declarator":
865
+ break
866
+ nested = found_nested
867
+
868
+ signature = get_signature(
869
+ sig_node
870
+ if sig_node and sig_node.type == "function_declarator"
871
+ else root_node
872
+ )
873
+ class_info = get_class_name(root_node, index)
874
+
875
+ if class_info:
876
+ class_index, class_name_list = class_info
877
+ if function_name == "main":
878
+ records["main_function"] = function_index
879
+ records["main_class"] = class_index
880
+
881
+ for class_name in class_name_list:
882
+ key = ((class_name, function_name), signature)
883
+ records["function_list"][key] = function_index
884
+
885
+ if len(signature) > 0 and signature[-1] == "...":
886
+ records["variadic_functions"][key] = True
887
+
888
+ return_type_node = root_node.child_by_field_name("type")
889
+ if return_type_node:
890
+ return_type = return_type_node.text.decode("UTF-8")
891
+ else:
892
+ return_type = "void"
893
+ records["return_type"][key] = return_type
894
+
895
+ if is_virtual or is_pure_virtual:
896
+ records["virtual_functions"][function_index] = {
897
+ "is_virtual": is_virtual,
898
+ "is_pure_virtual": is_pure_virtual,
899
+ }
900
+ if is_operator:
901
+ records["operator_overloads"][
902
+ function_index
903
+ ] = function_name
904
+ if deleted_or_defaulted:
905
+ records["special_functions"][
906
+ function_index
907
+ ] = deleted_or_defaulted
908
+ if has_initializers:
909
+ records["functions_with_initializers"][
910
+ function_index
911
+ ] = True
912
+
913
+ if is_constexpr:
914
+ records["constexpr_functions"][function_index] = True
915
+ if is_inline:
916
+ records["inline_functions"][function_index] = True
917
+ if has_noexcept:
918
+ records["noexcept_functions"][function_index] = True
919
+ if attributes:
920
+ records["attributed_functions"][
921
+ function_index
922
+ ] = attributes
923
+ else:
924
+ if function_name == "main":
925
+ records["main_function"] = function_index
926
+
927
+ records["function_list"][
928
+ ((None, function_name), signature)
929
+ ] = function_index
930
+ return_type_node = root_node.child_by_field_name("type")
931
+ if return_type_node:
932
+ return_type = return_type_node.text.decode("UTF-8")
933
+ else:
934
+ return_type = "void"
935
+ records["return_type"][
936
+ ((None, function_name), signature)
937
+ ] = return_type
938
+ except:
939
+ pass
940
+
941
+ graph_node_list.append(
942
+ (function_index, root_node.start_point[0], label, type_label)
943
+ )
944
+
945
+ elif (
946
+ root_node.type == "class_specifier"
947
+ or root_node.type == "struct_specifier"
948
+ ):
949
+ class_name_node = get_child_of_type(root_node, ["type_identifier"])
950
+ if class_name_node:
951
+ class_name = class_name_node.text.decode("UTF-8")
952
+ label = f"{root_node.type.replace('_specifier', '')} {class_name}"
953
+ else:
954
+ label = f"anonymous_{root_node.type.replace('_specifier', '')}"
955
+ class_name = label
956
+
957
+ type_label = root_node.type
958
+ class_index = index[
959
+ (root_node.start_point, root_node.end_point, root_node.type)
960
+ ]
961
+ records["class_list"][class_name] = class_index
962
+
963
+ base_list = root_node.child_by_field_name("base_class_clause")
964
+ if base_list is not None:
965
+ for child in base_list.children:
966
+ if child.type in [
967
+ "type_identifier",
968
+ "template_type",
969
+ "qualified_identifier",
970
+ ]:
971
+ parent_name = child.text.decode("UTF-8")
972
+ try:
973
+ records["extends"][class_name].append(parent_name)
974
+ except:
975
+ records["extends"][class_name] = [parent_name]
976
+
977
+ elif root_node.type == "namespace_definition":
978
+ namespace_name_node = root_node.child_by_field_name("name")
979
+ if namespace_name_node:
980
+ namespace_name = namespace_name_node.text.decode("UTF-8")
981
+ label = f"namespace {namespace_name}"
982
+ else:
983
+ label = "anonymous namespace"
984
+ type_label = "namespace_definition"
985
+
986
+ elif root_node.type == "if_statement":
987
+ condition = root_node.child_by_field_name("condition")
988
+ if condition:
989
+ label = "if(" + condition.text.decode("UTF-8") + ")"
990
+ else:
991
+ label = "if"
992
+ type_label = "if"
993
+
994
+ elif root_node.type == "for_statement":
995
+ try:
996
+ init = root_node.child_by_field_name("initializer")
997
+ init_text = init.text.decode("UTF-8") if init else ""
998
+ if init_text and not init_text.endswith(";"):
999
+ init_text = init_text + ";"
1000
+ except:
1001
+ init_text = ""
1002
+ try:
1003
+ condition = root_node.child_by_field_name("condition")
1004
+ condition_text = condition.text.decode("UTF-8") if condition else ""
1005
+ except:
1006
+ condition_text = ""
1007
+ try:
1008
+ update = root_node.child_by_field_name("update")
1009
+ update_text = update.text.decode("UTF-8") if update else ""
1010
+ except:
1011
+ update_text = ""
1012
+ label = "for(" + init_text + condition_text + ";" + update_text + ")"
1013
+ type_label = "for"
1014
+
1015
+ elif root_node.type == "for_range_loop":
1016
+ try:
1017
+ declarator = root_node.child_by_field_name("declarator")
1018
+ declarator_text = (
1019
+ declarator.text.decode("UTF-8") if declarator else ""
1020
+ )
1021
+ range_expr = root_node.child_by_field_name("right")
1022
+ range_text = range_expr.text.decode("UTF-8") if range_expr else ""
1023
+ label = f"for({declarator_text} : {range_text})"
1024
+ except:
1025
+ label = "for(range)"
1026
+ type_label = "for"
1027
+
1028
+ elif root_node.type == "while_statement":
1029
+ condition = root_node.child_by_field_name("condition")
1030
+ if condition:
1031
+ label = "while(" + condition.text.decode("UTF-8") + ")"
1032
+ else:
1033
+ label = "while"
1034
+ type_label = "while"
1035
+
1036
+ elif root_node.type == "do_statement":
1037
+ label = "do"
1038
+ type_label = "do"
1039
+
1040
+ elif root_node.type == "switch_statement":
1041
+ condition = root_node.child_by_field_name("condition")
1042
+ if condition:
1043
+ label = "switch(" + condition.text.decode("UTF-8") + ")"
1044
+ else:
1045
+ label = "switch"
1046
+ type_label = "switch"
1047
+
1048
+ elif root_node.type == "case_statement":
1049
+ value = root_node.child_by_field_name("value")
1050
+ if value:
1051
+ label = "case " + value.text.decode("UTF-8") + ":"
1052
+ else:
1053
+ label = "default:"
1054
+ type_label = "case"
1055
+
1056
+ elif root_node.type == "try_statement":
1057
+ label = "try"
1058
+ type_label = "try"
1059
+
1060
+ elif root_node.type == "labeled_statement":
1061
+ label_node = root_node.child_by_field_name("label")
1062
+ if label_node:
1063
+ label = label_node.text.decode("UTF-8") + ":"
1064
+ records["label_statement_map"][label] = (
1065
+ root_node.start_point,
1066
+ root_node.end_point,
1067
+ root_node.type,
1068
+ )
1069
+ else:
1070
+ label = "label:"
1071
+ type_label = "label"
1072
+
1073
+ elif root_node.type == "return_statement":
1074
+ if has_inner_definition(root_node):
1075
+ label = "return"
1076
+ else:
1077
+ label = root_node.text.decode("UTF-8")
1078
+ type_label = "return"
1079
+
1080
+ elif root_node.type == "enum_specifier":
1081
+ enum_name_node = get_child_of_type(root_node, ["type_identifier"])
1082
+ is_scoped = "class" in [child.type for child in root_node.children]
1083
+ if enum_name_node:
1084
+ enum_name = enum_name_node.text.decode("UTF-8")
1085
+ if is_scoped:
1086
+ label = f"enum class {enum_name}"
1087
+ else:
1088
+ label = f"enum {enum_name}"
1089
+ else:
1090
+ label = "enum (anonymous)"
1091
+ type_label = "enum"
1092
+
1093
+ enum_index = index[
1094
+ (root_node.start_point, root_node.end_point, root_node.type)
1095
+ ]
1096
+ if enum_name_node:
1097
+ records["enum_list"][enum_name] = enum_index
1098
+
1099
+ elif root_node.type == "union_specifier":
1100
+ union_name_node = get_child_of_type(root_node, ["type_identifier"])
1101
+ if union_name_node:
1102
+ union_name = union_name_node.text.decode("UTF-8")
1103
+ label = f"union {union_name}"
1104
+ else:
1105
+ label = "union (anonymous)"
1106
+ type_label = "union"
1107
+
1108
+ union_index = index[
1109
+ (root_node.start_point, root_node.end_point, root_node.type)
1110
+ ]
1111
+ if union_name_node:
1112
+ records["union_list"][union_name] = union_index
1113
+
1114
+ elif root_node.type == "type_definition":
1115
+ type_identifier_node = get_child_of_type(root_node, ["type_identifier"])
1116
+ if type_identifier_node:
1117
+ typedef_name = type_identifier_node.text.decode("UTF-8")
1118
+ label = f"typedef {typedef_name}"
1119
+ else:
1120
+ label = "typedef"
1121
+ type_label = "typedef"
1122
+
1123
+ typedef_index = index[
1124
+ (root_node.start_point, root_node.end_point, root_node.type)
1125
+ ]
1126
+ if type_identifier_node:
1127
+ records["typedef_list"][typedef_name] = typedef_index
1128
+
1129
+ elif root_node.type == "friend_declaration":
1130
+ label = (
1131
+ "friend "
1132
+ + root_node.text.decode("UTF-8").replace("friend", "").strip()
1133
+ )
1134
+ if len(label) > 80:
1135
+ label = label[:77] + "..."
1136
+ type_label = "friend"
1137
+
1138
+ elif root_node.type == "static_assert_declaration":
1139
+ label = root_node.text.decode("UTF-8")
1140
+ if len(label) > 80:
1141
+ label = label[:77] + "..."
1142
+ type_label = "static_assert"
1143
+
1144
+ elif root_node.type == "namespace_alias_definition":
1145
+ label = root_node.text.decode("UTF-8")
1146
+ if len(label) > 80:
1147
+ label = label[:77] + "..."
1148
+ type_label = "namespace_alias"
1149
+
1150
+ elif root_node.type == "using_declaration":
1151
+ label = root_node.text.decode("UTF-8")
1152
+ if len(label) > 80:
1153
+ label = label[:77] + "..."
1154
+ type_label = "using"
1155
+
1156
+ elif root_node.type == "attributed_statement":
1157
+ attributes = []
1158
+ for child in root_node.children:
1159
+ if child.type == "attribute_declaration":
1160
+ for attr_child in child.named_children:
1161
+ if attr_child.type == "attribute":
1162
+ attr_text = attr_child.text.decode("utf-8")
1163
+ attr_name = attr_text.split("(")[0].strip()
1164
+ attributes.append(attr_name)
1165
+
1166
+ label = root_node.text.decode("UTF-8")
1167
+ if len(label) > 80:
1168
+ label = label[:77] + "..."
1169
+ type_label = "expression_statement"
1170
+
1171
+ elif root_node.type == "new_expression":
1172
+ label = root_node.text.decode("UTF-8")
1173
+ if len(label) > 80:
1174
+ label = label[:77] + "..."
1175
+ type_label = "new"
1176
+
1177
+ excluded_from_graph = {
1178
+ "function_definition",
1179
+ "preproc_include",
1180
+ "preproc_def",
1181
+ "preproc_function_def",
1182
+ "preproc_call",
1183
+ "preproc_if",
1184
+ "preproc_ifdef",
1185
+ "preproc_elif",
1186
+ "preproc_else",
1187
+ "using_declaration",
1188
+ "alias_declaration",
1189
+ "namespace_alias_definition",
1190
+ }
1191
+
1192
+ if root_node.type not in excluded_from_graph:
1193
+ graph_node_list.append(
1194
+ (
1195
+ index[
1196
+ (root_node.start_point, root_node.end_point, root_node.type)
1197
+ ],
1198
+ root_node.start_point[0],
1199
+ label,
1200
+ type_label,
1201
+ )
1202
+ )
1203
+
1204
+ if root_node.type in ["preproc_ifdef", "preproc_if", "preproc_elif"]:
1205
+ condition = None
1206
+ is_ifndef = False
1207
+
1208
+ if root_node.type == "preproc_ifdef":
1209
+ for child in root_node.children:
1210
+ if child.type == "#ifndef":
1211
+ is_ifndef = True
1212
+ elif child.type == "identifier":
1213
+ condition = child.text.decode("UTF-8")
1214
+ break
1215
+ elif root_node.type == "preproc_if" or root_node.type == "preproc_elif":
1216
+ found_directive = False
1217
+ for child in root_node.children:
1218
+ if child.type in ["#if", "#elif"]:
1219
+ found_directive = True
1220
+ elif (
1221
+ found_directive
1222
+ and child.is_named
1223
+ and child.type
1224
+ not in [
1225
+ "preproc_elif",
1226
+ "preproc_else",
1227
+ "declaration",
1228
+ "expression_statement",
1229
+ ]
1230
+ ):
1231
+ condition = child.text.decode("UTF-8")
1232
+ break
1233
+
1234
+ condition_met = False
1235
+ if condition:
1236
+ result = evaluate_preprocessor_condition(condition, macro_definitions)
1237
+ if result is not None:
1238
+ condition_met = (not result) if is_ifndef else result
1239
+ if os.environ.get("DEBUG_PREPROC"):
1240
+ print(
1241
+ f"[PREPROC] {root_node.type} condition='{condition}' is_ifndef={is_ifndef} macros={macro_definitions} result={result} condition_met={condition_met}"
1242
+ )
1243
+ else:
1244
+ condition_met = True
1245
+ if os.environ.get("DEBUG_PREPROC"):
1246
+ print(
1247
+ f"[PREPROC] {root_node.type} condition='{condition}' macros={macro_definitions} CANNOT_EVALUATE, including by default"
1248
+ )
1249
+
1250
+ if root_node.type == "preproc_elif":
1251
+ if condition_met:
1252
+ for child in root_node.children:
1253
+ if child.is_named and child.type not in [
1254
+ "preproc_else",
1255
+ "preproc_elif",
1256
+ ]:
1257
+ root_node, node_list, graph_node_list, records = get_nodes(
1258
+ root_node=child,
1259
+ node_list=node_list,
1260
+ graph_node_list=graph_node_list,
1261
+ index=index,
1262
+ records=records,
1263
+ macro_definitions=macro_definitions,
1264
+ )
1265
+ elif root_node.type == "preproc_ifdef" or root_node.type == "preproc_if":
1266
+ found_elif_or_else = False
1267
+ for child in root_node.children:
1268
+ if not child.is_named:
1269
+ continue
1270
+
1271
+ if child.type in ["preproc_elif", "preproc_else"]:
1272
+ if condition_met:
1273
+ continue
1274
+ found_elif_or_else = True
1275
+
1276
+ if child.type == "preproc_elif":
1277
+ root_node, node_list, graph_node_list, records = get_nodes(
1278
+ root_node=child,
1279
+ node_list=node_list,
1280
+ graph_node_list=graph_node_list,
1281
+ index=index,
1282
+ records=records,
1283
+ macro_definitions=macro_definitions,
1284
+ )
1285
+ elif child.type == "preproc_else":
1286
+ if not condition_met:
1287
+ for else_child in child.children:
1288
+ if else_child.is_named:
1289
+ root_node, node_list, graph_node_list, records = (
1290
+ get_nodes(
1291
+ root_node=else_child,
1292
+ node_list=node_list,
1293
+ graph_node_list=graph_node_list,
1294
+ index=index,
1295
+ records=records,
1296
+ macro_definitions=macro_definitions,
1297
+ )
1298
+ )
1299
+ elif condition_met:
1300
+ root_node, node_list, graph_node_list, records = get_nodes(
1301
+ root_node=child,
1302
+ node_list=node_list,
1303
+ graph_node_list=graph_node_list,
1304
+ index=index,
1305
+ records=records,
1306
+ macro_definitions=macro_definitions,
1307
+ )
1308
+
1309
+ elif root_node.type == "preproc_else":
1310
+ pass
1311
+
1312
+ elif root_node.type in [
1313
+ "preproc_include",
1314
+ "preproc_def",
1315
+ "preproc_function_def",
1316
+ "preproc_call",
1317
+ ]:
1318
+ pass
1319
+
1320
+ else:
1321
+ for child in root_node.children:
1322
+ root_node, node_list, graph_node_list, records = get_nodes(
1323
+ root_node=child,
1324
+ node_list=node_list,
1325
+ graph_node_list=graph_node_list,
1326
+ index=index,
1327
+ records=records,
1328
+ macro_definitions=macro_definitions,
1329
+ )
1330
+
1331
+ return root_node, node_list, graph_node_list, records