Merge pull request #73 from robotpy/multiple-template-declarations
Support multiple template declarations on a class or function
This commit is contained in:
commit
955214cef4
@ -44,6 +44,7 @@ from .types import (
|
||||
Reference,
|
||||
TemplateArgument,
|
||||
TemplateDecl,
|
||||
TemplateDeclTypeVar,
|
||||
TemplateInst,
|
||||
TemplateNonTypeParam,
|
||||
TemplateParam,
|
||||
@ -615,7 +616,18 @@ class CxxParser:
|
||||
|
||||
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 @@ class CxxParser:
|
||||
typename: PQName,
|
||||
tok: LexToken,
|
||||
doxygen: typing.Optional[str],
|
||||
template: typing.Optional[TemplateDecl],
|
||||
template: TemplateDeclTypeVar,
|
||||
typedef: bool,
|
||||
location: Location,
|
||||
mods: ParsedTypeModifiers,
|
||||
@ -1795,7 +1807,7 @@ class CxxParser:
|
||||
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 @@ class CxxParser:
|
||||
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 @@ class CxxParser:
|
||||
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 @@ class CxxParser:
|
||||
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 @@ class CxxParser:
|
||||
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 @@ class CxxParser:
|
||||
parsed_type: Type,
|
||||
mods: ParsedTypeModifiers,
|
||||
doxygen: typing.Optional[str],
|
||||
template: typing.Optional[TemplateDecl],
|
||||
template: TemplateDeclTypeVar,
|
||||
is_typedef: bool,
|
||||
is_friend: bool,
|
||||
location: Location,
|
||||
|
@ -514,6 +514,26 @@ class TemplateDecl:
|
||||
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 <typename T>
|
||||
#: 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<class U>
|
||||
#: struct A<char>::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.
|
||||
|
@ -2027,3 +2027,139 @@ def test_fwd_declared_method() -> None:
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_multiple_explicit_member_specialization() -> None:
|
||||
content = """
|
||||
template <>
|
||||
template <>
|
||||
inline Standard_CString
|
||||
StdObjMgt_Attribute<TDF_TagSource>::Simple<Standard_Integer>::PName() const {
|
||||
return "PDF_TagSource";
|
||||
}
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
method_impls=[
|
||||
Method(
|
||||
return_type=Type(
|
||||
typename=PQName(
|
||||
segments=[NameSpecifier(name="Standard_CString")]
|
||||
)
|
||||
),
|
||||
name=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="StdObjMgt_Attribute",
|
||||
specialization=TemplateSpecialization(
|
||||
args=[
|
||||
TemplateArgument(
|
||||
arg=Type(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="TDF_TagSource"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
NameSpecifier(
|
||||
name="Simple",
|
||||
specialization=TemplateSpecialization(
|
||||
args=[
|
||||
TemplateArgument(
|
||||
arg=Type(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="Standard_Integer"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
NameSpecifier(name="PName"),
|
||||
]
|
||||
),
|
||||
parameters=[],
|
||||
inline=True,
|
||||
has_body=True,
|
||||
template=[TemplateDecl(), TemplateDecl()],
|
||||
const=True,
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_member_class_template_specialization() -> None:
|
||||
content = """
|
||||
template <> // specialization of a member class template
|
||||
template <class U>
|
||||
struct A<char>::C {
|
||||
void f();
|
||||
};
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
classes=[
|
||||
ClassScope(
|
||||
class_decl=ClassDecl(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="A",
|
||||
specialization=TemplateSpecialization(
|
||||
args=[
|
||||
TemplateArgument(
|
||||
arg=Type(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
FundamentalSpecifier(
|
||||
name="char"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
NameSpecifier(name="C"),
|
||||
],
|
||||
classkey="struct",
|
||||
),
|
||||
template=[
|
||||
TemplateDecl(),
|
||||
TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="U")]
|
||||
),
|
||||
],
|
||||
),
|
||||
methods=[
|
||||
Method(
|
||||
return_type=Type(
|
||||
typename=PQName(
|
||||
segments=[FundamentalSpecifier(name="void")]
|
||||
)
|
||||
),
|
||||
name=PQName(segments=[NameSpecifier(name="f")]),
|
||||
parameters=[],
|
||||
access="public",
|
||||
)
|
||||
],
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user