PyForTool
Python-fortran-tool
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | List of all members
pyfortool.statements.Statements Class Reference
Inheritance diagram for pyfortool.statements.Statements:
Inheritance graph
[legend]

Public Member Functions

 isNodeInProcedure (self, node, procList)
 
 isNodeInCall (self, node)
 
 removeCall (self, callName, simplify=False)
 
 removePrints (self, simplify=False)
 
 removeArraySyntax (self, concurrent=False, useMnhExpand=True, everywhere=True, loopVar=None, reuseLoop=True, funcList=None, updateMemSet=False, updateCopy=False, addAccIndependentCollapse=True)
 
 inlineContainedSubroutines (self, simplify=False, loopVar=None)
 
 inline (self, subContained, callStmt, mainScope, simplify=False, loopVar=None)
 
 setFalseIfStmt (self, flags, simplify=False)
 
 evalFalseIfStmt (self, nodes, simplify=False)
 
 checkOpInCall (self, mustRaise=False)
 
 checkEmptyParensInCall (self, mustRaise=False)
 
 insertStatement (self, stmt, first)
 
 removeStmtNode (self, nodes, simplifyVar, simplifyStruct)
 
 removeConstructNode (self, node, simplifyVar, simplifyStruct)
 
 removeFromList (self, item, itemPar)
 

Static Public Member Functions

 createDoConstruct (loopVariables, indent=0, concurrent=False)
 
 insertInList (pos, item, parent)
 

Detailed Description

Methods to act on statements

Definition at line 91 of file statements.py.

Member Function Documentation

◆ checkEmptyParensInCall()

pyfortool.statements.Statements.checkEmptyParensInCall (   self,
  mustRaise = False 
)
:param mustRaise: True to raise
Issue a logging.warning if some call arguments are arrays with empty parens
Example: CALL FOO(A(:))
If mustRaise is True, issue a logging.error instead and raise an error

Definition at line 1383 of file statements.py.

Here is the call graph for this function:

◆ checkOpInCall()

pyfortool.statements.Statements.checkOpInCall (   self,
  mustRaise = False 
)
:param mustRaise: True to raise
Issue a logging.warning if some call arguments are operations
If mustRaise is True, issue a logging.error instead and raise an error

Definition at line 1366 of file statements.py.

Here is the call graph for this function:

◆ createDoConstruct()

pyfortool.statements.Statements.createDoConstruct (   loopVariables,
  indent = 0,
  concurrent = False 
)
static
:param loopVariables: ordered dictionnary with loop variables as key and bounds as values.
                      Bounds are expressed with a 2-tuple.
                      Keys must be in the same order as the order used when addressing an
                        element: if loopVariables.keys is [JI, JK], arrays are
                        addressed with (JI, JK)
:param indent: current indentation
:param concurrent: if False, output is made of nested 'DO' loops
                   if True, output is made of a single 'DO CONCURRENT' loop
:return: (inner, outer, extraindent) with
          - inner the inner do-construct where statements must be added
          - outer the outer do-construct to be inserted somewhere
          - extraindent the number of added indentation
            (2 if concurrent else 2*len(loopVariables))

Definition at line 1649 of file statements.py.

Here is the caller graph for this function:

◆ evalFalseIfStmt()

pyfortool.statements.Statements.evalFalseIfStmt (   self,
  nodes,
  simplify = False 
)
Evaluate if-stmt with multiple op-E and remove the nodes if only .FALSE. are present
:param nodes: list of nodes of type op-E to evaluate (containing .FALSE.)
:param simplify: try to simplify code (if if-block is removed, variables used in the
                 if condition are also checked)

Definition at line 1344 of file statements.py.

Here is the call graph for this function:

◆ inline()

pyfortool.statements.Statements.inline (   self,
  subContained,
  callStmt,
  mainScope,
  simplify = False,
  loopVar = None 
)
Inline a single contained subroutine at its call site.

This method performs the actual inlining of a contained subroutine
into the calling scope. It handles:
- ELEMENTAL subroutines with array arguments
- Optional arguments (PRESENT intrinsic)
- Variable name conflicts
- USE statement merging

