From 90c5f130dbf8d9a1466c9d3df44e65c9850ead25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Riette?= Date: Thu, 7 Nov 2024 11:24:27 +0100 Subject: [PATCH] BF in variables, better handling of exceptions, version 0.2.1 --- src/pyfortool/__init__.py | 2 +- src/pyfortool/scripting.py | 36 +++++----- src/pyfortool/variables.py | 144 ++++++++++++++++++++----------------- 3 files changed, 95 insertions(+), 87 deletions(-) diff --git a/src/pyfortool/__init__.py b/src/pyfortool/__init__.py index 8ffd753..854dd50 100644 --- a/src/pyfortool/__init__.py +++ b/src/pyfortool/__init__.py @@ -3,7 +3,7 @@ FORTRAN files to apply source-to-source transformations. """ -__version__ = "0.2.0" +__version__ = "0.2.1" # NAMESPACE should be defined first NAMESPACE = 'http://fxtran.net/#syntax' diff --git a/src/pyfortool/scripting.py b/src/pyfortool/scripting.py index 856d987..1e89a7b 100644 --- a/src/pyfortool/scripting.py +++ b/src/pyfortool/scripting.py @@ -29,29 +29,27 @@ def task(filename): allArgs, orderedOptions = allFileArgs[filename] try: # Opening and reading of the FORTRAN file - pft = PYFT(filename, filename, parser=allArgs.parser, - parserOptions=getParserOptions(allArgs), verbosity=allArgs.logLevel, - wrapH=allArgs.wrapH, - enableCache=allArgs.enableCache) - - # apply the transformation in the order they were specified - for arg in orderedOptions: - logging.debug('Applying %s on %s', arg, filename) - applyTransfo(pft, arg, allArgs, - filename if filename == allArgs.plotCentralFile else None) - logging.debug(' -> Done') - - # Writing - if not allArgs.dryRun: - pft.write() - - # Closing and reporting - pft.close() + with PYFT(filename, filename, parser=allArgs.parser, + parserOptions=getParserOptions(allArgs), verbosity=allArgs.logLevel, + wrapH=allArgs.wrapH, + enableCache=allArgs.enableCache) as pft: + + # apply the transformation in the order they were specified + for arg in orderedOptions: + logging.debug('Applying %s on %s', arg, filename) + applyTransfo(pft, arg, allArgs, + filename if filename == allArgs.plotCentralFile else None) + logging.debug(' -> Done') + + # Writing + if not allArgs.dryRun: + pft.write() + + # Reporting return (0, filename) except Exception as exc: # pylint: disable=broad-except logging.error("The following error has occurred in the file %s", filename) - PYFT.unlockFile(filename, silence=True) traceback.print_exception(exc, file=sys.stdout) sys.stdout.flush() return (1, filename) diff --git a/src/pyfortool/variables.py b/src/pyfortool/variables.py index 196e44a..52de001 100644 --- a/src/pyfortool/variables.py +++ b/src/pyfortool/variables.py @@ -1442,40 +1442,10 @@ def insertInArgList(varName, varNameToUse, pos, callFuncStmt): if len(self.path.split('/')) == 1: filename, scopePathInterface = self.tree.findScopeInterface(self.path) if filename is not None: - if self.getFileName() == os.path.normpath(filename): - # interface declared in same file - xml = self.mainScope - pft = None - else: - pft = pyfortool.pyfortoolconservativePYFT( - filename, parser, parserOptions, wrapH, tree=self.tree, - clsPYFT=self._mainScope.__class__) - xml = pft - scopeInterface = xml.getScopeNode(scopePathInterface) - varInterface = scopeInterface.varList.findVar(varName, exactScope=True) - if varInterface is None: - scopeInterface.addVar([[scopePathInterface, varName, declStmt, pos]]) - if moduleVarList is not None: - # Module variables must be added when var is added - xml.addModuleVar([(scopePathInterface, moduleName, moduleVarNames) - for (moduleName, - moduleVarNames) in moduleVarList]) - if pft is not None: - pft.write() - pft.close() - - if var is None and self.path not in stopScopes: - # We must propagates upward - # scopes calling the current scope - for scopePathUp in self.tree.calledByScope(self.path): - if scopePathUp in stopScopes or self.tree.isUnderStopScopes(scopePathUp, - stopScopes): - # We are on the path to a scope in the stopScopes list, or scopePathUp is - # one of the stopScopes - # can be defined several times? - for filename in self.tree.scopeToFiles(scopePathUp): + pft = None + try: if self.getFileName() == os.path.normpath(filename): - # Upper scope is in the same file + # interface declared in same file xml = self.mainScope pft = None else: @@ -1483,44 +1453,84 @@ def insertInArgList(varName, varNameToUse, pos, callFuncStmt): filename, parser, parserOptions, wrapH, tree=self.tree, clsPYFT=self._mainScope.__class__) xml = pft - scopeUp = xml.getScopeNode(scopePathUp) - # Add the argument and propagate upward - scopeUp.addArgInTree( - varName, declStmt, pos, - stopScopes, moduleVarList, otherNames, - parser=parser, parserOptions=parserOptions, - wrapH=wrapH) - # Add the argument to calls (subroutine or function) - name = self.path.split('/')[-1].split(':')[1].upper() - isCalled = False - varNameToUse = varName - if otherNames is not None: - vOther = [scopeUp.varList.findVar(v, exactScope=True) - for v in otherNames] - vOther = [v for v in vOther if v is not None] - if len(vOther) > 0: - varNameToUse = vOther[-1]['n'] - if self.path.split('/')[-1].split(':')[0] == 'sub': - # We look for call statements - for callStmt in scopeUp.findall('.//{*}call-stmt'): - callName = n2name(callStmt.find('./{*}procedure-designator/' + - '{*}named-E/{*}N')).upper() - if callName == name: - insertInArgList(varName, varNameToUse, pos, callStmt) - isCalled = True - else: - # We look for function use - for funcCall in scopeUp.findall( - './/{*}named-E/{*}R-LT/{*}parens-R/' + - '{*}element-LT/../../..'): - funcName = n2name(funcCall.find('./{*}N')).upper() - if funcName == name: - insertInArgList(varName, varNameToUse, pos, funcCall) - isCalled = True + scopeInterface = xml.getScopeNode(scopePathInterface) + varInterface = scopeInterface.varList.findVar(varName, exactScope=True) + if varInterface is None: + scopeInterface.addVar([[scopePathInterface, varName, + declStmt, pos]]) + if moduleVarList is not None: + # Module variables must be added when var is added + xml.addModuleVar( + [(scopePathInterface, moduleName, moduleVarNames) + for (moduleName, moduleVarNames) in moduleVarList]) if pft is not None: pft.write() + finally: + if pft is not None: pft.close() + if var is None and self.path not in stopScopes: + # We must propagates upward + # scopes calling the current scope + for scopePathUp in self.tree.calledByScope(self.path): + if scopePathUp in stopScopes or self.tree.isUnderStopScopes(scopePathUp, + stopScopes): + # We are on the path to a scope in the stopScopes list, or scopePathUp is + # one of the stopScopes + # can be defined several times? + for filename in self.tree.scopeToFiles(scopePathUp): + pft = None + try: + if self.getFileName() == os.path.normpath(filename): + # Upper scope is in the same file + xml = self.mainScope + pft = None + else: + pft = pyfortool.pyfortool.conservativePYFT( + filename, parser, parserOptions, wrapH, + tree=self.tree, + clsPYFT=self._mainScope.__class__) + xml = pft + scopeUp = xml.getScopeNode(scopePathUp) + # Add the argument and propagate upward + scopeUp.addArgInTree( + varName, declStmt, pos, + stopScopes, moduleVarList, otherNames, + parser=parser, parserOptions=parserOptions, + wrapH=wrapH) + # Add the argument to calls (subroutine or function) + name = self.path.split('/')[-1].split(':')[1].upper() + isCalled = False + varNameToUse = varName + if otherNames is not None: + vOther = [scopeUp.varList.findVar(v, exactScope=True) + for v in otherNames] + vOther = [v for v in vOther if v is not None] + if len(vOther) > 0: + varNameToUse = vOther[-1]['n'] + if self.path.split('/')[-1].split(':')[0] == 'sub': + # We look for call statements + for callStmt in scopeUp.findall('.//{*}call-stmt'): + callName = n2name(callStmt.find( + './{*}procedure-designator/{*}named-E/{*}N')).upper() + if callName == name: + insertInArgList(varName, varNameToUse, pos, callStmt) + isCalled = True + else: + # We look for function use + for funcCall in scopeUp.findall( + './/{*}named-E/{*}R-LT/{*}parens-R/' + + '{*}element-LT/../../..'): + funcName = n2name(funcCall.find('./{*}N')).upper() + if funcName == name: + insertInArgList(varName, varNameToUse, pos, funcCall) + isCalled = True + if pft is not None: + pft.write() + finally: + if pft is not None: + pft.close() + if isCalled: # We must check in the scope (or upper scopes) if an interface # block declares the routine