Reference Guide  2.5.0
psyclone.psyir.frontend.fparser2.Fparser2Reader Class Reference

Classes

class  SelectTypeInfo
 

Public Member Functions

def __init__ (self)
 
def generate_psyir (self, parse_tree)
 
def generate_container (self, module_ast)
 
def get_routine_schedules (self, name, module_ast)
 
def process_declarations (self, parent, nodes, arg_list, visibility_map=None)
 
def process_nodes (self, parent, nodes)
 

Static Public Member Functions

def nodes_to_code_block (parent, fp2_nodes, message=None)
 
def process_access_statements (nodes)
 

Public Attributes

 handlers
 

Static Public Attributes

 unary_operators
 
 binary_operators
 

Detailed Description

Class to encapsulate the functionality for processing the fparser2 AST and
convert the nodes to PSyIR.

Definition at line 1025 of file fparser2.py.

Member Function Documentation

◆ generate_container()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.generate_container (   self,
  module_ast 
)
Create a Container from the supplied fparser2 module AST.

:param module_ast: fparser2 AST of the full module.
:type module_ast: :py:class:`fparser.two.Fortran2003.Program`

:returns: PSyIR container representing the given module_ast or None \
          if there's no module in the parse tree.
:rtype: :py:class:`psyclone.psyir.nodes.Container`

:raises GenerationError: unable to generate a Container from the \
                         provided fpaser2 parse tree.

Definition at line 1224 of file fparser2.py.

1224  def generate_container(self, module_ast):
1225  '''
1226  Create a Container from the supplied fparser2 module AST.
1227 
1228  :param module_ast: fparser2 AST of the full module.
1229  :type module_ast: :py:class:`fparser.two.Fortran2003.Program`
1230 
1231  :returns: PSyIR container representing the given module_ast or None \
1232  if there's no module in the parse tree.
1233  :rtype: :py:class:`psyclone.psyir.nodes.Container`
1234 
1235  :raises GenerationError: unable to generate a Container from the \
1236  provided fpaser2 parse tree.
1237  '''
1238  # Assume just 1 or 0 Fortran module definitions in the file
1239  modules = walk(module_ast, Fortran2003.Module_Stmt)
1240  if len(modules) > 1:
1241  raise GenerationError(
1242  f"Could not process {module_ast}. Just one module definition "
1243  f"per file supported.")
1244  if not modules:
1245  return None
1246 
1247  module = modules[0].parent
1248  mod_name = str(modules[0].children[1])
1249 
1250  # Create a container to capture the module information
1251  new_container = Container(mod_name)
1252 
1253  # Search for any accessibility statements (e.g. "PUBLIC :: my_var") to
1254  # determine the default accessibility of symbols as well as identifying
1255  # those that are explicitly declared as public or private.
1256  (default_visibility, visibility_map) = self.process_access_statements(
1257  module)
1258  new_container.symbol_table.default_visibility = default_visibility
1259 
1260  # Create symbols for all routines defined within this module
1261  _process_routine_symbols(module_ast, new_container.symbol_table,
1262  visibility_map)
1263 
1264  # Parse the declarations if it has any
1265  for child in module.children:
1266  if isinstance(child, Fortran2003.Specification_Part):
1267  self.process_declarations(new_container, child.children,
1268  [], visibility_map)
1269  break
1270 
1271  return new_container
1272 

References psyclone.psyir.frontend.fparser2.Fparser2Reader.process_access_statements(), and psyclone.psyir.frontend.fparser2.Fparser2Reader.process_declarations().

Here is the call graph for this function:

◆ generate_psyir()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.generate_psyir (   self,
  parse_tree 
)
Translate the supplied fparser2 parse_tree into PSyIR.

:param parse_tree: the supplied fparser2 parse tree.
:type parse_tree: :py:class:`fparser.two.Fortran2003.Program`

:returns: PSyIR representation of the supplied fparser2 parse_tree.
:rtype: :py:class:`psyclone.psyir.nodes.Container` or \
    :py:class:`psyclone.psyir.nodes.Routine`

:raises GenerationError: if the root of the supplied fparser2 \
    parse tree is not a Program.

Definition at line 1199 of file fparser2.py.

