pp.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # Copyright Aleksey Gurtovoy 2001-2004
  2. #
  3. # Distributed under the Boost Software License, Version 1.0.
  4. # (See accompanying file LICENSE_1_0.txt or copy at
  5. # http://www.boost.org/LICENSE_1_0.txt)
  6. #
  7. # See http://www.boost.org/libs/mpl for documentation.
  8. # $Id$
  9. # $Date$
  10. # $Revision$
  11. import fileinput
  12. import os
  13. import re
  14. import string
  15. import sys
  16. if_else = lambda a,b,c:(a and [b] or [c])[0]
  17. max_len = 79
  18. ident = 4
  19. def nearest_ident_pos(text):
  20. return (len(text)/ident) * ident
  21. def block_format(limits, text, first_sep=' ', sep=',', need_last_ident=1 ):
  22. if sep == ',' and string.find( text, '<' ) != -1:
  23. sep = '%s ' % sep
  24. words = string.split(
  25. string.join( string.split( text ), ' ' )
  26. , sep
  27. )
  28. s = ' ' * limits[0]
  29. max_len = limits[1]
  30. return '%s\n%s' \
  31. % (
  32. reduce(
  33. lambda t,w,max_len=max_len,s=s,sep=sep:
  34. if_else(t[1] + len(w) < max_len
  35. , ('%s%s%s'% (t[0],t[2],w), t[1]+len(w)+len(t[2]), sep)
  36. , ('%s\n%s%s%s'% (t[0],s,sep,w), len(s)+len(w)+len(sep), sep)
  37. )
  38. , words
  39. , (s,len(s)+len(first_sep),first_sep)
  40. )[0]
  41. , if_else(need_last_ident,s,'')
  42. )
  43. def handle_args( match ):
  44. if re.compile('^\s*(typedef|struct|static)\s+.*?$').match(match.group(0)):
  45. return match.group(0)
  46. return '%s'\
  47. % block_format(
  48. (nearest_ident_pos(match.group(1)),max_len)
  49. , match.group(3)
  50. , match.group(2)
  51. , ','
  52. , 0
  53. )
  54. def handle_inline_args(match):
  55. if len(match.group(0)) < max_len:
  56. return match.group(0)
  57. if match.group(9) == None:
  58. return '%s%s<\n%s>\n'\
  59. % (
  60. match.group(1)
  61. , match.group(3)
  62. , block_format(
  63. (nearest_ident_pos(match.group(1))+ident,max_len)
  64. , match.group(4)
  65. )
  66. )
  67. return '%s%s<\n%s>\n%s%s'\
  68. % (
  69. match.group(1)
  70. , match.group(3)
  71. , block_format(
  72. (nearest_ident_pos(match.group(1))+ident,max_len-len(match.group(9)))
  73. , match.group(4)
  74. )
  75. , string.replace(match.group(1),',',' ')
  76. , match.group(9)
  77. )
  78. def handle_simple_list(match):
  79. if match.group(1) == 'template':
  80. return match.group(0)
  81. single_arg = re.compile('^\s*(\w|\d)+\s*$').match(match.group(2))
  82. return if_else(single_arg,'%s<%s>','%s< %s >') %\
  83. (
  84. match.group(1)
  85. , string.join(string.split(match.group(2)), '')
  86. )
  87. def handle_static(match):
  88. if len(match.group(0)) < max_len:
  89. return match.group(0)
  90. (first_sep,sep) = if_else(string.find(match.group(0),'+') == -1, (' ',' '),(' ','+'))
  91. return '%s%s\n%s%s' %\
  92. (
  93. match.group(1)
  94. , string.join(string.split(match.group(2)), ' ')
  95. , block_format(
  96. (nearest_ident_pos(match.group(1))+ident,max_len)
  97. , match.group(4)
  98. , first_sep
  99. , sep
  100. )
  101. , match.group(5)
  102. )
  103. def handle_typedefs(match):
  104. if string.count(match.group(2), ';') == 1:
  105. return match.group(0)
  106. join_sep = ';\n%s' % match.group(1)
  107. return '%s%s\n' \
  108. % (
  109. match.group(1)
  110. , string.join(map(string.strip, string.split(match.group(2), ';')), join_sep)
  111. )
  112. def fix_angle_brackets( match ):
  113. return ' '.join( ''.join( match.group(1).split( ' ' ) ) ) + match.group(3)
  114. class pretty:
  115. def __init__(self, name):
  116. self.output = open(name, "w")
  117. self.prev_line = ''
  118. self.re_copyright_start = re.compile( r'^// Copyright .*$' )
  119. self.re_copyright_end = re.compile( r'^// See .* for documentation.$' )
  120. self.reading_copyright = 0
  121. self.copyright = None
  122. self.re_header_name_comment = re.compile(
  123. r'^\s*//\s+\$[I]d:\s+(.*?%s\.hpp)\s+[^$]+[$]$'
  124. % os.path.splitext( name )[0]
  125. )
  126. self.header_was_written = 0
  127. self.re_junk = re.compile(r'^\s*(#|//[^/]|////).*$')
  128. self.re_c_comment_start = re.compile(r'^\s*/\*.*')
  129. self.re_c_comment_end = re.compile(r'^.*\*/\s*$')
  130. self.inside_c_comment = 0
  131. self.re_empty_line = re.compile(r'^\s*$')
  132. self.re_comma = re.compile(r'(\S+)\s*,\s*')
  133. self.re_assign = re.compile(r'(\S+[^<|^!|^>])\s*(=+)\s*(\S+)')
  134. self.re_marked_empty_comment = re.compile(r'^\s*//\s*$')
  135. self.re_typedef = re.compile(r'^\s+typedef\s+.*?;$')
  136. self.re_nsl = re.compile(r'^(\s+typedef\s+.*?;|\s*(private|public):\s*|\s*{\s*|\s*(\w|\d|,)+\s*)$')
  137. self.re_templ_decl = re.compile(r'^(\s*template\s*<\s*.*?|\s*(private|public):\s*)$')
  138. self.re_type_const = re.compile(r'(const)\s+((unsigned|signed)?(bool|char|short|int|long))')
  139. #self.re_templ_args = re.compile(r'^(\s*)(, | {2})((.*::.*?,?)+)\s*$')
  140. self.re_templ_args = re.compile(r'^(\s*)(, | {2})((\s*(\w+)(\s+|::)\w+\s*.*?,?)+)\s*$')
  141. self.re_inline_templ_args = re.compile(
  142. r'^(\s+(,|:\s+)?|struct\s+)(\w+)\s*<((\s*(typename\s+)?\w+\s*(=\s*.*|<(\s*\w+\s*,?)+>\s*)?,?)+)\s*>\s+((struct|class).*?)?$'
  143. )
  144. self.re_simple_list = re.compile(r'(\w+)\s*<((\w|,| |-)+)>')
  145. self.re_static_const = re.compile(r'(\s*)((BOOST_STATIC_CONSTANT\(\s*\w+,\s*|enum\s*\w*\s*{\s*)value\s*=)(.*?)([}|\)];)$')
  146. self.re_typedefs = re.compile(r'(\s*)((\s*typedef\s*.*?;)+)\s*$')
  147. self.re_fix_angle_brackets = re.compile( r'(>(\s*>)+)(,|\n$)' )
  148. self.re_closing_curly_brace = re.compile(r'^(}|struct\s+\w+);\s*$')
  149. self.re_namespace_scope_templ = re.compile(r'^template\s*<\s*$')
  150. self.re_namespace = re.compile(r'^\n?namespace\s+\w+\s*{\s*\n?$')
  151. def process(self, line):
  152. if self.reading_copyright:
  153. if not self.re_copyright_end.match( line ):
  154. self.copyright += line
  155. return
  156. self.reading_copyright = 0
  157. if not self.header_was_written and self.re_copyright_start.match( line ):
  158. self.copyright = line
  159. self.reading_copyright = 1
  160. return
  161. # searching for header line
  162. if not self.header_was_written:
  163. if self.re_header_name_comment.match( line ):
  164. self.header_was_written = 1
  165. match = self.re_header_name_comment.match( line )
  166. self.output.write( \
  167. '\n%s\n' \
  168. '// *Preprocessed* version of the main "%s" header\n' \
  169. '// -- DO NOT modify by hand!\n\n' \
  170. % ( self.copyright, match.group(1) )
  171. )
  172. return
  173. # skipping preprocessor directives, comments, etc.
  174. if self.re_junk.match(line):
  175. return
  176. if self.inside_c_comment or self.re_c_comment_start.match(line):
  177. self.inside_c_comment = not self.re_c_comment_end.match(line)
  178. return
  179. # restoring some empty lines
  180. if self.re_templ_decl.match(line) and self.re_typedef.match(self.prev_line) \
  181. or not self.re_empty_line.match(line) and self.re_closing_curly_brace.match(self.prev_line) \
  182. or not self.re_empty_line.match(self.prev_line) \
  183. and ( self.re_namespace_scope_templ.match(line) \
  184. or self.re_namespace.match(line) and not self.re_namespace.match(self.prev_line) \
  185. ):
  186. line = '\n%s' % line
  187. # removing excessive empty lines
  188. if self.re_empty_line.match(line):
  189. if self.re_empty_line.match(self.prev_line) or not self.header_was_written:
  190. return
  191. # skip empty line after typedef
  192. if self.re_nsl.match(self.prev_line):
  193. return
  194. # formatting
  195. line = self.re_comma.sub( r'\1, ', line )
  196. line = self.re_assign.sub( r'\1 \2 \3', line )
  197. line = self.re_marked_empty_comment.sub( r'\n', line )
  198. line = self.re_type_const.sub( r'\2 \1', line )
  199. line = self.re_templ_args.sub( handle_args, line )
  200. line = self.re_inline_templ_args.sub( handle_inline_args, line )
  201. line = self.re_simple_list.sub( handle_simple_list, line)
  202. line = self.re_static_const.sub( handle_static, line )
  203. line = self.re_typedefs.sub( handle_typedefs, line )
  204. line = self.re_fix_angle_brackets.sub( fix_angle_brackets, line )
  205. # write the output
  206. self.output.write(line)
  207. self.prev_line = line
  208. def main( src, dest ):
  209. p = pretty( os.path.basename( dest ) )
  210. for line in fileinput.input( src ):
  211. p.process(line)
  212. if __name__ == '__main__':
  213. main( sys.argv[1], sys.argv[2] )