fparser Reference Guide  0.0.14
fparser.common.readfortran.FortranReaderBase Class Reference
Inheritance diagram for fparser.common.readfortran.FortranReaderBase:

Public Member Functions

def __init__ (self, source, mode, ignore_comments)
 
def __repr__ (self)
 
def find_module_source_file (self, mod_name)
 
def set_format (self, mode)
 
def format (self)
 
def name (self)
 
def close_source (self)
 
def put_single_line (self, line)
 
def get_single_line (self, ignore_empty=False, ignore_comments=None)
 
def get_next_line (self, ignore_empty=False, ignore_comments=None)
 
def get_item (self, ignore_comments=None)
 
def put_item (self, item)
 
def __iter__ (self)
 
def __next__ (self)
 
def next (self, ignore_comments=None)
 
def line_item (self, line, startlineno, endlineno, label, name, errmessage=None)
 
def multiline_item (self, prefix, lines, suffix, startlineno, endlineno, errmessage=None)
 
def comment_item (self, comment, startlineno, endlineno)
 
def cpp_directive_item (self, line, startlineno, endlineno)
 
def format_message (self, kind, message, startlineno, endlineno, startcolno=0, endcolno=-1)
 
def format_error_message (self, message, startlineno, endlineno, startcolno=0, endcolno=-1)
 
def format_warning_message (self, message, startlineno, endlineno, startcolno=0, endcolno=-1)
 
def info (self, message, item=None)
 
def error (self, message, item=None)
 
def warning (self, message, item=None)
 
def handle_cpp_directive (self, line)
 
def handle_cf2py_start (self, line)
 
def handle_inline_comment (self, line, lineno, quotechar=None)
 
def handle_multilines (self, line, startlineno, mlstr)
 
def get_source_item (self)
 

Public Attributes

 source
 
 linecount
 
 isclosed
 
 filo_line
 
 fifo_item
 
 source_lines
 
 f2py_comment_lines
 
 reader
 
 include_dirs
 
 source_only
 
 exit_on_error
 
 restore_cache
 

Detailed Description

Base class for reading Fortran sources.

A Fortran source must be a file-like object (have a ``.next()``
method) and it may hold Fortran 77 code, fixed format Fortran
code, free format Fortran code, or PYF signatures (with extended
free format Fortran syntax).

:param source: a file-like object with .next() method used to \
               retrive a line.
:type source: :py:class:`StringIO` or a file handle
:param mode: a FortranFormat object as returned by \
             `sourceinfo.get_source_info()`
:type mode: :py:class:`fparser.common.sourceinfo.Format`
:param bool isstrict: whether we are strictly enforcing fixed format.
:param bool ignore_comments: whether or not to discard comments.

The Fortran source is iterated by `get_single_line`,
`get_next_line`, `put_single_line` methods.

Definition at line 545 of file readfortran.py.

Member Function Documentation

◆ __iter__()

def fparser.common.readfortran.FortranReaderBase.__iter__ (   self)
Make FortranReader an iterator.

Definition at line 763 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.next().

763  def __iter__(self):
764  """Make FortranReader an iterator."""
765  return self
766 
Here is the call graph for this function:

◆ close_source()

def fparser.common.readfortran.FortranReaderBase.close_source (   self)
Called when self.source.next() raises StopIteration.

Definition at line 644 of file readfortran.py.

644  def close_source(self):
645  """Called when self.source.next() raises StopIteration."""
646  pass
647 
Here is the caller graph for this function:

◆ comment_item()

def fparser.common.readfortran.FortranReaderBase.comment_item (   self,
  comment,
  startlineno,
  endlineno 
)
Construct Comment item.

Definition at line 956 of file readfortran.py.

956  def comment_item(self, comment, startlineno, endlineno):
957  """Construct Comment item."""
958  return Comment(comment, (startlineno, endlineno), self)
959 
Here is the caller graph for this function:

◆ cpp_directive_item()

def fparser.common.readfortran.FortranReaderBase.cpp_directive_item (   self,
  line,
  startlineno,
  endlineno 
)
Construct :py:class:`fparser.common.readfortran.CppDirective` item.

:param str line: string containing the text of a single or \
         multi-line preprocessor directive.
:param int startlineno: start line number of the directive from \
                the input source.
:param int endlineno: end line number of the directive from \
              the input source.

Definition at line 960 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.format_message().

960  def cpp_directive_item(self, line, startlineno, endlineno):
961  """
962  Construct :py:class:`fparser.common.readfortran.CppDirective` item.
963 
964  :param str line: string containing the text of a single or \
965  multi-line preprocessor directive.
966  :param int startlineno: start line number of the directive from \
967  the input source.
968  :param int endlineno: end line number of the directive from \
969  the input source.
970 
971  """
972  return CppDirective(line, (startlineno, endlineno), self)
973 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ error()

def fparser.common.readfortran.FortranReaderBase.error (   self,
  message,
  item = None 
)
Logs an error message.

Definition at line 1037 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.exit_on_error, fparser.common.readfortran.FortranReaderBase.format_error_message(), and fparser.common.readfortran.FortranReaderBase.source_lines.

1037  def error(self, message, item=None):
1038  """
1039  Logs an error message.
1040  """
1041  if item is None:
1042  m = self.format_error_message(
1043  message, len(self.source_lines) - 2, len(self.source_lines)
1044  )
1045  else:
1046  m = self.format_error_message(message, item.span[0], item.span[1])
1047  logging.getLogger(__name__).error(m)
1048  if self.exit_on_error:
1049  sys.exit(1)
1050 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_module_source_file()

def fparser.common.readfortran.FortranReaderBase.find_module_source_file (   self,
  mod_name 
)
Scans registered dependees for a named module.

Definition at line 602 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.include_dirs, and fparser.common.readfortran.FortranReaderBase.source_only.

