Implement basic concept parsing
- requires clauses are collected into a Value and not interpreted at this time
This commit is contained in:
403
tests/test_concepts.py
Normal file
403
tests/test_concepts.py
Normal file
@@ -0,0 +1,403 @@
|
||||
from cxxheaderparser.simple import NamespaceScope, ParsedData, parse_string
|
||||
from cxxheaderparser.tokfmt import Token
|
||||
from cxxheaderparser.types import (
|
||||
Concept,
|
||||
Function,
|
||||
FundamentalSpecifier,
|
||||
NameSpecifier,
|
||||
PQName,
|
||||
Parameter,
|
||||
TemplateArgument,
|
||||
TemplateDecl,
|
||||
TemplateNonTypeParam,
|
||||
TemplateSpecialization,
|
||||
TemplateTypeParam,
|
||||
Type,
|
||||
Value,
|
||||
Variable,
|
||||
)
|
||||
|
||||
|
||||
def test_concept_basic_constraint() -> None:
|
||||
content = """
|
||||
template <class T, class U>
|
||||
concept Derived = std::is_base_of<U, T>::value;
|
||||
|
||||
template <Derived<Base> T> void f(T); // T is constrained by Derived<T, Base>
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
functions=[
|
||||
Function(
|
||||
return_type=Type(
|
||||
typename=PQName(segments=[FundamentalSpecifier(name="void")])
|
||||
),
|
||||
name=PQName(segments=[NameSpecifier(name="f")]),
|
||||
parameters=[
|
||||
Parameter(
|
||||
type=Type(
|
||||
typename=PQName(segments=[NameSpecifier(name="T")])
|
||||
)
|
||||
)
|
||||
],
|
||||
template=TemplateDecl(
|
||||
params=[
|
||||
TemplateNonTypeParam(
|
||||
type=Type(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="Derived",
|
||||
specialization=TemplateSpecialization(
|
||||
args=[
|
||||
TemplateArgument(
|
||||
arg=Type(
|
||||
typename=PQName(
|
||||
segments=[
|
||||
NameSpecifier(
|
||||
name="Base"
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
name="T",
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
concepts=[
|
||||
Concept(
|
||||
template=TemplateDecl(
|
||||
params=[
|
||||
TemplateTypeParam(typekey="class", name="T"),
|
||||
TemplateTypeParam(typekey="class", name="U"),
|
||||
]
|
||||
),
|
||||
name="Derived",
|
||||
raw_constraint=Value(
|
||||
tokens=[
|
||||
Token(value="std"),
|
||||
Token(value="::"),
|
||||
Token(value="is_base_of"),
|
||||
Token(value="<"),
|
||||
Token(value="U"),
|
||||
Token(value=","),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="::"),
|
||||
Token(value="value"),
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_concept_basic_constraint2() -> None:
|
||||
content = """
|
||||
template <class T> constexpr bool is_meowable = true;
|
||||
|
||||
template <class T> constexpr bool is_cat = true;
|
||||
|
||||
template <class T>
|
||||
concept Meowable = is_meowable<T>;
|
||||
|
||||
template <class T>
|
||||
concept BadMeowableCat = is_meowable<T> && is_cat<T>;
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
variables=[
|
||||
Variable(
|
||||
name=PQName(segments=[NameSpecifier(name="is_meowable")]),
|
||||
type=Type(
|
||||
typename=PQName(segments=[FundamentalSpecifier(name="bool")])
|
||||
),
|
||||
value=Value(tokens=[Token(value="true")]),
|
||||
constexpr=True,
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="T")]
|
||||
),
|
||||
),
|
||||
Variable(
|
||||
name=PQName(segments=[NameSpecifier(name="is_cat")]),
|
||||
type=Type(
|
||||
typename=PQName(segments=[FundamentalSpecifier(name="bool")])
|
||||
),
|
||||
value=Value(tokens=[Token(value="true")]),
|
||||
constexpr=True,
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="T")]
|
||||
),
|
||||
),
|
||||
],
|
||||
concepts=[
|
||||
Concept(
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="T")]
|
||||
),
|
||||
name="Meowable",
|
||||
raw_constraint=Value(
|
||||
tokens=[
|
||||
Token(value="is_meowable"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
]
|
||||
),
|
||||
),
|
||||
Concept(
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="T")]
|
||||
),
|
||||
name="BadMeowableCat",
|
||||
raw_constraint=Value(
|
||||
tokens=[
|
||||
Token(value="is_meowable"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="&&"),
|
||||
Token(value="is_cat"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
]
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_concept_basic_requires() -> None:
|
||||
content = """
|
||||
template <typename T>
|
||||
concept Hashable = requires(T a) {
|
||||
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
|
||||
};
|
||||
|
||||
template <Hashable T> void f(T) {}
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
functions=[
|
||||
Function(
|
||||
return_type=Type(
|
||||
typename=PQName(segments=[FundamentalSpecifier(name="void")])
|
||||
),
|
||||
name=PQName(segments=[NameSpecifier(name="f")]),
|
||||
parameters=[
|
||||
Parameter(
|
||||
type=Type(
|
||||
typename=PQName(segments=[NameSpecifier(name="T")])
|
||||
)
|
||||
)
|
||||
],
|
||||
has_body=True,
|
||||
template=TemplateDecl(
|
||||
params=[
|
||||
TemplateNonTypeParam(
|
||||
type=Type(
|
||||
typename=PQName(
|
||||
segments=[NameSpecifier(name="Hashable")]
|
||||
)
|
||||
),
|
||||
name="T",
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
concepts=[
|
||||
Concept(
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="typename", name="T")]
|
||||
),
|
||||
name="Hashable",
|
||||
raw_constraint=Value(
|
||||
tokens=[
|
||||
Token(value="requires"),
|
||||
Token(value="("),
|
||||
Token(value="T"),
|
||||
Token(value="a"),
|
||||
Token(value=")"),
|
||||
Token(value="{"),
|
||||
Token(value="{"),
|
||||
Token(value="std"),
|
||||
Token(value="::"),
|
||||
Token(value="hash"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="{"),
|
||||
Token(value="}"),
|
||||
Token(value="("),
|
||||
Token(value="a"),
|
||||
Token(value=")"),
|
||||
Token(value="}"),
|
||||
Token(value="->"),
|
||||
Token(value="std"),
|
||||
Token(value="::"),
|
||||
Token(value="convertible_to"),
|
||||
Token(value="<"),
|
||||
Token(value="std"),
|
||||
Token(value="::"),
|
||||
Token(value="size_t"),
|
||||
Token(value=">"),
|
||||
Token(value=";"),
|
||||
Token(value="}"),
|
||||
]
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_concept_nested_requirements() -> None:
|
||||
content = """
|
||||
template<class T>
|
||||
concept Semiregular = DefaultConstructible<T> &&
|
||||
CopyConstructible<T> && CopyAssignable<T> && Destructible<T> &&
|
||||
requires(T a, std::size_t n)
|
||||
{
|
||||
requires Same<T*, decltype(&a)>; // nested: "Same<...> evaluates to true"
|
||||
{ a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw
|
||||
requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true"
|
||||
requires Same<T*, decltype(new T[n])>; // nested
|
||||
{ delete new T }; // compound
|
||||
{ delete new T[n] }; // compound
|
||||
};
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
concepts=[
|
||||
Concept(
|
||||
template=TemplateDecl(
|
||||
params=[TemplateTypeParam(typekey="class", name="T")]
|
||||
),
|
||||
name="Semiregular",
|
||||
raw_constraint=Value(
|
||||
tokens=[
|
||||
Token(value="DefaultConstructible"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="&&"),
|
||||
Token(value="CopyConstructible"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="&&"),
|
||||
Token(value="CopyAssignable"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="&&"),
|
||||
Token(value="Destructible"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value=">"),
|
||||
Token(value="&&"),
|
||||
Token(value="requires"),
|
||||
Token(value="("),
|
||||
Token(value="T"),
|
||||
Token(value="a"),
|
||||
Token(value=","),
|
||||
Token(value="std"),
|
||||
Token(value="::"),
|
||||
Token(value="size_t"),
|
||||
Token(value="n"),
|
||||
Token(value=")"),
|
||||
Token(value="{"),
|
||||
Token(value="requires"),
|
||||
Token(value="Same"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value="*"),
|
||||
Token(value=","),
|
||||
Token(value="decltype"),
|
||||
Token(value="("),
|
||||
Token(value="&"),
|
||||
Token(value="a"),
|
||||
Token(value=")"),
|
||||
Token(value=">"),
|
||||
Token(value=";"),
|
||||
Token(value="{"),
|
||||
Token(value="a"),
|
||||
Token(value="."),
|
||||
Token(value="~T"),
|
||||
Token(value="("),
|
||||
Token(value=")"),
|
||||
Token(value="}"),
|
||||
Token(value="noexcept"),
|
||||
Token(value=";"),
|
||||
Token(value="requires"),
|
||||
Token(value="Same"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value="*"),
|
||||
Token(value=","),
|
||||
Token(value="decltype"),
|
||||
Token(value="("),
|
||||
Token(value="new"),
|
||||
Token(value="T"),
|
||||
Token(value=")"),
|
||||
Token(value=">"),
|
||||
Token(value=";"),
|
||||
Token(value="requires"),
|
||||
Token(value="Same"),
|
||||
Token(value="<"),
|
||||
Token(value="T"),
|
||||
Token(value="*"),
|
||||
Token(value=","),
|
||||
Token(value="decltype"),
|
||||
Token(value="("),
|
||||
Token(value="new"),
|
||||
Token(value="T"),
|
||||
Token(value="["),
|
||||
Token(value="n"),
|
||||
Token(value="]"),
|
||||
Token(value=")"),
|
||||
Token(value=">"),
|
||||
Token(value=";"),
|
||||
Token(value="{"),
|
||||
Token(value="delete"),
|
||||
Token(value="new"),
|
||||
Token(value="T"),
|
||||
Token(value="}"),
|
||||
Token(value=";"),
|
||||
Token(value="{"),
|
||||
Token(value="delete"),
|
||||
Token(value="new"),
|
||||
Token(value="T"),
|
||||
Token(value="["),
|
||||
Token(value="n"),
|
||||
Token(value="]"),
|
||||
Token(value="}"),
|
||||
Token(value=";"),
|
||||
Token(value="}"),
|
||||
]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user