autosar-calltree 0.3.0__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.
@@ -0,0 +1,314 @@
1
+ """
2
+ AUTOSAR-specific function parser.
3
+
4
+ Parses AUTOSAR macro-based function declarations like:
5
+ - FUNC(rettype, memclass) function_name(...)
6
+ - FUNC_P2VAR(rettype, ptrclass, memclass) function_name(...)
7
+ - STATIC FUNC(...) ...
8
+ """
9
+
10
+ import re
11
+ from pathlib import Path
12
+ from typing import List, Optional
13
+
14
+ from ..database.models import FunctionInfo, FunctionType, Parameter
15
+
16
+
17
+ class AutosarParser:
18
+ """Parse AUTOSAR-specific function declarations."""
19
+
20
+ # AUTOSAR function patterns
21
+ FUNC_PATTERN = re.compile(
22
+ r"(STATIC\s+)?FUNC\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)\s*\(", re.MULTILINE
23
+ )
24
+
25
+ FUNC_P2VAR_PATTERN = re.compile(
26
+ r"(STATIC\s+)?FUNC_P2VAR\(\s*([^,]+?)\s*,\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)\s*\(",
27
+ re.MULTILINE,
28
+ )
29
+
30
+ FUNC_P2CONST_PATTERN = re.compile(
31
+ r"(STATIC\s+)?FUNC_P2CONST\(\s*([^,]+?)\s*,\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)\s*\(",
32
+ re.MULTILINE,
33
+ )
34
+
35
+ # Parameter patterns
36
+ # Note: Order matters! More specific patterns (P2VAR, P2CONST) must be checked
37
+ # before less specific ones (VAR, CONST) to prevent false matches
38
+ P2VAR_PATTERN = re.compile(
39
+ r"P2VAR\(\s*([^,]+?)\s*,\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)"
40
+ )
41
+ P2CONST_PATTERN = re.compile(
42
+ r"P2CONST\(\s*([^,]+?)\s*,\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)"
43
+ )
44
+ # Use negative lookbehind to prevent matching P2VAR or P2CONST as VAR/CONST
45
+ VAR_PATTERN = re.compile(r"(?<!P2)VAR\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)")
46
+ CONST_PATTERN = re.compile(r"(?<!P2)CONST\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)\s+(\w+)")
47
+
48
+ def parse_function_declaration(
49
+ self, line: str, file_path: Path, line_number: int
50
+ ) -> Optional[FunctionInfo]:
51
+ """
52
+ Parse AUTOSAR function declaration.
53
+
54
+ Args:
55
+ line: Line of code to parse
56
+ file_path: Path to source file
57
+ line_number: Line number in file
58
+
59
+ Returns:
60
+ FunctionInfo object or None if not a function declaration
61
+ """
62
+ # Try FUNC pattern
63
+ match = self.FUNC_PATTERN.search(line)
64
+ if match:
65
+ is_static_str, return_type, memory_class, func_name = match.groups()
66
+ # Extract parameters from the line
67
+ param_start = line.find(func_name) + len(func_name)
68
+ param_string = self._extract_param_string(line, param_start)
69
+ parameters = self.parse_parameters(param_string)
70
+
71
+ return FunctionInfo(
72
+ name=func_name,
73
+ return_type=return_type.strip(),
74
+ file_path=file_path,
75
+ line_number=line_number,
76
+ is_static=bool(is_static_str),
77
+ function_type=FunctionType.AUTOSAR_FUNC,
78
+ memory_class=memory_class.strip(),
79
+ macro_type="FUNC",
80
+ parameters=parameters,
81
+ )
82
+
83
+ # Try FUNC_P2VAR pattern
84
+ match = self.FUNC_P2VAR_PATTERN.search(line)
85
+ if match:
86
+ is_static_str, return_type, ptr_class, memory_class, func_name = (
87
+ match.groups()
88
+ )
89
+ # Extract parameters from the line
90
+ param_start = line.find(func_name) + len(func_name)
91
+ param_string = self._extract_param_string(line, param_start)
92
+ parameters = self.parse_parameters(param_string)
93
+
94
+ return FunctionInfo(
95
+ name=func_name,
96
+ return_type=f"{return_type.strip()}*",
97
+ file_path=file_path,
98
+ line_number=line_number,
99
+ is_static=bool(is_static_str),
100
+ function_type=FunctionType.AUTOSAR_FUNC_P2VAR,
101
+ memory_class=memory_class.strip(),
102
+ macro_type="FUNC_P2VAR",
103
+ parameters=parameters,
104
+ )
105
+
106
+ # Try FUNC_P2CONST pattern
107
+ match = self.FUNC_P2CONST_PATTERN.search(line)
108
+ if match:
109
+ is_static_str, return_type, ptr_class, memory_class, func_name = (
110
+ match.groups()
111
+ )
112
+ # Extract parameters from the line
113
+ param_start = line.find(func_name) + len(func_name)
114
+ param_string = self._extract_param_string(line, param_start)
115
+ parameters = self.parse_parameters(param_string)
116
+
117
+ return FunctionInfo(
118
+ name=func_name,
119
+ return_type=f"const {return_type.strip()}*",
120
+ file_path=file_path,
121
+ line_number=line_number,
122
+ is_static=bool(is_static_str),
123
+ function_type=FunctionType.AUTOSAR_FUNC_P2CONST,
124
+ memory_class=memory_class.strip(),
125
+ macro_type="FUNC_P2CONST",
126
+ parameters=parameters,
127
+ )
128
+
129
+ return None
130
+
131
+ def _extract_param_string(self, line: str, start_pos: int) -> str:
132
+ """
133
+ Extract parameter string from function declaration line.
134
+
135
+ Args:
136
+ line: Function declaration line
137
+ start_pos: Position to start searching for parameters
138
+
139
+ Returns:
140
+ Parameter string (content inside parentheses)
141
+ """
142
+ # Find opening parenthesis
143
+ paren_start = line.find("(", start_pos)
144
+ if paren_start == -1:
145
+ return ""
146
+
147
+ # Find matching closing parenthesis
148
+ paren_depth = 0
149
+ param_chars = []
150
+
151
+ for char in line[paren_start:]:
152
+ param_chars.append(char)
153
+ if char == "(":
154
+ paren_depth += 1
155
+ elif char == ")":
156
+ paren_depth -= 1
157
+ if paren_depth == 0:
158
+ break
159
+
160
+ # Remove outer parentheses
161
+ param_string = "".join(param_chars)
162
+ if param_string.startswith("(") and param_string.endswith(")"):
163
+ param_string = param_string[1:-1]
164
+
165
+ return param_string.strip()
166
+
167
+ def parse_parameters(self, param_string: str) -> List[Parameter]:
168
+ """
169
+ Parse function parameters (both AUTOSAR and traditional).
170
+
171
+ Args:
172
+ param_string: Parameter list string (inside parentheses)
173
+
174
+ Returns:
175
+ List of Parameter objects
176
+ """
177
+ if not param_string or param_string.strip() in ("void", ""):
178
+ return []
179
+
180
+ parameters = []
181
+
182
+ # Split by comma, but respect nested parentheses
183
+ params = self._split_parameters(param_string)
184
+
185
+ for param in params:
186
+ param = param.strip()
187
+ if not param or param == "void":
188
+ continue
189
+
190
+ parsed_param = self._parse_single_parameter(param)
191
+ if parsed_param:
192
+ parameters.append(parsed_param)
193
+
194
+ return parameters
195
+
196
+ def _parse_single_parameter(self, param_str: str) -> Optional[Parameter]:
197
+ """Parse a single parameter."""
198
+ # Try P2VAR pattern first (more specific)
199
+ match = self.P2VAR_PATTERN.search(param_str)
200
+ if match:
201
+ param_type, ptr_class, memory_class, name = match.groups()
202
+ return Parameter(
203
+ name=name,
204
+ param_type=param_type.strip(),
205
+ is_pointer=True,
206
+ is_const=False,
207
+ memory_class=memory_class.strip(),
208
+ )
209
+
210
+ # Try P2CONST pattern (more specific)
211
+ match = self.P2CONST_PATTERN.search(param_str)
212
+ if match:
213
+ param_type, ptr_class, memory_class, name = match.groups()
214
+ return Parameter(
215
+ name=name,
216
+ param_type=param_type.strip(),
217
+ is_pointer=True,
218
+ is_const=True,
219
+ memory_class=memory_class.strip(),
220
+ )
221
+
222
+ # Try VAR pattern (less specific)
223
+ match = self.VAR_PATTERN.search(param_str)
224
+ if match:
225
+ param_type, memory_class, name = match.groups()
226
+ return Parameter(
227
+ name=name,
228
+ param_type=param_type.strip(),
229
+ is_pointer=False,
230
+ is_const=False,
231
+ memory_class=memory_class.strip(),
232
+ )
233
+
234
+ # Try CONST pattern (less specific)
235
+ match = self.CONST_PATTERN.search(param_str)
236
+ if match:
237
+ param_type, memory_class, name = match.groups()
238
+ return Parameter(
239
+ name=name,
240
+ param_type=param_type.strip(),
241
+ is_pointer=False,
242
+ is_const=True,
243
+ memory_class=memory_class.strip(),
244
+ )
245
+
246
+ # Fallback: Traditional C parameter
247
+ return self._parse_traditional_parameter(param_str)
248
+
249
+ def _parse_traditional_parameter(self, param_str: str) -> Optional[Parameter]:
250
+ """Parse traditional C parameter format."""
251
+ param_str = param_str.strip()
252
+
253
+ # Check for const
254
+ is_const = "const" in param_str
255
+ if is_const:
256
+ param_str = param_str.replace("const", "").strip()
257
+
258
+ # Check for pointer
259
+ is_pointer = "*" in param_str
260
+ if is_pointer:
261
+ param_str = param_str.replace("*", "").strip()
262
+
263
+ # Split type and name
264
+ parts = param_str.rsplit(None, 1)
265
+ if len(parts) == 2:
266
+ param_type, name = parts
267
+ return Parameter(
268
+ name=name,
269
+ param_type=param_type.strip(),
270
+ is_pointer=is_pointer,
271
+ is_const=is_const,
272
+ )
273
+ elif len(parts) == 1:
274
+ # Only type, no name (parameter name omitted)
275
+ return Parameter(
276
+ name="",
277
+ param_type=parts[0].strip(),
278
+ is_pointer=is_pointer,
279
+ is_const=is_const,
280
+ )
281
+
282
+ return None
283
+
284
+ def _split_parameters(self, param_string: str) -> List[str]:
285
+ """Split parameters by comma, respecting nested parentheses."""
286
+ parameters = []
287
+ current_param = []
288
+ paren_depth = 0
289
+
290
+ for char in param_string:
291
+ if char == "(":
292
+ paren_depth += 1
293
+ current_param.append(char)
294
+ elif char == ")":
295
+ paren_depth -= 1
296
+ current_param.append(char)
297
+ elif char == "," and paren_depth == 0:
298
+ parameters.append("".join(current_param))
299
+ current_param = []
300
+ else:
301
+ current_param.append(char)
302
+
303
+ if current_param:
304
+ parameters.append("".join(current_param))
305
+
306
+ return parameters
307
+
308
+ def is_autosar_function(self, line: str) -> bool:
309
+ """Check if line contains AUTOSAR function declaration."""
310
+ return bool(
311
+ self.FUNC_PATTERN.search(line)
312
+ or self.FUNC_P2VAR_PATTERN.search(line)
313
+ or self.FUNC_P2CONST_PATTERN.search(line)
314
+ )