Skip to content

Commit

Permalink
Merge pull request #89 from robotpy/fn-constraints
Browse files Browse the repository at this point in the history
Move non-template requires to the function
  • Loading branch information
virtuald committed Dec 3, 2023
2 parents 04ba4bf + 85f93ec commit 64c5290
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 43 deletions.
15 changes: 4 additions & 11 deletions cxxheaderparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1912,12 +1912,10 @@ def _parse_fn_end(self, fn: Function) -> None:
else:
rtok = self.lex.token_if("requires")
if rtok:
fn_template = fn.template
if fn_template is None:
# requires on a function must always be accompanied by a template
if fn.template is None:
raise self._parse_error(rtok)
elif isinstance(fn_template, list):
fn_template = fn_template[0]
fn_template.raw_requires_post = self._parse_requires(rtok)
fn.raw_requires = self._parse_requires(rtok)

if self.lex.token_if("ARROW"):
self._parse_trailing_return_type(fn)
Expand Down Expand Up @@ -1983,12 +1981,7 @@ def _parse_method_end(self, method: Method) -> None:
toks = self._consume_balanced_tokens(otok)[1:-1]
method.noexcept = self._create_value(toks)
elif tok_value == "requires":
method_template = method.template
if method_template is None:
raise self._parse_error(tok)
elif isinstance(method_template, list):
method_template = method_template[0]
method_template.raw_requires_post = self._parse_requires(tok)
method.raw_requires = self._parse_requires(tok)
else:
self.lex.return_token(tok)
break
Expand Down
10 changes: 7 additions & 3 deletions cxxheaderparser/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,6 @@ class Foo {};
#: template <typename T> requires ...
raw_requires_pre: typing.Optional[Value] = None

#: template <typename T> int main() requires ...
raw_requires_post: typing.Optional[Value] = None


#: If no template, this is None. This is a TemplateDecl if this there is a single
#: declaration:
Expand Down Expand Up @@ -730,6 +727,13 @@ class Function:
#: is the string "conversion" and the full Type is found in return_type
operator: typing.Optional[str] = None

#: A requires constraint following the function declaration. If you need the
#: prior, look at TemplateDecl.raw_requires_pre. At the moment this is just
#: a raw value, if we interpret it in the future this will change.
#:
#: template <typename T> int main() requires ...
raw_requires: typing.Optional[Value] = None


@dataclass
class Method(Function):
Expand Down
125 changes: 96 additions & 29 deletions tests/test_concepts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Concept,
Function,
FundamentalSpecifier,
Method,
MoveReference,
NameSpecifier,
PQName,
Expand Down Expand Up @@ -495,15 +496,15 @@ def test_requires_last_elem() -> None:
)
],
template=TemplateDecl(
params=[TemplateTypeParam(typekey="typename", name="T")],
raw_requires_post=Value(
tokens=[
Token(value="Eq"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
]
),
params=[TemplateTypeParam(typekey="typename", name="T")]
),
raw_requires=Value(
tokens=[
Token(value="Eq"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
]
),
)
]
Expand Down Expand Up @@ -752,14 +753,14 @@ def test_requires_both() -> None:
Token(value=">"),
]
),
raw_requires_post=Value(
tokens=[
Token(value="Subtractable"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
]
),
),
raw_requires=Value(
tokens=[
Token(value="Subtractable"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
]
),
)
]
Expand Down Expand Up @@ -791,20 +792,86 @@ def test_requires_paren() -> None:
)
],
template=TemplateDecl(
params=[TemplateTypeParam(typekey="class", name="T")],
raw_requires_post=Value(
tokens=[
Token(value="("),
Token(value="is_purrable"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
Token(value="("),
Token(value=")"),
Token(value=")"),
]
params=[TemplateTypeParam(typekey="class", name="T")]
),
raw_requires=Value(
tokens=[
Token(value="("),
Token(value="is_purrable"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
Token(value="("),
Token(value=")"),
Token(value=")"),
]
),
)
]
)
)


def test_non_template_requires() -> None:
content = """
// clang-format off
template <class T>
struct Payload
{
constexpr Payload(T v)
requires(std::is_pod_v<T>)
: Value(v)
{
}
};
"""
data = parse_string(content, cleandoc=True)

assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="Payload")], classkey="struct"
),
template=TemplateDecl(
params=[TemplateTypeParam(typekey="class", name="T")]
),
),
methods=[
Method(
return_type=None,
name=PQName(segments=[NameSpecifier(name="Payload")]),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[NameSpecifier(name="T")]
)
),
name="v",
)
],
constexpr=True,
has_body=True,
raw_requires=Value(
tokens=[
Token(value="("),
Token(value="std"),
Token(value="::"),
Token(value="is_pod_v"),
Token(value="<"),
Token(value="T"),
Token(value=">"),
Token(value=")"),
]
),
access="public",
constructor=True,
)
],
)
]
)
Expand Down

0 comments on commit 64c5290

Please sign in to comment.