68 Base classes for all Fortran statement types 91 Defines a object with predefined attributes. Only those attributes 92 are allowed that are specified as keyword arguments of a constructor. 93 When an argument is callable then the corresponding attribute will 94 be read-only and set by the value the callable object returns. 97 def __init__(self, **kws):
100 for k, v
in list(kws.items()):
105 def __getattr__(self, name):
107 message =
"%s instance has no attribute %r, " +
"expected attributes: %s" 108 attributes =
", ".join(list(self.
_attributes.keys()))
109 raise AttributeError(message % (self.__class__.__name__, name, attributes))
116 def __setattr__(self, name, value):
117 if name
in [
"_attributes",
"_readonly"]:
118 self.__dict__[name] = value
121 message =
"%s instance attribute %r is readonly" 122 raise AttributeError(message % (self.__class__.__name__, name))
124 message =
"%s instance has no attribute %r, " +
"expected attributes: %s" 125 attributes =
",".join(list(self.
_attributes.keys()))
126 raise AttributeError(message % (self.__class__.__name__, name, attributes))
139 def torepr(self, depth=-1, tab=""):
141 return tab + self.__class__.__name__
142 lines = [self.__class__.__name__ +
":"]
147 if isinstance(v, list):
148 lines.append(ttab +
"%s=<%s-list>" % (k, len(v)))
149 elif isinstance(v, dict):
150 lines.append(ttab +
"%s=<dict with keys %s>" % (k, list(v.keys())))
152 lines.append(ttab +
"%s=<%s>" % (k, type(v)))
153 return "\n".join(lines)
163 def get_base_classes(cls):
165 for c
in cls.__bases__:
166 bases += get_base_classes(c)
167 return bases + cls.__bases__ + (cls,)
172 Variable instance has attributes: 178 parent - Statement instances defining the variable 181 def __init__(self, parent, name):
216 line.append(
"%s=%r" % (a, v))
217 return "Variable: " +
", ".join(line)
219 def get_typedecl(self):
224 def add_parent(self, parent):
225 if id(parent)
not in list(map(id, self.
parents)):
229 def set_type(self, typedecl):
233 "variable %r already has type %s, " 237 assert typedecl
is not None 240 def set_init(self, expr):
241 if self.
init is not None:
242 if not self.
init == expr:
244 "variable %r already has initialization %r, " 245 "resetting to %r" % (self.
name, self.expr, expr)
249 def set_dimension(self, dims):
250 dims = [tuple(dim.split(
":"))
for dim
in dims]
251 dims = [tuple(map(str.strip, dim))
for dim
in dims]
255 "variable %r already has dimension %r, " 260 def set_bounds(self, bounds):
261 if self.
bounds is not None:
262 if not self.
bounds == bounds:
264 "variable %r already has bounds %r, " 265 "resetting to %r" % (self.
name, self.
bounds, bounds)
269 def set_length(self, length):
270 if self.
length is not None:
271 if not self.
length == length:
273 "variable %r already has length %r, " 274 "resetting to %r" % (self.
name, self.
length, length)
278 known_intent_specs = [
293 def set_intent(self, intent):
300 "unknown intent-spec %r for %r" % (i, self.
name)
322 def is_intent_in(self):
333 if "INPLACE" in self.
intent:
339 if "INOUT" in self.
intent:
341 if "OUTIN" in self.
intent:
345 def is_intent_inout(self):
348 if "INOUT" in self.
intent:
350 message =
"INOUT ignored in INPUT(%s)" 356 def is_intent_hide(self):
364 and "INPLACE" not in self.
intent 365 and "INOUT" not in self.
intent 369 def is_intent_inplace(self):
372 def is_intent_out(self):
375 def is_intent_c(self):
378 def is_intent_cache(self):
381 def is_intent_copy(self):
384 def is_intent_overwrite(self):
387 def is_intent_callback(self):
390 def is_intent_aux(self):
393 def is_private(self):
398 return self.
parent.parent.check_private(self.
name)
403 def is_allocatable(self):
406 def is_external(self):
409 def is_intrinsic(self):
412 def is_parameter(self):
415 def is_optional(self):
422 def is_required(self):
425 def is_pointer(self):
434 def update(self, *attrs):
436 if len(attrs) == 1
and isinstance(attrs[0], (tuple, list)):
441 if lattr.startswith(
"dimension"):
443 line = attr[9:].lstrip()
444 assert line[0] + line[-1] ==
"()", repr(line)
447 if lattr.startswith(
"intent"):
448 line = attr[6:].lstrip()
449 assert line[0] + line[-1] ==
"()", repr(line)
451 specs_split_comma(line[1:-1].strip(), self.
parent.item, upper=
True)
454 if lattr.startswith(
"bind"):
455 line = attr[4:].lstrip()
456 assert line[0] + line[-1] ==
"()", repr(line)
457 self.
bind = specs_split_comma(
458 line[1:-1].strip(), self.
parent.item, upper=
True 461 if lattr.startswith(
"check"):
462 line = attr[5:].lstrip()
463 assert line[0] + line[-1] ==
"()", repr(line)
464 self.
check.extend(split_comma(line[1:-1].strip(), self.
parent.item))
466 if uattr
not in attributes:
468 self.
parent.warning(
"unknown attribute %r" % (attr))
469 attributes.append(uattr)
474 if typedecl
is not None:
475 s += typedecl.tostr() +
" " 478 dimensions = [
":".join(spec)
for spec
in self.
dimension]
479 a.append(
"DIMENSION(%s)" % (
", ".join(dimensions)))
480 if self.
intent is not None:
481 a.append(
"INTENT(%s)" % (
", ".join(self.
intent)))
483 a.append(
"BIND(%s)" % (
", ".join(self.
bind)))
485 a.append(
"CHECK(%s)" % (
", ".join(self.
check)))
487 s +=
", " +
", ".join(a) +
" :: " 490 s +=
"(%s)" % (
", ".join([
":".join(spec)
for spec
in self.
bounds]))
492 if is_int_literal_constant(self.
length):
493 s +=
"*%s" % (self.
length)
495 s +=
"*(%s)" % (self.
length)
497 s +=
" = " + self.
init 500 def get_array_spec(self):
501 assert self.
is_array(),
"array_spec is available only for arrays" 505 "both bounds=%r and dimension=%r are defined, " 506 +
"ignoring dimension." 514 def is_deferred_shape_array(self):
519 def is_assumed_size_array(self):
524 def is_assumed_shape_array(self):
534 def is_explicit_shape_array(self):
540 if not spec[-1]
or spec[-1] ==
"*":
544 def is_allocatable_array(self):
547 def is_array_pointer(self):
554 self.
rank = len(array_spec)
559 for spec
in array_spec:
561 shape.append(spec[0].replace(
" ",
""))
565 lss = int(spec[0].replace(
" ",
""))
567 uss = int(spec[1].replace(
" ",
""))
570 n =
"(%s)-(%s)" % (spec[1], spec[0])
574 def error(self, message):
575 return self.
parent.error(message)
577 def warning(self, message):
578 return self.
parent.warning(message)
580 def info(self, message):
581 return self.
parent.info(message)
590 Statement instance has attributes: 591 parent - Parent BeginStatement or FortranParser instance 592 item - Line instance containing the statement line 593 isvalid - boolean, when False, the Statement instance will be ignored 596 modes = [
"free",
"fix",
"f77",
"pyf"]
597 _repr_attr_names = []
599 def __init__(self, parent, item):
604 self.
reader = parent.reader
605 self.
top = getattr(parent,
"top",
None)
608 if isinstance(parent, ProgramBlock):
610 elif isinstance(self, ProgramBlock):
612 elif hasattr(parent,
"programblock"):
625 for cls
in get_base_classes(self.__class__):
626 if hasattr(cls,
"a"):
627 a_dict.update(copy.deepcopy(cls.
a.todict()))
629 if hasattr(self.__class__,
"a"):
630 assert self.
a is not self.__class__.a
637 def torepr(self, depth=-1, incrtab=""):
639 clsname = self.__class__.__name__
640 lines = [tab + clsname]
642 return "\n".join(lines)
645 attr = getattr(self, n,
None)
648 if hasattr(attr,
"torepr"):
649 r = attr.torepr(depth - 1, incrtab)
652 lines.append(ttab +
"%s=%s" % (n, r))
653 if self.
item is not None:
654 lines.append(ttab +
"item=%r" % (self.
item))
656 lines.append(ttab +
"isvalid=%r" % (self.
isvalid))
658 lines.append(ttab +
"ignore=%r" % (self.
ignore))
659 if not self.
a.isempty():
661 ttab +
"a=" + self.
a.torepr(depth - 1, incrtab +
" ").lstrip()
663 return "\n".join(lines)
665 def get_indent_tab(self, deindent=False, isfix=None):
667 isfix = self.
reader.format.is_fixed
673 while isinstance(p, Statement):
678 label = getattr(self.
item,
"label",
None)
691 return self.tofortran()
695 for line
in self.tofortran(isfix=
True).split(
"\n"):
696 if len(line) > 72
and line[0] ==
" ":
697 lines.append(line[:72] +
"&\n &")
699 while len(line) > 66:
700 lines.append(line[:66] +
"&\n &")
702 lines.append(line +
"\n")
704 lines.append(line +
"\n")
705 return "".join(lines).replace(
"\n &\n",
"\n")
707 def format_message(self, kind, message):
708 if self.
item is not None:
709 message = self.
reader.format_message(
710 kind, message, self.
item.span[0], self.
item.span[1]
721 def error(self, message):
723 logging.getLogger(__name__).error(message)
725 def warning(self, message):
727 logging.getLogger(__name__).warning(message)
729 def info(self, message):
731 logging.getLogger(__name__).info(message)
734 self.
warning(
"nothing analyzed")
737 """Return Variable instance of variable name.""" 738 mth = getattr(self,
"get_variable_by_name", self.
parent.get_variable)
742 """Return type declaration using implicit rules 745 mth = getattr(self,
"get_type_by_name", self.
parent.get_type)
748 def get_type_decl(self, kind):
749 mth = getattr(self,
"get_type_decl_by_kind", self.
parent.get_type_decl)
754 Returns dictonary containing statements that block provides or None 761 """[ construct_name : ] <blocktype> [ <name> ] 763 BeginStatement instances have additional attributes: 767 Block instance has attributes: 768 content - list of Line or Statement instances 769 name - name of the block, unnamed blocks are named 771 construct_name - name of a construct 772 parent - Block or FortranParser instance 773 item - Line instance containing the block start statement 774 get_item, put_item - methods to retrive/submit Line instances 775 from/to Fortran reader. 776 isvalid - boolean, when False, the Block instance will be ignored. 778 stmt_cls, end_stmt_cls 786 ] + Statement._repr_attr_names
788 def __init__(self, parent, item=None):
793 if not hasattr(self,
"blocktype"):
794 self.
blocktype = self.__class__.__name__.lower()
795 if not hasattr(self,
"name"):
799 Statement.__init__(self, parent, item)
804 def tofortran(self, isfix=None):
806 construct_name = construct_name +
": " if construct_name
else "" 809 lines.append(c.tofortran(isfix=isfix))
810 return "\n".join(lines)
812 def torepr(self, depth=-1, incrtab=""):
815 lines = [Statement.torepr(self, depth=depth, incrtab=incrtab)]
816 if depth == 0
or not self.
content:
817 return "\n".join(lines)
818 lines.append(ttab +
"content:")
820 if isinstance(c, EndStatement):
821 lines.append(c.torepr(depth - 1, incrtab))
823 lines.append(c.torepr(depth - 1, incrtab +
" "))
824 return "\n".join(lines)
827 """Process the line""" 833 def fill(self, end_flag=False):
835 Fills blocks content until the end of block statement. 838 mode = self.
reader.format.mode
839 class_list = self.get_classes()
840 self.
classes = [cls
for cls
in class_list
if mode
in cls.
modes]
844 while item
is not None:
845 if isinstance(item, Line):
849 elif isinstance(item, Comment):
851 self.
content.append(classes.Comment(self, item))
853 raise NotImplementedError(repr(item))
857 self.
warning(
"failed to find the end of block")
861 Check if item is blocks start statement, if it is, read the block. 863 Return True to stop adding items to given block. 865 line = item.get_line()
868 cls = self.end_stmt_cls
870 stmt = cls(self, item)
875 if item.is_f2py_directive:
883 stmt = cls(self, item)
889 line = item.get_line()
893 if item.reader.format.is_f77:
896 message = item.reader.format_message(
898 'no parse pattern found for "%s" in %r block, ' 899 "trying to remove inline comment (not in Fortran 77)." 900 % (item.get_line(), self.__class__.__name__),
905 logging.getLogger(__name__).warning(message)
907 newitem = item.copy(line[:i].rstrip())
915 for cls
in self.get_classes():
916 if "f77" in cls.
modes and cls
not in f77_classes:
919 message = item.reader.format_message(
921 'no parse pattern found for "%s" in %r block' 922 " maybe due to strict f77 mode." 923 " Trying f90 fix mode patterns.." 924 % (item.get_line(), self.__class__.__name__),
928 logging.getLogger(__name__).warning(message)
930 item.reader.set_mode(
False,
False)
933 r = BeginStatement.process_subitem(self, item)
937 item.reader.set_mode(
False,
True)
939 message = item.reader.format_message(
941 "The f90 fix mode resolved the parse pattern issue." 942 " Setting reader to f90 fix mode.",
946 logging.getLogger(__name__).info(message)
948 self.
classes = f77_classes + classes
949 self.
reader.set_mode(
False,
False)
955 """Called when process_subitem does not find a start or end of block. 956 It adds the item (which is an instance of Line) to the content, but 957 then raises an AnalyzeError. An instance of Line in content typically 958 results in other errors later (e.g. because Line has no analyze 961 message = item.reader.format_message(
963 'no parse pattern found for "%s" in %r block.' 964 % (item.get_line(), self.__class__.__name__),
968 logging.getLogger(__name__).warning(message)
979 END [<blocktype> [<name>]] 981 EndStatement instances have additional attributes: 986 _repr_attr_names = [
"blocktype",
"name"] + Statement._repr_attr_names
988 def __init__(self, parent, item):
989 if not hasattr(self,
"blocktype"):
990 self.
blocktype = self.__class__.__name__.lower()[3:]
991 Statement.__init__(self, parent, item)
993 def process_item(self):
995 line = item.get_line().replace(
" ",
"")[3:]
996 line = item.apply_map(line)
999 if line.lower().startswith(blocktype):
1000 line = line[len(blocktype) :].strip()
1006 if self.
parent.construct_name:
1007 name = self.
parent.construct_name
1016 if line.lower() != name.lower():
1018 "expected the end of %r block " +
"but got the end of %r, skipping." 1020 self.
warning(message % (name, line))
1027 def get_indent_tab(self, deindent=False, isfix=None):
1028 return Statement.get_indent_tab(self, deindent=
True, isfix=isfix)
1031 """Returns a valid Fortran string for this END statement. It 1032 guarantees that there is no white space after the 'END' in case 1033 of an unnamed statement. 1035 :param bool isfix: True if the code is in fixed format. 1037 :returns: the (named or unnamed) valid Fortran END statement \
def is_explicit_shape_array(self)
def set_intent(self, intent)
def torepr(self, depth=-1, incrtab="")
def set_dimension(self, dims)
def set_type(self, typedecl)
def get_indent_tab(self, deindent=False, isfix=None)
def tofortran(self, isfix=None)
def warning(self, message)
def process_subitem(self, item)
def handle_unknown_item_and_raise(self, item)
def is_deferred_shape_array(self)
def fill(self, end_flag=False)
def torepr(self, depth=-1, tab="")
def get_variable(self, name)
def format_message(self, kind, message)
def warning(self, message)