1199  def generate_psyir(self, parse_tree):
1200  '''Translate the supplied fparser2 parse_tree into PSyIR.
1201 
1202  :param parse_tree: the supplied fparser2 parse tree.
1203  :type parse_tree: :py:class:`fparser.two.Fortran2003.Program`
1204 
1205  :returns: PSyIR representation of the supplied fparser2 parse_tree.
1206  :rtype: :py:class:`psyclone.psyir.nodes.Container` or \
1207  :py:class:`psyclone.psyir.nodes.Routine`
1208 
1209  :raises GenerationError: if the root of the supplied fparser2 \
1210  parse tree is not a Program.
1211 
1212  '''
1213  if not isinstance(parse_tree, Fortran2003.Program):
1214  raise GenerationError(
1215  f"The Fparser2Reader generate_psyir method expects the root "
1216  f"of the supplied fparser2 tree to be a Program, but found "
1217  f"'{type(parse_tree).__name__}'")
1218 
1219  node = Container("dummy")
1220  self.process_nodes(node, [parse_tree])
1221  result = node.children[0]
1222  return result.detach()
1223 

References psyclone.psyir.frontend.fparser2.Fparser2Reader.process_nodes().

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

◆ get_routine_schedules()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.get_routine_schedules (   self,
  name,
  module_ast 
)
Create one or more schedules for routines corresponding to the
supplied name in the supplied fparser2 AST. (There can be more than
one routine if the supplied name corresponds to an interface block
in the AST.)

:param str name: name of the subroutine represented by the kernel.
:param module_ast: fparser2 AST of the full module where the kernel \
                   code is located.
:type module_ast: :py:class:`fparser.two.Fortran2003.Program`

:returns: PSyIR schedules representing the matching subroutine(s).
:rtype: List[:py:class:`psyclone.psyir.nodes.KernelSchedule`]

:raises GenerationError: if supplied parse tree contains more than \
                         one module.
:raises GenerationError: unable to generate a kernel schedule from \
                         the provided fpaser2 parse tree.

Definition at line 1273 of file fparser2.py.

1273  def get_routine_schedules(self, name, module_ast):
1274  '''Create one or more schedules for routines corresponding to the
1275  supplied name in the supplied fparser2 AST. (There can be more than
1276  one routine if the supplied name corresponds to an interface block
1277  in the AST.)
1278 
1279  :param str name: name of the subroutine represented by the kernel.
1280  :param module_ast: fparser2 AST of the full module where the kernel \
1281  code is located.
1282  :type module_ast: :py:class:`fparser.two.Fortran2003.Program`
1283 
1284  :returns: PSyIR schedules representing the matching subroutine(s).
1285  :rtype: List[:py:class:`psyclone.psyir.nodes.KernelSchedule`]
1286 
1287  :raises GenerationError: if supplied parse tree contains more than \
1288  one module.
1289  :raises GenerationError: unable to generate a kernel schedule from \
1290  the provided fpaser2 parse tree.
1291 
1292  '''
1293  psyir = self.generate_psyir(module_ast)
1294  lname = name.lower()
1295 
1296  containers = [ctr for ctr in psyir.walk(Container) if
1297  not isinstance(ctr, FileContainer)]
1298  if not containers:
1299  raise GenerationError(
1300  f"The parse tree supplied to get_routine_schedules() must "
1301  f"contain a single module but found none when searching for "
1302  f"kernel '{name}'.")
1303  if len(containers) > 1:
1304  raise GenerationError(
1305  f"The parse tree supplied to get_routine_schedules() must "
1306  f"contain a single module but found more than one "
1307  f"({[ctr.name for ctr in containers]}) when searching for "
1308  f"kernel '{name}'.")
1309  container = containers[0]
1310 
1311  # Check for an interface block
1312  actual_names = []
1313  interfaces = walk(module_ast, Fortran2003.Interface_Block)
1314 
1315  for interface in interfaces:
1316  if interface.children[0].children[0].string.lower() == lname:
1317  # We have an interface block with the name of the routine
1318  # we are searching for.
1319  procs = walk(interface, Fortran2003.Procedure_Stmt)
1320  for proc in procs:
1321  for child in proc.children[0].children:
1322  actual_names.append(child.string.lower())
1323  break
1324  if not actual_names:
1325  # No interface block was found so we proceed to search for a
1326  # routine with the original name that we were passed.
1327  actual_names = [lname]
1328 
1329  routines = container.walk(Routine)
1330  selected_routines = [routine for routine in routines
1331  if routine.name.lower() in actual_names]
1332 
1333  if not selected_routines:
1334  raise GenerationError(
1335  f"Could not find subroutine or interface '{name}' in the "
1336  f"module '{container.name}'.")
1337 
1338  return selected_routines
1339 

References psyclone.psyir.frontend.fparser2.Fparser2Reader.generate_psyir().

Here is the call graph for this function:

