fparser Reference Guide  0.0.14
fparser.two.utils.BlockBase Class Reference
Inheritance diagram for fparser.two.utils.BlockBase:
Collaboration diagram for fparser.two.utils.BlockBase:

Public Member Functions

def init (self, content)
 
def tostr (self)
 
def torepr (self)
 
def tofortran (self, tab="", isfix=None)
 
def restore_reader (self, reader)
 
- Public Member Functions inherited from fparser.two.utils.Base
def __init__ (self, string, parent_cls=None)
 
def __new__ (cls, string, parent_cls=None)
 
def get_root (self)
 
def children (self)
 
def init (self, items)
 
def torepr (self)
 
def __str__ (self)
 
def __repr__ (self)
 
def tofortran (self, tab="", isfix=None)
 
def restore_reader (self, reader)
 
- Public Member Functions inherited from fparser.two.utils.ComparableMixin
def __lt__ (self, other)
 
def __le__ (self, other)
 
def __eq__ (self, other)
 
def __ge__ (self, other)
 
def __gt__ (self, other)
 
def __ne__ (self, other)
 

Static Public Member Functions

def match (startcls, subclasses, endcls, reader, match_labels=False, match_names=False, match_name_classes=(), enable_do_label_construct_hook=False, enable_if_construct_hook=False, enable_where_construct_hook=False, strict_order=False, strict_match_names=False)
 

Public Attributes

 content
 
- Public Attributes inherited from fparser.two.utils.Base
 parent
 
 items
 

Additional Inherited Members

- Static Public Attributes inherited from fparser.two.utils.Base
 subclasses
 

Detailed Description

Base class for matching all block constructs.

<block-base> = [ <startcls> ]
                 [ <subcls> ]...
                 ...
                 [ <subcls> ]...
                 [ <endcls> ]

Definition at line 528 of file utils.py.

Member Function Documentation

◆ init()

def fparser.two.utils.BlockBase.init (   self,
  content 
)
Initialise the `content` attribute with the list of child nodes.

:param content: list of nodes that are children of this one.
:type content: list of :py:class:`fparser.two.utils.Base` or NoneType

Definition at line 789 of file utils.py.

References fparser.one.statements.GeneralAssignment.__class__, fparser.one.statements.Read.__class__, fparser.common.base_classes.BeginStatement.content, fparser.two.utils.BlockBase.content, fparser.one.statements.Forall.content, fparser.one.statements.Where.content, fparser.one.statements.Comment.content, fparser.one.statements.StatementWithNamelist.tofortran(), fparser.one.statements.GeneralAssignment.tofortran(), fparser.one.statements.Assign.tofortran(), fparser.one.block_statements.BeginSource.tofortran(), fparser.one.typedecl_statements.TypeDeclarationStatement.tofortran(), fparser.one.statements.Call.tofortran(), fparser.one.statements.Goto.tofortran(), fparser.one.statements.ComputedGoto.tofortran(), fparser.one.statements.AssignedGoto.tofortran(), fparser.one.statements.Continue.tofortran(), fparser.one.statements.Return.tofortran(), fparser.two.utils.Base.tofortran(), fparser.one.statements.Stop.tofortran(), fparser.one.statements.Print.tofortran(), fparser.one.statements.Read0.tofortran(), fparser.one.statements.Read1.tofortran(), fparser.one.statements.Write.tofortran(), fparser.one.typedecl_statements.Implicit.tofortran(), fparser.one.statements.Flush.tofortran(), fparser.one.statements.Wait.tofortran(), fparser.one.statements.Contains.tofortran(), fparser.one.statements.Allocate.tofortran(), fparser.common.base_classes.BeginStatement.tofortran(), fparser.one.statements.Deallocate.tofortran(), fparser.one.statements.ModuleProcedure.tofortran(), fparser.one.statements.Access.tofortran(), fparser.one.statements.Close.tofortran(), fparser.one.statements.Cycle.tofortran(), fparser.one.statements.FilePositioningStatement.tofortran(), fparser.common.base_classes.EndStatement.tofortran(), fparser.one.statements.Open.tofortran(), fparser.one.statements.Format.tofortran(), fparser.one.statements.Save.tofortran(), fparser.one.statements.Data.tofortran(), fparser.one.statements.Nullify.tofortran(), fparser.one.block_statements.If.tofortran(), fparser.one.statements.Use.tofortran(), fparser.one.statements.Exit.tofortran(), fparser.one.statements.Parameter.tofortran(), fparser.one.statements.Equivalence.tofortran(), fparser.one.statements.Dimension.tofortran(), fparser.one.statements.Target.tofortran(), fparser.one.statements.Pointer.tofortran(), fparser.one.statements.ArithmeticIf.tofortran(), fparser.one.statements.Inquire.tofortran(), fparser.one.statements.Sequence.tofortran(), fparser.one.statements.Namelist.tofortran(), fparser.one.statements.Common.tofortran(), fparser.one.statements.Intent.tofortran(), fparser.one.statements.Entry.tofortran(), fparser.one.statements.Forall.tofortran(), fparser.one.statements.SpecificBinding.tofortran(), fparser.one.statements.GenericBinding.tofortran(), fparser.one.statements.Allocatable.tofortran(), fparser.one.statements.Bind.tofortran(), fparser.one.statements.Else.tofortran(), fparser.one.statements.ElseIf.tofortran(), fparser.one.statements.Case.tofortran(), fparser.one.statements.TypeIs.tofortran(), fparser.one.statements.ClassIs.tofortran(), fparser.one.statements.Where.tofortran(), fparser.one.statements.ElseWhere.tofortran(), fparser.one.statements.Enumerator.tofortran(), fparser.one.statements.FortranName.tofortran(), fparser.one.statements.Threadsafe.tofortran(), fparser.one.statements.Depend.tofortran(), fparser.one.statements.Check.tofortran(), fparser.one.statements.CallStatement.tofortran(), fparser.one.statements.CallProtoArgument.tofortran(), fparser.one.statements.Pause.tofortran(), and fparser.one.statements.Comment.tofortran().