Parameters
----------
subContained : xml element
    XML fragment corresponding to the contained subroutine scope.
callStmt : xml element
    The call-stmt node to replace with inlined code.
mainScope : PYFTscope
    Scope of the main (calling) subroutine.
simplify : bool, optional
    If True, remove empty constructs and unused variables
    after inlining. Default is False.
loopVar : callable or None, optional
    Function to determine loop index variable name.
    Used when inlining ELEMENTAL subroutines called on arrays.
    Takes: (lowerDecl, upperDecl, lowerUsed, upperUsed, name, index)
    Returns: str, True (auto-generate), or False (skip).

Notes
-----
- For ELEMENTAL subroutines on arrays: DO loops are introduced.
- Optional arguments: PRESENT(var) is replaced with .TRUE. or .FALSE.
- Missing optional arguments: code paths using them are removed.
- Name conflicts: local variables are renamed with _N suffixes.

Definition at line 810 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ inlineContainedSubroutines()

pyfortool.statements.Statements.inlineContainedSubroutines (   self,
  simplify = False,
  loopVar = None 
)
Inline all contained subroutines into their parent.

Transforms contained subroutines (defined after CONTAINS) by:
1. Identifying contained subroutines
2. Finding all CALL statements to contained routines
3. Inlining the routine body where called
4. Removing the contained routine definitions

Parameters
----------
simplify : bool, optional
    If True, simplify code by removing empty constructs
    and unused variables after inlining. Default is False.
loopVar : callable or None, optional
    Function to determine loop index variable name for ELEMENTAL
    subroutine calls on arrays.
    Takes: (lowerDecl, upperDecl, lowerUsed, upperUsed, name, index)
    Returns: str, True (auto-generate), or False (skip).

Examples
--------
>>> pft = PYFT('input.F90')
>>> pft.inlineContainedSubroutines()
>>> pft.write()

Notes
-----
- ELEMENTAL subroutines called on arrays get wrapped in DO loops.
- Optional arguments are handled (PRESENT checks are added/removed).
- Variables in contained routines may be renamed to avoid conflicts.
- Empty CONTAINS sections are removed when simplify=True.

Definition at line 732 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ insertInList()

pyfortool.statements.Statements.insertInList (   pos,
  item,
  parent 
)
static
:param pos: insertion position
:param item: item to add to the list
:param parent: the parent of item (the list)

Definition at line 1754 of file statements.py.

Here is the caller graph for this function:

◆ insertStatement()

pyfortool.statements.Statements.insertStatement (   self,
  stmt,
  first 
)
Insert a statement to be executed first (or last)
:param stmt: statement to insert
:param first: True to insert it in first position, False to insert it in last position
:return: the index of the stmt inserted in scope

Definition at line 1404 of file statements.py.

Here is the call graph for this function:

◆ isNodeInCall()

pyfortool.statements.Statements.isNodeInCall (   self,
  node 
)
Check if a node is an argument of a CALL statement.

Parameters
----------
node : xml element
    A named-E element to check.

Returns
-------
bool
    True if the node is an argument in a CALL statement,
    False otherwise.

Examples
--------
>>> node = pft.find('.//{*}named-E[{*}N/{*}n="X"]')
>>> is_arg = pft.isNodeInCall(node)  # True if X is in CALL FOO(X)

Definition at line 142 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isNodeInProcedure()

pyfortool.statements.Statements.isNodeInProcedure (   self,
  node,
  procList 
)
Check if a node is an argument of a specific intrinsic procedure.

Parameters
----------
node : xml element
    A named-E element to check.
procList : list of str
    List of intrinsic procedure names (e.g., ['ALLOCATED', 'PRESENT']).

Returns
-------
bool
    True if the node is an argument of one of the specified procedures.

Examples
--------
>>> node = pft.find('.//{*}named-E')
>>> is_arg = pft.isNodeInProcedure(node, ['ALLOCATED', 'PRESENT'])