◆ nodes_to_code_block()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.nodes_to_code_block (   parent,
  fp2_nodes,
  message = None 
)
static
Create a CodeBlock for the supplied list of fparser2 nodes and then
wipe the list. A CodeBlock is a node in the PSyIR (Schedule)
that represents a sequence of one or more Fortran statements
and/or expressions which PSyclone does not attempt to handle.

:param parent: Node in the PSyclone AST to which to add this CodeBlock.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:param fp2_nodes: list of fparser2 AST nodes constituting the
                  CodeBlock.
:type fp2_nodes: list of :py:class:`fparser.two.utils.Base`
:param message: Include a preceeding comment attached to the CodeBlock.
:type message: Optional[str]

:returns: a CodeBlock instance.
:rtype: :py:class:`psyclone.CodeBlock`

Definition at line 1156 of file fparser2.py.

1156  def nodes_to_code_block(parent, fp2_nodes, message=None):
1157  '''Create a CodeBlock for the supplied list of fparser2 nodes and then
1158  wipe the list. A CodeBlock is a node in the PSyIR (Schedule)
1159  that represents a sequence of one or more Fortran statements
1160  and/or expressions which PSyclone does not attempt to handle.
1161 
1162  :param parent: Node in the PSyclone AST to which to add this CodeBlock.
1163  :type parent: :py:class:`psyclone.psyir.nodes.Node`
1164  :param fp2_nodes: list of fparser2 AST nodes constituting the
1165  CodeBlock.
1166  :type fp2_nodes: list of :py:class:`fparser.two.utils.Base`
1167  :param message: Include a preceeding comment attached to the CodeBlock.
1168  :type message: Optional[str]
1169 
1170  :returns: a CodeBlock instance.
1171  :rtype: :py:class:`psyclone.CodeBlock`
1172 
1173  '''
1174  if not fp2_nodes:
1175  return None
1176 
1177  # Determine whether this code block is a statement or an
1178  # expression. Statements always have a `Schedule` as parent
1179  # and expressions do not. The only unknown at this point are
1180  # directives whose structure are in discussion. Therefore, for
1181  # the moment, an exception is raised if a directive is found
1182  # as a parent.
1183  if isinstance(parent, (Schedule, Container)):
1184  structure = CodeBlock.Structure.STATEMENT
1185  elif isinstance(parent, Directive):
1186  raise InternalError(
1187  "Fparser2Reader:nodes_to_code_block: A CodeBlock with "
1188  "a Directive as parent is not yet supported.")
1189  else:
1190  structure = CodeBlock.Structure.EXPRESSION
1191 
1192  code_block = CodeBlock(fp2_nodes, structure, parent=parent)
1193  if message:
1194  code_block.preceding_comment = message
1195  parent.addchild(code_block)
1196  del fp2_nodes[:]
1197  return code_block
1198 
Here is the caller graph for this function:

◆ process_access_statements()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.process_access_statements (   nodes)
static
Search the supplied list of fparser2 nodes (which must represent a
complete Specification Part) for any accessibility
statements (e.g. "PUBLIC :: my_var") to determine the default
visibility of symbols as well as identifying those that are
explicitly declared as public or private.

:param nodes: nodes in the fparser2 parse tree describing a \
              Specification Part that will be searched.
:type nodes: list of :py:class:`fparser.two.utils.Base`

:returns: default visibility of symbols within the current scoping \
    unit and dict of symbol names with explicit visibilities.
:rtype: 2-tuple of (:py:class:`psyclone.symbols.Symbol.Visibility`, \
        dict)

:raises InternalError: if an accessibility attribute which is not \
    'public' or 'private' is encountered.
:raises GenerationError: if the parse tree is found to contain more \
    than one bare accessibility statement (i.e. 'PUBLIC' or 'PRIVATE')
:raises GenerationError: if a symbol is explicitly declared as being \
    both public and private.

Definition at line 1486 of file fparser2.py.

