fparser Reference Guide  0.0.14
block_statements.py
1 # -*- coding: utf-8 -*-
2 # Modified work Copyright (c) 2017-2018 Science and Technology
3 # Facilities Council.
4 # Original work Copyright (c) 1999-2008 Pearu Peterson.
5 
6 # All rights reserved.
7 
8 # Modifications made as part of the fparser project are distributed
9 # under the following license:
10 
11 # Redistribution and use in source and binary forms, with or without
12 # modification, are permitted provided that the following conditions are
13 # met:
14 
15 # 1. Redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer.
17 
18 # 2. Redistributions in binary form must reproduce the above copyright
19 # notice, this list of conditions and the following disclaimer in the
20 # documentation and/or other materials provided with the distribution.
21 
22 # 3. Neither the name of the copyright holder nor the names of its
23 # contributors may be used to endorse or promote products derived from
24 # this software without specific prior written permission.
25 
26 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 
38 # --------------------------------------------------------------------
39 
40 # The original software (in the f2py project) was distributed under
41 # the following license:
42 
43 # Redistribution and use in source and binary forms, with or without
44 # modification, are permitted provided that the following conditions are met:
45 
46 # a. Redistributions of source code must retain the above copyright notice,
47 # this list of conditions and the following disclaimer.
48 # b. Redistributions in binary form must reproduce the above copyright
49 # notice, this list of conditions and the following disclaimer in the
50 # documentation and/or other materials provided with the distribution.
51 # c. Neither the name of the F2PY project nor the names of its
52 # contributors may be used to endorse or promote products derived from
53 # this software without specific prior written permission.
54 
55 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
56 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
59 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
61 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
62 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
65 # DAMAGE.
66 
67 """
68 Fortran block statements.
69 
70 """
71 
72 import logging
73 import re
74 import sys
75 
76 import fparser.one.statements as statements
77 from fparser.one.statements import *
78 import fparser.one.typedecl_statements as typedecl_statements
80 
81 from fparser.common.base_classes import (
82  BeginStatement,
83  EndStatement,
84  Statement,
85  AttributeHolder,
86  ProgramBlock,
87  Variable,
88 )
89 from fparser.common.utils import (
90  split_comma,
91  filter_stmts,
92  parse_bind,
93  parse_result,
94  AnalyzeError,
95  is_name,
96 )
97 
98 __all__ = [
99  "BeginSource",
100  "Module",
101  "PythonModule",
102  "Program",
103  "BlockData",
104  "Interface",
105  "Subroutine",
106  "Function",
107  "SelectCase",
108  "SelectType",
109  "WhereConstruct",
110  "ForallConstruct",
111  "IfThen",
112  "If",
113  "Do",
114  "Associate",
115  "TypeDecl",
116  "Enum",
117  "EndSource",
118  "EndModule",
119  "EndPythonModule",
120  "EndProgram",
121  "EndBlockData",
122  "EndInterface",
123  "EndSubroutine",
124  "EndFunction",
125  "EndSelect",
126  "EndWhere",
127  "EndForall",
128  "EndIfThen",
129  "EndDo",
130  "EndAssociate",
131  "EndType",
132  "EndEnum",
133 ]
134 __all__.extend(statements.__all__)
135 __all__.extend(typedecl_statements.__all__)
136 
137 
139  """
140  Class encapsulating information about any Implicit statements
141  contained within a scoping block.
142  """
143 
144  a = AttributeHolder(implicit_rules={})
145 
146  def get_type_by_name(self, name):
147  """
148  Returns an object of the correct type (Integer or Real) using
149  Fortran's implicit typing rules for the supplied variable name.
150 
151  :param str name: The variable name.
152  :returns: Object describing the variable.
153  :rtype: Either :py:class:`fparser.one.typedecl_statements.Real` \
154  or :py:class:`fparser.one.typedecl_statements.Integer`.
155 
156  """
157  # The implicit_rules dict is populated by the analyze() method
158  # of one.typedecl_statements.Implicit
159  implicit_rules = self.a.implicit_rules
160  if implicit_rules is None:
161  raise AnalyzeError(
162  "Implicit rules mapping is null " "while getting %r type" % (name)
163  )
164  line = name[0].lower()
165  if line in implicit_rules:
166  return implicit_rules[line]
167  # default rules:
168  if line in "ijklmn":
169  line = "default_integer"
170  else:
171  line = "default_real"
172  var = implicit_rules.get(line, None)
173  if var is None:
174  if line[8:] == "real":
175  implicit_rules[line] = var = Real(self, self.item.copy("real"))
176  else:
177  implicit_rules[line] = var = Integer(self, self.item.copy("integer"))
178  return var
179 
180  def topyf(self, tab=" "):
181  """
182  Constructs a pyf representation of this class.
183 
184  :param str tab: White space to prepend to output.
185  :returns: pyf code for this implicit statement.
186  :rtype: str
187  """
188  implicit_rules = self.a.implicit_rules
189  if implicit_rules is None:
190  return tab + "IMPLICIT NONE\n"
191  # Construct a dict where the keys are types and the items are
192  # the list of initial letters mapped to that type
193  items = {}
194  for char, itype in list(implicit_rules.items()):
195  if char.startswith("default"):
196  continue
197  type_str = itype.tostr()
198  if type_str in items:
199  items[type_str].append(char)
200  else:
201  items[type_str] = [char]
202  if not items:
203  return tab + "! default IMPLICIT rules apply\n"
204  stmt = "IMPLICIT"
205  impl_list = []
206  for itype, letter_list in list(items.items()):
207  letter_list.sort()
208  impl_list.append(itype + " (%s)" % (", ".join(letter_list)))
209  stmt += " " + ", ".join(impl_list)
210  return tab + stmt + "\n"
211 
212 
214 
215  a = AttributeHolder(use={}, use_provides={})
216 
217  def get_entity(self, name):
218  for modname, modblock in list(self.top.a.module.items()):
219  for stmt in modblock.content:
220  if getattr(stmt, "name", "") == name:
221  return stmt
222  return
223 
224  def topyf(self, tab=" "):
225  sys.stderr.write("HasUseStmt.topyf not implemented\n")
226  return ""
227 
228 
230 
231  a = AttributeHolder(private_id_list=[], public_id_list=[])
232 
233  def topyf(self, tab=" "):
234  private_list = self.a.private_id_list
235  public_list = self.a.public_id_list
236  lines = []
237  if "" in private_list:
238  lines.append(tab + "PRIVATE\n")
239  if "" in public_list:
240  lines.append(tab + "PUBLIC\n")
241  for a in private_list:
242  if not a:
243  continue
244  lines.append(tab + "PRIVATE :: %s\n" % (a))
245  for a in public_list:
246  if not a:
247  continue
248  lines.append(tab + "PUBLIC :: %s\n" % (a))
249  return "".join(lines)
250 
251 
253 
254  a = AttributeHolder(
255  variables={}, variable_names=[] # defines the order of declarations
256  )
257 
258  def get_variable_by_name(self, name):
259  variables = self.a.variables
260  if name in variables:
261  var = variables[name]
262  else:
263  var = variables[name] = Variable(self, name)
264  self.a.variable_names.append(name)
265  return var
266 
267  def topyf(self, tab="", only_variables=None):
268  s = ""
269  if only_variables is None:
270  only_variables = list(self.a.variables.keys())
271  for name in only_variables:
272  var = self.a.variables[name]
273  s += tab + str(var) + "\n"
274  return s
275 
276 
278 
279  a = AttributeHolder(type_decls={})
280 
281  def topyf(self, tab=""):
282  s = ""
283  for name, stmt in list(self.a.type_decls.items()):
284  s += stmt.topyf(tab=" " + tab)
285  return s
286 
287  def get_type_decl_by_kind(self, kind):
288  type_decls = self.a.type_decls
289  type_decl = type_decls.get(kind, None)
290  if type_decl is None:
291  return self.get_entity(kind)
292  return type_decl
293 
294 
296 
297  known_attributes = []
298  a = AttributeHolder(attributes=[])
299 
300  def topyf(self, tab=""):
301  s = ""
302  for attr in self.a.attributes:
303  s += tab + attr + "\n"
304  return s
305 
306  def update_attributes(self, *attrs):
307  attributes = self.a.attributes
308  known_attributes = self.known_attributes
309  if len(attrs) == 1 and isinstance(attrs[0], (tuple, list)):
310  attrs = attrs[0]
311  for attr in attrs:
312  uattr = attr.upper()
313  if uattr not in attributes:
314  if isinstance(known_attributes, (list, tuple)):
315  if uattr not in known_attributes:
316  self.warning("unknown attribute %r" % (attr))
317  elif not known_attributes(uattr):
318  self.warning("unknown attribute %r" % (attr))
319  attributes.append(uattr)
320  else:
321  self.warning("multiple specification of attribute %r" % (attr))
322  return
323 
324 
326 
327  a = AttributeHolder(module_procedures=[])
328 
329 
330 # File block
331 
332 
333 class EndSource(EndStatement):
334  """
335  Dummy End statement for BeginSource.
336  """
337 
338  match = staticmethod(lambda s: False)
339 
340 
341 class BeginSource(BeginStatement):
342  """
343  Fortran source content.
344  """
345 
346  match = staticmethod(lambda s: True)
347  end_stmt_cls = EndSource
348  a = AttributeHolder(module={}, external_subprogram={}, blockdata={})
349 
350  def tofortran(self, isfix=None):
351  if isfix:
352  tab = "C"
353  else:
354  tab = self.get_indent_tab(isfix=isfix) + "!"
355  return tab + BeginStatement.tofortran(self, isfix=isfix)
356 
357  def tostr(self):
358  return self.blocktype.upper() + " " + self.name
359 
360  def process_item(self):
361  self.name = self.reader.name
362  self.top = self
363  self.fill(end_flag=True)
364  return
365 
366  def analyze(self):
367  for stmt in self.content:
368  if isinstance(stmt, Module):
369  stmt.analyze()
370  self.a.module[stmt.name] = stmt
371  elif isinstance(stmt, SubProgramStatement):
372  stmt.analyze()
373  self.a.external_subprogram[stmt.name] = stmt
374  elif isinstance(stmt, BlockData):
375  stmt.analyze()
376  self.a.blockdata[stmt.name] = stmt
377  else:
378  stmt.analyze()
379  return
380 
381  def get_classes(self):
382  if self.reader.format.is_pyf:
383  return [PythonModule] + program_unit
384  return program_unit
385 
386  def process_subitem(self, item):
387  # MAIN block does not define start/end line conditions,
388  # so it should never end until all lines are read.
389  # However, sometimes F77 programs lack the PROGRAM statement,
390  # and here we fix that:
391  if self.reader.format.is_f77:
392  line = item.get_line()
393  if line == "end":
394  message = item.reader.format_message(
395  "WARNING",
396  "assuming the end of undefined PROGRAM statement",
397  item.span[0],
398  item.span[1],
399  )
400  logger.warning(message)
401  # print >> sys.stderr, message
402  p = Program(self)
403  p.content.extend(self.content)
404  p.content.append(EndProgram(p, item))
405  self.content[:] = [p]
406  return
407  return BeginStatement.process_subitem(self, item)
408 
409  def topyf(self, tab=""): # XXXX
410  s = ""
411  for name, stmt in list(self.a.module.items()):
412  s += stmt.topyf(tab=tab)
413  for name, stmt in list(self.a.external_subprogram.items()):
414  s += stmt.topyf(tab=tab)
415  for name, stmt in list(self.a.blockdata.items()):
416  s += stmt.topyf(tab=tab)
417  return s
418 
419 
420 # Module
421 
422 
423 class EndModule(EndStatement):
424  match = re.compile(r"end(\s*module\s*\w*|)\Z", re.I).match
425 
426 
427 class Module(
428  BeginStatement,
429  HasAttributes,
430  HasImplicitStmt,
431  HasUseStmt,
432  HasVariables,
433  HasTypeDecls,
434  AccessSpecs,
435 ):
436  """
437  MODULE <name>
438  ..
439  END [MODULE [name]]
440  """
441 
442  match = re.compile(r"module\s*\w+\Z", re.I).match
443  end_stmt_cls = EndModule
444 
445  a = AttributeHolder(
446  module_subprogram={},
447  module_provides={}, # all symbols that are public and
448  # so can be imported via USE
449  # statement by other blocks
450  module_interface={},
451  )
452 
453  known_attributes = ["PUBLIC", "PRIVATE"]
454 
455  def get_classes(self):
456  return access_spec + specification_part + module_subprogram_part
457 
458  def process_item(self):
459  name = self.item.get_line().replace(" ", "")
460  name = name[len(self.blocktype) :].strip()
461  self.name = name
462  return BeginStatement.process_item(self)
463 
464  def get_provides(self):
465  return self.a.module_provides
466 
467  def get_interface(self):
468  return self.a.module_interface
469 
470  def analyze(self):
471  content = self.content[:]
472 
473  while content:
474  stmt = content.pop(0)
475  if isinstance(stmt, Contains):
476  for stmt in filter_stmts(content, SubProgramStatement):
477  stmt.analyze()
478  self.a.module_subprogram[stmt.name] = stmt
479  stmt = content.pop(0)
480  while isinstance(stmt, Comment):
481  stmt = content.pop(0)
482  if not isinstance(stmt, EndModule):
483  stmt.error("Expected END MODULE statement (analyzer).")
484  continue
485  stmt.analyze()
486 
487  if content:
488  logger.info("Not analyzed content: %s" % content)
489  # self.show_message('Not analyzed content: %s' % content)
490 
491  module_provides = self.a.module_provides
492  for name, var in list(self.a.variables.items()):
493  if var.is_public():
494  if name in module_provides:
495  message = (
496  "module data object name conflict with %s, " + "overriding."
497  )
498  self.warning(message % (name))
499  module_provides[name] = var
500 
501  return
502 
503  def topyf(self, tab=""):
504  s = tab + "MODULE " + self.name + "\n"
505  s += HasImplicitStmt.topyf(self, tab=tab + " ")
506  s += AccessSpecs.topyf(self, tab=tab + " ")
507  s += HasAttributes.topyf(self, tab=tab + " ")
508  s += HasTypeDecls.topyf(self, tab=tab + " ")
509  s += HasVariables.topyf(self, tab=tab + " ")
510  for name, stmt in list(self.a.module_interface.items()):
511  s += stmt.topyf(tab=tab + " ")
512  s += tab + " CONTAINS\n"
513  for name, stmt in list(self.a.module_subprogram.items()):
514  s += stmt.topyf(tab=tab + " ")
515  s += tab + "END MODULE " + self.name + "\n"
516  return s
517 
518  def check_private(self, name):
519  if name in self.a.public_id_list:
520  return False
521  if name in self.a.private_id_list:
522  return True
523  if "" in self.a.public_id_list:
524  return False
525  if "" in self.a.private_id_list:
526  return True
527  # todo: handle generic-spec-s in id-lists.
528  return
529 
530 
531 # Python Module
532 
533 
534 class EndPythonModule(EndStatement):
535  match = re.compile(r"end(\s*python\s*module\s*\w*|)\Z", re.I).match
536 
537 
539  """
540  PYTHON MODULE <name>
541  ..
542  END [PYTHON MODULE [name]]
543  """
544 
545  modes = ["pyf"]
546  match = re.compile(r"python\s*module\s*\w+\Z", re.I).match
547  end_stmt_cls = EndPythonModule
548 
549  def get_classes(self):
550  return [Interface, Function, Subroutine, Module]
551 
552  def process_item(self):
553  self.name = self.item.get_line().replace(" ", "")
554  self.name = self.name[len(self.blocktype) :].strip()
555  return BeginStatement.process_item(self)
556 
557 
558 # Program
559 
560 
561 class EndProgram(EndStatement):
562  """
563  END [PROGRAM [name]]
564  """
565 
566  match = re.compile(r"end(\s*program\s*\w*|)\Z", re.I).match
567 
568 
569 class Program(
570  BeginStatement,
571  ProgramBlock,
572  # HasAttributes, # XXX: why Program needs .attributes?
573  HasVariables,
574  HasImplicitStmt,
575  HasUseStmt,
576  AccessSpecs,
577 ):
578  """PROGRAM [name]"""
579 
580  match = re.compile(r"program\s*\w*\Z", re.I).match
581  end_stmt_cls = EndProgram
582 
583  def get_classes(self):
584  return specification_part + execution_part + internal_subprogram_part
585 
586  def process_item(self):
587  if self.item is not None:
588  name = self.item.get_line().replace(" ", "")
589  name = name[len(self.blocktype) :].strip()
590  if name:
591  self.name = name
592  return BeginStatement.process_item(self)
593 
594 
595 # BlockData
596 
597 
598 class EndBlockData(EndStatement):
599  """
600  END [BLOCK DATA [<block-data-name>]]
601  """
602 
603  match = re.compile(r"end(\s*block\s*data\s*\w*|)\Z", re.I).match
604  blocktype = "blockdata"
605 
606 
608  """
609  BLOCK DATA [<block-data-name>]
610  """
611 
612  end_stmt_cls = EndBlockData
613  match = re.compile(r"block\s*data\s*\w*\Z", re.I).match
614 
615  def process_item(self):
616  self.name = self.item.get_line()[5:].lstrip()[4:].lstrip()
617  return BeginStatement.process_item(self)
618 
619  def get_classes(self):
620  return specification_part
621 
622 
623 # Interface
624 
625 
626 class EndInterface(EndStatement):
627  match = re.compile(r"end\s*interface\s*(\w+\s*\(.*\)|\w*)\Z", re.I).match
628  blocktype = "interface"
629 
630 
631 class Interface(
632  BeginStatement,
633  HasAttributes,
634  HasImplicitStmt,
635  HasUseStmt,
636  HasModuleProcedures,
637  AccessSpecs,
638 ):
639  """
640  INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
641  END INTERFACE [<generic-spec>]
642 
643  <generic-spec> = <generic-name>
644  | OPERATOR ( <defined-operator> )
645  | ASSIGNMENT ( = )
646  | <dtio-generic-spec>
647  <dtio-generic-spec> = READ ( FORMATTED )
648  | READ ( UNFORMATTED )
649  | WRITE ( FORMATTED )
650  | WRITE ( UNFORMATTED )
651 
652  """
653 
654  modes = ["free", "fix", "pyf"]
655  pattern = r"(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z"
656  match = re.compile(pattern, re.I).match
657  end_stmt_cls = EndInterface
658  blocktype = "interface"
659 
660  a = AttributeHolder(interface_provides={})
661 
662  def get_classes(self):
663  line = intrinsic_type_spec + interface_specification
664  if self.reader.format.mode == "pyf":
665  return [Subroutine, Function] + line
666  return line
667 
668  def process_item(self):
669  line = self.item.get_line()
670  line = self.item.apply_map(line)
671  self.isabstract = line.startswith("abstract")
672  if self.isabstract:
673  self.generic_spec = ""
674  else:
675  self.generic_spec = line[len(self.blocktype) :].strip()
676  self.name = self.generic_spec # XXX
677  return BeginStatement.process_item(self)
678 
679  def tostr(self):
680  if self.isabstract:
681  return "ABSTRACT INTERFACE"
682  return "INTERFACE " + str(self.generic_spec)
683 
684  def analyze(self):
685  content = self.content[:]
686 
687  while content:
688  stmt = content.pop(0)
689  if isinstance(stmt, self.end_stmt_cls):
690  break
691  stmt.analyze()
692  if content:
693  logger.info("Not analyzed content: %s" % content)
694  # self.show_message('Not analyzed content: %s' % content)
695 
696  if self.name in self.parent.a.variables:
697  var = self.parent.a.variables.pop(self.name)
698  self.update_attributes(var.attributes)
699 
700  if isinstance(self.parent, Module): # XXX
701  parent_interface = self.parent.get_interface()
702  if self.name in parent_interface:
703  p = parent_interface[self.name]
704  last = p.content.pop()
705  assert isinstance(last, EndInterface), repr(last.__class__)
706  p.content += self.content
707  p.update_attributes(self.a.attributes)
708  else:
709  parent_interface[self.name] = self
710  return
711 
712  def topyf(self, tab=""):
713  s = tab + self.tostr() + "\n"
714  s += HasImplicitStmt.topyf(self, tab=tab + " ")
715  s += HasAttributes.topyf(self, tab=tab + " ")
716  s += HasUseStmt.topyf(self, tab=tab + " ")
717  s += tab + "END" + self.tostr() + "\n"
718  return s
719 
720 
721 # Subroutine
722 
723 
724 class SubProgramStatement(
725  BeginStatement,
726  ProgramBlock,
727  HasImplicitStmt,
728  HasAttributes,
729  HasUseStmt,
730  HasVariables,
731  HasTypeDecls,
732  AccessSpecs,
733 ):
734  """
735  [<prefix>] <FUNCTION|SUBROUTINE> <name> [( <args> )] [<suffix>]
736  """
737 
738  a = AttributeHolder(internal_subprogram={})
739  known_attributes = ["RECURSIVE", "PURE", "ELEMENTAL"]
740 
741  def process_item(self):
742  clsname = self.__class__.__name__.lower()
743  item = self.item
744  line = item.get_line()
745  m = self.match(line)
746  i = line.lower().find(clsname)
747  assert i != -1, repr((clsname, line))
748  self.prefix = line[:i].rstrip()
749  self.name = line[i : m.end()].lstrip()[len(clsname) :].strip()
750  line = line[m.end() :].lstrip()
751  args = []
752  if line.startswith("("):
753  i = line.find(")")
754  assert i != -1, repr(line)
755  line2 = item.apply_map(line[: i + 1])
756  for a in line2[1:-1].split(","):
757  a = a.strip()
758  if not a:
759  continue
760  args.append(a)
761  line = line[i + 1 :].lstrip()
762  suffix = item.apply_map(line)
763  self.bind, suffix = parse_bind(suffix, item)
764  self.result = None
765  if isinstance(self, Function):
766  self.result, suffix = parse_result(suffix, item)
767  if suffix:
768  assert self.bind is None, repr(self.bind)
769  self.bind, suffix = parse_result(suffix, item)
770  if self.result is None:
771  self.result = self.name
772  assert not suffix, repr(suffix)
773  self.args = args
774  self.typedecl = None
775  return BeginStatement.process_item(self)
776 
777  def tostr(self):
778  clsname = self.__class__.__name__.upper()
779  s = ""
780  if self.prefix:
781  s += self.prefix + " "
782  if self.typedecl is not None:
783  assert isinstance(self, Function), repr(self.__class__.__name__)
784  s += self.typedecl.tostr() + " "
785  s += clsname
786  suf = ""
787  if self.result and self.result != self.name:
788  suf += " RESULT ( %s )" % (self.result)
789  if self.bind:
790  suf += " BIND ( %s )" % (", ".join(self.bind))
791  return "%s %s(%s)%s" % (s, self.name, ", ".join(self.args), suf)
792 
793  def get_classes(self):
794  return (
795  f2py_stmt + specification_part + execution_part + internal_subprogram_part
796  )
797 
798  def analyze(self):
799  content = self.content[:]
800 
801  if self.prefix:
802  self.update_attributes(self.prefix.upper().split())
803 
804  variables = self.a.variables
805  for a in self.args:
806  assert a not in variables
807  if is_name(a):
808  variables[a] = Variable(self, a)
809  elif a == "*":
810  variables[a] = Variable(self, a) # XXX: fix me appropriately
811  else:
812  message = "argument must be a name or * but got %r"
813  raise AnalyzeError(message % (a))
814 
815  if isinstance(self, Function):
816  var = variables[self.result] = Variable(self, self.result)
817  if self.typedecl is not None:
818  var.set_type(self.typedecl)
819 
820  while content:
821  stmt = content.pop(0)
822  if isinstance(stmt, Contains):
823  for stmt in filter_stmts(content, SubProgramStatement):
824  stmt.analyze()
825  self.a.internal_subprogram[stmt.name] = stmt
826  stmt = content.pop(0)
827  while isinstance(stmt, Comment):
828  stmt = content.pop(0)
829  assert isinstance(stmt, self.end_stmt_cls), repr(stmt)
830  elif isinstance(stmt, self.end_stmt_cls):
831  continue
832  else:
833  if hasattr(stmt, "analyze"):
834  stmt.analyze()
835  else:
836  message = "Failed to parse: {0}"
837  raise AnalyzeError(message.format(str(stmt)))
838 
839  if content:
840  logger.info("Not analyzed content: %s" % content)
841  # self.show_message('Not analyzed content: %s' % content)
842 
843  parent_provides = self.parent.get_provides()
844  if parent_provides is not None:
845  if self.name in parent_provides:
846  message = "module subprogram name conflict with %s, " + "overriding."
847  self.warning(message % (self.name))
848  if self.is_public():
849  parent_provides[self.name] = self
850 
851  if self.is_recursive() and self.is_elemental():
852  message = (
853  "C1241 violation: prefix cannot specify both "
854  + "ELEMENTAL and RECURSIVE"
855  )
856  self.warning(message)
857  return
858 
859  def topyf(self, tab=""):
860  s = tab + self.__class__.__name__.upper()
861  s += " " + self.name + " (%s)" % (", ".join(self.args))
862  if isinstance(self, Function) and self.result != self.name:
863  s += " RESULT (%s)" % (self.result)
864  s += "\n"
865  s += HasImplicitStmt.topyf(self, tab=tab + " ")
866  s += AccessSpecs.topyf(self, tab=tab + " ")
867  s += HasTypeDecls.topyf(self, tab=tab + " ")
868  s += HasVariables.topyf(self, tab=tab + " ", only_variables=self.args)
869  s += tab + "END " + self.__class__.__name__.upper() + " " + self.name + "\n"
870  return s
871 
872  def is_public(self):
873  return not self.is_private()
874 
875  def is_private(self):
876  return self.parent.check_private(self.name)
877 
878  def is_recursive(self):
879  return "RECURSIVE" in self.a.attributes
880 
881  def is_pure(self):
882  return "PURE" in self.a.attributes
883 
884  def is_elemental(self):
885  return "ELEMENTAL" in self.a.attributes
886 
887 
888 class EndSubroutine(EndStatement):
889  """
890  END [SUBROUTINE [name]]
891  """
892 
893  match = re.compile(
894  r"end\s*(?:subroutine\s*(?:(?P<name>\w+)\s*)?)?$", re.IGNORECASE
895  ).match
896 
897 
899  """
900  [<prefix>] SUBROUTINE <name> [( [<dummy-arg-list>] )
901  [<proc-language-binding-spec>]]
902  """
903 
904  end_stmt_cls = EndSubroutine
905  pattern = r"(recursive|pure|elemental|\s)*subroutine\s*\w+"
906  match = re.compile(pattern, re.I).match
907  _repr_attr_names = ["prefix", "bind", "suffix", "args"] + Statement._repr_attr_names
908 
909 
910 # Function
911 
912 
913 class EndFunction(EndStatement):
914  """
915  END [FUNCTION [name]]
916  """
917 
918  match = re.compile(r"end(\s*function\s*\w*|)\Z", re.I).match
919 
920 
922  """
923  [<prefix>] FUNCTION <name> ( [<dummy-arg-list>] ) [<suffix>]
924  <prefix> = <prefix-spec> [<prefix-spec>]...
925  <prefix-spec> = <declaration-type-spec>
926  | RECURSIVE | PURE | ELEMENTAL
927  <suffix> = <proc-language-binding-spec> [RESULT ( <result-name> )]
928  | RESULT ( <result-name> ) [<proc-language-binding-spec>]
929  """
930 
931  end_stmt_cls = EndFunction
932  pattern = r"(recursive|pure|elemental|\s)*function\s*\w+"
933  match = re.compile(pattern, re.I).match
934  _repr_attr_names = [
935  "prefix",
936  "bind",
937  "suffix",
938  "args",
939  "typedecl",
940  ] + Statement._repr_attr_names
941 
942  def subroutine_wrapper_code(self):
943  name = "f2pywrap_" + self.name
944  args = ["f2pyvalue_" + self.result] + self.args
945  var = self.a.variables[self.result]
946  typedecl = var.get_typedecl().astypedecl()
947  lines = []
948  tab = " " * 6
949  lines.append("%sSUBROUTINE %s(%s)" % (tab, name, ", ".join(args)))
950  if isinstance(self.parent, Module):
951  lines.append("%s USE %s" % (tab, self.parent.name))
952  else:
953  if isinstance(typedecl, TypeStmt):
954  type_decl = typedecl.get_type_decl(typedecl.name)
955  if type_decl.parent is self:
956  for line in str(type_decl).split("\n"):
957  lines.append("%s %s" % (tab, line.lstrip()))
958  lines.append("%s EXTERNAL %s" % (tab, self.name))
959  lines.append("%s %s %s" % (tab, str(typedecl).lstrip(), self.name))
960  lines.append("%s %s %s" % (tab, str(typedecl).lstrip(), args[0]))
961  lines.append("!f2py intent(out) %s" % (args[0]))
962  for a in self.args:
963  v = self.a.variables[a]
964  lines.append("%s %s" % (tab, str(v).lstrip()))
965  lines.append(
966  "%s %s = %s(%s)" % (tab, args[0], self.name, ", ".join(self.args))
967  )
968  lines.append("%sEND SUBROUTINE %s" % (tab, name))
969  return "\n".join(lines)
970 
971  def subroutine_wrapper(self):
972  code = self.subroutine_wrapper_code()
973  from .api import parse
974 
975  block = parse(code) # XXX: set include_dirs
976  while len(block.content) == 1:
977  block = block.content[0]
978  return block
979 
980 
981 # Handle subprogram prefixes
982 
983 
985  """
986  <prefix> <declaration-type-spec> <function|subroutine> ...
987  """
988 
989  match = re.compile(r"(pure|elemental|recursive|\s)+\b", re.I).match
990 
991  def process_item(self):
992  line = self.item.get_line()
993  m = self.match(line)
994  prefix = line[: m.end()].rstrip()
995  rest = self.item.get_line()[m.end() :].lstrip()
996  if rest:
997  self.parent.put_item(self.item.copy(prefix))
998  self.item.clone(rest)
999  self.isvalid = False
1000  return
1001  if self.parent.__class__ not in [Function, Subroutine]:
1002  self.isvalid = False
1003  return
1004  prefix = prefix + " " + self.parent.prefix
1005  self.parent.prefix = prefix.strip()
1006  self.ignore = True
1007  return
1008 
1009 
1010 # SelectCase
1011 
1012 
1013 class EndSelect(EndStatement):
1014  match = re.compile(r"end\s*select\s*\w*\Z", re.I).match
1015  blocktype = "select"
1016 
1017 
1018 class Select(BeginStatement):
1019  """
1020  Base class for the Select (case/type) statement
1021 
1022  """
1023 
1024  end_stmt_cls = EndSelect
1025  name = ""
1026 
1027  def process_item(self):
1028  """Populate the state of this Select object by parsing the
1029  associated line of code"""
1030  item = self.item
1031  # TODO make the following more robust, particularly to the
1032  # presence of a name at the beginning
1033  # (e.g. "a_name: select case(...)")
1034  line = item.get_line()[6:].lstrip()[4:].lstrip()[1:-1].strip()
1035  self.expr = item.apply_map(line)
1036  self.construct_name = self.item.name
1037  return BeginStatement.process_item(self)
1038 
1039 
1041  """
1042  [<case-construct-name> :] SELECT CASE ( <case-expr> )
1043 
1044  """
1045 
1046  match = re.compile(r"select\s*case\s*\(.*\)\Z", re.I).match
1047 
1048  def tostr(self):
1049  return "SELECT CASE ( %s )" % (self.expr)
1050 
1051  def get_classes(self):
1052  """Return the list of classes that this instance may
1053  have as children"""
1054  return [Case] + execution_part_construct
1055 
1056 
1058  """
1059  [<case-construct-name> :] SELECT TYPE ( <case-expr> )
1060 
1061  """
1062 
1063  match = re.compile(r"select\s*type\s*\(.*\)\Z", re.I).match
1064 
1065  def tostr(self):
1066  return "SELECT TYPE ( %s )" % (self.expr)
1067 
1068  def get_classes(self):
1069  """Return the list of classes that this instance may
1070  have as children"""
1071  return [TypeIs, ClassIs] + execution_part_construct
1072 
1073 
1074 # Where
1075 
1076 
1077 class EndWhere(EndStatement):
1078  """
1079  END WHERE [<where-construct-name>]
1080  """
1081 
1082  match = re.compile(r"end\s*\where\s*\w*\Z", re.I).match
1083 
1084 
1085 class Where(BeginStatement):
1086  """
1087  [<where-construct-name> :] WHERE ( <mask-expr> )
1088  <mask-expr> = <logical-expr>
1089  """
1090 
1091  match = re.compile(r"where\s*\([^)]*\)\Z", re.I).match
1092  end_stmt_cls = EndWhere
1093  name = ""
1094 
1095  def tostr(self):
1096  return "WHERE ( %s )" % (self.expr)
1097 
1098  def process_item(self):
1099  self.expr = self.item.get_line()[5:].lstrip()[1:-1].strip()
1100  self.construct_name = self.item.name
1101  return BeginStatement.process_item(self)
1102 
1103  def get_classes(self):
1104  return [Assignment, WhereStmt, WhereConstruct, ElseWhere]
1105 
1106 
1107 WhereConstruct = Where
1108 
1109 
1110 # Forall
1111 
1112 
1113 class EndForall(EndStatement):
1114  """
1115  END FORALL [<forall-construct-name>]
1116  """
1117 
1118  match = re.compile(r"end\s*forall\s*\w*\Z", re.I).match
1119 
1120 
1121 class Forall(BeginStatement):
1122  """
1123  [<forall-construct-name> :] FORALL <forall-header>
1124  [<forall-body-construct>]...
1125  <forall-body-construct> = <forall-assignment-stmt>
1126  | <where-stmt>
1127  | <where-construct>
1128  | <forall-construct>
1129  | <forall-stmt>
1130  <forall-header> = ( <forall-triplet-spec-list> [, <scalar-mask-expr>] )
1131  <forall-triplet-spec> = <index-name> = <subscript> : <subscript>
1132  [: <stride>]
1133  <subscript|stride> = <scalar-int-expr>
1134  <forall-assignment-stmt> = <assignment-stmt> | <pointer-assignment-stmt>
1135  """
1136 
1137  end_stmt_cls = EndForall
1138  match = re.compile(r"forall\s*\(.*\)\Z", re.I).match
1139  name = ""
1140 
1141  def process_item(self):
1142  self.specs = self.item.get_line()[6:].lstrip()[1:-1].strip()
1143  return BeginStatement.process_item(self)
1144 
1145  def tostr(self):
1146  return "FORALL (%s)" % (self.specs)
1147 
1148  def get_classes(self):
1149  return [
1150  GeneralAssignment,
1151  WhereStmt,
1152  WhereConstruct,
1153  ForallConstruct,
1154  ForallStmt,
1155  ]
1156 
1157 
1158 ForallConstruct = Forall
1159 
1160 
1161 # IfThen
1162 
1163 
1164 class EndIfThen(EndStatement):
1165  """
1166  END IF [<if-construct-name>]
1167  """
1168 
1169  match = re.compile(r"end\s*if\s*\w*\Z", re.I).match
1170  blocktype = "if"
1171 
1172 
1173 class IfThen(BeginStatement):
1174  """
1175  [<if-construct-name> :] IF ( <scalar-logical-expr> ) THEN
1176 
1177  IfThen instance has the following attributes:
1178  expr
1179  """
1180 
1181  match = re.compile(r"if\s*\(.*\)\s*then\Z", re.I).match
1182  end_stmt_cls = EndIfThen
1183  name = ""
1184 
1185  def tostr(self):
1186  return "IF (%s) THEN" % (self.expr)
1187 
1188  def process_item(self):
1189  item = self.item
1190  line = item.get_line()[2:-4].strip()
1191  assert line[0] == "(" and line[-1] == ")", repr(line)
1192  self.expr = item.apply_map(line[1:-1].strip())
1193  self.construct_name = item.name
1194  return BeginStatement.process_item(self)
1195 
1196  def get_classes(self):
1197  return [Else, ElseIf] + execution_part_construct
1198 
1199 
1200 class If(BeginStatement):
1201  """
1202  IF ( <scalar-logical-expr> ) action-stmt
1203  """
1204 
1205  match = re.compile(r"if\s*\(", re.I).match
1206 
1207  def process_item(self):
1208  item = self.item
1209  mode = self.reader.format.mode
1210  classes = self.get_classes()
1211  classes = [cls for cls in classes if mode in cls.modes]
1212 
1213  line = item.get_line()[2:].lstrip()
1214  i = line.find(")")
1215  expr = line[1:i].strip()
1216  line = line[i + 1 :].strip()
1217  if line.lower() == "then":
1218  self.isvalid = False
1219  return
1220  self.expr = item.apply_map(expr)
1221 
1222  if not line:
1223  newitem = self.get_item()
1224  else:
1225  newitem = item.copy(line, apply_map=True)
1226  newline = newitem.get_line()
1227  for cls in classes:
1228  if cls.match(newline):
1229  stmt = cls(self, newitem)
1230  if stmt.isvalid:
1231  self.content.append(stmt)
1232  return
1233  if not line:
1234  self.put_item(newitem)
1235  self.isvalid = False
1236  return
1237 
1238  def tostr(self):
1239  assert len(self.content) == 1, repr(self.content)
1240  return "IF (%s) %s" % (self.expr, str(self.content[0]).lstrip())
1241 
1242  def tofortran(self, isfix=None):
1243  return self.get_indent_tab(isfix=isfix) + self.tostr()
1244 
1245  def get_classes(self):
1246  return action_stmt
1247 
1248 
1249 # Do
1250 
1251 
1252 class EndDo(EndStatement):
1253  """
1254  END DO [<do-construct-name>]
1255  """
1256 
1257  match = re.compile(r"end\s*do\s*(?:(?P<name>\w+)\s*)?\Z", re.IGNORECASE).match
1258  blocktype = "do"
1259 
1260  def process_item(self):
1261  """
1262  Parses the next line assuming it is an "End do" statement.
1263 
1264  Overrides method in `EndStatement`.
1265  """
1266  item = self.item
1267  line = item.get_line()
1268  matched = self.match(line)
1269  # Check for matching labels
1270  found_label = getattr(self.item, "label", None)
1271  expected_label = getattr(self.parent, "endlabel", None)
1272  if expected_label:
1273  if found_label:
1274  if found_label != expected_label:
1275  message = (
1276  'When entering the "do" block {start} was'
1277  + " given as the end label but {end} was found."
1278  )
1279  self.warning(message.format(start=expected_label, end=found_label))
1280  self.isvalid = False
1281  else:
1282  message = (
1283  'A label was specified when entering the "do" '
1284  + " block ({label}) but none was found at the end."
1285  )
1286  self.warning(message.format(label=expected_label))
1287  self.isvalid = False
1288  # Check for matching names
1289  found_name = matched.group("name") or None
1290  expected_name = self.parent.construct_name
1291  if expected_name:
1292  if found_name:
1293  if found_name != expected_name:
1294  message = (
1295  'The "do" block was specified with the name'
1296  + ' "{open}" but was closed with the name'
1297  + ' "{close}".'
1298  )
1299  self.warning(message.format(open=expected_name, close=found_name))
1300  self.isvalid = False
1301  else:
1302  message = (
1303  'A name ("{name}") was specified for the "do" '
1304  + "block but was not given when closing the block."
1305  )
1306  self.warning(message.format(name=expected_name))
1307  self.isvalid = False
1308  else:
1309  if found_name:
1310  message = (
1311  'The name "{name}" was used when closing a "do"'
1312  + "block but none was specified when opening it."
1313  )
1314  self.warning(message.format(name=found_name))
1315  self.isvalid = False
1316  return EndStatement.process_item(self)
1317 
1318 
1319 class Do(BeginStatement):
1320  """
1321  [<do-construct-name> :] DO label [loopcontrol]
1322  [<do-construct-name> :] DO [loopcontrol]
1323 
1324  """
1325 
1326  match = re.compile(r"do\b\s*\d*", re.I).match
1327  pattern = r"do\b\s*(?:(?P<label>\d+)\s*)?(?:,\s*)?(?P<loopcontrol>.+)?\Z"
1328  item_re = re.compile(pattern, re.IGNORECASE).match
1329  end_stmt_cls = EndDo
1330  name = ""
1331 
1332  def tostr(self):
1333  lst = ["DO"]
1334  for part in [self.endlabel, self.loopcontrol]:
1335  if part:
1336  lst.append(str(part))
1337  return " ".join(lst)
1338 
1339  def process_item(self):
1340  """
1341  Parses the next line assuming it is a "Do" statement.
1342 
1343  Overrides method in `BeginStatement`.
1344  """
1345  item = self.item
1346  line = item.get_line()
1347  matched = self.item_re(line)
1348  if matched.group("label"):
1349  self.endlabel = int(matched.group("label").strip())
1350  else:
1351  self.endlabel = None
1352  self.construct_name = item.name
1353  if matched.group("loopcontrol"):
1354  self.loopcontrol = item.apply_map(matched.group("loopcontrol").strip())
1355  else:
1356  self.loopcontrol = None
1357  return BeginStatement.process_item(self)
1358 
1359  def process_subitem(self, item):
1360  result = False
1361  if self.endlabel:
1362  label = item.label
1363  if label == self.endlabel:
1364  result = True
1365  if isinstance(self.parent, Do) and label == self.parent.endlabel:
1366  # the same item label may be used for different block ends
1367  self.put_item(item)
1368  return BeginStatement.process_subitem(self, item) or result
1369 
1370  def get_classes(self):
1371  return execution_part_construct
1372 
1373 
1374 # Associate
1375 
1376 
1377 class EndAssociate(EndStatement):
1378  """
1379  END ASSOCIATE [<associate-construct-name>]
1380  """
1381 
1382  match = re.compile(r"end\s*associate\s*\w*\Z", re.I).match
1383 
1384 
1385 class Associate(BeginStatement):
1386  """
1387  [<associate-construct-name> :] ASSOCIATE ( <association-list> )
1388  <block>
1389 
1390  <association> = <associate-name> => <selector>
1391  <selector> = <expr> | <variable>
1392  """
1393 
1394  match = re.compile(r"associate\s*\(.*\)\Z", re.I).match
1395  end_stmt_cls = EndAssociate
1396 
1397  def process_item(self):
1398  line = self.item.get_line()[9:].lstrip()
1399  self.associations = line[1:-1].strip()
1400  return BeginStatement.process_item(self)
1401 
1402  def tostr(self):
1403  return "ASSOCIATE (%s)" % (self.associations)
1404 
1405  def get_classes(self):
1406  return execution_part_construct
1407 
1408 
1409 # Type
1410 
1411 
1412 class EndType(EndStatement):
1413  """
1414  END TYPE [<type-name>]
1415  """
1416 
1417  match = re.compile(r"end\s*type\s*\w*\Z", re.I).match
1418  blocktype = "type"
1419 
1420 
1421 class Type(
1422  BeginStatement, HasVariables, HasAttributes, HasModuleProcedures, AccessSpecs
1423 ):
1424  """
1425  TYPE [[, <typ-attr-spec-list>] ::] <type-name> [( <type-param-name-list> )]
1426  <typ-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> )
1427  | ABSTRACT | BIND(C)
1428  """
1429 
1430  match = re.compile(r"type\b\s*").match
1431  end_stmt_cls = EndType
1432 
1433  a = AttributeHolder(
1434  extends=None,
1435  parameters={},
1436  component_names=[], # Order for sequence types
1437  components={},
1438  )
1439  pattern = r"\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z"
1440  known_attributes = re.compile(pattern, re.I).match
1441 
1442  def process_item(self):
1443  line = self.item.get_line()[4:].lstrip()
1444  if line.startswith("("):
1445  self.isvalid = False
1446  return
1447  specs = []
1448  i = line.find("::")
1449  if i != -1:
1450  for s in line[:i].split(","):
1451  s = s.strip()
1452  if s:
1453  specs.append(s)
1454  line = line[i + 2 :].lstrip()
1455  self.specs = specs
1456  i = line.find("(")
1457  if i != -1:
1458  self.name = line[:i].rstrip()
1459  assert line[-1] == ")", repr(line)
1460  self.params = split_comma(line[i + 1 : -1].lstrip())
1461  else:
1462  self.name = line
1463  self.params = []
1464  if not is_name(self.name):
1465  self.isvalid = False
1466  return
1467  return BeginStatement.process_item(self)
1468 
1469  def tostr(self):
1470  s = "TYPE"
1471  if self.specs:
1472  s += ", ".join([""] + self.specs) + " ::"
1473  s += " " + self.name
1474  if self.params:
1475  s += " (" + ", ".join(self.params) + ")"
1476  return s
1477 
1478  def get_classes(self):
1479  return (
1480  [Integer] + private_or_sequence + component_part + type_bound_procedure_part
1481  )
1482 
1483  def analyze(self):
1484  for spec in self.specs:
1485  i = spec.find("(")
1486  if i != -1:
1487  assert spec.endswith(")"), repr(spec)
1488  s = spec[:i].rstrip().upper()
1489  n = spec[i + 1 : -1].strip()
1490  if s == "EXTENDS":
1491  self.a.extends = n
1492  continue
1493  elif s == "BIND":
1494  args, rest = parse_bind(spec)
1495  assert not rest, repr(rest)
1496  spec = "BIND(%s)" % (", ".join(args))
1497  else:
1498  spec = "%s(%s)" % (s, n)
1499  else:
1500  spec = spec.upper()
1501  self.update_attributes(spec)
1502 
1503  component_names = self.a.component_names
1504  content = self.content[:]
1505  while content:
1506  stmt = content.pop(0)
1507  if isinstance(stmt, self.end_stmt_cls):
1508  break
1509  stmt.analyze()
1510 
1511  if content:
1512  message = "Not analyzed content: %s" % content
1513  logging.getLogger(__class__).info(message)
1514 
1515  parameters = self.a.parameters
1516  components = self.a.components
1517  component_names = self.a.component_names
1518  for name in self.a.variable_names:
1519  var = self.a.variables[name]
1520  if name in self.params:
1521  parameters[name] = var
1522  else:
1523  component_names.append(name)
1524  components[name] = var
1525 
1526  self.parent.a.type_decls[self.name] = self
1527 
1528  parent_provides = self.parent.get_provides()
1529  if parent_provides is not None:
1530  if self.is_public():
1531  if self.name in parent_provides:
1532  message = "type declaration name conflict with {}, " + "overriding."
1533  self.warning(message.format(self.name))
1534  parent_provides[self.name] = self
1535 
1536  return
1537 
1538  def topyf(self, tab=""):
1539  s = tab + "TYPE"
1540  if self.a.extends is not None:
1541  s += ", EXTENDS(%s) ::" % (self.a.extends)
1542  s += " " + self.name
1543  if self.a.parameters:
1544  s += " (%s)" % (", ".join(self.a.parameters))
1545  s += "\n"
1546  s += AccessSpecs.topyf(self, tab=tab + " ")
1547  s += HasAttributes.topyf(self, tab=tab + " ")
1548  s += HasVariables.topyf(self, tab=tab + " ")
1549  s += tab + "END TYPE " + self.name + "\n"
1550  return s
1551 
1552  # Wrapper methods:
1553 
1554  def is_public(self):
1555  return not self.is_private()
1556 
1557  def is_private(self):
1558  if "PUBLIC" in self.a.attributes:
1559  return False
1560  if "PRIVATE" in self.a.attributes:
1561  return True
1562  return self.parent.check_private(self.name)
1563 
1564 
1565 TypeDecl = Type
1566 
1567 
1568 # Enum
1569 
1570 
1571 class EndEnum(EndStatement):
1572  """
1573  END ENUM
1574  """
1575 
1576  match = re.compile(r"end\s*enum\Z", re.I).match
1577  blocktype = "enum"
1578 
1579 
1580 class Enum(BeginStatement):
1581  """
1582  ENUM , BIND(C)
1583  <enumerator-def-stmt>
1584  [<enumerator-def-stmt>]...
1585  """
1586 
1587  blocktype = "enum"
1588  end_stmt_cls = EndEnum
1589  match = re.compile(r"enum\s*,\s*bind\s*\(\s*c\s*\)\Z", re.I).match
1590 
1591  def process_item(self):
1592  return BeginStatement.process_item(self)
1593 
1594  def get_classes(self):
1595  return [Enumerator]
1596 
1597 
1598 
1599 
1600 f2py_stmt = [Threadsafe, FortranName, Depend, Check, CallStatement, CallProtoArgument]
1601 
1602 access_spec = [Public, Private]
1603 
1604 interface_specification = [Function, Subroutine, ModuleProcedure]
1605 
1606 module_subprogram_part = [Contains, Function, Subroutine]
1607 
1608 specification_stmt = access_spec + [
1609  Allocatable,
1610  Asynchronous,
1611  Bind,
1612  Common,
1613  Data,
1614  Dimension,
1615  Equivalence,
1616  External,
1617  Intent,
1618  Intrinsic,
1619  Namelist,
1620  Optional,
1621  Pointer,
1622  Protected,
1623  Save,
1624  Target,
1625  Volatile,
1626  Value,
1627 ]
1628 
1629 intrinsic_type_spec = [
1630  SubprogramPrefix,
1631  Integer,
1632  Real,
1633  DoublePrecision,
1634  Complex,
1635  DoubleComplex,
1636  Character,
1637  Logical,
1638  Byte,
1639 ]
1640 
1641 derived_type_spec = []
1642 type_spec = intrinsic_type_spec + derived_type_spec
1643 declaration_type_spec = intrinsic_type_spec + [TypeStmt, Class]
1644 
1645 type_declaration_stmt = declaration_type_spec
1646 
1647 private_or_sequence = [Private, Sequence]
1648 
1649 component_part = declaration_type_spec + [ModuleProcedure]
1650 
1651 proc_binding_stmt = [SpecificBinding, GenericBinding, FinalBinding]
1652 
1653 type_bound_procedure_part = [Contains, Private] + proc_binding_stmt
1654 
1655 # R214
1656 action_stmt = [
1657  Allocate,
1658  GeneralAssignment,
1659  Assign,
1660  Backspace,
1661  Call,
1662  Close,
1663  Continue,
1664  Cycle,
1665  Deallocate,
1666  Endfile,
1667  Exit,
1668  Flush,
1669  ForallStmt,
1670  Goto,
1671  If,
1672  Inquire,
1673  Nullify,
1674  Open,
1675  Print,
1676  Read,
1677  Return,
1678  Rewind,
1679  Stop,
1680  Wait,
1681  WhereStmt,
1682  Write,
1683  ArithmeticIf,
1684  ComputedGoto,
1685  AssignedGoto,
1686  Pause,
1687 ]
1688 # GeneralAssignment = Assignment + PointerAssignment
1689 # EndFunction, EndProgram, EndSubroutine - part of the corresponding blocks
1690 
1691 executable_construct = [
1692  Associate,
1693  Do,
1694  ForallConstruct,
1695  IfThen,
1696  SelectCase,
1697  SelectType,
1698  WhereConstruct,
1699 ] + action_stmt
1700 
1701 execution_part_construct = executable_construct + [Format, Entry, Data]
1702 
1703 execution_part = execution_part_construct[:]
1704 
1705 # C201, R208
1706 for cls in [EndFunction, EndProgram, EndSubroutine]:
1707  try:
1708  execution_part.remove(cls)
1709  except ValueError:
1710  pass
1711 
1712 internal_subprogram = [Function, Subroutine]
1713 
1714 internal_subprogram_part = [Contains] + internal_subprogram
1715 
1716 # In Fortran2003 we can have a Procedure declaration. We therefore
1717 # include SpecificBinding as a valid declaration construct.
1718 declaration_construct = (
1719  [
1720  TypeDecl,
1721  Entry,
1722  Enum,
1723  Format,
1724  Interface,
1725  Parameter,
1726  ModuleProcedure,
1727  SpecificBinding,
1728  ]
1729  + specification_stmt
1730  + type_declaration_stmt
1731 )
1732 # stmt-function-stmt
1733 
1734 implicit_part = [Implicit, Parameter, Format, Entry]
1735 
1736 specification_part = [Use, Import] + implicit_part + declaration_construct
1737 
1738 
1739 external_subprogram = [Function, Subroutine]
1740 
1741 main_program = (
1742  [Program] + specification_part + execution_part + internal_subprogram_part
1743 )
1744 
1745 program_unit = main_program + external_subprogram + [Module, BlockData]