73 """Provides Fortran reader classes. 77 Provides FortranReader classes for reading Fortran codes from files and 78 strings. FortranReader handles comments and line continuations of both 79 fix and free format Fortran codes. 85 >> from fparser.common.readfortran import FortranFileReader 87 >>> reader = FortranFileReader(os.path.expanduser('~/src/blas/daxpy.f')) 88 >>> print reader.next() 89 line #1 'subroutine daxpy(n,da,dx,incx,dy,incy)' 90 >>> print `reader.next()` 91 Comment('c constant times a vector plus a vector.\\n 92 c uses unrolled loops for increments equal to one.\\n 93 c jack dongarra, linpack, 3/11/78.\\n 94 c modified 12/3/93, array(1) declarations changed to array(*)',(3, 6)) 95 >>> print `reader.next()` 96 Line('double precision dx(*),dy(*),da',(8, 8),'') 97 >>> print `reader.next()` 98 Line('integer i,incx,incy,ix,iy,m,mp1,n',(9, 9),'') 100 Note that the ``.next()`` method may return `Line`, `SyntaxErrorLine`, 101 `Comment`, `MultiLine`, or `SyntaxErrorMultiLine` instance. 102 Let us continue with the above example session to illustrate the `Line` 103 methods and attributes:: 105 >>> item = reader.next() 107 Line('if (da .eq. 0.0d0) return',(12, 12),'') 109 'if (da .eq. 0.0d0) return' 111 'if (F2PY_EXPR_TUPLE_5) return' 113 {'F2PY_EXPR_TUPLE_5': 'da .eq. 0.0d0'} 117 'if (F2PY_EXPR_TUPLE_5) return' 119 To read a Fortran code from a string, use `FortranStringReader` class:: 121 >>> from fparser.common.sourceinfo import FortranFormat 122 >>> from fparser.common.readfortran import FortranStringReader 124 ... subroutine foo(a) 129 >>> reader = FortranStringReader(code) 130 >>> reader.set_format(FortranFormat(False, True)) 132 Line('subroutine foo(a)',(2, 2),'') 134 Line('integer a',(3, 3),'') 136 Line('print*,\"a=\",a',(4, 4),'') 145 from io
import StringIO
152 "FortranStringReader",
153 "FortranReaderError",
158 "SyntaxErrorMultiLine",
161 _SPACEDIGITS =
" 0123456789" 162 _CF2PY_RE = re.compile(
r"(?P<indent>\s*)!f2py(?P<rest>.*)", re.I)
163 _LABEL_RE = re.compile(
r"\s*(?P<label>\d+)\s*(\b|(?=&)|\Z)", re.I)
164 _CONSTRUCT_NAME_RE = re.compile(
r"\s*(?P<name>\w+)\s*:\s*(\b|(?=&)|\Z)", re.I)
165 _IS_INCLUDE_LINE = re.compile(
166 r'\s*include\s*("[^"]+"' +
r"|\'[^\']+\')\s*\Z", re.I
170 def _is_fix_cont(line):
171 return line
and len(line) > 5
and line[5] !=
" " and line[:5] == 5 *
" " 174 def _is_fix_comment(line, isstrict, f2py_enabled):
176 Check whether line is a comment line in fixed format Fortran source. 182 :param str line: line of code to check. 183 :param bool isstrict: whether we are strictly enforcing fixed/free fmt. 184 :param bool f2py_enabled: whether support for f2py directives is enabled. 186 :returns: whether or not the supplied line is a fixed-format comment. 191 if line[0]
in "*cC!":
192 if f2py_enabled
and line[1:5].lower() ==
"f2py":
198 start = line[:i].lstrip()
213 _HOLLERITH_START_SEARCH = re.compile(
214 r"(?P<pre>\A|,\s*)" +
r"(?P<num>\d+)h", re.I
216 _IS_CALL_STMT = re.compile(
r"call\b", re.I).match
219 def extract_label(line):
220 """Look for an integer label at the start of 'line' and if there is 221 one then remove it from 'line' and store it as an integer in 222 'label', returning both in a tuple. 224 :param str line: a string that potentially contains a label at the \ 227 :returns: a 2-tuple containing the label and updated line if a \ 228 label is found or None and the unchanged line if a label is \ 230 :rtype: (int or NoneType, str) 234 match = _LABEL_RE.match(line)
236 label = int(match.group(
"label"))
237 line = line[match.end() :].lstrip()
241 def extract_construct_name(line):
242 """Look for a construct name at the start of 'line' and if there is 243 one then remove it from 'line' and return it as a string in 244 'name', returning both in a tuple. 246 :param str line: a string that potentially contains a construct \ 249 :returns: a 2-tuple containing the construct name and updated line \ 250 if a construct name is found or None and the unchanged line if \ 251 a construct name is not found. 252 :rtype: (str or NoneType, str) 255 construct_name =
None 256 match = _CONSTRUCT_NAME_RE.match(line)
258 construct_name = match.group(
"name")
259 line = line[match.end() :].lstrip()
260 return construct_name, line
265 Thrown when there is an error reading the Fortran source file. 272 """Holds a Fortran source line. 279 starting and ending line numbers 281 Specify statement label 283 Specify construct name. 284 reader : FortranReaderBase 285 strline : {None, str} 286 is_f2py_directive : bool 287 the line contains f2py directive 291 def __init__(self, line, linenospan, label, name, reader):
292 self.line = line.strip()
294 raise FortranReaderError(
295 "Got empty line: '{0}'. linenospan={1}, " 296 "label='{2}'".format(line, linenospan, label)
298 self.span = linenospan
299 assert label
is None or isinstance(label, int), repr(label)
300 assert name
is None or isinstance(name, str)
and name !=
"", repr(name)
305 self.is_f2py_directive = linenospan[0]
in reader.f2py_comment_lines
306 self.parse_cache = {}
310 Returns true when a substitution map has been registered. 312 return hasattr(self,
"strlinemap")
and self.
strlinemap 316 Substitutes magic strings in a line with values specified in a map. 318 if not hasattr(self,
"strlinemap")
or not self.
strlinemap:
322 def copy(self, line=None, apply_map=False):
324 Creates a Line object from a string. 326 If no line argument is specified a copy is made of this Line. 328 If a substitution map is provided it is used while making the copy. 338 This Line has its contents overwitten by the passed string. The 339 incoming string has substitution applied. 345 return self.__class__.__name__ +
"(%r,%s,%r,%r,<reader>)" % (
353 s =
"line #%s" % (self.
span[0])
354 if self.
label is not None:
355 s +=
" %s " % (self.
label)
356 if self.
name is not None:
357 s +=
"%s: " % (self.
name)
358 return s + repr(self.
line)
360 def isempty(self, ignore_comments=False):
361 return not (self.
line or self.
label is not None or self.
name is not None)
363 def get_line(self, apply_map=False):
370 if self.
reader.format.is_f77:
379 if _IS_CALL_STMT(line):
380 l2 = self.
line[4:].lstrip()
382 if i != -1
and l2[-1] ==
")":
383 substrings = [
"call " + l2[: i + 1]]
384 start_search = _HOLLERITH_START_SEARCH
385 l2 = l2[i + 1 : -1].strip()
388 substrings.append(l2[: m.start()])
389 substrings.append(m.group(
"pre"))
390 num = int(m.group(
"num"))
391 substrings.append(
"'" + l2[m.end() : m.end() + num] +
"'")
392 l2 = l2[m.end() + num :]
394 substrings.append(l2)
395 substrings.append(
")")
396 line =
"".join(substrings)
398 line, str_map = string_replace_map(line, lower=
not self.
reader.format.is_pyf)
403 def parse_line(self, cls, parent_cls):
406 obj = cls(self.
line, parent_cls=parent_cls)
412 def parse_block(self, reader, cls, parent_cls):
413 key = cls, tuple(parent_cls)
415 obj = cls(reader, parent_cls=parent_cls)
424 Indicates a syntax error while processing a line. 427 def __init__(self, line, linenospan, label, name, reader, message):
428 Line.__init__(self, line, linenospan, label, name, reader)
429 FortranReaderError.__init__(self, message)
433 """Holds a Fortran comment. 435 :param str comment: String containing the text of a single or \ 437 :param linenospan: A 2-tuple containing the start and end line \ 438 numbers of the comment from the input source. 439 :type linenospan: (int, int) 440 :param reader: The reader object being used to read the input \ 442 :type reader: :py:class:`fparser.common.readfortran.FortranReaderBase` 446 def __init__(self, comment, linenospan, reader):
449 self.
span = linenospan
458 return self.__class__.__name__ +
"(%r,%s)" % (self.
comment, self.
span)
462 Whether or not this comment is in fact empty (or we are ignoring 463 it). Provided for compatibility with Line.isempty() 465 :param bool ignore_comments: whether we ignore comments 466 :return: True if we are ignoring comments, False otherwise 469 return ignore_comments
473 """Holds PYF file multiline. 475 PYF file multiline is represented as follows:: 476 prefix+'''+lines+'''+suffix. 478 :param str prefix: the prefix of the line(s) 479 :param block: list of lines 480 :type block: List[:py:class:`fparser.common.readfortran.Line`] 481 :param str suffix: the suffix of the block of lines 482 :param linenospan: starting and ending line numbers 483 :type linenospan: Tuple[int, int] 484 :param reader: the current reader instance. 485 :type reader: :py:class:`fparser.common.readfortran.FortranReaderBase` 489 def __init__(self, prefix, block, suffix, linenospan, reader):
493 self.
span = linenospan
497 string =
"{cls}({prefix!r},{block},{suffix!r},{span})" 498 return string.format(
499 cls=self.__class__.__name__,
508 Returns true if there is no significant text in this multi-line 516 Indicates a syntax error while processing Python multi-line strings. 519 def __init__(self, prefix, block, suffix, linenospan, reader, message):
520 MultiLine.__init__(self, prefix, block, suffix, linenospan, reader)
521 FortranReaderError.__init__(self, message)
525 """Holds a preprocessor directive source line. 527 :param str line: string containing the text of a single or \ 528 multi-line preprocessor directive. 529 :param linenospan: a 2-tuple containing the start and end line \ 530 numbers of the directive from the input source. 531 :type linenospan: (int, int) 532 :param reader: The reader object being used to read the input \ 534 :type reader: :py:class:`fparser.common.readfortran.FortranReaderBase` 538 def __init__(self, line, linenospan, reader):
539 super(CppDirective, self).__init__(line, linenospan,
None,
None, reader)
547 Base class for reading Fortran sources. 549 A Fortran source must be a file-like object (have a ``.next()`` 550 method) and it may hold Fortran 77 code, fixed format Fortran 551 code, free format Fortran code, or PYF signatures (with extended 552 free format Fortran syntax). 554 :param source: a file-like object with .next() method used to \ 556 :type source: :py:class:`StringIO` or a file handle 557 :param mode: a FortranFormat object as returned by \ 558 `sourceinfo.get_source_info()` 559 :type mode: :py:class:`fparser.common.sourceinfo.Format` 560 :param bool isstrict: whether we are strictly enforcing fixed format. 561 :param bool ignore_comments: whether or not to discard comments. 563 The Fortran source is iterated by `get_single_line`, 564 `get_next_line`, `put_single_line` methods. 568 def __init__(self, source, mode, ignore_comments):
595 return "%s(%r, %r, %r)" % (
596 self.__class__.__name__,
604 Scans registered dependees for a named module. 606 from .utils
import get_module_file, module_in_file
610 if module_in_file(mod_name, sf):
615 fn = get_module_file(mod_name, d)
621 Set Fortran code mode (fixed/free format etc). 623 :param mode: Object describing the desired mode for the reader 624 :type mode: :py:class:`fparser.common.sourceinfo.FortranFormat` 631 :returns: the currently applicable format. 632 :rtype: :py:class:`fparser.sourceinfo.FortranFormat` 639 :returns: the name of this reader. 645 """Called when self.source.next() raises StopIteration.""" 651 """Put single line to FILO line buffer. 653 ``linecount`` will be decremented, that is, the line was 654 returned by ``get_single_line`` call then it will be 659 get_single_line, get_next_line 665 """ Return line from FILO line buffer or from source. 667 First try getting the line from FILO line buffer. 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. 675 In both situations ``linecount`` will be incremented, that is, 676 the line will be consumed. 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) 684 put_single_line, get_next_line 686 if ignore_comments
is None:
699 except StopIteration:
706 line = line.expandtabs().replace(
"\xa0",
" ").rstrip()
710 if ignore_comments
and (self.
_format.is_fixed
or self.
_format.is_f77):
716 isstrict=self.
_format.is_strict,
717 f2py_enabled=self.
_format.f2py_enabled,
721 if ignore_empty
and not line:
727 """Return next non-empty line from FILO line buffer or from source. 729 The line will be put to FILO line buffer. So, this method can 730 be used for looking forward lines without consuming them. 734 get_single_line, put_single_line 736 if ignore_comments
is None:
747 """Return next item.""" 748 if ignore_comments
is None:
752 item = self.
next(ignore_comments=ignore_comments)
753 except StopIteration:
758 """Insert item to FIFO item buffer.""" 764 """Make FortranReader an iterator.""" 770 def next(self, ignore_comments=None):
771 """Return the next Fortran code item. Include statements are dealt 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 \ 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` 783 :raises StopIteration: if no more lines are found. 784 :raises StopIteration: if a general error has occured. 787 if ignore_comments
is None:
790 if self.
reader is not None:
804 except StopIteration:
809 item = self.
_next(ignore_comments)
810 if isinstance(item, Line)
and _IS_INCLUDE_LINE(item.line):
814 filename = item.line.strip()[7:].lstrip()[1:-1]
817 for incl_dir
in include_dirs:
818 path = os.path.join(incl_dir, filename)
819 if os.path.exists(path):
821 if not os.path.isfile(path):
832 reader.info(
"including file %r" % (path), item)
834 path, include_dirs=include_dirs, ignore_comments=ignore_comments
836 result = self.
reader.
next(ignore_comments=ignore_comments)
839 except StopIteration:
843 except Exception
as err:
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")
854 def _next(self, ignore_comments=None):
856 Return the next item from FIFO item buffer or construct 857 one from source line. 859 Resolves ``;`` statement terminations. 863 next, get_source_item 865 :param bool ignore_comments: Whether or not to ignore comments \ 866 (overrides self._ignore_comments) 868 :returns: the next line of Fortran. 869 :rtype: :py:class:`fparser.common.readfortran.Line` 871 :raises StopIteration: if no new items are found. 874 if ignore_comments
is None:
880 item = fifo_item_pop(0)
886 if not item.isempty(ignore_comments):
890 if not isinstance(item, Comment):
894 and isinstance(item, Line)
895 and not item.is_f2py_directive
896 and ";" in item.get_line()
901 split_line_iter = iter(item.get_line().split(
";"))
902 first =
next(split_line_iter)
913 items.append(item.copy(first.strip(), apply_map=
True))
914 for line
in split_line_iter:
921 label, line = extract_label(line)
922 name, line = extract_construct_name(line)
927 item.apply_map(line), item.span, label, name, item.reader
929 items.append(new_line)
931 for newitem
in items:
933 return fifo_item_pop(0)
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)
943 line, (startlineno, endlineno), label, name, self, errmessage
947 self, prefix, lines, suffix, startlineno, endlineno, errmessage=None
949 """Construct MultiLine item.""" 950 if errmessage
is None:
951 return MultiLine(prefix, lines, suffix, (startlineno, endlineno), self)
953 prefix, lines, suffix, (startlineno, endlineno), self, errmessage
957 """Construct Comment item.""" 958 return Comment(comment, (startlineno, endlineno), self)
962 Construct :py:class:`fparser.common.readfortran.CppDirective` item. 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 \ 968 :param int endlineno: end line number of the directive from \ 972 return CppDirective(line, (startlineno, endlineno), self)
977 self, kind, message, startlineno, endlineno, startcolno=0, endcolno=-1
980 Prepares a string for logging. 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):
987 startlineno, min(endlineno + back_index, len(self.
source_lines)) + 1
991 linenostr =
"%5d:" % (i)
994 l0 = linenostr + sourceline[:startcolno]
996 l1 = sourceline[startcolno:]
999 l1 = sourceline[startcolno:endcolno]
1000 l2 = sourceline[endcolno:]
1001 r.append(
"%s%s%s <== %s" % (l0, l1, l2, message))
1007 self, message, startlineno, endlineno, startcolno=0, endcolno=-1
1009 """Create a string with an error message.""" 1011 "ERROR", message, startlineno, endlineno, startcolno, endcolno
1015 self, message, startlineno, endlineno, startcolno=0, endcolno=-1
1017 """Create a string with a warning message.""" 1019 "WARNING", message, startlineno, endlineno, startcolno, endcolno
1022 def info(self, message, item=None):
1024 Logs an information message. 1034 m = self.
format_message(
"INFORMATION", message, item.span[0], item.span[1])
1035 logging.getLogger(__name__).
info(m)
1039 Logs an error message. 1047 logging.getLogger(__name__).
error(m)
1053 Logs a warning message. 1061 logging.getLogger(__name__).
warning(m)
1067 Determine whether the current line is likely to hold 1068 C preprocessor directive. 1070 If the first non whitespace character of a line is the symbol ``#`` 1071 it is assumed this is a preprocessor directive. 1073 Preprocessor directives can be used only in Fortran codes. They are 1074 ignored when used inside PYF files. 1076 The actual line content is not altered. 1078 :param str line: the line to be tested for directives. 1080 :return: a tuple containing the line and True/False depending on \ 1081 whether it holds a C preprocessor directive. 1085 if not line
or self.
_format.is_pyf:
1086 return (line,
False)
1087 return (line, line.lstrip().startswith(
"#"))
1091 Process any f2py directives contained in the supplied line. If 1092 support for such directives has been disabled then the line is 1095 F2py directives are specified in the beginning of the line. 1097 f2py directives can be used only in Fortran codes. They are 1098 ignored when used inside PYF files. 1100 :param str line: the line to check for f2py directives. 1102 :returns: the line with any f2py directives applied (if they are \ 1103 enabled in the reader). 1107 if not line
or self.
_format.is_pyf
or not self.
_format.f2py_enabled:
1110 if line[0]
in "*cC!#":
1111 if line[1:5].lower() ==
"f2py":
1112 line = 5 *
" " + line[5:]
1116 m = _CF2PY_RE.match(line)
1118 newline = m.group(
"indent") + 5 *
" " + m.group(
"rest")
1120 assert len(newline) == len(line), repr((newline, line))
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 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} 1136 :return: line_with_no_comments, quotechar, had_comment 1137 :rtype: 3-tuple of str, str, bool 1147 return line, quotechar, had_comment
1149 idx = line.find(
"!")
1151 if quotechar
is None and idx != -1:
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"):
1157 return newline, quotechar,
True 1160 items, newquotechar = splitquote(line, quotechar)
1161 noncomment_items = []
1162 noncomment_items_append = noncomment_items.append
1167 if isinstance(item, String)
or "!" not in item:
1168 noncomment_items_append(item)
1171 noncomment_items_append(item[:j])
1173 commentline =
"".join(items[k:])
1175 if commentline
is not None:
1176 if self.
_format.f2py_enabled
and commentline.startswith(
"!f2py"):
1178 newline =
"".join(noncomment_items) + commentline[5:]
1183 return "".join(noncomment_items), newquotechar, had_comment
1187 Examines line for Python triple quote strings (f2py feature). 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 1195 i = line.find(mlstr)
1200 while p.endswith(
"\\"):
1201 p, k = p[:-1], k + 1
1204 if i != -1
and "!" not in prefix:
1208 if prefix.count(quote) % 2:
1210 "multiline prefix contains odd number of" 1211 +
" {!r} characters".
format(quote)
1214 message, startlineno, startlineno, 0, len(prefix)
1216 logging.getLogger(__name__).
warning(message)
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 :]
1227 multilines.append(line)
1230 message =
"multiline block never ends" 1232 message, startlineno, startlineno, i
1235 prefix, multilines, suffix, startlineno, self.
linecount, message
1240 message =
"following character continuation: {!r}," +
" expected None." 1242 "ASSERTION FAILURE(pyf)",
1247 logging.getLogger(__name__).
warning(message)
1251 prefix, multilines, suffix, startlineno, self.
linecount 1259 Return the next source item. 1263 - a list of continued fortran lines 1264 - a multiline - lines inside triple-quotes, only when in ispyf mode 1266 - a preprocessor directive line 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` 1283 if is_cpp_directive:
1286 while line.rstrip().endswith(
"\\"):
1288 lines.append(line.rstrip()[:-1])
1295 is_f2py_directive = (
1298 isstrict = self.
_format.is_strict
1299 have_comment =
False 1305 for mlstr
in [
'"""',
"'''"]:
1310 if _is_fix_comment(line, isstrict, self.
_format.f2py_enabled):
1312 return self.
comment_item(line, startlineno, startlineno)
1314 for i
in range(min(5, len(line))):
1317 if line[i]
not in _SPACEDIGITS:
1319 "non-space/digit char %r found in column %i" 1320 " of fixed Fortran code" % (line[i], i + 1)
1323 message +=
", interpreting line as comment line" 1326 message +=
", switching to free format mode" 1330 logging.getLogger(__name__).
warning(message)
1333 return self.
comment_item(line, startlineno, startlineno)
1340 logging.getLogger(__name__).
warning(message)
1343 return self.
comment_item(line, startlineno, startlineno)
1350 line[6:], startlineno, self.
linecount, label, name, message
1354 s = line[:5].strip().lower()
1358 m = _CONSTRUCT_NAME_RE.match(line[6:])
1360 name = m.group(
"name")
1361 line = line[:6] + line[6:][m.end() :].lstrip()
1362 if not line[6:].strip():
1364 if name
is not None:
1365 self.
error(
"No construct following construct-name.")
1366 elif label
is not None:
1368 "Label must follow nonblank character" +
" (F2008:3.2.5_2)" 1373 if self.
_format.is_f77
and not is_f2py_directive:
1375 lines = [line[6:72]]
1387 lines.append(line[6:72])
1389 "".join(lines), startlineno, self.
linecount, label, name
1395 if self.
_format.is_fix
and not is_f2py_directive:
1398 have_comment |= had_comment
1402 while _is_fix_cont(next_line)
or _is_fix_comment(
1403 next_line, isstrict, self.
_format.f2py_enabled
1410 if _is_fix_comment(line2, isstrict, self.
_format.f2py_enabled):
1420 have_comment |= had_comment
1421 lines.append(newline)
1426 message =
"following character continuation: " +
"{!r}, expected None." 1428 "ASSERTION FAILURE(fix)",
1433 logging.getLogger(__name__).
warning(message)
1435 for i
in range(len(lines)):
1437 if line.rstrip().endswith(
"&"):
1439 "free format line continuation character " 1440 +
"`&' detected in fix format code" 1442 location = line.rfind(
"&") + 5
1444 message, startlineno + i, startlineno + i, location
1446 logging.getLogger(__name__).
warning(message)
1447 return self.
line_item(
"".join(lines), startlineno, endlineno, label, name)
1456 lines_append = lines.append
1459 while line
is not None:
1464 have_comment |= had_comment
1468 line_lstrip = line.lstrip()
1470 if line_lstrip.startswith(
"!"):
1480 elif line_lstrip ==
"":
1487 label, line = extract_label(line)
1488 name, line = extract_construct_name(line)
1491 have_comment |= had_comment
1496 line_i1_rstrip = line[i + 1 :].rstrip()
1499 if i == -1
or line_i1_rstrip:
1503 lines_append(line[:i])
1506 if i == -1
or line_i1_rstrip:
1512 k = line[:i].find(
"&")
1513 if k != 1
and line[:k].lstrip():
1516 lines_append(line[k + 1 : i])
1522 message =
"following character continuation: {!r}, " +
"expected None." 1524 "ASSERTION FAILURE(free)", message.format(qc), startlineno, endlineno
1526 logging.getLogger(__name__).
error(message)
1527 line_content =
"".join(lines).strip()
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)" 1533 if name
is not None:
1534 self.
error(
"No construct following construct-name.")
1543 return Comment(
"", (startlineno, endlineno), self)
1548 Constructs a FortranFileReader object from a file. 1550 :param file_candidate: A filename or file-like object. 1551 :param list include_dirs: Directories in which to look for inclusions. 1552 :param list source_only: Fortran source files to search for modules 1553 required by "use" statements. 1554 :param bool ignore_comments: Whether or not to ignore comments 1558 >>> from fparser.common.readfortran import FortranFileReader 1560 >>> reader = FortranFileReader(\'myfile.f90\') 1565 self, file_candidate, include_dirs=None, source_only=None, ignore_comments=True
1572 if isinstance(file_candidate, str):
1573 self.
id = file_candidate
1577 file_candidate,
"r", encoding="UTF-8", errors="fparser-logging"
1580 elif hasattr(file_candidate,
"read")
and hasattr(
1581 file_candidate,
"name" 1583 self.
id = file_candidate.name
1584 self.
file = file_candidate
1586 message =
"FortranFileReader is used with a filename" 1587 message +=
" or file-like object." 1588 raise ValueError(message)
1591 FortranReaderBase.__init__(self, self.
file, mode, ignore_comments)
1593 if include_dirs
is None:
1597 if source_only
is not None:
1604 def close_source(self):
1610 Reads Fortran source code as a string. 1612 :param str string: string to read 1613 :param list include_dirs: List of dirs to search for include files 1614 :param list source_only: Fortran source files to search for modules 1615 required by "use" statements. 1616 :param bool ignore_comments: Whether or not to ignore comments 1620 >>> from fparser.common.readfortran import FortranStringReader 1627 >>> reader = FortranStringReader(code) 1632 self, string, include_dirs=None, source_only=None, ignore_comments=True
1643 self.
id =
"string-" + str(hash(string))
1644 source = StringIO(string)
1646 FortranReaderBase.__init__(self, source, mode, ignore_comments)
1647 if include_dirs
is not None:
1649 if source_only
is not None:
def format_warning_message(self, message, startlineno, endlineno, startcolno=0, endcolno=-1)
def put_single_line(self, line)
def get_next_line(self, ignore_empty=False, ignore_comments=None)
def error(self, message, item=None)
def handle_cpp_directive(self, line)
def handle_multilines(self, line, startlineno, mlstr)
def set_format(self, mode)
def warning(self, message, item=None)
def comment_item(self, comment, startlineno, endlineno)
def find_module_source_file(self, mod_name)
def copy(self, line=None, apply_map=False)
def cpp_directive_item(self, line, startlineno, endlineno)
def format_message(self, kind, message, startlineno, endlineno, startcolno=0, endcolno=-1)
def handle_inline_comment(self, line, lineno, quotechar=None)
def _next(self, ignore_comments=None)
def get_line(self, apply_map=False)
def get_source_info_str(source)
def get_source_info(file_candidate)
def info(self, message, item=None)
def next(self, ignore_comments=None)
def get_source_item(self)
def format_error_message(self, message, startlineno, endlineno, startcolno=0, endcolno=-1)
def get_single_line(self, ignore_empty=False, ignore_comments=None)
def multiline_item(self, prefix, lines, suffix, startlineno, endlineno, errmessage=None)
def apply_map(self, line)
def isempty(self, ignore_comments=False)
def get_item(self, ignore_comments=None)
def line_item(self, line, startlineno, endlineno, label, name, errmessage=None)
def handle_cf2py_start(self, line)