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