1#!/usr/bin/python
2"""
3Filters out some of the #defines used throughout the GCC sources:
4- GTY(()) marks declarations for gengtype.c
5- PARAMS(()) is used for K&R compatibility. See ansidecl.h.
6
7When passed one or more filenames, acts on those files and prints the
8results to stdout.
9
10When run without a filename, runs a unit-testing suite.
11"""
12import re
13import sys
14import unittest
15
16# Optional whitespace
17OPT_WS = '\s*'
18
19def filter_src(text):
20    """
21    str -> str.  We operate on the whole of the source file at once
22    (rather than individual lines) so that we can have multiline
23    regexes.
24    """
25
26    # Convert C comments from GNU coding convention of:
27    #    /* FIRST_LINE
28    #       NEXT_LINE
29    #       FINAL_LINE.  */
30    # to:
31    #    /** @verbatim FIRST_LINE
32    #       NEXT_LINE
33    #       FINAL_LINE.  @endverbatim */
34    # so that doxygen will parse them.
35    #
36    # Only comments that begin on the left-most column are converted.
37    #
38    text = re.sub(r'^/\*\* ',
39                  r'/** @verbatim ',
40                  text,
41                  flags=re.MULTILINE)
42    text = re.sub(r'^/\* ',
43                  r'/** @verbatim ',
44                  text,
45                  flags=re.MULTILINE)
46    text = re.sub(r'\*/',
47                  r' @endverbatim */',
48                  text)
49
50    # Remove GTY markings (potentially multiline ones):
51    text = re.sub('GTY' + OPT_WS + r'\(\(.*?\)\)\s+',
52                  '',
53                  text,
54                  flags=(re.MULTILINE|re.DOTALL))
55
56    # Strip out 'ATTRIBUTE_UNUSED'
57    text = re.sub('\sATTRIBUTE_UNUSED',
58                  '',
59                  text)
60
61    # PARAMS(()) is used for K&R compatibility. See ansidecl.h.
62    text = re.sub('PARAMS' + OPT_WS + r'\(\((.*?)\)\)',
63                  r'(\1)',
64                  text)
65
66    # Replace 'ENUM_BITFIELD(enum_name)' with 'enum enum_name'.
67    text = re.sub('ENUM_BITFIELD\s*\(([^\)]*)\)',
68                  r'enum \1',
69                  text)
70
71    return text
72
73class FilteringTests(unittest.TestCase):
74    '''
75    Unit tests for filter_src.
76    '''
77    def assert_filters_to(self, src_input, expected_result):
78        # assertMultiLineEqual was added to unittest in 2.7/3.1
79        if hasattr(self, 'assertMultiLineEqual'):
80            assertion = self.assertMultiLineEqual
81        else:
82            assertion = self.assertEqual
83        assertion(expected_result, filter_src(src_input))
84
85    def test_comment_example(self):
86        self.assert_filters_to(
87            ('/* FIRST_LINE\n'
88             '   NEXT_LINE\n'
89             '   FINAL_LINE.  */\n'),
90            ('/** @verbatim FIRST_LINE\n'
91             '   NEXT_LINE\n'
92             '   FINAL_LINE.   @endverbatim */\n'))
93
94    def test_comment_example_gengtype(self):
95        self.assert_filters_to(
96            ('/** Allocate and initialize an input buffer state.\n'
97             ' * @param file A readable stream.\n'
98             ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n'
99             ' * \n'
100             ' * @return the allocated buffer state.\n'
101             ' */'),
102            ('/** @verbatim Allocate and initialize an input buffer state.\n'
103             ' * @param file A readable stream.\n'
104             ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n'
105             ' * \n'
106             ' * @return the allocated buffer state.\n'
107             '  @endverbatim */'))
108
109    def test_oneliner_comment(self):
110        self.assert_filters_to(
111            '/* Returns the string representing CLASS.  */\n',
112            ('/** @verbatim Returns the string representing CLASS.   @endverbatim */\n'))
113
114    def test_multiline_comment(self):
115        self.assert_filters_to(
116            ('/* The thread-local storage model associated with a given VAR_DECL\n'
117             "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n"
118             "   to it, so it's here.  */\n"),
119            ('/** @verbatim The thread-local storage model associated with a given VAR_DECL\n'
120             "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n"
121             "   to it, so it's here.   @endverbatim */\n"))
122
123    def test_GTY(self):
124        self.assert_filters_to(
125            ('typedef struct GTY(()) alias_pair {\n'
126             '  tree decl;\n'
127             '  tree target;\n'
128             '} alias_pair;\n'),
129            ('typedef struct alias_pair {\n'
130             '  tree decl;\n'
131             '  tree target;\n'
132             '} alias_pair;\n'))
133
134    def test_multiline_GTY(self):
135        # Ensure that a multiline GTY is filtered out.
136        self.assert_filters_to(
137            ('class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),\n'
138             '\t   chain_next ("%h.next"), chain_prev ("%h.previous")))\n'
139             '  symtab_node_base\n'
140             '{\n'),
141            ('class symtab_node_base\n'
142             '{\n'))
143
144    def test_ATTRIBUTE_UNUSED(self):
145        # Ensure that ATTRIBUTE_UNUSED is filtered out.
146        self.assert_filters_to(
147            ('static void\n'
148             'record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED)\n'
149             '{\n'),
150            ('static void\n'
151             'record_set (rtx dest, const_rtx set, void *data)\n'
152             '{\n'))
153
154    def test_PARAMS(self):
155        self.assert_filters_to(
156            'char *strcpy PARAMS ((char *dest, char *source));\n',
157            'char *strcpy (char *dest, char *source);\n')
158
159    def test_ENUM_BITFIELD(self):
160        self.assert_filters_to(
161            '  ENUM_BITFIELD (sym_intent) intent:2;\n',
162            '  enum sym_intent intent:2;\n')
163
164def act_on_files(argv):
165    for filename in argv[1:]:
166        with open(filename) as f:
167            text = f.read()
168            print(filter_src(text))
169
170if __name__ == '__main__':
171    if len(sys.argv) > 1:
172        act_on_files(sys.argv)
173    else:
174        unittest.main()
175