summaryrefslogtreecommitdiff
path: root/contrib/filter_params.py
blob: a82a8d5728cdb3b282ec80e2c5fb991c1de19702 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/python
"""
Filters out some of the #defines used throughout the GCC sources:
- GTY(()) marks declarations for gengtype.c
- PARAMS(()) is used for K&R compatibility. See ansidecl.h.

When passed one or more filenames, acts on those files and prints the
results to stdout.

When run without a filename, runs a unit-testing suite.
"""
import re
import sys
import unittest

# Optional whitespace
OPT_WS = '\s*'

def filter_src(text):
    """
    str -> str.  We operate on the whole of the source file at once
    (rather than individual lines) so that we can have multiline
    regexes.
    """

    # Convert C comments from GNU coding convention of:
    #    /* FIRST_LINE
    #       NEXT_LINE
    #       FINAL_LINE.  */
    # to:
    #    /** @verbatim FIRST_LINE
    #       NEXT_LINE
    #       FINAL_LINE.  @endverbatim */
    # so that doxygen will parse them.
    #
    # Only comments that begin on the left-most column are converted.
    #
    text = re.sub(r'^/\*\* ',
                  r'/** @verbatim ',
                  text,
                  flags=re.MULTILINE)
    text = re.sub(r'^/\* ',
                  r'/** @verbatim ',
                  text,
                  flags=re.MULTILINE)
    text = re.sub(r'\*/',
                  r' @endverbatim */',
                  text)

    # Remove GTY markings (potentially multiline ones):
    text = re.sub('GTY' + OPT_WS + r'\(\(.*?\)\)\s+',
                  '',
                  text,
                  flags=(re.MULTILINE|re.DOTALL))

    # Strip out 'ATTRIBUTE_UNUSED'
    text = re.sub('\sATTRIBUTE_UNUSED',
                  '',
                  text)

    # PARAMS(()) is used for K&R compatibility. See ansidecl.h.
    text = re.sub('PARAMS' + OPT_WS + r'\(\((.*?)\)\)',
                  r'(\1)',
                  text)

    # Replace 'ENUM_BITFIELD(enum_name)' with 'enum enum_name'.
    text = re.sub('ENUM_BITFIELD\s*\(([^\)]*)\)',
                  r'enum \1',
                  text)

    return text

class FilteringTests(unittest.TestCase):
    '''
    Unit tests for filter_src.
    '''
    def assert_filters_to(self, src_input, expected_result):
        # assertMultiLineEqual was added to unittest in 2.7/3.1
        if hasattr(self, 'assertMultiLineEqual'):
            assertion = self.assertMultiLineEqual
        else:
            assertion = self.assertEqual
        assertion(expected_result, filter_src(src_input))

    def test_comment_example(self):
        self.assert_filters_to(
            ('/* FIRST_LINE\n'
             '   NEXT_LINE\n'
             '   FINAL_LINE.  */\n'),
            ('/** @verbatim FIRST_LINE\n'
             '   NEXT_LINE\n'
             '   FINAL_LINE.   @endverbatim */\n'))

    def test_comment_example_gengtype(self):
        self.assert_filters_to(
            ('/** Allocate and initialize an input buffer state.\n'
             ' * @param file A readable stream.\n'
             ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n'
             ' * \n'
             ' * @return the allocated buffer state.\n'
             ' */'),
            ('/** @verbatim Allocate and initialize an input buffer state.\n'
             ' * @param file A readable stream.\n'
             ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n'
             ' * \n'
             ' * @return the allocated buffer state.\n'
             '  @endverbatim */'))

    def test_oneliner_comment(self):
        self.assert_filters_to(
            '/* Returns the string representing CLASS.  */\n',
            ('/** @verbatim Returns the string representing CLASS.   @endverbatim */\n'))

    def test_multiline_comment(self):
        self.assert_filters_to(
            ('/* The thread-local storage model associated with a given VAR_DECL\n'
             "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n"
             "   to it, so it's here.  */\n"),
            ('/** @verbatim The thread-local storage model associated with a given VAR_DECL\n'
             "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n"
             "   to it, so it's here.   @endverbatim */\n"))

    def test_GTY(self):
        self.assert_filters_to(
            ('typedef struct GTY(()) alias_pair {\n'
             '  tree decl;\n'
             '  tree target;\n'
             '} alias_pair;\n'),
            ('typedef struct alias_pair {\n'
             '  tree decl;\n'
             '  tree target;\n'
             '} alias_pair;\n'))

    def test_multiline_GTY(self):
        # Ensure that a multiline GTY is filtered out.
        self.assert_filters_to(
            ('class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),\n'
             '\t   chain_next ("%h.next"), chain_prev ("%h.previous")))\n'
             '  symtab_node_base\n'
             '{\n'),
            ('class symtab_node_base\n'
             '{\n'))

    def test_ATTRIBUTE_UNUSED(self):
        # Ensure that ATTRIBUTE_UNUSED is filtered out.
        self.assert_filters_to(
            ('static void\n'
             'record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED)\n'
             '{\n'),
            ('static void\n'
             'record_set (rtx dest, const_rtx set, void *data)\n'
             '{\n'))

    def test_PARAMS(self):
        self.assert_filters_to(
            'char *strcpy PARAMS ((char *dest, char *source));\n',
            'char *strcpy (char *dest, char *source);\n')

    def test_ENUM_BITFIELD(self):
        self.assert_filters_to(
            '  ENUM_BITFIELD (sym_intent) intent:2;\n',
            '  enum sym_intent intent:2;\n')

def act_on_files(argv):
    for filename in argv[1:]:
        with open(filename) as f:
            text = f.read()
            print(filter_src(text))

if __name__ == '__main__':
    if len(sys.argv) > 1:
        act_on_files(sys.argv)
    else:
        unittest.main()