602  def find_module_source_file(self, mod_name):
603  """
604  Scans registered dependees for a named module.
605  """
606  from .utils import get_module_file, module_in_file
607 
608  if self.source_only:
609  for sf in self.source_only:
610  if module_in_file(mod_name, sf):
611  return sf
612  else:
613  fn = None
614  for d in self.include_dirs:
615  fn = get_module_file(mod_name, d)
616  if fn is not None:
617  return fn
618 

◆ format()

def fparser.common.readfortran.FortranReaderBase.format (   self)
:returns: the currently applicable format.
:rtype: :py:class:`fparser.sourceinfo.FortranFormat`

Definition at line 629 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format.

629  def format(self):
630  """
631  :returns: the currently applicable format.
632  :rtype: :py:class:`fparser.sourceinfo.FortranFormat`
633  """
634  return self._format
635 
Here is the caller graph for this function:

◆ format_error_message()

def fparser.common.readfortran.FortranReaderBase.format_error_message (   self,
  message,
  startlineno,
  endlineno,
  startcolno = 0,
  endcolno = -1 
)
Create a string with an error message.

Definition at line 1008 of file readfortran.py.

References fparser.common.base_classes.Statement.format_message(), fparser.common.readfortran.FortranReaderBase.format_message(), and fparser.common.readfortran.FortranReaderBase.format_warning_message().

1008  ):
1009  """Create a string with an error message."""
1010  return self.format_message(
1011  "ERROR", message, startlineno, endlineno, startcolno, endcolno
1012  )
1013 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_message()

def fparser.common.readfortran.FortranReaderBase.format_message (   self,
  kind,
  message,
  startlineno,
  endlineno,
  startcolno = 0,
  endcolno = -1 
)
Prepares a string for logging.

Definition at line 978 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase.format_error_message(), fparser.common.readfortran.FortranFileReader.id, fparser.common.readfortran.FortranStringReader.id, and fparser.common.readfortran.FortranReaderBase.source_lines.

978  ):
979  """
980  Prepares a string for logging.
981  """
982  back_index = {"warning": 2, "error": 3, "info": 0}.get(kind.lower(), 3)
983  r = ["While processing %r (mode=%r).." % (self.id, self._format.mode)]
984  for i in range(max(1, startlineno - back_index), startlineno):
985  r.append("%5d:%s" % (i, self.source_lines[i - 1]))
986  for i in range(
987  startlineno, min(endlineno + back_index, len(self.source_lines)) + 1
988  ):
989  if i == 0 and not self.source_lines:
990  break
991  linenostr = "%5d:" % (i)
992  if i == endlineno:
993  sourceline = self.source_lines[i - 1]
994  l0 = linenostr + sourceline[:startcolno]
995  if endcolno == -1:
996  l1 = sourceline[startcolno:]
997  l2 = ""
998  else:
999  l1 = sourceline[startcolno:endcolno]
1000  l2 = sourceline[endcolno:]
1001  r.append("%s%s%s <== %s" % (l0, l1, l2, message))
1002  else:
1003  r.append(linenostr + self.source_lines[i - 1])
1004  return "\n".join(r)
1005 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ format_warning_message()

def fparser.common.readfortran.FortranReaderBase.format_warning_message (   self,
  message,
  startlineno,
  endlineno,
  startcolno = 0,
  endcolno = -1 
)
Create a string with a warning message.

Definition at line 1016 of file readfortran.py.

References fparser.common.base_classes.Statement.format_message(), and fparser.common.readfortran.FortranReaderBase.format_message().

1016  ):
1017  """Create a string with a warning message."""
1018  return self.format_message(
1019  "WARNING", message, startlineno, endlineno, startcolno, endcolno
1020  )
1021 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_item()

def fparser.common.readfortran.FortranReaderBase.get_item (   self,
  ignore_comments = None 
)
Return next item.

Definition at line 746 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._ignore_comments, and fparser.common.readfortran.FortranReaderBase.next().

746  def get_item(self, ignore_comments=None):
747  """Return next item."""
748  if ignore_comments is None:
749  ignore_comments = self._ignore_comments
750 
751  try:
752  item = self.next(ignore_comments=ignore_comments)
753  except StopIteration:
754  return
755  return item
756 
Here is the call graph for this function:

◆ get_next_line()

def fparser.common.readfortran.FortranReaderBase.get_next_line (   self,
  ignore_empty = False,
  ignore_comments = None 
)
Return next non-empty line from FILO line buffer or from source.

The line will be put to FILO line buffer. So, this method can
be used for looking forward lines without consuming them.

See also
--------
get_single_line, put_single_line

Definition at line 726 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._ignore_comments, fparser.common.readfortran.FortranReaderBase.get_single_line(), and fparser.common.readfortran.FortranReaderBase.put_single_line().

726  def get_next_line(self, ignore_empty=False, ignore_comments=None):
727  """Return next non-empty line from FILO line buffer or from source.
728 
729  The line will be put to FILO line buffer. So, this method can
730  be used for looking forward lines without consuming them.
731 
732  See also
733  --------
734  get_single_line, put_single_line
735  """
736  if ignore_comments is None:
737  ignore_comments = self._ignore_comments
738 
739  line = self.get_single_line(ignore_empty, ignore_comments)
740  if line is None:
741  return
742  self.put_single_line(line)
743  return line
744 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_single_line()

def fparser.common.readfortran.FortranReaderBase.get_single_line (   self,
  ignore_empty = False,
  ignore_comments = None 
)
Return line from FILO line buffer or from source.

First try getting the line from FILO line buffer.

If FILO line buffer is empty then get the next line from
source. Tabs in source line are expanded, ending blank and new
line characters will be removed.  The source line will be
added to ``source_lines`` list. If source line is empty then
recursively get next non-empty line.

In both situations ``linecount`` will be incremented, that is,
the line will be consumed.

