Commits

Takayuki Shimizukawa  committed 46d91be Merge

Merged in jakobla/sphinx (pull request #263)

Rewrite of C++ domain (also fixes #1013, #1103)

  • Participants
  • Parent commits 3d6ac86, 347fc57

Comments (0)

Files changed (5)

File doc/domains.rst

 
 The C++ domain (name **cpp**) supports documenting C++ projects.
 
-The following directives are available:
+The following directives are available. All declarations can start with a visibility statement
+(``public``, ``private`` or ``protected``).
 
-.. rst:directive:: .. cpp:class:: signatures
-               .. cpp:function:: signatures
-               .. cpp:member:: signatures
-               .. cpp:type:: signatures
+.. rst:directive:: .. cpp:class:: class speicifer
 
-   Describe a C++ object.  Full signature specification is supported -- give the
-   signature as you would in the declaration.  Here some examples::
+   Describe a class/struct, possibly with specification of inheritance, e.g.,::
+   
+      .. cpp:class:: SomeName::SomeClass : public MyBase, MyOtherBase
+
+.. rst:directive:: .. cpp:function:: (member-)function prototype
+
+   Describe a function or member function, e.g.,::
 
       .. cpp:function:: bool namespaced::theclass::method(int arg1, std::string arg2)
 
          Describes a method with parameters and types.
 
-      .. cpp:function:: bool namespaced::theclass::method(arg1, arg2)
+      .. cpp:function:: bool namespaced::theclass::method(T1, T2)
 
-         Describes a method without types.
+         Describes a method with unnamed parameters.
 
       .. cpp:function:: const T &array<T>::operator[]() const
 
 
          Describe a constexpr function here.
 
-      .. cpp:member:: std::string theclass::name
+      .. cpp:function:: MyClass::MyClass(const MyClass&) = default
 
-      .. cpp:member:: std::string theclass::name[N][M]
+         Describe a copy constructor with default implementation.
 
-      .. cpp:type:: theclass::const_iterator
+.. rst:directive:: .. cpp:member:: variable or member declaration
 
-   Will be rendered like this:
-
-      .. cpp:function:: bool namespaced::theclass::method(int arg1, std::string arg2)
-
-         Describes a method with parameters and types.
-
-      .. cpp:function:: bool namespaced::theclass::method(arg1, arg2)
-
-         Describes a method without types.
-
-      .. cpp:function:: const T &array<T>::operator[]() const
-
-         Describes the constant indexing operator of a templated array.
-
-      .. cpp:function:: operator bool() const
-
-         Describe a casting operator here.
-
-      .. cpp:function:: constexpr void foo(std::string &bar[2]) noexcept
-
-         Describe a constexpr function here.
+   Describe a varible or member variable, e.g.,::
 
       .. cpp:member:: std::string theclass::name
 
       .. cpp:member:: std::string theclass::name[N][M]
 
+.. rst:directive:: .. cpp:type:: typedef-like declaration
+                   .. cpp:type:: name
+
+   Describe a type as in a typedef declaration, or the name of a type with unspecified type, e.g.,::
+
+      .. cpp:type:: std::vector<int> MyList
+
+         A typedef-like declaration of a type.
+
       .. cpp:type:: theclass::const_iterator
 
+         Declaration of a type alias with unspecified type.
+
 .. rst:directive:: .. cpp:namespace:: namespace
 
-   Select the current C++ namespace for the following objects.
+   Select the current namespace for the following objects. Note that the namespace
+   does not need to correspond to C++ namespaces, but can end in names of classes, e.g.,::
+
+      .. cpp:namespace:: Namespace1::Namespace2::SomeClass::AnInnerClass
+
+   All following objects will be defined as if their name were declared with the namespace
+   prepended. The following cross-references will be search for by both their specified name
+   and with the namespace prepended.
 
 
 .. _cpp-roles:
           cpp:member
           cpp:type
 
-   Reference a C++ object.  You can give the full signature (and need to, for
+   Reference a C++ object.  You can give the full specification (and need to, for
    overloaded functions.)
 
    .. note::
    specific overload.  Currently Sphinx will link to the first overloaded
    version of the method / function.
 
+.. admonition:: Note on Template Delcarations
+
+   The C++ domain currently does not support template classes/functions/aliases/variables
+   (e.g., ``template<typename T> MyClass``), only template instantiations
+   (e.g., ``MyClass<T>``).
+
 
 The Standard Domain
 -------------------

File sphinx/domains/c.py

File contents unchanged.

File sphinx/domains/cpp.py

 
     :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
     :license: BSD, see LICENSE for details.
+    
+    See http://www.nongnu.org/hcb/ for the grammar.
+    See http://mentorembedded.github.io/cxx-abi/abi.html#mangling for the inspiration for the id generation.
+    
+    common grammar things:
+           simple-declaration
+        -> attribute-specifier-seq[opt] decl-specifier-seq[opt] init-declarator-list[opt] ;
+        # Drop the semi-colon. For now: drop the attributes (TODO).
+        # Use at most 1 init-declerator.
+        -> decl-specifier-seq init-declerator
+        -> decl-specifier-seq declerator initializer
+        
+        decl-specifier ->
+              storage-class-specifier -> "static" (only for member_object and function_object)
+            | type-specifier -> trailing-type-specifier
+            | function-specifier -> "inline" | "virtual" | "explicit" (only for function_object)
+            | "friend" (only for function_object)
+            | "constexpr" (only for member_object and function_object)
+        trailing-type-specifier ->
+              simple-type-specifier
+            | elaborated-type-specifier
+            | typename-specifier
+            | cv-qualifier -> "const" | "volatile"
+        stricter grammar for decl-specifier-seq (with everything, each object uses a subset):
+            visibility storage-class-specifier function-specifier "friend" "constexpr" "volatile" "const" trailing-type-specifier
+            # where trailing-type-specifier can no be cv-qualifier
+        # Inside e.g., template paramters a strict subset is used (see type-specifier-seq)
+        trailing-type-specifier ->
+              simple-type-specifier ->
+                ::[opt] nested-name-specifier[opt] type-name
+              | ::[opt] nested-name-specifier "template" simple-template-id
+              | "char" | "bool" | ect.
+              | decltype-specifier
+            | elaborated-type-specifier ->
+                class-key attribute-specifier-seq[opt] ::[opt] nested-name-specifier[opt] identifier
+              | class-key ::[opt] nested-name-specifier[opt] template[opt] simple-template-id
+              | "enum" ::[opt] nested-name-specifier[opt] identifier
+            | typename-specifier ->
+                "typename" ::[opt] nested-name-specifier identifier
+              | "typename" ::[opt] nested-name-specifier template[opt] simple-template-id
+        class-key -> "class" | "struct" | "union"
+        type-name ->* identifier | simple-template-id
+        # ignoring attributes and decltype, and then some left-factoring
+        trailing-type-specifier ->
+            rest-of-trailing
+            ("class" | "struct" | "union" | "typename") rest-of-trailing
+            build-in -> "char" | "bool" | ect.
+            decltype-specifier
+        rest-of-trailing -> (with some simplification)
+            "::"[opt] list-of-elements-separated-by-::
+        element ->
+            "template"[opt] identifier ("<" template-argument-list ">")[opt]
+        template-argument-list ->
+              template-argument "..."[opt]
+            | template-argument-list "," template-argument "..."[opt]
+        template-argument ->
+              constant-expression
+            | type-specifier-seq abstract-declerator
+            | id-expression
+        
+        
+        declerator ->
+              ptr-declerator
+            | noptr-declarator parameters-and-qualifiers trailing-return-type (TODO: for now we don't support it)
+        ptr-declerator ->
+              noptr-declerator
+            | ptr-operator ptr-declarator
+        noptr-declerator ->
+              declarator-id attribute-specifier-seq[opt] ->
+                    "..."[opt] id-expression
+                  | rest-of-trailing
+            | noptr-declerator parameters-and-qualifiers
+            | noptr-declarator "[" constant-expression[opt] "]" attribute-specifier-seq[opt]
+            | "(" ptr-declarator ")"  # TODO: not implemented yet
+        # function_object must use a parameters-and-qualifiers, the others may use it (e.g., function poitners)
+        parameters-and-qualifiers ->
+            "(" parameter-clause ")" attribute-specifier-seq[opt] cv-qualifier-seq[opt] ref-qualifier[opt] exception-specification[opt]
+        ref-qualifier -> "&" | "&&"
+        exception-specification ->
+            "noexcept" ("(" constant-expression ")")[opt]
+            "throw" ("(" type-id-list ")")[opt]
+        # TODO: we don't implement attributes
+        # member functions can have initializers, but we fold them into here
+        memberFunctionInit -> "=" "0"
+        # (note: only "0" is allowed as the value, according to the standard, right?)
+         
+    
+    We additionally add the possibility for specifying the visibility as the first thing.
+    
+    type_object:
+        goal:
+            either a single type (e.g., "MyClass:Something_T" or a typedef-like thing
+            (e.g. "Something Something_T" or "int I_arr[]"
+        grammar, single type: based on a type in a function parameter, but without a name:
+               parameter-declaration
+            -> attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+            # Drop the attributes
+            -> decl-specifier-seq abstract-declarator[opt]
+        grammar, typedef-like: no initilizer
+            decl-specifier-seq declerator
+        
+        
+    member_object:
+        goal: as a type_object which must have a declerator, and optionally with a initializer
+        grammar:
+            decl-specifier-seq declerator initializer
+        
+    function_object:
+        goal: a function declaration, TODO: what about templates? for now: skip
+        grammar: no initializer
+           decl-specifier-seq declerator
 """
 
 import re
+import traceback
 from copy import deepcopy
 
 from six import iteritems, text_type
     |   [!<>=/*%+|&^~-]=?
 ''')
 
-_id_shortwords = {
-    'char':                 'c',
-    'signed char':          'c',
-    'unsigned char':        'C',
-    'int':                  'i',
-    'signed int':           'i',
-    'unsigned int':         'U',
-    'long':                 'l',
-    'signed long':          'l',
-    'unsigned long':        'L',
-    'bool':                 'b',
-    'size_t':               's',
-    'std::string':          'ss',
-    'std::ostream':         'os',
-    'std::istream':         'is',
-    'std::iostream':        'ios',
-    'std::vector':          'v',
-    'std::map':             'm',
-    'operator[]':           'subscript-operator',
-    'operator()':           'call-operator',
-    'operator!':            'not-operator',
-    'operator<':            'lt-operator',
-    'operator<=':           'lte-operator',
-    'operator>':            'gt-operator',
-    'operator>=':           'gte-operator',
-    'operator=':            'assign-operator',
-    'operator/':            'div-operator',
-    'operator*':            'mul-operator',
-    'operator%':            'mod-operator',
-    'operator+':            'add-operator',
-    'operator-':            'sub-operator',
-    'operator|':            'or-operator',
-    'operator&':            'and-operator',
-    'operator^':            'xor-operator',
-    'operator&&':           'sand-operator',
-    'operator||':           'sor-operator',
-    'operator==':           'eq-operator',
-    'operator!=':           'neq-operator',
-    'operator<<':           'lshift-operator',
-    'operator>>':           'rshift-operator',
-    'operator-=':           'sub-assign-operator',
-    'operator+=':           'add-assign-operator',
-    'operator*-':           'mul-assign-operator',
-    'operator/=':           'div-assign-operator',
-    'operator%=':           'mod-assign-operator',
-    'operator&=':           'and-assign-operator',
-    'operator|=':           'or-assign-operator',
-    'operator<<=':          'lshift-assign-operator',
-    'operator>>=':          'rshift-assign-operator',
-    'operator^=':           'xor-assign-operator',
-    'operator,':            'comma-operator',
-    'operator->':           'pointer-operator',
-    'operator->*':          'pointer-by-pointer-operator',
-    'operator~':            'inv-operator',
-    'operator++':           'inc-operator',
-    'operator--':           'dec-operator',
-    'operator new':         'new-operator',
-    'operator new[]':       'new-array-operator',
-    'operator delete':      'delete-operator',
-    'operator delete[]':    'delete-array-operator'
+_id_prefix = '_CPP'
+_id_fundamental = { # not all of these are actually parsed as fundamental types, TODO: do that
+    'void' : 'v',
+    'bool' : 'b',
+    'char' : 'c',
+    'signed char' : 'a',
+    'unsigned char' : 'h',
+    'wchar_t' : 'w',
+    'char32_t' : 'Di',
+    'char16_t' : 'Ds',
+    'short' : 's', 'short int' : 's', 'signed short' : 's', 'signed short int' : 's',  
+    'unsigned short' : 't', 'unsigned short int' : 't',
+    'int' : 'i', 'signed' : 'i', 'signed int' : 'i',
+    'unsigned' : 'j', 'unsigned int' : 'j',
+    'long' : 'l', 'long int' : 'l', 'signed long' : 'l', 'signed long int' : 'l',
+    'unsigned long' : 'm', 'unsigned long int' : 'm',
+    'long long' : 'x', 'long long int' : 'x', 'signed long long' : 'x', 'signed long long int' : 'x',
+    'unsigned long long' : 'y', 'unsigned long long int' : 'y',
+    'float' : 'f',
+    'double' : 'd',
+    'long double' : 'e',
+    'auto' : 'Da',
+    'decltype(auto)' : 'Dc',
+    'std::nullptr_t' : 'Dn'
 }
-
+_id_operator = {
+    'new' : 'nw',
+    'new[]' : 'na',
+    'delete' : 'dl',
+    'delete[]' : 'da',
+    # the arguments will make the difference between unary and binary
+    #'+(unary)' : 'ps',
+    #'-(unary)' : 'ng',
+    #'&(unary)' : 'ad',
+    #'*(unary)' : 'de',
+    '~' : 'co',
+    '+' : 'pl',
+    '-' : 'mi',
+    '*' : 'ml',
+    '/' : 'dv',
+    '%' : 'rm',
+    '&' : 'an',
+    '|' : 'or',
+    '^' : 'eo',
+    '=' : 'aS',
+    '+=' : 'pL',
+    '-=' : 'mI',
+    '*=' : 'mL',
+    '/=' : 'dV',
+    '%=' : 'rM',
+    '&=' : 'aN',
+    '|=' : 'oR',
+    '^=' : 'eO',
+    '<<' : 'ls',
+    '>>' : 'rs',
+    '<<=' : 'lS',
+    '>>=' : 'rS',
+    '==' : 'eq',
+    '!=' : 'ne',
+    '<' : 'lt',
+    '>' : 'gt',
+    '<=' : 'le',
+    '>=' : 'ge',
+    '!' : 'nt',
+    '&&' : 'aa',
+    '||' : 'oo',
+    '++' : 'pp',
+    '--' : 'mm',
+    ',' : 'cm',
+    '->*' : 'pm',
+    '->' : 'pt',
+    '()' : 'cl',
+    '[]' : 'ix'
+}
 
 class DefinitionError(UnicodeMixin, Exception):
 
     def __unicode__(self):
         return self.description
 
-
-class DefExpr(UnicodeMixin):
+class ASTBase(UnicodeMixin):
 
     def __eq__(self, other):
         if type(self) is not type(other):
 
     def get_id(self):
         """Return the id for the node."""
-        return u''
+        raise NotImplementedError(repr(self))
 
     def get_name(self):
         """Return the name.
         Returns either `None` or a node with a name you might call
         :meth:`split_owner` on.
         """
-        return None
+        raise NotImplementedError(repr(self))
 
-    def split_owner(self):
-        """Nodes returned by :meth:`get_name` can split off their
-        owning parent.  This function returns the owner and the
-        name as a tuple of two items.  If a node does not support
-        it, it returns None as owner and self as name.
-        """
-        return None, self
-
-    def prefix(self, prefix):
+    def prefix_nested_name(self, prefix):
         """Prefix a name node (a node returned by :meth:`get_name`)."""
-        raise NotImplementedError()
+        raise NotImplementedError(repr(self))
 
     def __unicode__(self):
-        raise NotImplementedError()
+        raise NotImplementedError(repr(self))
 
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, self)
+    
+def _verify_description_mode(mode):
+    if not mode in {'lastIsName', 'noneIsName', 'markType', 'param'}:
+        raise Exception("Description mode '%s' is invalid." % mode)
 
+class ASTOperatorBuildIn(ASTBase):
+    
+    def __init__(self, op):
+        self.op = op
+        
+    def get_id(self):
+        if not self.op in _id_operator:
+            raise Exception('Internal error: Build-in operator "%s" can not be mapped to an id.' % self.op)
+        return _id_operator[self.op]
+        
+    def __unicode__(self):
+        if self.op in {'new', 'new[]', 'delete', 'delete[]'}:
+            return u'operator ' + self.op
+        else: return u'operator' + self.op 
+    
+    def get_name_no_template(self):
+        return text_type(self)
+    
+    def describe_signature(self, signode, mode, env, prefix):
+        _verify_description_mode(mode)
+        identifier = text_type(self)
+        if mode == 'lastIsName':
+            signode += addnodes.desc_name(identifier, identifier)
+        else:
+            signode += addnodes.desc_addname(identifier, identifier)
+        
+class ASTOperatorType(ASTBase):
+    
+    def __init__(self, type):
+        self.type = type
+        
+    def __unicode__(self):
+        return u''.join(['operator ', text_type(self.type)])
+    
+    def get_id(self):
+        return u'cv' + self.type.get_id()
+    
+    def get_name_no_template(self):
+        return text_type(self)
+    
+    def describe_signature(self, signode, mode, env, prefix):
+        _verify_description_mode(mode)
+        identifier = text_type(self)
+        if mode == 'lastIsName':
+            signode += addnodes.desc_name(identifier, identifier)
+        else:
+            signode += addnodes.desc_addname(identifier, identifier)
+            
+class ASTTemplateArgConstant(ASTBase):
+    
+    def __init__(self, value):
+        self.value = value
+        
+    def __unicode__(self):
+        return text_type(self.value)
+    
+    def get_id(self):
+        # TODO: doing this properly needs parsing of expressions, let's just juse it verbatim for now
+        return u'X' + text_type(self) + u'E' 
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        signode += nodes.Text(text_type(self))
 
-class PrimaryDefExpr(DefExpr):
+class ASTNestedNameElement(ASTBase):
 
-    def get_name(self):
+    def __init__(self, identifier, templateArgs):
+        self.identifier = identifier
+        self.templateArgs = templateArgs
+        
+    def get_id(self):
+        res = []
+        if self.identifier == "std":
+            res.append(u'St')
+        else:
+            res.append(text_type(len(self.identifier)))
+            res.append(self.identifier)
+        if self.templateArgs:
+            res.append('I')
+            for a in self.templateArgs:
+                res.append(a.get_id())
+            res.append('E')
+        return u''.join(res)
+        
+    def __unicode__(self):
+        res = []
+        res.append(self.identifier)
+        if self.templateArgs:
+            res.append('<')
+            first = True
+            for a in self.templateArgs:
+                if not first: res.append(', ')
+                first = False
+                res.append(text_type(a))
+            res.append('>')
+        return u''.join(res)
+    
+    def get_name_no_template(self):
+        return text_type(self.identifier)
+    
+    def describe_signature(self, signode, mode, env, prefix):
+        _verify_description_mode(mode)
+        if mode == 'markType':
+            targetText = prefix + text_type(self)
+            pnode = addnodes.pending_xref(
+                '', refdomain='cpp', reftype='type',
+                reftarget=targetText, modname=None, classname=None)
+            if env: # during testing we don't have an env, do we?
+                pnode['cpp:parent'] = env.temp_data.get('cpp:parent')
+            pnode += nodes.Text(text_type(self.identifier))
+            signode += pnode
+        elif mode == 'lastIsName':
+            name = text_type(self.identifier)
+            signode += addnodes.desc_name(name, name)
+        else:
+            raise Exception('Unknown description mode: %s' % mode)
+        if self.templateArgs:
+            signode += nodes.Text('<')
+            first = True
+            for a in self.templateArgs:
+                if not first: signode += nodes.Text(', ')
+                first = False
+                a.describe_signature(signode, 'markType', env)
+            signode += nodes.Text('>')
+
+class ASTNestedName(ASTBase):
+    
+    def __init__(self, names):
+        """Use an empty string as the first name if it should start with '::' """
+        self.names = names
+        
+    @property
+    def name(self):
         return self
+    
+    def get_id(self):
+        res = []
+        if len(self.names) > 1:
+            res.append('N')
+        for n in self.names:
+            res.append(n.get_id())
+        if len(self.names) > 1:
+            res.append('E')
+        return u''.join(res)
+    
+    def get_name_no_last_template(self):
+        res = u'::'.join([text_type(n) for n in self.names[:-1]])
+        if len(self.names) > 1: res += '::'
+        res += self.names[-1].get_name_no_template()
+        return res
+    
+    def prefix_nested_name(self, prefix):
+        if self.names[0] == '':
+            return self # it's defined at global namespace, don't tuch it
+        assert isinstance(prefix, ASTNestedName)
+        names = prefix.names[:]
+        names.extend(self.names)
+        return ASTNestedName(names)
+    
+    def __unicode__(self):
+        return u'::'.join([text_type(n) for n in self.names])
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        if mode == 'lastIsName':
+            addname = u'::'.join([text_type(n) for n in self.names[:-1]])
+            if len(self.names) > 1: addname += u'::'
+            name = text_type(self.names[-1])
+            signode += addnodes.desc_addname(addname, addname)
+            self.names[-1].describe_signature(signode, mode, env, '')
+        elif mode == 'noneIsName':
+            name = text_type(self)
+            signode += nodes.Text(name)
+        elif mode == 'param':
+            name = text_type(self)
+            signode += nodes.emphasis(name, name)
+        elif mode == 'markType':
+            # each element should be a pending xref targeting the complete prefix
+            # however, only the identifier part should be a link, such that template args can be a link as well
+            prefix = ''
+            first = True
+            for name in self.names:
+                if not first:
+                    signode += nodes.Text('::')
+                    prefix += '::'
+                first = False
+                if name != '':
+                    name.describe_signature(signode, mode, env, prefix)
+                prefix += text_type(name)
+        else:
+            raise Exception('Unknown description mode: %s' % mode)
 
-    def prefix(self, prefix):
-        if isinstance(prefix, PathDefExpr):
-            prefix = prefix.clone()
-            prefix.path.append(self)
-            return prefix
-        return PathDefExpr([prefix, self])
-
-
-class NameDefExpr(PrimaryDefExpr):
-
+class ASTTrailingTypeSpecFundamental(ASTBase):
+    
     def __init__(self, name):
         self.name = name
+    
+    def __unicode__(self):
+        return self.name
+    
+    def get_id(self):
+        if not self.name in _id_fundamental:
+            raise Exception('Semi-internal error: Fundamental type "%s" can not be mapped to an id. Is it a true fundamental type? If not so, the parser should have rejected it.' % self.name)
+        return _id_fundamental[self.name]
+    
+    def describe_signature(self, signode, mode, env):
+        signode += nodes.Text(text_type(self.name))
+    
+class ASTTrailingTypeSpecName(ASTBase):
+    
+    def __init__(self, prefix, nestedName):
+        self.prefix = prefix
+        self.nestedName = nestedName
+        
+    @property
+    def name(self):
+        return self.nestedName
+    
+    def get_id(self):
+        return self.nestedName.get_id()
+        
+    def __unicode__(self):
+        res = []
+        if self.prefix:
+            res.append(self.prefix)
+            res.append(' ')
+        res.append(text_type(self.nestedName))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        if self.prefix:
+            signode += addnodes.desc_annotation(self.prefix, self.prefix)
+            signode += nodes.Text(' ')
+        self.nestedName.describe_signature(signode, mode, env)
 
+class ASTFunctinoParameter(ASTBase):
+    
+    def __init__(self, arg, ellipsis=False):
+        self.arg = arg
+        self.ellipsis = ellipsis
+    
     def get_id(self):
-        name = _id_shortwords.get(self.name)
-        if name is not None:
-            return name
-        return self.name.replace(u' ', u'-')
+        if self.ellipsis: return 'z'
+        else: return self.arg.get_id()
+    
+    def __unicode__(self):
+        if self.ellipsis: return '...'
+        else: return text_type(self.arg)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        if self.ellipsis: signode += nodes.Text('...')
+        else: self.arg.describe_signature(signode, mode, env)
 
+class ASTParametersQualifiers(ASTBase):
+    
+    def __init__(self, args, volatile, const, refQual, exceptionSpec, override, final, initializer):
+        self.args = args
+        self.volatile = volatile
+        self.const = const
+        self.refQual = refQual
+        self.exceptionSpec = exceptionSpec
+        self.override = override
+        self.final = final
+        self.initializer = initializer
+        
+    def get_modifiers_id(self):
+        res = []
+        if self.volatile: res.append('V')
+        if self.const: res.append('K')
+        if self.refQual == '&&': res.append('O')
+        elif self.refQual == '&': res.append('R')
+        return u''.join(res)
+        
+    def get_param_id(self):
+        if len(self.args) == 0: return 'v'
+        else: return u''.join(a.get_id() for a in self.args)
+    
     def __unicode__(self):
-        return text_type(self.name)
+        res = []
+        res.append('(')
+        first = True
+        for a in self.args:
+            if not first: res.append(', ')
+            first = False
+            res.append(text_type(a))
+        res.append(')')
+        if self.volatile: res.append(' volatile')
+        if self.const: res.append(' const')
+        if self.refQual:
+            res.append(' ')
+            res.append(self.refQual)
+        if self.exceptionSpec:
+            res.append(' ')
+            res.append(text_type(self.exceptionSpec))
+        if self.final: res.append(' final')
+        if self.override: res.append(' override')
+        if self.initializer:
+            res.append(' = ')
+            res.append(self.initializer)
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        paramlist = addnodes.desc_parameterlist()
+        for arg in self.args:
+            param = addnodes.desc_parameter('', '', noemph=True)
+            if mode == 'lastIsName': # i.e., outer-function params
+                arg.describe_signature(param, 'param', env)
+            else:arg.describe_signature(param, 'markType', env) 
+            paramlist += param
+        signode += paramlist
+        def _add_anno(signode, text):
+            signode += nodes.Text(' ')
+            signode += addnodes.desc_annotation(text, text)
+        def _add_text(signode, text):
+            signode += nodes.Text(' ' + text)
+        if self.volatile: _add_anno(signode, 'volatile')
+        if self.const: _add_anno(signode, 'const')
+        if self.refQual: _add_text(signode, self.refQual)
+        if self.exceptionSpec: _add_anno(signode, text_type(self.exceptionSpec))
+        if self.final: _add_anno(signode, 'final')
+        if self.override: _add_anno(signode, 'override')
+        if self.initializer: _add_text(signode, '= ' + text_type(self.initializer))            
 
+class ASTDeclSpecs(ASTBase):
+    
+    def __init__(self, outer, visibility, storage, inline, virtual, explicit, constexpr, volatile, const, trailing):
+        self.outer = outer
+        self.visibility = visibility
+        self.storage = storage
+        self.inline = inline
+        self.virtual = virtual
+        self.explicit = explicit
+        self.constexpr = constexpr
+        self.volatile = volatile
+        self.const = const
+        self.trailingTypeSpec = trailing
+        
+    @property
+    def name(self):
+        return self.trailingTypeSpec.name
+    
+    def get_id(self):
+        res = []
+        if self.volatile: res.append('V')
+        if self.const: res.append('K')
+        res.append(self.trailingTypeSpec.get_id())
+        return u''.join(res)
+        
+    def _print_visibility(self):
+        return self.visibility and not (self.outer in {'type', 'member', 'function'} and self.visibility == 'public')
+        
+    def __unicode__(self):
+        res = []
+        if self._print_visibility(): res.append(self.visibility)
+        if self.storage: res.append(self.storage)
+        if self.inline: res.append('inline')
+        if self.virtual: res.append('virtual')
+        if self.explicit: res.append('explicit')
+        if self.constexpr: res.append('constexpr')
+        if self.volatile: res.append('volatile')
+        if self.const: res.append('const')
+        if self.trailingTypeSpec: res.append(text_type(self.trailingTypeSpec))
+        return u' '.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        modifiers = []
+        def _add(modifiers, text):
+            if len(modifiers) > 0:
+                modifiers.append(nodes.Text(' '))
+            modifiers.append(addnodes.desc_annotation(text, text))
+        if self._print_visibility(): _add(modifiers, self.visibility)
+        if self.storage: _add(modifiers, self.storage)
+        if self.inline: _add(modifiers, 'inline')
+        if self.virtual: _add(modifiers, 'virtual')
+        if self.explicit: _add(modifiers, 'explicit')
+        if self.constexpr: _add(modifiers, 'constexpr')
+        if self.volatile: _add(modifiers, 'volatile')
+        if self.const: _add(modifiers, 'const')
+        for m in modifiers: signode += m
+        if self.trailingTypeSpec:
+            if len(modifiers) > 0:
+                signode += nodes.Text(' ')
+            self.trailingTypeSpec.describe_signature(signode, mode, env)
+    
+class ASTPtrOpPtr(ASTBase):
+    
+    def __init__(self, volatile, const):
+        self.volatile = volatile
+        self.const = const
+        
+    def __unicode__(self):
+        res = ['*']
+        if self.volatile: res.append('volatile ')
+        if self.const: res.append('const ')
+        return u''.join(res)
+    
+    def get_id(self):
+        res = ['P']
+        if self.volatile: res.append('V')
+        if self.const: res.append('C')
+        return u''.join(res)
+    
+class ASTPtrOpRef(ASTBase):
+    
+    def __unicode__(self):
+        return '&'
+    
+    def get_id(self):
+        return 'R'
+    
+class ASTPtrOpParamPack(ASTBase):
+    
+    def __unicode__(self):
+        return '...'
+    
+    def get_id(self):
+        return 'Dp'
+    
+class ASTArray(ASTBase):
+    
+    def __init__(self, size):
+        self.size = size
+        
+    def __unicode__(self):
+        return u''.join(['[', text_type(self.size), ']'])
+    
+    def get_id(self):
+        # TODO: this should maybe be done differently
+        return u'A' + text_type(self.size) + u'_'
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        signode += nodes.Text(text_type(self))
+    
+class ASTDeclerator(ASTBase):
+        
+    def __init__(self, ptrOps, declId, suffixOps):
+        self.ptrOps = ptrOps
+        self.declId = declId
+        self.suffixOps = suffixOps
+        
+    @property
+    def name(self):
+        return self.declId
+    
+    def get_modifiers_id(self): # only the modifiers for a function, e.g., cv-qualifiers
+        for op in self.suffixOps:
+            if isinstance(op, ASTParametersQualifiers):
+                return op.get_modifiers_id()
+        raise Exception("This should only be called on a function: %s" % text_type(self))
+    
+    def get_param_id(self): # only the parameters (if any)
+        for op in self.suffixOps:
+            if isinstance(op, ASTParametersQualifiers):
+                return op.get_param_id()
+        return ''
+    
+    def get_ptr_suffix_id(self): # only the ptr ops and array specifiers
+        return u''.join(a.get_id() for a in self.ptrOps + self.suffixOps if not isinstance(a, ASTParametersQualifiers))            
+    
+    def require_start_space(self):
+        if len(self.ptrOps) > 0 and isinstance(self.ptrOps[-1], ASTPtrOpParamPack): return False
+        else: return self.declId != None
+        
+    def __unicode__(self):
+        res = []
+        for op in self.ptrOps:
+            res.append(text_type(op))
+            if isinstance(op, ASTPtrOpParamPack) and self.declId: res.append(' ')
+        if self.declId:
+            res.append(text_type(self.declId))
+        for op in self.suffixOps: res.append(text_type(op))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        for op in self.ptrOps:
+            signode += nodes.Text(text_type(op))
+            if isinstance(op, ASTPtrOpParamPack) and self.declId: signode += nodes.Text(' ')
+        if self.declId: self.declId.describe_signature(signode, mode, env)
+        for op in self.suffixOps: op.describe_signature(signode, mode, env)
+    
+class ASTInitializer(ASTBase):
+    
+    def __init__(self, value):
+        self.value = value
+        
+    def __unicode__(self):
+        return u''.join([' = ', text_type(self.value)])
+    
+    def describe_signature(self, signode, mode):
+        _verify_description_mode(mode)
+        signode += nodes.Text(text_type(self))
 
-class PathDefExpr(PrimaryDefExpr):
+class ASTType(ASTBase):
+    
+    def __init__(self, declSpecs, decl):
+        self.declSpecs = declSpecs
+        self.decl = decl
+        self.objectType = None
+        
+    @property
+    def name(self):
+        name = self.decl.name
+        if not name: name = self.declSpecs.name
+        return name
+    
+    def get_id(self):
+        res = []
+        if self.objectType: # needs the name
+            res.append(_id_prefix)
+            if self.objectType == 'function': # also modifiers
+                res.append(self.decl.get_modifiers_id())
+                res.append(self.prefixedName.get_id())
+                res.append(self.decl.get_param_id())
+            elif self.objectType == 'type': # just the name
+                res.append(self.prefixedName.get_id())
+            else:
+                print(self.objectType)
+                assert False
+        else: # only type encoding
+            res.append(self.decl.get_ptr_suffix_id())
+            res.append(self.declSpecs.get_id())
+            res.append(self.decl.get_param_id())
+        return u''.join(res)
+        
+    def __unicode__(self):
+        res = []
+        declSpecs = text_type(self.declSpecs) 
+        res.append(declSpecs)
+        if self.decl.require_start_space() and len(declSpecs) > 0:
+            res.append(u' ')
+        res.append(text_type(self.decl))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        self.declSpecs.describe_signature(signode, 'markType', env)
+        if self.decl.require_start_space() and len(text_type(self.declSpecs)) > 0:
+            signode += nodes.Text(' ')
+        self.decl.describe_signature(signode, mode, env)
+    
+class ASTTypeWithInit(ASTBase):
+    
+    def __init__(self, type, init):
+        self.objectType = None
+        self.type = type
+        self.init = init
+        
+    @property
+    def name(self):
+        return self.type.name
+    
+    def get_id(self):
+        if self.objectType == 'member':
+            return _id_prefix + self.prefixedName.get_id()
+        else:
+            return self.type.get_id()
+        
+    def __unicode__(self):
+        res = []
+        res.append(text_type(self.type))
+        if self.init: res.append(text_type(self.init))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        self.type.describe_signature(signode, mode, env)
+        if self.init: self.init.describe_signature(signode, mode)
 
-    def __init__(self, parts):
-        self.path = parts
-
-    def get_id(self):
-        rv = u'::'.join(x.get_id() for x in self.path)
-        return _id_shortwords.get(rv, rv)
-
-    def split_owner(self):
-        if len(self.path) > 1:
-            return PathDefExpr(self.path[:-1]), self.path[-1]
-        return None, self
-
-    def prefix(self, prefix):
-        if isinstance(prefix, PathDefExpr):
-            prefix = prefix.clone()
-            prefix.path.extend(self.path)
-            return prefix
-        return PathDefExpr([prefix] + self.path)
-
-    def __unicode__(self):
-        return u'::'.join(map(text_type, self.path))
-
-
-class ArrayTypeSuffixDefExpr(UnicodeMixin):
-
-    def __init__(self, size_hint=None):
-        self.size_hint = size_hint
-
-    def get_id_suffix(self):
-        return 'A'
-
-    def __unicode__(self):
-        return u'[%s]' % (
-            self.size_hint is not None and text_type(self.size_hint) or u'',
-        )
-
-
-class TemplateDefExpr(PrimaryDefExpr):
-
-    def __init__(self, typename, args):
-        self.typename = typename
-        self.args = args
-
-    def split_owner(self):
-        owner, typename = self.typename.split_owner()
-        return owner, TemplateDefExpr(typename, self.args)
-
-    def get_id(self):
-        return u'%s:%s:' % (self.typename.get_id(),
-                            u'.'.join(x.get_id() for x in self.args))
-
-    def __unicode__(self):
-        return u'%s<%s>' % (self.typename, u', '.join(map(text_type, self.args)))
-
-
-class ConstantTemplateArgExpr(PrimaryDefExpr):
-
-    def __init__(self, arg):
-        self.arg = arg
-
-    def get_id(self):
-        return self.arg.replace(u' ', u'-')
-
-    def __unicode__(self):
-        return text_type(self.arg)
-
-
-class WrappingDefExpr(DefExpr):
-
-    def __init__(self, typename):
-        self.typename = typename
-
-    def get_name(self):
-        return self.typename.get_name()
-
-
-class ModifierDefExpr(WrappingDefExpr):
-
-    def __init__(self, typename, modifiers):
-        WrappingDefExpr.__init__(self, typename)
-        self.modifiers = modifiers
-
-    def get_id(self):
-        pieces = [_id_shortwords.get(text_type(x), text_type(x))
-                  for x in self.modifiers]
-        pieces.append(self.typename.get_id())
-        return u'-'.join(pieces)
-
-    def __unicode__(self):
-        return u' '.join(map(text_type, list(self.modifiers) + [self.typename]))
-
-
-class PtrDefExpr(WrappingDefExpr):
-
-    def get_id(self):
-        return self.typename.get_id() + u'P'
-
-    def __unicode__(self):
-        return u'%s*' % self.typename
-
-
-class LValRefDefExpr(WrappingDefExpr):
-
-    def get_id(self):
-        return self.typename.get_id() + u'R'
-
-    def __unicode__(self):
-        return u'%s&' % self.typename
-
-
-class RValRefDefExpr(WrappingDefExpr):
-
-    def get_id(self):
-        return self.typename.get_id() + u'RR'
-
-    def __unicode__(self):
-        return u'%s&&' % self.typename
-
-
-class ConstDefExpr(WrappingDefExpr):
-
-    def __init__(self, typename, prefix=False):
-        WrappingDefExpr.__init__(self, typename)
-        self.prefix = prefix
-
-    def get_id(self):
-        return self.typename.get_id() + u'C'
-
-    def __unicode__(self):
-        return (self.prefix and u'const %s' or u'%s const') % self.typename
-
-
-class CastOpDefExpr(PrimaryDefExpr):
-
-    def __init__(self, typename):
-        self.typename = typename
-
-    def get_id(self):
-        return u'castto-%s-operator' % self.typename.get_id()
-
-    def __unicode__(self):
-        return u'operator %s' % self.typename
-
-
-class ArgumentDefExpr(DefExpr):
-
-    def __init__(self, type, name, type_suffixes, default=None, param_pack=False):
-        self.name = name
-        self.type = type
-        self.type_suffixes = type_suffixes
-        self.default = default
-        self.param_pack = param_pack
-
-    def get_name(self):
-        return self.name.get_name()
-
-    def get_id(self):
-        buf = []
-        buf.append(self.type and self.type.get_id() or 'X')
-        for suffix in self.type_suffixes:
-            buf.append(suffix.get_id_suffix())
-        return u''.join(buf)
-
-    def __unicode__(self):
-        buf = [(u'%s%s %s' % (
-            self.type or u'',
-            '...' if self.param_pack else u'',
-            self.name or u'')
-        ).strip()]
-        if self.default is not None:
-            buf.append('=%s' % self.default)
-        for suffix in self.type_suffixes:
-            buf.append(text_type(suffix))
-        return u''.join(buf)
-
-
-class NamedDefExpr(DefExpr):
-
-    def __init__(self, name, visibility, static):
+class ASTBaseClass(ASTBase):
+    
+    def __init__(self, name, visibility):
         self.name = name
         self.visibility = visibility
-        self.static = static
+    
+    def __unicode__(self):
+        res = []
+        if self.visibility != 'private':
+            res.append(self.visibility)
+            res.append(' ')
+        res.append(text_type(self.name))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        if self.visibility != 'private':
+            signode += addnodes.desc_annotation(self.visibility, self.visibility)
+            signode += nodes.Text(' ')
+            self.name.describe_signature(signode, mode, env)
 
-    def get_name(self):
-        return self.name.get_name()
-
-    def get_modifiers(self, visibility='public'):
-        rv = []
-        if self.visibility != visibility:
-            rv.append(self.visibility)
-        if self.static:
-            rv.append(u'static')
-        return rv
-
-
-class TypeObjDefExpr(NamedDefExpr):
-
-    def __init__(self, name, visibility, static, typename, type_suffixes):
-        NamedDefExpr.__init__(self, name, visibility, static)
-        self.typename = typename
-        self.type_suffixes = type_suffixes
-
+class ASTClass(ASTBase):
+    
+    def __init__(self, name, bases):
+        self.name = name
+        self.bases = bases
+        
     def get_id(self):
-        if self.typename is None:
-            buf = [self.name.get_id()]
-        else:
-            buf = [u'%s__%s' % (self.name.get_id(), self.typename.get_id())]
-        for suffix in self.type_suffixes:
-            buf.append(suffix.get_id_suffix())
-        return u''.join(buf)
-
+        return _id_prefix + self.prefixedName.get_id()
+        
     def __unicode__(self):
-        buf = self.get_modifiers()
-        if self.typename is None:
-            buf.append(text_type(self.name))
-        else:
-            buf.extend(map(text_type, (self.typename, self.name)))
-        buf = [u' '.join(buf)]
-        for suffix in self.type_suffixes:
-            buf.append(text_type(suffix))
-        return u''.join(buf)
-
-
-class MemberObjDefExpr(NamedDefExpr):
-
-    def __init__(self, name, visibility, static, typename, type_suffixes,
-                 value):
-        NamedDefExpr.__init__(self, name, visibility, static)
-        self.typename = typename
-        self.type_suffixes = type_suffixes
-        self.value = value
-
-    def get_id(self):
-        buf = [u'%s__%s' % (self.name.get_id(), self.typename.get_id())]
-        for suffix in self.type_suffixes:
-            buf.append(suffix.get_id_suffix())
-        return u''.join(buf)
-
-    def __unicode__(self):
-        buf = self.get_modifiers()
-        buf.extend((text_type(self.typename), text_type(self.name)))
-        buf = [u' '.join(buf)]
-        for suffix in self.type_suffixes:
-            buf.append(text_type(suffix))
-        if self.value is not None:
-            buf.append(u' = %s' % self.value)
-        return u''.join(buf)
-
-
-class FuncDefExpr(NamedDefExpr):
-
-    def __init__(self, name, visibility, static, explicit, constexpr, rv,
-                 signature, **kwargs):
-        NamedDefExpr.__init__(self, name, visibility, static)
-        self.rv = rv
-        self.signature = signature
-        self.explicit = explicit
-        self.constexpr = constexpr
-        self.const = kwargs.get('const', False)
-        self.volatile = kwargs.get('volatile', False)
-        self.noexcept = kwargs.get('noexcept', False)
-        self.override = kwargs.get('override', False)
-        self.rvalue_this = kwargs.get('rvalue_this', False)
-        self.lvalue_this = kwargs.get('lvalue_this', False)
-        self.pure_virtual = kwargs.get('pure_virtual', False)
-        self.delete = kwargs.get('delete', False)
-        self.default = kwargs.get('default', False)
-
-    def get_id(self):
-        return u'%s%s%s%s' % (
-            self.name.get_id(),
-            self.signature and u'__' +
-                u'.'.join(x.get_id() for x in self.signature) or u'',
-            self.const and u'C' or u'',
-            self.constexpr and 'CE' or ''
-        )
-
-    def __unicode__(self):
-        buf = self.get_modifiers()
-        if self.explicit:
-            buf.append(u'explicit')
-        if self.constexpr:
-            buf.append(u'constexpr')
-        if self.rv is not None:
-            buf.append(text_type(self.rv))
-        buf.append(u'%s(%s)' % (self.name, u', '.join(
-            map(text_type, self.signature))))
-        if self.const:
-            buf.append(u'const')
-        if self.volatile:
-            buf.append(u'volatile')
-        if self.rvalue_this:
-            buf.append(u'&&')
-        if self.lvalue_this:
-            buf.append(u'&')
-        if self.noexcept:
-            buf.append(u'noexcept')
-        if self.override:
-            buf.append(u'override')
-        if self.pure_virtual:
-            buf.append(u'= 0')
-        if self.default:
-            buf.append(u'= default')
-        if self.delete:
-            buf.append(u'= delete')
-        return u' '.join(buf)
-
-
-class ClassDefExpr(NamedDefExpr):
-
-    def __init__(self, name, visibility, static, bases):
-        NamedDefExpr.__init__(self, name, visibility, static)
-        self.bases = bases
-
-    def get_id(self):
-        return self.name.get_id()
-
-    def _tostring(self, visibility='public'):
-        buf = self.get_modifiers(visibility)
-        buf.append(text_type(self.name))
-        if self.bases:
-            buf.append(u':')
-            buf.append(u', '.join(base._tostring('private')
-                                  for base in self.bases))
-        return u' '.join(buf)
-
-    def __unicode__(self):
-        return self._tostring('public')
+        res = []
+        res.append(text_type(self.name))
+        if len(self.bases) > 0:
+            res.append(' : ')
+            first = True
+            for b in self.bases:
+                if not first: res.append(', ')
+                first = False
+                res.append(text_type(b))
+        return u''.join(res)
+    
+    def describe_signature(self, signode, mode, env):
+        _verify_description_mode(mode)
+        self.name.describe_signature(signode, mode, env)
+        if len(self.bases) > 0:
+            signode += nodes.Text(' : ')
+            for b in self.bases:
+                b.describe_signature(signode, mode, env) 
+                signode += nodes.Text(', ')
+            signode.pop()
 
 class DefinitionParser(object):
-
-    # mapping of valid type modifiers.  if the set is None it means
-    # the modifier can prefix all types, otherwise only the types
-    # (actually more keywords) in the set.  Also check
-    # _guess_typename when changing this.
-    _modifiers = {
-        'volatile':     None,
-        'register':     None,
-        'mutable':      None,
-        'const':        None,
-        'typename':     None,
-        'struct':       None,
-        'unsigned':     set(('char', 'short', 'int', 'long')),
-        'signed':       set(('char', 'short', 'int', 'long')),
-        'short':        set(('int',)),
-        'long':         set(('int', 'long', 'double'))
+    
+    # those without signedness and size modifiers
+    # see http://en.cppreference.com/w/cpp/language/types
+    _simple_fundemental_types = {
+        'void', 'bool',  'char', 'wchar_t', 'char16_t', 'char32_t', 'int', 'float', 'double', 'auto'
     }
+    
+    _prefix_keys = {'class', 'struct', 'union', 'typename'}
 
     def __init__(self, definition):
         self.definition = definition.strip()
         self._previous_state = (0, None)
 
     def fail(self, msg):
-        raise DefinitionError('Invalid definition: %s [error at %d]\n  %s' %
-            (msg, self.pos, self.definition))
+        indicator = '-'*self.pos + '^'
+        raise DefinitionError('Invalid definition: %s [error at %d]\n  %s\n  %s' % 
+            (msg, self.pos, self.definition, indicator))
 
     def match(self, regex):
         match = regex.match(self.definition, self.pos)
         if self.last_match is not None:
             return self.last_match.group()
 
-    def _parse_operator(self):
-        self.skip_ws()
-        # thank god, a regular operator definition
-        if self.match(_operator_re):
-            return NameDefExpr('operator' +
-                                _whitespace_re.sub('', self.matched_text))
-
-        # new/delete operator?
-        for allocop in 'new', 'delete':
-            if not self.skip_word(allocop):
-                continue
-            self.skip_ws()
-            if self.skip_string('['):
-                self.skip_ws()
-                if not self.skip_string(']'):
-                    self.fail('expected "]" for ' + allocop)
-                allocop += '[]'
-            return NameDefExpr('operator ' + allocop)
-
-        # oh well, looks like a cast operator definition.
-        # In that case, eat another type.
-        type = self._parse_type()
-        return CastOpDefExpr(type)
-
-    def _parse_name(self):
-        return self._parse_name_or_template_arg(False)
-
-    def _parse_name_or_template_arg(self, in_template):
-        if not self.match(_identifier_re):
-            if not in_template:
-                self.fail('expected name')
-            if not self.match(_template_arg_re):
-                self.fail('expected name or constant template argument')
-            return ConstantTemplateArgExpr(self.matched_text.strip())
-        identifier = self.matched_text
-
-        # strictly speaking, operators are not regular identifiers
-        # but because operator is a keyword, it might not be used
-        # for variable names anyways, so we can safely parse the
-        # operator here as identifier
-        if identifier == 'operator':
-            return self._parse_operator()
-
-        return NameDefExpr(identifier)
-
-    def _guess_typename(self, path):
-        if not path:
-            return [], 'int'
-        # for the long type, we don't want the int in there
-        if 'long' in path:
-            path = [x for x in path if x != 'int']
-            # remove one long
-            path.remove('long')
-            return path, 'long'
-        if path[-1] in ('int', 'char'):
-            return path[:-1], path[-1]
-        return path, 'int'
-
-    def _attach_crefptr(self, expr, is_const=False):
-        if is_const:
-            expr = ConstDefExpr(expr, prefix=True)
-        while 1:
-            self.skip_ws()
-            if self.skip_word('const'):
-                expr = ConstDefExpr(expr)
-            elif self.skip_string('*'):
-                expr = PtrDefExpr(expr)
-            elif self.skip_string('&'):
-                if self.skip_string('&'):
-                    expr = RValRefDefExpr(expr)
-                else:
-                    expr = LValRefDefExpr(expr)
-            else:
-                return expr
-
-    def _try_parse_type_suffixes(self):
-        rv = []
-        while self.match(_array_def_re):
-            rv.append(ArrayTypeSuffixDefExpr(self.last_match.group(1)))
-            self.skip_ws()
-        return rv
-
-    def _peek_const(self, path):
-        try:
-            path.remove('const')
-            return True
-        except ValueError:
-            return False
-
-    def _parse_builtin(self, modifiers):
-        modifier = modifiers[-1]
-        path = modifiers
-        following = self._modifiers[modifier]
-        while 1:
-            self.skip_ws()
-            if not self.match(_identifier_re):
-                break
-            identifier = self.matched_text
-            if identifier in following:
-                path.append(identifier)
-                following = self._modifiers[modifier]
-                assert following
-            else:
-                self.backout()
-                break
-
-        is_const = self._peek_const(path)
-        modifiers, typename = self._guess_typename(path)
-        rv = ModifierDefExpr(NameDefExpr(typename), modifiers)
-        return self._attach_crefptr(rv, is_const)
-
-    def _parse_type_expr(self, in_template=False):
-        typename = self._parse_name_or_template_arg(in_template)
-        self.skip_ws()
-        if not self.skip_string('<'):
-            return typename
-
-        args = []
-        while 1:
-            self.skip_ws()
-            if self.skip_string('>'):
-                break
-            if args:
-                if not self.skip_string(','):
-                    self.fail('"," or ">" in template expected')
-                self.skip_ws()
-            args.append(self._parse_type(True))
-        return TemplateDefExpr(typename, args)
-
-    def _parse_type(self, in_template=False):
-        self.skip_ws()
-        result = []
-        modifiers = []
-
-        # if there is a leading :: or not, we don't care because we
-        # treat them exactly the same.  Buf *if* there is one, we
-        # don't have to check for type modifiers
-        if not self.skip_string('::'):
-            self.skip_ws()
-            while self.match(_identifier_re):
-                modifier = self.matched_text
-                if modifier in self._modifiers:
-                    following = self._modifiers[modifier]
-                    # if the set is not none, there is a limited set
-                    # of types that might follow.  It is technically
-                    # impossible for a template to follow, so what
-                    # we do is go to a different function that just
-                    # eats types
-                    modifiers.append(modifier)
-                    if following is not None:
-                        return self._parse_builtin(modifiers)
-                    self.skip_ws()
-                else:
-                    self.backout()
-                    break
-
-        while 1:
-            self.skip_ws()
-            if (in_template and self.current_char in ',>') or \
-               (result and not self.skip_string('::')) or \
-               self.eof:
-                break
-            result.append(self._parse_type_expr(in_template))
-
-        if not result:
-            self.fail('expected type')
-        if len(result) == 1:
-            rv = result[0]
-        else:
-            rv = PathDefExpr(result)
-        is_const = self._peek_const(modifiers)
-        if modifiers:
-            rv = ModifierDefExpr(rv, modifiers)
-        return self._attach_crefptr(rv, is_const)
-
-    def _parse_default_expr(self):
-        self.skip_ws()
-        if self.match(_string_re):
-            return self.matched_text
-        paren_stack_depth = 0
-        max_pos = len(self.definition)
-        rv_start = self.pos
-        while 1:
-            idx0 = self.definition.find('(', self.pos)
-            idx1 = self.definition.find(',', self.pos)
-            idx2 = self.definition.find(')', self.pos)
-            if idx0 < 0:
-                idx0 = max_pos
-            if idx1 < 0:
-                idx1 = max_pos
-            if idx2 < 0:
-                idx2 = max_pos
-            idx = min(idx0, idx1, idx2)
-            if idx >= max_pos:
-                self.fail('unexpected end in default expression')
-            if idx == idx0:
-                paren_stack_depth += 1
-            elif idx == idx2:
-                paren_stack_depth -= 1
-                if paren_stack_depth < 0:
-                    break
-            elif paren_stack_depth == 0:
-                break
-            self.pos = idx+1
-
-        rv = self.definition[rv_start:idx]
-        self.pos = idx
-        return rv
-
-    def _parse_signature(self):
-        self.skip_ws()
-        if not self.skip_string('('):
-            self.fail('expected parentheses for function')
-
-        args = []
-        while 1:
-            self.skip_ws()
-            if self.eof:
-                self.fail('missing closing parentheses')
-            if self.skip_string(')'):
-                break
-            if args:
-                if not self.skip_string(','):
-                    self.fail('expected comma between arguments')
-                self.skip_ws()
-
-            if self.skip_string('...'):
-                args.append(ArgumentDefExpr(None, '...', [], None))
-                if self.skip_string(')'):
-                    break
-                else:
-                    self.fail('expected closing parenthesis after ellipses')
-
-            argname = default = None
-            argtype = self._parse_type()
-            self.skip_ws()
-            param_pack = self.skip_string('...')
-            if param_pack:
-                self.skip_ws()
-            type_suffixes = self._try_parse_type_suffixes()
-            if self.skip_string('='):
-                default = self._parse_default_expr()
-            elif self.current_char not in ',)':
-                argname = self._parse_name()
-                self.skip_ws()
-                type_suffixes.extend(self._try_parse_type_suffixes())
-                if self.skip_string('='):
-                    default = self._parse_default_expr()
-            if argname is None:
-                argname = argtype
-                argtype = None
-
-            args.append(ArgumentDefExpr(argtype, argname,
-                                        type_suffixes, default, param_pack))
-        self.skip_ws()
-        attributes = dict(
-            signature=args,
-            const=self.skip_word_and_ws('const'),
-            volatile=self.skip_word_and_ws('volatile'),
-            noexcept=self.skip_word_and_ws('noexcept'),
-            override=self.skip_word_and_ws('override'),
-            pure_virtual=False,
-            lvalue_this=False,
-            rvalue_this=False,
-            delete=False,
-            default=False)
-
-        if self.skip_string('&&'):
-            attributes['rvalue_this'] = True
-        if self.skip_string('&'):
-            attributes['lvalue_this'] = True
-
-        if attributes['lvalue_this'] and attributes['rvalue_this']:
-            self.fail('rvalue reference for *this specifier must be one of'
-                      '"&&" or "&"')
-
-        if self.skip_string('='):
-            self.skip_ws()
-            if self.skip_string('0'):
-                attributes['pure_virtual'] = True
-                return attributes
-            if self.skip_word('NULL') or self.skip_word('nullptr'):
-                attributes['pure_virtual'] = True
-                return attributes
-            if self.skip_word('delete'):
-                attributes['delete'] = True
-                return attributes
-            if self.skip_word('default'):
-                attributes['default'] = True
-                return attributes
-
-            self.fail('functions must be defined with '
-                      'either 0, NULL, nullptr, default or delete, other'
-                      'macros are not allowed')
-        return attributes
-
-    def _parse_visibility_static(self):
-        visibility = 'public'
-        if self.match(_visibility_re):
-            visibility = self.matched_text
-        static = self.skip_word_and_ws('static')
-        return visibility, static
-
-    def parse_type(self):
-        return self._parse_type()
-
-    def parse_type_object(self):
-        visibility, static = self._parse_visibility_static()
-        typename = self._parse_type()
-        self.skip_ws()
-        if not self.eof:
-            name = self._parse_type()
-            type_suffixes = self._try_parse_type_suffixes()
-        else:
-            name = typename
-            typename = None
-            type_suffixes = []
-        return TypeObjDefExpr(name, visibility, static, typename, type_suffixes)
-
-    def parse_member_object(self):
-        visibility, static = self._parse_visibility_static()
-        typename = self._parse_type()
-        name = self._parse_type()
-        type_suffixes = self._try_parse_type_suffixes()
-        self.skip_ws()
-        if self.skip_string('='):
-            value = self.read_rest().strip()
-        else:
-            value = None
-        return MemberObjDefExpr(name, visibility, static, typename,
-                                type_suffixes, value)
-
-    def parse_function(self):
-        visibility, static = self._parse_visibility_static()
-        explicit = self.skip_word_and_ws('explicit')
-        constexpr = self.skip_word_and_ws('constexpr')
-
-        rv = self._parse_type()
-        self.skip_ws()
-        # some things just don't have return values
-        if self.current_char == '(':
-            name = rv
-            rv = None
-        else:
-            name = self._parse_type()
-        return FuncDefExpr(name, visibility, static, explicit, constexpr, rv,
-                           **self._parse_signature())
-
-    def parse_class(self):
-        visibility, static = self._parse_visibility_static()
-        name = self._parse_type()
-        bases = []
-        if self.skip_string(':'):
-            self.skip_ws()
-            while 1:
-                access = 'private'
-                if self.match(_visibility_re):
-                    access = self.matched_text
-                base = self._parse_type()
-                bases.append(ClassDefExpr(base, access, False, []))
-                if self.skip_string(','):
-                    self.skip_ws()
-                else:
-                    break
-        return ClassDefExpr(name, visibility, static, bases)
-
     def read_rest(self):
         rv = self.definition[self.pos:]
         self.pos = self.end
     def assert_end(self):
         self.skip_ws()
         if not self.eof:
-            self.fail('expected end of definition, got %r' %
+            self.fail('expected end of definition, got %r' % 
                       self.definition[self.pos:])
-
+            
+    def _parse_operator(self):
+        self.skip_ws()
+        # adapted from the old code
+        # thank god, a regular operator definition
+        if self.match(_operator_re):
+            return ASTOperatorBuildIn(self.matched_text)
+        
+        # new/delete operator?
+        for op in 'new', 'delete':
+            if not self.skip_word(op):
+                continue
+            self.skip_ws()
+            if self.skip_string('['):
+                self.skip_ws()
+                if not self.skip_string(']'):
+                    self.fail('Expected "]" after  "operator ' + op + '["')
+                op += '[]'
+            return ASTOperatorBuildIn(op)
+        
+        # oh well, looks like a cast operator definition.
+        # In that case, eat another type.
+        type = self._parse_type()
+        return ASTOperatorType(type)
+        
+    def _parse_nested_name(self):
+        names = []
+        
+        self.skip_ws()
+        if self.skip_string('::'): names.append(u'')
+        while 1:
+            self.skip_ws()
+            # TODO: parse the "template" keyword
+            if not self.match(_identifier_re):
+                self.fail("expected identifier")
+            identifier = self.matched_text
+            if identifier == 'operator':
+                op = self._parse_operator()
+                names.append(op)
+            else:
+                templateArgs = None
+                self.skip_ws()
+                if self.skip_string('<'):
+                    templateArgs = []
+                    while 1:
+                        pos = self.pos                    
+                        try:
+                            type = self._parse_type(allowParams=True)
+                            templateArgs.append(type)
+                        except DefinitionError:
+                            self.pos = pos
+                            symbols = []
+                            startPos = self.pos
+                            self.skip_ws()
+                            if self.match(_string_re):
+                                value = self.matched_text
+                            else:
+                                while not self.eof:
+                                    if len(symbols) == 0 and self.current_char in {',', '>'}: break
+                                    # TODO: actually implement nice handling of quotes, braces, brackets, parens, and whatever
+                                    self.pos += 1
+                                if self.eof:
+                                    self.pos = startPos
+                                    self.fail('Could not find end of constant template argument.')
+                                value = self.definition[startPos:self.pos].strip()
+                            templateArgs.append(ASTTemplateArgConstant(value))
+                        self.skip_ws()
+                        if self.skip_string('>'): break
+                        elif self.skip_string(','): continue
+                        else:
+                            self.fail('Expected ">" or "," in template argument list.')
+                names.append(ASTNestedNameElement(identifier, templateArgs))
+            
+            self.skip_ws()
+            if not self.skip_string('::'): break
+        return ASTNestedName(names)
+        
+    def _parse_trailing_type_spec(self):        
+        # fundemental types
+        self.skip_ws()
+        for t in self._simple_fundemental_types:
+            if self.skip_word(t): return ASTTrailingTypeSpecFundamental(t)
+        
+        # TODO: this could/should be more strict
+        elements = []
+        self.skip_ws()
+        if self.skip_word_and_ws('signed'): elements.append('signed')
+        elif self.skip_word_and_ws('unsigned'): elements.append('unsigned')
+        while 1:
+            if self.skip_word_and_ws('short'): elements.append('short')
+            elif self.skip_word_and_ws('long'): elements.append('long')
+            else: break
+        if self.skip_word_and_ws('int'): elements.append('int')
+        elif self.skip_word_and_ws('double'): elements.append('double')
+        if len(elements) > 0: return ASTTrailingTypeSpecFundamental(u' '.join(elements))
+        
+        # decltype
+        self.skip_ws()
+        if self.skip_word_and_ws('decltype'):
+            self.fail('"decltype(.)" in trailing_type_spec not implemented')
+        
+        # prefixed
+        prefix = None
+        self.skip_ws()
+        for k in self._prefix_keys:
+            if self.skip_word_and_ws(k):
+                prefix = k
+                break
+        
+        nestedName = self._parse_nested_name()
+        return ASTTrailingTypeSpecName(prefix, nestedName)
+    
+    def _parse_parameters_and_qualifiers(self, paramMode):
+        self.skip_ws()
+        if not self.skip_string('('):
+            if paramMode == 'function':
+                self.fail('Expecting "(" in parameters_and_qualifiers.')
+            else: return None
+        args = []
+        self.skip_ws()
+        if not self.skip_string(')'):
+            while 1:
+                self.skip_ws()
+                if self.skip_string('...'):
+                    args.append(ASTFunctinoParameter(None, True))
+                    self.skip_ws()
+                    if not self.skip_string(')'):
+                        self.fail('Expected ")" after "..." in parameters_and_qualifiers.')
+                    break
+                if paramMode == 'function':
+                    arg = self._parse_type_with_init(named='maybe')
+                else:
+                    arg = self._parse_type()
+                # TODO: parse default parameters
+                args.append(ASTFunctinoParameter(arg))
+                
+                self.skip_ws()
+                if self.skip_string(','): continue
+                elif self.skip_string(')'): break
+                else: self.fail('Expecting "," or ")" in parameters_and_qualifiers, got "%s".' % self.current_char)
+        
+        if paramMode != 'function':
+            return ASTParametersQualifiers(args, None, None, None, None, None, None, None)
+        
+        self.skip_ws()
+        const = self.skip_word_and_ws('const')
+        volatile = self.skip_word_and_ws('volatile')
+        if not const: # the can be permuted
+            const = self.skip_word_and_ws('const')
+        
+        refQual = None
+        if self.skip_string('&&'): refQual = '&&'
+        if not refQual and self.skip_string('&'): refQual = '&'
+        
+        exceptionSpec = None
+        override = None
+        final = None
+        initializer = None
+        self.skip_ws()
+        if self.skip_string('noexcept'):
+            exceptionSpec = 'noexcept'
+            self.skip_ws()
+            if self.skip_string('('):
+                self.fail('Parameterised "noexcept" not implemented.')
+                    
+        self.skip_ws()
+        override = self.skip_word_and_ws('override')
+        final = self.skip_word_and_ws('final')
+        if not override: override = self.skip_word_and_ws('override') # they can be permuted
+                    
+        self.skip_ws()
+        if self.skip_string('='):
+            self.skip_ws()
+            valid = {'0', 'delete', 'default'}
+            for w in valid:
+                if self.skip_word_and_ws(w):
+                    initializer = w
+                    break
+            if not initializer:
+                self.fail('Expected "%s" in initializer-specifier.' % u'" or "'.join(valid))
+        
+        return ASTParametersQualifiers(args, volatile, const, refQual, exceptionSpec, override, final, initializer)
+        
+    def _parse_decl_specs(self, outer, typed=True):
+        """
+        visibility storage-class-specifier function-specifier "constexpr" "volatile" "const" trailing-type-specifier
+        storage-class-specifier -> "static" (only for member_object and function_object)
+        function-specifier -> "inline" | "virtual" | "explicit" (only for function_object)
+        "constexpr" (only for member_object and function_object)
+        """
+        visibility = None
+        storage = None
+        inline = None
+        virtual = None
+        explicit = None
+        constexpr = None
+        volatile = None
+        const = None
+        
+        if outer:
+            self.skip_ws()
+            if self.match(_visibility_re):
+                visibility = self.matched_text
+        
+        while 1: # accept any permutation of a subset of some decl-specs
+            self.skip_ws()
+            if not storage:
+                if outer in {'member', 'function'}:
+                    if self.skip_word('static'):
+                        storage = 'static'
+                        continue
+                if outer == 'member':
+                    if self.skip_word('mutable'):
+                        storage = 'mutable'
+                        continue
+                if outer == 'fuction': # TODO: maybe in more contexts, missing test cases
+                    if self.skip_word('register'):
+                        storage = 'register'
+                        continue
+            
+            if outer == 'function':
+                # function-specifiers
+                if not inline:
+                    inline = self.skip_word('inline')
+                    if inline: continue
+                if not virtual:
+                    virtual = self.skip_word('virtual')
+                    if virtual: continue
+                if not explicit:
+                    explicit = self.skip_word('explicit')
+                    if explicit: continue
+                
+            if not constexpr and outer in {'member', 'function'}:
+                constexpr = self.skip_word("constexpr")
+                if constexpr: continue
+            if not volatile and typed:
+                volatile = self.skip_word('volatile')
+                if volatile: continue
+            if not const and typed:
+                const = self.skip_word('const')
+                if const: continue
+            break
+        
+        if typed: trailing = self._parse_trailing_type_spec()
+        else: trailing = None
+        return ASTDeclSpecs(outer, visibility, storage, inline, virtual, explicit, constexpr, volatile, const, trailing)
+    
+    def _parse_declerator(self, named, paramMode=None, typed=True):
+        if paramMode:
+            if not paramMode in {'type', 'function'}:
+                raise Exception("Internal error, unknown paramMode '%s'." % paramMode)
+        ptrOps = []
+        while 1:
+            if not typed: break
+            self.skip_ws()
+            if self.skip_string('*'):
+                self.skip_ws()
+                volatile = self.skip_word_and_ws('volatile')
+                const = self.skip_word_and_ws('const')
+                ptrOps.append(ASTPtrOpPtr(volatile=volatile, const=const))
+            elif self.skip_string('&'): ptrOps.append(ASTPtrOpRef())
+            elif self.skip_string('...'):
+                ptrOps.append(ASTPtrOpParamPack())
+                break
+            else: break
+        
+        if named == 'maybe':
+            try:
+                declId = self._parse_nested_name()
+            except DefinitionError:
+                declId = None
+        elif named:
+            declId = self._parse_nested_name()
+        else:
+            declId = None
+        
+        suffixOpts = []
+        while 1:
+            self.skip_ws()
+            if typed and self.skip_string('['):
+                startPos = self.pos - 1
+                openCount = 1
+                while not self.eof:
+                    c = self.current_char
+                    if c == '[': openCount += 1
+                    elif c == ']': openCount -= 1
+                    if openCount == 0: break
+                    self.pos += 1
+                if self.eof:
+                    self.pos = startPos
+                    self.fail("Could not find closing square bracket for array.")
+                self.pos += 1
+                suffixOpts.append(ASTArray(self.definition[startPos+1:self.pos-1].strip()))
+                continue
+            if paramMode:
+                paramQual = self._parse_parameters_and_qualifiers(paramMode)
+                if paramQual: suffixOpts.append(paramQual)
+            break
+        
+        return ASTDeclerator(ptrOps, declId, suffixOpts)
+    
+    def _parse_initializer(self, outer=None):