Definition at line 97 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeArraySyntax()

pyfortool.statements.Statements.removeArraySyntax (   self,
  concurrent = False,
  useMnhExpand = True,
  everywhere = True,
  loopVar = None,
  reuseLoop = True,
  funcList = None,
  updateMemSet = False,
  updateCopy = False,
  addAccIndependentCollapse = True 
)
Transform array syntax assignments into explicit DO loops.

Converts Fortran array syntax (e.g., A(:) = B(:)) into equivalent DO loop form.

Parameters
----------
concurrent : bool, optional
    If True, use 'DO CONCURRENT' loops instead of simple 'DO' loops.
    Default is False.
useMnhExpand : bool, optional
    If True, respect mnh_expand directives to transform entire blocks
    into a single loop. Default is True.
everywhere : bool, optional
    If True, transform all array syntax in the code.
    If False, only transform sections marked with !$mnh_expand directives.
    Default is True.
loopVar : callable or None, optional
    Function to determine loop index variable name.
    Takes arguments: (lowerDecl, upperDecl, lowerUsed, upperUsed, name, index)
    Returns: str (variable name), True (auto-generate name), or False (skip).
    None (default) auto-generates variable names (J1, J2, etc.).
reuseLoop : bool, optional
    If True, attempt to reuse loops when consecutive statements
    have identical bounds. Default is True.
funcList : list of str, optional
    Additional function names to recognize as array functions.
    These functions will not be expanded. Default is None (empty list).
updateMemSet : bool, optional
    If True, transform constant array initializations (e.g., A(:) = 0)
    into DO loops. Default is False.
updateCopy : bool, optional
    If True, transform array copy operations (e.g., A(:) = B(:))
    into DO loops. Default is False.
addAccIndependentCollapse : bool, optional
    If True, add !$acc loop independent collapse(N) directive
    before DO constructs. Default is True.

Returns
-------
None

Transformation Examples
----------------------
Simple assignment:

Before:
    A(:) = B(:) + C(:)

After (standard):
    DO J1 = LBOUND(A, 1), UBOUND(A, 1)
        A(J1) = B(J1) + C(J1)
    END DO

After (concurrent):
    DO CONCURRENT (J1=LBOUND(A, 1):UBOUND(A, 1))
        A(J1) = B(J1) + C(J1)
    END DO

WHERE construct:

Before:
    WHERE (MASK(:)) X(:) = Y(:)

After:
    DO J1 = 1, SIZE(X, 1)
        IF (MASK(J1)) X(J1) = Y(J1)
    END DO

Notes
-----
- Only transforms array syntax using explicit ':' notation.
- Intrinsic array functions (COUNT, ANY, SUM, etc.) are preserved.
- Does not transform:
  - A=A(:) (no-op on left side)
  - A(:)=A (single array without slice on right side)
- When useMnhExpand=True, requires specific directive format:
  !$mnh_expand_array(INDEX=bounds)
  ... code to transform ...
  !$mnh_end_expand_array(INDEX=bounds)

Definition at line 244 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeCall()

pyfortool.statements.Statements.removeCall (   self,
  callName,
  simplify = False 
)
Remove all CALL statements to a specified subprogram.

Parameters
----------
callName : str
    Name of the subprogram to remove calls to.
simplify : bool, optional
    If True, also remove variables that become unused after the deletion.
    For example, if "CALL FOO(X)" is removed and X is not used elsewhere,
    X will also be removed.

Returns
-------
int
    Number of CALL statements removed.

Examples
--------
>>> pft = PYFT('input.F90')
>>> n = pft.removeCall('FOO')  # Remove all CALL FOO statements
>>> print(f"Removed {n} calls")

Remove calls and simplify (remove unused variables):
>>> pft.removeCall('BAR', simplify=True)

Notes
-----
- When simplify=True, may cascade to remove:
  - Empty IF constructs (if call was the only statement)
  - Variables only used in removed calls
  - Type declarations that become empty

Definition at line 179 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeConstructNode()

