Peano
Loading...
Searching...
No Matches
Parser.py
Go to the documentation of this file.
1import ast_comments as ast, inspect
2from exahype2.api.dslhype import SyntaxTree
3import copy
4
5class Parser:
6 def _parse_constant(self, constant: ast.Constant, type_name = None):
7 if type(constant.value) is int:
8 return SyntaxTree.Integer(constant.value)
9 if type(constant.value) is str:
10 if constant.value.startswith("SolverType::") and SyntaxTree.FunctionDefinition._stateless == False:
11 return SyntaxTree.String(constant.value[len("SolverType::"):])
12 return SyntaxTree.String(constant.value)
13 if type(constant.value) is float:
14 return SyntaxTree.Float(constant.value)
15 if type(constant.value) is bool:
16 return SyntaxTree.Boolean(constant.value)
17
18 def _parse_call(self, call: ast.Call):
19 function = call.func
20 if type(function) is ast.Name:
21 if function.id == "DataBlock":
22 return self._parse_patch_constructor(call)
23 if function.id == "FaceDataBlock":
24 return self._parse_patch_constructor(call, isFace = True)
25 elif function.id == "Vector":
26 return SyntaxTree.Vector([], SyntaxTree.String(""), call.args[0].value)
27 elif function.id == "DiagonalMatrix":
29 elif function.id == "Matrix":
30 return self._parse_matrix_constructor(call)
31 elif function.id == "kroneckerProduct":
32 return self._parse_kronecker_product(call)
33 elif function.id == "Integer":
34 return SyntaxTree.Integer(0, call.args[0].value)
35 elif function.id == "Float":
36 return SyntaxTree.Float(0, call.args[0].value)
37 elif function.id == "FloatReference":
38 return SyntaxTree.Float(0.0, call.args[0].value, reference = True)
39 elif function.id == "logDataBlock":
40 return SyntaxTree.LogDataBlock(self._parse_expression(call.args[0]), self._parse_constant(call.args[1]))
41 elif function.id == "matrixVectorProduct":
42 return self._parse_matrix_vector_product(call)
43 elif function.id == "dot":
45 elif function.id == "max":
46 if len(call.args) > 1:
47 return SyntaxTree.DataBlockMax(self._parse_expression(call.args[0]), self._parse_expression(call.args[1]))
48 else:
49 return SyntaxTree.DataBlockUnaryMax(self._parse_expression(call.args[0]))
50 else:
51 return SyntaxTree.DataBlockIndex(SyntaxTree.Name(function.id), self._parse_expression(call.args[0]))
52
53 def _parse_diagonal_matrix_vector_product(self, call: ast.Call):
54 matrix = self._parse_expression(call.args[0])
55 vector = self._parse_expression(call.args[1])
56 return SyntaxTree.DataBlockConstructionFromDotProduct(SyntaxTree.Name(call.args[2].id, vector.get_type()), matrix, vector)
57
58 def _parse_matrix_vector_product(self, call: ast.Call):
59 matrix = self._parse_expression(call.args[0])
60 vector = self._parse_expression(call.args[1])
61 return SyntaxTree.DataBlockConstructionFromMatrixVectorProduct(SyntaxTree.Name(call.args[2].id, vector.get_type()), matrix, vector)
62
63 #def _parse_vector_constructor(self, constructor: ast.Call):
64 # return SyntaxTree.VectorFromDataBlock(self._parse_expression(constructor.args[0]))
65
66 def _parse_diagonal_matrix_constructor(self, constructor: ast.Call):
67 width = self._parse_expression(constructor.args[0])
68 array = self._parse_expression(constructor.args[1])
69 return SyntaxTree.DiagonalMatrix(width, array, [width])
70
71 def _parse_matrix_constructor(self, constructor: ast.Call):
72 rows = self._parse_expression(constructor.args[0])
73 cols = self._parse_expression(constructor.args[1])
74 array = self._parse_expression(constructor.args[2])
75 return SyntaxTree.Matrix([rows, cols], array, [rows])
76
77 def _parse_kronecker_product(self, product: ast.Call):
78 lhs_matrix = self._parse_expression(product.args[0])
79 rhs_matrix = self._parse_expression(product.args[1])
80
81 if type(lhs_matrix.get_type()) is SyntaxTree.TDiagonalMatrix and type(rhs_matrix.get_type()) is SyntaxTree.TDiagonalMatrix:
82 if type(lhs_matrix) is SyntaxTree.Name:
83 lhs_width = SyntaxTree.Name.variables[lhs_matrix.id]._width
84 else:
85 lhs_width = lhs_matrix._width
86
87 if type(rhs_matrix) is SyntaxTree.Name:
88 rhs_width = SyntaxTree.Name.variables[rhs_matrix.id]._width
89 else:
90 rhs_width = rhs_matrix._width
91
92 width = lhs_width * rhs_width
93 return SyntaxTree.DiagonalMatrix(width, SyntaxTree.FunctionCall("kroneckerProduct", [lhs_matrix, rhs_matrix]), [lhs_width, rhs_width])
94 else:
95 if type(lhs_matrix) is SyntaxTree.Name and type(lhs_matrix.get_type()) is SyntaxTree.TMatrix:
96 lhs_dimensions = SyntaxTree.Name.variables[lhs_matrix.id]._dimensions
97 elif type(lhs_matrix) is SyntaxTree.Name and type(lhs_matrix.get_type()) is SyntaxTree.TDiagonalMatrix:
98 lhs_dimensions = [SyntaxTree.Name.variables[lhs_matrix.id]._width, SyntaxTree.Name.variables[lhs_matrix.id]._width]
99 elif type(lhs_matrix) is SyntaxTree.TMatrix:
100 lhs_dimensions = lhs_matrix._dimensions
101 else:
102 lhs_dimensions = [lhs_matrix._width, lhs_matrix._width]
103
104 if type(rhs_matrix) is SyntaxTree.Name and type(rhs_matrix.get_type()) is SyntaxTree.TMatrix:
105 rhs_dimensions = SyntaxTree.Name.variables[rhs_matrix.id]._dimensions
106 elif type(rhs_matrix) is SyntaxTree.Name and type(rhs_matrix.get_type()) is SyntaxTree.TDiagonalMatrix:
107 rhs_dimensions = [SyntaxTree.Name.variables[rhs_matrix.id]._width, SyntaxTree.Name.variables[rhs_matrix.id]._width]
108 elif type(rhs_matrix) is SyntaxTree.TMatrix:
109 rhs_dimensions = rhs_matrix._dimensions
110 else:
111 rhs_dimensions = [rhs_matrix._width, rhs_matrix._width]
112
113 dimensions = [lhs_dimensions[0] * rhs_dimensions[0], lhs_dimensions[1] * rhs_dimensions[1]]
114 return SyntaxTree.Matrix(dimensions, SyntaxTree.FunctionCall("kroneckerProduct", [lhs_matrix, rhs_matrix]), [lhs_dimensions[0], lhs_dimensions[1]])
115
116 def _parse_patch_constructor(self, constructor: ast.Call, isFace = False):
117 iteration_range = []
118 for interval in constructor.args[0].elts:
119 iteration_range.append([self._parse_expression(interval.elts[0]), self._parse_expression(interval.elts[1])])
120
121 if type(constructor.args[1]) is ast.Call:
122 internal = SyntaxTree.String(constructor.args[1].args[0].value)
123 underlying_type = SyntaxTree.String("double")
124 if len(constructor.args) > 2:
125 underlying_type = SyntaxTree.String(constructor.args[2].value)
126 function_arguments = []
127 for arg in constructor.args[1].args[1:]:
128 function_arguments.append(self._parse_expression(arg))
129 if SyntaxTree.FunctionDefinition._stateless:
130 internal = SyntaxTree.FunctionCall("SolverType::" + constructor.args[1].args[0].value, function_arguments, True)
131 else:
132 internal = SyntaxTree.FunctionCall(constructor.args[1].args[0].value, function_arguments)
133 if not isFace:
134 return SyntaxTree.DataBlock(iteration_range, internal, True, underlying_type=underlying_type)
135 else:
136 return SyntaxTree.FaceDataBlock(iteration_range, internal, True, underlying_type=underlying_type)
137 elif type(constructor.args[1]) is ast.Constant:
138 if type(constructor.args[1].value) is str:
139 internal = SyntaxTree.String(constructor.args[1].value)
140 if not isFace:
141 if len(constructor.args) > 2:
142 return SyntaxTree.DataBlock(iteration_range, internal, False, underlying_type=SyntaxTree.String(constructor.args[2].value))
143 else:
144 return SyntaxTree.DataBlock(iteration_range, internal, False)
145 else:
146 if len(constructor.args) > 2:
147 return SyntaxTree.FaceDataBlock(iteration_range, internal, False, underlying_type=SyntaxTree.String(constructor.args[2].value))
148 else:
149 return SyntaxTree.FaceDataBlock(iteration_range, internal, False)
150 else:
151 internal = self._parse_constant(constructor.args[1])
152 if not isFace:
153 return SyntaxTree.DataBlock(iteration_range, internal, True)
154 else:
155 return SyntaxTree.FaceDataBlock(iteration_range, internal, True)
156
157 def _parse_unary_operation(self, unary_operation: ast.UnaryOp):
158 operand = self._parse_expression(unary_operation.operand)
159
160 if type(unary_operation.op) is ast.USub:
161 if type(operand.get_type()) is SyntaxTree.TDataBlock:
162 return SyntaxTree.DataBlockUnaryOperation("-", operand)
163 else:
164 return SyntaxTree.UnaryOperation("-", self._parse_expression(unary_operation.operand))
165
166
167 def _parse_binary_operation(self, binary_operation: ast.BinOp):
168 lhs = self._parse_expression(binary_operation.left)
169 rhs = self._parse_expression(binary_operation.right)
170 if type(binary_operation.op) is ast.Add:
171 operation = "+"
172 elif type(binary_operation.op) is ast.Mult:
173 operation = "*"
174 elif type(binary_operation.op) is ast.Sub:
175 operation = "-"
176 elif type(binary_operation.op) is ast.Div:
177 operation = "/"
178
179 if type(lhs.get_type()) is SyntaxTree.TDataBlock or type(rhs.get_type()) is SyntaxTree.TDataBlock:
180 return SyntaxTree.DataBlockBinaryOperation(operation, lhs, rhs)
181 #elif type(lhs.get_type()) is SyntaxTree.TMatrix or type(rhs.get_type()) is SyntaxTree.TMatrix:
182 # return SyntaxTree.DiagonalMatrixBinaryOperation(operation, lhs, rhs)
183 else:
184 return SyntaxTree.BinaryOperation(operation, lhs, rhs)
185
186 def _parse_subscript(self, subscript: ast.Subscript):
187 value = self._parse_expression(subscript.value)
188 if type(value.get_type()) is SyntaxTree.TDataBlock:
189 offset = []
190 if type(subscript.slice) is ast.Tuple:
191 for axis_offset in subscript.slice.elts:
192 if type(axis_offset) is ast.Slice:
193 offset.append([self._parse_expression(axis_offset.lower), self._parse_expression(axis_offset.upper)])
194 else:
195 offset.append([self._parse_expression(axis_offset), self._parse_expression(axis_offset) + SyntaxTree.Integer(1)])
196
197 elif type(axis_offset) is ast.Slice:
198 offset.append([self._parse_expression(axis_offset.lower), self._parse_expression(axis_offset.upper)])
199 else:
200 offset.append([self._parse_expression(axis_offset), self._parse_expression(axis_offset) + SyntaxTree.Integer(1)])
201
202 return SyntaxTree.Name.variables[value.id].offset(offset)
203
204 def _parse_comparison(self, comparison: ast.Compare):
205 lhs = self._parse_expression(comparison.left)
206 rhs = self._parse_expression(comparison.comparators[0])
207 if type(comparison.ops[0]) is ast.Gt:
208 return SyntaxTree.DataBlockComparison(">", lhs, rhs)
209 if type(comparison.ops[0]) is ast.Lt:
210 return SyntaxTree.DataBlockComparison(">", lhs, rhs)
211 if type(comparison.ops[0]) is ast.Eq:
212 return SyntaxTree.DataBlockComparison("==", lhs, rhs)
213
214 def _parse_expression(self, expression):
215 if type(expression) is ast.Constant:
216 return self._parse_constant(expression)
217 if type(expression) is ast.UnaryOp:
218 return self._parse_unary_operation(expression)
219 if type(expression) is ast.Compare:
220 return self._parse_comparison(expression)
221 if type(expression) is ast.BinOp:
222 return self._parse_binary_operation(expression)
223 if type(expression) is ast.Name:
224 if expression.id == "index":
225 return SyntaxTree.Index()
226 return SyntaxTree.Name(expression.id)
227 if type(expression) is ast.Call:
228 return self._parse_call(expression)
229 if type(expression) is ast.Subscript:
230 return self._parse_subscript(expression)
231 if expression is None:
232 return None
233
234 def _parse_assignment_with_declaration(self, assignment_with_declaration: ast.Assign):
235 value = self._parse_expression(assignment_with_declaration.value)
236 id = assignment_with_declaration.targets[0].id
237 if type(value.get_type()) is SyntaxTree.TDataBlock:
238 if type(value) is SyntaxTree.DataBlockUnaryMax:
239 value.set_output_variable(SyntaxTree.Name(id, value.get_type()))
240 return value
241 if value.requires_memory_allocation == False:
242 return SyntaxTree.DataBlockConstructionFromExisting(SyntaxTree.Name(id, value.get_type()), value)
243 else:
244 if type(value) is SyntaxTree.DataBlockBinaryOperation or type(value) is SyntaxTree.DataBlockMax or type(value) is SyntaxTree.DataBlockComparison or type(value._internal) is not SyntaxTree.FunctionCall:
245 return SyntaxTree.DataBlockConstructionFromOperation(SyntaxTree.Name(id, value.get_type()), value)
246 else:
247 return SyntaxTree.DataBlockConstructionFromFunction(SyntaxTree.Name(id, value.get_type()), value)
248# elif type(value) is SyntaxTree.VectorFromDataBlock:
249# SyntaxTree.Name.variables.update({id: value})
250# return None
251 elif type(value) is SyntaxTree.DiagonalMatrix:
252 SyntaxTree.Name.variables.update({id: value})
253 if type(value._internal) is SyntaxTree.FunctionCall and value._internal.id == "kroneckerProduct":
254 value._id = SyntaxTree.String(id)
256 if type(value._internal) is SyntaxTree.String:
257 return None
259 elif type(value) is SyntaxTree.Matrix:
260 SyntaxTree.Name.variables.update({id: value})
261 if type(value._internal) is SyntaxTree.FunctionCall and value._internal.id == "kroneckerProduct":
262 value._id = SyntaxTree.String(id)
264 return None
265 else:
266 return SyntaxTree.Construction(SyntaxTree.Name(id, value.get_type()), value)
267
268 def _parse_assignment_without_declaration(self, assignment_with_declaration: ast.Assign):
269 value = self._parse_expression(assignment_with_declaration.value)
270 target = self._parse_expression(assignment_with_declaration.targets[0])
271
272 if type(value.get_type()) is SyntaxTree.TDataBlock or type(target.get_type()) is SyntaxTree.TDataBlock:
273 if type(value) is SyntaxTree.DataBlockUnaryMax:
274 value.set_output_variable(target)
275 return value
276 return SyntaxTree.DataBlockAssignment(target, value)
277 elif type(target.get_type()) is SyntaxTree.TVector:
278 return SyntaxTree.VectorAssignment(target, value)
279 else:
280 return SyntaxTree.Assignment(target, value)
281
282 def _parse_assignment(self, assignment: ast.Assign):
283 target = assignment.targets[0]
284 if type(target) is ast.Subscript:
285 return self._parse_assignment_without_declaration(assignment)
286 elif target.id not in SyntaxTree.Name.variables:
287 return self._parse_assignment_with_declaration(assignment)
288 else:
289 return self._parse_assignment_without_declaration(assignment)
290
291 def _parse_if(self, statement: ast.If):
292 pde_term_is_in_use = False
293 assert(isinstance(statement.test, ast.Name))
294 test = statement.test.id
295 for pde_term in self.inuse_pde_terms:
296 if pde_term.NAME == test:
297 pde_term_is_in_use = True
298
299 if pde_term_is_in_use:
300 statements = []
301 for s in statement.body:
302 statements.append(self._parse_statement(s))
303 return statements
304 else:
305 return None
306# if_node = SyntaxTree.If(self._parse_expression(statement.test))
307# SyntaxTree.MemoryAllocation.memoryAllocated.append([])
308#
309# for s in statement.body:
310# if_node.add_statement(self._parse_statement(s))
311# for allocation in SyntaxTree.MemoryAllocation.memoryAllocated[-1]:
312# if_node.add_statement(SyntaxTree.MemoryDeallocation(allocation))
313#
314# SyntaxTree.MemoryAllocation.memoryAllocated.pop()
315# return if_node
316
317 def _parse_statement(self, statement: ast.Expr):
318 if type(statement) is ast.Assign:
319 return self._parse_assignment(statement)
320 if type(statement) is ast.Comment:
321 return SyntaxTree.Comment(statement.value)
322 if type(statement) is ast.If:
323 return self._parse_if(statement)
324 if type(statement) is ast.Expr:
325 return self._parse_expression(statement.value)
326
327 def _parse_function(self, function: ast.FunctionDef, template, functor_arguments, namespaces, stateless, use_accelerator, top_level = False, function_name = None):
328 id = function.name if function_name is None else function_name
329 return_type = SyntaxTree.TCustom(function.returns.value) if function.returns is not None else SyntaxTree.TCustom(function.returns)
330 parsed_function = SyntaxTree.FunctionDefinition(id, return_type, template, namespaces, stateless, top_level)
331
332 if use_accelerator:
333 parsed_function.add_argument(SyntaxTree.Argument("targetDevice", SyntaxTree.TInteger()))
334 SyntaxTree.Node.use_accelerator = True
335 for argument in function.args.args:
336 parsed_function.add_argument(SyntaxTree.Argument(argument.arg, SyntaxTree.TCustom(argument.annotation.value) if argument.annotation is not None else SyntaxTree.TCustom(argument.annotation)))
337
338 if stateless:
339 parsed_function.id = parsed_function.id + "Stateless"
340 parsed_function._template.insert(0, SyntaxTree.Argument("SolverType", SyntaxTree.TCustom("class")))
341 for functor in functor_arguments:
342 if type(functor._type) is not SyntaxTree.TCustom:
343 parsed_function.add_argument(functor)
344 else:
345 for functor in functor_arguments:
346 parsed_function.add_argument(functor)
347
348 SyntaxTree.MemoryAllocation.memoryAllocated.append([])
349 for statement in function.body:
350 next_statement = self._parse_statement(statement)
351 if isinstance(next_statement, list):
352 for nested_statement in next_statement:
353 parsed_function.add_statement(nested_statement)
354 elif next_statement is not None:
355 parsed_function.add_statement(next_statement)
356 for allocation in SyntaxTree.MemoryAllocation.memoryAllocated[-1]:
357 parsed_function.add_statement(SyntaxTree.MemoryDeallocation(allocation))
358 SyntaxTree.MemoryAllocation.memoryAllocated.pop()
359
360 return parsed_function
361
362 def parse(self, function, template_arguments, functor_arguments, inuse_pde_terms, namespace = [], stateless = False, use_accelerator = False, mlir_omp = False, use_memory_manager = False, function_name = None):
363 SyntaxTree.Name.variables.clear()
364 SyntaxTree.For._inuse_iteration_variables.clear()
365 SyntaxTree.Node.use_accelerator = False
366 SyntaxTree.Node.use_mlir_omp = mlir_omp
367 SyntaxTree.Node.use_memory_manager = use_memory_manager
368 #SyntaxTree.FunctionDefinition._syclDataToCopy.clear()
369 self.inuse_pde_terms = inuse_pde_terms
370 source_code = inspect.getsource(function)
371
372 module = ast.parse(source_code)
373 function_definition = module.body[0]
374 assert isinstance(function_definition, ast.FunctionDef)
375 for argument in template_arguments:
376 if type(argument._type) is SyntaxTree.TInteger:
377 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Integer(99)})
378 if type(argument._type) is SyntaxTree.TBoolean:
379 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Boolean(False)})
380 if type(argument._type) is SyntaxTree.TFloat:
381 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Float(99.0)})
382 for argument in functor_arguments:
383 if type(argument._type) is SyntaxTree.TInteger:
384 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Integer(99)})
385 if type(argument._type) is SyntaxTree.TBoolean:
386 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Boolean(False)})
387 if type(argument._type) is SyntaxTree.TFloat:
388 SyntaxTree.Name.variables.update({argument.id: SyntaxTree.Float(99.0)})
389
390 template_arguments_copy = copy.deepcopy(template_arguments)
391 root = self._parse_function(function_definition, template_arguments_copy, functor_arguments, namespace, stateless, use_accelerator, top_level = True, function_name = function_name)
392 #root.top_level(True)
393 return root
#define assert(...)
Definition LinuxAMD.h:28
_parse_unary_operation(self, ast.UnaryOp unary_operation)
Definition Parser.py:157
_parse_call(self, ast.Call call)
Definition Parser.py:18
_parse_diagonal_matrix_constructor(self, ast.Call constructor)
Definition Parser.py:66
_parse_comparison(self, ast.Compare comparison)
Definition Parser.py:204
_parse_function(self, ast.FunctionDef function, template, functor_arguments, namespaces, stateless, use_accelerator, top_level=False, function_name=None)
Definition Parser.py:327
_parse_constant(self, ast.Constant constant, type_name=None)
Definition Parser.py:6
_parse_subscript(self, ast.Subscript subscript)
Definition Parser.py:186
_parse_matrix_vector_product(self, ast.Call call)
Definition Parser.py:58
_parse_statement(self, ast.Expr statement)
Definition Parser.py:317
_parse_assignment(self, ast.Assign assignment)
Definition Parser.py:282
parse(self, function, template_arguments, functor_arguments, inuse_pde_terms, namespace=[], stateless=False, use_accelerator=False, mlir_omp=False, use_memory_manager=False, function_name=None)
Definition Parser.py:362
_parse_expression(self, expression)
Definition Parser.py:214
_parse_diagonal_matrix_vector_product(self, ast.Call call)
Definition Parser.py:53
_parse_kronecker_product(self, ast.Call product)
Definition Parser.py:77
_parse_matrix_constructor(self, ast.Call constructor)
Definition Parser.py:71
_parse_assignment_with_declaration(self, ast.Assign assignment_with_declaration)
Definition Parser.py:234
_parse_if(self, ast.If statement)
Definition Parser.py:291
_parse_patch_constructor(self, ast.Call constructor, isFace=False)
Definition Parser.py:116
_parse_binary_operation(self, ast.BinOp binary_operation)
Definition Parser.py:167
_parse_assignment_without_declaration(self, ast.Assign assignment_with_declaration)
Definition Parser.py:268