File: Synopsis/Processors/Comments/Filter.py
  1#
  2# Copyright (C) 2005 Stefan Seefeld
  3# All rights reserved.
  4# Licensed to the public under the terms of the GNU LGPL (>= 2),
  5# see the file COPYING for details.
  6#
  7
  8from Synopsis.Processor import Processor
  9from Synopsis import ASG
 10import re
 11
 12class Filter(Processor, ASG.Visitor):
 13    """Base class for comment filters."""
 14
 15    def process(self, ir, **kwds):
 16
 17        self.set_parameters(kwds)
 18
 19        self.ir = self.merge_input(ir)
 20
 21        for sf in self.ir.files.values():
 22            self.visit_sourcefile(sf)
 23
 24        for d in ir.asg.declarations:
 25            d.accept(self)
 26
 27        return self.output_and_return_ir()
 28
 29
 30    def visit_declaration(self, decl):
 31
 32        comments = decl.annotations.get('comments', [])
 33        comments[:] = [c is not None and self.filter_comment(c) or None
 34                       for c in comments]
 35
 36    visit_builtin = visit_declaration
 37    visit_sourcefile = visit_declaration
 38
 39    def filter_comment(self, comment):
 40        """Filter comment."""
 41
 42        return comment
 43
 44
 45class CFilter(Filter):
 46    """A class that filters C-style comments."""
 47
 48    comment = r'/[\*]+[ \t]*(?P<text>.*)(?P<lines>(\n[ \t]*.*)*?)(\n[ \t]*)?[\*]+/'
 49    # Match lines with and without asterisk.
 50    # Preserve space after asterisk so empty lines are formatted correctly.
 51    line = r'\n[ \t]*([ \t]*[\*]+(?=[ \t\n]))*(?P<text>.*)'
 52
 53    def __init__(self, **kwds):
 54        """Compiles the regular expressions"""
 55
 56        Filter.__init__(self, **kwds)
 57        self.comment = re.compile(CFilter.comment)
 58        self.line = re.compile(CFilter.line)
 59
 60    def filter_comment(self, comment):
 61        """Finds comments in the C format. The format is  /* ... */.
 62        It has to cater for all five line forms: "/* ...", " * ...", " ...",
 63        " */" and the one-line "/* ... */".
 64        """
 65
 66        text = []
 67        mo = self.comment.search(comment)
 68        while mo:
 69            text.append(mo.group('text'))
 70            lines = mo.group('lines')
 71            if lines:
 72                mol = self.line.search(lines)
 73                while mol:
 74                    text.append(mol.group('text'))
 75                    mol = self.line.search(lines, mol.end())
 76            mo = self.comment.search(comment, mo.end())
 77        return '\n'.join(text)
 78
 79
 80class SSFilter(Filter):
 81    """A class that selects only // comments."""
 82
 83    ss = r'^[ \t]*// ?(.*)$'
 84
 85    def __init__(self, **kwds):
 86        "Compiles the regular expressions"
 87
 88        Filter.__init__(self, **kwds)
 89        self.ss = re.compile(SSFilter.ss, re.M)
 90
 91
 92    def filter_comment(self, comment):
 93        """"""
 94
 95        return '\n'.join(self.ss.findall(comment))
 96
 97
 98class SSDFilter(Filter):
 99    """A class that selects only //. comments."""
100
101    ssd = r'^[ \t]*//\. ?(.*)$'
102
103    def __init__(self, **kwds):
104        "Compiles the regular expressions"
105
106        Filter.__init__(self, **kwds)
107        self.ssd = re.compile(SSDFilter.ssd, re.M)
108
109
110    def filter_comment(self, comment):
111        """"""
112
113        return '\n'.join(self.ssd.findall(comment))
114
115
116class SSSFilter(Filter):
117    """A class that selects only /// comments."""
118
119    sss = r'^[ \t]*/// ?(.*)$'
120
121    def __init__(self, **kwds):
122        "Compiles the regular expressions"
123
124        Filter.__init__(self, **kwds)
125        self.sss = re.compile(SSSFilter.sss, re.M)
126
127
128    def filter_comment(self, comment):
129        """"""
130
131        return '\n'.join(self.sss.findall(comment))
132
133
134class QtFilter(Filter):
135    """A class that finds Qt style comments. These have two styles: //! ...
136    and /*! ... */. The first means "brief comment" and there must only be
137    one. The second type is the detailed comment."""
138
139    brief = r"[ \t]*//!(.*)"
140    detail = r"[ \t]*/\*!(.*)\*/[ \t\n]*"
141
142    def __init__(self, **kwds):
143        "Compiles the regular expressions"
144
145        Filter.__init__(self, **kwds)
146        self.brief = re.compile(QtFilter.brief)
147        self.detail = re.compile(QtFilter.detail, re.S)
148
149
150    def filter_comment(self, comment):
151        "Matches either brief or detailed comments."
152
153        mo = self.brief.match(comment)
154        if mo:
155            return mo.group(1)
156        else:
157            mo = self.detail.match(comment)
158            if mo:
159                return mo.group(1)
160        return ''
161
162
163class JavaFilter(Filter):
164    """A class that selects java /** style comments"""
165
166    java = r'/\*\*[ \t]*(?P<text>.*)(?P<lines>(\n[ \t]*\*.*)*?)(\n[ \t]*)?\*/'
167    line = r'\n[ \t]*\*[ \t]*(?P<text>.*)'
168
169
170    def __init__(self):
171        "Compiles the regular expressions"
172
173        self.java = re.compile(JavaFilter.java)
174        self.line = re.compile(JavaFilter.line)
175
176
177    def filter_comment(self, comment):
178      """Finds comments in the java format. The format is  /** ... */, and
179      it has to cater for all four line forms: "/** ...", " * ...", " */" and
180      the one-line "/** ... */".
181      """
182
183      text_list = []
184      mo = self.java.search(comment)
185      while mo:
186         text_list.append(mo.group('text'))
187         lines = mo.group('lines')
188         if lines:
189            mol = self.line.search(lines)
190            while mol:
191               text_list.append(mol.group('text'))
192               mol = self.line.search(lines, mol.end())
193         mo = self.java.search(comment, mo.end())
194      return '\n'.join(text_list)
195
196