PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/TOOLS/FparserTools/fparser/block_statements.py

http://github.com/tkotani/ecalj
Python | 1277 lines | 1254 code | 10 blank | 13 comment | 22 complexity | fcc23f9cef1d3f016becd2bb14ed9fbb MD5 | raw file
  1. """
  2. Fortran block statements.
  3. -----
  4. Permission to use, modify, and distribute this software is given under the
  5. terms of the NumPy License. See http://scipy.org.
  6. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  7. Author: Pearu Peterson <pearu@cens.ioc.ee>
  8. Created: May 2006
  9. -----
  10. """
  11. __all__ = ['BeginSource','Module','PythonModule','Program','BlockData','Interface',
  12. 'Subroutine','Function','Select','WhereConstruct','ForallConstruct',
  13. 'IfThen','If','Do','Associate','TypeDecl','Enum',
  14. 'EndSource','EndModule','EndPythonModule','EndProgram','EndBlockData','EndInterface',
  15. 'EndSubroutine','EndFunction','EndSelect','EndWhere','EndForall',
  16. 'EndIfThen','EndDo','EndAssociate','EndType','EndEnum',
  17. ]
  18. import re
  19. import sys
  20. from base_classes import BeginStatement, EndStatement, Statement,\
  21. AttributeHolder, ProgramBlock, Variable
  22. from readfortran import Line
  23. from utils import filter_stmts, parse_bind, parse_result, AnalyzeError, is_name
  24. class HasImplicitStmt(object):
  25. a = AttributeHolder(implicit_rules = {})
  26. def get_type_by_name(self, name):
  27. implicit_rules = self.a.implicit_rules
  28. if implicit_rules is None:
  29. raise AnalyzeError,'Implicit rules mapping is null while getting %r type' % (name)
  30. l = name[0].lower()
  31. if l in implicit_rules:
  32. return implicit_rules[l]
  33. # default rules:
  34. if l in 'ijklmn':
  35. l = 'default_integer'
  36. else:
  37. l = 'default_real'
  38. t = implicit_rules.get(l, None)
  39. if t is None:
  40. if l[8:]=='real':
  41. implicit_rules[l] = t = Real(self, self.item.copy('real'))
  42. else:
  43. implicit_rules[l] = t = Integer(self, self.item.copy('integer'))
  44. return t
  45. def topyf(self, tab=' '):
  46. implicit_rules = self.a.implicit_rules
  47. if implicit_rules is None:
  48. return tab + 'IMPLICIT NONE\n'
  49. items = {}
  50. for c,t in implicit_rules.items():
  51. if c.startswith('default'):
  52. continue
  53. st = t.tostr()
  54. if st in items:
  55. items[st].append(c)
  56. else:
  57. items[st] = [c]
  58. if not items:
  59. return tab + '! default IMPLICIT rules apply\n'
  60. s = 'IMPLICIT'
  61. ls = []
  62. for st,l in items.items():
  63. l.sort()
  64. ls.append(st + ' (%s)' % (', '.join(l)))
  65. s += ' ' + ', '.join(ls)
  66. return tab + s + '\n'
  67. class HasUseStmt(object):
  68. a = AttributeHolder(use = {},
  69. use_provides = {})
  70. def get_entity(self, name):
  71. for modname, modblock in self.top.a.module.items():
  72. for stmt in modblock.content:
  73. if getattr(stmt,'name','') == name:
  74. return stmt
  75. return
  76. def topyf(self, tab=' '):
  77. sys.stderr.write('HasUseStmt.topyf not implemented\n')
  78. return ''
  79. class AccessSpecs(object):
  80. a = AttributeHolder(private_id_list = [], public_id_list = [])
  81. def topyf(self, tab=' '):
  82. private_list = self.a.private_id_list
  83. public_list = self.a.public_id_list
  84. l = []
  85. if '' in private_list: l.append(tab + 'PRIVATE\n')
  86. if '' in public_list: l.append(tab + 'PUBLIC\n')
  87. for a in private_list:
  88. if not a: continue
  89. l.append(tab + 'PRIVATE :: %s\n' % (a))
  90. for a in public_list:
  91. if not a: continue
  92. l.append(tab + 'PUBLIC :: %s\n' % (a))
  93. return ''.join(l)
  94. class HasVariables(object):
  95. a = AttributeHolder(variables = {},
  96. variable_names = [] # defines the order of declarations
  97. )
  98. def get_variable_by_name(self, name):
  99. variables = self.a.variables
  100. if name in variables:
  101. var = variables[name]
  102. else:
  103. var = variables[name] = Variable(self, name)
  104. self.a.variable_names.append(name)
  105. return var
  106. def topyf(self,tab='', only_variables = None):
  107. s = ''
  108. if only_variables is None:
  109. only_variables = self.a.variables.keys()
  110. for name in only_variables:
  111. var = self.a.variables[name]
  112. s += tab + str(var) + '\n'
  113. return s
  114. class HasTypeDecls(object):
  115. a = AttributeHolder(type_decls = {})
  116. def topyf(self, tab=''):
  117. s = ''
  118. for name, stmt in self.a.type_decls.items():
  119. s += stmt.topyf(tab=' '+tab)
  120. return s
  121. def get_type_decl_by_kind(self, kind):
  122. type_decls = self.a.type_decls
  123. type_decl = type_decls.get(kind, None)
  124. if type_decl is None:
  125. return self.get_entity(kind)
  126. return type_decl
  127. class HasAttributes(object):
  128. known_attributes = []
  129. a = AttributeHolder(attributes = [])
  130. def topyf(self, tab=''):
  131. s = ''
  132. for attr in self.a.attributes:
  133. s += tab + attr + '\n'
  134. return s
  135. def update_attributes(self,*attrs):
  136. attributes = self.a.attributes
  137. known_attributes = self.known_attributes
  138. if len(attrs)==1 and isinstance(attrs[0],(tuple,list)):
  139. attrs = attrs[0]
  140. for attr in attrs:
  141. uattr = attr.upper()
  142. if uattr not in attributes:
  143. if isinstance(known_attributes,(list, tuple)):
  144. if uattr not in known_attributes:
  145. self.warning('unknown attribute %r' % (attr))
  146. elif not known_attributes(uattr):
  147. self.warning('unknown attribute %r' % (attr))
  148. attributes.append(uattr)
  149. else:
  150. self.warning('multiple specification of attribute %r' % (attr))
  151. return
  152. class HasModuleProcedures(object):
  153. a = AttributeHolder(module_procedures = [])
  154. # File block
  155. class EndSource(EndStatement):
  156. """
  157. Dummy End statement for BeginSource.
  158. """
  159. match = staticmethod(lambda s: False)
  160. class BeginSource(BeginStatement):
  161. """
  162. Fortran source content.
  163. """
  164. match = staticmethod(lambda s: True)
  165. end_stmt_cls = EndSource
  166. a = AttributeHolder(module = {},
  167. external_subprogram = {},
  168. blockdata = {},
  169. )
  170. def tofortran(self,isfix=None):
  171. if isfix:
  172. tab = 'C'
  173. else:
  174. tab = self.get_indent_tab(isfix=isfix) + '!'
  175. return tab + BeginStatement.tofortran(self, isfix=isfix)
  176. def tostr(self):
  177. return self.blocktype.upper() + ' '+ self.name
  178. def process_item(self):
  179. self.name = self.reader.name
  180. self.top = self
  181. self.fill(end_flag = True)
  182. return
  183. def analyze(self):
  184. for stmt in self.content:
  185. if isinstance(stmt, Module):
  186. stmt.analyze()
  187. self.a.module[stmt.name] = stmt
  188. elif isinstance(stmt, SubProgramStatement):
  189. stmt.analyze()
  190. self.a.external_subprogram[stmt.name] = stmt
  191. elif isinstance(stmt, BlockData):
  192. stmt.analyze()
  193. self.a.blockdata[stmt.name] = stmt
  194. else:
  195. stmt.analyze()
  196. return
  197. def get_classes(self):
  198. if self.reader.ispyf:
  199. return [PythonModule] + program_unit
  200. return program_unit
  201. def process_subitem(self, item):
  202. # MAIN block does not define start/end line conditions,
  203. # so it should never end until all lines are read.
  204. # However, sometimes F77 programs lack the PROGRAM statement,
  205. # and here we fix that:
  206. if self.reader.isf77:
  207. line = item.get_line()
  208. if line=='end':
  209. message = item.reader.format_message(\
  210. 'WARNING',
  211. 'assuming the end of undefined PROGRAM statement',
  212. item.span[0],item.span[1])
  213. print >> sys.stderr, message
  214. p = Program(self)
  215. p.content.extend(self.content)
  216. p.content.append(EndProgram(p,item))
  217. self.content[:] = [p]
  218. return
  219. return BeginStatement.process_subitem(self, item)
  220. def topyf(self, tab=''): # XXXX
  221. s = ''
  222. for name, stmt in self.a.module.items():
  223. s += stmt.topyf(tab=tab)
  224. for name, stmt in self.a.external_subprogram.items():
  225. s += stmt.topyf(tab=tab)
  226. for name, stmt in self.a.blockdata.items():
  227. s += stmt.topyf(tab=tab)
  228. return s
  229. # Module
  230. class EndModule(EndStatement):
  231. match = re.compile(r'end(\s*module\s*\w*|)\Z', re.I).match
  232. class Module(BeginStatement, HasAttributes,
  233. HasImplicitStmt, HasUseStmt, HasVariables,
  234. HasTypeDecls, AccessSpecs):
  235. """
  236. MODULE <name>
  237. ..
  238. END [MODULE [name]]
  239. """
  240. match = re.compile(r'module\s*\w+\Z', re.I).match
  241. end_stmt_cls = EndModule
  242. a = AttributeHolder(module_subprogram = {},
  243. module_provides = {}, # all symbols that are public and so
  244. # can be imported via USE statement
  245. # by other blocks
  246. module_interface = {}
  247. )
  248. known_attributes = ['PUBLIC', 'PRIVATE']
  249. def get_classes(self):
  250. return access_spec + specification_part + module_subprogram_part
  251. def process_item(self):
  252. name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip()
  253. self.name = name
  254. return BeginStatement.process_item(self)
  255. def get_provides(self):
  256. return self.a.module_provides
  257. def get_interface(self):
  258. return self.a.module_interface
  259. def analyze(self):
  260. content = self.content[:]
  261. while content:
  262. stmt = content.pop(0)
  263. if isinstance(stmt, Contains):
  264. for stmt in filter_stmts(content, SubProgramStatement):
  265. stmt.analyze()
  266. self.a.module_subprogram[stmt.name] = stmt
  267. stmt = content.pop(0)
  268. while isinstance(stmt, Comment):
  269. stmt = content.pop(0)
  270. if not isinstance(stmt, EndModule):
  271. stmt.error('Expected END MODULE statement (analyzer).')
  272. continue
  273. stmt.analyze()
  274. if content:
  275. self.show_message('Not analyzed content: %s' % content)
  276. module_provides = self.a.module_provides
  277. for name, var in self.a.variables.items():
  278. if var.is_public():
  279. if name in module_provides:
  280. self.warning('module data object name conflict with %s, overriding.' % (name))
  281. module_provides[name] = var
  282. return
  283. def topyf(self, tab=''):
  284. s = tab + 'MODULE '+self.name + '\n'
  285. s += HasImplicitStmt.topyf(self, tab=tab+' ')
  286. s += AccessSpecs.topyf(self, tab=tab+' ')
  287. s += HasAttributes.topyf(self, tab=tab+' ')
  288. s += HasTypeDecls.topyf(self, tab=tab+' ')
  289. s += HasVariables.topyf(self, tab=tab+' ')
  290. for name, stmt in self.a.module_interface.items():
  291. s += stmt.topyf(tab=tab+' ')
  292. s += tab + ' CONTAINS\n'
  293. for name, stmt in self.a.module_subprogram.items():
  294. s += stmt.topyf(tab=tab+' ')
  295. s += tab + 'END MODULE ' + self.name + '\n'
  296. return s
  297. def check_private(self, name):
  298. if name in self.a.public_id_list: return False
  299. if name in self.a.private_id_list: return True
  300. if '' in self.a.public_id_list: return False
  301. if '' in self.a.private_id_list: return True
  302. #todo: handle generic-spec-s in id-lists.
  303. return
  304. # Python Module
  305. class EndPythonModule(EndStatement):
  306. match = re.compile(r'end(\s*python\s*module\s*\w*|)\Z', re.I).match
  307. class PythonModule(BeginStatement, HasImplicitStmt, HasUseStmt):
  308. """
  309. PYTHON MODULE <name>
  310. ..
  311. END [PYTHON MODULE [name]]
  312. """
  313. modes = ['pyf']
  314. match = re.compile(r'python\s*module\s*\w+\Z', re.I).match
  315. end_stmt_cls = EndPythonModule
  316. def get_classes(self):
  317. return [Interface, Function, Subroutine, Module]
  318. def process_item(self):
  319. self.name = self.item.get_line().replace(' ','')\
  320. [len(self.blocktype):].strip()
  321. return BeginStatement.process_item(self)
  322. # Program
  323. class EndProgram(EndStatement):
  324. """
  325. END [PROGRAM [name]]
  326. """
  327. match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
  328. class Program(BeginStatement, ProgramBlock,
  329. #HasAttributes, # XXX: why Program needs .attributes?
  330. HasVariables,
  331. HasImplicitStmt, HasUseStmt, AccessSpecs):
  332. """ PROGRAM [name]
  333. """
  334. match = re.compile(r'program\s*\w*\Z', re.I).match
  335. end_stmt_cls = EndProgram
  336. def get_classes(self):
  337. return specification_part + execution_part + internal_subprogram_part
  338. def process_item(self):
  339. if self.item is not None:
  340. name = self.item.get_line().replace(' ','')\
  341. [len(self.blocktype):].strip()
  342. if name:
  343. self.name = name
  344. return BeginStatement.process_item(self)
  345. # BlockData
  346. class EndBlockData(EndStatement):
  347. """
  348. END [ BLOCK DATA [ <block-data-name> ] ]
  349. """
  350. match = re.compile(r'end(\s*block\s*data\s*\w*|)\Z', re.I).match
  351. blocktype = 'blockdata'
  352. class BlockData(BeginStatement, HasImplicitStmt, HasUseStmt,
  353. HasVariables, AccessSpecs):
  354. """
  355. BLOCK DATA [ <block-data-name> ]
  356. """
  357. end_stmt_cls = EndBlockData
  358. match = re.compile(r'block\s*data\s*\w*\Z', re.I).match
  359. def process_item(self):
  360. self.name = self.item.get_line()[5:].lstrip()[4:].lstrip()
  361. return BeginStatement.process_item(self)
  362. def get_classes(self):
  363. return specification_part
  364. # Interface
  365. class EndInterface(EndStatement):
  366. match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match
  367. blocktype = 'interface'
  368. class Interface(BeginStatement, HasAttributes, HasImplicitStmt, HasUseStmt,
  369. HasModuleProcedures, AccessSpecs
  370. ):
  371. """
  372. INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
  373. END INTERFACE [<generic-spec>]
  374. <generic-spec> = <generic-name>
  375. | OPERATOR ( <defined-operator> )
  376. | ASSIGNMENT ( = )
  377. | <dtio-generic-spec>
  378. <dtio-generic-spec> = READ ( FORMATTED )
  379. | READ ( UNFORMATTED )
  380. | WRITE ( FORMATTED )
  381. | WRITE ( UNFORMATTED )
  382. """
  383. modes = ['free', 'fix', 'pyf']
  384. match = re.compile(r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z',re.I).match
  385. end_stmt_cls = EndInterface
  386. blocktype = 'interface'
  387. a = AttributeHolder(interface_provides = {})
  388. def get_classes(self):
  389. l = intrinsic_type_spec + interface_specification
  390. if self.reader.mode=='pyf':
  391. return [Subroutine, Function] + l
  392. return l
  393. def process_item(self):
  394. line = self.item.get_line()
  395. self.isabstract = line.startswith('abstract')
  396. if self.isabstract:
  397. self.generic_spec = ''
  398. else:
  399. self.generic_spec = line[len(self.blocktype):].strip()
  400. self.name = self.generic_spec # XXX
  401. return BeginStatement.process_item(self)
  402. def tostr(self):
  403. if self.isabstract:
  404. return 'ABSTRACT INTERFACE'
  405. return 'INTERFACE '+ str(self.generic_spec)
  406. #def get_provides(self):
  407. # return self.a.interface_provides
  408. def analyze(self):
  409. content = self.content[:]
  410. while content:
  411. stmt = content.pop(0)
  412. if isinstance(stmt, self.end_stmt_cls):
  413. break
  414. stmt.analyze()
  415. #assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__`
  416. if content:
  417. self.show_message('Not analyzed content: %s' % content)
  418. if self.name in self.parent.a.variables:
  419. var = self.parent.a.variables.pop(self.name)
  420. self.update_attributes(var.attributes)
  421. if isinstance(self.parent, Module):#XXX
  422. parent_interface = self.parent.get_interface()
  423. if self.name in parent_interface:
  424. p = parent_interface[self.name]
  425. last = p.content.pop()
  426. assert isinstance(last,EndInterface),`last.__class__`
  427. p.content += self.content
  428. p.update_attributes(self.a.attributes)
  429. else:
  430. parent_interface[self.name] = self
  431. return
  432. def topyf(self, tab=''):
  433. s = tab + self.tostr() + '\n'
  434. s += HasImplicitStmt.topyf(self, tab=tab+' ')
  435. s += HasAttributes.topyf(self, tab=tab+' ')
  436. s += HasUseStmt.topyf(self, tab=tab+' ')
  437. s += tab + 'END' + self.tostr() + '\n'
  438. return s
  439. # Subroutine
  440. class SubProgramStatement(BeginStatement, ProgramBlock,
  441. HasImplicitStmt, HasAttributes,
  442. HasUseStmt,
  443. HasVariables, HasTypeDecls, AccessSpecs
  444. ):
  445. """
  446. [ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ]
  447. """
  448. a = AttributeHolder(internal_subprogram = {})
  449. known_attributes = ['RECURSIVE', 'PURE', 'ELEMENTAL']
  450. def process_item(self):
  451. clsname = self.__class__.__name__.lower()
  452. item = self.item
  453. line = item.get_line()
  454. m = self.match(line)
  455. i = line.lower().find(clsname)
  456. assert i!=-1,`clsname, line`
  457. self.prefix = line[:i].rstrip()
  458. self.name = line[i:m.end()].lstrip()[len(clsname):].strip()
  459. line = line[m.end():].lstrip()
  460. args = []
  461. if line.startswith('('):
  462. i = line.find(')')
  463. assert i!=-1,`line`
  464. line2 = item.apply_map(line[:i+1])
  465. for a in line2[1:-1].split(','):
  466. a=a.strip()
  467. if not a: continue
  468. args.append(a)
  469. line = line[i+1:].lstrip()
  470. suffix = item.apply_map(line)
  471. self.bind, suffix = parse_bind(suffix, item)
  472. self.result = None
  473. if isinstance(self, Function):
  474. self.result, suffix = parse_result(suffix, item)
  475. if suffix:
  476. assert self.bind is None,`self.bind`
  477. self.bind, suffix = parse_result(suffix, item)
  478. if self.result is None:
  479. self.result = self.name
  480. assert not suffix,`suffix`
  481. self.args = args
  482. self.typedecl = None
  483. return BeginStatement.process_item(self)
  484. def tostr(self):
  485. clsname = self.__class__.__name__.upper()
  486. s = ''
  487. if self.prefix:
  488. s += self.prefix + ' '
  489. if self.typedecl is not None:
  490. assert isinstance(self, Function),`self.__class__.__name__`
  491. s += self.typedecl.tostr() + ' '
  492. s += clsname
  493. suf = ''
  494. if self.result and self.result!=self.name:
  495. suf += ' RESULT ( %s )' % (self.result)
  496. if self.bind:
  497. suf += ' BIND ( %s )' % (', '.join(self.bind))
  498. return '%s %s(%s)%s' % (s, self.name,', '.join(self.args),suf)
  499. def get_classes(self):
  500. return f2py_stmt + specification_part + execution_part \
  501. + internal_subprogram_part
  502. def analyze(self):
  503. content = self.content[:]
  504. if self.prefix:
  505. self.update_attributes(self.prefix.upper().split())
  506. variables = self.a.variables
  507. for a in self.args:
  508. assert a not in variables
  509. if is_name(a):
  510. variables[a] = Variable(self, a)
  511. elif a=='*':
  512. variables[a] = Variable(self, a) # XXX: fix me appropriately
  513. else:
  514. raise AnalyzeError('argument must be a name or * but got %r' % (a))
  515. if isinstance(self, Function):
  516. var = variables[self.result] = Variable(self, self.result)
  517. if self.typedecl is not None:
  518. var.set_type(self.typedecl)
  519. while content:
  520. stmt = content.pop(0)
  521. if isinstance(stmt, Contains):
  522. for stmt in filter_stmts(content, SubProgramStatement):
  523. stmt.analyze()
  524. self.a.internal_subprogram[stmt.name] = stmt
  525. stmt = content.pop(0)
  526. assert isinstance(stmt, self.end_stmt_cls),`stmt`
  527. elif isinstance(stmt, self.end_stmt_cls):
  528. continue
  529. else:
  530. stmt.analyze()
  531. if content:
  532. self.show_message('Not analyzed content: %s' % content)
  533. parent_provides = self.parent.get_provides()
  534. if parent_provides is not None:
  535. if self.name in parent_provides:
  536. self.warning('module subprogram name conflict with %s, overriding.' % (self.name))
  537. parent_provides[self.name] = self
  538. if self.is_recursive() and self.is_elemental():
  539. self.warning('C1241 violation: prefix cannot specify both ELEMENTAL and RECURSIVE')
  540. return
  541. def topyf(self, tab=''):
  542. s = tab + self.__class__.__name__.upper()
  543. s += ' ' + self.name + ' (%s)' % (', '.join(self.args))
  544. if isinstance(self, Function) and self.result != self.name:
  545. s += ' RESULT (%s)' % (self.result)
  546. s += '\n'
  547. s += HasImplicitStmt.topyf(self, tab=tab+' ')
  548. s += AccessSpecs.topyf(self, tab=tab+' ')
  549. s += HasTypeDecls.topyf(self, tab=tab+' ')
  550. s += HasVariables.topyf(self, tab=tab+' ', only_variables = self.args)
  551. s += tab + 'END ' + self.__class__.__name__.upper() + ' ' + self.name + '\n'
  552. return s
  553. def is_public(self): return not self.is_private()
  554. def is_private(self): return self.parent.check_private(self.name)
  555. def is_recursive(self): return 'RECURSIVE' in self.a.attributes
  556. def is_pure(self): return 'PURE' in self.a.attributes
  557. def is_elemental(self): return 'ELEMENTAL' in self.a.attributes
  558. class EndSubroutine(EndStatement):
  559. """
  560. END [SUBROUTINE [name]]
  561. """
  562. match = re.compile(r'end(\s*subroutine\s*\w*|)\Z', re.I).match
  563. class Subroutine(SubProgramStatement):
  564. """
  565. [ <prefix> ] SUBROUTINE <name> [ ( [ <dummy-arg-list> ] ) [ <proc-language-binding-spec> ]]
  566. """
  567. end_stmt_cls = EndSubroutine
  568. match = re.compile(r'(recursive|pure|elemental|\s)*subroutine\s*\w+', re.I).match
  569. _repr_attr_names = ['prefix','bind','suffix','args'] + Statement._repr_attr_names
  570. # Function
  571. class EndFunction(EndStatement):
  572. """
  573. END [FUNCTION [name]]
  574. """
  575. match = re.compile(r'end(\s*function\s*\w*|)\Z', re.I).match
  576. class Function(SubProgramStatement):
  577. """
  578. [ <prefix> ] FUNCTION <name> ( [<dummy-arg-list>] ) [<suffix>]
  579. <prefix> = <prefix-spec> [ <prefix-spec> ]...
  580. <prefix-spec> = <declaration-type-spec>
  581. | RECURSIVE | PURE | ELEMENTAL
  582. <suffix> = <proc-language-binding-spec> [ RESULT ( <result-name> ) ]
  583. | RESULT ( <result-name> ) [ <proc-language-binding-spec> ]
  584. """
  585. end_stmt_cls = EndFunction
  586. match = re.compile(r'(recursive|pure|elemental|\s)*function\s*\w+', re.I).match
  587. _repr_attr_names = ['prefix','bind','suffix','args','typedecl'] + Statement._repr_attr_names
  588. def subroutine_wrapper_code(self):
  589. name = 'f2pywrap_' + self.name
  590. args = ['f2pyvalue_'+self.result] + self.args
  591. var = self.a.variables[self.result]
  592. typedecl = var.get_typedecl().astypedecl()
  593. lines = []
  594. tab = ' '*6
  595. lines.append('%sSUBROUTINE %s(%s)' % (tab, name, ', '.join(args)))
  596. if isinstance(self.parent,Module):
  597. lines.append('%s USE %s' % (tab, self.parent.name))
  598. else:
  599. if isinstance(typedecl, TypeStmt):
  600. type_decl = typedecl.get_type_decl(typedecl.name)
  601. if type_decl.parent is self:
  602. for line in str(type_decl).split('\n'):
  603. lines.append('%s %s' % (tab, line.lstrip()))
  604. lines.append('%s EXTERNAL %s' % (tab, self.name))
  605. lines.append('%s %s %s' % (tab, str(typedecl).lstrip(), self.name))
  606. lines.append('%s %s %s' % (tab, str(typedecl).lstrip(), args[0]))
  607. lines.append('!f2py intent(out) %s' % (args[0]))
  608. for a in self.args:
  609. v = self.a.variables[a]
  610. lines.append('%s %s' % (tab, str(v).lstrip()))
  611. lines.append('%s %s = %s(%s)' % (tab, args[0], self.name, ', '.join(self.args)))
  612. #lines.append('%s print*,"%s=",%s' % (tab, args[0], args[0])) # debug line
  613. lines.append('%sEND SUBROUTINE %s' % (tab, name))
  614. return '\n'.join(lines)
  615. def subroutine_wrapper(self):
  616. code = self.subroutine_wrapper_code()
  617. from api import parse
  618. block = parse(code) # XXX: set include_dirs
  619. while len(block.content)==1:
  620. block = block.content[0]
  621. return block
  622. # Handle subprogram prefixes
  623. class SubprogramPrefix(Statement):
  624. """
  625. <prefix> <declaration-type-spec> <function|subroutine> ...
  626. """
  627. match = re.compile(r'(pure|elemental|recursive|\s)+\b',re.I).match
  628. def process_item(self):
  629. line = self.item.get_line()
  630. m = self.match(line)
  631. prefix = line[:m.end()].rstrip()
  632. rest = self.item.get_line()[m.end():].lstrip()
  633. if rest:
  634. self.parent.put_item(self.item.copy(prefix))
  635. self.item.clone(rest)
  636. self.isvalid = False
  637. return
  638. if self.parent.__class__ not in [Function, Subroutine]:
  639. self.isvalid = False
  640. return
  641. prefix = prefix + ' ' + self.parent.prefix
  642. self.parent.prefix = prefix.strip()
  643. self.ignore = True
  644. return
  645. # SelectCase
  646. class EndSelect(EndStatement):
  647. match = re.compile(r'end\s*select\s*\w*\Z', re.I).match
  648. blocktype = 'select'
  649. class Select(BeginStatement):
  650. """
  651. [ <case-construct-name> : ] SELECT CASE ( <case-expr> )
  652. """
  653. match = re.compile(r'select\s*case\s*\(.*\)\Z',re.I).match
  654. end_stmt_cls = EndSelect
  655. name = ''
  656. def tostr(self):
  657. return 'SELECT CASE ( %s )' % (self.expr)
  658. def process_item(self):
  659. self.expr = self.item.get_line()[6:].lstrip()[4:].lstrip()[1:-1].strip()
  660. self.construct_name = self.item.name
  661. return BeginStatement.process_item(self)
  662. def get_classes(self):
  663. return [Case] + execution_part_construct
  664. # Where
  665. class EndWhere(EndStatement):
  666. """
  667. END WHERE [ <where-construct-name> ]
  668. """
  669. match = re.compile(r'end\s*\where\s*\w*\Z',re.I).match
  670. class Where(BeginStatement):
  671. """
  672. [ <where-construct-name> : ] WHERE ( <mask-expr> )
  673. <mask-expr> = <logical-expr>
  674. """
  675. match = re.compile(r'where\s*\([^)]*\)\Z',re.I).match
  676. end_stmt_cls = EndWhere
  677. name = ''
  678. def tostr(self):
  679. return 'WHERE ( %s )' % (self.expr)
  680. def process_item(self):
  681. self.expr = self.item.get_line()[5:].lstrip()[1:-1].strip()
  682. self.construct_name = self.item.name
  683. return BeginStatement.process_item(self)
  684. def get_classes(self):
  685. return [Assignment, WhereStmt,
  686. WhereConstruct, ElseWhere
  687. ]
  688. WhereConstruct = Where
  689. # Forall
  690. class EndForall(EndStatement):
  691. """
  692. END FORALL [ <forall-construct-name> ]
  693. """
  694. match = re.compile(r'end\s*forall\s*\w*\Z',re.I).match
  695. class Forall(BeginStatement):
  696. """
  697. [ <forall-construct-name> : ] FORALL <forall-header>
  698. [ <forall-body-construct> ]...
  699. <forall-body-construct> = <forall-assignment-stmt>
  700. | <where-stmt>
  701. | <where-construct>
  702. | <forall-construct>
  703. | <forall-stmt>
  704. <forall-header> = ( <forall-triplet-spec-list> [ , <scalar-mask-expr> ] )
  705. <forall-triplet-spec> = <index-name> = <subscript> : <subscript> [ : <stride> ]
  706. <subscript|stride> = <scalar-int-expr>
  707. <forall-assignment-stmt> = <assignment-stmt> | <pointer-assignment-stmt>
  708. """
  709. end_stmt_cls = EndForall
  710. match = re.compile(r'forarr\s*\(.*\)\Z',re.I).match
  711. name = ''
  712. def process_item(self):
  713. self.specs = self.item.get_line()[6:].lstrip()[1:-1].strip()
  714. return BeginStatement.process_item(self)
  715. def tostr(self):
  716. return 'FORALL (%s)' % (self.specs)
  717. def get_classes(self):
  718. return [GeneralAssignment, WhereStmt, WhereConstruct,
  719. ForallConstruct, ForallStmt]
  720. ForallConstruct = Forall
  721. # IfThen
  722. class EndIfThen(EndStatement):
  723. """
  724. END IF [ <if-construct-name> ]
  725. """
  726. match = re.compile(r'end\s*if\s*\w*\Z', re.I).match
  727. blocktype = 'if'
  728. class IfThen(BeginStatement):
  729. """
  730. [<if-construct-name> :] IF ( <scalar-logical-expr> ) THEN
  731. IfThen instance has the following attributes:
  732. expr
  733. """
  734. match = re.compile(r'if\s*\(.*\)\s*then\Z',re.I).match
  735. end_stmt_cls = EndIfThen
  736. name = ''
  737. def tostr(self):
  738. return 'IF (%s) THEN' % (self.expr)
  739. def process_item(self):
  740. item = self.item
  741. line = item.get_line()[2:-4].strip()
  742. assert line[0]=='(' and line[-1]==')',`line`
  743. self.expr = line[1:-1].strip()
  744. self.construct_name = item.name
  745. return BeginStatement.process_item(self)
  746. def get_classes(self):
  747. return [Else, ElseIf] + execution_part_construct
  748. class If(BeginStatement):
  749. """
  750. IF ( <scalar-logical-expr> ) action-stmt
  751. """
  752. match = re.compile(r'if\s*\(',re.I).match
  753. def process_item(self):
  754. item = self.item
  755. mode = self.reader.mode
  756. classes = self.get_classes()
  757. classes = [cls for cls in classes if mode in cls.modes]
  758. line = item.get_line()[2:].lstrip()
  759. i = line.find(')')
  760. expr = line[1:i].strip()
  761. line = line[i+1:].strip()
  762. if line.lower()=='then':
  763. self.isvalid = False
  764. return
  765. self.expr = item.apply_map(expr)
  766. if not line:
  767. newitem = self.get_item()
  768. else:
  769. newitem = item.copy(line)
  770. newline = newitem.get_line()
  771. for cls in classes:
  772. if cls.match(newline):
  773. stmt = cls(self, newitem)
  774. if stmt.isvalid:
  775. self.content.append(stmt)
  776. return
  777. if not line:
  778. self.put_item(newitem)
  779. self.isvalid = False
  780. return
  781. def tostr(self):
  782. assert len(self.content)==1,`self.content`
  783. return 'IF (%s) %s' % (self.expr, str(self.content[0]).lstrip())
  784. def tofortran(self,isfix=None):
  785. return self.get_indent_tab(isfix=isfix) + self.tostr()
  786. def get_classes(self):
  787. return action_stmt
  788. # Do
  789. class EndDo(EndStatement):
  790. """
  791. END DO [ <do-construct-name> ]
  792. """
  793. match = re.compile(r'end\s*do\s*\w*\Z', re.I).match
  794. blocktype = 'do'
  795. class Do(BeginStatement):
  796. """
  797. [ <do-construct-name> : ] DO label [loopcontrol]
  798. [ <do-construct-name> : ] DO [loopcontrol]
  799. """
  800. match = re.compile(r'do\b\s*\d*',re.I).match
  801. item_re = re.compile(r'do\b\s*(?P<label>\d*)\s*,?\s*(?P<loopcontrol>.*)\Z',re.I).match
  802. end_stmt_cls = EndDo
  803. name = ''
  804. def tostr(self):
  805. l = ['DO']
  806. for part in [self.endlabel, self.loopcontrol]:
  807. if part:
  808. l.append(str(part))
  809. return ' '.join(l)
  810. def process_item(self):
  811. item = self.item
  812. line = item.get_line()
  813. m = self.item_re(line)
  814. label = m.group('label').strip() or None
  815. if label:
  816. label = int(label)
  817. self.endlabel = label
  818. self.construct_name = item.name
  819. self.loopcontrol = m.group('loopcontrol').strip()
  820. return BeginStatement.process_item(self)
  821. def process_subitem(self, item):
  822. r = False
  823. if self.endlabel:
  824. label = item.label
  825. if label == self.endlabel:
  826. r = True
  827. if isinstance(self.parent, Do) and label==self.parent.endlabel:
  828. # the same item label may be used for different block ends
  829. self.put_item(item)
  830. return BeginStatement.process_subitem(self, item) or r
  831. def get_classes(self):
  832. return execution_part_construct
  833. # Associate
  834. class EndAssociate(EndStatement):
  835. """
  836. END ASSOCIATE [ <associate-construct-name> ]
  837. """
  838. match = re.compile(r'end\s*associate\s*\w*\Z',re.I).match
  839. class Associate(BeginStatement):
  840. """
  841. [ <associate-construct-name> : ] ASSOCIATE ( <association-list> )
  842. <block>
  843. <association> = <associate-name> => <selector>
  844. <selector> = <expr> | <variable>
  845. """
  846. match = re.compile(r'associate\s*\(.*\)\Z',re.I).match
  847. end_stmt_cls = EndAssociate
  848. def process_item(self):
  849. line = self.item.get_line()[9:].lstrip()
  850. self.associations = line[1:-1].strip()
  851. return BeginStatement.process_item(self)
  852. def tostr(self):
  853. return 'ASSOCIATE (%s)' % (self.associations)
  854. def get_classes(self):
  855. return execution_part_construct
  856. # Type
  857. class EndType(EndStatement):
  858. """
  859. END TYPE [<type-name>]
  860. """
  861. match = re.compile(r'end\s*type\s*\w*\Z', re.I).match
  862. blocktype = 'type'
  863. class Type(BeginStatement, HasVariables, HasAttributes, AccessSpecs):
  864. """
  865. TYPE [ [ , <type-attr-spec-list>] :: ] <type-name> [ ( <type-param-name-list> ) ]
  866. <type-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> )
  867. | ABSTRACT | BIND(C)
  868. """
  869. match = re.compile(r'type\b\s*').match
  870. end_stmt_cls = EndType
  871. a = AttributeHolder(extends = None,
  872. parameters = {},
  873. component_names = [], # specifies component order for sequence types
  874. components = {}
  875. )
  876. known_attributes = re.compile(r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z',re.I).match
  877. def process_item(self):
  878. line = self.item.get_line()[4:].lstrip()
  879. if line.startswith('('):
  880. self.isvalid = False
  881. return
  882. specs = []
  883. i = line.find('::')
  884. if i!=-1:
  885. for s in line[:i].split(','):
  886. s = s.strip()
  887. if s: specs.append(s)
  888. line = line[i+2:].lstrip()
  889. self.specs = specs
  890. i = line.find('(')
  891. if i!=-1:
  892. self.name = line[:i].rstrip()
  893. assert line[-1]==')',`line`
  894. self.params = split_comma(line[i+1:-1].lstrip())
  895. else:
  896. self.name = line
  897. self.params = []
  898. if not is_name(self.name):
  899. self.isvalid = False
  900. return
  901. return BeginStatement.process_item(self)
  902. def tostr(self):
  903. s = 'TYPE'
  904. if self.specs:
  905. s += ', '.join(['']+self.specs) + ' ::'
  906. s += ' ' + self.name
  907. if self.params:
  908. s += ' ('+', '.join(self.params)+')'
  909. return s
  910. def get_classes(self):
  911. return [Integer] + private_or_sequence + component_part +\
  912. type_bound_procedure_part
  913. def analyze(self):
  914. BeginStatement.analyze(self)
  915. for spec in self.specs:
  916. i = spec.find('(')
  917. if i!=-1:
  918. assert spec.endswith(')'),`spec`
  919. s = spec[:i].rstrip().upper()
  920. n = spec[i+1:-1].strip()
  921. if s=='EXTENDS':
  922. self.a.extends = n
  923. continue
  924. elif s=='BIND':
  925. args,rest = parse_bind(spec)
  926. assert not rest,`rest`
  927. spec = 'BIND(%s)' % (', '.join(args))
  928. else:
  929. spec = '%s(%s)' % (s,n)
  930. else:
  931. spec = spec.upper()
  932. self.update_attributes(spec)
  933. component_names = self.a.component_names
  934. content = self.content[:]
  935. while content:
  936. stmt = content.pop(0)
  937. if isinstance(stmt, self.end_stmt_cls):
  938. break
  939. stmt.analyze()
  940. if content:
  941. self.show_message('Not analyzed content: %s' % content)
  942. parameters = self.a.parameters
  943. components = self.a.components
  944. component_names = self.a.component_names
  945. for name in self.a.variable_names:
  946. var = self.a.variables[name]
  947. if name in self.params:
  948. parameters[name] = var
  949. else:
  950. component_names.append(name)
  951. components[name] = var
  952. self.parent.a.type_decls[self.name] = self
  953. parent_provides = self.parent.get_provides()
  954. if parent_provides is not None:
  955. if self.is_public():
  956. if self.name in parent_provides:
  957. self.warning('type declaration name conflict with %s, overriding.' % (self.name))
  958. parent_provides[self.name] = self
  959. return
  960. def topyf(self, tab=''):
  961. s = tab + 'TYPE'
  962. if self.a.extends is not None:
  963. s += ', EXTENDS(%s) ::' % (self.a.extends)
  964. s += ' ' + self.name
  965. if self.a.parameters:
  966. s += ' (%s)' % (', '.join(self.a.parameters))
  967. s += '\n'
  968. s += AccessSpecs.topyf(self, tab=tab+' ')
  969. s += HasAttributes.topyf(self, tab=tab+' ')
  970. s += HasVariables.topyf(self, tab=tab+' ')
  971. s += tab + 'END TYPE ' + self.name + '\n'
  972. return s
  973. # Wrapper methods:
  974. def get_bit_size(self, _cache={}):
  975. try:
  976. return _cache[id(self)]
  977. except KeyError:
  978. s = 0
  979. for name,var in self.a.components.items():
  980. s += var.get_bit_size()
  981. _cache[id(self)] = s
  982. return s
  983. def is_public(self): return not self.is_private()
  984. def is_private(self):
  985. if 'PUBLIC' in self.a.attributes: return False
  986. if 'PRIVATE' in self.a.attributes: return True
  987. return self.parent.check_private(self.name)
  988. TypeDecl = Type
  989. # Enum
  990. class EndEnum(EndStatement):
  991. """
  992. END ENUM
  993. """
  994. match = re.compile(r'end\s*enum\Z',re.I).match
  995. blocktype = 'enum'
  996. class Enum(BeginStatement):
  997. """
  998. ENUM , BIND(C)
  999. <enumerator-def-stmt>
  1000. [ <enumerator-def-stmt> ]...
  1001. """
  1002. blocktype = 'enum'
  1003. end_stmt_cls = EndEnum
  1004. match = re.compile(r'enum\s*,\s*bind\s*\(\s*c\s*\)\Z',re.I).match
  1005. def process_item(self):
  1006. return BeginStatement.process_item(self)
  1007. def get_classes(self):
  1008. return [Enumerator]
  1009. ###################################################
  1010. import statements
  1011. import typedecl_statements
  1012. __all__.extend(statements.__all__)
  1013. __all__.extend(typedecl_statements.__all__)
  1014. from statements import *
  1015. from typedecl_statements import *
  1016. f2py_stmt = [Threadsafe, FortranName, Depend, Check, CallStatement,
  1017. CallProtoArgument]
  1018. access_spec = [Public, Private]
  1019. interface_specification = [Function, Subroutine,
  1020. ModuleProcedure
  1021. ]
  1022. module_subprogram_part = [ Contains, Function, Subroutine ]
  1023. specification_stmt = access_spec + [ Allocatable, Asynchronous, Bind,
  1024. Common, Data, Dimension, Equivalence, External, Intent, Intrinsic,
  1025. Namelist, Optional, Pointer, Protected, Save, Target, Volatile,
  1026. Value ]
  1027. intrinsic_type_spec = [ SubprogramPrefix, Integer , Real,
  1028. DoublePrecision, Complex, DoubleComplex, Character, Logical, Byte
  1029. ]
  1030. derived_type_spec = [ ]
  1031. type_spec = intrinsic_type_spec + derived_type_spec
  1032. declaration_type_spec = intrinsic_type_spec + [ TypeStmt, Class ]
  1033. type_declaration_stmt = declaration_type_spec
  1034. private_or_sequence = [ Private, Sequence ]
  1035. component_part = declaration_type_spec + [ ModuleProcedure ]
  1036. proc_binding_stmt = [SpecificBinding, GenericBinding, FinalBinding]
  1037. type_bound_procedure_part = [Contains, Private] + proc_binding_stmt
  1038. #R214
  1039. action_stmt = [ Allocate, GeneralAssignment, Assign, Backspace, Call, Close,
  1040. Continue, Cycle, Deallocate, Endfile, Exit, Flush, ForallStmt,
  1041. Goto, If, Inquire, Nullify, Open, Print, Read, Return, Rewind,
  1042. Stop, Wait, WhereStmt, Write, ArithmeticIf, ComputedGoto,
  1043. AssignedGoto, Pause ]
  1044. # GeneralAssignment = Assignment + PointerAssignment
  1045. # EndFunction, EndProgram, EndSubroutine - part of the corresponding blocks
  1046. executable_construct = [ Associate, Do, ForallConstruct, IfThen,
  1047. Select, WhereConstruct ] + action_stmt
  1048. #Case, see Select
  1049. execution_part_construct = executable_construct + [ Format, Entry,
  1050. Data ]
  1051. execution_part = execution_part_construct[:]
  1052. #C201, R208
  1053. for cls in [EndFunction, EndProgram, EndSubroutine]:
  1054. try: execution_part.remove(cls)
  1055. except ValueError: pass
  1056. internal_subprogram = [Function, Subroutine]
  1057. internal_subprogram_part = [ Contains, ] + internal_subprogram
  1058. declaration_construct = [ TypeDecl, Entry, Enum, Format, Interface,
  1059. Parameter, ModuleProcedure, ] + specification_stmt + \
  1060. type_declaration_stmt
  1061. # stmt-function-stmt
  1062. implicit_part = [ Implicit, Parameter, Format, Entry ]
  1063. specification_part = [ Use, Import ] + implicit_part + \
  1064. declaration_construct
  1065. external_subprogram = [Function, Subroutine]
  1066. main_program = [Program] + specification_part + execution_part + \
  1067. internal_subprogram_part
  1068. program_unit = main_program + external_subprogram + [Module,
  1069. BlockData ]