diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index 2be0537..a2c031a 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -44,6 +44,7 @@ Reference, TemplateArgument, TemplateDecl, + TemplateDeclTypeVar, TemplateInst, TemplateNonTypeParam, TemplateParam, @@ -615,7 +616,18 @@ def _parse_template(self, tok: LexToken, doxygen: typing.Optional[str]) -> None: template = self._parse_template_decl() + # Check for multiple specializations tok = self.lex.token() + if tok.type == "template": + templates = [template] + while tok.type == "template": + templates.append(self._parse_template_decl()) + tok = self.lex.token() + + # Can only be followed by declarations + self._parse_declarations(tok, doxygen, templates) + return + if tok.type == "using": self._parse_using(tok, doxygen, template) elif tok.type == "friend": @@ -1094,7 +1106,7 @@ def _parse_class_decl( typename: PQName, tok: LexToken, doxygen: typing.Optional[str], - template: typing.Optional[TemplateDecl], + template: TemplateDeclTypeVar, typedef: bool, location: Location, mods: ParsedTypeModifiers, @@ -1795,7 +1807,7 @@ def _parse_function( return_type: typing.Optional[DecoratedType], pqname: PQName, op: typing.Optional[str], - template: typing.Optional[TemplateDecl], + template: TemplateDeclTypeVar, doxygen: typing.Optional[str], location: Location, constructor: bool, @@ -2168,7 +2180,7 @@ def _parse_decl( mods: ParsedTypeModifiers, location: Location, doxygen: typing.Optional[str], - template: typing.Optional[TemplateDecl], + template: TemplateDeclTypeVar, is_typedef: bool, is_friend: bool, ) -> bool: @@ -2295,6 +2307,9 @@ def _parse_decl( if not dtype: raise CxxParseError("appear to be parsing a field without a type") + if isinstance(template, list): + raise CxxParseError("multiple template declarations on a field") + self._parse_field(mods, dtype, pqname, template, doxygen, location, is_typedef) return False @@ -2303,7 +2318,7 @@ def _parse_operator_conversion( mods: ParsedTypeModifiers, location: Location, doxygen: typing.Optional[str], - template: typing.Optional[TemplateDecl], + template: TemplateDeclTypeVar, is_typedef: bool, is_friend: bool, ) -> None: @@ -2356,7 +2371,7 @@ def _parse_declarations( self, tok: LexToken, doxygen: typing.Optional[str], - template: typing.Optional[TemplateDecl] = None, + template: TemplateDeclTypeVar = None, is_typedef: bool = False, is_friend: bool = False, ) -> None: @@ -2426,7 +2441,7 @@ def _maybe_parse_class_enum_decl( parsed_type: Type, mods: ParsedTypeModifiers, doxygen: typing.Optional[str], - template: typing.Optional[TemplateDecl], + template: TemplateDeclTypeVar, is_typedef: bool, is_friend: bool, location: Location, diff --git a/cxxheaderparser/types.py b/cxxheaderparser/types.py index c594001..b71ff6b 100644 --- a/cxxheaderparser/types.py +++ b/cxxheaderparser/types.py @@ -514,6 +514,26 @@ class Foo {}; params: typing.List[TemplateParam] = field(default_factory=list) +#: If no template, this is None. This is a TemplateDecl if this there is a single +#: declaration: +#: +#: .. code-block:: c++ +#: +#: template +#: struct C {}; +#: +#: If there are multiple template declarations, then this is a list of +#: declarations in the order that they're encountered: +#: +#: .. code-block:: c++ +#: +#: template<> +#: template +#: struct A::C {}; +#: +TemplateDeclTypeVar = typing.Union[None, TemplateDecl, typing.List[TemplateDecl]] + + @dataclass class TemplateInst: """ @@ -538,7 +558,7 @@ class ForwardDecl: """ typename: PQName - template: typing.Optional[TemplateDecl] = None + template: TemplateDeclTypeVar = None doxygen: typing.Optional[str] = None #: Set if this is a forward declaration of an enum and it has a base @@ -576,7 +596,7 @@ class ClassDecl: typename: PQName bases: typing.List[BaseClass] = field(default_factory=list) - template: typing.Optional[TemplateDecl] = None + template: TemplateDeclTypeVar = None explicit: bool = False final: bool = False @@ -642,7 +662,7 @@ class Function: #: whatever the trailing return type was has_trailing_return: bool = False - template: typing.Optional[TemplateDecl] = None + template: TemplateDeclTypeVar = None #: Value of any throw specification for this function. The value omits the #: outer parentheses. diff --git a/cxxheaderparser/version.py b/cxxheaderparser/version.py index d7e4179..515d6c1 100644 --- a/cxxheaderparser/version.py +++ b/cxxheaderparser/version.py @@ -1 +1 @@ -__version__ = '0.0.0-127-g1758155' +__version__ = '0.0.0-129-g955214c'