:param bool ignore_empty: if True then ignore empty lines.
:param bool ignore_comments: if True then ignore comments (overrides \
                     self._ignore_comments)

See also
--------
put_single_line, get_next_line

Definition at line 664 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase._ignore_comments, fparser.common.readfortran.FortranReaderBase.close_source(), fparser.common.readfortran.FortranReaderBase.filo_line, fparser.common.readfortran.FortranReaderBase.get_single_line(), fparser.common.readfortran.FortranReaderBase.isclosed, fparser.common.readfortran.FortranReaderBase.linecount, fparser.common.readfortran.FortranReaderBase.next(), fparser.common.readfortran.FortranReaderBase.source, and fparser.common.readfortran.FortranReaderBase.source_lines.

664  def get_single_line(self, ignore_empty=False, ignore_comments=None):
665  """ Return line from FILO line buffer or from source.
666 
667  First try getting the line from FILO line buffer.
668 
669  If FILO line buffer is empty then get the next line from
670  source. Tabs in source line are expanded, ending blank and new
671  line characters will be removed. The source line will be
672  added to ``source_lines`` list. If source line is empty then
673  recursively get next non-empty line.
674 
675  In both situations ``linecount`` will be incremented, that is,
676  the line will be consumed.
677 
678  :param bool ignore_empty: if True then ignore empty lines.
679  :param bool ignore_comments: if True then ignore comments (overrides \
680  self._ignore_comments)
681 
682  See also
683  --------
684  put_single_line, get_next_line
685  """
686  if ignore_comments is None:
687  ignore_comments = self._ignore_comments
688 
689  try:
690  line = self.filo_line.pop()
691  self.linecount += 1
692  return line
693  except IndexError:
694  pass
695  if self.isclosed:
696  return None
697  try:
698  line = next(self.source)
699  except StopIteration:
700  self.isclosed = True
701  self.close_source()
702  return None
703  self.linecount += 1
704 
705  # expand tabs, replace special symbols, get rid of nl characters
706  line = line.expandtabs().replace("\xa0", " ").rstrip()
707 
708  self.source_lines.append(line)
709 
710  if ignore_comments and (self._format.is_fixed or self._format.is_f77):
711  # Check for a fixed-format comment. If the current line *is*
712  # a comment and we are ignoring them, then recursively call this
713  # routine again to get the next source line.
714  if _is_fix_comment(
715  line,
716  isstrict=self._format.is_strict,
717  f2py_enabled=self._format.f2py_enabled,
718  ):
719  return self.get_single_line(ignore_empty, ignore_comments)
720 
721  if ignore_empty and not line:
722  return self.get_single_line(ignore_empty, ignore_comments)
723 
724  return line
725 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_source_item()

def fparser.common.readfortran.FortranReaderBase.get_source_item (   self)
Return the next source item.

A source item is ..
- a fortran line
- a list of continued fortran lines
- a multiline - lines inside triple-quotes, only when in ispyf mode
- a comment line
- a preprocessor directive line

:returns: the next source item.
:rtype: :py:class:`fparser.common.readfortran.Line` or \
    :py:class:`fparser.common.readfortran.MultiLine` or \
    :py:class:`fparser.common.readfortran.Comment` or \
    :py:class:`fparser.common.readfortran.CppDirective` or \
    :py:class:`fparser.common.readfortran.SyntaxErrorLine` or \
    :py:class:`fparser.common.readfortran.SyntaxErrorMultiLine`

Definition at line 1257 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase.comment_item(), fparser.common.readfortran.FortranReaderBase.cpp_directive_item(), fparser.common.base_classes.Variable.error(), fparser.common.base_classes.Statement.error(), fparser.common.readfortran.FortranReaderBase.error(), fparser.common.readfortran.FortranReaderBase.f2py_comment_lines, fparser.common.readfortran.FortranReaderBase.fifo_item, fparser.common.readfortran.FortranReaderBase.format_error_message(), fparser.common.base_classes.Statement.format_message(), fparser.common.readfortran.FortranReaderBase.format_message(), fparser.common.readfortran.FortranReaderBase.format_warning_message(), fparser.common.readfortran.FortranReaderBase.get_next_line(), fparser.common.readfortran.FortranReaderBase.get_single_line(), fparser.common.readfortran.FortranReaderBase.handle_cf2py_start(), fparser.common.readfortran.FortranReaderBase.handle_cpp_directive(), fparser.common.readfortran.FortranReaderBase.handle_inline_comment(), fparser.common.readfortran.FortranReaderBase.handle_multilines(), fparser.common.readfortran.FortranReaderBase.line_item(), fparser.common.readfortran.FortranReaderBase.linecount, fparser.common.readfortran.FortranReaderBase.put_item(), fparser.common.readfortran.FortranReaderBase.set_format(), fparser.common.base_classes.Variable.warning(), fparser.common.base_classes.Statement.warning(), and fparser.common.readfortran.FortranReaderBase.warning().