1486  def process_access_statements(nodes):
1487  '''
1488  Search the supplied list of fparser2 nodes (which must represent a
1489  complete Specification Part) for any accessibility
1490  statements (e.g. "PUBLIC :: my_var") to determine the default
1491  visibility of symbols as well as identifying those that are
1492  explicitly declared as public or private.
1493 
1494  :param nodes: nodes in the fparser2 parse tree describing a \
1495  Specification Part that will be searched.
1496  :type nodes: list of :py:class:`fparser.two.utils.Base`
1497 
1498  :returns: default visibility of symbols within the current scoping \
1499  unit and dict of symbol names with explicit visibilities.
1500  :rtype: 2-tuple of (:py:class:`psyclone.symbols.Symbol.Visibility`, \
1501  dict)
1502 
1503  :raises InternalError: if an accessibility attribute which is not \
1504  'public' or 'private' is encountered.
1505  :raises GenerationError: if the parse tree is found to contain more \
1506  than one bare accessibility statement (i.e. 'PUBLIC' or 'PRIVATE')
1507  :raises GenerationError: if a symbol is explicitly declared as being \
1508  both public and private.
1509 
1510  '''
1511  default_visibility = None
1512  # Sets holding the names of those symbols whose access is specified
1513  # explicitly via an access-stmt (e.g. "PUBLIC :: my_var")
1514  explicit_public = set()
1515  explicit_private = set()
1516  # R518 an access-stmt shall appear only in the specification-part
1517  # of a *module*.
1518  access_stmts = walk(nodes, Fortran2003.Access_Stmt)
1519 
1520  for stmt in access_stmts:
1521 
1522  if stmt.children[0].lower() == "public":
1523  public_stmt = True
1524  elif stmt.children[0].lower() == "private":
1525  public_stmt = False
1526  else:
1527  raise InternalError(
1528  f"Failed to process '{stmt}'. Found an accessibility "
1529  f"attribute of '{stmt.children[0]}' but expected either "
1530  f"'public' or 'private'.")
1531  if not stmt.children[1]:
1532  if default_visibility:
1533  # We've already seen an access statement without an
1534  # access-id-list. This is therefore invalid Fortran (which
1535  # fparser does not catch).
1536  current_node = stmt.parent
1537  while current_node:
1538  if isinstance(current_node, Fortran2003.Module):
1539  mod_name = str(
1540  current_node.children[0].children[1])
1541  raise GenerationError(
1542  f"Module '{mod_name}' contains more than one "
1543  f"access statement with an omitted "
1544  f"access-id-list. This is invalid Fortran.")
1545  current_node = current_node.parent
1546  # Failed to find an enclosing Module. This is also invalid
1547  # Fortran since an access statement is only permitted
1548  # within a module.
1549  raise GenerationError(
1550  "Found multiple access statements with omitted access-"
1551  "id-lists and no enclosing Module. Both of these "
1552  "things are invalid Fortran.")
1553  if public_stmt:
1554  default_visibility = Symbol.Visibility.PUBLIC
1555  else:
1556  default_visibility = Symbol.Visibility.PRIVATE
1557  else:
1558  symbol_names = [child.string.lower() for child in
1559  stmt.children[1].children]
1560  if public_stmt:
1561  explicit_public.update(symbol_names)
1562  else:
1563  explicit_private.update(symbol_names)
1564  # Sanity check the lists of symbols (because fparser2 does not
1565  # currently do much validation)
1566  invalid_symbols = explicit_public.intersection(explicit_private)
1567  if invalid_symbols:
1568  raise GenerationError(
1569  f"Symbols {list(invalid_symbols)} appear in access statements "
1570  f"with both PUBLIC and PRIVATE access-ids. This is invalid "
1571  f"Fortran.")
1572 
1573  # Symbols are public by default in Fortran
1574  if default_visibility is None:
1575  default_visibility = Symbol.Visibility.PUBLIC
1576 
1577  visibility_map = {}
1578  for name in explicit_public:
1579  visibility_map[name] = Symbol.Visibility.PUBLIC
1580  for name in explicit_private:
1581  visibility_map[name] = Symbol.Visibility.PRIVATE
1582 
1583  return (default_visibility, visibility_map)
1584 

