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,565 @@
1
+ from ..tree_parser.custom_parser import CustomParser
2
+
3
+
4
+ class CParser(CustomParser):
5
+ def __init__(self, src_language, src_code):
6
+ super().__init__(src_language, src_code)
7
+ self.struct_definitions = {}
8
+ self.typedef_map = {}
9
+ self._parse_struct_definitions()
10
+ self._parse_typedefs()
11
+
12
+ def check_declaration(self, current_node):
13
+ """
14
+ Check if the current node is a variable declaration in C.
15
+ C declarations can be:
16
+ - init_declarator (e.g., int x = 5;)
17
+ - Direct child of declaration (e.g., int x;)
18
+ - parameter_declaration (function parameters)
19
+ - pointer_declarator (pointer variables)
20
+ """
21
+ parent_types = [
22
+ "init_declarator",
23
+ "parameter_declaration",
24
+ "pointer_declarator",
25
+ "array_declarator",
26
+ ]
27
+ current_types = ["identifier"]
28
+
29
+ if (
30
+ current_node.parent is not None
31
+ and current_node.parent.type in parent_types
32
+ and current_node.type in current_types
33
+ ):
34
+ if current_node.parent.type == "init_declarator":
35
+ if (
36
+ current_node.parent.children
37
+ and current_node.parent.children[0] == current_node
38
+ ):
39
+ return True
40
+ if current_node.parent.children[0].type == "pointer_declarator":
41
+ pointer_node = current_node.parent.children[0]
42
+ if self.find_identifier_in_declarator(pointer_node) == current_node:
43
+ return True
44
+ elif current_node.parent.type == "pointer_declarator":
45
+ if current_node.type == "identifier":
46
+ return True
47
+ elif current_node.parent.type == "array_declarator":
48
+ if (
49
+ current_node.parent.children
50
+ and current_node.parent.children[0] == current_node
51
+ ):
52
+ return True
53
+ elif current_node.parent.type == "parameter_declaration":
54
+ return True
55
+
56
+ if (
57
+ current_node.parent is not None
58
+ and current_node.parent.type == "declaration"
59
+ and current_node.type == "identifier"
60
+ ):
61
+ for i, child in enumerate(current_node.parent.children):
62
+ if child == current_node and i > 0:
63
+ prev_sibling = current_node.parent.children[i - 1]
64
+ if prev_sibling.type in [
65
+ "primitive_type",
66
+ "type_identifier",
67
+ "sized_type_specifier",
68
+ "struct_specifier",
69
+ "union_specifier",
70
+ "enum_specifier",
71
+ "storage_class_specifier",
72
+ "type_qualifier",
73
+ ]:
74
+ return True
75
+ return False
76
+
77
+ if current_node.parent is not None and current_node.parent.type == "declarator":
78
+ if (
79
+ current_node.parent.parent is not None
80
+ and current_node.parent.parent.type
81
+ in ["declaration", "parameter_declaration"]
82
+ ):
83
+ return True
84
+
85
+ if (
86
+ current_node.parent is not None
87
+ and current_node.parent.type == "function_declarator"
88
+ ):
89
+ if (
90
+ current_node.parent.children
91
+ and current_node.parent.children[0] == current_node
92
+ ):
93
+ return True
94
+
95
+ return False
96
+
97
+ def find_identifier_in_declarator(self, node):
98
+ """Recursively find the identifier within a declarator node."""
99
+ if node.type == "identifier":
100
+ return node
101
+ for child in node.children:
102
+ result = self.find_identifier_in_declarator(child)
103
+ if result is not None:
104
+ return result
105
+ return None
106
+
107
+ def get_type(self, node):
108
+ """
109
+ Given a declarator node, return the variable type of the identifier INCLUDING pointer indicators.
110
+ C type specifiers include: primitive_type, type_identifier, sized_type_specifier, etc.
111
+
112
+ This function traverses up the tree to find the declaration or parameter_declaration node,
113
+ then searches for the type specifier among its children. This handles complex nested
114
+ declarators like int **pp, int ***ppp, int (*ptr_arr)[10], etc.
115
+
116
+ Returns the full type including pointers, e.g., "char*", "int**", "uint32_t*"
117
+ """
118
+ datatypes = [
119
+ "primitive_type",
120
+ "type_identifier",
121
+ "sized_type_specifier",
122
+ "struct_specifier",
123
+ "union_specifier",
124
+ "enum_specifier",
125
+ ]
126
+
127
+ current = node
128
+ pointer_count = 0
129
+ is_array = False
130
+
131
+ while current is not None:
132
+ if current.type == "pointer_declarator":
133
+ for child in current.children:
134
+ if child.type == "*":
135
+ pointer_count += 1
136
+
137
+ if current.type == "array_declarator":
138
+ is_array = True
139
+
140
+ if current.type in ["declaration", "parameter_declaration"]:
141
+ base_type = None
142
+ for child in current.children:
143
+ if child.type in datatypes:
144
+ base_type = child.text.decode("utf-8")
145
+ break
146
+
147
+ if base_type:
148
+ if pointer_count > 0:
149
+ base_type += "*" * pointer_count
150
+ elif is_array:
151
+ base_type += "*"
152
+
153
+ return self.expand_typedef(base_type)
154
+
155
+ return None
156
+
157
+ current = current.parent
158
+
159
+ return None
160
+
161
+ def scope_check(self, parent_scope, child_scope):
162
+ """Check if parent_scope is a subset of child_scope."""
163
+ for p in parent_scope:
164
+ if p not in child_scope:
165
+ return False
166
+ return True
167
+
168
+ def longest_scope_match(self, name_matches, symbol_table):
169
+ """Given a list of name matches, return the longest scope match."""
170
+ scope_array = list(map(lambda x: symbol_table["scope_map"][x[0]], name_matches))
171
+ max_val = max(scope_array, key=lambda x: len(x))
172
+ for i in range(len(scope_array)):
173
+ if scope_array[i] == max_val:
174
+ return name_matches[i][0]
175
+
176
+ def create_all_tokens(
177
+ self,
178
+ src_code,
179
+ root_node,
180
+ all_tokens,
181
+ label,
182
+ method_map,
183
+ method_calls,
184
+ start_line,
185
+ declaration,
186
+ declaration_map,
187
+ symbol_table,
188
+ ):
189
+ """
190
+ Create tokens for C language.
191
+ Handles C-specific constructs like pointers, arrays, function calls, etc.
192
+ """
193
+ remove_list = ["function_definition", "call_expression"]
194
+
195
+ block_types = [
196
+ "compound_statement",
197
+ "if_statement",
198
+ "while_statement",
199
+ "for_statement",
200
+ "do_statement",
201
+ "switch_statement",
202
+ "case_statement",
203
+ "function_definition",
204
+ ]
205
+
206
+ if root_node.is_named and root_node.type in block_types:
207
+ symbol_table["scope_id"] = symbol_table["scope_id"] + 1
208
+ symbol_table["scope_stack"].append(symbol_table["scope_id"])
209
+
210
+ if (
211
+ root_node.is_named
212
+ and (
213
+ len(root_node.children) == 0
214
+ or root_node.type in ["string_literal", "variadic_parameter"]
215
+ )
216
+ and root_node.type != "comment"
217
+ ):
218
+ index = self.index[
219
+ (root_node.start_point, root_node.end_point, root_node.type)
220
+ ]
221
+
222
+ label[index] = root_node.text.decode("UTF-8")
223
+
224
+ start_line[index] = root_node.start_point[0]
225
+
226
+ all_tokens.append(index)
227
+
228
+ symbol_table["scope_map"][index] = symbol_table["scope_stack"].copy()
229
+
230
+ current_node = root_node
231
+
232
+ if (
233
+ current_node.parent is not None
234
+ and current_node.parent.type in remove_list
235
+ ):
236
+ method_map.append(index)
237
+ if (
238
+ current_node.next_named_sibling is not None
239
+ and current_node.next_named_sibling.type == "argument_list"
240
+ ):
241
+ method_calls.append(index)
242
+
243
+ if (
244
+ current_node.parent is not None
245
+ and current_node.parent.type == "call_expression"
246
+ ):
247
+ if (
248
+ current_node.parent.children
249
+ and current_node.parent.children[0] == current_node
250
+ ):
251
+ method_map.append(index)
252
+ method_calls.append(index)
253
+
254
+ if (
255
+ current_node.parent is not None
256
+ and current_node.parent.type == "field_expression"
257
+ ):
258
+ field_node = current_node.parent.child_by_field_name("field")
259
+ if field_node is not None:
260
+ field_index = self.index[
261
+ (field_node.start_point, field_node.end_point, field_node.type)
262
+ ]
263
+ current_index = self.index[
264
+ (
265
+ current_node.start_point,
266
+ current_node.end_point,
267
+ current_node.type,
268
+ )
269
+ ]
270
+ if field_index == current_index:
271
+ method_map.append(current_index)
272
+
273
+ while (
274
+ current_node.parent is not None
275
+ and current_node.parent.type == "field_expression"
276
+ ):
277
+ current_node = current_node.parent
278
+
279
+ if (
280
+ current_node.parent is not None
281
+ and current_node.parent.type == "call_expression"
282
+ ):
283
+ method_map.append(index)
284
+ method_calls.append(index)
285
+ label[index] = current_node.text.decode("UTF-8")
286
+
287
+ if self.check_declaration(current_node):
288
+ variable_name = label[index]
289
+ declaration[index] = variable_name
290
+
291
+ variable_type = self.get_type(current_node.parent)
292
+ if variable_type is not None:
293
+ symbol_table["data_type"][index] = variable_type
294
+ else:
295
+ current_scope = symbol_table["scope_map"][index]
296
+
297
+ if (
298
+ current_node.parent is not None
299
+ and current_node.parent.type == "field_expression"
300
+ ):
301
+ field_variable = current_node.parent.children[-1]
302
+ field_variable_name = field_variable.text.decode("utf-8")
303
+
304
+ for ind, var in declaration.items():
305
+ if var == field_variable_name:
306
+ parent_scope = symbol_table["scope_map"][ind]
307
+ if self.scope_check(parent_scope, current_scope):
308
+ declaration_map[index] = ind
309
+ break
310
+ else:
311
+ name_matches = []
312
+ for ind, var in declaration.items():
313
+ if var == label[index]:
314
+ parent_scope = symbol_table["scope_map"][ind]
315
+ if self.scope_check(parent_scope, current_scope):
316
+ name_matches.append((ind, var))
317
+
318
+ if name_matches:
319
+ closest_index = self.longest_scope_match(
320
+ name_matches, symbol_table
321
+ )
322
+ declaration_map[index] = closest_index
323
+
324
+ else:
325
+ for child in root_node.children:
326
+ self.create_all_tokens(
327
+ src_code,
328
+ child,
329
+ all_tokens,
330
+ label,
331
+ method_map,
332
+ method_calls,
333
+ start_line,
334
+ declaration,
335
+ declaration_map,
336
+ symbol_table,
337
+ )
338
+
339
+ if root_node.is_named and root_node.type in block_types:
340
+ symbol_table["scope_stack"].pop(-1)
341
+
342
+ return (
343
+ all_tokens,
344
+ label,
345
+ method_map,
346
+ method_calls,
347
+ start_line,
348
+ declaration,
349
+ declaration_map,
350
+ symbol_table,
351
+ )
352
+
353
+ def _parse_struct_definitions(self):
354
+ """
355
+ Parse all struct definitions in the code and build a mapping of
356
+ struct_name -> {field_name: field_type}
357
+
358
+ This allows us to resolve struct field types when we encounter
359
+ field_expression nodes like p.x or ptr->field.
360
+ """
361
+
362
+ def traverse_for_structs(node):
363
+ if node.type == "struct_specifier":
364
+ struct_name = None
365
+ field_list = None
366
+
367
+ for child in node.children:
368
+ if child.type == "type_identifier":
369
+ struct_name = child.text.decode("utf-8")
370
+ elif child.type == "field_declaration_list":
371
+ field_list = child
372
+
373
+ if struct_name and field_list:
374
+ fields = {}
375
+ for field_decl in field_list.children:
376
+ if field_decl.type == "field_declaration":
377
+ field_type = None
378
+ field_names = []
379
+
380
+ for fc in field_decl.children:
381
+ if fc.type in [
382
+ "primitive_type",
383
+ "type_identifier",
384
+ "sized_type_specifier",
385
+ "struct_specifier",
386
+ ]:
387
+ if fc.type == "struct_specifier":
388
+ for sc in fc.children:
389
+ if sc.type == "type_identifier":
390
+ field_type = "struct " + sc.text.decode(
391
+ "utf-8"
392
+ )
393
+ break
394
+ else:
395
+ field_type = fc.text.decode("utf-8")
396
+
397
+ elif fc.type == "field_identifier":
398
+ field_names.append(fc.text.decode("utf-8"))
399
+ elif fc.type == "pointer_declarator":
400
+ pointer_count = fc.text.decode("utf-8").count("*")
401
+ for pchild in fc.named_children:
402
+ if pchild.type == "field_identifier":
403
+ field_names.append(
404
+ pchild.text.decode("utf-8")
405
+ )
406
+ break
407
+ if field_type:
408
+ field_type += "*" * pointer_count
409
+ elif fc.type == "array_declarator":
410
+ for achild in fc.children:
411
+ if achild.type == "field_identifier":
412
+ field_names.append(
413
+ achild.text.decode("utf-8")
414
+ )
415
+ break
416
+ if field_type:
417
+ field_type += "*"
418
+
419
+ for fname in field_names:
420
+ fields[fname] = field_type if field_type else "unknown"
421
+
422
+ self.struct_definitions[struct_name] = fields
423
+
424
+ for child in node.children:
425
+ traverse_for_structs(child)
426
+
427
+ traverse_for_structs(self.root_node)
428
+
429
+ def get_struct_field_type(self, struct_name, field_name):
430
+ """
431
+ Get the type of a field in a struct.
432
+
433
+ Args:
434
+ struct_name: Name of the struct (without 'struct' keyword)
435
+ field_name: Name of the field
436
+
437
+ Returns:
438
+ Type string or "unknown" if not found
439
+ """
440
+ if struct_name.startswith("struct "):
441
+ struct_name = struct_name[7:]
442
+
443
+ if struct_name in self.struct_definitions:
444
+ return self.struct_definitions[struct_name].get(field_name, "unknown")
445
+ return "unknown"
446
+
447
+ def _parse_typedefs(self):
448
+ """
449
+ Parse all typedef declarations and build a mapping of
450
+ typedef_name -> actual_type
451
+
452
+ This allows us to expand typedef aliases when resolving types.
453
+ """
454
+
455
+ def traverse_for_typedefs(node):
456
+ if node.type == "type_definition":
457
+ children = [
458
+ c for c in node.children if c.type != ";" and c.type != "typedef"
459
+ ]
460
+
461
+ if len(children) < 2:
462
+ return
463
+
464
+ typedef_name = None
465
+ actual_type = None
466
+ pointer_count = 0
467
+
468
+ if any(c.type == "pointer_declarator" for c in children):
469
+ if children[0].type in [
470
+ "primitive_type",
471
+ "sized_type_specifier",
472
+ "type_identifier",
473
+ ]:
474
+ actual_type = children[0].text.decode("utf-8")
475
+
476
+ for child in children:
477
+ if child.type == "pointer_declarator":
478
+ pointer_count = child.text.decode("utf-8").count("*")
479
+
480
+ def find_typedef_name(node):
481
+ if node.type in ["type_identifier", "identifier"]:
482
+ return node.text.decode("utf-8")
483
+ for c in node.named_children:
484
+ result = find_typedef_name(c)
485
+ if result:
486
+ return result
487
+ return None
488
+
489
+ typedef_name = find_typedef_name(child)
490
+
491
+ elif any(c.type == "function_declarator" for c in children):
492
+ if children[0].type in ["primitive_type", "type_identifier"]:
493
+ actual_type = "function_pointer"
494
+
495
+ for child in children:
496
+ if child.type == "function_declarator":
497
+ for fc in child.children:
498
+ if fc.type == "pointer_declarator":
499
+ for pdc in fc.named_children:
500
+ if pdc.type in [
501
+ "identifier",
502
+ "type_identifier",
503
+ ]:
504
+ typedef_name = pdc.text.decode("utf-8")
505
+ break
506
+
507
+ elif any(c.type == "struct_specifier" for c in children):
508
+ for i, child in enumerate(children):
509
+ if child.type == "struct_specifier":
510
+ for sc in child.children:
511
+ if sc.type == "type_identifier":
512
+ actual_type = "struct " + sc.text.decode("utf-8")
513
+ break
514
+ if not actual_type:
515
+ actual_type = child.text.decode("utf-8")
516
+
517
+ elif (
518
+ child.type in ["type_identifier", "primitive_type"]
519
+ and i > 0
520
+ ):
521
+ typedef_name = child.text.decode("utf-8")
522
+
523
+ else:
524
+ if len(children) >= 2:
525
+ if children[0].type in [
526
+ "primitive_type",
527
+ "sized_type_specifier",
528
+ "type_identifier",
529
+ ]:
530
+ actual_type = children[0].text.decode("utf-8")
531
+
532
+ if children[-1].type in ["type_identifier", "primitive_type"]:
533
+ typedef_name = children[-1].text.decode("utf-8")
534
+
535
+ if actual_type and pointer_count > 0:
536
+ actual_type += "*" * pointer_count
537
+
538
+ if typedef_name and actual_type:
539
+ self.typedef_map[typedef_name] = actual_type
540
+
541
+ for child in node.children:
542
+ traverse_for_typedefs(child)
543
+
544
+ traverse_for_typedefs(self.root_node)
545
+
546
+ def expand_typedef(self, type_name):
547
+ """
548
+ Recursively expand a typedef to its actual type.
549
+
550
+ Args:
551
+ type_name: Type name (possibly a typedef)
552
+
553
+ Returns:
554
+ Expanded type string, or original if not a typedef
555
+ """
556
+ if type_name.endswith("*"):
557
+ base = type_name.rstrip("*")
558
+ stars = "*" * type_name.count("*")
559
+ expanded = self.expand_typedef(base.strip())
560
+ return expanded + stars
561
+
562
+ if type_name in self.typedef_map:
563
+ return self.expand_typedef(self.typedef_map[type_name])
564
+
565
+ return type_name