1257  def get_source_item(self):
1258  """
1259  Return the next source item.
1260 
1261  A source item is ..
1262  - a fortran line
1263  - a list of continued fortran lines
1264  - a multiline - lines inside triple-quotes, only when in ispyf mode
1265  - a comment line
1266  - a preprocessor directive line
1267 
1268  :returns: the next source item.
1269  :rtype: :py:class:`fparser.common.readfortran.Line` or \
1270  :py:class:`fparser.common.readfortran.MultiLine` or \
1271  :py:class:`fparser.common.readfortran.Comment` or \
1272  :py:class:`fparser.common.readfortran.CppDirective` or \
1273  :py:class:`fparser.common.readfortran.SyntaxErrorLine` or \
1274  :py:class:`fparser.common.readfortran.SyntaxErrorMultiLine`
1275 
1276  """
1277  get_single_line = self.get_single_line
1278  line = get_single_line()
1279  if line is None:
1280  return None
1281  startlineno = self.linecount
1282  line, is_cpp_directive = self.handle_cpp_directive(line)
1283  if is_cpp_directive:
1284  # CPP directive line
1285  lines = []
1286  while line.rstrip().endswith("\\"):
1287  # Line continuation
1288  lines.append(line.rstrip()[:-1])
1289  line = get_single_line()
1290  lines.append(line)
1291  endlineno = self.linecount
1292  return self.cpp_directive_item("".join(lines), startlineno, endlineno)
1293 
1294  line = self.handle_cf2py_start(line)
1295  is_f2py_directive = (
1296  self._format.f2py_enabled and startlineno in self.f2py_comment_lines
1297  )
1298  isstrict = self._format.is_strict
1299  have_comment = False
1300  label = None
1301  name = None
1302 
1303  if self._format.is_pyf:
1304  # handle multilines
1305  for mlstr in ['"""', "'''"]:
1306  multiline = self.handle_multilines(line, startlineno, mlstr)
1307  if multiline:
1308  return multiline
1309  if self._format.is_fixed:
1310  if _is_fix_comment(line, isstrict, self._format.f2py_enabled):
1311  # comment line:
1312  return self.comment_item(line, startlineno, startlineno)
1313 
1314  for i in range(min(5, len(line))):
1315  # check that fixed format line starts according to Fortran
1316  # standard
1317  if line[i] not in _SPACEDIGITS:
1318  message = (
1319  "non-space/digit char %r found in column %i"
1320  " of fixed Fortran code" % (line[i], i + 1)
1321  )
1322  if i == 0:
1323  message += ", interpreting line as comment line"
1324  if self._format.is_fix:
1325  if i != 0:
1326  message += ", switching to free format mode"
1327  message = self.format_warning_message(
1328  message, startlineno, self.linecount
1329  )
1330  logging.getLogger(__name__).warning(message)
1331  if i == 0:
1332  # non standard comment line:
1333  return self.comment_item(line, startlineno, startlineno)
1334  mode = fparser.common.sourceinfo.FortranFormat(True, False)
1335  self.set_format(mode)
1336  else:
1337  message = self.format_warning_message(
1338  message, startlineno, self.linecount
1339  )
1340  logging.getLogger(__name__).warning(message)
1341  if i == 0:
1342  # non standard comment line:
1343  return self.comment_item(line, startlineno, startlineno)
1344  # return line item with error message
1345  # TODO: handle cases with line[6:]==''
1346  message = self.format_error_message(
1347  message, startlineno, self.linecount
1348  )
1349  return self.line_item(
1350  line[6:], startlineno, self.linecount, label, name, message
1351  )
1352  if self._format.is_fixed: # Check for switched to free format
1353  # check for label
1354  s = line[:5].strip().lower()
1355  if s:
1356  label = int(s)
1357  if not self._format.is_f77:
1358  m = _CONSTRUCT_NAME_RE.match(line[6:])
1359  if m:
1360  name = m.group("name")
1361  line = line[:6] + line[6:][m.end() :].lstrip()
1362  if not line[6:].strip():
1363  # check for a blank line
1364  if name is not None:
1365  self.error("No construct following construct-name.")
1366  elif label is not None:
1367  self.warning(
1368  "Label must follow nonblank character" + " (F2008:3.2.5_2)"
1369  )
1370  return self.comment_item("", startlineno, self.linecount)
1371  # line is not a comment and the start of the line is valid
1372 
1373  if self._format.is_f77 and not is_f2py_directive:
1374  # Fortran 77 is easy..
1375  lines = [line[6:72]]
1376  # get_next_line does not actually consume lines - they are put
1377  # into the FILO buffer as well as being returned. This means
1378  # that we can ignore comments for the purposes of dealing
1379  # with the continued line and then handle them as though they
1380  # follow on after the single line constructed from the multiple
1381  # continued lines.
1382  while _is_fix_cont(
1383  self.get_next_line(ignore_empty=True, ignore_comments=True)
1384  ):
1385  # handle fix format line continuations for F77 code
1386  line = get_single_line()
1387  lines.append(line[6:72])
1388  return self.line_item(
1389  "".join(lines), startlineno, self.linecount, label, name
1390  )
1391 
1392  handle_inline_comment = self.handle_inline_comment
1393 
1394  endlineno = self.linecount
1395  if self._format.is_fix and not is_f2py_directive:
1396  # handle inline comment
1397  newline, qc, had_comment = handle_inline_comment(line[6:], startlineno)
1398  have_comment |= had_comment
1399  lines = [newline]
1400  next_line = self.get_next_line()
1401 
1402  while _is_fix_cont(next_line) or _is_fix_comment(
1403  next_line, isstrict, self._format.f2py_enabled
1404  ):
1405  # handle fix format line continuations for F90 or
1406  # newer code. Mixing fix format and free format line
1407  # continuations is not allowed nor detected, just
1408  # eject warnings.
1409  line2 = get_single_line() # consume next_line as line2
1410  if _is_fix_comment(line2, isstrict, self._format.f2py_enabled):
1411  # handle fix format comments inside line continuations
1412  # after the line construction
1413  citem = self.comment_item(line2, self.linecount, self.linecount)
1414  self.fifo_item.append(citem)
1415  else:
1416  # line continuation
1417  newline, qc, had_comment = self.handle_inline_comment(
1418  line2[6:], self.linecount, qc
1419  )
1420  have_comment |= had_comment
1421  lines.append(newline)
1422  endlineno = self.linecount
1423  next_line = self.get_next_line()
1424  # no character continuation should follows now
1425  if qc is not None:
1426  message = "following character continuation: " + "{!r}, expected None."
1427  message = self.format_message(
1428  "ASSERTION FAILURE(fix)",
1429  message.format(qc),
1430  startlineno,
1431  self.linecount,
1432  )
1433  logging.getLogger(__name__).warning(message)
1434  if len(lines) > 1:
1435  for i in range(len(lines)):
1436  line = lines[i]
1437  if line.rstrip().endswith("&"):
1438  message = (
1439  "free format line continuation character "
1440  + "`&' detected in fix format code"
1441  )
1442  location = line.rfind("&") + 5
1443  message = self.format_warning_message(
1444  message, startlineno + i, startlineno + i, location
1445  )
1446  logging.getLogger(__name__).warning(message)
1447  return self.line_item("".join(lines), startlineno, endlineno, label, name)
1448 
1449  # line is free format or fixed format with f2py directive (that
1450  # will be interpretted as free format line).
1451 
1452  start_index = 0
1453  if self._format.is_fix:
1454  start_index = 6
1455  lines = []
1456  lines_append = lines.append
1457  put_item = self.fifo_item.append
1458  qc = None
1459  while line is not None:
1460  if start_index: # fix format code
1461  line, qc, had_comment = handle_inline_comment(
1462  line[start_index:], self.linecount, qc
1463  )
1464  have_comment |= had_comment
1465  is_f2py_directive = self.linecount in self.f2py_comment_lines
1466  else:
1467  # free format
1468  line_lstrip = line.lstrip()
1469  if lines:
1470  if line_lstrip.startswith("!"):
1471  # check for comment line within line continuation
1472  put_item(
1473  self.comment_item(
1474  line_lstrip, self.linecount, self.linecount
1475  )
1476  )
1477  have_comment = True
1478  line = get_single_line()
1479  continue
1480  elif line_lstrip == "":
1481  # skip blank lines within a line continuation
1482  line = get_single_line()
1483  continue
1484  else:
1485  # Extract label and/or construct name from line if
1486  # there is one.
1487  label, line = extract_label(line)
1488  name, line = extract_construct_name(line)
1489 
1490  line, qc, had_comment = handle_inline_comment(line, self.linecount, qc)
1491  have_comment |= had_comment
1492  is_f2py_directive = self.linecount in self.f2py_comment_lines
1493 
1494  i = line.rfind("&")
1495  if i != -1:
1496  line_i1_rstrip = line[i + 1 :].rstrip()
1497  if not lines:
1498  # first line
1499  if i == -1 or line_i1_rstrip:
1500  lines_append(line)
1501  break
1502  endlineno = self.linecount
1503  lines_append(line[:i])
1504  line = get_single_line()
1505  continue
1506  if i == -1 or line_i1_rstrip:
1507  # no line continuation follows
1508  i = len(line)
1509  k = -1
1510  if i != -1:
1511  # handle the beggining of continued line
1512  k = line[:i].find("&")
1513  if k != 1 and line[:k].lstrip():
1514  k = -1
1515  endlineno = self.linecount
1516  lines_append(line[k + 1 : i])
1517  if i == len(line):
1518  break
1519  line = get_single_line()
1520 
1521  if qc is not None:
1522  message = "following character continuation: {!r}, " + "expected None."
1523  message = self.format_message(
1524  "ASSERTION FAILURE(free)", message.format(qc), startlineno, endlineno
1525  )
1526  logging.getLogger(__name__).error(message)
1527  line_content = "".join(lines).strip()
1528  if line_content:
1529  return self.line_item(line_content, startlineno, endlineno, label, name)
1530  if label is not None:
1531  message = "Label must follow nonblank character (F2008:3.2.5_2)"
1532  self.warning(message)
1533  if name is not None:
1534  self.error("No construct following construct-name.")
1535 
1536  # If this point is reached, the line is a comment or is
1537  # blank. If it is a comment, it has been pushed onto the
1538  # fifo_item list.
1539  try:
1540  return self.fifo_item.pop(0)
1541  except IndexError:
1542  # A blank line is represented as an empty comment
1543  return Comment("", (startlineno, endlineno), self)
1544 
1545 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_cf2py_start()

