Skip to content

Commit 59879b7

Browse files
authored
Clean up unnecessary arguments in the codegen stage (pyccel#1791)
The codegen stage contains lots of old code which sometimes refers to parameters which no longer exist. Here we clean up some of that code and remove commented dead code which refers to it. Specifically the functions `fcode`, `ccode` and `pycode` are removed as well as `Codegen.doprint` and `Codegen.set_printer`. An instance of `Codegen` must now be created with the language passed as argument.
1 parent 718e1f3 commit 59879b7

File tree

16 files changed

+99
-329
lines changed

16 files changed

+99
-329
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ All notable changes to this project will be documented in this file.
2828
- \[INTERNALS\] Moved precision from `ast.basic.TypedAstNode` to an internal property of `ast.datatypes.FixedSizeNumericType` objects.
2929
- \[INTERNALS\] Use cached `__add__` method to determine result type of arithmetic operations.
3030
- \[INTERNALS\] Use cached `__and__` method to determine result type of bitwise comparison operations.
31+
- \[INTERNALS\] Removed unused `fcode`, `ccode`, `cwrappercode`, `luacode`, and `pycode` functions from printers.
32+
- \[INTERNALS\] Removed unused arguments from methods in `pyccel.codegen.codegen.Codegen`.
3133

3234
### Deprecated
3335

pyccel/codegen/codegen.py

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from pyccel.codegen.printing.pycode import PythonCodePrinter
1212

1313
from pyccel.ast.core import FunctionDef, Interface, ModuleHeader
14-
from pyccel.errors.errors import Errors
1514
from pyccel.utilities.stage import PyccelStage
1615

1716
_extension_registry = {'fortran': 'f90', 'c':'c', 'python':'py'}
@@ -24,28 +23,31 @@
2423

2524
pyccel_stage = PyccelStage()
2625

27-
class Codegen(object):
28-
29-
"""Abstract class for code generator."""
30-
31-
def __init__(self, parser, name):
32-
"""Constructor for Codegen.
33-
34-
parser: pyccel parser
35-
36-
37-
name: str
38-
name of the generated module or program.
39-
"""
26+
class Codegen:
27+
"""
28+
Class which handles the generation of code.
29+
30+
The class which handles the generation of code. This is done by creating an appropriate
31+
class inheriting from `CodePrinter` and using it to create strings describing the code
32+
that should be printed. This class then takes care of creating the necessary files.
33+
34+
Parameters
35+
----------
36+
parser : SemanticParser
37+
The Pyccel semantic parser for a Python program or module. This contains the
38+
annotated AST and additional information about the variables scope.
39+
name : str
40+
Name of the generated module or program.
41+
language : str
42+
The language which the printer should print to.
43+
"""
44+
def __init__(self, parser, name, language):
4045
pyccel_stage.set_stage('codegen')
4146
self._parser = parser
4247
self._ast = parser.ast
4348
self._name = name
4449
self._printer = None
45-
self._language = None
46-
47-
#TODO verify module name != function name
48-
#it generates a compilation error
50+
self._language = language
4951

5052
self._stmts = {}
5153
_structs = [
@@ -63,11 +65,32 @@ def __init__(self, parser, name):
6365
self._collect_statements()
6466
self._is_program = self.ast.program is not None
6567

68+
# instantiate code_printer
69+
try:
70+
CodePrinterSubclass = printer_registry[language]
71+
except KeyError as err:
72+
raise ValueError(f'{language} language is not available') from err
73+
74+
self._printer = CodePrinterSubclass(self.parser.filename)
6675

6776
@property
6877
def parser(self):
78+
"""
79+
The parser which generated the AST printed by this class.
80+
81+
The parser which generated the AST printed by this class.
82+
"""
6983
return self._parser
7084

85+
@property
86+
def printer(self):
87+
"""
88+
The printer which is used to generate code.
89+
90+
The printer which is used by this class to generate code in the target language.
91+
"""
92+
return self._printer
93+
7194
@property
7295
def name(self):
7396
"""Returns the name associated to the source code"""
@@ -134,22 +157,6 @@ def language(self):
134157

135158
return self._language
136159

137-
def set_printer(self, **settings):
138-
""" Set the current codeprinter instance"""
139-
# Get language used (default language used is fortran)
140-
language = settings.pop('language', 'fortran')
141-
142-
# Set language
143-
if not language in ['fortran', 'c', 'python']:
144-
raise ValueError('{} language is not available'.format(language))
145-
self._language = language
146-
147-
# instantiate codePrinter
148-
code_printer = printer_registry[language]
149-
errors = Errors()
150-
# set the code printer
151-
self._printer = code_printer(self.parser.filename, **settings)
152-
153160
def get_printer_imports(self):
154161
"""return the imports of the current codeprinter"""
155162
return self._printer.get_additional_imports()
@@ -176,22 +183,38 @@ def _collect_statements(self):
176183
self._stmts['interfaces'] = interfaces
177184
self._stmts['body'] = self.ast
178185

179-
def doprint(self, **settings):
180-
"""Prints the code in the target language."""
181-
if not self._printer:
182-
self.set_printer(**settings)
183-
return self._printer.doprint(self.ast)
184186

185-
186-
def export(self, filename=None, **settings):
187-
"""Export code in filename"""
188-
self.set_printer(**settings)
187+
def export(self, filename):
188+
"""
189+
Export code to a file with the requested name.
190+
191+
Generate the code in the target language from the AST and print this code
192+
to file. Between 1 and 3 files are generated depending on the AST and the
193+
target language. A source file is always generated. In languages with
194+
header files, a header file is also generated. Finally if the AST includes
195+
a program and the target language is not Python a program source file is
196+
also generated. The source and header files are named by appending the
197+
extension to the requested filename. The program source file is named by
198+
additionally prepending 'prog_' to the requested filename.
199+
200+
Parameters
201+
----------
202+
filename : str
203+
The base (i.e. no extensions) of the filename of the file where the
204+
code should be printed to.
205+
206+
Returns
207+
-------
208+
filename : str
209+
The name of the file where the source code was printed.
210+
prog_filename : str
211+
The name of the file where the source code for the program was printed.
212+
"""
189213
ext = _extension_registry[self._language]
190214
header_ext = _header_extension_registry[self._language]
191215

192-
if filename is None: filename = self.name
193-
header_filename = '{name}.{ext}'.format(name=filename, ext=header_ext)
194-
filename = '{name}.{ext}'.format(name=filename, ext=ext)
216+
header_filename = f'{filename}.{header_ext}'
217+
filename = f'{filename}.{ext}'
195218

196219
# print module header
197220
if header_ext is not None:

pyccel/codegen/pipeline.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ def handle_error(stage):
260260
start_codegen = time.time()
261261
# Generate .f90 file
262262
try:
263-
codegen = Codegen(semantic_parser, module_name)
263+
codegen = Codegen(semantic_parser, module_name, language)
264264
fname = os.path.join(pyccel_dirpath, module_name)
265-
fname, prog_name = codegen.export(fname, language=language)
265+
fname, prog_name = codegen.export(fname)
266266
except NotImplementedError as error:
267267
msg = str(error)
268268
errors.report(msg+'\n'+PYCCEL_RESTRICTION_TODO,

pyccel/codegen/printing/ccode.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2515,27 +2515,3 @@ def indent_code(self, code):
25152515
level += increase[n]
25162516
return pretty
25172517

2518-
def ccode(expr, filename, assign_to=None, **settings):
2519-
"""Converts an expr to a string of c code
2520-
2521-
expr : Expr
2522-
A pyccel expression to be converted.
2523-
filename : str
2524-
The name of the file being translated. Used in error printing
2525-
assign_to : optional
2526-
When given, the argument is used as the name of the variable to which
2527-
the expression is assigned. Can be a string, ``Symbol``,
2528-
``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
2529-
line-wrapping, or for expressions that generate multi-line statements.
2530-
user_functions : dict, optional
2531-
A dictionary where keys are ``FunctionClass`` instances and values are
2532-
their string representations. Alternatively, the dictionary value can
2533-
be a list of tuples i.e. [(argument_test, cfunction_string)]. See below
2534-
for examples.
2535-
dereference : iterable, optional
2536-
An iterable of symbols that should be dereferenced in the printed code
2537-
expression. These would be values passed by address to the function.
2538-
For example, if ``dereference=[a]``, the resulting code would print
2539-
``(*a)`` instead of ``a``.
2540-
"""
2541-
return CCodePrinter(filename, **settings).doprint(expr, assign_to)

pyccel/codegen/printing/cwrappercode.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -515,31 +515,3 @@ def _print_IndexedElement(self, expr):
515515
return f'{base}{idxs}'
516516
else:
517517
return CCodePrinter._print_IndexedElement(self, expr)
518-
519-
def cwrappercode(expr, filename, target_language, assign_to=None, **settings):
520-
"""Converts an expr to a string of c wrapper code
521-
522-
expr : Expr
523-
A pyccel expression to be converted.
524-
filename : str
525-
The name of the file being translated. Used in error printing
526-
assign_to : optional
527-
When given, the argument is used as the name of the variable to which
528-
the expression is assigned. Can be a string, ``Symbol``,
529-
``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
530-
line-wrapping, or for expressions that generate multi-line statements.
531-
precision : integer, optional
532-
The precision for numbers such as pi [default=15].
533-
user_functions : dict, optional
534-
A dictionary where keys are ``FunctionClass`` instances and values are
535-
their string representations. Alternatively, the dictionary value can
536-
be a list of tuples i.e. [(argument_test, cfunction_string)]. See below
537-
for examples.
538-
dereference : iterable, optional
539-
An iterable of symbols that should be dereferenced in the printed code
540-
expression. These would be values passed by address to the function.
541-
For example, if ``dereference=[a]``, the resulting code would print
542-
``(*a)`` instead of ``a``.
543-
"""
544-
545-
return CWrapperCodePrinter(filename, target_language, **settings).doprint(expr, assign_to)

pyccel/codegen/printing/fcode.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3266,25 +3266,3 @@ def _print_BindCClassDef(self, expr):
32663266
*[a.getter for a in expr.attributes], *[a.setter for a in expr.attributes]]
32673267
sep = f'\n{self._print(SeparatorComment(40))}\n'
32683268
return '', sep.join(self._print(f) for f in funcs)
3269-
3270-
3271-
def fcode(expr, filename, assign_to=None, **settings):
3272-
"""Converts an expr to a string of Fortran code
3273-
3274-
expr : Expr
3275-
A pyccel expression to be converted.
3276-
filename : str
3277-
The name of the file being translated. Used in error printing
3278-
assign_to : optional
3279-
When given, the argument is used as the name of the variable to which
3280-
the expression is assigned. Can be a string, ``Symbol``,
3281-
``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
3282-
line-wrapping, or for expressions that generate multi-line statements.
3283-
user_functions : dict, optional
3284-
A dictionary where keys are ``FunctionClass`` instances and values are
3285-
their string representations. Alternatively, the dictionary value can
3286-
be a list of tuples i.e. [(argument_test, cfunction_string)]. See below
3287-
for examples.
3288-
"""
3289-
3290-
return FCodePrinter(filename, **settings).doprint(expr, assign_to)

pyccel/codegen/printing/luacode.py

Lines changed: 0 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -507,118 +507,3 @@ def indent_code(self, code):
507507
level += increase[n]
508508
return pretty
509509

510-
511-
def lua_code(expr, assign_to=None, **settings):
512-
"""Converts an expr to a string of Lua code
513-
514-
expr : Expr
515-
A sympy expression to be converted.
516-
assign_to : optional
517-
When given, the argument is used as the name of the variable to which
518-
the expression is assigned. Can be a string, ``Symbol``,
519-
``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of
520-
line-wrapping, or for expressions that generate multi-line statements.
521-
precision : integer, optional
522-
The precision for numbers such as pi [default=15].
523-
user_functions : dict, optional
524-
A dictionary where the keys are string representations of either
525-
``FunctionClass`` or ``UndefinedFunction`` instances and the values
526-
are their desired C string representations. Alternatively, the
527-
dictionary value can be a list of tuples i.e. [(argument_test,
528-
cfunction_string)]. See below for examples.
529-
dereference : iterable, optional
530-
An iterable of symbols that should be dereferenced in the printed code
531-
expression. These would be values passed by address to the function.
532-
For example, if ``dereference=[a]``, the resulting code would print
533-
``(*a)`` instead of ``a``.
534-
human : bool, optional
535-
If True, the result is a single string that may contain some constant
536-
declarations for the number symbols. If False, the same information is
537-
returned in a tuple of (symbols_to_declare, not_supported_functions,
538-
code_text). [default=True].
539-
contract: bool, optional
540-
If True, ``Indexed`` instances are assumed to obey tensor contraction
541-
rules and the corresponding nested loops over indices are generated.
542-
Setting contract=False will not generate loops, instead the user is
543-
responsible to provide values for the indices in the code.
544-
[default=True].
545-
locals: dict
546-
A dictionary that contains the list of local symbols. these symbols will
547-
be preceeded by local for their first assignment.
548-
549-
Examples
550-
551-
>>> from sympy import lua_code, symbols, Rational, sin, ceiling, Abs, Function
552-
>>> x, tau = symbols("x, tau")
553-
>>> lua_code((2*tau)**Rational(7, 2))
554-
'8*1.4142135623731*tau.powf(7_f64/2.0)'
555-
>>> lua_code(sin(x), assign_to="s")
556-
's = x.sin();'
557-
558-
Simple custom printing can be defined for certain types by passing a
559-
dictionary of {"type" : "function"} to the ``user_functions`` kwarg.
560-
Alternatively, the dictionary value can be a list of tuples i.e.
561-
[(argument_test, cfunction_string)].
562-
563-
>>> custom_functions = {
564-
... "ceiling": "CEIL",
565-
... "Abs": [(lambda x: not x.is_integer, "fabs", 4),
566-
... (lambda x: x.is_integer, "ABS", 4)],
567-
... "func": "f"
568-
... }
569-
>>> func = Function('func')
570-
>>> lua_code(func(Abs(x) + ceiling(x)), user_functions=custom_functions)
571-
'(fabs(x) + x.CEIL()).f()'
572-
573-
``Piecewise`` expressions are converted into conditionals. If an
574-
``assign_to`` variable is provided an if statement is created, otherwise
575-
the ternary operator is used. Note that if the ``Piecewise`` lacks a
576-
default term, represented by ``(expr, True)`` then an error will be thrown.
577-
This is to prevent generating an expression that may not evaluate to
578-
anything.
579-
580-
>>> from sympy import Piecewise
581-
>>> expr = Piecewise((x + 1, x > 0), (x, True))
582-
>>> print(lua_code(expr, tau))
583-
tau = if (x > 0) {
584-
x + 1
585-
} else {
586-
x
587-
};
588-
589-
Support for loops is provided through ``Indexed`` types. With
590-
``contract=True`` these expressions will be turned into loops, whereas
591-
``contract=False`` will just print the assignment expression that should be
592-
looped over:
593-
594-
>>> from sympy import Eq, IndexedBase, Idx
595-
>>> len_y = 5
596-
>>> y = IndexedBase('y', shape=(len_y,))
597-
>>> t = IndexedBase('t', shape=(len_y,))
598-
>>> Dy = IndexedBase('Dy', shape=(len_y-1,))
599-
>>> i = Idx('i', len_y-1)
600-
>>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i]))
601-
>>> lua_code(e.rhs, assign_to=e.lhs, contract=False)
602-
'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);'
603-
604-
Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions
605-
must be provided to ``assign_to``. Note that any expression that can be
606-
generated normally can also exist inside a Matrix:
607-
608-
>>> from sympy import Matrix, MatrixSymbol
609-
>>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)])
610-
>>> A = MatrixSymbol('A', 3, 1)
611-
>>> print(lua_code(mat, A))
612-
A = [x.powi(2), if (x > 0) {
613-
x + 1
614-
} else {
615-
x
616-
}, x.sin()];
617-
"""
618-
619-
return LuaCodePrinter(settings).doprint(expr, assign_to)
620-
621-
622-
def print_lua_code(expr, **settings):
623-
"""Prints Lua representation of the given expression."""
624-
print((lua_code(expr, **settings)))

0 commit comments

Comments
 (0)