References psyclone.psyir.frontend.fparser2.Fparser2Reader._parse_dimensions(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_decln(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_precision(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_type_spec(), and psyclone.psyir.frontend.fparser2.Fparser2Reader.process_nodes().

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

◆ process_declarations()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.process_declarations (   self,
  parent,
  nodes,
  arg_list,
  visibility_map = None 
)
Transform the variable declarations in the fparser2 parse tree into
symbols in the symbol table of the PSyIR parent node. The default
visibility of any new symbol is taken from the symbol table associated
with the `parent` node if necessary. The `visibility_map` provides
information on any explicit symbol visibilities that are specified
for the declarations.

:param parent: PSyIR node in which to insert the symbols found.
:type parent: :py:class:`psyclone.psyir.nodes.KernelSchedule`
:param nodes: fparser2 AST nodes containing declaration statements.
:type nodes: List[:py:class:`fparser.two.utils.Base`]
:param arg_list: fparser2 AST node containing the argument list.
:type arg_list: :py:class:`fparser.Fortran2003.Dummy_Arg_List`
:param visibility_map: mapping of symbol names to explicit
    visibilities.
:type visibility_map: dict[
    str, :py:class:`psyclone.psyir.symbols.Symbol.Visibility`]

:raises GenerationError: if an INCLUDE statement is encountered.
:raises NotImplementedError: the provided declarations contain
    attributes which are not supported yet.
:raises GenerationError: if the parse tree for a USE statement does
    not have the expected structure.
:raises SymbolError: if a declaration is found for a Symbol that is
    already in the symbol table with a defined interface.
:raises InternalError: if the provided declaration is an unexpected
    or invalid fparser or Fortran expression.

Definition at line 2505 of file fparser2.py.

2506  visibility_map=None):
2507  '''
2508  Transform the variable declarations in the fparser2 parse tree into
2509  symbols in the symbol table of the PSyIR parent node. The default
2510  visibility of any new symbol is taken from the symbol table associated
2511  with the `parent` node if necessary. The `visibility_map` provides
2512  information on any explicit symbol visibilities that are specified
2513  for the declarations.
2514 
2515  :param parent: PSyIR node in which to insert the symbols found.
2516  :type parent: :py:class:`psyclone.psyir.nodes.KernelSchedule`
2517  :param nodes: fparser2 AST nodes containing declaration statements.
2518  :type nodes: List[:py:class:`fparser.two.utils.Base`]
2519  :param arg_list: fparser2 AST node containing the argument list.
2520  :type arg_list: :py:class:`fparser.Fortran2003.Dummy_Arg_List`
2521  :param visibility_map: mapping of symbol names to explicit
2522  visibilities.
2523  :type visibility_map: dict[
2524  str, :py:class:`psyclone.psyir.symbols.Symbol.Visibility`]
2525 
2526  :raises GenerationError: if an INCLUDE statement is encountered.
2527  :raises NotImplementedError: the provided declarations contain
2528  attributes which are not supported yet.
2529  :raises GenerationError: if the parse tree for a USE statement does
2530  not have the expected structure.
2531  :raises SymbolError: if a declaration is found for a Symbol that is
2532  already in the symbol table with a defined interface.
2533  :raises InternalError: if the provided declaration is an unexpected
2534  or invalid fparser or Fortran expression.
2535 
2536  '''
2537  if visibility_map is None:
2538  visibility_map = {}
2539 
2540  # Look at any USE statements
2541  self._process_use_stmts(parent, nodes, visibility_map)
2542 
2543  # Look at any SAVE statements to determine any static symbols.
2544  statics_list = self._process_save_statements(nodes, parent)
2545 
2546  # Handle any derived-type declarations/definitions before we look
2547  # at general variable declarations in case any of the latter use
2548  # the former.
2549  for decl in walk(nodes, Fortran2003.Derived_Type_Def):
2550  self._process_derived_type_decln(parent, decl, visibility_map)
2551 
2552  # INCLUDE statements are *not* part of the Fortran language and
2553  # can appear anywhere. Therefore we have to do a walk to make sure we
2554  # find them if they are present.
2555  incl_nodes = walk(nodes, (Fortran2003.Include_Stmt,
2556  C99Preprocessor.Cpp_Include_Stmt))
2557  if incl_nodes:
2558  # The include_handler just raises an error so we use that to
2559  # reduce code duplication.
2560  self._include_handler(incl_nodes[0], parent)
2561 
2562  # Now we've captured any derived-type definitions, proceed to look
2563  # at the variable declarations.
2564  for node in nodes:
2565 
2566  if isinstance(node, Fortran2003.Interface_Block):
2567 
2568  self._process_interface_block(node, parent.symbol_table,
2569  visibility_map)
2570 
2571  elif isinstance(node, Fortran2003.Type_Declaration_Stmt):
2572  try:
2573  self._process_decln(parent, parent.symbol_table, node,
2574  visibility_map, statics_list)
2575  except NotImplementedError:
2576  # Found an unsupported variable declaration. Create a
2577  # DataSymbol with UnsupportedType for each entity being
2578  # declared. Currently this means that any symbols that come
2579  # after an unsupported declaration will also have
2580  # UnsupportedType. This is the subject of Issue #791.
2581  specs = walk(node, Fortran2003.Access_Spec)
2582  if specs:
2583  decln_vis = _process_access_spec(specs[0])
2584  else:
2585  decln_vis = parent.symbol_table.default_visibility
2586 
2587  orig_children = list(node.children[2].children[:])
2588  for child in orig_children:
2589  # Modify the fparser2 parse tree so that it only
2590  # declares the current entity. `items` is a tuple and
2591  # thus immutable so we create a new one.
2592  node.children[2].items = (child,)
2593  symbol_name = str(child.children[0]).lower()
2594  vis = visibility_map.get(symbol_name, decln_vis)
2595 
2596  # Check whether the symbol we're about to add
2597  # corresponds to the routine we're currently inside. If
2598  # it does then we remove the RoutineSymbol in order to
2599  # free the exact name for the DataSymbol, but we keep
2600  # the tag to reintroduce it to the new symbol.
2601  tag = None
2602  try:
2603  routine_sym = parent.symbol_table.lookup_with_tag(
2604  "own_routine_symbol")
2605  if routine_sym.name.lower() == symbol_name:
2606  parent.symbol_table.remove(routine_sym)
2607  tag = "own_routine_symbol" # Keep the tag
2608  except KeyError:
2609  pass
2610 
2611  # Try to extract partial datatype information.
2612  datatype, init = self._get_partial_datatype(
2613  node, parent, visibility_map)
2614 
2615  # If a declaration declares multiple entities, it's
2616  # possible that some may have already been processed
2617  # successfully and thus be in the symbol table.
2618  try:
2619  parent.symbol_table.add(
2620  DataSymbol(
2621  symbol_name, UnsupportedFortranType(
2622  str(node),
2623  partial_datatype=datatype),
2624  interface=UnknownInterface(),
2625  visibility=vis,
2626  initial_value=init),
2627  tag=tag)
2628 
2629  except KeyError as err:
2630  if len(orig_children) == 1:
2631  raise SymbolError(
2632  f"Error while processing unsupported "
2633  f"declaration ('{node}'). An entry for "
2634  f"symbol '{symbol_name}' is already in "
2635  f"the symbol table.") from err
2636  # Restore the fparser2 parse tree
2637  node.children[2].items = tuple(orig_children)
2638 
2639  elif isinstance(node, (Fortran2003.Access_Stmt,
2640  Fortran2003.Save_Stmt,
2641  Fortran2003.Derived_Type_Def,
2642  Fortran2003.Stmt_Function_Stmt,
2643  Fortran2003.Common_Stmt,
2644  Fortran2003.Use_Stmt)):
2645  # These node types are handled separately
2646  pass
2647 
2648  elif isinstance(node, Fortran2003.Implicit_Part):
2649  # Anything other than a PARAMETER statement or an
2650  # IMPLICIT NONE means we can't handle this code.
2651  # Any PARAMETER statements are handled separately by the
2652  # call to _process_parameter_stmts below.
2653  # Any ENTRY statements are checked for in _subroutine_handler.
2654  child_nodes = walk(node, Fortran2003.Format_Stmt)
2655  if child_nodes:
2656  raise NotImplementedError(
2657  f"Error processing implicit-part: Format statements "
2658  f"are not supported but found '{child_nodes[0]}'")
2659  child_nodes = walk(node, Fortran2003.Implicit_Stmt)
2660  if any(imp.children != ('NONE',) for imp in child_nodes):
2661  raise NotImplementedError(
2662  f"Error processing implicit-part: implicit variable "
2663  f"declarations not supported but found '{node}'")
2664 
2665  elif isinstance(node, Fortran2003.Namelist_Stmt):
2666  # Place the declaration statement into the symbol table using
2667  # an internal symbol name. In case that we need more details
2668  # (e.g. to update symbol information), the following code
2669  # loops over namelist and each symbol:
2670  # for namelist_object in node.children:
2671  # for symbol_name in namelist_object[1].items:
2672  parent.symbol_table.new_symbol(
2673  root_name="_PSYCLONE_INTERNAL_NAMELIST",
2674  symbol_type=DataSymbol,
2675  datatype=UnsupportedFortranType(str(node)))
2676  else:
2677  raise NotImplementedError(
2678  f"Error processing declarations: fparser2 node of type "
2679  f"'{type(node).__name__}' not supported")
2680 
2681  # Process the nodes again, looking for PARAMETER statements. This is
2682  # done after the main declarations loop because they modify existing
2683  # symbols and can appear in any order.
2684  self._process_parameter_stmts(nodes, parent)
2685 
2686  # We process the nodes again looking for common blocks.
2687  # We do this here, after the main declarations loop, because they
2688  # modify the interface of existing symbols and can appear in any order.
2689  self._process_common_blocks(nodes, parent)
2690 
2691  if visibility_map is not None:
2692  # Check for symbols named in an access statement but not explicitly
2693  # declared. These must then refer to symbols that have been brought
2694  # into scope by an unqualified use statement.
2695  for name, vis in visibility_map.items():
2696  if name not in parent.symbol_table:
2697  # This call creates a Symbol and inserts it in the
2698  # appropriate symbol table.
2699  _find_or_create_unresolved_symbol(parent, name,
2700  visibility=vis)
2701  try:
2702  arg_symbols = []
2703  # Ensure each associated symbol has the correct interface info.
2704  for arg_name in [x.string.lower() for x in arg_list]:
2705  symbol = parent.symbol_table.lookup(arg_name)
2706  if not symbol.is_argument:
2707  # We didn't previously know that this Symbol was an
2708  # argument (as it had no 'intent' qualifier). Mark
2709  # that it is an argument by specifying its interface.
2710  # Although a Fortran argument has intent(inout) by default,
2711  # specifying this for an argument that is actually read
2712  # only (and is declared as such in the caller) causes
2713  # gfortran to complain. We therefore specify that the
2714  # access is unknown at this stage.
2715  symbol.interface = ArgumentInterface(
2716  ArgumentInterface.Access.UNKNOWN)
2717  arg_symbols.append(symbol)
2718  # Now that we've updated the Symbols themselves, set the
2719  # argument list
2720  parent.symbol_table.specify_argument_list(arg_symbols)
2721  except KeyError as info:
2722  decls_str_list = [str(node) for node in nodes]
2723  arg_str_list = [arg.string.lower() for arg in arg_list]
2724  raise InternalError(
2725  f"The argument list {arg_str_list} for routine '{parent.name}'"
2726  f" does not match the variable declarations:\n"
2727  f"{os.linesep.join(decls_str_list)}\n"
2728  f"(Note that PSyclone does not support implicit declarations.)"
2729  f" Specific PSyIR error is {info}.") from info
2730 
2731  # fparser2 does not always handle Statement Functions correctly, this
2732  # loop checks for Stmt_Functions that should be an array statement
2733  # and recovers them, otherwise it raises an error as currently
2734  # Statement Functions are not supported in PSyIR.
2735  for stmtfn in walk(nodes, Fortran2003.Stmt_Function_Stmt):
2736  (fn_name, arg_list, scalar_expr) = stmtfn.items
2737  try:
2738  symbol = parent.symbol_table.lookup(fn_name.string.lower())
2739  if symbol.is_array:
2740  # This is an array assignment wrongly categorized as a
2741  # statement_function by fparser2.
2742  array_subscript = arg_list.items
2743 
2744  assignment_rhs = scalar_expr
2745 
2746  # Create assignment node
2747  assignment = Assignment(parent=parent)
2748  parent.addchild(assignment)
2749 
2750  # Build lhs
2751  lhs = ArrayReference(symbol, parent=assignment)
2752  self.process_nodes(parent=lhs, nodes=array_subscript)
2753  assignment.addchild(lhs)
2754 
2755  # Build rhs
2756  self.process_nodes(parent=assignment,
2757  nodes=[assignment_rhs])
2758  else:
2759  raise InternalError(
2760  f"Could not process '{stmtfn}'. Symbol "
2761  f"'{symbol.name}' is in the SymbolTable but it is not "
2762  f"an array as expected, so it can not be recovered as "
2763  f"an array assignment.")
2764  except KeyError as err:
2765  raise NotImplementedError(
2766  f"Could not process '{stmtfn}'. Statement Function "
2767  f"declarations are not supported.") from err
2768 

References psyclone.psyir.frontend.fparser2.Fparser2Reader._get_partial_datatype(), psyclone.psyir.frontend.fparser2.Fparser2Reader._include_handler(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_common_blocks(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_decln(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_derived_type_decln(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_interface_block(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_parameter_stmts(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_save_statements(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_use_stmts(), and psyclone.psyir.frontend.fparser2.Fparser2Reader.process_nodes().

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

◆ process_nodes()

def psyclone.psyir.frontend.fparser2.Fparser2Reader.process_nodes (   self,
  parent,
  nodes 
)
Create the PSyIR of the supplied list of nodes in the
fparser2 AST.

:param parent: Parent node in the PSyIR we are constructing.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:param nodes: List of sibling nodes in fparser2 AST.
:type nodes: list[:py:class:`fparser.two.utils.Base`]

Definition at line 2894 of file fparser2.py.

2894  def process_nodes(self, parent, nodes):
2895  '''
2896  Create the PSyIR of the supplied list of nodes in the
2897  fparser2 AST.
2898 
2899  :param parent: Parent node in the PSyIR we are constructing.
2900  :type parent: :py:class:`psyclone.psyir.nodes.Node`
2901  :param nodes: List of sibling nodes in fparser2 AST.
2902  :type nodes: list[:py:class:`fparser.two.utils.Base`]
2903 
2904  '''
2905  code_block_nodes = []
2906  message = "PSyclone CodeBlock (unsupported code) reason:"
2907  for child in nodes:
2908  try:
2909  psy_child = self._create_child(child, parent)
2910  except NotImplementedError as err:
2911  # If child type implementation not found, add them on the
2912  # ongoing code_block node list.
2913  message += "\n - " + str(err)
2914  code_block_nodes.append(child)
2915  if not isinstance(parent, Schedule):
2916  # If we're not processing a statement then we create a
2917  # separate CodeBlock for each node in the parse tree.
2918  # (Otherwise it is hard to correctly reconstruct e.g.
2919  # the arguments to a Call.)
2920  self.nodes_to_code_block(parent, code_block_nodes, message)
2921  message = "PSyclone CodeBlock (unsupported code) reason:"
2922  else:
2923  if psy_child:
2924  self.nodes_to_code_block(parent, code_block_nodes, message)
2925  message = "PSyclone CodeBlock (unsupported code) reason:"
2926  parent.addchild(psy_child)
2927  # If psy_child is not initialised but it didn't produce a
2928  # NotImplementedError, it means it is safe to ignore it.
2929 
2930  # Complete any unfinished code-block
2931  self.nodes_to_code_block(parent, code_block_nodes, message)
2932 

References psyclone.psyir.frontend.fparser2.Fparser2Reader._add_target_attribute(), psyclone.psyir.frontend.fparser2.Fparser2Reader._array_notation_rank(), psyclone.psyir.frontend.fparser2.Fparser2Reader._array_syntax_to_indexed(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_bounded_loop(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_child(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_ifblock_for_select_type_content(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_loop(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_select_type(), psyclone.psyir.frontend.fparser2.Fparser2Reader._create_select_type_info(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_args(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_case_value(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_case_value_list(), psyclone.psyir.frontend.fparser2.Fparser2Reader._process_type_spec(), psyclone.psyir.frontend.fparser2.Fparser2Reader.handlers, psyclone.psyir.frontend.fparser2.Fparser2Reader.nodes_to_code_block(), psyclone.psyir.frontend.fparser2.Fparser2Reader.process_access_statements(), psyclone.psyir.frontend.fparser2.Fparser2Reader.process_declarations(), and psyclone.psyir.frontend.fparser2.Fparser2Reader.process_nodes().

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

Member Data Documentation

◆ binary_operators

psyclone.psyir.frontend.fparser2.Fparser2Reader.binary_operators
static
Initial value:
= OrderedDict([
('+', BinaryOperation.Operator.ADD),
('-', BinaryOperation.Operator.SUB),
('*', BinaryOperation.Operator.MUL),
('/', BinaryOperation.Operator.DIV),
('**', BinaryOperation.Operator.POW),
('==', BinaryOperation.Operator.EQ),
('.eq.', BinaryOperation.Operator.EQ),
('.eqv.', BinaryOperation.Operator.EQV),
('/=', BinaryOperation.Operator.NE),
('.ne.', BinaryOperation.Operator.NE),
('.neqv.', BinaryOperation.Operator.NEQV),
('<=', BinaryOperation.Operator.LE),
('.le.', BinaryOperation.Operator.LE),
('<', BinaryOperation.Operator.LT),
('.lt.', BinaryOperation.Operator.LT),
('>=', BinaryOperation.Operator.GE),
('.ge.', BinaryOperation.Operator.GE),
('>', BinaryOperation.Operator.GT),
('.gt.', BinaryOperation.Operator.GT),
('.and.', BinaryOperation.Operator.AND),
('.or.', BinaryOperation.Operator.OR)])

Definition at line 1036 of file fparser2.py.

◆ unary_operators

psyclone.psyir.frontend.fparser2.Fparser2Reader.unary_operators
static
Initial value:
= OrderedDict([
('+', UnaryOperation.Operator.PLUS),
('-', UnaryOperation.Operator.MINUS),
('.not.', UnaryOperation.Operator.NOT)])

Definition at line 1031 of file fparser2.py.


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