Skip to content

Commit d8f8bd0

Browse files
authored
Merge pull request #104 from robotpy/fancy-templates
Support for fancy template/concept features
2 parents 544c253 + 78afc93 commit d8f8bd0

File tree

4 files changed

+206
-1
lines changed

4 files changed

+206
-1
lines changed

cxxheaderparser/parser.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,17 @@ def _parse_template_specialization(self) -> TemplateSpecialization:
718718
if dtype:
719719
args.append(TemplateArgument(dtype, param_pack))
720720
else:
721+
# special case for sizeof...(thing)
722+
if (
723+
param_pack
724+
and len(val.tokens) == 1
725+
and val.tokens[0].value == "sizeof"
726+
):
727+
val.tokens.append(Token("...", "ELLIPSIS"))
728+
tok = self._next_token_must_be("(")
729+
raw_toks = self._consume_balanced_tokens(tok)
730+
val.tokens.extend(Token(tok.value, tok.type) for tok in raw_toks)
731+
721732
args.append(TemplateArgument(val, param_pack))
722733

723734
tok = self._next_token_must_be(",", ">")
@@ -2624,6 +2635,16 @@ def _parse_declarations(
26242635
):
26252636
return
26262637

2638+
# Check for an abbreviated template return type, promote it
2639+
if not is_typedef and parsed_type is not None and self.lex.token_if_val("auto"):
2640+
abv_ret_tmpl = TemplateNonTypeParam(type=parsed_type, param_idx=-1)
2641+
if template is None:
2642+
template = TemplateDecl(params=[abv_ret_tmpl])
2643+
elif isinstance(template, TemplateDecl):
2644+
template.params.append(abv_ret_tmpl)
2645+
else:
2646+
template[-1].params.append(abv_ret_tmpl)
2647+
26272648
var_ok = True
26282649

26292650
if is_typedef:

cxxheaderparser/types.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,13 +458,18 @@ class TemplateNonTypeParam:
458458
// abbreviated template parameters are converted to this and param_idx is set
459459
void fn(C auto p)
460460
~~~~~~
461+
462+
// abbreviated template parameters that are return types have param_idx = -1
463+
C auto fn()
464+
~~~~~~
461465
"""
462466

463467
type: DecoratedType
464468
name: typing.Optional[str] = None
465469
default: typing.Optional[Value] = None
466470

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

470475
#: Contains a ``...``

tests/test_abv_template.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,77 @@ def test_abv_template_f5() -> None:
351351
]
352352
)
353353
)
354+
355+
356+
def test_returned_abv_template() -> None:
357+
content = """
358+
constexpr std::signed_integral auto FloorDiv(std::signed_integral auto x,
359+
std::signed_integral auto y);
360+
"""
361+
data = parse_string(content, cleandoc=True)
362+
363+
assert data == ParsedData(
364+
namespace=NamespaceScope(
365+
functions=[
366+
Function(
367+
return_type=Type(
368+
typename=PQName(
369+
segments=[
370+
NameSpecifier(name="std"),
371+
NameSpecifier(name="signed_integral"),
372+
]
373+
)
374+
),
375+
name=PQName(segments=[NameSpecifier(name="FloorDiv")]),
376+
parameters=[
377+
Parameter(
378+
type=Type(typename=PQName(segments=[AutoSpecifier()])),
379+
name="x",
380+
),
381+
Parameter(
382+
type=Type(typename=PQName(segments=[AutoSpecifier()])),
383+
name="y",
384+
),
385+
],
386+
constexpr=True,
387+
template=TemplateDecl(
388+
params=[
389+
TemplateNonTypeParam(
390+
type=Type(
391+
typename=PQName(
392+
segments=[
393+
NameSpecifier(name="std"),
394+
NameSpecifier(name="signed_integral"),
395+
]
396+
)
397+
),
398+
param_idx=-1,
399+
),
400+
TemplateNonTypeParam(
401+
type=Type(
402+
typename=PQName(
403+
segments=[
404+
NameSpecifier(name="std"),
405+
NameSpecifier(name="signed_integral"),
406+
]
407+
)
408+
),
409+
param_idx=0,
410+
),
411+
TemplateNonTypeParam(
412+
type=Type(
413+
typename=PQName(
414+
segments=[
415+
NameSpecifier(name="std"),
416+
NameSpecifier(name="signed_integral"),
417+
]
418+
)
419+
),
420+
param_idx=1,
421+
),
422+
]
423+
),
424+
)
425+
]
426+
)
427+
)

tests/test_template.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,3 +2247,108 @@ def test_template_deduction_guide() -> None:
22472247
]
22482248
)
22492249
)
2250+
2251+
2252+
def test_sizeof_pack() -> None:
2253+
content = """
2254+
template <std::same_as<int>... OutputIndices>
2255+
LinearSystem<States, Inputs, sizeof...(OutputIndices)> Slice(OutputIndices... outputIndices);
2256+
"""
2257+
data = parse_string(content, cleandoc=True)
2258+
2259+
assert data == ParsedData(
2260+
namespace=NamespaceScope(
2261+
functions=[
2262+
Function(
2263+
return_type=Type(
2264+
typename=PQName(
2265+
segments=[
2266+
NameSpecifier(
2267+
name="LinearSystem",
2268+
specialization=TemplateSpecialization(
2269+
args=[
2270+
TemplateArgument(
2271+
arg=Type(
2272+
typename=PQName(
2273+
segments=[
2274+
NameSpecifier(name="States")
2275+
]
2276+
)
2277+
)
2278+
),
2279+
TemplateArgument(
2280+
arg=Type(
2281+
typename=PQName(
2282+
segments=[
2283+
NameSpecifier(name="Inputs")
2284+
]
2285+
)
2286+
)
2287+
),
2288+
TemplateArgument(
2289+
arg=Value(
2290+
tokens=[
2291+
Token(value="sizeof"),
2292+
Token(value="..."),
2293+
Token(value="("),
2294+
Token(value="OutputIndices"),
2295+
Token(value=")"),
2296+
]
2297+
),
2298+
param_pack=True,
2299+
),
2300+
]
2301+
),
2302+
)
2303+
]
2304+
)
2305+
),
2306+
name=PQName(segments=[NameSpecifier(name="Slice")]),
2307+
parameters=[
2308+
Parameter(
2309+
type=Type(
2310+
typename=PQName(
2311+
segments=[NameSpecifier(name="OutputIndices")]
2312+
)
2313+
),
2314+
name="outputIndices",
2315+
param_pack=True,
2316+
)
2317+
],
2318+
template=TemplateDecl(
2319+
params=[
2320+
TemplateNonTypeParam(
2321+
type=Type(
2322+
typename=PQName(
2323+
segments=[
2324+
NameSpecifier(name="std"),
2325+
NameSpecifier(
2326+
name="same_as",
2327+
specialization=TemplateSpecialization(
2328+
args=[
2329+
TemplateArgument(
2330+
arg=Type(
2331+
typename=PQName(
2332+
segments=[
2333+
FundamentalSpecifier(
2334+
name="int"
2335+
)
2336+
]
2337+
)
2338+
)
2339+
)
2340+
]
2341+
),
2342+
),
2343+
]
2344+
)
2345+
),
2346+
name="OutputIndices",
2347+
param_pack=True,
2348+
)
2349+
]
2350+
),
2351+
)
2352+
]
2353+
)
2354+
)

0 commit comments

Comments
 (0)