BASIS  r3148
doxyfilter-perl.py
Go to the documentation of this file.
00001 #! /sbia/sbiasfw/external/python/epd/7.3.1/bin/python
00002 import sys; import os.path; __dir__ = os.path.dirname(os.path.realpath(__file__)); sys.path.insert(0, os.path.realpath(os.path.join(__dir__, 'python'))); sys.path.insert(0, os.path.realpath(os.path.join(__dir__, '.'))) # <-- added by BASIS
00003 ##############################################################################
00004 # @file  doxyfilter-perl.py
00005 # @brief Doxygen filter for Perl modules.
00006 #
00007 # Copyright (c) 2012 University of Pennsylvania. All rights reserved.<br />
00008 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00009 #
00010 # Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00011 #
00012 # @ingroup Tools
00013 ##############################################################################
00014 
00015 import sys
00016 import re
00017 
00018 if __name__ == "__main__":
00019     # parse arguments
00020     if len(sys.argv) != 2:
00021         sys.stderr.write("No file specified to process!\n")
00022         sys.exit(1)
00023     fileName = sys.argv[1]
00024     # open input file
00025     f = open(fileName, 'r')
00026     if not f:
00027         sys.stderr.write("Failed to open file " + fileName + " for reading!\n")
00028         sys.exit(1)
00029     # compile regular expressions
00030     reShaBang       = re.compile(r"#!\s*/usr/bin/env\s+perl$|#!\s*/usr/bin/perl$")
00031     reConstant      = re.compile(r"use\s+constant\s+(?P<name>\w+)(\s+.*|;)?$")
00032     reInclude       = re.compile(r"use\s+(?P<module>[a-zA-Z:]+)(\s+.*|;)?$")
00033     reFunctionStart = re.compile(r"sub\s*(?P<name1>\w+)\s*{?$")
00034     reFunctionEnd   = re.compile(r"}$")
00035     reCommentStart  = re.compile(r"##+(?P<comment>.*)$")
00036     reCommentLine   = re.compile(r"#+(?P<comment>.*)$")
00037     reParamDoc      = re.compile(r"[\@\\]param\s*(\[\s*(?P<inout>in|out|in\s*,\s*out|out\s*,\s*in)\s*\]|\s*)\s+(?P<type>[$%@]\$?)?(?P<param>\w+)")
00038     # parse line-by-line and output pseudo C++ code to stdout
00039     previousBlock = '' # name of previous code block
00040     currentBlock  = '' # name of current code block
00041     params        = []
00042     for line in f:
00043         line = line.strip()
00044         # skip sha-bang directive
00045         if reShaBang.match(line) is not None:
00046             sys.stdout.write("\n")
00047             continue
00048         # next comment line,
00049         if currentBlock == 'comment':
00050             m = reCommentLine.match(line)
00051             if m is not None:
00052                 comment = m.group('comment')
00053                 m = reParamDoc.search(line)
00054                 if m is not None:
00055                     inout   = m.group('inout')
00056                     argtype = m.group('type')
00057                     param   = m.group('param')
00058                     params.append([inout, argtype, param])
00059                     comment = comment.replace(argtype + param, param)
00060                 sys.stdout.write("///" + comment + "\n")
00061                 continue
00062             else:
00063                 previousBlock = currentBlock
00064                 currentBlock = ''
00065                 # continue processing of this (yet unhandled) line
00066         # inside function definition
00067         if currentBlock == 'function':
00068             m = reFunctionEnd.match(line)
00069             if m is not None:
00070                 previousBlock = currentBlock
00071                 currentBlock = ''
00072             sys.stdout.write("\n")
00073             continue
00074         # look for new comment block or block following a comment
00075         if currentBlock == '':
00076             # constant - before include match
00077             m = reConstant.match(line)
00078             if m is not None:
00079                 name = m.group('name')
00080                 sys.stdout.write("const " + name + ";\n")
00081                 continue
00082             # include
00083             m = reInclude.match(line)
00084             if m is not None:
00085                 module = m.group('module')
00086                 if module in ('strict', 'warnings', 'constant'):
00087                     sys.stdout.write('\n')
00088                 else:
00089                     module = module.replace('::', '/')
00090                     sys.stdout.write("#include \"" + module + ".pm\"\n")
00091                 continue
00092             # Doxygen comment
00093             m = reCommentStart.match(line)
00094             if m is not None:
00095                 comment = m.group('comment')
00096                 sys.stdout.write("///" + comment + "\n")
00097                 currentBlock = 'comment'
00098                 m = reParamDoc.search (line)
00099                 if m is not None:
00100                     param = m.group('param')
00101                     params.append(param)
00102                 continue
00103             # if previous block was a Doxygen comment process
00104             # supported following blocks such as variable setting
00105             # and function definition optionally only the one
00106             # inside the if-case of an if-else-clause
00107             if previousBlock == 'comment':
00108                 # function
00109                 m = reFunctionStart.match(line)
00110                 if m is not None:
00111                     name = m.group('name1')
00112                     if not name:
00113                         name = m.group('name2')
00114                     sys.stdout.write("sub " + name + "(")
00115                     for i in range(0, len(params)):
00116                         if i > 0:
00117                             sys.stdout.write(", ")
00118                         inout   = params[i][0]
00119                         argtype = params[i][1]
00120                         param   = params[i][2]
00121                         if inout:
00122                             if   'out' in inout and 'in' in inout: inout = 'inout'
00123                             elif 'out' in inout:                   inout = 'out'
00124                             else:                                  inout = 'in'
00125                         else: inout = 'in'
00126                         if argtype:
00127                             if   argtype == '$':  argtype = 'scalar'
00128                             elif argtype == '@':  argtype = 'array'
00129                             elif argtype == '%':  argtype = 'hash'
00130                             elif argtype == '$$': argtype = 'scalarref'
00131                             elif argtype == '@$': argtype = 'arrayref'
00132                             elif argtype == '%$': argtype = 'hashref'
00133                             else: argtype = None
00134                         if not argtype: argtype = inout
00135                         sys.stdout.write(' '.join([argtype, param]))
00136                     sys.stdout.write(");\n")
00137                     currentBlock = 'function'
00138                     params = []
00139                     continue
00140             # unhandled lines...
00141             if line != '':
00142                 if previousBlock == 'comment':
00143                     # prevent comments that are not associated with any
00144                     # processed block to be merged with subsequent comments
00145                     sys.stdout.write("class COMMENT_DUMPED_BY_DOXYGEN_FILTER;\n")
00146                 else:
00147                     sys.stdout.write("\n")
00148                 previousBlock = ''
00149             else:
00150                 sys.stdout.write("\n")
00151         else:
00152             sys.stdout.write("\n")
00153     # close input file
00154     f.close()
00155     # done
00156     sys.exit(0)