File: Synopsis/DeclarationSorter.py
  1#
  2# Copyright (C) 2007 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 Parametrized, Parameter
  9from Synopsis import ASG
 10
 11# The names of the access specifiers
 12_access_specs = {ASG.DEFAULT: '',
 13                 ASG.PUBLIC: 'Public ',
 14                 ASG.PROTECTED: 'Protected ',
 15                 ASG.PRIVATE: 'Private '}
 16
 17# The predefined order for section names
 18_section_order = ('Packages',
 19                  'Modules',
 20                  'Namespaces',
 21                  'Macros',
 22                  'Class templates',
 23                  'Classes',
 24                  'Interfaces',
 25                  'Typedefs',
 26                  'Structs',
 27                  'Enums',
 28                  'Unions',
 29                  'Member function templates',
 30                  'Member functions',
 31                  'Function templates',
 32                  'Functions')
 33
 34def _compare(a, b):
 35    """Compare two section names."""
 36
 37    ai, bi = 0, 0
 38    an, bn = a, b
 39    for i in range(1,4):
 40        access = _access_specs[i]
 41        len_access = len(access)
 42        is_a = (a[:len_access] == access)
 43        is_b = (b[:len_access] == access)
 44        if is_a:
 45            if not is_b: return -1 # a before b
 46            # Both matched
 47            an = a[len_access:]
 48            bn = b[len_access:]
 49            break
 50        if is_b:
 51            return 1 # b before a
 52        # Neither matched
 53    # Same access, sort by predefined order 
 54    for section in _section_order:
 55        if an == section: return -1 # a before b
 56        if bn == section: return 1 # b before a
 57    return 0
 58
 59
 60class DeclarationSorter(Parametrized, ASG.Visitor):
 61    """Sort declarations by type and accessibility."""
 62
 63    struct_as_class = Parameter(False, 'Fuse structs and classes into the same section.')
 64    group_as_section = Parameter(True, 'Map group to section, instead of keeping it as a single declaration.')
 65
 66    def __init__(self, declarations = None, **args):
 67
 68        super(DeclarationSorter, self).__init__(**args)
 69        self.__sections = {}
 70        self.__sorted_keys = []
 71        if not declarations: # This is a prototype
 72            return
 73        for d in declarations:
 74            d.accept(self)
 75        self.__sorted_keys = self.__sections.keys()
 76        self.__sorted_keys.sort(_compare)
 77
 78    def __iter__(self): return iter(self.__sorted_keys)
 79    def __getitem__(self, i): return self.__sections[i]
 80    def get(self, *args): return self.__sections.get(*args)
 81    def has_key(self, k): return self.__sections.haskey(k)
 82    def keys(self): return self.__sorted_keys
 83    def values(self): return self.__sections.values()
 84
 85    def _section_of(self, decl, name = None):
 86        """Generate a section name for the given declaration."""
 87
 88        section = name or decl.type.capitalize()
 89        if self.struct_as_class and section == 'Struct':
 90            section = 'Class'
 91        if section[-1] == 's': section += 'es'
 92        else: section += 's'
 93        if decl.accessibility != ASG.DEFAULT:
 94            section = _access_specs[decl.accessibility] + section
 95        return section
 96
 97
 98    def _add_declaration(self, decl, section):
 99        "Adds the given declaration with given name and section."
100
101        if section not in self.__sections:
102            self.__sections[section] = [decl]
103        else:
104            self.__sections[section].append(decl)
105
106
107    def visit_declaration(self, decl):
108        self._add_declaration(decl, self._section_of(decl))
109
110    def visit_builtin(self, decl): pass
111    def visit_macro(self, decl):
112        self._add_declaration(decl, self._section_of(decl, 'Macro'))
113    def visit_forward(self, decl):
114        if decl.template:
115            self.visit_class_template(decl)
116        else:
117            self.visit_declaration(decl)
118    def visit_group(self, group):
119        if self.group_as_section:
120            section = group.name[-1]
121            for d in group.declarations:
122                self._add_declaration(d, section)
123        else:
124            self.visit_declaration(group)
125    def visit_scope(self, decl):
126        self.visit_declaration(decl)
127    def visit_class_template(self, decl):
128        self._add_declaration(decl, self._section_of(decl, 'Class template'))
129    def visit_function(self, decl):
130        self.visit_declaration(decl)
131    def visit_function_template(self, decl):
132        self._add_declaration(decl, self._section_of(decl, 'Function template'))
133