Skip to content

Commit

Permalink
Merge pull request #104 from robotpy/fancy-templates
Browse files Browse the repository at this point in the history
Support for fancy template/concept features
  • Loading branch information
virtuald authored Aug 21, 2024
2 parents 544c253 + 78afc93 commit d8f8bd0
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 1 deletion.
21 changes: 21 additions & 0 deletions cxxheaderparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,17 @@ def _parse_template_specialization(self) -> TemplateSpecialization:
if dtype:
args.append(TemplateArgument(dtype, param_pack))
else:
# special case for sizeof...(thing)
if (
param_pack
and len(val.tokens) == 1
and val.tokens[0].value == "sizeof"
):
val.tokens.append(Token("...", "ELLIPSIS"))
tok = self._next_token_must_be("(")
raw_toks = self._consume_balanced_tokens(tok)
val.tokens.extend(Token(tok.value, tok.type) for tok in raw_toks)

args.append(TemplateArgument(val, param_pack))

tok = self._next_token_must_be(",", ">")
Expand Down Expand Up @@ -2624,6 +2635,16 @@ def _parse_declarations(
):
return

# Check for an abbreviated template return type, promote it
if not is_typedef and parsed_type is not None and self.lex.token_if_val("auto"):
abv_ret_tmpl = TemplateNonTypeParam(type=parsed_type, param_idx=-1)
if template is None:
template = TemplateDecl(params=[abv_ret_tmpl])
elif isinstance(template, TemplateDecl):
template.params.append(abv_ret_tmpl)
else:
template[-1].params.append(abv_ret_tmpl)

var_ok = True

if is_typedef:
Expand Down
7 changes: 6 additions & 1 deletion cxxheaderparser/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,13 +458,18 @@ class TemplateNonTypeParam:
// abbreviated template parameters are converted to this and param_idx is set
void fn(C auto p)
~~~~~~
// abbreviated template parameters that are return types have param_idx = -1
C auto fn()
~~~~~~
"""

type: DecoratedType
name: typing.Optional[str] = None
default: typing.Optional[Value] = None

#: If this was promoted, the parameter index that this corresponds with
#: If this was promoted, the parameter index that this corresponds with. Return
#: types are set to -1
param_idx: typing.Optional[int] = None

#: Contains a ``...``
Expand Down
74 changes: 74 additions & 0 deletions tests/test_abv_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,77 @@ def test_abv_template_f5() -> None:
]
)
)


def test_returned_abv_template() -> None:
content = """
constexpr std::signed_integral auto FloorDiv(std::signed_integral auto x,
std::signed_integral auto y);
"""
data = parse_string(content, cleandoc=True)

assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="signed_integral"),
]
)
),
name=PQName(segments=[NameSpecifier(name="FloorDiv")]),
parameters=[
Parameter(
type=Type(typename=PQName(segments=[AutoSpecifier()])),
name="x",
),
Parameter(
type=Type(typename=PQName(segments=[AutoSpecifier()])),
name="y",
),
],
constexpr=True,
template=TemplateDecl(
params=[
TemplateNonTypeParam(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="signed_integral"),
]
)
),
param_idx=-1,
),
TemplateNonTypeParam(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="signed_integral"),
]
)
),
param_idx=0,
),
TemplateNonTypeParam(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(name="signed_integral"),
]
)
),
param_idx=1,
),
]
),
)
]
)
)
105 changes: 105 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2247,3 +2247,108 @@ def test_template_deduction_guide() -> None:
]
)
)


def test_sizeof_pack() -> None:
content = """
template <std::same_as<int>... OutputIndices>
LinearSystem<States, Inputs, sizeof...(OutputIndices)> Slice(OutputIndices... outputIndices);
"""
data = parse_string(content, cleandoc=True)

assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Type(
typename=PQName(
segments=[
NameSpecifier(
name="LinearSystem",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
arg=Type(
typename=PQName(
segments=[
NameSpecifier(name="States")
]
)
)
),
TemplateArgument(
arg=Type(
typename=PQName(
segments=[
NameSpecifier(name="Inputs")
]
)
)
),
TemplateArgument(
arg=Value(
tokens=[
Token(value="sizeof"),
Token(value="..."),
Token(value="("),
Token(value="OutputIndices"),
Token(value=")"),
]
),
param_pack=True,
),
]
),
)
]
)
),
name=PQName(segments=[NameSpecifier(name="Slice")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="OutputIndices")]
)
),
name="outputIndices",
param_pack=True,
)
],
template=TemplateDecl(
params=[
TemplateNonTypeParam(
type=Type(
typename=PQName(
segments=[
NameSpecifier(name="std"),
NameSpecifier(
name="same_as",
specialization=TemplateSpecialization(
args=[
TemplateArgument(
arg=Type(
typename=PQName(
segments=[
FundamentalSpecifier(
name="int"
)
]
)
)
)
]
),
),
]
)
),
name="OutputIndices",
param_pack=True,
)
]
),
)
]
)
)

0 comments on commit d8f8bd0

Please sign in to comment.