def fparser.common.readfortran.FortranReaderBase.handle_cf2py_start (   self,
  line 
)
Process any f2py directives contained in the supplied line. If
support for such directives has been disabled then the line is
returned unchanged.

F2py directives are specified in the beginning of the line.

f2py directives can be used only in Fortran codes.  They are
ignored when used inside PYF files.

:param str line: the line to check for f2py directives.

:returns: the line with any f2py directives applied (if they are \
  enabled in the reader).
:rtype: str

Definition at line 1089 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase.f2py_comment_lines, and fparser.common.readfortran.FortranReaderBase.linecount.

1089  def handle_cf2py_start(self, line):
1090  """
1091  Process any f2py directives contained in the supplied line. If
1092  support for such directives has been disabled then the line is
1093  returned unchanged.
1094 
1095  F2py directives are specified in the beginning of the line.
1096 
1097  f2py directives can be used only in Fortran codes. They are
1098  ignored when used inside PYF files.
1099 
1100  :param str line: the line to check for f2py directives.
1101 
1102  :returns: the line with any f2py directives applied (if they are \
1103  enabled in the reader).
1104  :rtype: str
1105 
1106  """
1107  if not line or self._format.is_pyf or not self._format.f2py_enabled:
1108  return line
1109  if self._format.is_fixed:
1110  if line[0] in "*cC!#":
1111  if line[1:5].lower() == "f2py":
1112  line = 5 * " " + line[5:]
1113  self.f2py_comment_lines.append(self.linecount)
1114  if self._format.is_f77:
1115  return line
1116  m = _CF2PY_RE.match(line)
1117  if m:
1118  newline = m.group("indent") + 5 * " " + m.group("rest")
1119  self.f2py_comment_lines.append(self.linecount)
1120  assert len(newline) == len(line), repr((newline, line))
1121  return newline
1122  return line
1123 
Here is the caller graph for this function:

◆ handle_cpp_directive()

