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,
|
Reference,
|
||||||
TemplateArgument,
|
TemplateArgument,
|
||||||
TemplateDecl,
|
TemplateDecl,
|
||||||
|
TemplateDeclTypeVar,
|
||||||
TemplateInst,
|
TemplateInst,
|
||||||
TemplateNonTypeParam,
|
TemplateNonTypeParam,
|
||||||
TemplateParam,
|
TemplateParam,
|
||||||
@ -615,7 +616,18 @@ class CxxParser:
|
|||||||
|
|
||||||
template = self._parse_template_decl()
|
template = self._parse_template_decl()
|
||||||
|
|
||||||
|
# Check for multiple specializations
|
||||||
tok = self.lex.token()
|
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":
|
if tok.type == "using":
|
||||||
self._parse_using(tok, doxygen, template)
|
self._parse_using(tok, doxygen, template)
|
||||||
elif tok.type == "friend":
|
elif tok.type == "friend":
|
||||||
@ -1094,7 +1106,7 @@ class CxxParser:
|
|||||||
typename: PQName,
|
typename: PQName,
|
||||||
tok: LexToken,
|
tok: LexToken,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl],
|
template: TemplateDeclTypeVar,
|
||||||
typedef: bool,
|
typedef: bool,
|
||||||
location: Location,
|
location: Location,
|
||||||
mods: ParsedTypeModifiers,
|
mods: ParsedTypeModifiers,
|
||||||
@ -1795,7 +1807,7 @@ class CxxParser:
|
|||||||
return_type: typing.Optional[DecoratedType],
|
return_type: typing.Optional[DecoratedType],
|
||||||
pqname: PQName,
|
pqname: PQName,
|
||||||
op: typing.Optional[str],
|
op: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl],
|
template: TemplateDeclTypeVar,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
location: Location,
|
location: Location,
|
||||||
constructor: bool,
|
constructor: bool,
|
||||||
@ -2168,7 +2180,7 @@ class CxxParser:
|
|||||||
mods: ParsedTypeModifiers,
|
mods: ParsedTypeModifiers,
|
||||||
location: Location,
|
location: Location,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl],
|
template: TemplateDeclTypeVar,
|
||||||
is_typedef: bool,
|
is_typedef: bool,
|
||||||
is_friend: bool,
|
is_friend: bool,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
@ -2295,6 +2307,9 @@ class CxxParser:
|
|||||||
if not dtype:
|
if not dtype:
|
||||||
raise CxxParseError("appear to be parsing a field without a type")
|
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)
|
self._parse_field(mods, dtype, pqname, template, doxygen, location, is_typedef)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -2303,7 +2318,7 @@ class CxxParser:
|
|||||||
mods: ParsedTypeModifiers,
|
mods: ParsedTypeModifiers,
|
||||||
location: Location,
|
location: Location,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl],
|
template: TemplateDeclTypeVar,
|
||||||
is_typedef: bool,
|
is_typedef: bool,
|
||||||
is_friend: bool,
|
is_friend: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -2356,7 +2371,7 @@ class CxxParser:
|
|||||||
self,
|
self,
|
||||||
tok: LexToken,
|
tok: LexToken,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl] = None,
|
template: TemplateDeclTypeVar = None,
|
||||||
is_typedef: bool = False,
|
is_typedef: bool = False,
|
||||||
is_friend: bool = False,
|
is_friend: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -2426,7 +2441,7 @@ class CxxParser:
|
|||||||
parsed_type: Type,
|
parsed_type: Type,
|
||||||
mods: ParsedTypeModifiers,
|
mods: ParsedTypeModifiers,
|
||||||
doxygen: typing.Optional[str],
|
doxygen: typing.Optional[str],
|
||||||
template: typing.Optional[TemplateDecl],
|
template: TemplateDeclTypeVar,
|
||||||
is_typedef: bool,
|
is_typedef: bool,
|
||||||
is_friend: bool,
|
is_friend: bool,
|
||||||
location: Location,
|
location: Location,
|
||||||
|
@ -514,6 +514,26 @@ class TemplateDecl:
|
|||||||
params: typing.List[TemplateParam] = field(default_factory=list)
|
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
|
@dataclass
|
||||||
class TemplateInst:
|
class TemplateInst:
|
||||||
"""
|
"""
|
||||||
@ -538,7 +558,7 @@ class ForwardDecl:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
typename: PQName
|
typename: PQName
|
||||||
template: typing.Optional[TemplateDecl] = None
|
template: TemplateDeclTypeVar = None
|
||||||
doxygen: typing.Optional[str] = None
|
doxygen: typing.Optional[str] = None
|
||||||
|
|
||||||
#: Set if this is a forward declaration of an enum and it has a base
|
#: Set if this is a forward declaration of an enum and it has a base
|
||||||
@ -576,7 +596,7 @@ class ClassDecl:
|
|||||||
typename: PQName
|
typename: PQName
|
||||||
|
|
||||||
bases: typing.List[BaseClass] = field(default_factory=list)
|
bases: typing.List[BaseClass] = field(default_factory=list)
|
||||||
template: typing.Optional[TemplateDecl] = None
|
template: TemplateDeclTypeVar = None
|
||||||
|
|
||||||
explicit: bool = False
|
explicit: bool = False
|
||||||
final: bool = False
|
final: bool = False
|
||||||
@ -642,7 +662,7 @@ class Function:
|
|||||||
#: whatever the trailing return type was
|
#: whatever the trailing return type was
|
||||||
has_trailing_return: bool = False
|
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
|
#: Value of any throw specification for this function. The value omits the
|
||||||
#: outer parentheses.
|
#: 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