#ifndef RNGTEST_H #define RNGTEST_H #include #include #include #include /** * This relaxng validation implementation was ported from Haskell. * The Haskell implementation can be found here: * http://www.thaiopensource.com/relaxng/derivative.html * The Haskell implementation is extensively documented. This implemention * follows function names and function order closely so the Haskell * documentation applies mostly to this implementation. * Exceptions are noted. */ namespace rng { namespace types { using String = const char*; constexpr char emptyString[] = ""; using Uri = String; using LocalName = String; struct ParamList { struct Item { const LocalName& localName; const String& string; }; const std::vector& paramList; }; template struct Datatype; /** NameClasses */ struct AnyName; template struct AnyNameExcept { const NameClass& nameClass; explicit constexpr AnyNameExcept(const NameClass& n) :nameClass(n) {} }; // Name is not defined, use QName, which is identical template struct NsName { static constexpr String Uri = U; }; template struct NsNameExcept { static constexpr String Uri = U; using NameClass = NC; }; template struct NameClassChoice { using NameClass1 = NC1; using NameClass2 = NC2; }; /** Patterns */ struct Empty {}; struct NotAllowed {}; struct Text {}; template struct Choice; template struct Interleave; template struct Group; template struct OneOrMore; template struct List; template struct Data; template struct DataExcept; template struct Value; template struct Attribute; template struct Element; template struct After; template struct QName { static constexpr String Uri = U; static constexpr String LocalName = L; }; template struct AttributeNode {}; template struct StringAttribute {}; template struct ElementStart; template struct ElementStart,std::tuple> { using QName = rng::types::QName; using Attributes = std::tuple; const Attributes attributes; explicit constexpr ElementStart(const Attributes& a) :attributes(a) {} ElementStart(const ElementStart&) = delete; }; struct TextNode { const String& text; explicit constexpr TextNode(const String& t) :text(t) {} }; } namespace functions { using namespace rng::types; /** declaratations */ template struct contains_struct; template constexpr bool contains() { return contains_struct::value; } template struct nullable_struct; template constexpr bool nullable() { return nullable_struct::value; } /* This code uses startTagDeriv instead of childDeriv. * Since not all children are know at compile time, childrenDeriv is left out * and endTagDeriv and textDeriv must be called explicitly. */ template struct startTagDeriv; template struct textDeriv; // TODO: listDeriv template struct choice; template struct group; template struct interleave; template struct after; // TODO: datatypeAllows // TODO: datatypeEqual // TODO: normalizeWhitespace template class F, typename P, typename Pattern> struct applyAfter; // instead of implementing 'flip', a flipped variant of applyAfter is used template class F, typename P, typename Pattern> struct applyAfterFlip; template struct startTagOpenDeriv; template struct attsDeriv; template struct attDeriv; template struct valueMatch; template struct startTagCloseDeriv; template struct oneOrMore; // childrenDeriv, stripChildrenDeriv,strip, and whitespace are not implemented // in this code template struct whitespace; template struct endTagDeriv; /** specializations */ template struct contains_struct> { static constexpr bool value = true; }; template struct contains_struct,QName> { static constexpr bool value = !contains>(); }; template struct contains_struct,QName> { static constexpr bool value = strcmp(U1, U2) == 0; }; template struct contains_struct,QName> { static constexpr bool value = strcmp(U1, U2) == 0 && !contains>(); }; template struct contains_struct,QName> { static constexpr bool value = strcmp(U1, U2) == 0 && strcmp(L1, L2) == 0; }; template struct contains_struct,QName> { static constexpr bool value = contains>() || contains>(); }; template struct nullable_struct> { static constexpr bool value = nullable() && nullable(); }; template struct nullable_struct> { static constexpr bool value = nullable() && nullable(); }; template struct nullable_struct> { static constexpr bool value = nullable() || nullable(); }; template struct nullable_struct> { static constexpr bool value = nullable(); }; template struct nullable_struct> { static constexpr bool value = false; }; template struct nullable_struct> { static constexpr bool value = false; }; template struct nullable_struct> { static constexpr bool value = false; }; template struct nullable_struct> { static constexpr bool value = false; }; template struct nullable_struct> { static constexpr bool value = false; }; template struct nullable_struct> { static constexpr bool value = false; }; template <> struct nullable_struct { static constexpr bool value = false; }; template <> struct nullable_struct { static constexpr bool value = true; }; template <> struct nullable_struct { static constexpr bool value = true; }; template struct nullable_struct> { static constexpr bool value = false; }; template struct startTagDeriv,std::tuple>> { using p1 = typename startTagOpenDeriv>::type; using p2 = typename attsDeriv>::type; using type = typename startTagCloseDeriv::type; }; template struct textDeriv,V> { using p1 = typename textDeriv::type; using p2 = typename textDeriv::type; using type = typename choice::type; }; template struct textDeriv,V> { using p1 = typename textDeriv::type; using p2 = typename textDeriv::type; using i1 = typename interleave::type; using i2 = typename interleave::type; using type = typename choice::type; }; template struct textDeriv,V> { using p1 = typename textDeriv::type; using p2 = typename textDeriv::type; using p = typename group::type; using c = typename choice::type; using type = typename std::conditional(),c,p>::type; }; template struct textDeriv,V> { using p1 = typename textDeriv::type; using type = typename after::type; }; template struct textDeriv,V> { using p = typename textDeriv::type; using c = typename choice,Empty>::type; using type = typename group::type; }; template struct textDeriv { using type = Text; }; // TODO: implement for more types than String template struct textDeriv,V> { using type = Empty; }; template struct textDeriv,W> { using type = NotAllowed; }; // TODO: implement for Data<> // TODO: implement for DataExcept<> // TODO: implement for List<> template struct textDeriv { using type = NotAllowed; }; // TODO: listDeriv template struct choice { using type = Pattern; }; template struct choice { using type = Pattern; }; template struct choice { using type = Choice; }; template struct group { using type = NotAllowed; }; template struct group { using type = NotAllowed; }; template struct group { using type = Pattern; }; template struct group { using type = Pattern; }; template struct group { using type = Group; }; template <> struct interleave { using type = NotAllowed; }; template struct interleave { using type = NotAllowed; }; template struct interleave { using type = NotAllowed; }; template struct interleave { using type = Pattern; }; template struct interleave { using type = Pattern; }; template struct interleave { using type = Interleave; }; template struct after { using type = NotAllowed; }; template struct after { using type = NotAllowed; }; template struct after { using type = After; }; // TODO: datatypeAllows // TODO: datatypeEqual // TODO: normalizeWhitespace template class F, typename P, typename Pattern> struct applyAfter { using type = NotAllowed; }; template class F, typename P, typename Pattern> struct applyAfterFlip { using type = NotAllowed; }; template class F, typename P, typename Pattern1, typename Pattern2> struct applyAfter> { using p1 = typename F::type; using type = typename after::type; }; template class F, typename P, typename Pattern1, typename Pattern2> struct applyAfterFlip> { using p1 = typename F::type; using type = typename after::type; }; template class F, typename P, typename Pattern1, typename Pattern2> struct applyAfter> { using p1 = typename applyAfter::type; using p2 = typename applyAfter::type; using type = typename choice::type; }; template class F, typename P, typename Pattern1, typename Pattern2> struct applyAfterFlip> { using p1 = typename applyAfterFlip::type; using p2 = typename applyAfterFlip::type; using type = typename choice::type; }; template struct startTagOpenDeriv,QName> { using c1 = typename startTagOpenDeriv::type; using c2 = typename startTagOpenDeriv::type; using type = typename choice::type; }; template struct startTagOpenDeriv,QName> { static constexpr bool contains = contains(); using after = typename after::type; using type = typename std::conditional::type; }; template struct startTagOpenDeriv,QName> { using p1 = typename startTagOpenDeriv::type; using p2 = typename startTagOpenDeriv::type; using c1 = typename applyAfterFlip::type; using c2 = typename applyAfter::type; using type = typename choice::type; }; template struct startTagOpenDeriv,QName> { using p = typename startTagOpenDeriv::type; using c = typename choice,Empty>::type; using type = typename applyAfterFlip::type; }; template struct startTagOpenDeriv,QName> { using p1 = typename startTagOpenDeriv::type; using p2 = typename startTagOpenDeriv::type; using x = typename applyAfterFlip::type; using c = typename choice::type; using type = typename std::conditional(),c,x>::type; }; template struct startTagOpenDeriv,QName> { using p1 = typename startTagOpenDeriv::type; using type = typename applyAfterFlip::type; }; template struct startTagOpenDeriv { using type = NotAllowed; }; template struct attsDeriv> { using p = typename attDeriv::type; using type = typename attsDeriv>::type; }; template struct attsDeriv> { using type = Pattern; }; template struct attDeriv,Att> { using p1 = typename attDeriv::type; using type = typename after::type; }; template struct attDeriv,Att> { using p1 = typename attDeriv::type; using p2 = typename attDeriv::type; using type = typename choice::type; }; template struct attDeriv,Att> { using p1 = typename attDeriv::type; using p2 = typename attDeriv::type; using g1 = typename group::type; using g2 = typename group::type; using type = typename choice::type; }; template struct attDeriv,Att> { using p1 = typename attDeriv::type; using p2 = typename attDeriv::type; using i1 = typename interleave::type; using i2 = typename interleave::type; using type = typename choice::type; }; template struct attDeriv,Att> { using p = typename attDeriv::type; using c = typename choice,Empty>::type; using type = typename group::type; }; template struct attDeriv,AttributeNode> { static constexpr bool c = contains(); // there is not enough information to do value matching // TODO: check data type using type = typename std::conditional::type; }; template struct attDeriv,StringAttribute> { static constexpr bool c = contains(); static constexpr bool vm = valueMatch::value; using type = typename std::conditional::type; }; template struct attDeriv { using type = NotAllowed; }; template struct valueMatch { using p = typename textDeriv::type; static constexpr bool value = (nullable() && whitespace::value) || nullable