def fparser.common.readfortran.FortranReaderBase.handle_cpp_directive (   self,
  line 
)
Determine whether the current line is likely to hold
C preprocessor directive.

If the first non whitespace character of a line is the symbol ``#``
it is assumed this is a preprocessor directive.

Preprocessor directives can be used only in Fortran codes. They are
ignored when used inside PYF files.

The actual line content is not altered.

:param str line: the line to be tested for directives.

:return: a tuple containing the line and True/False depending on \
 whether it holds a C preprocessor directive.
:rtype: (str, bool)

Definition at line 1065 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format.

1065  def handle_cpp_directive(self, line):
1066  """
1067  Determine whether the current line is likely to hold
1068  C preprocessor directive.
1069 
1070  If the first non whitespace character of a line is the symbol ``#``
1071  it is assumed this is a preprocessor directive.
1072 
1073  Preprocessor directives can be used only in Fortran codes. They are
1074  ignored when used inside PYF files.
1075 
1076  The actual line content is not altered.
1077 
1078  :param str line: the line to be tested for directives.
1079 
1080  :return: a tuple containing the line and True/False depending on \
1081  whether it holds a C preprocessor directive.
1082  :rtype: (str, bool)
1083 
1084  """
1085  if not line or self._format.is_pyf:
1086  return (line, False)
1087  return (line, line.lstrip().startswith("#"))
1088 
Here is the caller graph for this function:

◆ handle_inline_comment()

def fparser.common.readfortran.FortranReaderBase.handle_inline_comment (   self,
  line,
  lineno,
  quotechar = None 
)
Any in-line comment is extracted from the line. If
keep_inline_comments==True then the extracted comments are put back
into the fifo sequence where they will subsequently be processed as
a comment line.

:param str line: line of code from which to remove in-line comment
:param int lineno: line-no. in orig. file
:param quotechar: String to use as character-string delimiter
:type quotechar: {None, str}

:return: line_with_no_comments, quotechar, had_comment
:rtype: 3-tuple of str, str, bool

Definition at line 1124 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase.comment_item(), fparser.common.readfortran.FortranReaderBase.f2py_comment_lines, fparser.common.readfortran.FortranReaderBase.fifo_item, fparser.one.statements.Print.format, fparser.one.statements.Read1.format, fparser.common.readfortran.FortranReaderBase.format(), fparser.common.readfortran.FortranReaderBase.handle_inline_comment(), and fparser.common.readfortran.FortranReaderBase.put_item().

1124  def handle_inline_comment(self, line, lineno, quotechar=None):
1125  """
1126  Any in-line comment is extracted from the line. If
1127  keep_inline_comments==True then the extracted comments are put back
1128  into the fifo sequence where they will subsequently be processed as
1129  a comment line.
1130 
1131  :param str line: line of code from which to remove in-line comment
1132  :param int lineno: line-no. in orig. file
1133  :param quotechar: String to use as character-string delimiter
1134  :type quotechar: {None, str}
1135 
1136  :return: line_with_no_comments, quotechar, had_comment
1137  :rtype: 3-tuple of str, str, bool
1138  """
1139  had_comment = False
1140  if (
1141  quotechar is None
1142  and "!" not in line
1143  and '"' not in line
1144  and "'" not in line
1145  ):
1146  # There's no comment on this line
1147  return line, quotechar, had_comment
1148 
1149  idx = line.find("!")
1150  put_item = self.fifo_item.append
1151  if quotechar is None and idx != -1:
1152  # first try a quick method:
1153  newline = line[:idx]
1154  if '"' not in newline and "'" not in newline:
1155  if self.format.is_f77 or not line[idx:].startswith("!f2py"):
1156  put_item(self.comment_item(line[idx:], lineno, lineno))
1157  return newline, quotechar, True
1158 
1159  # We must allow for quotes...
1160  items, newquotechar = splitquote(line, quotechar)
1161  noncomment_items = []
1162  noncomment_items_append = noncomment_items.append
1163  n = len(items)
1164  commentline = None
1165  for k in range(n):
1166  item = items[k]
1167  if isinstance(item, String) or "!" not in item:
1168  noncomment_items_append(item)
1169  continue
1170  j = item.find("!")
1171  noncomment_items_append(item[:j])
1172  items[k] = item[j:]
1173  commentline = "".join(items[k:])
1174  break
1175  if commentline is not None:
1176  if self._format.f2py_enabled and commentline.startswith("!f2py"):
1177  # go to next iteration:
1178  newline = "".join(noncomment_items) + commentline[5:]
1179  self.f2py_comment_lines.append(lineno)
1180  return self.handle_inline_comment(newline, lineno, quotechar)
1181  put_item(self.comment_item(commentline, lineno, lineno))
1182  had_comment = True
1183  return "".join(noncomment_items), newquotechar, had_comment
1184 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_multilines()

def fparser.common.readfortran.FortranReaderBase.handle_multilines (   self,
  line,
  startlineno,
  mlstr 
)
Examines line for Python triple quote strings (f2py feature).

:param str line: line of Fortran source text
:param int startlineno: the number of the line on which this
                 multi-line string began.
:param list mlstr: list of delimiters for a multi-line string
           (e.g. '"""')

Definition at line 1185 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.format(), fparser.common.readfortran.FortranReaderBase.format_error_message(), fparser.common.base_classes.Statement.format_message(), fparser.common.readfortran.FortranReaderBase.format_message(), fparser.common.readfortran.FortranReaderBase.format_warning_message(), fparser.common.readfortran.FortranReaderBase.get_single_line(), fparser.common.readfortran.FortranReaderBase.handle_inline_comment(), fparser.common.readfortran.FortranReaderBase.linecount, fparser.common.readfortran.FortranReaderBase.multiline_item(), and fparser.common.readfortran.FortranReaderBase.warning().

