PyForTool
Python-fortran-tool
Loading...
Searching...
No Matches
scripting.py
1"""
2This module contains functions usefull to build scripts around the pyfortool library
3"""
4
5import sys
6from multiprocessing import cpu_count, Pool
7from multiprocessing.managers import BaseManager
8import re
9import shlex
10import os
11import argparse
12import logging
13import traceback
14
15from pyfortool.pyfortool import PYFT
16from pyfortool.tree import Tree
17from pyfortool.util import isint, PYFTError
18from pyfortool import __version__
19
20
21def task(filename):
22 """
23 Function to use on each file
24 :param clsPYFT: PYFT class to use
25 :param filename: file name
26 """
27 global PYFT
28 global allFileArgs
29 allArgs, orderedOptions = allFileArgs[filename]
30 try:
31 # Opening and reading of the FORTRAN file
32 with PYFT(filename, filename, parser=allArgs.parser,
33 parserOptions=getParserOptions(allArgs), verbosity=allArgs.logLevel,
34 wrapH=allArgs.wrapH,
35 enableCache=allArgs.enableCache) as pft:
36
37 # apply the transformation in the order they were specified
38 for arg in orderedOptions:
39 logging.debug('Applying %s on %s', arg, filename)
40 applyTransfo(pft, arg, allArgs,
41 filename if filename == allArgs.plotCentralFile else None)
42 logging.debug(' -> Done')
43
44 # Writing
45 if not allArgs.dryRun:
46 pft.write()
47
48 # Reporting
49 return (0, filename)
50
51 except Exception as exc: # pylint: disable=broad-except
52 logging.error("The following error has occurred in the file %s", filename)
53 traceback.print_exception(exc, file=sys.stdout)
54 sys.stdout.flush()
55 return (1, filename)
56
57
59 """
60 Core of the pyfortool_parallel.py command
61 """
62
63 class MyManager(BaseManager):
64 """
65 Custom manager to deal with Tree instances
66 """
67
68 MyManager.register('Tree', Tree)
69
70 def init(cls, afa):
71 """
72 Pool initializer
73 """
74 # After many, many attempts, it seems very difficult (if not impossible)
75 # to do without global variables
76 global PYFT # pylint: disable=global-statement
77 global allFileArgs # pylint: disable=global-statement
78 PYFT = cls
79 allFileArgs = afa
80
81 parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
82 epilog="The argument order matters.")
83
84 updateParser(parser, withInput=False, withOutput=False, withXml=False, withPlotCentralFile=True,
85 treeIsOptional=False, nbPar=True, restrictScope=False)
86 commonArgs, getFileArgs = getArgs(parser)
87
88 # Manager to share the Tree instance
89 with MyManager() as manager:
90 # Set-up the Tree instance
91 sharedTree = getDescTree(commonArgs, manager.Tree)
92
93 # Prepare PYFT to be used in parallel
94 PYFT.setParallel(sharedTree)
95
96 # Set-up the processes
97 allFileArgs = {file: getFileArgs(file) for file in sharedTree.getFiles()}
98 logging.info('Executing in parallel on %i files with a maximum of %i processes',
99 len(allFileArgs), commonArgs.nbPar)
100 with Pool(commonArgs.nbPar, initializer=init, initargs=(PYFT, allFileArgs)) as pool:
101 result = pool.map(task, sharedTree.getFiles())
102
103 # Writting the descTree object
104 sharedTree.toJson(commonArgs.descTree)
105
106 # General error
107 errors = [item[1] for item in result if item[0] != 0]
108 status = len(errors)
109 if status != 0:
110 logging.error('List of files with error:')
111 for error in errors:
112 logging.error(' - %s', error)
113 raise PYFTError(f"Errors have been reported in {status} file(s).")
114
115
116def main():
117 """
118 Core of the pyfortool.py command
119 """
120 parser = argparse.ArgumentParser(description='Python FORTRAN tool', allow_abbrev=False,
121 epilog="The argument order matters.")
122
123 updateParser(parser, withInput=True, withOutput=True, withXml=True, withPlotCentralFile=False,
124 treeIsOptional=True, nbPar=False, restrictScope=True)
125 args, orderedOptions = getArgs(parser)[1]()
126
127 parserOptions = getParserOptions(args)
128 descTree = getDescTree(args)
129
130 try:
131 # Opening and reading of the FORTRAN file
132 pft = PYFT(args.INPUT, args.OUTPUT, parser=args.parser, parserOptions=parserOptions,
133 verbosity=args.logLevel, wrapH=args.wrapH, tree=descTree,
134 enableCache=args.enableCache)
135 if args.restrictScope != '':
136 pft = pft.getScopeNode(args.restrictScope)
137
138 # apply the transformation in the order they were specified
139 for arg in orderedOptions:
140 logging.debug('Applying %s on %s', arg, args.INPUT)
141 applyTransfo(pft, arg, args, plotCentralFile=args.INPUT)
142 logging.debug(' -> Done')
143
144 # Writing
145 if descTree is not None:
146 descTree.toJson(args.descTree)
147 if args.xml is not None:
148 pft.mainScope.writeXML(args.xml)
149 if not args.dryRun:
150 pft.mainScope.write()
151
152 # Closing
153 pft.mainScope.close()
154
155 except: # noqa E722
156 # 'exept' everything and re-raise error systematically
157 logging.error("The following error has occurred in the file %s", args.INPUT)
158 raise
159
160
161ARG_UPDATE_CNT = ('--alignContinuation', '--addBeginContinuation',
162 '--removeBeginContinuation',
163 '--emoveALLContinuation')
164
165
166def getArgs(parser):
167 """
168 Parse arguments and interpret the --optsByEnv option
169 :param parser: argparse parser
170 :return: a tuple with
171 - an argparse namespace containing common arguments (not using the --optsEnv option)
172 - a function taking a filename as input and returning
173 - an argparse namespace with the common arguments and the ones added by
174 interpreting the --optsEnv option
175 - an ordered list of arguments
176 """
177 args = parser.parse_args()
178
179 def getFileArgs(filename=args.INPUT if hasattr(args, 'INPUT') else None):
180 """
181 :param filename: name of source code file
182 :return: argparse namespace to use with this file and
183 a list given the order in which the arguments were provided
184 """
185 # Decode the --optsByEnv option
186 arguments = sys.argv[1:]
187 if args.optsByEnv is not None:
188 extra = ''
189 for line in [] if args.optsByEnv is None else os.environ[args.optsByEnv].split('\n'):
190 if ':=:' in line:
191 if re.match(line.split(':=:')[0], filename):
192 extra = line.split(':=:')[1]
193 else:
194 extra = line
195 arguments.extend(shlex.split(extra))
196
197 # Compute the ordered list
198 updateCnt = False
199 optList = []
200 for arg in arguments:
201 if arg.startswith('--') and arg not in optList:
202 if arg in ARG_UPDATE_CNT:
203 if not updateCnt:
204 updateCnt = True
205 optList.append(arg)
206 else:
207 optList.append(arg)
208
209 return parser.parse_args(arguments), optList
210
211 return args, getFileArgs
212
213
215 """
216 Get the options to use for the fxtran parser
217 :param args: arguments parsed by the argparse parser
218 """
219 if args.parserOption is None:
220 parserOptions = PYFT.DEFAULT_FXTRAN_OPTIONS.copy()
221 else:
222 parserOptions = [el for elements in args.parserOption for el in elements]
223 if args.addIncludes:
224 parserOptions = [opt for opt in parserOptions if opt not in ('-no-include', '-noinclude')]
225 return parserOptions
226
227
228def getDescTree(args, cls=Tree):
229 """
230 get the Tree object built with the parsed arguments
231 :param args: arguments parsed by the argparse parser
232 :param cls: class to use (usefull for manager)
233 :return: a Tree instance
234 """
235 parserOptions = getParserOptions(args)
236 if args.descTree:
237 descTree = cls(tree=args.tree, descTreeFile=args.descTree,
238 parser=args.parser, parserOptions=parserOptions,
239 wrapH=args.wrapH, verbosity=args.logLevel)
240 else:
241 descTree = None
242 return descTree
243
244
245def updateParser(parser, withInput, withOutput, withXml, withPlotCentralFile, treeIsOptional,
246 nbPar, restrictScope):
247 """
248 Updates an argparse parser with arguments common to all the different tools
249 :param parser: parser in which arguments are added
250 :param withOutput: do we need the INPUT argument
251 :param withOutput: do we need the OUTPUT argument
252 :param withXml: do we need to be able to define an XML output file
253 :param withPlotCentralFile: to add the --plotCentralFile argument
254 :param treeIsOptional: is the --tree argument optional?
255 :param nbPar: number of parallel processes
256 :param restrictScope: can we specify the scope path
257 """
258
259 # ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
260 # IMPORTANT NOTE
261 # Argument order matters but argparse is not able to give the order
262 # Therefore, arguments are processed twice. The first time by argparse to fully decode them.
263 # The a second pass is made direcly on sys.argv. This mechanism has two implications:
264 # allow_abbrev must be set to False in ArgumentParser
265 # only long argument options are allowed (begining with two dashes)
266 # ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
267 assert not parser.allow_abbrev, 'parser must be created with allow_abbrev=False'
268
269 parser.add_argument('--version', action='version',
270 version='%(prog)s {version}'.format(version=__version__))
271 parser.add_argument('--simplify', default=False, action='store_true',
272 help='After a deletion, recursively deletes the code ' +
273 'and variables that have become useless')
274 parser.add_argument('--logLevel', default='warning',
275 help='Provide logging level. Example --logLevel debug (default is warning)')
276 parser.add_argument('--enableCache', default=False, action='store_true',
277 help='Precompute parent of each xml node and store the result')
278 if nbPar:
279 parser.add_argument('--nbPar', default=cpu_count(), type=int,
280 help='Number of parallel processes, 0 to get as many processes ' +
281 'as the number of cores (default=0)')
282 parser.add_argument('--optsByEnv', default=None, type=str,
283 help='Name of the environment variable containing additional arguments ' +
284 'to use. These arguments are processed after all other arguments. ' +
285 'The variable can contain a multi-lines string. The ' +
286 'variable is read line by line and the last applicable line is ' +
287 'used. A line can take one of these two forms: ' +
288 '1) "FILE_DESCRIPTOR:=:OPTIONS" (where FILE_DESCRIPTOR is a ' +
289 'regular expression to test against the filename. If there ' +
290 'is a match, the OPTIONS can be used for the file) and ' +
291 '2) "OPTIONS" (if the line doesn\'t contain the FILE_DESCRIPTOR ' +
292 'part, it applies to all source code).')
293
294 if restrictScope:
295 parser.add_argument('--restrictScope', default='', type=str, metavar='SCOPEPATH',
296 help="Limit the action to this scope path (SUBROUTINE/FUNCTION/" +
297 "MODULE/TYPE). It is '/'-separated path with each element " +
298 "having the form 'module:<name of the module>', " +
299 "'sub:<name of the subroutine>', " +
300 "'func:<name of the function>' or 'type:<name of the type>'.")
301
302 # Inputs and outputs
303 updateParserInputsOutputs(parser, withInput, withOutput, withXml)
304
305 # fxtran
306 updateParserFxtran(parser)
307
308 # Variables
310
311 # Cosmetics
313
314 # Applications
316
317 # openACC
318 updateParserOpenACC(parser)
319
320 # Checks
321 updateParserChecks(parser)
322
323 # Statements
325
326 # Misc
327 updateParserMisc(parser)
328
329 # Tree
330 updateParserTree(parser, withPlotCentralFile, treeIsOptional)
331
332 # Preprocessot
334
335
336def updateParserInputsOutputs(parser, withInput, withOutput, withXml):
337 """
338 Updates an argparse parser with input/output arguments
339 :param parser: parser in which arguments are added
340 :param withOutput: do we need the INPUT argument
341 :param withOutput: do we need the OUTPUT argument
342 :param withXml: do we need to be able to define an XML output file
343 """
344 gInOut = parser.add_argument_group('Input and output')
345 if withInput:
346 gInOut.add_argument('INPUT', help='FORTRAN input file')
347 if withOutput:
348 gInOut.add_argument('OUTPUT', default=None, help='FORTRAN output file', nargs='?')
349 gInOut.add_argument('--renamefF', default=False, action='store_true',
350 help='Put file extension in upper case')
351 gInOut.add_argument('--renameFf', default=False, action='store_true',
352 help='Put file extension in lower case')
353 if withXml:
354 gInOut.add_argument('--xml', default=None, type=str,
355 help='Output file for xml')
356 gInOut.add_argument('--dryRun', default=False, action='store_true',
357 help='Dry run without writing the FORTRAN file (the xml ' +
358 'is still written')
359
360
362 """
363 Updates an argparse parser with fxtran arguments
364 """
365 gParser = parser.add_argument_group('fxtran parser relative options')
366 gParser.add_argument('--parser', default=None, type=str,
367 help='Path to the fxtran parser binary')
368 gParser.add_argument('--parserOption', nargs='*', action='append',
369 help='Option to pass to fxtran, defaults ' +
370 f'to {PYFT.DEFAULT_FXTRAN_OPTIONS}')
371 gParser.add_argument('--wrapH', default=False, action='store_true',
372 help='Wrap .h file content into a MODULE to enable the reading')
373
374
376 """
377 Updates an argparse parser with variables arguments
378 """
379 gVariables = parser.add_argument_group('Options to deal with variables')
380 gVariables.add_argument('--showVariables', default=False, action='store_true',
381 help='Show the declared variables')
382 gVariables.add_argument('--removeVariable', nargs=2, action='append',
383 metavar=('SCOPEPATH', 'VARNAME'),
384 help="Variable to remove from declaration. The first argument " +
385 "is the SUBROUTINE/FUNCTION/MODULE/TYPE where the variable " +
386 "is declared. It is '/'-separated path with each element having " +
387 "the form 'module:<name of the module>', " +
388 "'sub:<name of the subroutine>', " +
389 "'func:<name of the function>' or 'type:<name of the type>'. " +
390 "The second argument is the variable name")
391 gVariables.add_argument('--attachArraySpecToEntity', default=False, action='store_true',
392 help='Find all T-decl-stmt elements that have a child element ' +
393 'attribute with attribute-N=DIMENSION and move the attribute ' +
394 'into EN-N elements')
395 gVariables.add_argument('--addVariable', nargs=4, action='append',
396 metavar=('SCOPEPATH', 'VARNAME', 'DECLARATION', 'POSITION'),
397 help='Add a variable. First argument is the scope path (as for ' +
398 'the --removeVariable option. The second is the variable ' +
399 'name, the third is the declarative statement to insert, ' +
400 'the fourth is the position (python indexing) the new ' +
401 'variable will have in the calling statment of the ' +
402 'routine (non-integer value for a local variable).')
403 gVariables.add_argument('--addModuleVariable', nargs=3, action='append',
404 metavar=('SCOPEPATH', 'MODULENAME', 'VARNAME'),
405 help='Add a USE statement. The first argument is the scope path ' +
406 '(as for the --removeVariable option). The second is the module ' +
407 'name; the third is the variable name.')
408 gVariables.add_argument('--showUnusedVariables', default=False, action='store_true',
409 help='Show a list of unused variables.')
410 gVariables.add_argument('--removeUnusedLocalVariables',
411 help='Remove unused local variables, excluding some variables (comma-' +
412 'separated list or NONE to exclude nothing).')
413 gVariables.add_argument('--removePHYEXUnusedLocalVariables',
414 help='Remove unused local variables, excluding some variables (comma-' +
415 'separated list or NONE to exclude nothing). This option takes ' +
416 'into account the mnh_expand directives to prevent from ' +
417 'removing useful variables.')
418 gVariables.add_argument('--addExplicitArrayBounds', action='store_true',
419 help='Adds explicit bounds to arrays that already have parentheses.')
420 gVariables.add_argument('--addArrayParentheses', action='store_true',
421 help='Adds parentheses to arrays (A => A(:))')
422 gVariables.add_argument('--modifyAutomaticArrays', metavar="DECL#START#END",
423 help='Transform all automatic arrays declaration using the templates.' +
424 ' The DECL part of the template will replace the declaration ' +
425 'statement, the START part will be inserted as the first ' +
426 'executable statement while the END part will be inserted as ' +
427 'the last executable statement. Each part ' +
428 'of the template can use the following place holders: ' +
429 '"{doubledotshape}", "{shape}", "{lowUpList}", "{name}" and ' +
430 '"{type}" which are, respectively modified into ' +
431 '":, :, :", "I, I:J, 0:I", "1, I, I, J, 0, I", "A", "REAL" ' +
432 'if the original declaration statement ' +
433 'was "A(I, I:J, 0:I)". For example, the template ' +
434 '"{type}, DIMENSION({doubledotshape}), ALLOCATABLE :: ' +
435 '{name}#ALLOCATE({name}({shape}))#DEALLOCATE({name})"' +
436 'will replace automatic arrays by allocatables.')
437 gVariables.add_argument('--replaceAutomaticWithAllocatable', action='store_true',
438 help='Replace all automatic arrays with allocatable arrays.')
439 gVariables.add_argument('--addArgInTree', default=None, action='append', nargs=3,
440 metavar=('VARNAME', 'DECLARATION', 'POSITION'),
441 help='Add an argument variable. The first argument is the variable ' +
442 'name, the second one is the declarative statement to insert, ' +
443 'the third one is the position (python indexing) the new ' +
444 'variable will have in the calling statement of the ' +
445 'routine. Needs the --stopScopes argument')
446
447
449 """
450 Updates an argparse parser with cosmetics arguments
451 """
452 gCosmetics = parser.add_argument_group('Cosmetics options')
453 gCosmetics.add_argument('--upperCase', default=False, action='store_true',
454 help='Put FORTRAN code in upper case letters')
455 gCosmetics.add_argument('--lowerCase', default=False, action='store_true',
456 help='Put FORTRAN code in lower case letters')
457 gCosmetics.add_argument('--changeIfStatementsInIfConstructs', default=False,
458 action='store_true',
459 help='Find all if-statement and convert it to if-then-statement')
460 gCosmetics.add_argument('--indent', default=False, action='store_true',
461 help='Correct indentation')
462 gCosmetics.add_argument('--removeIndent', default=False, action='store_true',
463 help='Remove indentation')
464 gCosmetics.add_argument('--removeEmptyLines', default=False, action='store_true',
465 help='Remove empty lines')
466 gCosmetics.add_argument('--removeComments', default=False, action='store_true',
467 help='Remove comments')
468 gCosmetics.add_argument('--updateSpaces', default=False, action='store_true',
469 help='Updates spaces around operators, commas, parenthesis and ' +
470 'at the end of line')
471 gCosmetics.add_argument('--alignContinuation', default=False, action='store_true',
472 help='Align the beginings of continued lines')
473 gCosmetics.add_argument('--addBeginContinuation', default=False, action='store_true',
474 help='Add missing continuation characters (\'&\') at the ' +
475 'begining of lines')
476 gCosmetics.add_argument('--removeBeginContinuation', default=False, action='store_true',
477 help='Remove continuation characters (\'&\') at the begining of lines')
478 gCosmetics.add_argument('--removeALLContinuation', default=False, action='store_true',
479 help='Remove all continuation characters(\'&\')')
480 gCosmetics.add_argument('--prettify', default=False, action='store_true',
481 help='Prettify the source code (indentation, spaces...)')
482 gCosmetics.add_argument('--minify', default=False, action='store_true',
483 help='Simplify the source code (indentation, spaces...)')
484 gCosmetics.add_argument('--removeEmptyCONTAINS', default=False, action='store_true',
485 help='Remove useless CONTAINS statements')
486
487
489 """
490 Updates an argparse parser with applications arguments
491 """
492 gApplications = parser.add_argument_group('Options to apply upper level transformation')
493 gApplications.add_argument('--deleteDrHook', default=False, action='store_true',
494 help='Delete DR HOOK use')
495 gApplications.add_argument('--addDrHook', default=False, action='store_true',
496 help='Add DR HOOK')
497 gApplications.add_argument('--deleteBudgetDDH', default=False, action='store_true',
498 help='Delete Budget/DDH use')
499 gApplications.add_argument('--deleteRoutineCallsMesoNHGPU', default=False, action='store_true',
500 help='Delete parts of the code not compatible with MesoNH-OpenACC' +
501 'such as OCND2 blocks')
502 gApplications.add_argument('--splitModuleRoutineFile', default=False, action='store_true',
503 help='Split a file')
504 gApplications.add_argument('--deleteNonColumnCallsPHYEX', default=False, action='store_true',
505 help='Delete call to PHYEX routines that needs information on ' +
506 'horizontal points (multiple column dependency')
507 gApplications.add_argument('--removeIJDim', default=False, action='store_true',
508 help='Remove I and J dimensions (1, KLON). ' +
509 'Needs the --stopScopes argument.')
510 gApplications.add_argument('--expandAllArraysPHYEX', default=False, action='store_true',
511 help='Expand all array syntax (computing and where block) ' +
512 'using PHYEX conventions')
513 gApplications.add_argument('--expandAllArraysPHYEXConcurrent', default=False,
514 action='store_true',
515 help='Expand all array syntax with DO CONCURRENT loops ' +
516 '(computing and where block) using PHYEX conventions')
517 gApplications.add_argument('--expandAllArrays', default=False, action='store_true',
518 help='Expand all array syntax (computing and where block) ' +
519 'using mnh directives if present')
520 gApplications.add_argument('--expandAllArraysConcurrent', default=False, action='store_true',
521 help='Expand all array syntax with DO CONCURRENT loops ' +
522 '(computing and where block) using mnh directives if present')
523 gApplications.add_argument('--inlineContainedSubroutinesPHYEX', default=False,
524 action='store_true',
525 help='Inline containted subroutines in main routine, using ' +
526 'PHYEX conventions')
527 gApplications.add_argument('--addStack', metavar='MODEL', type=str,
528 help='Add local arrays to the stack. The argument is the ' +
529 'the model name in which stack must be added ("AROME" ' +
530 'or "MESONH"). Needs the --stopScopes argument for AROME.')
531 gApplications.add_argument('--addIncludes', default=False, action='store_true',
532 help='Add .h includes in the file and remove the INCLUDE statement')
533 gApplications.add_argument('--mnhExpand', default=False, action='store_true',
534 help='Apply the mnh_expand directives with DO loops')
535 gApplications.add_argument('--mnhExpandConcurrent', default=False, action='store_true',
536 help='Apply the mnh_expand directives with DO CONCURRENT loops')
537 gApplications.add_argument('--addMPPDB_CHECKS', default=False, action='store_true',
538 help='Add MPPDB_CHEKS bit-repro checking routines of MesoNH for ' +
539 'all in and inout arrays in subroutines')
540 gApplications.add_argument('--addPrints', default=False, action='store_true',
541 help='Add Prints of min/maxval and shape of all in, out, inout ' +
542 'arguments of all scopes')
543 gApplications.add_argument('--shumanFUNCtoCALL', default=False, action='store_true',
544 help='Transform shuman functions to call statements')
545 gApplications.add_argument('--mathFunctoBRFunc', default=False, action='store_true',
546 help='Convert intrinsic math functions **, LOG, ATAN, **2, **3, ' +
547 '**4, EXP, COS, SIN, ATAN2 into a self defined function BR_ ' +
548 'for MesoNH bit-repro.')
549 gApplications.add_argument('--convertTypesInCompute', default=False, action='store_true',
550 help='Use single variable instead of variable contained in ' +
551 'structure in compute statement for optimization issue ')
552 gApplications.add_argument('--buildModi', default=False, action='store_true',
553 help='Builds the corresponding modi_ file')
554
555
557 """
558 Updates an argparse parser with openACC arguments
559 """
560 gOpenACC = parser.add_argument_group('OpenACC')
561 gOpenACC.add_argument('--addACCData', default=False, action='store_true',
562 help='Add !$acc data present and !$acc end data directives')
563 gOpenACC.add_argument('--addACCRoutineSeq', default=False, action='store_true',
564 help='Add "!$acc routine seq" to routines under stopScopes')
565 gOpenACC.add_argument('--craybyPassDOCONCURRENT', default=False, action='store_true',
566 help='remove acc loop independant collapse for BR_ fonctions and ' +
567 'mnh_undef(OPENACC) macro' +
568 ' use DO CONCURRENT with mnh_undef(LOOP)')
569 gOpenACC.add_argument('--removeACC', default=False, action='store_true',
570 help='remove all ACC directives')
571 gOpenACC.add_argument('--removebyPassDOCONCURRENT', default=False, action='store_true',
572 help='remove macro !$mnh_(un)def(OPENACC) and !$mnh_(un)def(LOOP) ' +
573 'directives')
574 gOpenACC.add_argument('--buildACCTypeHelpers', default=False, action='store_true',
575 help='build module files containing helpers to copy user ' +
576 'type structures')
577
578
580 """
581 Updates an argparse parser with checks arguments
582 """
583
584 gChecks = parser.add_argument_group('Check options')
585 gChecks.add_argument('--checkIMPLICIT', choices={'Warn', 'Err'}, default=None,
586 help='Send a warning or raise an error if the "IMPLICIT NONE" ' +
587 'is missing')
588 gChecks.add_argument('--checkINTENT', choices={'Warn', 'Err'}, default=None,
589 help='Send a warning or raise an error if the "INTENT" ' +
590 'attribute is missing for a dummy argument')
591 gChecks.add_argument('--checkOpInCall', choices={'Warn', 'Err'}, default=None,
592 help='Send a warning or raise an error if a call argument is an '
593 'operation.')
594
595
597 """
598 Updates an argparse parser with statements arguments
599 """
600
601 gStatement = parser.add_argument_group('Statements options')
602 gStatement.add_argument('--removeCall', action='append',
603 help="Call to remove from the source code. The argument " +
604 "is the subprogram name")
605 gStatement.add_argument('--removePrints', default=False, action='store_true',
606 help="Remove print statements from the source code.")
607 gStatement.add_argument('--inlineContainedSubroutines', default=False, action='store_true',
608 help='Inline containted subroutines in main routine')
609 gStatement.add_argument('--setFalseIfStmt', default=None,
610 help='Replace this value by .FALSE. in if statements')
611
612
614 """
615 Updates an argparse parser with misc arguments
616 """
617 gMisc = parser.add_argument_group('Miscellaneous')
618 gMisc.add_argument('--showScopes', default=False, action='store_true',
619 help='Show the different scopes found in the source code')
620 gMisc.add_argument('--empty', default=False, action='store_true',
621 help='Empty the different scopes')
622
623
624def updateParserTree(parser, withPlotCentralFile, treeIsOptional):
625 """
626 Updates an argparse parser with statements arguments
627 :param withPlotCentralFile: to add the --plotCentralFile argumen
628 :param treeIsOptional: is the --tree argument optional?
629 """
630 gTree = parser.add_argument_group('Tree')
631 gTree.add_argument('--tree', default=None, action='append', required=not treeIsOptional,
632 help='Directories where source code must be searched for')
633 gTree.add_argument('--descTree', default=None, required=not treeIsOptional,
634 help='File to write and/or read the description of the tree.')
635 if withPlotCentralFile:
636 gTree.add_argument('--plotCentralFile', default=None, type=str,
637 help='Central file of the plot')
638 gTree.add_argument('--plotCompilTree', default=None,
639 help='File name for compilation dependency graph (.dot or image extension)')
640 gTree.add_argument('--plotExecTree', default=None,
641 help='File name for execution dependency graph (.dot or image extension)')
642 gTree.add_argument('--plotMaxUpper', default=None, type=int,
643 help='Maximum number of upper elements in the plot tree')
644 gTree.add_argument('--plotMaxLower', default=None, type=int,
645 help='Maximum number of lower elements in the plot tree')
646 gTree.add_argument('--stopScopes', default=None, type=str,
647 help='#-separated list of scopes ' +
648 'where the recursive inclusion of an argument variable ' +
649 'must stop (needed for some transformations).')
650
651
653 """
654 Updates an argparse parser with statements arguments
655 """
656 gCpp = parser.add_argument_group('Preprocessor')
657 gCpp.add_argument('--applyCPPifdef', nargs='*', action='append',
658 help="This option is followed by the list of defined or undefined " +
659 "CPP keys. " +
660 "All #ifdef and #ifndef concerning these keys are evaluated. " +
661 "Undefined keys are preceded by a percentage sign.")
662
663
664def applyTransfo(pft, arg, args, plotCentralFile):
665 """
666 Apply transformation on a PYFT instance
667 :param pft: PYFT instance
668 :param arg: argument to deal with
669 :param args: parsed argparsed arguments
670 :param plotCentralFile: central file for plots
671 """
672 simplify = {'simplify': args.simplify}
673 parserOptions = getParserOptions(args)
674 stopScopes = args.stopScopes.split('#') if args.stopScopes is not None else None
675
676 # File name manipulations
677 applyTransfoFileName(pft, arg)
678
679 # Variables
680 applyTransfoVariables(pft, arg, args, simplify, parserOptions, stopScopes)
681
682 # Applications
683 applyTransfoApplications(pft, arg, args, simplify, parserOptions, stopScopes)
684
685 # OpenACC
686 applyTransfoOpenACC(pft, arg, args, stopScopes)
687
688 # Cosmetics
689 applyTransfoCosmetics(pft, arg, args)
690
691 # Checks
692 applyTransfoChecks(pft, arg, args)
693
694 # Statements
695 applyTransfoStatements(pft, arg, args, simplify)
696
697 # Misc
698 applyTransfoMisc(pft, arg, args, simplify)
699
700 # Tree
701 applyTransfoTree(pft, arg, args, plotCentralFile)
702
703 # Preprocessor
704 applyTransfoPreprocessor(pft, arg, args)
705
706
708 """
709 Apply file name transformations on a PYFT instance
710 :param pft: PYFT instance
711 :param arg: argument to deal with
712 :param args: parsed argparsed arguments
713 """
714
715 # File name manipulations
716 if arg == '--renamefF':
717 pft.renameUpper()
718 elif arg == '--renameFf':
719 pft.renameLower()
720
721
722def applyTransfoVariables(pft, arg, args, simplify, parserOptions, stopScopes):
723 """
724 Apply variables transformations on a PYFT instance
725 :param pft: PYFT instance
726 :param arg: argument to deal with
727 :param args: parsed argparsed arguments
728 :param simplify: kwargs to simplify
729 :param parserOptions: fxtran parser options
730 :param stopScopes: upper limit in call tree for some transformations
731 """
732 if arg == '--showVariables':
733 pft.varList.showVarList()
734 elif arg == '--attachArraySpecToEntity':
735 pft.attachArraySpecToEntity()
736 elif arg == '--removeVariable':
737 pft.removeVar(args.removeVariable, **simplify)
738 elif arg == '--addVariable':
739 pft.addVar([[v[0], v[1], v[2], (int(v[3]) if isint(v[3]) else None)]
740 for v in args.addVariable])
741 elif arg == '--addModuleVariable':
742 pft.addModuleVar([[v[0], v[1], v[2]] for v in args.addModuleVariable])
743 elif arg == '--showUnusedVariables':
744 pft.showUnusedVar()
745 elif arg == '--removeUnusedLocalVariables':
746 pft.removeUnusedLocalVar(
747 [item.strip() for item in args.removeUnusedLocalVariables.split(',')]
748 if args.removeUnusedLocalVariables != 'NONE' else None, **simplify)
749 elif arg == '--removePHYEXUnusedLocalVariables':
750 pft.removePHYEXUnusedLocalVar(
751 [item.strip() for item in args.removePHYEXUnusedLocalVariables.split(',')]
752 if args.removePHYEXUnusedLocalVariables != 'NONE' else None, **simplify)
753 elif arg == '--addExplicitArrayBounds':
754 pft.addExplicitArrayBounds()
755 elif arg == '--addArrayParentheses':
756 pft.addArrayParentheses()
757 elif arg == '--modifyAutomaticArrays':
758 pft.modifyAutomaticArrays(*(args.modifyAutomaticArrays.split('#')))
759 elif arg == '--replaceAutomaticWithAllocatable':
760 pft.modifyAutomaticArrays(
761 "{type}, DIMENSION({doubledotshape}), ALLOCATABLE :: {name}",
762 "ALLOCATE({name}({shape}))", "DEALLOCATE({name})")
763 elif arg == '--addArgInTree':
764 for varName, declStmt, pos in args.addArgInTree:
765 pft.addArgInTree(varName, declStmt, int(pos), stopScopes,
766 parser=args.parser,
767 parserOptions=parserOptions,
768 wrapH=args.wrapH)
769
770
771def applyTransfoApplications(pft, arg, args, simplify, parserOptions, stopScopes):
772 """
773 Apply applications transformations on a PYFT instance
774 :param pft: PYFT instance
775 :param arg: argument to deal with
776 :param args: parsed argparsed arguments
777 :param simplify: kwargs to simplify
778 :param parserOptions: fxtran parser options
779 :param stopScopes: upper limit in call tree for some transformations
780 """
781 if arg == '--addStack':
782 pft.addStack(args.addStack, stopScopes,
783 parser=args.parser, parserOptions=parserOptions,
784 wrapH=args.wrapH)
785 elif arg == '--deleteDrHook':
786 pft.deleteDrHook(**simplify)
787 elif arg == '--addDrHook':
788 pft.addDrHook()
789 elif arg == '--deleteBudgetDDH':
790 pft.deleteBudgetDDH(**simplify)
791 elif arg == '--deleteRoutineCallsMesoNHGPU':
792 pft.deleteRoutineCallsMesoNHGPU(**simplify)
793 elif arg == '--deleteNonColumnCallsPHYEX':
794 pft.deleteNonColumnCallsPHYEX(**simplify)
795 elif arg == '--addMPPDB_CHECKS':
796 pft.addMPPDB_CHECKS()
797 elif arg == '--addPrints':
798 pft.addMPPDB_CHECKS(printsMode=True)
799 # mnhExpand must be before inlineContainedSubroutines as inlineContainedSubroutines
800 # can change variable names used by mnh_expand directives
801 assert not (args.mnhExpand and args.mnhExpandConcurrent), \
802 "Only one of --mnhExpand and --mnhExpandConcurrent"
803 if arg == '--mnhExpand':
804 pft.removeArraySyntax(everywhere=False, addAccIndependentCollapse=False)
805 elif arg == '--mnhExpandConcurrent':
806 pft.removeArraySyntax(concurrent=True, everywhere=False)
807 elif arg == '--inlineContainedSubroutines':
808 pft.inlineContainedSubroutines(**simplify)
809 elif arg == '--inlineContainedSubroutinesPHYEX':
810 pft.inlineContainedSubroutinesPHYEX(**simplify)
811 elif arg == '--expandAllArrays':
812 pft.removeArraySyntax()
813 elif arg == '--expandAllArraysConcurrent':
814 pft.removeArraySyntax(concurrent=True)
815 elif arg == '--expandAllArraysPHYEX':
816 pft.expandAllArraysPHYEX()
817 elif arg == '--expandAllArraysPHYEXConcurrent':
818 pft.expandAllArraysPHYEX(concurrent=True)
819 elif arg == '--removeIJDim':
820 pft.removeIJDim(stopScopes,
821 parser=args.parser, parserOptions=parserOptions,
822 wrapH=args.wrapH, **simplify)
823 elif arg == '--shumanFUNCtoCALL':
824 pft.shumanFUNCtoCALL()
825 elif arg == '--buildACCTypeHelpers':
826 pft.buildACCTypeHelpers()
827 elif arg == '--mathFunctoBRFunc':
828 pft.mathFunctoBRFunc()
829 elif arg == '--convertTypesInCompute':
830 pft.convertTypesInCompute()
831 elif arg == '--buildModi':
832 pft.buildModi()
833 elif arg == '--splitModuleRoutineFile':
834 pft.splitModuleRoutineFile()
835
836
837def applyTransfoOpenACC(pft, arg, args, stopScopes): # pylint: disable=unused-argument
838 """
839 Apply openACC transformations on a PYFT instance
840 :param pft: PYFT instance
841 :param arg: argument to deal with
842 :param args: parsed argparsed arguments
843 :param stopScopes: upper limit in call tree for some transformations
844 """
845 if arg == '--addACCData':
846 pft.addACCData()
847 elif arg == '--craybyPassDOCONCURRENT':
848 pft.craybyPassDOCONCURRENT()
849 elif arg == '--removebyPassDOCONCURRENT':
850 pft.removebyPassDOCONCURRENT()
851 elif arg == '--addACCRoutineSeq':
852 pft.addACCRoutineSeq(stopScopes)
853 elif arg == '--removeACC':
854 pft.removeACC()
855
856
857def applyTransfoCosmetics(pft, arg, args):
858 """
859 Apply cosmetics transformations on a PYFT instance
860 :param pft: PYFT instance
861 :param arg: argument to deal with
862 :param args: parsed argparsed arguments
863 """
864 if arg == '--upperCase':
865 pft.upperCase()
866 elif arg == '--lowerCase':
867 pft.lowerCase()
868 elif arg == '--changeIfStatementsInIfConstructs':
869 pft.changeIfStatementsInIfConstructs()
870 elif arg == '--indent':
871 pft.indent()
872 elif arg == '--removeIndent':
873 pft.indent(indentProgramunit=0, indentBranch=0)
874 elif arg == '--removeEmptyLines':
875 pft.removeEmptyLines()
876 elif arg == '--removeComments':
877 pft.removeComments()
878 elif arg == '--updateSpaces':
879 pft.updateSpaces()
880 elif arg in ARG_UPDATE_CNT:
881 pft.updateContinuation(align=args.alignContinuation,
882 addBegin=args.addBeginContinuation,
883 removeBegin=args.removeBeginContinuation,
884 removeALL=args.removeALLContinuation)
885 elif arg == '--prettify':
886 pft.indent()
887 pft.upperCase()
888 pft.removeEmptyLines()
889 pft.updateSpaces()
890 pft.updateContinuation()
891 elif arg == '--minify':
892 pft.indent(indentProgramunit=0, indentBranch=0)
893 pft.upperCase()
894 pft.removeComments()
895 pft.removeEmptyLines()
896 pft.updateSpaces()
897 pft.updateContinuation(align=False, removeALL=True, addBegin=False)
898 elif arg == '--removeEmptyCONTAINS':
899 pft.removeEmptyCONTAINS()
900
901
902def applyTransfoChecks(pft, arg, args):
903 """
904 Apply checks transformations on a PYFT instance
905 :param pft: PYFT instance
906 :param arg: argument to deal with
907 :param args: parsed argparsed arguments
908 """
909 if arg == '--checkIMPLICIT':
910 pft.checkImplicitNone(args.checkIMPLICIT == 'Err')
911 elif arg == '--checkINTENT':
912 pft.checkIntent(args.checkINTENT == 'Err')
913 elif arg == '--checkOpInCall':
914 pft.checkOpInCall(args.checkOpInCall == 'Err')
915
916
917def applyTransfoStatements(pft, arg, args, simplify):
918 """
919 Apply statements transformations on a PYFT instance
920 :param pft: PYFT instance
921 :param arg: argument to deal with
922 :param args: parsed argparsed arguments
923 :param simplify: kwargs to simplify
924 """
925 if arg == '--removeCall':
926 for rc in args.removeCall:
927 pft.removeCall(rc, **simplify)
928 elif arg == '--removePrints':
929 pft.removePrints(**simplify)
930 elif arg == '--setFalseIfStmt':
931 pft.setFalseIfStmt(args.setFalseIfStmt, **simplify)
932
933
934def applyTransfoMisc(pft, arg, args, simplify): # pylint: disable=unused-argument
935 """
936 Apply misc transformations on a PYFT instance
937 :param pft: PYFT instance
938 :param arg: argument to deal with
939 :param args: parsed argparsed arguments
940 :param simplify: kwargs to simplify
941 """
942 if arg == '--showScopes':
943 pft.showScopesList()
944 elif arg == '--empty':
945 pft.empty(**simplify)
946
947
948def applyTransfoTree(pft, arg, args, plotCentralFile):
949 """
950 Apply tree transformations on a PYFT instance
951 :param pft: PYFT instance
952 :param arg: argument to deal with
953 :param args: parsed argparsed arguments
954 :param plotCentralFile: central file for plots
955 """
956 if arg == '--plotCompilTree' and plotCentralFile is not None:
957 pft.tree.plotCompilTreeFromFile(plotCentralFile, args.plotCompilTree,
958 args.plotMaxUpper, args.plotMaxLower)
959 elif arg == '--plotExecTree' and plotCentralFile is not None:
960 pft.tree.plotExecTreeFromFile(plotCentralFile, args.plotExecTree,
961 args.plotMaxUpper, args.plotMaxLower)
962
963
964def applyTransfoPreprocessor(pft, arg, args):
965 """
966 Apply preprocessor transformations on a PYFT instance
967 :param pft: PYFT instance
968 :param arg: argument to deal with
969 :param args: parsed argparsed arguments
970 """
971 if arg == '--applyCPPifdef':
972 pft.applyCPPifdef([k for aList in args.applyCPPifdef for k in aList])
applyTransfoApplications(pft, arg, args, simplify, parserOptions, stopScopes)
Definition scripting.py:771
updateParserVariables(parser)
Definition scripting.py:375
applyTransfoStatements(pft, arg, args, simplify)
Definition scripting.py:917
applyTransfoTree(pft, arg, args, plotCentralFile)
Definition scripting.py:948
applyTransfoPreprocessor(pft, arg, args)
Definition scripting.py:964
updateParserCosmetics(parser)
Definition scripting.py:448
applyTransfoVariables(pft, arg, args, simplify, parserOptions, stopScopes)
Definition scripting.py:722
updateParserInputsOutputs(parser, withInput, withOutput, withXml)
Definition scripting.py:336
updateParserApplications(parser)
Definition scripting.py:488
updateParserFxtran(parser)
Definition scripting.py:361
updateParserChecks(parser)
Definition scripting.py:579
updateParserOpenACC(parser)
Definition scripting.py:556
updateParserPreprocessor(parser)
Definition scripting.py:652
applyTransfoOpenACC(pft, arg, args, stopScopes)
Definition scripting.py:837
updateParserStatements(parser)
Definition scripting.py:596
applyTransfoChecks(pft, arg, args)
Definition scripting.py:902
applyTransfo(pft, arg, args, plotCentralFile)
Definition scripting.py:664
getDescTree(args, cls=Tree)
Definition scripting.py:228
applyTransfoMisc(pft, arg, args, simplify)
Definition scripting.py:934
updateParser(parser, withInput, withOutput, withXml, withPlotCentralFile, treeIsOptional, nbPar, restrictScope)
Definition scripting.py:246
applyTransfoCosmetics(pft, arg, args)
Definition scripting.py:857
applyTransfoFileName(pft, arg)
Definition scripting.py:707
updateParserTree(parser, withPlotCentralFile, treeIsOptional)
Definition scripting.py:624
updateParserMisc(parser)
Definition scripting.py:613