Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for fancy template/concept features #104

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
)
]
),
)
]
)
)
Loading