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 concept Derived = std::is_base_of::value; template T> void f(T); // T is constrained by Derived """ 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 constexpr bool is_meowable = true; template constexpr bool is_cat = true; template concept Meowable = is_meowable; template concept BadMeowableCat = is_meowable && is_cat; """ 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 concept Hashable = requires(T a) { { std::hash{}(a) } -> std::convertible_to; }; template 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 concept Semiregular = DefaultConstructible && CopyConstructible && CopyAssignable && Destructible && requires(T a, std::size_t n) { requires Same; // nested: "Same<...> evaluates to true" { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw requires Same; // nested: "Same<...> evaluates to true" requires Same; // 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="}"), ] ), ) ] ) )