1- # Copyright (C) 2023 Chris Richardson
1+ # Copyright (C) 2023-2025 Chris Richardson and Paul T. Kühner
22#
33# This file is part of FFCx. (https://www.fenicsproject.org)
44#
55# SPDX-License-Identifier: LGPL-3.0-or-later
66"""C implementation."""
77
88import warnings
9+ from functools import singledispatchmethod
910
1011import numpy as np
1112import numpy .typing as npt
1213
1314import ffcx .codegeneration .lnodes as L
15+ from ffcx .codegeneration .interface import Formatter as FormatterInterface
1416from ffcx .codegeneration .utils import dtype_to_c_type , dtype_to_scalar_dtype
1517
1618math_table = {
142144}
143145
144146
145- class Formatter :
147+ class Formatter ( FormatterInterface ) :
146148 """C formatter."""
147149
148150 scalar_type : np .dtype
@@ -184,11 +186,18 @@ def _build_initializer_lists(self, values):
184186 arr += "}"
185187 return arr
186188
187- def format_statement_list (self , slist ) -> str :
189+ @singledispatchmethod
190+ def __call__ (self , obj : L .LNode ) -> str :
191+ """Format an L Node."""
192+ raise NotImplementedError (f"Can not format object to type { type (obj )} " )
193+
194+ @__call__ .register
195+ def _ (self , slist : L .StatementList ) -> str :
188196 """Format a statement list."""
189- return "" .join (self . format (s ) for s in slist .statements )
197+ return "" .join (self (s ) for s in slist .statements )
190198
191- def format_section (self , section ) -> str :
199+ @__call__ .register
200+ def _ (self , section : L .Section ) -> str :
192201 """Format a section."""
193202 # add new line before section
194203 comments = (
@@ -197,28 +206,30 @@ def format_section(self, section) -> str:
197206 f"// Inputs: { ', ' .join (w .name for w in section .input )} \n "
198207 f"// Outputs: { ', ' .join (w .name for w in section .output )} \n "
199208 )
200- declarations = "" .join (self . format (s ) for s in section .declarations )
209+ declarations = "" .join (self (s ) for s in section .declarations )
201210
202211 body = ""
203212 if len (section .statements ) > 0 :
204213 declarations += "{\n "
205- body = "" .join (self . format (s ) for s in section .statements )
214+ body = "" .join (self (s ) for s in section .statements )
206215 body = body .replace ("\n " , "\n " )
207216 body = body [:- 2 ] + "}\n "
208217
209218 body += "// ------------------------ \n "
210219 return str (comments + declarations + body )
211220
212- def format_comment (self , c : L .Comment ) -> str :
221+ @__call__ .register
222+ def _ (self , c : L .Comment ) -> str :
213223 """Format a comment."""
214- return "// " + c .comment + " \n "
224+ return f "// { c .comment } \n "
215225
216- def format_array_decl (self , arr ) -> str :
226+ @__call__ .register
227+ def _ (self , arr : L .ArrayDecl ) -> str :
217228 """Format an array declaration."""
218229 dtype = arr .symbol .dtype
219230 typename = self ._dtype_to_name (dtype )
220231
221- symbol = self . format (arr .symbol )
232+ symbol = self (arr .symbol )
222233 dims = "" .join ([f"[{ i } ]" for i in arr .sizes ])
223234 if arr .values is None :
224235 assert arr .const is False
@@ -228,23 +239,26 @@ def format_array_decl(self, arr) -> str:
228239 cstr = "static const " if arr .const else ""
229240 return f"{ cstr } { typename } { symbol } { dims } = { vals } ;\n "
230241
231- def format_array_access (self , arr ) -> str :
242+ @__call__ .register
243+ def _ (self , arr : L .ArrayAccess ) -> str :
232244 """Format an array access."""
233- name = self . format (arr .array )
234- indices = f"[{ '][' .join (self . format (i ) for i in arr .indices )} ]"
245+ name = self (arr .array )
246+ indices = f"[{ '][' .join (self (i ) for i in arr .indices )} ]"
235247 return f"{ name } { indices } "
236248
237- def format_variable_decl (self , v ) -> str :
249+ @__call__ .register
250+ def _ (self , v : L .VariableDecl ) -> str :
238251 """Format a variable declaration."""
239- val = self . format (v .value )
240- symbol = self . format (v .symbol )
252+ val = self (v .value )
253+ symbol = self (v .symbol )
241254 typename = self ._dtype_to_name (v .symbol .dtype )
242255 return f"{ typename } { symbol } = { val } ;\n "
243256
244- def format_nary_op (self , oper ) -> str :
257+ @__call__ .register
258+ def _ (self , oper : L .NaryOp ) -> str :
245259 """Format an n-ary operation."""
246260 # Format children
247- args = [self . format (arg ) for arg in oper .args ]
261+ args = [self (arg ) for arg in oper .args ]
248262
249263 # Apply parentheses
250264 for i in range (len (args )):
@@ -254,11 +268,12 @@ def format_nary_op(self, oper) -> str:
254268 # Return combined string
255269 return f" { oper .op } " .join (args )
256270
257- def format_binary_op (self , oper ) -> str :
271+ @__call__ .register
272+ def _ (self , oper : L .BinOp ) -> str :
258273 """Format a binary operation."""
259274 # Format children
260- lhs = self . format (oper .lhs )
261- rhs = self . format (oper .rhs )
275+ lhs = self (oper .lhs )
276+ rhs = self (oper .rhs )
262277
263278 # Apply parentheses
264279 if oper .lhs .precedence >= oper .precedence :
@@ -269,52 +284,61 @@ def format_binary_op(self, oper) -> str:
269284 # Return combined string
270285 return f"{ lhs } { oper .op } { rhs } "
271286
272- def format_unary_op (self , oper ) -> str :
287+ @__call__ .register (L .Neg )
288+ @__call__ .register (L .Not )
289+ def _ (self , oper : L .Neg | L .Not ) -> str :
273290 """Format a unary operation."""
274- arg = self . format (oper .arg )
291+ arg = self (oper .arg )
275292 if oper .arg .precedence >= oper .precedence :
276293 return f"{ oper .op } ({ arg } )"
277294 return f"{ oper .op } { arg } "
278295
279- def format_literal_float (self , val ) -> str :
296+ @__call__ .register
297+ def _ (self , val : L .LiteralFloat ) -> str :
280298 """Format a literal float."""
281299 value = self ._format_number (val .value )
282300 return f"{ value } "
283301
284- def format_literal_int (self , val ) -> str :
302+ @__call__ .register
303+ def _ (self , val : L .LiteralInt ) -> str :
285304 """Format a literal int."""
286305 return f"{ val .value } "
287306
288- def format_for_range (self , r ) -> str :
307+ @__call__ .register
308+ def _ (self , r : L .ForRange ) -> str :
289309 """Format a for loop over a range."""
290- begin = self . format (r .begin )
291- end = self . format (r .end )
292- index = self . format (r .index )
310+ begin = self (r .begin )
311+ end = self (r .end )
312+ index = self (r .index )
293313 output = f"for (int { index } = { begin } ; { index } < { end } ; ++{ index } )\n "
294314 output += "{\n "
295- body = self . format (r .body )
315+ body = self (r .body )
296316 for line in body .split ("\n " ):
297317 if len (line ) > 0 :
298318 output += f" { line } \n "
299319 output += "}\n "
300320 return output
301321
302- def format_statement (self , s ) -> str :
322+ @__call__ .register
323+ def _ (self , s : L .Statement ) -> str :
303324 """Format a statement."""
304- return self . format (s .expr )
325+ return self (s .expr )
305326
306- def format_assign (self , expr ) -> str :
327+ @__call__ .register (L .Assign )
328+ @__call__ .register (L .AssignAdd )
329+ def _ (self , expr : L .Assign | L .AssignAdd ) -> str :
307330 """Format an assignment."""
308- rhs = self . format (expr .rhs )
309- lhs = self . format (expr .lhs )
331+ rhs = self (expr .rhs )
332+ lhs = self (expr .lhs )
310333 return f"{ lhs } { expr .op } { rhs } ;\n "
311334
312- def format_conditional (self , s ) -> str :
335+ @__call__ .register
336+ def _ (self , s : L .Conditional ) -> str :
313337 """Format a conditional."""
314338 # Format children
315- c = self . format (s .condition )
316- t = self . format (s .true )
317- f = self . format (s .false )
339+ c = self (s .condition )
340+ t = self (s .true )
341+ f = self (s .false )
318342
319343 # Apply parentheses
320344 if s .condition .precedence >= s .precedence :
@@ -327,15 +351,18 @@ def format_conditional(self, s) -> str:
327351 # Return combined string
328352 return c + " ? " + t + " : " + f
329353
330- def format_symbol (self , s ) -> str :
354+ @__call__ .register
355+ def _ (self , s : L .Symbol ) -> str :
331356 """Format a symbol."""
332357 return f"{ s .name } "
333358
334- def format_multi_index (self , mi ) -> str :
359+ @__call__ .register
360+ def _ (self , mi : L .MultiIndex ) -> str :
335361 """Format a multi-index."""
336- return self . format (mi .global_index )
362+ return self (mi .global_index )
337363
338- def format_math_function (self , c ) -> str :
364+ @__call__ .register
365+ def _ (self , c : L .MathFunction ) -> str :
339366 """Format a mathematical function."""
340367 # Get a table of functions for this type, if available
341368 arg_type = self .scalar_type
@@ -349,48 +376,5 @@ def format_math_function(self, c) -> str:
349376
350377 # Get a function from the table, if available, else just use bare name
351378 func = dtype_math_table .get (c .function , c .function )
352- args = ", " .join (self . format (arg ) for arg in c .args )
379+ args = ", " .join (self (arg ) for arg in c .args )
353380 return f"{ func } ({ args } )"
354-
355- impl = {
356- "Section" : format_section ,
357- "StatementList" : format_statement_list ,
358- "Comment" : format_comment ,
359- "ArrayDecl" : format_array_decl ,
360- "ArrayAccess" : format_array_access ,
361- "MultiIndex" : format_multi_index ,
362- "VariableDecl" : format_variable_decl ,
363- "ForRange" : format_for_range ,
364- "Statement" : format_statement ,
365- "Assign" : format_assign ,
366- "AssignAdd" : format_assign ,
367- "Product" : format_nary_op ,
368- "Neg" : format_unary_op ,
369- "Sum" : format_nary_op ,
370- "Add" : format_binary_op ,
371- "Sub" : format_binary_op ,
372- "Mul" : format_binary_op ,
373- "Div" : format_binary_op ,
374- "Not" : format_unary_op ,
375- "LiteralFloat" : format_literal_float ,
376- "LiteralInt" : format_literal_int ,
377- "Symbol" : format_symbol ,
378- "Conditional" : format_conditional ,
379- "MathFunction" : format_math_function ,
380- "And" : format_binary_op ,
381- "Or" : format_binary_op ,
382- "NE" : format_binary_op ,
383- "EQ" : format_binary_op ,
384- "GE" : format_binary_op ,
385- "LE" : format_binary_op ,
386- "GT" : format_binary_op ,
387- "LT" : format_binary_op ,
388- }
389-
390- def format (self , s ) -> str :
391- """Format as C."""
392- name = s .__class__ .__name__
393- try :
394- return self .impl [name ](self , s )
395- except KeyError :
396- raise RuntimeError ("Unknown statement: " , name )
0 commit comments