Skip to content

Commit 20e83a9

Browse files
authored
Merge pull request #121 from kdkavanagh/deduce-this
Add support for cxx23 deducing-this. Fixes #120
2 parents 7db87aa + a19a1b4 commit 20e83a9

File tree

3 files changed

+92
-8
lines changed

3 files changed

+92
-8
lines changed

cxxheaderparser/parser.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -608,11 +608,19 @@ def _parse_template_decl(self) -> TemplateDecl:
608608
param = self._parse_template_type_parameter(tok, None)
609609
else:
610610
param, _ = self._parse_parameter(
611-
ptok, TemplateNonTypeParam, False, ">"
611+
ptok,
612+
TemplateNonTypeParam,
613+
concept_ok=False,
614+
deduce_this_ok=False,
615+
end=">",
612616
)
613617
else:
614618
param, _ = self._parse_parameter(
615-
tok, TemplateNonTypeParam, concept_ok=False, end=">"
619+
tok,
620+
TemplateNonTypeParam,
621+
concept_ok=False,
622+
deduce_this_ok=False,
623+
end=">",
616624
)
617625

618626
params.append(param)
@@ -1761,6 +1769,7 @@ def _parse_parameter(
17611769
tok: typing.Optional[LexToken],
17621770
cls: typing.Type[PT],
17631771
concept_ok: bool,
1772+
deduce_this_ok: bool,
17641773
end: str = ")",
17651774
) -> typing.Tuple[PT, typing.Optional[Type]]:
17661775
"""
@@ -1775,6 +1784,10 @@ def _parse_parameter(
17751784
param_pack = False
17761785
parsed_type: typing.Optional[Type]
17771786
at_type: typing.Optional[Type] = None
1787+
extras: typing.Dict[str, typing.Any] = {}
1788+
1789+
if deduce_this_ok and self.lex.token_if("this"):
1790+
extras["deduces_this"] = True
17781791

17791792
if not tok:
17801793
tok = self.lex.token()
@@ -1825,12 +1838,18 @@ def _parse_parameter(
18251838
if at_type and self.lex.token_if("ELLIPSIS"):
18261839
param_pack = True
18271840

1828-
param = cls(type=dtype, name=param_name, default=default, param_pack=param_pack)
1841+
param = cls(
1842+
type=dtype,
1843+
name=param_name,
1844+
default=default,
1845+
param_pack=param_pack,
1846+
**extras,
1847+
)
18291848
self.debug_print("parameter: %s", param)
18301849
return param, at_type
18311850

18321851
def _parse_parameters(
1833-
self, concept_ok: bool
1852+
self, concept_ok: bool, deduce_this_ok: bool
18341853
) -> typing.Tuple[typing.List[Parameter], bool, typing.List[TemplateParam]]:
18351854
"""
18361855
Consumes function parameters and returns them, and vararg if found, and
@@ -1854,7 +1873,13 @@ def _parse_parameters(
18541873
self._next_token_must_be(")")
18551874
break
18561875

1857-
param, at_type = self._parse_parameter(None, Parameter, concept_ok)
1876+
# Deduce-this only applicable for first function parameter
1877+
param, at_type = self._parse_parameter(
1878+
None,
1879+
Parameter,
1880+
concept_ok,
1881+
deduce_this_ok=deduce_this_ok and len(params) == 0,
1882+
)
18581883
params.append(param)
18591884
if at_type:
18601885
at_params.append(
@@ -2047,7 +2072,9 @@ def _parse_function(
20472072
state.location = location
20482073
is_class_block = isinstance(state, ClassBlockState)
20492074

2050-
params, vararg, at_params = self._parse_parameters(True)
2075+
params, vararg, at_params = self._parse_parameters(
2076+
True, deduce_this_ok=is_class_block
2077+
)
20512078

20522079
# Promote abbreviated template parameters
20532080
if at_params:
@@ -2243,7 +2270,7 @@ def _parse_cv_ptr_or_fn(
22432270
toks = self._consume_balanced_tokens(gtok)
22442271
self.lex.return_tokens(toks[1:-1])
22452272

2246-
fn_params, vararg, _ = self._parse_parameters(False)
2273+
fn_params, vararg, _ = self._parse_parameters(False, False)
22472274

22482275
assert not isinstance(dtype, FunctionType)
22492276
dtype = dtype_fn = FunctionType(dtype, fn_params, vararg)
@@ -2273,7 +2300,7 @@ def _parse_cv_ptr_or_fn(
22732300
assert not isinstance(dtype, FunctionType)
22742301
dtype = self._parse_array_type(aptok, dtype)
22752302
elif aptok.type == "(":
2276-
fn_params, vararg, _ = self._parse_parameters(False)
2303+
fn_params, vararg, _ = self._parse_parameters(False, False)
22772304
# the type we already have is the return type of the function pointer
22782305

22792306
assert not isinstance(dtype, FunctionType)

cxxheaderparser/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,9 @@ class Parameter:
665665
default: typing.Optional[Value] = None
666666
param_pack: bool = False
667667

668+
#: Indicates that this parameter is the parameter used for cxx23 deducing-this
669+
deduces_this: bool = False
670+
668671
def format(self) -> str:
669672
default = f" = {self.default.format()}" if self.default else ""
670673
pp = "... " if self.param_pack else ""

tests/test_class.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,60 @@ class StoneClass {
883883
)
884884

885885

886+
def test_class_fn_deduce_this() -> None:
887+
content = """
888+
class StoneClass {
889+
template<typename Self>
890+
int doSelf(this Self&& self);
891+
};
892+
"""
893+
data = parse_string(content, cleandoc=True)
894+
895+
assert data == ParsedData(
896+
namespace=NamespaceScope(
897+
classes=[
898+
ClassScope(
899+
class_decl=ClassDecl(
900+
typename=PQName(
901+
segments=[NameSpecifier(name="StoneClass")],
902+
classkey="class",
903+
)
904+
),
905+
methods=[
906+
Method(
907+
return_type=Type(
908+
typename=PQName(
909+
segments=[FundamentalSpecifier(name="int")]
910+
)
911+
),
912+
name=PQName(segments=[NameSpecifier(name="doSelf")]),
913+
parameters=[
914+
Parameter(
915+
type=MoveReference(
916+
moveref_to=Type(
917+
typename=PQName(
918+
segments=[NameSpecifier(name="Self")]
919+
)
920+
)
921+
),
922+
name="self",
923+
deduces_this=True,
924+
)
925+
],
926+
template=TemplateDecl(
927+
params=[
928+
TemplateTypeParam(typekey="typename", name="Self")
929+
]
930+
),
931+
access="private",
932+
),
933+
],
934+
)
935+
]
936+
)
937+
)
938+
939+
886940
def test_class_fn_return_global_ns() -> None:
887941
content = """
888942
struct Avacado {

0 commit comments

Comments
 (0)