1185  def handle_multilines(self, line, startlineno, mlstr):
1186  '''
1187  Examines line for Python triple quote strings (f2py feature).
1188 
1189  :param str line: line of Fortran source text
1190  :param int startlineno: the number of the line on which this
1191  multi-line string began.
1192  :param list mlstr: list of delimiters for a multi-line string
1193  (e.g. '"""')
1194  '''
1195  i = line.find(mlstr)
1196  if i != -1:
1197  prefix = line[:i]
1198  # skip fake multiline starts
1199  p, k = prefix, 0
1200  while p.endswith("\\"):
1201  p, k = p[:-1], k + 1
1202  if k % 2:
1203  return
1204  if i != -1 and "!" not in prefix:
1205  # Note character constants like 'abc"""123',
1206  # so multiline prefix should better not contain `'' or `"' not `!'.
1207  for quote in "\"'":
1208  if prefix.count(quote) % 2:
1209  message = (
1210  "multiline prefix contains odd number of"
1211  + " {!r} characters".format(quote)
1212  )
1213  message = self.format_warning_message(
1214  message, startlineno, startlineno, 0, len(prefix)
1215  )
1216  logging.getLogger(__name__).warning(message)
1217 
1218  suffix = None
1219  multilines = []
1220  line = line[i + 3 :]
1221  while line is not None:
1222  j = line.find(mlstr)
1223  if j != -1 and "!" not in line[:j]:
1224  multilines.append(line[:j])
1225  suffix = line[j + 3 :]
1226  break
1227  multilines.append(line)
1228  line = self.get_single_line()
1229  if line is None:
1230  message = "multiline block never ends"
1231  message = self.format_error_message(
1232  message, startlineno, startlineno, i
1233  )
1234  return self.multiline_item(
1235  prefix, multilines, suffix, startlineno, self.linecount, message
1236  )
1237  suffix, qc, had_comment = self.handle_inline_comment(suffix, self.linecount)
1238  # no line continuation allowed in multiline suffix
1239  if qc is not None:
1240  message = "following character continuation: {!r}," + " expected None."
1241  message = self.format_message(
1242  "ASSERTION FAILURE(pyf)",
1243  message.format(qc),
1244  startlineno,
1245  self.linecount,
1246  )
1247  logging.getLogger(__name__).warning(message)
1248  # XXX: should we do line.replace('\\'+mlstr[0],mlstr[0])
1249  # for line in multilines?
1250  return self.multiline_item(
1251  prefix, multilines, suffix, startlineno, self.linecount
1252  )
1253 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ info()

def fparser.common.readfortran.FortranReaderBase.info (   self,
  message,
  item = None 
)
Logs an information message.

Definition at line 1022 of file readfortran.py.

References fparser.common.base_classes.Statement.format_message(), fparser.common.readfortran.FortranReaderBase.format_message(), and fparser.common.readfortran.FortranReaderBase.source_lines.

1022  def info(self, message, item=None):
1023  """
1024  Logs an information message.
1025  """
1026  if item is None:
1027  m = self.format_message(
1028  "INFORMATION",
1029  message,
1030  len(self.source_lines) - 2,
1031  len(self.source_lines),
1032  )
1033  else:
1034  m = self.format_message("INFORMATION", message, item.span[0], item.span[1])
1035  logging.getLogger(__name__).info(m)
1036 
Here is the call graph for this function:

◆ line_item()

def fparser.common.readfortran.FortranReaderBase.line_item (   self,
  line,
  startlineno,
  endlineno,
  label,
  name,
  errmessage = None 
)
Construct Line item.

Definition at line 938 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.multiline_item().

938  def line_item(self, line, startlineno, endlineno, label, name, errmessage=None):
939  """Construct Line item."""
940  if errmessage is None:
941  return Line(line, (startlineno, endlineno), label, name, self)
942  return SyntaxErrorLine(
943  line, (startlineno, endlineno), label, name, self, errmessage
944  )
945 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ multiline_item()

def fparser.common.readfortran.FortranReaderBase.multiline_item (   self,
  prefix,
  lines,
  suffix,
  startlineno,
  endlineno,
  errmessage = None 
)
Construct MultiLine item.

Definition at line 948 of file readfortran.py.

948  ):
949  """Construct MultiLine item."""
950  if errmessage is None:
951  return MultiLine(prefix, lines, suffix, (startlineno, endlineno), self)
952  return SyntaxErrorMultiLine(
953  prefix, lines, suffix, (startlineno, endlineno), self, errmessage
954  )
955 
Here is the caller graph for this function:

◆ name()

def fparser.common.readfortran.FortranReaderBase.name (   self)
:returns: the name of this reader.
:rtype: str

Definition at line 637 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase.format(), and fparser.common.readfortran.FortranReaderBase.source.

637  def name(self):
638  """
639  :returns: the name of this reader.
640  :rtype: str
641  """
642  return "{source} mode={mode}".format(source=self.source, mode=self._format.mode)
643 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ next()

def fparser.common.readfortran.FortranReaderBase.next (   self,
  ignore_comments = None 
)
Return the next Fortran code item. Include statements are dealt
with here.

:param bool ignore_comments: When True then act as if Fortran \
code does not contain any comments or blank lines. if this \
optional arguement is not provided then use the default \
value.

:returns: the next line item. This can be from a local fifo \
buffer, from an include reader or from this reader.
:rtype: py:class:`fparser.common.readfortran.Line`

:raises StopIteration: if no more lines are found.
:raises StopIteration: if a general error has occured.

Definition at line 770 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format, fparser.common.readfortran.FortranReaderBase._ignore_comments, fparser.common.readfortran.FortranReaderBase._next(), fparser.common.readfortran.FortranReaderBase.fifo_item, fparser.common.base_classes.Statement.format_message(), fparser.common.readfortran.FortranReaderBase.format_message(), fparser.common.readfortran.FortranReaderBase.get_source_item(), fparser.common.readfortran.FortranReaderBase.include_dirs, fparser.common.readfortran.FortranReaderBase.linecount, fparser.common.readfortran.Line.reader, fparser.common.readfortran.Comment.reader, fparser.common.readfortran.MultiLine.reader, fparser.common.readfortran.FortranReaderBase.reader, and fparser.common.base_classes.Statement.reader.