(); }; template struct startTagCloseDeriv> { using p1 = typename startTagCloseDeriv::type; using type = typename after::type; }; template struct startTagCloseDeriv> { using p1 = typename startTagCloseDeriv::type; using p2 = typename startTagCloseDeriv::type; using type = typename choice::type; }; template struct startTagCloseDeriv> { using p1 = typename startTagCloseDeriv::type; using p2 = typename startTagCloseDeriv::type; using type = typename group::type; }; template struct startTagCloseDeriv> { using p1 = typename startTagCloseDeriv::type; using p2 = typename startTagCloseDeriv::type; using type = typename interleave::type; }; template struct startTagCloseDeriv> { using p = typename startTagCloseDeriv::type; using type = typename oneOrMore

::type; }; template struct startTagCloseDeriv> { using type = NotAllowed; }; template struct startTagCloseDeriv { using type = Pattern; }; template struct oneOrMore { using type = Pattern; }; template <> struct oneOrMore { using type = NotAllowed; }; // childrenDeriv, stripChildrenDeriv, and strip are ommitted template struct whitespace { static constexpr bool value = strspn(V, " \t\n\r") == strlen(V); }; template struct endTagDeriv> { using p1 = typename endTagDeriv::type; using p2 = typename endTagDeriv::type; using type = typename choice::type; }; template struct endTagDeriv> { const bool c = nullable(); using type = typename std::conditional(),Pattern2,NotAllowed>::type; }; template struct endTagDeriv { using type = NotAllowed; }; } // functions } // rng #endif // RNGTEST_H