789  def init(self, content):
790  """
791  Initialise the `content` attribute with the list of child nodes.
792 
793  :param content: list of nodes that are children of this one.
794  :type content: list of :py:class:`fparser.two.utils.Base` or NoneType
795 
796  """
797  self.content = content
798 

◆ match()

def fparser.two.utils.BlockBase.match (   startcls,
  subclasses,
  endcls,
  reader,
  match_labels = False,
  match_names = False,
  match_name_classes = (),
  enable_do_label_construct_hook = False,
  enable_if_construct_hook = False,
  enable_where_construct_hook = False,
  strict_order = False,
  strict_match_names = False 
)
static
Checks whether the content in reader matches the given
type of block statement (e.g. DO..END DO, IF...END IF etc.)

:param type startcls: the class marking the beginning of the block
:param list subclasses: list of classes that can be children of \
                the block.
:param type endcls: the class marking the end of the block.
:param reader: content to check for match.
:type reader: str or instance of :py:class:`FortranReaderBase`
:param bool match_labels: whether or not the statement terminating \
    the block must have a label that matches the opening statement. \
    Default is False.
:param bool match_names: TBD
:param tuple match_name_classes: TBD
:param bool enable_do_label_construct_hook: TBD
:param bool enable_if_construct_hook: TBD
:param bool enable_where_construct_hook: TBD
:param bool strict_order: whether to enforce the order of the \
                  given subclasses.
:param bool strict_match_names: if start name present, end name \
                        must exist and match.

:return: instance of startcls or None if no match is found
:rtype: startcls

Definition at line 554 of file utils.py.

554  ):
555  """
556  Checks whether the content in reader matches the given
557  type of block statement (e.g. DO..END DO, IF...END IF etc.)
558 
559  :param type startcls: the class marking the beginning of the block
560  :param list subclasses: list of classes that can be children of \
561  the block.
562  :param type endcls: the class marking the end of the block.
563  :param reader: content to check for match.
564  :type reader: str or instance of :py:class:`FortranReaderBase`
565  :param bool match_labels: whether or not the statement terminating \
566  the block must have a label that matches the opening statement. \
567  Default is False.
568  :param bool match_names: TBD
569  :param tuple match_name_classes: TBD
570  :param bool enable_do_label_construct_hook: TBD
571  :param bool enable_if_construct_hook: TBD
572  :param bool enable_where_construct_hook: TBD
573  :param bool strict_order: whether to enforce the order of the \
574  given subclasses.
575  :param bool strict_match_names: if start name present, end name \
576  must exist and match.
577 
578  :return: instance of startcls or None if no match is found
579  :rtype: startcls
580 
581  """
582  # This implementation uses the DynamicImport class and its instance di
583  # to access the Fortran2003 and C99Preprocessor classes, this is a
584  # performance optimization to avoid importing the classes inside this
585  # method since it is in the hotpath (and it can't be done in the
586  # top-level due to circular dependencies).
587  assert isinstance(reader, FortranReaderBase), repr(reader)
588  content = []
589 
590  if startcls is not None:
591  # Deal with any preceding comments, includes, and/or directives
592  DynamicImport.add_comments_includes_directives(content, reader)
593  # Now attempt to match the start of the block
594  try:
595  obj = startcls(reader)
596  except NoMatchError:
597  obj = None
598  if obj is None:
599  # Ultimately we failed to find a match for the
600  # start of the block so put back any comments that
601  # we processed along the way
602  for obj in reversed(content):
603  obj.restore_reader(reader)
604  return
605  if startcls in SYMBOL_TABLES.scoping_unit_classes:
606  # We are entering a new scoping unit so create a new
607  # symbol table.
608  # NOTE: if the match subsequently fails then we must
609  # delete this symbol table.
610  table_name = str(obj.children[1])
611  SYMBOL_TABLES.enter_scope(table_name)
612  # Store the index of the start of this block proper (i.e.
613  # excluding any comments)
614  start_idx = len(content)
615  content.append(obj)
616 
617  if hasattr(obj, "get_start_label") and enable_do_label_construct_hook:
618  start_label = obj.get_start_label()
619  if match_names:
620  start_name = obj.get_start_name()
621 
622  # Comments and Include statements are always valid sub-classes
623  classes = subclasses + [di.Comment, di.Include_Stmt]
624  # Preprocessor directives are always valid sub-classes
625  cpp_classes = [
626  getattr(di.C99Preprocessor, cls_name)
627  for cls_name in di.C99Preprocessor.CPP_CLASS_NAMES
628  ]
629  classes += cpp_classes
630  if endcls is not None:
631  classes += [endcls]
632  endcls_all = tuple([endcls] + endcls.subclasses[endcls.__name__])
633 
634  try:
635  # Start trying to match the various subclasses, starting from
636  # the beginning of the list (where else?)
637  i = 0
638  had_match = False
639  found_end = False
640  while i < len(classes):
641  if enable_do_label_construct_hook:
642  # Multiple, labelled DO statements can reference the
643  # same label.
644  obj = startcls(reader)
645  if obj is not None and hasattr(obj, "get_start_label"):
646  if start_label == obj.get_start_label():
647  content.append(obj)
648  continue
649  obj.restore_reader(reader)
650  # Attempt to match the i'th subclass
651  cls = classes[i]
652  try:
653  obj = cls(reader)
654  except NoMatchError:
655  obj = None
656  if obj is None:
657  # No match for this class, continue checking the list
658  # starting from the i+1'th...
659  i += 1
660  continue
661 
662  # We got a match for this class
663  had_match = True
664  content.append(obj)
665 
666  if match_names and isinstance(obj, match_name_classes):
667  end_name = obj.get_end_name()
668  if end_name and not start_name:
669  raise FortranSyntaxError(
670  reader,
671  f"Name '{end_name}' has no corresponding starting name",
672  )
673  if (
674  end_name
675  and start_name
676  and end_name.lower() != start_name.lower()
677  ):
678  raise FortranSyntaxError(
679  reader, f"Expecting name '{start_name}', got '{end_name}'"
680  )
681 
682  if endcls is not None and isinstance(obj, endcls_all):
683  if match_labels:
684  start_label, end_label = (
685  content[start_idx].get_start_label(),
686  content[-1].get_end_label(),
687  )
688  if start_label != end_label:
689  continue
690  if match_names:
691  start_name, end_name = (
692  content[start_idx].get_start_name(),
693  content[-1].get_end_name(),
694  )
695 
696  if end_name and not start_name:
697  raise FortranSyntaxError(
698  reader,
699  f"Name '{end_name}' has no corresponding starting name",
700  )
701  elif strict_match_names and start_name and not end_name:
702  raise FortranSyntaxError(
703  reader, f"Expecting name '{start_name}' but none given"
704  )
705  elif (
706  start_name
707  and end_name
708  and (start_name.lower() != end_name.lower())
709  ):
710  raise FortranSyntaxError(
711  reader,
712  f"Expecting name '{start_name}', got '{end_name}'",
713  )
714  # We've found the enclosing end statement so break out
715  found_end = True
716  break
717  if not strict_order:
718  # Return to start of classes list now that we've matched.
719  i = 0
720  if enable_if_construct_hook:
721  if isinstance(obj, di.Else_If_Stmt):
722  # Got an else-if so go back to start of possible
723  # classes to match
724  i = 0
725  if isinstance(obj, (di.Else_Stmt, di.End_If_Stmt)):
726  # Found end-if
727  enable_if_construct_hook = False
728  if enable_where_construct_hook:
729  if isinstance(obj, di.Masked_Elsewhere_Stmt):
730  i = 0
731  if isinstance(obj, (di.Elsewhere_Stmt, di.End_Where_Stmt)):
732  enable_where_construct_hook = False
733  continue
734 
735  except FortranSyntaxError as err:
736  # We hit trouble so clean up the symbol table
737  if startcls in SYMBOL_TABLES.scoping_unit_classes:
738  SYMBOL_TABLES.exit_scope()
739  # Remove any symbol table that we created
740  SYMBOL_TABLES.remove(table_name)
741  raise err
742 
743  if startcls in SYMBOL_TABLES.scoping_unit_classes:
744  SYMBOL_TABLES.exit_scope()
745 
746  if not had_match or endcls and not found_end:
747  # We did not get a match from any of the subclasses or
748  # failed to find the endcls
749  if endcls is not None:
750  if startcls in SYMBOL_TABLES.scoping_unit_classes:
751  # Remove any symbol table that we created
752  SYMBOL_TABLES.remove(table_name)
753  for obj in reversed(content):
754  obj.restore_reader(reader)
755  return None
756 
757  if not content:
758  # We can only get to here if startcls is None - if startcls is not
759  # None and fails to match then we will already have returned. If
760  # it is not None and matches then content will not be empty.
761  # Since startcls must be None, we won't have created a symbol
762  # table so we don't have to clean up.
763  return None
764 
765  if startcls is not None and endcls is not None:
766  # check names of start and end statements:
767  start_stmt = content[start_idx]
768  end_stmt = content[-1]
769  if (
770  isinstance(end_stmt, endcls_all)
771  and hasattr(end_stmt, "get_name")
772  and hasattr(start_stmt, "get_name")
773  ):
774  if end_stmt.get_name() is not None:
775  if (
776  start_stmt.get_name().string.lower()
777  != end_stmt.get_name().string.lower()
778  ):
779  end_stmt.item.reader.error(
780  "expected <%s-name> is %s but got %s. Ignoring."
781  % (
782  end_stmt.get_type().lower(),
783  start_stmt.get_name(),
784  end_stmt.get_name(),
785  )
786  )
787  return (content,)
788 
Here is the caller graph for this function:

◆ tofortran()

def fparser.two.utils.BlockBase.tofortran (   self,
  tab = "",
  isfix = None 
)
Create a string containing the Fortran representation of this class

:param str tab: indent to prefix to code.
:param bool isfix: whether or not to generate fixed-format code.

:return: Fortran representation of this class.
:rtype: str

Definition at line 809 of file utils.py.

References fparser.common.base_classes.BeginStatement.content, fparser.two.utils.BlockBase.content, fparser.one.statements.Forall.content, fparser.one.statements.Where.content, and fparser.one.statements.Comment.content.

809  def tofortran(self, tab="", isfix=None):
810  """
811  Create a string containing the Fortran representation of this class
812 
813  :param str tab: indent to prefix to code.
814  :param bool isfix: whether or not to generate fixed-format code.
815 
816  :return: Fortran representation of this class.
817  :rtype: str
818  """
819  mylist = []
820  start = self.content[0]
821  end = self.content[-1]
822  extra_tab = ""
823  if isinstance(end, EndStmtBase):
824  extra_tab = " "
825  if start is not None:
826  mylist.append(start.tofortran(tab=tab, isfix=isfix))
827  for item in self.content[1:-1]:
828  mylist.append(item.tofortran(tab=tab + extra_tab, isfix=isfix))
829  if len(self.content) > 1:
830  mylist.append(end.tofortran(tab=tab, isfix=isfix))
831  return "\n".join(mylist)
832 

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