770  def next(self, ignore_comments=None):
771  """Return the next Fortran code item. Include statements are dealt
772  with here.
773 
774  :param bool ignore_comments: When True then act as if Fortran \
775  code does not contain any comments or blank lines. if this \
776  optional arguement is not provided then use the default \
777  value.
778 
779  :returns: the next line item. This can be from a local fifo \
780  buffer, from an include reader or from this reader.
781  :rtype: py:class:`fparser.common.readfortran.Line`
782 
783  :raises StopIteration: if no more lines are found.
784  :raises StopIteration: if a general error has occured.
785 
786  """
787  if ignore_comments is None:
788  ignore_comments = self._ignore_comments
789  try:
790  if self.reader is not None:
791  # inside INCLUDE statement
792  try:
793  # Manually check to see if something has not
794  # matched and has been placed in the fifo. We
795  # can't use _next() as this method is associated
796  # with the include reader (self.reader._next()),
797  # not this reader (self._next()).
798  return self.fifo_item.pop(0)
799  except IndexError:
800  # There is nothing in the fifo buffer.
801  try:
802  # Return a line from the include.
803  return self.reader.next(ignore_comments)
804  except StopIteration:
805  # There is nothing left in the include
806  # file. Setting reader to None indicates that
807  # we should now read from the main reader.
808  self.reader = None
809  item = self._next(ignore_comments)
810  if isinstance(item, Line) and _IS_INCLUDE_LINE(item.line):
811  # catch INCLUDE statement and create a new FortranReader
812  # to enter to included file.
813  reader = item.reader
814  filename = item.line.strip()[7:].lstrip()[1:-1]
815  include_dirs = self.include_dirs[:]
816  path = filename
817  for incl_dir in include_dirs:
818  path = os.path.join(incl_dir, filename)
819  if os.path.exists(path):
820  break
821  if not os.path.isfile(path):
822  # The include file does not exist in the specified
823  # locations.
824  #
825  # The Fortran standard states that an INCLUDE line
826  # is not a Fortran statement. However, fparser is
827  # a parser not a compiler and some subsequent tool
828  # might need to make use of this include so we
829  # return it and let the parser deal with it.
830  #
831  return item
832  reader.info("including file %r" % (path), item)
833  self.reader = FortranFileReader(
834  path, include_dirs=include_dirs, ignore_comments=ignore_comments
835  )
836  result = self.reader.next(ignore_comments=ignore_comments)
837  return result
838  return item
839  except StopIteration:
840  raise
841  # TODO can we specify one or more specific exception types
842  # rather than catching *every* exception.
843  except Exception as err:
844  message = self.format_message(
845  "FATAL ERROR", "while processing line", self.linecount, self.linecount
846  )
847  logging.getLogger(__name__).critical(message)
848  message = "Traceback\n" + "".join(traceback.format_stack())
849  logging.getLogger(__name__).debug(message)
850  logging.getLogger(__name__).debug(str(err))
851  logging.getLogger(__name__).critical("STOPPED READING")
852  raise StopIteration
853 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ put_item()

def fparser.common.readfortran.FortranReaderBase.put_item (   self,
  item 
)
Insert item to FIFO item buffer.

Definition at line 757 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.fifo_item.

757  def put_item(self, item):
758  """Insert item to FIFO item buffer."""
759  self.fifo_item.insert(0, item)
760 
Here is the caller graph for this function:

◆ put_single_line()

def fparser.common.readfortran.FortranReaderBase.put_single_line (   self,
  line 
)
Put single line to FILO line buffer.

``linecount`` will be decremented, that is, the line was
returned by ``get_single_line`` call then it will be
un-consumed.

See also
--------
get_single_line, get_next_line

Definition at line 650 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.filo_line, and fparser.common.readfortran.FortranReaderBase.linecount.

650  def put_single_line(self, line):
651  """Put single line to FILO line buffer.
652 
653  ``linecount`` will be decremented, that is, the line was
654  returned by ``get_single_line`` call then it will be
655  un-consumed.
656 
657  See also
658  --------
659  get_single_line, get_next_line
660  """
661  self.filo_line.append(line)
662  self.linecount -= 1
663 
Here is the caller graph for this function:

◆ set_format()

def fparser.common.readfortran.FortranReaderBase.set_format (   self,
  mode 
)
Set Fortran code mode (fixed/free format etc).

:param mode: Object describing the desired mode for the reader
:type mode: :py:class:`fparser.common.sourceinfo.FortranFormat`

Definition at line 619 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase._format.

619  def set_format(self, mode):
620  """
621  Set Fortran code mode (fixed/free format etc).
622 
623  :param mode: Object describing the desired mode for the reader
624  :type mode: :py:class:`fparser.common.sourceinfo.FortranFormat`
625  """
626  self._format = mode
627 
Here is the caller graph for this function:

◆ warning()

def fparser.common.readfortran.FortranReaderBase.warning (   self,
  message,
  item = None 
)
Logs a warning message.

Definition at line 1051 of file readfortran.py.

References fparser.common.readfortran.FortranReaderBase.format_warning_message(), and fparser.common.readfortran.FortranReaderBase.source_lines.

1051  def warning(self, message, item=None):
1052  """
1053  Logs a warning message.
1054  """
1055  if item is None:
1056  m = self.format_warning_message(
1057  message, len(self.source_lines) - 2, len(self.source_lines)
1058  )
1059  else:
1060  m = self.format_warning_message(message, item.span[0], item.span[1])
1061  logging.getLogger(__name__).warning(m)
1062 
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: