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,254 @@
|
|
|
1
|
+
from .custom_parser import CustomParser
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class JavaParser(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
|
+
# node_list_type = ['local_variable_declaration','declaration', 'expression_statement', 'labeled_statement', 'if_statement', 'while_statement', 'for_statement', 'enhanced_for_statement', 'assert_statement', 'do_statement', 'break_statement', 'continue_statement', 'return_statement', 'yield_statement', 'switch_expression', 'synchronized_statement', 'local_variable_declaration', 'throw_statement', 'try_statement', 'try_with_resources_statement', 'method_declaration','constructor_declaration', 'switch_block_statement_group', 'switch_rule', 'throw_statement', 'explicit_constructor_invocation']
|
|
11
|
+
parent_types = [
|
|
12
|
+
"variable_declarator",
|
|
13
|
+
"catch_formal_parameter",
|
|
14
|
+
"formal_parameter",
|
|
15
|
+
]
|
|
16
|
+
current_types = ["identifier"]
|
|
17
|
+
if (
|
|
18
|
+
current_node.parent is not None
|
|
19
|
+
and current_node.parent.type in parent_types
|
|
20
|
+
and current_node.type in current_types
|
|
21
|
+
):
|
|
22
|
+
if current_node.parent.type == "variable_declarator":
|
|
23
|
+
# TODO: If it is a class attribute need to maintain class_name.class_variable so that the correct datatype can be mapped
|
|
24
|
+
if (
|
|
25
|
+
len(
|
|
26
|
+
list(
|
|
27
|
+
filter(
|
|
28
|
+
lambda x: x.type == "=", current_node.parent.children
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
> 0
|
|
33
|
+
):
|
|
34
|
+
if (
|
|
35
|
+
current_node.next_sibling is not None
|
|
36
|
+
and current_node.next_sibling.type == "="
|
|
37
|
+
):
|
|
38
|
+
return True
|
|
39
|
+
else:
|
|
40
|
+
return False
|
|
41
|
+
else:
|
|
42
|
+
return True
|
|
43
|
+
return True
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
def get_type(self, node):
|
|
47
|
+
"""Given a variable declarator node, return the variable type of the identifier"""
|
|
48
|
+
datatypes = [
|
|
49
|
+
"type_identifier",
|
|
50
|
+
"integral_type",
|
|
51
|
+
"floating_point_type",
|
|
52
|
+
"void_type",
|
|
53
|
+
"boolean_type",
|
|
54
|
+
"scoped_type_identifier",
|
|
55
|
+
"generic_type",
|
|
56
|
+
]
|
|
57
|
+
if node.type == "formal_parameter":
|
|
58
|
+
return node.children[0].text.decode("utf-8")
|
|
59
|
+
|
|
60
|
+
for child in node.parent.children:
|
|
61
|
+
if child.type in datatypes:
|
|
62
|
+
return child.text.decode("utf-8")
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
def scope_check(self, parent_scope, child_scope):
|
|
66
|
+
for p in parent_scope:
|
|
67
|
+
if p not in child_scope:
|
|
68
|
+
return False
|
|
69
|
+
return True
|
|
70
|
+
|
|
71
|
+
def longest_scope_match(self, name_matches, symbol_table):
|
|
72
|
+
"""Given a list of name matches, return the longest scope match"""
|
|
73
|
+
# [(ind, var), (ind,var)]
|
|
74
|
+
scope_array = list(map(lambda x: symbol_table["scope_map"][x[0]], name_matches))
|
|
75
|
+
# scope_array.sort(key=lambda x: len(x), reverse=True)
|
|
76
|
+
# index = max(range(len(scope_array)), key=lambda x: len(x))
|
|
77
|
+
max_val = max(scope_array, key=lambda x: len(x))
|
|
78
|
+
for i in range(len(scope_array)):
|
|
79
|
+
if scope_array[i] == max_val:
|
|
80
|
+
return name_matches[i][0]
|
|
81
|
+
|
|
82
|
+
def create_all_tokens(
|
|
83
|
+
self,
|
|
84
|
+
src_code,
|
|
85
|
+
root_node,
|
|
86
|
+
all_tokens,
|
|
87
|
+
label,
|
|
88
|
+
method_map,
|
|
89
|
+
method_calls,
|
|
90
|
+
start_line,
|
|
91
|
+
declaration,
|
|
92
|
+
declaration_map,
|
|
93
|
+
symbol_table,
|
|
94
|
+
):
|
|
95
|
+
# Needs to be modifed for every language
|
|
96
|
+
remove_list = ["class_declaration", "method_declaration", "method_invocation"]
|
|
97
|
+
# node_list_type = ['local_variable_declaration', 'declaration', 'expression_statement', 'labeled_statement',
|
|
98
|
+
# 'if_statement', 'while_statement', 'for_statement', 'enhanced_for_statement',
|
|
99
|
+
# 'assert_statement', 'do_statement', 'break_statement', 'continue_statement',
|
|
100
|
+
# 'return_statement', 'yield_statement', 'synchronized_statement',
|
|
101
|
+
# 'local_variable_declaration', 'throw_statement', 'try_statement',
|
|
102
|
+
# 'try_with_resources_statement', 'method_declaration', 'constructor_declaration',
|
|
103
|
+
# 'switch_expression', 'switch_block_statement_group', 'switch_rule', 'throw_statement',
|
|
104
|
+
# 'explicit_constructor_invocation']
|
|
105
|
+
block_types = [
|
|
106
|
+
"block",
|
|
107
|
+
"if_statement",
|
|
108
|
+
"while_statement",
|
|
109
|
+
"for_statement",
|
|
110
|
+
"enhanced_for_statement",
|
|
111
|
+
"do_statement",
|
|
112
|
+
"switch_expression",
|
|
113
|
+
"switch_block_statement_group",
|
|
114
|
+
"switch_rule",
|
|
115
|
+
"throw_statement",
|
|
116
|
+
"synchronized_statement",
|
|
117
|
+
"try_statement",
|
|
118
|
+
"try_with_resources_statement",
|
|
119
|
+
"method_declaration",
|
|
120
|
+
"constructor_declaration",
|
|
121
|
+
"explicit_constructor_invocation",
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
if root_node.is_named and root_node.type in block_types:
|
|
125
|
+
"""On entering a new block, increment the scope id and push it to the scope_stack"""
|
|
126
|
+
# current_scope = symbol_table['scope_stack'][-1]
|
|
127
|
+
symbol_table["scope_id"] = symbol_table["scope_id"] + 1
|
|
128
|
+
symbol_table["scope_stack"].append(symbol_table["scope_id"])
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
root_node.is_named
|
|
132
|
+
and (len(root_node.children) == 0 or root_node.type == "string")
|
|
133
|
+
and root_node.type != "comment"
|
|
134
|
+
): # All identifiers
|
|
135
|
+
index = self.index[
|
|
136
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
137
|
+
]
|
|
138
|
+
label[index] = root_node.text.decode("UTF-8")
|
|
139
|
+
start_line[index] = root_node.start_point[0]
|
|
140
|
+
all_tokens.append(index)
|
|
141
|
+
"""Store a copy of the current scope stack in the scope map for each token. This token belongs to all the scopes in the current scope stack."""
|
|
142
|
+
|
|
143
|
+
symbol_table["scope_map"][index] = symbol_table["scope_stack"].copy()
|
|
144
|
+
|
|
145
|
+
current_node = root_node
|
|
146
|
+
if (
|
|
147
|
+
current_node.parent is not None
|
|
148
|
+
and current_node.parent.type in remove_list
|
|
149
|
+
):
|
|
150
|
+
method_map.append(index)
|
|
151
|
+
if current_node.next_named_sibling.type == "argument_list":
|
|
152
|
+
method_calls.append(index)
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
current_node.parent is not None
|
|
156
|
+
and current_node.parent.type == "field_access"
|
|
157
|
+
):
|
|
158
|
+
object_node = current_node.parent.child_by_field_name("field")
|
|
159
|
+
object_index = self.index[
|
|
160
|
+
(object_node.start_point, object_node.end_point, object_node.type)
|
|
161
|
+
]
|
|
162
|
+
current_index = self.index[
|
|
163
|
+
(
|
|
164
|
+
current_node.start_point,
|
|
165
|
+
current_node.end_point,
|
|
166
|
+
current_node.type,
|
|
167
|
+
)
|
|
168
|
+
]
|
|
169
|
+
if object_index == current_index:
|
|
170
|
+
method_map.append(current_index)
|
|
171
|
+
|
|
172
|
+
while (
|
|
173
|
+
current_node.parent is not None
|
|
174
|
+
and current_node.parent.type == "field_access"
|
|
175
|
+
):
|
|
176
|
+
current_node = current_node.parent
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
current_node.parent is not None
|
|
180
|
+
and current_node.parent.type == "method_invocation"
|
|
181
|
+
):
|
|
182
|
+
method_map.append(index)
|
|
183
|
+
label[index] = current_node.text.decode("UTF-8")
|
|
184
|
+
|
|
185
|
+
if self.check_declaration(current_node):
|
|
186
|
+
variable_name = label[index]
|
|
187
|
+
declaration[index] = variable_name
|
|
188
|
+
|
|
189
|
+
variable_type = self.get_type(current_node.parent)
|
|
190
|
+
if variable_type is not None:
|
|
191
|
+
symbol_table["data_type"][index] = variable_type
|
|
192
|
+
else:
|
|
193
|
+
current_scope = symbol_table["scope_map"][index]
|
|
194
|
+
|
|
195
|
+
if current_node.type == "field_access":
|
|
196
|
+
field_variable = current_node.children[-1]
|
|
197
|
+
# entire_variable_name = current_node.text.decode('utf-8')
|
|
198
|
+
field_variable_name = field_variable.text.decode("utf-8")
|
|
199
|
+
|
|
200
|
+
for ind, var in declaration.items():
|
|
201
|
+
if var == field_variable_name:
|
|
202
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
203
|
+
if self.scope_check(parent_scope, current_scope):
|
|
204
|
+
declaration_map[index] = ind
|
|
205
|
+
break
|
|
206
|
+
|
|
207
|
+
# Identify the leftmost - that is the reference - identify its class
|
|
208
|
+
# TODO: Handle field accesses
|
|
209
|
+
# If we can add the coorect declaration_map entry, we should be done.
|
|
210
|
+
# For this we need to identify the class to which it belongs, and the corresponding field variable
|
|
211
|
+
else:
|
|
212
|
+
name_matches = []
|
|
213
|
+
for ind, var in declaration.items():
|
|
214
|
+
if var == label[index]:
|
|
215
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
216
|
+
if self.scope_check(parent_scope, current_scope):
|
|
217
|
+
name_matches.append((ind, var))
|
|
218
|
+
for ind, var in name_matches:
|
|
219
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
220
|
+
closest_index = self.longest_scope_match(
|
|
221
|
+
name_matches, symbol_table
|
|
222
|
+
)
|
|
223
|
+
declaration_map[index] = closest_index
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
else:
|
|
227
|
+
for child in root_node.children:
|
|
228
|
+
self.create_all_tokens(
|
|
229
|
+
src_code,
|
|
230
|
+
child,
|
|
231
|
+
all_tokens,
|
|
232
|
+
label,
|
|
233
|
+
method_map,
|
|
234
|
+
method_calls,
|
|
235
|
+
start_line,
|
|
236
|
+
declaration,
|
|
237
|
+
declaration_map,
|
|
238
|
+
symbol_table,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
if root_node.is_named and root_node.type in block_types:
|
|
242
|
+
"""On exiting a block, pop the scope id from the scope_stack"""
|
|
243
|
+
symbol_table["scope_stack"].pop(-1)
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
all_tokens,
|
|
247
|
+
label,
|
|
248
|
+
method_map,
|
|
249
|
+
method_calls,
|
|
250
|
+
start_line,
|
|
251
|
+
declaration,
|
|
252
|
+
declaration_map,
|
|
253
|
+
symbol_table,
|
|
254
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from ..tree_parser.c_parser import CParser
|
|
2
|
+
from ..tree_parser.cpp_parser import CppParser
|
|
3
|
+
from ..tree_parser.java_parser import JavaParser
|
|
4
|
+
from ..utils import preprocessor
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ParserDriver:
|
|
8
|
+
"""Driver class for the parser"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, src_language, src_code):
|
|
11
|
+
"""Initialize the driver. Preprocess the code before parsing"""
|
|
12
|
+
self.src_language = src_language
|
|
13
|
+
self.src_code = self.pre_process_src_code(src_language, src_code)
|
|
14
|
+
|
|
15
|
+
self.parser_map = {
|
|
16
|
+
"c": CParser,
|
|
17
|
+
"cpp": CppParser,
|
|
18
|
+
"java": JavaParser,
|
|
19
|
+
}
|
|
20
|
+
self.parser = self.parser_map[self.src_language](
|
|
21
|
+
self.src_language, self.src_code
|
|
22
|
+
)
|
|
23
|
+
self.root_node, self.tree = self.parser.parse()
|
|
24
|
+
(
|
|
25
|
+
self.all_tokens,
|
|
26
|
+
self.label,
|
|
27
|
+
self.method_map,
|
|
28
|
+
self.method_calls,
|
|
29
|
+
self.start_line,
|
|
30
|
+
self.declaration,
|
|
31
|
+
self.declaration_map,
|
|
32
|
+
self.symbol_table,
|
|
33
|
+
) = self.create_all_tokens()
|
|
34
|
+
|
|
35
|
+
def pre_process_src_code(self, src_language, src_code):
|
|
36
|
+
"""Pre-process the source code"""
|
|
37
|
+
src_code = preprocessor.remove_empty_lines(src_code)
|
|
38
|
+
src_code = preprocessor.remove_comments(src_language, src_code)
|
|
39
|
+
return src_code
|
|
40
|
+
|
|
41
|
+
def create_all_tokens(self):
|
|
42
|
+
"""Return the variable list"""
|
|
43
|
+
return self.parser.create_all_tokens(
|
|
44
|
+
self.src_code,
|
|
45
|
+
self.parser.root_node,
|
|
46
|
+
self.parser.all_tokens,
|
|
47
|
+
self.parser.label,
|
|
48
|
+
self.parser.method_map,
|
|
49
|
+
self.parser.method_calls,
|
|
50
|
+
self.parser.start_line,
|
|
51
|
+
self.parser.declaration,
|
|
52
|
+
self.parser.declaration_map,
|
|
53
|
+
self.parser.symbol_table,
|
|
54
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
def tree_to_token_index(root_node):
|
|
2
|
+
"""Returns all tokens in the tree rooted at the given root node using index values"""
|
|
3
|
+
if (
|
|
4
|
+
len(root_node.children) == 0 or root_node.type == "string"
|
|
5
|
+
) and root_node.type != "comment":
|
|
6
|
+
return [(root_node.start_point, root_node.end_point, root_node.type)]
|
|
7
|
+
else:
|
|
8
|
+
code_tokens = []
|
|
9
|
+
for child in root_node.children:
|
|
10
|
+
code_tokens += tree_to_token_index(child)
|
|
11
|
+
return code_tokens
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def tree_to_variable_index(root_node, index_to_code):
|
|
15
|
+
"""Returns all tokens in the tree rooted at the given root node"""
|
|
16
|
+
if (
|
|
17
|
+
len(root_node.children) == 0 or root_node.type == "string"
|
|
18
|
+
) and root_node.type != "comment":
|
|
19
|
+
index = (root_node.start_point, root_node.end_point, root_node.type)
|
|
20
|
+
_, code = index_to_code[index]
|
|
21
|
+
if root_node.type != code:
|
|
22
|
+
return [(root_node.start_point, root_node.end_point, root_node.type)]
|
|
23
|
+
else:
|
|
24
|
+
return []
|
|
25
|
+
else:
|
|
26
|
+
code_tokens = []
|
|
27
|
+
for child in root_node.children:
|
|
28
|
+
code_tokens += tree_to_variable_index(child, index_to_code)
|
|
29
|
+
return code_tokens
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def index_to_code_token(index, code):
|
|
33
|
+
"""Returns code value given the indexes of a particular token"""
|
|
34
|
+
start_point = index[0]
|
|
35
|
+
end_point = index[1]
|
|
36
|
+
if start_point[0] == end_point[0]:
|
|
37
|
+
s = code[start_point[0]][start_point[1] : end_point[1]]
|
|
38
|
+
else:
|
|
39
|
+
s = ""
|
|
40
|
+
s += code[start_point[0]][start_point[1] :]
|
|
41
|
+
for i in range(start_point[0] + 1, end_point[0]):
|
|
42
|
+
s += code[i]
|
|
43
|
+
s += code[end_point[0]][: end_point[1]]
|
|
44
|
+
return s
|
|
File without changes
|