pyfortool.statements.Statements.removeConstructNode (   self,
  node,
  simplifyVar,
  simplifyStruct 
)
This function removes a construct node and:
  - suppress variable that became useless (if simplifyVar is True)
  - suppress outer loop/if if useless (if simplifyStruct is True)
:param node: node representing the statement to remove
:param simplifyVar: try to simplify code (if we delete "CALL FOO(X)" and if X not used
                    else where, we also delete it; or if the call was alone inside a
                    if-then-endif construct, with simplifyStruct=True, the construct is also
                    removed, and variables used in the if condition are also checked...)
:param simplifyStruct: try to simplify code (if we delete "CALL FOO(X)" and if the call was
                       alone inside a if-then-endif construct, the construct is also
                       removed, and variables used in the if condition
                       (with simplifyVar=True) are also checked...)

If a statement is passed, it is suppressed by removeStmtNode

Definition at line 1598 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removeFromList()

pyfortool.statements.Statements.removeFromList (   self,
  item,
  itemPar 
)
:param item: item to remove from list
:param itemPar: the parent of item (the list)

Definition at line 1773 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ removePrints()

pyfortool.statements.Statements.removePrints (   self,
  simplify = False 
)
Remove all PRINT statements from the code.

Parameters
----------
simplify : bool, optional
    If True, also remove variables that become unused after the deletion.

Examples
--------
>>> pft = PYFT('input.F90')
>>> pft.removePrints()  # Remove all PRINT statements
>>> pft.removePrints(simplify=True)  # Also remove unused variables

Notes
-----
- When simplify=True, may cascade to remove:
  - Empty IF constructs (if print was the only statement)
  - Variables only used in removed prints

Definition at line 220 of file statements.py.

Here is the call graph for this function:

◆ removeStmtNode()

pyfortool.statements.Statements.removeStmtNode (   self,
  nodes,
  simplifyVar,
  simplifyStruct 
)
Remove statement nodes with optional code simplification.

Parameters
----------
nodes : xml element or list of xml elements
    Node(s) to remove from the code tree.
simplifyVar : bool
    If True, also remove variables that become unused after
    the deletion of the nodes.
simplifyStruct : bool
    If True, also remove empty enclosing constructs
    (IF blocks, loops) that become empty after node removal.

Examples
--------
>>> pft = PYFT('input.F90')
>>> nodes = pft.findall('.//{*}call-stmt')
>>> pft.removeStmtNode(nodes, simplifyVar=True, simplifyStruct=True)

Notes
-----
- Handles nested structures (removes inner statements first).
- When simplifyStruct=True:
  - Empty IF blocks are removed
  - Empty loops are removed
  - WHERE constructs are handled
- When simplifyVar=True:
  - Unused local variables are removed
  - Empty type declarations are cleaned up

Definition at line 1449 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setFalseIfStmt()

pyfortool.statements.Statements.setFalseIfStmt (   self,
  flags,
  simplify = False 
)
Set conditional flags to .FALSE. in IF conditions.

Replaces specified flag variables in IF conditions with .FALSE.,
effectively disabling code paths controlled by those flags.

Parameters
----------
flags : str or list of str
    Flag variable name(s) to set to .FALSE.
    Can be a single string or a list of strings.
simplify : bool, optional
    If True, remove resulting dead code:
    - IF blocks that always evaluate to .FALSE. are removed
    - Unused variables are cleaned up. Default is False.

Examples
--------
>>> pft = PYFT('input.F90')
>>> pft.setFalseIfStmt('LFLAG')  # IF (LFLAG) -> .FALSE.
>>> pft.setFalseIfStmt(['LFLAG1', 'LFLAG2'], simplify=True)

Before:
    IF (LDEBUG) THEN
        PRINT*, "Debug info"
    END IF

After (LDEBUG set to .FALSE.):
    ! Block removed when simplify=True

Notes
-----
- Multiple flags in a single condition (e.g., LFLAG1 .AND. LFLAG2)
  result in removal of the entire condition.
- Works on both IF statements and IF constructs.

Definition at line 1272 of file statements.py.

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following file: